Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Mercure Bundle Laravel Package

symfony/mercure-bundle

Symfony bundle that integrates the Mercure Component into full-stack Symfony applications, making it easy to add real-time push updates over Server-Sent Events. Provides configuration, dependency injection setup, and seamless hub integration for publishing and subscribing to live updates.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Real-time feature roadmap: Enables push notifications, live updates, or collaborative editing without polling or WebSocket infrastructure.
  • Build vs. buy: Avoids reinventing Mercure integration (protocol, hub management, token signing) while keeping full control of UX and business logic. The 0.6.0 default to Mercure protocol 1.0 (now stable) materially lowers standards risk — we would be building on a finalized protocol rather than a draft.
  • Use cases:
    • Live dashboards (analytics, monitoring, ops views).
    • Chat/messaging with instant delivery.
    • Collaborative tools (shared documents, whiteboards).
    • Server-sent events (SSE) as an alternative to WebSockets, with broader client support.
  • Deployment topology decision: 0.6.0 picks Hub vs. FrankenPhpHub at runtime via a factory, and an empty url now reliably selects FrankenPHP's built-in hub. That makes "single-binary app + embedded hub" (FrankenPHP worker mode, Docker Compose with an unset MERCURE_URL) a credible low-infra option versus running a separate hub — a real cost/ops tradeoff we can now decide per environment instead of per codebase.
  • Internal-vs-public URL topology (updated in 0.6.1): Publisher tokens for protocol 1.0 now include the hub url in the default aud claim — and that claim is what the hub actually reads. Practically: a hub reachable as http://hub:80 inside the cluster but https://realtime.example.com publicly now accepts publications without the resource_identifier workaround we previously had to configure by hand. This removes a standing piece of bespoke config from any containerized/multi-network deployment and makes the "separate hub behind a different public hostname" topology a config-free default rather than a maintenance liability.
  • Multi-hub / multi-tenant architecture: Per-hub http_client (e.g. a scoped client with a short timeout) lets us isolate slow or flaky hubs from request latency; autowirable RemoteHubInterface (globally for the default remote hub, per hub via named arguments like RemoteHubInterface $fooHub) enables multi-region or per-tenant hubs without boilerplate.
  • Security posture: Per-hub publisher and subscriber options allow signing publisher and subscriber tokens with different keys, enabling least-privilege token issuance and cleaner key-rotation stories than a single shared jwt secret. Note that 0.6.1 broadens the default publisher aud to the hub URL — if we ever rely on audience as a restriction (rather than as the hub-selection hint it is here), we should set the claim explicitly instead of relying on the default.
  • Scalability: Horizontal scaling via Mercure hubs (self-hosted or third-party like Mercure.rocks), unchanged by this release.
  • Upgrade/maintenance planning (updated): 0.6.0 shipped two BC breaks (legacy Publisher/PublisherInterface/TraceablePublisher and StaticJwtProvider services removed; MercureDataCollector::getPublishers() removed) plus a hard config requirement for jwt.secret hubs. 0.6.1 is a patch release with no breaking changes — it only adds url to the default aud claim, so it is safe to take inside the same migration window. Still pin the bundle version in composer.json rather than floating it; the aud default is behavior, and behavior in a pre-1.0 package can shift again. As a cleanup item: if we added resource_identifier to publishers solely to work around internal/public URL mismatch, we can remove it after upgrading and verifying against our hub.

When to Consider This Package

  • Adopt if:
    • Your stack is Symfony (this bundle's DI, config, and profiler integration are Symfony-specific). For Laravel or other PHP frameworks, use the framework-agnostic symfony/mercure client (^0.9 supported here) directly — you get the hub/token plumbing without the bundle.
    • You need lightweight real-time updates — lower latency than polling, simpler than WebSockets.
    • Clients are browsers, mobile apps (SSE), or IoT devices supporting HTTP/2.
    • You prioritize standardized protocols — Mercure 1.0 is now stable and the bundle defaults to it.
    • Your team lacks WebSocket expertise but needs real-time features.
    • Preconditions for 0.6.x specifically: your hub is Mercure 1.0 (or you explicitly set protocol_version: 0.x), your code uses the Hub/HubInterface API (not the removed Publisher API), and any jwt.secret hub config defines iss, sub, and client_id in jwt.claims — otherwise the container fails to compile, which is a deploy-time failure, not a runtime one.
    • Your hub sits behind a different internal and public URL — as of 0.6.1 this now works out of the box for publications on protocol 1.0, with no resource_identifier needed.
  • Look elsewhere if:
    • You require bidirectional communication (use WebSockets via Ratchet or similar).
    • Clients are non-HTTP (desktop apps, legacy systems).
    • You need offline-first sync (consider Firebase or PouchDB).
    • Your team prefers JavaScript-first solutions (Socket.io, Ably).
    • Compliance mandates self-hosted WebSocket control (though self-hosting a Mercure hub remains an option).
    • You are pinned to a Mercure 0.x hub with no upgrade path and unwilling to carry the protocol_version: 0.x override long term. (The 0.6.1 aud change applies to protocol 1.0 publisher tokens only, so 0.x overrides see no behavior change.)
    • You are on a pre-0.6 codebase that heavily uses the legacy Publisher/StaticJwtProvider APIs and cannot absorb the migration now — pin the current version and defer, but do not assume the deprecation-free path exists forever.
    • Your hub validates aud strictly against a fixed custom value rather than the hub URL — verify before upgrading, and override the claim explicitly if so.
    • You need token/session semantics significantly outside the hub's JWT model (note the 0.6.0 cookie rename to __Secure-mercure_access_token, and mercure_access_token under kernel.debug).

How to Pitch It (Stakeholders)

For Executives: "MercureBundle lets us deliver real-time updates—live notifications, dashboards, collaborative features—without the cost and complexity of WebSockets. The 0.6.x line is a maturity milestone: it defaults to the now-final Mercure 1.0 protocol, so we're building on a stable standard rather than a draft. It also lets us collapse infrastructure: an empty hub URL reliably runs Mercure inside FrankenPHP, so we can ship real-time as part of the app binary instead of standing up and operating a separate service. Operationally we gain per-hub HTTP clients (so one slow hub can't stall requests) and separate signing keys for publishers and subscribers (better least-privilege and rotation). The 0.6.1 patch additionally removes a piece of bespoke configuration we used to need whenever the hub's internal network address differed from its public hostname — fewer environment-specific knobs, fewer ways for a deploy to be subtly wrong. The cost is a one-time migration: 0.6.0 removed the old Publisher APIs and requires explicit JWT claims in config. That's a scheduled, contained piece of work — worth doing now while the surface is small, and it clears the deprecated code paths that were firing warnings on every boot. MIT-licensed, Symfony-backed, low risk."

For Engineers: *"0.6.1 is a one-line patch on top of 0.6.0 — no BC breaks. It adds the hub url to the default aud claim of protocol 1.0 publisher tokens, which is where those tokens are actually sent. Concretely: if the hub is addressed internally (http://hub:80) but publicly known as something else, publications are accepted without setting resource_identifier. Upgrade, then delete that override if you added it for this reason, and re-run your publish path against the real hub topology. If any hub-side validation pins aud to a custom value, set the claim explicitly.

Everything from 0.6.0 still applies. What you get:

  • Protocol 1.0 by default — set protocol_version: 0.x to stay on an old hub; also accepts ProtocolVersion enum cases.
  • Runtime hub selection — Hub vs FrankenPhpHub chosen by a factory, not at container build time. Empty url (unset MERCURE_URL, all Compose can express) reliably selects FrankenPHP's hub, autowirable via HubInterface. url/public_url default to null unconditionally.
  • Per-hub http_client — publish through a dedicated/scoped client with a short timeout instead of the global one.
  • Autowirable RemoteHubInterface — globally for the default remote hub, per hub via named arguments.
  • Per-hub publisher/subscriber — separate signing keys as an alternative to a single jwt.
  • symfony/mercure ^0.9 support.
  • Bug fixes — default_hub pointing at an undefined hub now raises a config error instead of a TypeError; TraceableHub no longer accumulates previous requests' messages in long-running processes (FrankenPHP worker mode).

Breaking changes to plan for (from 0.6.0; 0.6.1 adds none):

  • Legacy Publisher / PublisherInterface / TraceablePublisher services and aliases, plus StaticJwtProvider (mercure.hub.*.jwt_provider), are gone. Migrate to Hub / HubInterface / TraceableHub and StaticTokenProvider (mercure.hub.*.jwt.provider). Side benefit: no more symfony/mercure 0.5 deprecations on every container boot.
  • MercureDataCollector::getPublishers() removed — use getHubs().
  • jwt.secret hubs must declare iss, sub, client_id in jwt.claims, or container compilation fails.
  • Default access-token cookie is now __Secure-mercure_access_token (mercure_access_token when kernel.debug, matching the hub's playground default). Audit any custom subscriber clients or integration tests that read the cookie name.

Other tradeoffs: not for bidirectional comms; requires HTTP/2 (falls back gracefully); hubs may be third-party (self-hosting available); pre-1.0 versioning means more BC breaks ahead — pin the version. The 0.6.1 aud default is convenient but is behavior, not contract; don't build authorization logic on top of it.

Next steps:

  1. Upgrade spike: branch, bump to 0.6.1, grep for Publisher/PublisherInterface/TraceablePublisher/StaticJwtProvider, add required jwt.claims, compile the container (this is where failures surface).
  2. Hub readiness: confirm hub is Mercure 1.0, or set protocol_version: 0.x as a documented stopgap.
  3. Config cleanup: remove resource_identifier overrides that existed only to bridge internal/public hub URLs, and verify publishing still succeeds against the deployed hub topology.
  4. Pilot: use for a live dashboard or notification feature; benchmark latency vs. polling/WebSockets.
  5. Scale: evaluate hub hosting (self-hosted vs. Mercure.rocks vs. embedded FrankenPHP) and add per-hub http_client timeouts where hub calls are on a request path.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log