WebSocket API

Event Broker WebSocket

The sub, unsub and pub operations, the message delivery, and every reply and error, with frames.

Endpoint: wss://api.thuum.dev/api/{domain}/event/connect?token=…. The connection needs a key linked to an Event Broker claim. Framing, refs and general errors are on WebSocket protocol.

Operations#

OpFieldsFlagReply
subtopic, ref?Ssub:ok
unsubtopic, ref?—unsub:ok
pubtopic, type, data, ref?Ppub:ok with id, ts

The server pushes one more op, message, for each delivered event.

sub#

Subscribe to a topic and its whole subtree. Idempotent: subscribing twice is not an error and doesn't duplicate deliveries.

JSON
→ [{ "op": "sub", "topic": "orders", "ref": "1" }]
← [{ "op": "sub:ok", "topic": "orders", "ref": "1" }]

From then on, every event published on orders or any orders:* topic arrives as a message. Events published before the sub:ok are not delivered: read them from history.

unsub#

Stop receiving a topic's events. Idempotent, and needs no flag. Unsubscribing from orders doesn't affect a separate subscription to orders:1042.

JSON
→ [{ "op": "unsub", "topic": "orders", "ref": "2" }]
← [{ "op": "unsub:ok", "topic": "orders", "ref": "2" }]

pub#

Publish an event on exactly topic. The reply comes after the event is stored and broadcast, and carries the server-generated id and ts.

JSON
→ [{ "op": "pub", "topic": "orders:1042", "type": "order.shipped", "data": { "carrier": "DHL" }, "ref": "3" }]
← [{ "op": "pub:ok", "topic": "orders:1042", "ref": "3", "id": "5bac385f-e73a-48c2-a505-8f1f8caa3c85", "ts": 1792590697447 }]

Only topic, type and data are used: you cannot choose the id or the timestamp.

message#

One frame per delivered event, with the exact topic it was published on:

JSON
← [{ "op": "message", "id": "5bac385f-e73a-48c2-a505-8f1f8caa3c85", "topic": "orders:1042", "type": "order.shipped", "data": { "carrier": "DHL" }, "ts": 1792590697447 }]

If the publishing connection is itself subscribed, it receives its message too, in addition to pub:ok. The order between the two is not guaranteed.

Errors#

JSON
→ [{ "op": "pub", "topic": "orders:1042", "type": "bad type", "data": 1, "ref": "4" }]
← [{ "op": "pub:error", "topic": "orders:1042", "ref": "4", "code": "bad_request", "message": "type …" }]

→ [{ "op": "sub", "topic": "payroll", "ref": "5" }]
← [{ "op": "sub:error", "topic": "payroll", "ref": "5", "code": "forbidden", "message": "Missing S claim on topic" }]
OpPossible codes
subbad_request (invalid topic), forbidden
unsubbad_request (invalid topic)
pubbad_request, forbidden, internal

With the client#

TypeScript
const socket = acme.eventBroker.connect();
socket.onMessage((event) => console.log(event));
await socket.ready;

await socket.sub('orders');
const { id, ts } = await socket.pub('orders:1042', 'order.shipped', { carrier: 'DHL' });
await socket.unsub('orders');
socket.close();

Failed ops reject with EventBrokerSocketError, whose code is one of the codes above, or closed if the connection dropped first. See Sockets.