Files
skills/docs/api-stack/api/api-plugin-sse
2026-05-29 08:20:56 +01:00
..
2026-05-29 08:20:56 +01:00
2026-05-29 08:20:56 +01:00

@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 — Bounded per-channel ring buffer that powers Last-Event-ID resume. The SSE service appends every broadcast to the buff…
    • ring-buffer — Bounded per-channel ring buffer that powers Last-Event-ID resume. The SSE service appends every broadcast to the buff…
  • error-codes — Stable error-code registry and SseError class for @suaveplan/api-plugin-sse. Every failure path in the plugin raise…
    • error-codes — Stable error-code registry and SseError class for @suaveplan/api-plugin-sse. Every failure path in the plugin raise…
  • fanout — Single-process publish/subscribe bus consumed by the SSE service to deliver every broadcast to every active subscriber…
    • in-process — Single-process publish/subscribe bus consumed by the SSE service to deliver every broadcast to every active subscriber…
  • format — Serialises SseEvent objects into the text/event-stream wire format defined by the WHATWG HTML Standard so the SSE h…
  • parse — Async streaming parser for text/event-stream. Decodes a ReadableStreamDefaultReader<Uint8Array> into a sequence of…
  • middleware — Hono handler factory that turns a subscription on SseService into a streaming HTTP response framed in the `text/event…
    • sse-handler — Hono handler factory that turns a subscription on SseService into a streaming HTTP response framed in the `text/event…
  • otel — Provides the canonical OpenTelemetry instrument bundle emitted by the SSE plugin. Counters and a histogram cover the fo…
    • instruments — Provides the canonical OpenTelemetry instrument bundle emitted by the SSE plugin. Counters and a histogram cover the fo…
  • plugin — Factory producing a typed PluginDescriptor for the SSE plugin. Wraps the @suaveplan/api-plugin definePlugin found…
    • plugin — Factory producing a typed PluginDescriptor for the SSE plugin. Wraps the @suaveplan/api-plugin definePlugin found…
  • registry — TypeScript module augmentation declaring the sseService slot on the @suaveplan/api-plugin/service-registry `Service…
    • service-registry — TypeScript module augmentation declaring the sseService slot on the @suaveplan/api-plugin/service-registry `Service…
  • event — Zod schema validating the SseEvent shape accepted by SseService.broadcast. Ensures application payloads cannot bypa…
  • options — Zod schema validating SsePluginOptions at the factory boundary. createSsePlugin calls `SsePluginOptionsSchema.safeP…
  • services — Core SSE service registered under the sseService slot in the host ServiceRegistry. Owns subscription lifecycle (id…
    • service — Core SSE service registered under the sseService slot in the host ServiceRegistry. Owns subscription lifecycle (id…

Install

bun add @suaveplan/api-plugin-sse

Quick start

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:

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

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