milpa/mercure

Mercure hub publisher for the Milpa PHP framework: self-signed JWT generation and SSE publish over cURL.

Maintainers

Package info

github.com/getmilpa/mercure

pkg:composer/milpa/mercure

Transparency log

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-07-07 18:28 UTC

This package is auto-updated.

Last update: 2026-07-07 19:45:47 UTC


README

Milpa

Milpa Mercure

The Mercure hub publisher for the Milpa PHP framework, with zero package dependencies. One class, MercureService, mints self-signed HS256 JWTs by hand and pushes real-time updates to a Mercure hub over curl_* directly — no HTTP client abstraction, no milpa/core at runtime.

CI Packagist PHP License Docs

milpa/mercure is the smallest possible seam onto a Mercure hub: sign a publisher JWT, POST a topic + JSON payload to the hub's /.well-known/mercure endpoint, and mint short-lived subscriber JWTs for the browser's EventSource connection. No ORM, no event dispatcher, no framework coupling — construct it with four strings and call publish().

Install

composer require milpa/mercure

Quick example

use Milpa\Mercure\MercureService;

$mercure = new MercureService(
    hubUrl: 'https://hub.internal/.well-known/mercure',      // server-side POST target
    publicUrl: 'https://hub.example.com/.well-known/mercure', // what the browser connects to
    publisherKey: $_ENV['MERCURE_PUBLISHER_JWT_KEY'],
    subscriberKey: $_ENV['MERCURE_SUBSCRIBER_JWT_KEY'],
);

// Server-side: push an update. Mints a 60s publisher JWT, POSTs form-encoded
// topic + JSON data, throws RuntimeException on cURL failure or HTTP >= 400.
$mercure->publish('conversations/42/messages', [
    'event' => 'message.created',
    'body' => 'hello',
]);

// Browser-side: mint a 5-minute subscriber JWT scoped to the topics this
// visitor may listen to, and hand the browser the public URL to connect to.
$jwt = $mercure->generateSubscriberJwt(['conversations/42/messages']);
$publicUrl = $mercure->getPublicUrl();

The browser then opens new EventSource(publicUrl + '?topic=...', { withCredentials: true }) with $jwt set as the mercureAuthorization cookie — standard Mercure subscribe flow, nothing Milpa-specific about it.

What it does — and doesn't

  • publish(string $topic, array $data) — signs a 1-minute publisher JWT scoped to $topic, form-encodes topic + json_encode($data), and POSTs it to hubUrl with Authorization: Bearer <jwt>. A curl_init() failure, a curl_exec() failure, or an HTTP status >= 400 all throw RuntimeExceptionpublish() never fails silently.
  • generateSubscriberJwt(array $topics) — a 5-minute HS256 JWT whose payload is {"mercure":{"subscribe":$topics},"exp":...}, signed with subscriberKey. This is the token a browser presents to subscribe; it grants no publish access.
  • getPublicUrl() — returns the publicUrl given to the constructor, unmodified. Kept separate from hubUrl because the two are commonly different: the server publishes to an internal/Docker-network hostname, while the browser subscribes through a public one.

Both JWTs are HS256, hand-assembled from header.payload.signature with hash_hmac() + base64url — no JWT library dependency. There is no retry, no queue, and no HTTP client abstraction to inject: publish() talks to curl_* directly, by design (see Requirements).

Requirements

  • PHP ≥ 8.3 with the cURL extension enabled (ext-curl)
  • Nothing else — milpa/mercure has no package dependencies, Milpa or otherwise

Documentation

Full API reference: getmilpa.github.io/mercure — generated straight from the source DocBlocks and dressed with the Milpa design system.

Contributing

Contributions are welcome — see CONTRIBUTING.md. Please report security issues via SECURITY.md, and note that this project follows a Code of Conduct.

License

Apache-2.0 © TeamX Agency.

Milpa is designed, built, and maintained by TeamX Agency.