first commit
This commit is contained in:
77
docs/api-stack/api/api-ws/src/connection/connection.md
Normal file
77
docs/api-stack/api/api-ws/src/connection/connection.md
Normal 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.
|
||||
Reference in New Issue
Block a user