pr3slaff / psst
Deliberate, fail-silent Laravel events and authenticated health metrics.
Requires
- php: ^8.3
- illuminate/database: ^12.0|^13.0
- illuminate/http: ^12.0|^13.0
- illuminate/queue: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^10.0|^11.0
- phpunit/phpunit: ^11.5|^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
An independent MIT Laravel 12/13 package for deliberately selected events. Requires PHP 8.3+. Tested on PHP 8.3–8.5. No Filament dependency. Source and releases: pr3slaff/psst.
Install
Once Packagist has indexed the package:
composer require pr3slaff/psst:^1.0 php artisan vendor:publish --tag=psst-config
You can also install the tagged release directly from its public GitHub repository, without a Packagist account or GitHub credentials:
composer config repositories.psst vcs https://github.com/pr3slaff/psst composer require pr3slaff/psst:^1.0 php artisan vendor:publish --tag=psst-config
composer require adds this package to a project. Commit the application's updated composer.json/composer.lock; subsequent deployments use composer install.
Create a project in Psst, save its one-time ingestion key and configure the source application's .env:
PSST_ENDPOINT=https://psst.pr3slaff.eu/api/v1/ingest PSST_KEY=your-project-ingestion-key PSST_MODE=sync
Refresh Laravel's configuration with php artisan config:cache if it was cached. Default sync mode does not need a queue worker in the source application. The Psst backend processes its notification queue independently.
Health monitoring is optional. To enable it, also set PSST_HEALTH_KEY to the separate health secret shown when creating/rotating the project keys, and save the source application's public HTTPS https://your-app.example/psst-health address in that project's Psst settings. Leave health unconfigured if you only need events.
Бърз старт на български
Добави пакета с командите по-горе, публикувай конфигурацията и задай PSST_ENDPOINT и PSST_KEY в .env на приложението, което ще изпраща събития. Ключът е ingestion ключът от проекта в Psst. След промяна обнови config cache. По подразбиране не е нужен worker в това приложение. Health адресът и отделният PSST_HEALTH_KEY са незадължителни.
Laravel discovers the provider and Psst alias automatically. You can explicitly import Pr3slaff\Psst\Facades\Psst. Publish configuration with php artisan vendor:publish --tag=psst-config, then set the values illustrated in .env.example. PSST_ENDPOINT is the complete ingestion URL, including /api/v1/ingest. Production must use HTTPS. Ingestion and health keys must be different secrets generated by their respective systems.
use Pr3slaff\Psst\Facades\Psst; $result = Psst::success('Order paid', ['order_id' => $order->id]); Psst::info('Import finished'); Psst::warning('Balance is low'); Psst::danger('Payment provider failed'); // status: accepted | queued | failed; stable client ID: $result->eventId if ($result->failed()) { /* optional application-specific observation */ }
Default sync makes one immediate network attempt with a one-second total timeout and a one-second connect timeout; redirects are disabled. There is no built-in immediate retry. accepted requires a 200/201 acknowledgement containing the original event ID and server ID. The backend acknowledges after durable persistence; it does not promise push delivery. Multiple sync calls accumulate latency. Internal errors in normalization, configuration, delivery, queue dispatch and the optional diagnostic callback are caught. Ordinary caller type errors are outside this promise.
Explicit asynchronous delivery
Set PSST_MODE=queue and PSST_QUEUE_CONNECTION=redis (or database, sqs, beanstalkd). Run permanent workers, for example php artisan queue:work redis --queue=psst --timeout=10. Configure the driver's reservation/retry timeout above the worker timeout. Database queues require Laravel's jobs migration. Workers need access to the same package configuration and ingestion key. Jobs contain the normalized payload; secure queue storage accordingly.
The package rejects sync, null, deferred, background, failover and unknown drivers to avoid inline HTTP or untracked retries. Queue insertion/serialization failure returns failed. Within an active database transaction it registers a callback; dispatch occurs only after commit, rollback discards it. queued inside a transaction means registered for enqueue after commit. If that eventual enqueue fails, the event is lost and only safe diagnostics run; commit still succeeds. A caught boundary surrounds the actual post-commit dispatch. Transactions on any Laravel-managed connection are supported.
Transient network errors, 429 and 5xx responses retry with exponential delays (5 seconds through one hour), respecting larger numeric or HTTP-date Retry-After values. Nothing retries past the immutable deadline of 24 hours from enqueue. A retry keeps the same ID, original timestamp and exact normalized payload. All other HTTP errors and invalid local configuration stop. Persistent worker infrastructure failures are subject to Laravel's worker configuration; the package never extends the deadline.
// Always attempts immediately even when the default mode is queue: Psst::force()->danger('Urgent event');
PSST_FALLBACK_TO_QUEUE=true explicitly enables queue fallback when an immediate sync or force call fails. Default is false. The fallback preserves the same event. Sync/force calls inside transactions execute immediately and may describe business changes later rolled back; place such calls after successful commit when appropriate.
Payload safety
Messages are repaired to UTF-8 and limited to 4000 Unicode characters. Context supports arrays and primitive JSON values, is traversed at most eight nested containers deep, and is bounded at 1000 entries per container. Strings and oversized events are truncated with an explicit marker and truncated=true; total encoded event size is at most 64 KiB. If context cannot fit, a small truncation context replaces it. Objects (including Eloquent models, exceptions and JsonSerializable instances) and resources are replaced without invoking serialization/accessor hooks. Non-finite floats are replaced.
Recursive case-insensitive key masking defaults to password, password_confirmation, token, access_token, refresh_token, authorization, secret, cookie and api_key. Change redact_fields in config to add domain fields; retain defaults as appropriate. Credentials in free text and intentional personal data are the developer's responsibility. Do not pass whole models/exceptions. Traversal also has a global 5000-node/60000-byte context budget, including cyclic/shared arrays. Default diagnostics emit a Laravel warning with only a fixed reason code and event ID, never response bodies, URLs, keys or payloads. An optional diagnostics callable replaces that logger; errors and recursive diagnostics are contained.
One authenticated health response and statistics
GET /psst-health requires X-Psst-Key: <PSST_HEALTH_KEY>. Without a configured key it returns 404; invalid credentials return 401. The successful response has Cache-Control: no-store. Boot health only confirms Laravel boot and a valid response, with no database/queue/external probe. There is exactly one response containing all registered metrics, irrespective of query parameters.
Register cheap scalar statistics in a source application's service provider:
public function boot(): void { Psst::metric('sales_today', 'Sales today', fn () => 24, [ 'unit' => 'orders', 'cache_ttl' => 60, ]); }
Metric keys start with a letter and contain letters, digits and underscores (max 64 characters). At most 20 unique keys; labels max 200 characters. Number, UTF-8 string (max 4000 characters) and boolean values are supported. Callback exceptions/invalid scalar values return a safe per-metric error. Last successful value and actual computed_at are preserved and marked stale; failures do not mark the whole application down. No last good result means null value/time. Metrics are cached separately in the application's configured cache store; default freshness is 60 seconds, configurable per metric with cache_ttl (0 recomputes each request). Use persistent shared cache in production. Last good values are retained until your cache evicts or clears them. Cache failures are isolated to the metric.
Outbound event delivery has a one-second timeout. Backend polling of this endpoint has a separate ten-second total timeout. A blocking callback cannot be preempted safely by this package and can exceed that polling timeout; use cheap or precomputed statistics. The source application's timezone defines business calculations such as "today"; all wire timestamps are UTC. Store/compute expensive aggregates ahead of health requests. There are no metric-specific routes, historical charts or threshold alerts.
Development
composer install then composer test runs a real Orchestra Testbench Laravel application. See IMPLEMENTATION.md for the actual dependency matrix and test evidence. Canonical v1 fixture checks additionally run when this package is in the monorepo. No service, package registry or public repository is created by these commands.