Initial Commit
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# `subscriptions.ts`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Bridges the `WsBroker` contract from `@suaveplan/api-ws` to GraphQL
|
||||
`Subscription` resolvers via `AsyncIterable<Payload>`. The Yoga engine
|
||||
wires `graphql-ws` over the host's already-mounted WebSocket transport;
|
||||
this module is the per-subscription helper that converts a broker `topic`
|
||||
+ `tenant` pair into an iterator the engine can consume.
|
||||
|
||||
Tenant filtering is enforced at the bridge: only `BrokerEnvelope` items
|
||||
whose `tenant === tenantArg` reach the GraphQL iterator. Closing the
|
||||
iterator (`return()` or the explicit `close()` method) calls
|
||||
`subscription.unsubscribe()` on the broker so the WS slot is released
|
||||
within one tick.
|
||||
|
||||
## Features
|
||||
|
||||
- Returns `AsyncIterable<Payload>` with an explicit `close()` accessor.
|
||||
- Queues payloads when no consumer is awaiting; resolves immediately when
|
||||
a consumer is parked.
|
||||
- Calls `GraphqlYogaError("SUBSCRIPTION_TRANSPORT_UNAVAILABLE")` when the
|
||||
host hands a `null` broker, satisfying the design doc §10.4 contract.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { createInMemoryWsBroker } from "@suaveplan/api-ws-broker-in-memory";
|
||||
import { subscribeBrokerTopic } from "@suaveplan/api-graphql-yoga";
|
||||
|
||||
const broker = createInMemoryWsBroker();
|
||||
const iterable = subscribeBrokerTopic(
|
||||
broker,
|
||||
"billing.invoice.created",
|
||||
"tenant-a" as never
|
||||
);
|
||||
for await (const event of iterable) {
|
||||
console.log(event);
|
||||
break;
|
||||
}
|
||||
await iterable.close();
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { subscribeBrokerTopic } from "@suaveplan/api-graphql-yoga";
|
||||
|
||||
const subscription = {
|
||||
invoiceCreated(_parent: unknown, _args: unknown, ctx: { broker: never; tenantId: never }) {
|
||||
return subscribeBrokerTopic(ctx.broker, "billing.invoice.created", ctx.tenantId);
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `subscribeBrokerTopic(broker, topic, tenant)` — returns
|
||||
`AsyncIterable<Payload> & { close(): Promise<void> }`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The internal `queue` + `waiters` arrays form a simple bounded mailbox.
|
||||
Backpressure (queue cap, drop oldest, etc.) is intentionally not modelled
|
||||
here — the in-memory broker enforces its own bounds, and the Redis broker
|
||||
will inherit the same back-end contract.
|
||||
Reference in New Issue
Block a user