feat: upgrade to Mercure 1.0 (#2611)
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:
https://github.com/crazywhalecc/static-php-cli/pull/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.