# `event-buffer` _(no submodules)_ ## Purpose The `event-buffer` module owns the per-`(tenant, topic)` replay storage the engine consults on `Last-Event-Id` reconnects. Two implementations are exported: an in-memory ring buffer for single-host deployments and a broker-backed adapter for clusters that share replay state with the WS engine. Both expose the same `EventBuffer` surface so the engine code path is identical regardless of deployment topology. ## Features - Multi-key buffer (`tenantId`, `topic`) on top of the abstract `ReplayBuffer` exported by `@suaveplan/api-sse`. - In-memory mode: lazy slot allocation, size + ttl bounded ring buffer, one `ReplayBuffer` per `(tenantId, topic)`. - Broker mode: delegates `publish` to the wired `SseBroker`, keeps a shadow in-memory mirror so reads stay synchronous. - `evictExpired(now)` sweeps every per-key buffer in one call. - Synchronous `size(key)` probe used by the `BUFFER_MISS` decision. ## Usage: Basic ```ts import { createInMemoryEventBuffer } from "@suaveplan/api-sse-bun"; const buffer = createInMemoryEventBuffer({ eventBufferSize: 256, eventBufferMs: 300_000, }); const key = { tenantId: "acme" as never, topic: "audit" }; buffer.append(key, { id: "1", data: "first" }); const replay = await buffer.since(key, "non-existent"); console.log(replay); // [] ``` ## Usage: Advanced ```ts import { createBrokerBackedEventBuffer, type EventBuffer, } from "@suaveplan/api-sse-bun"; import type { SseBroker } from "@suaveplan/api-sse"; declare const broker: SseBroker; const buffer: EventBuffer = createBrokerBackedEventBuffer({ eventBufferSize: 1024, eventBufferMs: 600_000, broker, }); await buffer.append( { tenantId: "acme" as never, topic: "audit" }, { id: "1", data: "first" } ); ``` ## API Reference - `interface EventBuffer` — `append(key, event)`, `since(key, lastId)`, `size(key)`, `evictExpired(now)`, `mode: "memory" | "broker"`. - `interface InMemoryEventBufferOptions` — `eventBufferSize`, `eventBufferMs`, optional `clock`. - `function createInMemoryEventBuffer(options): EventBuffer`. - `interface BrokerBackedEventBufferOptions extends InMemoryEventBufferOptions` — adds required `broker: SseBroker`. - `function createBrokerBackedEventBuffer(options): EventBuffer`. ## Implementation Notes The broker-backed adapter keeps a shadow in-memory mirror because the `SseBroker` contract does not yet expose a synchronous read path — real implementations (Redis sorted-set) require an async query and the engine resolves `since` synchronously during the handshake. The shadow mirror is consistent on the local host; cross-host replay (a client reconnects to a different host than the one that emitted the event) delegates to the broker's `since` surface, which lives in the broker package, not here. Eviction in broker mode operates only on the local shadow — the broker manages its own TTL via Redis' native expiration.