Skip to content

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/.

LayerDescription
ElysiaNative .ws() for WebSocket; OpenAPI for REST docs.
Sub-socket storeMap<topic, Set<connectionId>>; O(1) subscribe, O(subscribers) broadcast per topic.
BackboneIn-memory for single-node; replace with NATS/Kafka for horizontal scale.
DedupIn-memory by messageId per userId (I₂); use Redis for multi-instance.
AuthDemo: any non-empty token → userId; use JWT + ACL in production.

Run the Example

bash
cd examples/elysia-micro-socket
bun install
bun run dev
ResourceURL
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)
StatsGET http://localhost:3000/stats
Demo publishGET 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

MethodPathDescription
GET/docsSingle-page API docs and WebSocket playground (connect, send WS messages, view log).
GET/openapiOpenAPI (Scalar) UI for REST only.
GET/statsReturns { connections, topics, subscriptions }.
GET/demo/publish/:topicQuery 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

EndpointUse case
ws://host/wsOne connection, multiple topics: send setup then subscribe per topic (or use setup.topics).
ws://host/ws/sub/:topicSub 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)

typeDescriptionJSON body
setupAuthenticate and optionally auto-subscribe. Required first (after connect).{ "type": "setup", "token": "<non-empty>", "topics": ["prices", "alerts"] } (topics optional)
subscribeSubscribe to a topic (requires prior setup).{ "type": "subscribe", "topic": "prices" }
unsubscribeUnsubscribe from a topic.{ "type": "unsubscribe", "topic": "prices" }
publishPublish to a topic (dedup by messageId per user).{ "type": "publish", "topic": "orders", "messageId": "idempotency-key", "payload": { ... } }

Server → Client (responses you receive)

typeWhen
readyAfter successful setup. { "type": "ready", "sessionId": "<id>" }
subscribedAfter subscribe or auto-subscribe (URL or setup.topics). { "type": "subscribed", "topic": "<topic>" }
unsubscribedAfter unsubscribe. { "type": "unsubscribed", "topic": "<topic>" }
messageBroadcast to a topic you are subscribed to. { "type": "message", "topic", "seqNo", "messageId", "data" }
ackAfter publish. { "type": "ack", "messageId", "status": "ok" | "duplicate" }
errorOn auth failure, ACL, invalid message, etc. { "type": "error", "code", "message" }

Sending WebSocket Requests from the Docs

  1. Open http://localhost:3000/docs.
  2. In the WebSocket section:
    • URL: Choose Multi-topic (/ws) or Sub: prices (/ws/sub/prices) (or type any WS URL).
    • Click Connect.
  3. Send requests:
    • Message: setup — fill token (e.g. demo-user); optionally topics (e.g. prices,alerts) for /ws. Click Send. You should see ready and optionally subscribed in the log.
    • Then subscribe / unsubscribe / publish as needed; each click Send sends one JSON frame and responses appear in the log.

So all WebSocket “istek” (requests) are sent from this page; no extra tool required.


Sub WebSocket Flow

  1. Connect to ws://host/ws/sub/prices (or /ws with setup.topics: ["prices"]).
  2. Send setup with token. Server sets userId and, for /ws/sub/:topic, auto-subscribes to prices; you get subscribed then ready.
  3. From then on you only receive message frames for topics you are subscribed to (e.g. prices).
  4. 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

InvariantIn this example
I₁ ACLDemo auth only; add topic–user checks for production.
I₂ DedupmessageId per userId before publish; ack duplicate.
I₃ OrderingPer-topic seqNo; clients can use lastSeq.
I₄ DeliveryAt-least-once; add ACK/retry/replay for exactly-once if needed.
I₅ SLOAdd latency metrics and expose in /stats or Prometheus.
I₆ ResumeProtocol supports resume; add session store + replay for production.
I₇ IntegrityUse TLS in production; optional message signing.

Star the repo on GitHub if this documentation is useful — link in the navbar above.