yorcreative/laravel-query-watcher
Laravel Query Watcher monitors your application's database queries and flags slow or problematic SQL. Configure thresholds to log warnings or trigger notifications, making it easier to catch performance issues early during development and production.
This release adds a server-side authorization endpoint that lets Pusher authenticate a client subscribing to a private channel scoped to query events. In practice this closes the loop on real-time query/model-event broadcasting: previously you could broadcast, but private-channel subscription had no first-party auth route.
Minimal path to first working subscription:
composer require <vendor>/<package> and let the service provider auto-register (Laravel 11+ package discovery; on older apps add it to config/app.php).php artisan vendor:publish --tag=<package>-config. Look here first for the channel name/prefix convention and the middleware applied to the new endpoint — that is the knob you will most likely need to touch.BROADCAST_CONNECTION=pusher (or BROADCAST_DRIVER pre-Laravel 11), plus PUSHER_APP_ID, PUSHER_APP_KEY, PUSHER_APP_SECRET, PUSHER_APP_CLUSTER.->withBroadcasting(__DIR__.'/../routes/channels.php', ['middleware' => ['web', 'auth']]) in bootstrap/app.php. Earlier: BroadcastServiceProvider booted with Broadcast::routes().laravel-echo + pusher-js, instantiate Echo with your cluster/forceTLS, then Echo.private('<channel-name-from-config>') and listen for the event name the package broadcasts.broadcast(new ...)->toOthers()), and confirm the browser receives it. If you get a 403 on the auth request, you are looking at the new endpoint — see Gotchas.Where to look first when something breaks: php artisan route:list --path=broadcasting (confirm the new endpoint is actually registered and which middleware it carries), then the published config, then the browser network tab for the /broadcasting/auth (or package-specific) POST.
Auth-endpoint wiring. Two viable shapes, pick one and stay consistent:
authEndpoint (/broadcasting/auth) and implement the channel callback in routes/channels.php via Broadcast::channel('...', fn ($user, $id) => ...). The package endpoint then serves as a convenience/alternative; do not point Echo at both.authEndpoint explicitly in your Echo config and let the package own authorization. Verify it accepts the same request body Pusher sends (socket_id, channel_name) and returns the auth string.Authorization must scope, not just authenticate. The new endpoint decides who may join a query event private channel. Treat the channel name as user input: parse the identifier out of the channel name and assert ownership/tenant membership before returning an auth signature. A route that only checks "is logged in" is a cross-tenant data leak, since private channels are otherwise only protected by that single callback.
SPA / token auth. For Sanctum or token-guarded APIs, the auth endpoint is hit by the browser without a session cookie in some setups. Either put the endpoint behind auth:sanctum and configure Echo's authorizer to attach Authorization: Bearer ..., or keep it on the web middleware stack with CSRF token included. Mixing the two is the most common source of intermittent 403s.
Broadcast side. Emit with broadcast(new QueryEvent(...))->toOthers() so the originating tab doesn't double-handle. Use PrivateChannel('...') on the server (Laravel adds the private- prefix for you) and Echo.private('...') on the client without the prefix.
Testing. Use Broadcast::fake() to assert the event/channel pairing, and Event::fake() where relevant. For the new endpoint, test it directly: $this->actingAs($user)->postJson($endpoint, ['socket_id' => '1.1', 'channel_name' => 'private-...']) and assert 200 for the owner and 403 for a different user — that second assertion is the one that catches regressions.
Deployment. Restart queue workers (php artisan queue:restart) and re-run php artisan config:cache after upgrading, since the endpoint's middleware/prefix likely comes from config.
PrivateChannel('query-events.1') + client Echo.private('query-events.1') is correct; Echo.private('private-query-events.1') is not. If auth succeeds but events never arrive, check this first./broadcasting/auth. In order of likelihood: missing auth middleware on the auth route; channel callback returning false/null (a null return is treated as deny); CSRF token missing on a session-authenticated POST; Echo pointed at the default endpoint while the package expects its own (or vice versa).cluster, or forceTLS: false on an HTTPS page, produces a silent "connected but no events" state. Watch the Pusher debug console — if the subscription never appears there, the problem is client config, not Laravel.->toOthers() requires a socket id. It reads X-Socket-ID from the request header, which Echo sets only when properly configured. Without it, the broadcasting user receives their own event and you get duplicated UI updates.config:cache on deploy is mandatory, and stale caches after a version bump are a classic "route not found" red herring.routes/channels.php. Override by publishing config or by defining the channel in your own channels.php and pointing Echo at the framework route instead — a clean escape hatch if the package's defaults don't match your guard.Broadcast::fake() for assertions, Telescope's event/broadcast watchers (or the Broadcast log driver) for server-side confirmation, and the browser network tab for the auth POST payload — paste the exact socket_id/channel_name into a curl against the endpoint to isolate Laravel from Pusher.How can I help you explore Laravel packages today?