3.2 KiB
@suaveplan/api-ws-broker-in-memory — In-memory WebSocket broker for tests
Package: @suaveplan/api-ws-broker-in-memory
Status: PROPOSED
Type: new-package
Stage: 5 (Testing kit + conformance suites) — see umbrella openspec/changes/api-plugin-foundation/
Why
Per design doc §11, api-ws defines a WsBroker abstraction for subscription fan-out. Multi-host deployments wire this to Redis via api-ws-broker-redis (Stage 7). For tests AND single-host development, an in-memory broker is sufficient — it pumps published messages directly to every interested connection without crossing a network.
The package is a load-bearing piece of createTestHost: any plugin manifesting WebSocket endpoints can be tested end-to-end (connect → subscribe → publish → assert received) without spinning up Redis. The broker is production-grade for single-host topologies; "in-memory" describes implementation, not test-double status.
What changes
Net-new package depending on @suaveplan/api-ws (contract + ./testing conformance), @suaveplan/api-types, @suaveplan/error, zod.
- ADDED:
createInMemoryWsBroker(opts)— factory returning aWsBroker(per@suaveplan/api-types) that maintains a per-subscription-topic set of connection ids and apublish(topic, message)method that delivers to every subscriber in O(subscribers). - ADDED:
InMemoryWsBrokerOptions— Zod schema (maxSubscribersPerTopic?: number(default unlimited),deliveryMode: "fire-and-forget" | "await-all"(default"fire-and-forget")). - ADDED:
subscribe(connectionId, topic),unsubscribe(connectionId, topic),publish(topic, message),subscribersOf(topic),cleanupConnection(connectionId). - ADDED:
WS_BROKER_IN_MEMORY_*error codes (WS_BROKER_IN_MEMORY_MAX_SUBSCRIBERS_EXCEEDED,WS_BROKER_IN_MEMORY_INVALID_OPTIONS). - ADDED: Registered in
@suaveplan/api-host/testing's adapter table asws.broker: "in-memory"(default forcreateTestHost).
Out of scope
- Network distribution — by design.
- Reconnect token persistence — that lives in the WebSocket engine (
api-ws-bunStage 7), not the broker. - Message persistence — broker is fan-out only; tests assert via
host.ws.connectionsOf(topic)and direct connection observation.
Source mapping
Genesis-original. Source of design intent: docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md.
| Requirement | Design doc section |
|---|---|
| Subscription bus + broker abstraction | §11.2, §11.3 |
| Single-host + test broker | §11.3 (final sentence) |
Registered in api-host/testing adapter table |
§15 Stage 5 |
Verification approach
src/factory/create-in-memory-ws-broker.test.ts— subscribe, publish, fan-out count; unsubscribe; cleanupConnection on disconnect.src/factory/create-in-memory-ws-broker.spec-conformance.test.ts—runWsBrokerConformance("in-memory-direct", ...).src/delivery/delivery-mode.test.ts—"await-all"waits for every subscriber's handler to settle;"fire-and-forget"returns synchronously.tests/integration/integration.test.ts— viacreateTestHost; full subscribe-then-publish flow against a plugin manifesting a WS endpoint.
Migration impact
None — additive only.