# @suaveplan/api-plugin-sse - Server-Sent Events plugin for @suaveplan/api. Registers a typed sseService in the host ServiceRegistry, mounts a Hono streamSSE handler with per-connection heartbeat, AbortSignal threading, backpressure, and Last-Event-ID resume from a bounded per-channel ring buffer. Server-tier. Server-Sent Events plugin for `@suaveplan/api`. Registers a typed `sseService` in the host `ServiceRegistry`, mounts a Hono streaming handler at `GET /sse/:channel`, and ships with per-connection heartbeat, `AbortSignal` threading on client disconnect, `Last-Event-ID` resume from a bounded per-channel ring buffer, and backpressure handling with `drop-oldest` / `drop-newest` overflow policies. ## Documentation tree - [buffer](./src/buffer/ring-buffer.md) — Bounded per-channel ring buffer that powers `Last-Event-ID` resume. The SSE service appends every broadcast to the buff… - [ring-buffer](./src/buffer/ring-buffer.md) — Bounded per-channel ring buffer that powers `Last-Event-ID` resume. The SSE service appends every broadcast to the buff… - [error-codes](./src/error-codes/error-codes.md) — Stable error-code registry and `SseError` class for `@suaveplan/api-plugin-sse`. Every failure path in the plugin raise… - [error-codes](./src/error-codes/error-codes.md) — Stable error-code registry and `SseError` class for `@suaveplan/api-plugin-sse`. Every failure path in the plugin raise… - [fanout](./src/fanout/in-process.md) — Single-process publish/subscribe bus consumed by the SSE service to deliver every broadcast to every active subscriber… - [in-process](./src/fanout/in-process.md) — Single-process publish/subscribe bus consumed by the SSE service to deliver every broadcast to every active subscriber… - [format](./src/formatter/format.md) — Serialises `SseEvent` objects into the `text/event-stream` wire format defined by the WHATWG HTML Standard so the SSE h… - [parse](./src/formatter/parse.md) — Async streaming parser for `text/event-stream`. Decodes a `ReadableStreamDefaultReader` into a sequence of… - [middleware](./src/middleware/sse-handler.md) — Hono handler factory that turns a subscription on `SseService` into a streaming HTTP response framed in the `text/event… - [sse-handler](./src/middleware/sse-handler.md) — Hono handler factory that turns a subscription on `SseService` into a streaming HTTP response framed in the `text/event… - [otel](./src/otel/instruments.md) — Provides the canonical OpenTelemetry instrument bundle emitted by the SSE plugin. Counters and a histogram cover the fo… - [instruments](./src/otel/instruments.md) — Provides the canonical OpenTelemetry instrument bundle emitted by the SSE plugin. Counters and a histogram cover the fo… - [plugin](./src/plugin/plugin.md) — Factory producing a typed `PluginDescriptor` for the SSE plugin. Wraps the `@suaveplan/api-plugin` `definePlugin` found… - [plugin](./src/plugin/plugin.md) — Factory producing a typed `PluginDescriptor` for the SSE plugin. Wraps the `@suaveplan/api-plugin` `definePlugin` found… - [registry](./src/registry/service-registry.md) — TypeScript module augmentation declaring the `sseService` slot on the `@suaveplan/api-plugin/service-registry` `Service… - [service-registry](./src/registry/service-registry.md) — TypeScript module augmentation declaring the `sseService` slot on the `@suaveplan/api-plugin/service-registry` `Service… - [event](./src/schemas/event.md) — Zod schema validating the `SseEvent` shape accepted by `SseService.broadcast`. Ensures application payloads cannot bypa… - [options](./src/schemas/options.md) — Zod schema validating `SsePluginOptions` at the factory boundary. `createSsePlugin` calls `SsePluginOptionsSchema.safeP… - [services](./src/services/service.md) — Core SSE service registered under the `sseService` slot in the host `ServiceRegistry`. Owns subscription lifecycle (id… - [service](./src/services/service.md) — Core SSE service registered under the `sseService` slot in the host `ServiceRegistry`. Owns subscription lifecycle (id… ## Install ```bash bun add @suaveplan/api-plugin-sse ``` ## Quick start ```ts import { Hono } from "hono"; import { createPluginRegistry } from "@suaveplan/api-plugin"; import { createSsePlugin } from "@suaveplan/api-plugin-sse"; const app = new Hono(); const registry = createPluginRegistry({ seedServices: { app } }); await registry.register(createSsePlugin({ heartbeatIntervalMs: 15_000 })); await registry.init(); const sse = registry.getService("sseService"); setInterval(() => { sse?.broadcast("notifications", { data: { ts: Date.now() } }); }, 1_000); export default app; ``` A browser client connects with the native `EventSource`: ```ts const source = new EventSource("/sse/notifications"); source.addEventListener("message", (evt) => console.log(evt.data)); ``` ## The 3-way plug-and-play contract This package follows the canonical API-plugin pattern pioneered by `@suaveplan/api-plugin-auth`: a plugin is a `definePlugin` consumer that owns its (1) Zod schemas at the boundary, (2) optional default route registration, and (3) typed `ServiceRegistry` slot. Mount or compose with any other `@suaveplan/api-plugin-*` package by passing them to the same plugin registry. ## Modules - [`src/error-codes/error-codes.md`](./src/error-codes/error-codes.md) — stable `SSE_*` codes + `SseError` - [`src/buffer/ring-buffer.md`](./src/buffer/ring-buffer.md) — bounded per-channel ring buffer for `Last-Event-ID` resume - [`src/fanout/in-process.md`](./src/fanout/in-process.md) — single-process pub/sub bus - [`src/formatter/format.md`](./src/formatter/format.md) — SSE wire-format serializer - [`src/formatter/parse.md`](./src/formatter/parse.md) — streaming parser for SSE clients - [`src/schemas/options.md`](./src/schemas/options.md) — Zod schema for plugin options - [`src/schemas/event.md`](./src/schemas/event.md) — Zod schema for events - [`src/otel/instruments.md`](./src/otel/instruments.md) — OpenTelemetry instruments - [`src/services/service.md`](./src/services/service.md) — `SseService` registered under `sseService` - [`src/middleware/sse-handler.md`](./src/middleware/sse-handler.md) — Hono streaming handler factory - [`src/plugin/plugin.md`](./src/plugin/plugin.md) — `createSsePlugin` factory - [`src/registry/service-registry.md`](./src/registry/service-registry.md) — `ServiceRegistry` augmentation ## Configuration | Option | Default | Description | |---|---|---| | `heartbeatIntervalMs` | `30_000` | Heartbeat comment-frame cadence per connection | | `routePrefix` | `"/sse"` | Mount path for the default route (`:channel` appended) | | `attachDefaultRoute` | `true` | Skip route registration to mount manually | | `retentionPerChannel` | `100` | Ring-buffer size per channel for resume | | `maxConnectionsPerPrincipal` | `16` | Per-principal connection cap | | `maxTotalConnections` | `10_000` | Global connection cap | | `queueHighWaterMark` | `256` | Per-connection backlog threshold | | `overflowPolicy` | `"drop-oldest"` | `drop-oldest` or `drop-newest` | | `idGenerator` | `crypto.randomUUID()` | Event id source | ## Observability - `sse.active_connections` — current open connections (UpDownCounter, `channel` attribute) - `sse.broadcasts_total{channel}` — broadcasts per channel - `sse.heartbeats_total` — heartbeat frames written - `sse.message_bytes_total` — bytes written to clients - `sse.queue_overflow_total{policy,code}` — events dropped under backpressure - `sse.connection_duration_ms` — per-connection lifetime histogram ## License MIT