Skip to content

frankenphp: build the Mercure hub with its 0.x compatibility tags - #1240

Merged
henderkes merged 1 commit into
crazywhalecc:v3from
dunglas:frankenphp-mercure-compat-tags
Sep 8, 2026
Merged

henderkes merged 1 commit into
crazywhalecc:v3from
dunglas:frankenphp-mercure-compat-tags

Conversation

@dunglas

@dunglas dunglas commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Mercure 1.0 (https://github.com/dunglas/mercure/releases/tag/v1.0.0-alpha.3) gates its 0.x behaviors behind two build tags, deprecated_topic and deprecated_claim, and only honors them when the Caddyfile sets protocol_version_compatibility 8. Without the tags, a hub in compatibility mode rejects 0.x tokens and topic= selectors outright.

FrankenPHP is adopting the 1.0 hub in php/frankenphp#2611 and ships both tags in its Docker images and CI builds, like the official Mercure binaries, so users can migrate progressively. Static binaries take their -tags list from here, and GOFLAGS cannot add to a -tags given on the command line, hence this change.

Go ignores unknown build tags, so FrankenPHP versions still on Mercure 0.24 build unchanged.

Mercure 1.0 gates its 0.x behaviors (legacy mercure claim, topic= selectors)
behind the deprecated_topic and deprecated_claim build tags, only honored
when the Caddyfile sets protocol_version_compatibility 8. FrankenPHP ships
them in its Docker images and CI builds so users can migrate progressively;
static binaries get their tags from here.

Go ignores unknown tags, so FrankenPHP versions still on Mercure 0.x build
unchanged.
@henderkes

Copy link
Copy Markdown
Collaborator

For this to take any effect, we need to switch to spc v3 which is still open because I don't have a mac to fix x86.

@henderkes
henderkes merged commit c81da11 into crazywhalecc:v3 Sep 8, 2026
8 checks passed
henderkes added a commit that referenced this pull request Sep 8, 2026
dunglas added a commit to php/frankenphp that referenced this pull request Sep 30, 2026
Upgrades `github.com/dunglas/mercure` and
`github.com/dunglas/mercure/caddy` from `v0.24.2` to `v1.0.2`, and
adapts the integration to the protocol changes of
[draft-dunglas-mercure-08](https://mercure.rocks/spec).

## `mercure_publish()`

The hub validates updates before dispatching them, so the function now
distinguishes the caller's mistakes from a failed publication:

- a `ValueError` carrying the reason for a topic addressing the reserved
`/.well-known/mercure` namespace or equal to `*`, an `$id` starting with
`#` or equal to `earliest`, a `$type` equal to `mercure`, control
characters, invalid UTF-8 `$data`, or no topic at all;
- a `RuntimeException` with the message of the hub when the dispatch
fails.

The negative values of `$retry` are also rejected, as the protocol only
allows digits in that field.

An enum in `frankenphp.h` replaces the status codes
`go_mercure_publish()` returned as bare integers. On the way, an array
of topics that cannot be converted no longer reports `No Mercure hub
configured`.

## Hot reloading

The subscribe query parameter of the protocol is `match`, so
`$_SERVER['FRANKENPHP_HOT_RELOAD']` advertises
`/.well-known/mercure?match=<topic>`. The `topic` parameter it replaces
is only honored by a hub built with the `deprecated_topic` tag, which
FrankenPHP doesn't set.

## Hub configuration

Setting `publisher_jwt` or `subscriber_jwt` without
`protocol_version_compatibility` is a configuration error now, because
that mode also drops the required `exp`, the audience check, the
`at+jwt` check and the issuer check. The keys are bound to a trusted
issuer instead:

```caddyfile
mercure {
	issuer {$MERCURE_TRUSTED_ISSUERS:https://localhost} {
		publisher {
			jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
		}
		subscriber {
			jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
		}
	}
}
```

`php-server --mercure` and the sample `Caddyfile` follow.
`MERCURE_TRUSTED_ISSUERS` accepts several identifiers separated by
commas or whitespace, all bound to the same keys.

FrankenPHP is built with the `deprecated_topic` and `deprecated_claim`
tags of the hub, like the official Mercure binaries, so
`protocol_version_compatibility 8` accepts the 0.x tokens and `topic=`
selectors during a migration. Static builds get the tags through
static-php-cli:
crazywhalecc/static-php-cli#1240.

## Docs

`docs/mercure.md` and the Laravel Octane section of `docs/laravel.md`
describe the 1.0 configuration. Octane writes each entry of its
`mercure` array as a `Caddyfile` line, so the `issuer` block is passed
as a multi-line value (verified with `caddy adapt` and a live hub). The
Symfony example targets [symfony/mercure
0.8](https://github.com/symfony/mercure/releases/tag/v0.8.0), which
ships `ProtocolVersion::V1`.

The translations of `docs/mercure.md` and `docs/laravel.md` still
describe the 0.x configuration.

The other Go dependencies are updated on the way.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants