first commit
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
# `subscription`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Validate incoming `graphql-ws` subscription envelopes and surface a typed
|
||||
"transport unavailable" failure when `api-ws` isn't wired into the host.
|
||||
Subscriptions ride the WebSocket engine published in `api-ws` (design
|
||||
§10.4); this file is the contract-side handshake validator + transport
|
||||
gating, not the dispatch loop itself.
|
||||
|
||||
The Zod-validated envelope shape covers the subset of the `graphql-ws`
|
||||
protocol the host care about (`connection_init`, `subscribe`, `next`,
|
||||
`error`, `complete`, plus the ping/pong heartbeat). Engines validate inbound
|
||||
frames with `parseSubscriptionMessage` before dispatching to a
|
||||
`SubscriptionResolver`.
|
||||
|
||||
## Features
|
||||
|
||||
- Zod schema covering all eight `graphql-ws` message types.
|
||||
- `parseSubscriptionMessage` returns a structured `{ ok, message }` or
|
||||
`{ ok: false, issues }` rather than throwing — engines decide whether
|
||||
to close the connection.
|
||||
- `assertSubscriptionTransport` raises
|
||||
`GRAPHQL.SUBSCRIPTION_TRANSPORT_UNAVAILABLE` when the marker reports
|
||||
the transport is offline.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { parseSubscriptionMessage } from "@suaveplan/api-graphql/subscription";
|
||||
|
||||
const result = parseSubscriptionMessage(JSON.parse(frame));
|
||||
if (result.ok) {
|
||||
dispatch(result.message);
|
||||
} else {
|
||||
closeWithCode(4400, result.issues.join("; "));
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Gate `executeSubscription` on transport availability so engine adapters
|
||||
return a typed error rather than a generic transport failure:
|
||||
|
||||
```ts
|
||||
import {
|
||||
assertSubscriptionTransport,
|
||||
GraphqlError,
|
||||
} from "@suaveplan/api-graphql";
|
||||
|
||||
try {
|
||||
assertSubscriptionTransport({ available: false, protocol: "graphql-ws" });
|
||||
} catch (e) {
|
||||
if (e instanceof GraphqlError) {
|
||||
// "GRAPHQL.SUBSCRIPTION_TRANSPORT_UNAVAILABLE"
|
||||
console.error(e.graphqlCode);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `subscriptionMessageSchema` — Zod discriminated union over the
|
||||
`graphql-ws` message types.
|
||||
- `SubscriptionMessage` — inferred TypeScript type.
|
||||
- `SubscriptionTransportMarker` — `{ available, protocol: "graphql-ws" }`.
|
||||
- `parseSubscriptionMessage(raw) → { ok: true; message } | { ok: false; issues }`.
|
||||
- `assertSubscriptionTransport(marker) → void` — throws when unavailable.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The schema is intentionally permissive on payload shape — the inner
|
||||
`payload.query` is validated; the `variables` and `extensions` carriers
|
||||
accept any record because plugin authors define their own variable shapes.
|
||||
The host re-validates `variables` against the operation's declared shape
|
||||
at execute time.
|
||||
|
||||
The `SUBSCRIPTION_TRANSPORT_UNAVAILABLE` failure mode exists because the
|
||||
host MAY ship without `api-ws` (a query-only deployment). Plugins that
|
||||
register subscription resolvers but find no transport wired need a clear
|
||||
boot-time signal; this is it.
|
||||
Reference in New Issue
Block a user