rocketeers-app/laravel
Laravel integration package from rocketeers-app that connects Rocketeers App tooling with Laravel applications through service provider bindings and configuration. It aims to simplify setup and usage for Laravel projects while keeping integration lightweight and straightforward.
This package wires a Laravel app into the Rocketeers dashboard, and v2.10.0 adds a signed, read-only Horizon stats endpoint so the dashboard can show Horizon state without ever holding your secret.
Minimal setup:
laravel/horizon is installed in the app you want to monitor. Without Horizon the stats route returns 404, so the package remains safe to install everywhere.ROCKETEERS_HORIZON_SECRET=<your Rocketeers environment id>
For an existing environment, use Insert › Horizon monitoring in the Rocketeers env editor rather than inventing a value. An empty secret keeps the endpoint closed.ROCKETEERS_HORIZON_ORIGIN (browser origin allowed to call the endpoint) and ROCKETEERS_HORIZON_TTL (signature lifetime, default 300 seconds).php artisan route:list --path=rocketeers should show GET /rocketeers/horizon/stats.403 means the signature is invalid or expired; a 404 means Horizon is not installed.First use case: point the Rocketeers Horizon monitor (or your own status page) at a short-lived signed URL and render the aggregate counts — status, processes, jobsPerMinute, failedJobs, recentJobs, wait — refreshing from the browser. Start there before touching anything else; it is the intended path and needs no bearer token.
Sign server-side, render client-side. The dashboard signs the URL and only the short-lived signature reaches the browser. Follow the same split in your own app: a controller or Blade view generates the URL with a short expires, the frontend polls it. Never send ROCKETEERS_HORIZON_SECRET to the client, and never log full signed URLs — the signature is a bearer credential for its TTL.
Pair with the existing bearer token access. v2.9.0 added bearer token access; v2.10.0 adds signed URLs. They are independent and coexist. A clean split:
Polling loop. Treat the payload as counters, not events. A dashboard refresh every 10–30 seconds is well within a 300s TTL; if you cache the signed URL, cache it for less than the TTL (e.g. TTL minus a minute) so it never expires mid-poll.
CORS-simple by design. No custom request headers means no preflight. Keep it that way: if you add Authorization or X-* headers on the client, you turn a simple GET into a preflighted request and will need ROCKETEERS_HORIZON_ORIGIN plus proper Access-Control-Allow-* handling from wherever the route is served.
Health checks and alerting. status and failedJobs are the useful signals. Wire them into an uptime check or an on-call alert: failedJobs increasing over consecutive polls, or status not running, is the cheap early warning. Keep the check on the server side if it must be reliable — browser polls stop when nobody has the dashboard open.
Multi-instance dashboards. Because each app signs its own URL with its own environment id, one dashboard can fan out across every Horizon instance and merge rows. Give each instance its own ROCKETEERS_HORIZON_SECRET and let the dashboard hold only the resulting URLs.
403 is ambiguous by design. It covers both a bad signature and an expired one. Check the expires value against the server clock first — clock skew between the signing host and the app is the usual culprit — then confirm both sides use the same environment id.ROCKETEERS_HORIZON_SECRET is unset or blank after a config change, the endpoint is closed and you will get 403s that look like signature bugs. Run php artisan config:clear after editing .env, especially in deployed environments with cached config.404 is not a bug. No Horizon installed means no route. Gate your frontend on the response code rather than assuming the endpoint always exists, and don't add Horizon as a dependency of every app just to satisfy a dashboard.web group. No session, no cookies, no CSRF token — so auth, web, VerifyCsrfToken and session-dependent middleware do not apply here. If you wrap the route with your own middleware, verify it does not assume a session or a CSRF token, and test with a clean client (curl, no cookies) before blaming the signature.ROCKETEERS_HORIZON_ORIGIN; otherwise the request may reach the route but be blocked by CORS in the browser with a confusing, apparently-empty failure.300 is a browser-polling default, not a transport default. Lower it for tighter security; raise it only if you know the URL is not being shared or cached. A URL pasted into chat or browser history is usable until it expires.illuminate/support: ^13.0, yet the suite booted Laravel 12 because orchestra/testbench was capped at ^10.0. On v2.10.0 the test run resolves laravel/framework 13.29 through testbench 11.x. If you run this package's tests in CI, pin testbench to 11.x and expect a real Laravel 13 boot — do not conclude "Laravel 13 is untested" from the older constraint.How can I help you explore Laravel packages today?