# `subscription` _(no submodules)_ ## 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.