2.9 KiB
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 abstractReplayBufferexported by@suaveplan/api-sse. - In-memory mode: lazy slot allocation, size + ttl bounded ring buffer,
one
ReplayBufferper(tenantId, topic). - Broker mode: delegates
publishto the wiredSseBroker, 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 theBUFFER_MISSdecision.
Usage: Basic
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
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, optionalclock.function createInMemoryEventBuffer(options): EventBuffer.interface BrokerBackedEventBufferOptions extends InMemoryEventBufferOptions— adds requiredbroker: 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.