# `connection` — canonical `WsConnection` contract _(no submodules)_ ## Purpose `@suaveplan/api-ws/connection` declares the abstract `WsConnection` interface every concrete engine (`api-ws-bun`, future browser shims) implements. Plugins author against this contract; the host wires whichever engine the deployment requires. This is The type-only foundation — no runtime, no state, just the interface and its supporting helper types. The handshake principal is frozen for the connection's lifetime; the contract intentionally exposes `principal` as a `readonly Principal` so a plugin cannot mutate it mid-session, and the host emits `connection.principal_expired` (an api-host concern) when the underlying session lapses. ## Features - `WsConnection` interface — id, principal, tenantId, lastEventId, state, plus `subscribe / unsubscribe / send / close / ack`. - `WsConnectionState` — `"open" | "closing" | "closed"`. - `SubscribeOptions` — tenant override and optional `filter` predicate. - `SubscriptionFilter` — `(payload: Payload) => boolean`. ## Usage: Basic ```ts import type { WsConnection } from "@suaveplan/api-ws/connection"; async function onConnect(conn: WsConnection): Promise { await conn.subscribe("orders.created", { tenant: conn.tenantId }); } ``` ## Usage: Advanced ```ts import type { SubscribeOptions, WsConnection, } from "@suaveplan/api-ws/connection"; interface OrderEvent { priority: number } const opts: SubscribeOptions = { tenant: tenantId, filter: (payload): boolean => payload.priority >= 5, }; await conn.subscribe("orders.created", opts); await conn.send({ id: "1", type: "ack", topic: "orders.created" }); conn.ack("e-42"); if (conn.state !== "open") { return; } ``` ## API Reference - `interface WsConnection { id, principal, tenantId, lastEventId, state, subscribe, unsubscribe, send, close, ack }`. - `type WsConnectionState = "open" | "closing" | "closed"`. - `type SubscriptionFilter = (payload: Payload) => boolean`. - `interface SubscribeOptions { tenant?: TenantId; filter?: SubscriptionFilter }`. ## Implementation Notes - `send` accepts a `WsEnvelope` (the wire schema) so engines can apply the same boundary validation on outbound frames they apply on inbound. - `subscribe` / `unsubscribe` / `send` / `close` are typed as `void | Promise` so engines that need to coordinate with a broker can be async, while in-memory engines can stay synchronous. - `ack` is synchronous because it only updates the connection's `lastEventId` cursor; it never blocks on I/O.