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-adapterWave-1 refactor (server-side rooms need theTransportcontract 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/— mainWebSocketGatewaydaemonchannel/— channel multiplexingroom/— room semantics (join / leave / broadcast / direct)presence/— presence subsystem (who's in which room)types/— public type surfaceindex.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:
wsorbun:websocket(universal façade) — add to root catalog undernetwork-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
bunx turbo lint typecheck test --filter=@suaveplan/websocket-gatewaygreen.bunx turbo test:coverage --filter=@suaveplan/websocket-gateway100/100/100/100.bun run docs:checkgreen.- Integration test: 3 clients connect via
network-transport-websockets, join rooms, exchange messages, observe presence events. No mocks. STATUS.mdrow flipped.
Out of scope
- Production TLS termination (deployment concern).
- Cross-instance gateway clustering (federate via
@suaveplan/networkmesh in a future change). - Persistent room state (separate
websocket-gateway-store-*package if needed).