isaadsalman/headless-refresh
Headless Refresh is a Laravel package for refreshing application state—tokens, cached data, or views—without a frontend. It provides simple, API-friendly endpoints and configurable drivers so headless apps stay in sync.
This is a 1.0.x line package and the jump from 1.0.2 to 1.0.5 is patch-level, so treat it as a stability/bugfix release rather than a feature release. Start by pinning to ^1.0.5 and reading the compare diff (1.0.2...1.0.5) in the repo before upgrading — the published release notes contain only the changelog link, so the diff is your only source of truth for what actually changed.
Minimal setup path:
composer require isaadsalman/headless-refreshphp artisan vendor:publish --tag=headless-refresh-config.env (do not commit the secret; keep it in the config file as env('HEADLESS_REFRESH_SECRET')).php artisan headless:refresh once manually to confirm connectivity and auth before wiring anything automatic.First use case: hook it to a single content model you already edit frequently (a Page or Post), trigger a refresh on save, and confirm the headless front end re-renders. Get that one path working end to end before expanding to global invalidation — global refreshes are the easiest way to make a cold-start problem look like a package bug.
Model-driven invalidation. The common pattern is to observe saved/deleted on content models and dispatch a refresh. Prefer a dedicated listener class over inline closures in booted() so you can queue it, test it, and disable it per-environment. Keep the observer registered in a service provider rather than on the model itself if you want to toggle it via config.
Queue the refresh, always. Refresh calls are outbound HTTP requests to another system. Running them synchronously inside a model save adds a third-party timeout to your request latency and can roll back or slow a transaction. Push the refresh onto a queue with ->onQueue('refreshes') and give that queue its own worker so a stalled front end doesn't starve mail or webhooks.
Batch on bulk operations. Imports, seeders, and mass updates will fire the observer hundreds of times. Wrap bulk work in a guard (a static flag, withoutEvents, or a "defer until commit" pattern) and issue one refresh at the end. If the package exposes tag/path-based invalidation, use the narrowest target available — path-level invalidation over a full-site purge.
Transactions and commits. If you must refresh synchronously, attach it to DB::afterCommit() so you never announce content that a rolled-back transaction erased. This is the single most common source of "the front end shows deleted content" reports.
Deployment integration. A refresh on deploy (after migrations and cache warm-up) is a reasonable second call site, and often the only one you need for a small site. Pair it with your existing deploy hook rather than adding a separate script.
Testing. Fake the outbound call with Http::fake() and assert a request was sent with the right payload and signature header. Assert on the queue with Queue::fake() for the dispatch side, and separately test the listener's behaviour. Two small tests cover both halves of the contract.
php artisan config:cache in deploy pipelines will freeze your webhook URL and secret. If a deploy changes either, you must re-cache — a stale secret presents as a silent 401 that nobody notices until content goes stale hours later.failed_jobs), otherwise the first signal is a stale page discovered by a user..env files get copied around."isaadsalman/headless-refresh": "1.0.5" in production and upgrade deliberately with the diff open, rather than floating on ^1.0.How can I help you explore Laravel packages today?