Add the mercure preset - #26
Merged
Merged
Conversation
geodro
force-pushed
the
feat/mercure-preset
branch
from
September 17, 2026 13:36
20f1e7f to
b11ef1e
Compare
Realtime in a Symfony project means Mercure, the way it means the Pusher protocol in a Laravel one. Soketi covers that side already and this covers the other: a site gets MERCURE_URL, MERCURE_PUBLIC_URL and MERCURE_JWT_SECRET, which are the keys the Symfony recipe writes into a new project, so the bundle picks them up without being configured. The two URLs are not a duplicate. The browser subscribes to the hub directly and needs the published address, while PHP publishes to it over the lerd network under its container name, and the bundle keeps them apart for exactly that reason. The hub's own Caddyfile is mounted rather than assembled from MERCURE_EXTRA_DIRECTIVES, because the three subdirectives this needs are newline separated and a container environment value cannot carry a newline: anonymous subscribers, since a local hub has no reason to demand a token to read, open CORS, and the debug UI. There is no transport_url in it either: 0.20 dropped the Bolt transport, so the hub keeps its history in memory and has nothing to persist between restarts, which is also why the preset declares no data directory. No dashboard yet. The UI sits at a fixed path under /.well-known and cannot be told a mount path, so embedding it needs the proxy's prefix-stripping mode, and a lerd without that would frame the port directly and get an empty box, since the hub answers X-Frame-Options: deny.
geodro
force-pushed
the
feat/mercure-preset
branch
from
September 17, 2026 14:30
b11ef1e to
f44bcd6
Compare
The store now renders one published tree per schema, so the preset moves to sources/ and the trees are regenerated from it. Rendered to schema 1 it carries no dashboard, since the mercure UI refuses framing and schema 1 has no proxy to strip that, and rendered to schema 2 it carries the dashboard and the strip flag.
The preset carries a dashboard that only works behind the schema 2 proxy, so it is authored there and rendered down: schema 1 publishes it without a dashboard rather than with one that cannot be framed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Realtime in a Symfony project means Mercure, the way it means the Pusher protocol in a Laravel one. Soketi already covers that side; this covers the other. A site gets MERCURE_URL, MERCURE_PUBLIC_URL and MERCURE_JWT_SECRET, which are the keys the Symfony recipe writes into a new project, so the bundle picks them up with no configuration.
The two URLs are not a duplicate of each other. The browser subscribes to the hub directly and needs the published address, while PHP publishes over the lerd network under the container name, and the bundle keeps them apart for exactly that reason.
The Caddyfile is mounted rather than assembled from MERCURE_EXTRA_DIRECTIVES, because the three subdirectives needed are newline separated and a container environment value cannot carry a newline: anonymous subscribers, since a local hub has no reason to demand a token to read, open CORS, and the debug UI. It carries no transport_url: 0.20 dropped the Bolt transport, so the hub keeps its history in memory and has nothing to persist, which is why there is no data directory either.
Tried end to end on a real Symfony 8 site with symfony/mercure-bundle installed. A page subscribing through the bundle's mercure() Twig helper received updates published from a controller, from curl, and from a Laravel project on the same machine, each arriving without a reload. Laravel works because the wiring is the same three keys and publishing is an HTTP POST, though Echo speaks the Pusher protocol and will not talk to this, so soketi remains the right answer there.
The dashboard is included and working: the overlay embeds the UI through the proxy's prefix-stripping mode, which also drops the framing header it answers with. That mode is in lerd-env/lerd#1841, so this preset needs the release that carries it. Merging it before then would put an empty box in front of everyone who has not upgraded, because an older lerd ignores dashboard_proxy_strip and frames the port directly. Hold this until that ships.
The mark is the one from mercure.rocks reduced to paths, and the colour is the saturated end of their brand gradient.