/** * Central envelope builders — single stamp point for `schemaVersion` * across every producer path. * * **Why centralize.** The `schemaVersion` forward-compat stamp is * emitted from many producer sites (wire helper, React-SDK emit * paths, OSS in-memory stream buffer, hosted server paths). * Spreading stamp logic across N sites * causes drift — producers silently skip the stamp. These builders * remove the drift surface by giving every producer a single function * to call; the default stamp happens inside the builder. * * **Override semantics.** Each builder accepts `schemaVersion` in the * input object: * * - **Key omitted** → the builder stamps {@link PROTOCOL_SCHEMA_VERSION}. * - **Explicit string** → used as-is (cross-version test scenarios, * replay fidelity when forwarding an already-stamped envelope). * - **Explicit `undefined`** (`makeXxx({ schemaVersion: undefined, * ... })`) → the builder OMITS the field entirely (no * `schemaVersion` key on the returned envelope). This is a * test-only pattern used by consumer-side tests that assert * behavior when the field is absent on the wire. Production * producers MUST NOT pass `undefined` explicitly. * * Key-present-vs-absent is distinguished via the `in` operator — * `'schemaVersion' in parts` is `true` iff the caller wrote the key, * even as `undefined`. The builders rely on that distinction so the * test-only omit path does not require a separate escape-hatch flag. * * **Exactly which key is set** matters. The builder omits `undefined` * optional fields entirely (it does not emit `{key: undefined}`) so * that `JSON.stringify` produces the same bytes as the old manual * `if (x !== undefined) envelope.x = x` pattern — byte-equivalence * with every pre-refactor stamp site is a load-bearing claim of the * centralization. * * **Scope.** These builders stamp and shape; they do NOT validate. * Validators live in `@ggui-ai/protocol/validation/*`. The division * is deliberate: stamping is part of the wire-shape contract (a * producer obligation), validation is part of the behavior contract * (an observable-violation obligation). Keeping them separate keeps * each module's surface narrow. * * @see PROTOCOL_SCHEMA_VERSION on `@ggui-ai/protocol` */ import type { ActionEnvelope, EventType } from '../types/events.js'; import type { ErrorPayload, StreamEnvelope } from '../types/live-channel.js'; import type { JsonValue, StreamChannelMode } from '../types/data-contract.js'; /** Input type for {@link makeActionEnvelope}. */ export interface MakeActionEnvelopeInput { readonly sessionId: string; readonly type: EventType; readonly payload?: TPayload; readonly clientSeq?: number; /** * `schemaVersion` override. See the module docstring for the three * semantic paths (omit key → default stamp; pass string → stamp * that value; pass explicit `undefined` → omit stamp entirely — * test-only). */ readonly schemaVersion?: string; } /** Input type for {@link makeStreamEnvelope}. */ export interface MakeStreamEnvelopeInput { readonly sessionId: string; readonly channel: string; readonly mode: StreamChannelMode; readonly payload: JsonValue; readonly complete?: boolean; readonly seq?: number; /** See {@link MakeActionEnvelopeInput.schemaVersion}. */ readonly schemaVersion?: string; } /** Input type for {@link makeErrorPayload}. */ export interface MakeErrorPayloadInput { readonly code: string; readonly message: string; readonly details?: JsonValue; } /** * Build an {@link ActionEnvelope} with `schemaVersion` stamped to * {@link PROTOCOL_SCHEMA_VERSION} unless the caller overrides. * * Filters `undefined` optional fields so the serialized wire message * omits them (matches the producer convention that "absent field = * default"). */ export declare function makeActionEnvelope(parts: MakeActionEnvelopeInput): ActionEnvelope; /** * Build a {@link StreamEnvelope} with `schemaVersion` stamped to * {@link PROTOCOL_SCHEMA_VERSION} unless the caller overrides. * * Filters `undefined` optional fields (`complete`, `seq`) so the * serialized wire message omits them. `seq` is server-assigned in * practice — callers pass the value the buffer hands them. */ export declare function makeStreamEnvelope(parts: MakeStreamEnvelopeInput): StreamEnvelope; /** * Build an {@link ErrorPayload} for the `{type: 'error'}` wire frame. * * Does NOT stamp `schemaVersion` — `ErrorPayload` is the wire-level * error envelope (free-form `code: string`), not an envelope that * opts into the forward-compat stamp (see {@link ActionEnvelope} / * {@link StreamEnvelope}). Keeping * `ErrorPayload` stamp-free preserves byte-equivalence with every * existing server-side error emission that pre-dates the central * builders. * * The builder exists so first-party subscribe / handshake paths emit * canonical codes (e.g. `UPGRADE_REQUIRED`) via a single helper * instead of spreading `{code, message}` object literals. `details` * is filtered when `undefined` so the serialized frame matches the * pre-builder `{code, message}` shape byte-for-byte. */ export declare function makeErrorPayload(parts: MakeErrorPayloadInput): ErrorPayload; //# sourceMappingURL=builders.d.ts.map