Elysia Example: Micro Socket Gateway
Full reference for the Elysia (Bun) Micro Socket gateway: HTTP and WebSocket endpoints, message protocol, sub-socket model, and how to send requests (including over WebSocket) from the docs UI.
Overview
The example lives in the repo under examples/elysia-micro-socket/.
| Layer | Description |
|---|---|
| Elysia | Native .ws() for WebSocket; OpenAPI for REST docs. |
| Sub-socket store | Map<topic, Set<connectionId>>; O(1) subscribe, O(subscribers) broadcast per topic. |
| Backbone | In-memory for single-node; replace with NATS/Kafka for horizontal scale. |
| Dedup | In-memory by messageId per userId (I₂); use Redis for multi-instance. |
| Auth | Demo: any non-empty token → userId; use JWT + ACL in production. |
Run the Example
bash
cd examples/elysia-micro-socket
bun install
bun run dev| Resource | URL |
|---|---|
| Docs (HTTP + WS playground) | http://localhost:3000/docs |
| OpenAPI (Scalar) | http://localhost:3000/openapi |
| WebSocket (multi-topic) | ws://localhost:3000/ws |
| WebSocket (sub, one topic) | ws://localhost:3000/ws/sub/:topic (e.g. ws://localhost:3000/ws/sub/prices) |
| Stats | GET http://localhost:3000/stats |
| Demo publish | GET http://localhost:3000/demo/publish/:topic?key=value |
On /docs you can connect to either WebSocket URL and send all message types (setup, subscribe, unsubscribe, publish) and see responses in the log.
HTTP API
| Method | Path | Description |
|---|---|---|
| GET | /docs | Single-page API docs and WebSocket playground (connect, send WS messages, view log). |
| GET | /openapi | OpenAPI (Scalar) UI for REST only. |
| GET | /stats | Returns { connections, topics, subscriptions }. |
| GET | /demo/publish/:topic | Query params are merged into message data and published to topic; all subscribers of that topic receive it. |
Example:
bash
curl "http://localhost:3000/stats"
curl "http://localhost:3000/demo/publish/prices?bid=100&ask=101"WebSocket Endpoints
| Endpoint | Use case |
|---|---|
ws://host/ws | One connection, multiple topics: send setup then subscribe per topic (or use setup.topics). |
ws://host/ws/sub/:topic | Sub WebSocket: one connection for one topic. After setup, server auto-subscribes to the topic from the path. |
All WebSocket frames are JSON. Same message protocol on both endpoints.
WebSocket Protocol (Request / Response)
Client → Server (requests you send)
| type | Description | JSON body |
|---|---|---|
setup | Authenticate and optionally auto-subscribe. Required first (after connect). | { "type": "setup", "token": "<non-empty>", "topics": ["prices", "alerts"] } (topics optional) |
subscribe | Subscribe to a topic (requires prior setup). | { "type": "subscribe", "topic": "prices" } |
unsubscribe | Unsubscribe from a topic. | { "type": "unsubscribe", "topic": "prices" } |
publish | Publish to a topic (dedup by messageId per user). | { "type": "publish", "topic": "orders", "messageId": "idempotency-key", "payload": { ... } } |
Server → Client (responses you receive)
| type | When |
|---|---|
ready | After successful setup. { "type": "ready", "sessionId": "<id>" } |
subscribed | After subscribe or auto-subscribe (URL or setup.topics). { "type": "subscribed", "topic": "<topic>" } |
unsubscribed | After unsubscribe. { "type": "unsubscribed", "topic": "<topic>" } |
message | Broadcast to a topic you are subscribed to. { "type": "message", "topic", "seqNo", "messageId", "data" } |
ack | After publish. { "type": "ack", "messageId", "status": "ok" | "duplicate" } |
error | On auth failure, ACL, invalid message, etc. { "type": "error", "code", "message" } |
Sending WebSocket Requests from the Docs
- Open http://localhost:3000/docs.
- In the WebSocket section:
- URL: Choose Multi-topic (
/ws) or Sub: prices (/ws/sub/prices) (or type any WS URL). - Click Connect.
- URL: Choose Multi-topic (
- Send requests:
- Message:
setup— fill token (e.g.demo-user); optionally topics (e.g.prices,alerts) for/ws. Click Send. You should seereadyand optionallysubscribedin the log. - Then subscribe / unsubscribe / publish as needed; each click Send sends one JSON frame and responses appear in the log.
- Message:
So all WebSocket “istek” (requests) are sent from this page; no extra tool required.
Sub WebSocket Flow
- Connect to
ws://host/ws/sub/prices(or/wswithsetup.topics: ["prices"]). - Send setup with
token. Server sets userId and, for/ws/sub/:topic, auto-subscribes toprices; you getsubscribedthenready. - From then on you only receive
messageframes for topics you are subscribed to (e.g.prices). - Optionally publish (same message format as on
/ws).
Architecture (Code Layout)
text
src/
index.ts - Elysia: /ws, /ws/sub/:topic, /docs, /stats, /demo/publish, OpenAPI
store.ts - Sub-socket store; pendingTopicsFromUrl for sub WebSocket
broadcast.ts - Fan-out to topic subscribers
backbone.ts - In-memory publish; simulateIncomingMessage for HTTP demo
dedup.ts - Idempotency (messageId)
auth.ts - Demo auth (token → userId)
types.ts - ClientMessage, ServerMessage, BackboneMessage
sub-socket-client.ts - Client: SubSocket.byUrl(), SubSocket.byTopics()
docs-html.ts - /docs page (HTTP + WS playground)Invariants
| Invariant | In this example |
|---|---|
| I₁ ACL | Demo auth only; add topic–user checks for production. |
| I₂ Dedup | messageId per userId before publish; ack duplicate. |
| I₃ Ordering | Per-topic seqNo; clients can use lastSeq. |
| I₄ Delivery | At-least-once; add ACK/retry/replay for exactly-once if needed. |
| I₅ SLO | Add latency metrics and expose in /stats or Prometheus. |
| I₆ Resume | Protocol supports resume; add session store + replay for production. |
| I₇ Integrity | Use TLS in production; optional message signing. |