SSE Driver
The SSE Driver is a signaling driver that uses Server-Sent Events for receiving real-time updates from Mercure-compatible servers over an HTTP connection. It uses standard HTTP POST requests for publishing messages to the server and an SSE stream for receiving messages from the server. This makes it a good choice when you want a simple, browser-friendly real-time transport without depending on WebSockets.
Usage
To use the SSE Driver, import the driver from Peerix, point it at your server endpoint, and create an instance:
import { SseDriver } from 'peerix';
const publisherJwtKey = 'mercure-publisher-jwt-key';
const driver = new SseDriver({
url: 'http://localhost:8080/.well-known/mercure',
publisher: {
headers: {
Authorization: `Bearer ${publisherJwtKey}`,
},
},
});The url option should point to a server endpoint that can both open an SSE stream for incoming updates and accept POST requests for outbound messages. You can provide additional options for publisher (fetch options) and subscriber (EventSource options) as needed. All peers that connect to the same server endpoint can discover each other and exchange signaling messages.
You can use this JWT publisher key with the Mercure server’s default configuration for testing purposes:
eyJhbGciOiJIUzI1NiJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsiKiJdLCJzdWJzY3JpYmUiOlsiKiJdfX0.bVXdlWXwfw9ySx7-iV5OpUSHo34RkjUdVzDLBcc6l_g
Message Flow
The SSE Driver uses two transport directions: HTTP POST from peer to server for outgoing messages, and SSE from server to peers for incoming messages.
sequenceDiagram
participant A as Peer A
participant S as SSE Server
participant B as Peer B
A->>S: GET /.well-known/mercure?topic=... (open SSE stream)
B->>S: GET /.well-known/mercure?topic=... (open SSE stream)
A->>S: POST /.well-known/mercure?topic=... (signal payload)
S-->>B: SSE event: data: payload
B->>S: POST /.well-known/mercure?topic=... (signal payload)
S-->>A: SSE event: data: payload
Backend Server
You can deploy a self-hosted Mercure server or create your own custom SSE server that follows the same conventions.
Here is a simple Node.js example that implements the required endpoints for the SSE Driver:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(cors({ origin: true, credentials: true }));
const namespaces = new Map();
// route for outgoing messages (subscribe/stream)
app.get('/.well-known/mercure', (req, res) => {
const { topic } = req.query;
if (!topic) return res.status(400).end();
// support multiple topics in a single request
const topics = Array.isArray(topic) ? topic : [topic];
for (const t of topics) {
const clients = namespaces.get(t) || new Set();
namespaces.set(t, clients);
clients.add(res);
}
// set headers to establish the SSE stream
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.flushHeaders();
// clean up if the browser closes the page or disconnects
req.on('close', () => {
for (const t of topics) {
const clients = namespaces.get(t);
if (clients) {
clients.delete(res);
if (!clients.size) namespaces.delete(t);
}
}
res.end();
});
});
// route for incoming messages (publish)
app.post('/.well-known/mercure', (req, res) => {
const { topic, data = '' } = req.body || {};
if (topic) {
const topics = Array.isArray(topic) ? topic : [topic];
for (const t of topics) {
const clients = namespaces.get(t);
if (clients) {
for (const client of clients) {
client.write(`data: ${data}\n\n`);
}
}
}
}
res.status(200).end();
});
app.listen(8080);This example uses the Express and CORS modules, so install them in your project:
npm install express corsIn this setup, each topic acts like a signaling channel. When one peer posts a message, the server relays it to every other connected client in the same topic through the SSE stream.