first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
# `connection` — canonical `WsConnection` contract
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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
```ts
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
```ts
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.