Files
2026-05-27 23:29:53 +01:00

4.3 KiB

Tasks: enterprise-websocket-gateway

Change ID: enterprise-websocket-gateway Package: @suaveplan/websocket-gateway Target path: api/framework/websocket-gateway Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/types, @suaveplan/logger, @suaveplan/events, @suaveplan/rate-limiter, @suaveplan/api


1. Scaffold

  • Create api/framework/websocket-gateway/ with all subdirs per layout.
  • package.json v0.0.0, "sideEffects": false, subpath exports.
  • tsconfig.json extending library-node.json.
  • vitest.config.ts via createTestConfig().
  • Scripts: lint, typecheck, test, test:coverage, build, docs:check, bench.

2. Types and errors

  • src/types/common.ts — all interfaces and types listed in proposal.
  • src/types/common.md (≥200 words, both examples).
  • src/errors/ws-errors.ts — 6-code union, metadata, registerWsGatewayErrorCodes().
  • ws-errors.test.ts and ws-errors.md.

3. Connection

  • WsConnection class: id (UUID), userId, tenantId, topics: Set<string>, outbound sendQueue (bounded ring buffer of size sendQueueSize).
  • subscribe(topic) / unsubscribe(topic).
  • send(message) — enqueue; drop oldest + increment ws.queue_drops_total if full.
  • close() — flush queue, call ws.close().
  • connection.test.ts: subscribe/unsubscribe, send queued, queue-full drops oldest, close flushes.
  • connection.md.

4. Heartbeat

  • HeartbeatManager: sends ping every heartbeatIntervalMs; schedules pingTimeoutMs deadline per connection; on pong received, cancel deadline; on deadline exceeded, close connection.
  • Injectable Clock for testability.
  • heartbeat.test.ts: pong received cancels deadline, deadline exceeded closes connection.
  • heartbeat.md.

5. WS Router

  • WsRouter: registers on(type: string, handler: WsMessageHandler) handlers; routes inbound messages by message.type.
  • WsMessageEnvelopeSchema (Zod) validates every inbound message; invalid → WsGatewayError(WS_INVALID_MESSAGE).
  • ws-router.test.ts: known type routed, unknown type → error, invalid envelope → error.
  • ws-router.md.

6. Gateway

  • createWebSocketGateway(options):
    • Maintains connections: Map<string, WsConnection>.
    • handleUpgrade(app, path) — registers Hono WebSocket route.
    • On connect: auth via options.authenticate; max-connections check; create WsConnection; start heartbeat; emit ws:connected event.
    • On message: rate-limit check; validate + route via WsRouter.
    • On disconnect: remove from map; stop heartbeat; emit ws:disconnected event.
    • publish(topic, message) — fan out to all connections subscribed to topic.
    • broadcast(message) — fan out to all connections.
    • close() — close all connections gracefully.
  • OTel: ws.connections_active gauge updated on connect/disconnect; counters + histograms on message receive/send.
  • gateway.test.ts (≤500 lines): connect + auth, auth failure closes ws, max-connections rejects, publish to topic, broadcast, rate-limited message dropped.
  • gateway.md.

7. Hono adapter

  • createHonoWsAdapter(gateway: WebSocketGateway): (app: HonoApp, path: string) => void — wraps Hono upgradeWebSocket; bridges native ws events to gateway lifecycle.
  • hono-ws-adapter.test.ts: upgrade handled, message forwarded.
  • hono-ws-adapter.md.

8. Benchmarks (src/__benchmarks__/ws-gateway.bench.ts)

  • ws_message_routing: route 10 000 messages through WsRouter with 5 registered handlers.
  • ws_publish_100_connections: publish() to a topic with 100 subscribers.

9. Integration tests (tests/integration.test.ts)

  • Start a real Hono server + WebSocket gateway; connect N clients; send messages; assert routing + heartbeat + disconnect.

10. Docs and publish

  • All co-located .md files (≥200 words, both examples, API reference).
  • Root README.md.
  • bunx turbo lint typecheck test --filter=@suaveplan/websocket-gateway — green.
  • bunx turbo test:coverage --filter=@suaveplan/websocket-gateway — 100%.
  • bun scripts/publish.ts --package @suaveplan/websocket-gateway.
  • Archive → openspec/archive/2026-04-24-enterprise-websocket-gateway/.