Files
suaveplan/packages/api-stack/api/api-ws-bun/README.md
2026-05-27 23:29:53 +01:00

116 lines
8.3 KiB
Markdown

# @suaveplan/api-ws-bun - Bun.serve-backed WebSocket engine for @suaveplan/api-ws. Implements the abstract WsEngine contract using Bun's native WebSocket primitives: handshake pipeline freezing the principal, per-tenant ConnectionRegistry, SubscriptionBus integration, backpressure eviction (default 256 msg queue), heartbeat (30s ping / 2 missed-pong drop), per-tenant caps (1000), HMAC-signed reconnect tokens (5-min TTL) with auto/memory/broker event-buffer strategies, and the OTel surface from design §11.7. Passes runWsEngineConformance.
Bun.serve-backed WebSocket engine for the `@suaveplan/api-ws` Stage-1 abstract contract. The engine composes the per-connection handshake pipeline, registry, subscription bus, backpressure guard, heartbeat controller, principal-expiry watcher, reconnect-token issuer, reconnect-event buffer, and OTel surface into one `createBunWsEngine(opts)` factory call. Passes `runWsEngineConformance` and ships a real `Bun.serve` integration smoke under `tests/integration/`.
<!-- begin:auto-docs -->
## Documentation tree
- [backpressure](./src/backpressure/backpressure.md) — Enforces the per-connection send-queue cap described in design §11.4. Each connection owns one `BackpressureGuard` inst…
- [backpressure](./src/backpressure/backpressure.md) — Enforces the per-connection send-queue cap described in design §11.4. Each connection owns one `BackpressureGuard` inst…
- [engine](./src/engine/bun-ws-engine.md) — `createBunWsEngine` is the package's headline factory. It composes every other module in the package — registry, bus, i…
- [bun-ws-engine](./src/engine/bun-ws-engine.md) — `createBunWsEngine` is the package's headline factory. It composes every other module in the package — registry, bus, i…
- [error-codes](./src/error-codes/error-codes.md) — Provides the stable error-code registry and the typed `WsBunError` subclass for `@suaveplan/api-ws-bun`. Every producti…
- [error-codes](./src/error-codes/error-codes.md) — Provides the stable error-code registry and the typed `WsBunError` subclass for `@suaveplan/api-ws-bun`. Every producti…
- [handshake](./src/handshake/handshake.md) — Freezes the per-request pipeline result onto a per-connection `HandshakeOutcome`. The host runs the standard pipeline s…
- [handshake](./src/handshake/handshake.md) — Freezes the per-request pipeline result onto a per-connection `HandshakeOutcome`. The host runs the standard pipeline s…
- [subprotocol](./src/handshake/subprotocol.md) — Implements RFC 6455 §4.1 subprotocol negotiation as a tiny pure function. The server is supplied the client's requested…
- [heartbeat](./src/heartbeat/heartbeat.md) — Implements the per-connection ping/pong state machine described in design §11.4. The engine instantiates one `Heartbeat…
- [heartbeat](./src/heartbeat/heartbeat.md) — Implements the per-connection ping/pong state machine described in design §11.4. The engine instantiates one `Heartbeat…
- [instruments](./src/instruments/instruments.md) — Builds the OTel instrument registry the engine emits to. The names, units, and attribute keys all match design doc §11.…
- [instruments](./src/instruments/instruments.md) — Builds the OTel instrument registry the engine emits to. The names, units, and attribute keys all match design doc §11.…
- [limits](./src/limits/tenant-cap.md) — Provides the per-tenant connection-count enforcement function that the handshake pipeline calls before admitting a new…
- [tenant-cap](./src/limits/tenant-cap.md) — Provides the per-tenant connection-count enforcement function that the handshake pipeline calls before admitting a new…
- [options](./src/options/options.md) — Defines the Zod-validated options surface accepted by `createBunWsEngine`. Every field has a documented default sourced…
- [options](./src/options/options.md) — Defines the Zod-validated options surface accepted by `createBunWsEngine`. Every field has a documented default sourced…
- [principal](./src/principal/principal-expiry.md) — Tracks the underlying token expiry for a frozen principal so the engine can drop the connection at the right moment. Th…
- [principal-expiry](./src/principal/principal-expiry.md) — Tracks the underlying token expiry for a frozen principal so the engine can drop the connection at the right moment. Th…
- [event-buffer](./src/reconnect/event-buffer.md) — Provides the per-`(tenant, topic)` reconnect-event buffer used to replay events to a reconnecting client whose `lastEve…
- [reconnect-token](./src/reconnect/reconnect-token.md) — Wraps the api-ws contract's `signReconnectToken` / `verifyReconnectToken` HMAC token helpers so the engine has a statef…
- [registry](./src/registry/connection-registry.md) — Wraps the api-ws contract's `InMemoryConnectionRegistry` to give the Bun engine a typed registry surface that the confo…
- [connection-registry](./src/registry/connection-registry.md) — Wraps the api-ws contract's `InMemoryConnectionRegistry` to give the Bun engine a typed registry surface that the confo…
- [subscription](./src/subscription/subscription-bus.md) — Builds the per-engine subscription bus instance and binds it to the engine's connection registry. The bus implementatio…
- [subscription-bus](./src/subscription/subscription-bus.md) — Builds the per-engine subscription bus instance and binds it to the engine's connection registry. The bus implementatio…
- [testing](./src/testing/conformance-binding.md) — Binds the abstract `runWsEngineConformance` harness from `@suaveplan/api-ws/testing` to a default `createBunWsEngine`-b…
- [conformance-binding](./src/testing/conformance-binding.md) — Binds the abstract `runWsEngineConformance` harness from `@suaveplan/api-ws/testing` to a default `createBunWsEngine`-b…
<!-- end:auto-docs -->
## Defaults
| Option | Default | Source |
|---|---|---|
| `maxQueuedMessages` | `256` | §11.4 |
| `heartbeatMs` | `30_000` (min 5_000) | §11.4 |
| `missedPongLimit` | `2` | §11.4 |
| `maxConnectionsPerTenant` | `1_000` | §11.4 |
| `reconnectTokenTtlMs` | `300_000` | §11.5 |
| `reconnectEventBufferStrategy` | `"auto"` | §11.5 + §14 |
| `reconnectEventBufferLimit` | `256` | engine |
| `subprotocols` | `[]` | engine |
| `pluginId` | `"api-ws-bun"` | engine |
## Modules
- `engine` — `createBunWsEngine`, `ManagedConnection`, `BunWsSocketSink`.
- `options` — `BunWsEngineOptions`, `bunWsEngineOptionsSchema`, `resolveBunWsEngineOptions`.
- `handshake` — `runHandshake`, `resolveSubprotocol`.
- `registry` — `BunConnectionRegistry`.
- `subscription` — `createBunSubscriptionBus`.
- `backpressure` — `BackpressureGuard`.
- `heartbeat` — `HeartbeatController`.
- `limits` — `enforceTenantCap`.
- `principal` — `PrincipalExpiryWatcher`.
- `reconnect` — `ReconnectTokenIssuer`, `MemoryReconnectEventBuffer`, `BrokerReconnectEventBuffer`, `resolveReconnectEventBuffer`.
- `instruments` — `createBunWsInstruments` (every §11.7 instrument).
- `error-codes` — `WS_BUN_CODES`, `WsBunError`, ten `raise*` helpers.
- `testing` (subpath `@suaveplan/api-ws-bun/testing`) — `runBunWsConformance`, `bunEngineFactory`, `adaptEngineToFactory`.
## Example
```ts
import { createBunWsEngine } from "@suaveplan/api-ws-bun";
import { createInMemoryWsBroker } from "@suaveplan/api-ws-broker-in-memory";
const broker = createInMemoryWsBroker();
const engine = createBunWsEngine({
reconnectTokenSecret: new Uint8Array(32).fill(7),
broker,
});
Bun.serve({
port: 8787,
fetch(req, srv) {
if (new URL(req.url).pathname === "/ws") {
return srv.upgrade(req, { data: { id: crypto.randomUUID() } })
? undefined
: new Response("upgrade failed", { status: 400 });
}
return new Response("ok");
},
websocket: {
open(ws) {
engine.attach({
id: ws.data.id,
principal,
tenantId,
capabilities: new Set(),
tokenExpiresAt: Date.now() + 3_600_000,
sink: {
send: (s) => ws.send(s),
close: (c, r) => ws.close(c, r),
ping: () => ws.ping?.(),
},
});
},
message() {},
close() {},
},
});
```
## Tests
```bash
bunx turbo lint typecheck test:coverage --filter=@suaveplan/api-ws-bun
```