Files
skills/docs/api-stack/api/api-ws/src/connection/connection.md
2026-05-29 08:20:56 +01:00

2.6 KiB

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: Payload) => boolean.

Usage: Basic

import type { WsConnection } from "@suaveplan/api-ws/connection";

async function onConnect(conn: WsConnection): Promise<void> {
    await conn.subscribe("orders.created", { tenant: conn.tenantId });
}

Usage: Advanced

import type {
    SubscribeOptions,
    WsConnection,
} from "@suaveplan/api-ws/connection";

interface OrderEvent { priority: number }

const opts: SubscribeOptions<OrderEvent> = {
    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: Payload) => boolean.
  • interface SubscribeOptions<Payload> { tenant?: TenantId; filter?: SubscriptionFilter<Payload> }.

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<void> 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.