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

5.4 KiB

OpenSpec Change: websocket-gateway

  • Change ID: websocket-gateway
  • Package: @suaveplan/websocket-gateway
  • Category: server (Node-only)
  • Target path: packages/network/websocket-gateway
  • Status: PROPOSED
  • Date: 2026-05-11
  • Parent: network-transport-family (2026-05-11) — Wave 5
  • Migration source: ../suaveplan/packages/server/websocket-gateway + ../suaveplan/enterprise/websocket-gateway.md

Summary

Migrate @suaveplan/websocket-gateway into genesis as a server-tier daemon providing rooms + presence semantics over WebSocket connections. Pairs with @suaveplan/network-transport-websockets ✅ (post-Wave-1 adapter refactor) on the client side. Rooms scope message delivery; presence tracks who is connected to which room; channel multiplexing lets multiple logical streams share one TCP connection.


Why Wave 5 (not earlier)

  • Depends on the network-transport-websockets-adapter Wave-1 refactor (server-side rooms need the Transport contract on the client side).
  • Server-tier package — bundles with Wave-4 transports, not Wave-3 browser packages.

Current-state audit

Upstream coverage: 97.85% statement.

Upstream source layout (../suaveplan/packages/server/websocket-gateway/src/):

  • gateway/ — main WebSocketGateway daemon
  • channel/ — channel multiplexing
  • room/ — room semantics (join / leave / broadcast / direct)
  • presence/ — presence subsystem (who's in which room)
  • types/ — public type surface
  • index.ts — barrel

Parity Checklist

Capability Upstream Migrated Notes
WebSocketGateway daemon ✅ ✅
Room semantics (join/leave/broadcast/direct) ✅ ✅
Presence tracking ✅ ✅
Channel multiplexing ✅ ✅
Plugin wiring via @suaveplan/api definePlugin() upstream-required ⬆️ Once @suaveplan/api lands on genesis (not yet ✅), wire via definePlugin(). Until then a standalone start()/stop() lifecycle.
JWT auth via @suaveplan/jwt-tenant upstream-required ⬆️ Once shipped on genesis. Until then inject AuthVerifier callback.
RBAC/ABAC via @suaveplan/permissions upstream-required ⬆️ Same: inject AuthorizationCheck callback.
Rate-limiting via @suaveplan/rate-limiter upstream-required ⬆️ Once available.
Idempotency via @suaveplan/idempotency ✅ upstream-required ✅ Wired directly.
Audit logging via @suaveplan/audit-logging upstream-required ⬆️ Once available. Until then @suaveplan/logger ✅ with structured fields.
OTel spans + Prometheus metrics upstream-required ⬆️ Spans ws_gateway.connect/message/broadcast, counters ws_gateway.rooms_active, ws_gateway.presence_updates_total, histograms ws_gateway.message_dispatch_ms.
AbortSignal everywhere partial ⬆️ Threaded through every lifecycle method.
Retry + circuit breakers via @suaveplan/retry ✅ upstream-required ✅ Wired on every outbound integration.
Health / readiness / liveness upstream-required ⬆️ Inline /health, /ready, /live endpoints until @suaveplan/health-check lands.
Webhooks via @suaveplan/webhook-client ✅ upstream-required ✅ Wired for presence-event webhooks.
Structured errors 🚫 ⬆️ defineCodes("WS_GATEWAY", [...]): ROOM_NOT_FOUND, ROOM_FULL, CHANNEL_INVALID, AUTH_REJECTED, RATE_LIMITED, INVALID_OPTIONS.
Zod boundary validation partial ⬆️ Every public option + every wire frame.
export * barrels check ⬆️ Convert to explicit named exports per §6a.
Test-runner imports direct vitest ⬆️ Rewrite to @suaveplan/testing/runner per §7.
100% test coverage 🚫 (97.85%) ⬆️ Bring to 100/100/100/100.
Integration tests partial ⬆️ Real-server boot via @suaveplan/testing-integration; no mocks.

Available workspace deps on genesis

  • @suaveplan/network-transport-websockets ⬅ post-Wave-1 (after adapter refactor)
  • @suaveplan/idempotency ✅
  • @suaveplan/retry ✅
  • @suaveplan/webhook-client ✅
  • @suaveplan/logger ✅
  • @suaveplan/error, @suaveplan/types, @suaveplan/events, @suaveplan/timing ✅
  • @suaveplan/testing + @suaveplan/testing-integration ✅
  • External: ws or bun:websocket (universal façade) — add to root catalog under network-server.

Blocking note. Migration can start once network-transport-websockets-adapter ships and (optionally) @suaveplan/api, @suaveplan/jwt-tenant, @suaveplan/permissions, @suaveplan/rate-limiter, @suaveplan/audit-logging, @suaveplan/health-check are on genesis. Auth and rate-limit hooks accept callbacks until those packages land.


Acceptance gate

  1. bunx turbo lint typecheck test --filter=@suaveplan/websocket-gateway green.
  2. bunx turbo test:coverage --filter=@suaveplan/websocket-gateway 100/100/100/100.
  3. bun run docs:check green.
  4. Integration test: 3 clients connect via network-transport-websockets, join rooms, exchange messages, observe presence events. No mocks.
  5. STATUS.md row flipped.

Out of scope

  • Production TLS termination (deployment concern).
  • Cross-instance gateway clustering (federate via @suaveplan/network mesh in a future change).
  • Persistent room state (separate websocket-gateway-store-* package if needed).