# `@suaveplan/api-ws-broker-redis` — Redis pub/sub broker for cross-host fan-out **Package**: `@suaveplan/api-ws-broker-redis` **Status**: PROPOSED **Type**: new-package **Stage**: 7 (GraphQL + WebSocket / SSE engines) — see umbrella `openspec/changes/api-plugin-foundation/` ## Why Per design doc §11.3 single-host deployments use an in-memory broker, but production deployments with multiple host replicas need cross-host broadcast: a `bus.broadcast` on host A must reach the locally-connected subscribers on host B. Redis pub/sub is the simplest and most operationally familiar transport for this. This package is the foundation's reference cross-host broker — required for any multi-replica deployment. The §11.6 SSE design explicitly reuses the same broker abstraction, so this package serves both `api-ws-bun` (WebSocket) and `api-sse-bun` (SSE) without duplication. Sticky sessions are NOT required because connections are not migrated across hosts — the broker just makes broadcasts visible everywhere; each host delivers to its own locally-connected subscribers. ## What changes Net-new package depending on `@suaveplan/api-types`, `@suaveplan/api-ws` (broker contract), `@suaveplan/api-sse` (also consumes the broker), `@suaveplan/error`, `@suaveplan/logger`, `@suaveplan/opentelemetry`, `ioredis` (peer), and `zod`. - ADDED: `createRedisWsBroker(opts)` — factory returning a broker value implementing the `WsBroker` contract from `@suaveplan/api-ws`. - ADDED: `RedisWsBrokerOptions` — Zod-validated config: `connection` (URL or `ioredis` options), `keyPrefix` (default `suaveplan:ws:`), `channelPrefix` (default `ws.broadcast.`), `eventBufferTtlSec` (default 300 = 5 min — pairs with `api-ws-bun`'s reconnect TTL), `eventBufferMaxEvents` (default 256 per `(tenant, topic)`), `compressionThresholdBytes` (default 1024 — payloads above this are gzipped before publish), `reconnectStrategy`. - ADDED: Pub/sub transport — `broker.broadcast(topic, { tenant, payload })` publishes to `` on Redis; every subscribed host receives the message and delivers to its locally-connected subscribers (looked up via local `ConnectionRegistry`). - ADDED: Reconnect event-buffer storage — for `api-ws-bun` when its `reconnectEventBufferStrategy` resolves to broker-backed, this package owns the event buffer: Redis sorted-set per `(tenant, topic)`, scored by `lastEventId`, capped at `eventBufferMaxEvents`, TTL `eventBufferTtlSec`. SSE consumes the same buffer for `Last-Event-Id` resume. - ADDED: Cross-host topology — every host subscribes to the host-wide channel pattern at start; on plugin install/uninstall the broker is informed so per-plugin topic prefixes can be added/dropped from the subscription set if optimisation is wanted. Default is whole-pattern subscription for simplicity. - ADDED: Health probe — `broker.healthz()` returns broker's connection state; consumed by the host's readiness endpoint. - ADDED: `WS_BROKER_REDIS_*` error codes: `WS_BROKER_REDIS_CONNECTION_LOST`, `WS_BROKER_REDIS_PUBLISH_FAILED`, `WS_BROKER_REDIS_SUBSCRIBE_FAILED`, `WS_BROKER_REDIS_BUFFER_WRITE_FAILED`, `WS_BROKER_REDIS_BUFFER_READ_FAILED`, `WS_BROKER_REDIS_PAYLOAD_TOO_LARGE`, `WS_BROKER_REDIS_DESERIALISE_FAILED`, `WS_BROKER_REDIS_CONFIG_INVALID`, `WS_BROKER_REDIS_RECONNECT_FAILED`, `WS_BROKER_REDIS_TIMEOUT`. - ADDED: OTel instruments: `ws.broker.publishes_total { topic, outcome }`, `ws.broker.publish_duration_ms`, `ws.broker.receives_total { topic }`, `ws.broker.buffer_writes_total`, `ws.broker.buffer_reads_total { hit }`, `ws.broker.connection_lost_total`. ## Out of scope - A non-Redis broker — design doc §11.3 specifically calls Redis as the reference. Other brokers (NATS, Kafka) can implement the same `WsBroker` contract in future packages. - The WebSocket engine itself — that's `api-ws-bun`. This broker just makes broadcasts visible across hosts. - The SSE engine — `api-sse-bun`. Consumes this same broker for fan-out + event-buffer. - Connection migration across hosts — out of scope by design. ## Source mapping Genesis-original. Source of design intent: `docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md`. | Requirement | Design doc section | |---|---| | Cross-host fan-out via Redis pub/sub | §11.3 | | Sticky sessions NOT required | §11.3 | | Reconnect event-buffer storage in Redis | §11.5 (paragraph 4) + §14 | | SSE reuses same broker | §11.6 | | Health probe | §12.6 | ## Verification approach - `src/broker/redis-broker.test.ts` (integration, 30000ms) — uses `@suaveplan/testing-integration-redis`; covers publish/subscribe round-trip, multi-host fan-out simulation (two broker instances bound to same Redis), reconnect after Redis bounce. - `src/broker/redis-broker.spec-conformance.test.ts` — pins the `WsBroker` contract conformance suite from `api-ws/testing`. - `src/event-buffer/event-buffer.test.ts` (integration, 30000ms) — sorted-set ops; TTL expiry; cap enforcement; replay by `lastEventId`. - `src/health/health.test.ts` — `healthz` reflects connection state; recovers after reconnect. - `tests/integration/two-host-broadcast.test.ts` (60000ms) — boots two `api-ws-bun` engines against the same Redis; connects clients to each; broadcasts from one; asserts delivery on both. ## Migration impact None — additive only.