import { type CryptoKey } from './encryption.js'; /** * Encryption key parameter type. Accepts a resolved key, undefined (no encryption), * a promise, or a resolver that can defer fetching the key until data needs it. * This allows synchronous function signatures (e.g., getReadable()) to thread the * key through without awaiting it — the value is resolved lazily inside the first * async transform() call. When a resolver function is passed, the underlying * fetch isn't even initiated until the first chunk is processed, which avoids * unobserved background lookups for empty or never-read streams. */ export type EncryptionKeyParam = CryptoKey | undefined | Promise | (() => Promise); export declare function resolveEncryptionKey(key: EncryptionKeyParam): Promise; /** * Known serialization format identifiers. * Each format ID is exactly 4 ASCII characters, matching the convention * used for other workflow IDs (wrun, step, wait, etc.) */ export declare const SerializationFormat: { /** devalue stringify/parse with TextEncoder/TextDecoder */ readonly DEVALUE_V1: "devl"; /** Encrypted payload (inner payload has its own format prefix) */ readonly ENCRYPTED: "encr"; }; export type SerializationFormatType = (typeof SerializationFormat)[keyof typeof SerializationFormat]; /** * Encode a payload with a format prefix. * * @param format - The format identifier (must be exactly 4 ASCII characters) * @param payload - The serialized payload bytes * @returns A new Uint8Array with format prefix prepended */ export declare function encodeWithFormatPrefix(format: SerializationFormatType, payload: Uint8Array | unknown): Uint8Array | unknown; /** * Peek at the format prefix without consuming it. * Useful for checking if data is encrypted before deciding how to process it. * * @param data - The format-prefixed data * @returns The format identifier, or null if data is legacy/non-binary */ export declare function peekFormatPrefix(data: Uint8Array | unknown): SerializationFormatType | null; /** * Check if data is encrypted (has 'encr' format prefix). * * @param data - The format-prefixed data * @returns true if data has the encrypted format prefix */ export declare function isEncrypted(data: Uint8Array | unknown): boolean; /** * Decode a format-prefixed payload. * * @param data - The format-prefixed data * @returns An object with the format identifier and payload * @throws Error if the data is too short or has an unknown format */ export declare function decodeFormatPrefix(data: Uint8Array | unknown): { format: SerializationFormatType; payload: Uint8Array; }; /** * Format a serialization error with context about what failed. * Extracts path, value, and reason from devalue's DevalueError when available. * Logs the problematic value to the console for better debugging. */ export declare function formatSerializationError(context: string, error: unknown): string; /** * Detect if a readable stream is a byte stream. * * @param stream * @returns `"bytes"` if the stream is a byte stream, `undefined` otherwise */ export declare function getStreamType(stream: ReadableStream): 'bytes' | undefined; export declare function getSerializeStream(reducers: Reducers, cryptoKey: EncryptionKeyParam): TransformStream; export declare function getDeserializeStream(revivers: Revivers, cryptoKey: EncryptionKeyParam): TransformStream; /** * Wraps each chunk of a byte stream in a 4-byte big-endian length * prefix. Used by the producer side of a framed byte-stream pipe. * * Empty chunks (length 0) are dropped — the resulting `[0x00 0x00 0x00 0x00]` * frame would be ambiguous with the legacy "looks framed" detection in * `getDeserializeStream`, and it carries no information. * * Load-bearing invariant: each user chunk becomes exactly one frame, and * each frame is enqueued as exactly one transport chunk (the downstream * writable performs one wire write per chunk, preserving boundaries). The * server therefore stores one frame per chunk index, which is what allows * a future reconnecting reader to resume a framed byte stream at * `startIndex + consumedFrames` — the same arithmetic * `createReconnectingFramedStream` relies on for object streams. Do not * coalesce or split frames here without revisiting that resume logic. */ export declare function getByteFramingStream(): TransformStream; /** * Unwraps length-prefixed byte-stream frames back into the original user * chunks. Used by the consumer side of a framed byte-stream pipe. * * Buffers across read boundaries — the transport may split a single * frame across multiple reads (header in one chunk, payload in another) * or coalesce multiple frames into a single read. The transform emits * whole user chunks regardless of transport chunking. * * Errors the stream if the length header advertises a frame larger than * `MAX_FRAME_SIZE` bytes, since that almost certainly indicates a * misframed wire (e.g. a raw byte stream being fed through this transform * by mistake) and we don't want to allocate an enormous buffer. */ export declare function getByteUnframingStream(): TransformStream; export declare class WorkflowServerReadableStream extends ReadableStream { #private; constructor(name: string, startIndex?: number); } /** * Maximum consecutive reconnect attempts for a single framed stream session. * The counter resets to zero whenever a reconnect makes forward progress (a * frame is delivered), so this bounds *consecutive* failures, not the lifetime * total — a long-lived serverless stream may legitimately reconnect far more * than this many times as long as each reconnect keeps delivering data. We only * give up after this many reconnects in a row produce nothing. */ export declare const FRAMED_STREAM_MAX_RECONNECTS = 50; /** * Absolute backstop on total reconnects for a single session, independent of * progress. The consecutive cap above resets on forward progress, which is * correct for a well-behaved backend that honors `startIndex`. But if a World's * `readFromStream` ever ignored `startIndex` and re-delivered earlier chunks, * "progress" would be reported every reconnect and the consecutive cap would * never trip — turning a bounded failure into an unbounded reconnect loop. This * hard ceiling guarantees the loop always terminates. It is set high enough * (hours of streaming at realistic per-session timeouts) to never interfere * with legitimate long-lived streams. */ export declare const FRAMED_STREAM_MAX_TOTAL_RECONNECTS = 1000; /** * Wraps the length-prefix-framed byte WorkflowServerReadableStream * with transparent auto-reconnect. * * Every fully-decoded outer frame corresponds to exactly one server-side * chunk (the serialize transform enqueues one frame per workflow write, and * the writable buffers one frame per chunk when multi-writing). The wrapper * counts completed frames and, on upstream error, reopens the connection * with `startIndex = resolvedStartIndex + consumedFrames`. Partial-frame * bytes buffered before the cut are discarded — the server will resend the * in-flight chunk in full from the new startIndex. * * A clean upstream close (EOF with no error) is NOT trusted as completion * on its own: some transport paths normalize a mid-stream abort into a * graceful end (observed in production on Vercel response streaming, where * the server's max-duration abort arrives at the client as a clean EOF). * On EOF the wrapper verifies against the stream's authoritative metadata * (`getStreamInfo`) that the stream is complete AND that every chunk up to * `done` was delivered; otherwise it reconnects from the next chunk exactly * like an errored connection. If the metadata read itself fails, the EOF is * trusted (legacy behavior) rather than failing a read that may well be * complete. * * Negative `startIndex` values (last-N semantics) skip the reconnect * machinery because we cannot compute an absolute resume position without * a tail-index lookup — the returned stream behaves as a single-shot read. */ export declare function createReconnectingFramedStream(runId: string, name: string, startIndex?: number): ReadableStream; export declare class WorkflowServerWritableStream extends WritableStream { constructor(name: string, runId: string); } /** * Wire-framing format identifier carried in the serialized * `ReadableStream` ref's `framing` field. * * - absent / `'raw'`: chunks are written to the transport verbatim * (legacy format — no auto-reconnect support). * - `'framed-v1'`: each chunk is wrapped in a 4-byte big-endian length * prefix, allowing the reader to identify chunk boundaries and * transparently reconnect on transient stream errors. */ export type ByteStreamFraming = 'raw' | 'framed-v1'; export interface SerializableSpecial { ArrayBuffer: string; BigInt: string; BigInt64Array: string; BigUint64Array: string; Date: string; DOMException: { message: string; name: string; stack?: string; cause?: unknown; }; Float32Array: string; Float64Array: string; Error: Record; Headers: [string, string][]; Int8Array: string; Int16Array: string; Int32Array: string; Map: [any, any][]; ReadableStream: { name: string; type?: 'bytes'; startIndex?: number; /** * Wire-framing format for byte streams. See {@link ByteStreamFraming} * and `getByteFramingStream` / `getByteUnframingStream`. * * Only meaningful when `type === 'bytes'`. Absent on object streams * (which always use length-prefixed devalue framing) and on legacy * byte streams written by SDKs that predate framing support — those * are interpreted as `'raw'` by the consumer. */ framing?: ByteStreamFraming; } | { bodyInit: any; }; RegExp: { source: string; flags: string; }; Request: { method: string; url: string; headers: Headers; body: Request['body']; duplex: Request['duplex']; responseWritable?: WritableStream; }; Response: { type: Response['type']; url: string; status: number; statusText: string; headers: Headers; body: Response['body']; redirected: boolean; }; Class: { classId: string; }; /** * Custom serialized class instance. * The class must have a `classId` property and be registered for deserialization. */ Instance: { classId: string; data: unknown; }; Set: any[]; StepFunction: { stepId: string; closureVars?: Record; boundThis?: unknown; boundArgs?: unknown[]; }; URL: string; URLSearchParams: string; Uint8Array: string; Uint8ClampedArray: string; Uint16Array: string; Uint32Array: string; WritableStream: { name: string; /** * The runId of the workflow run that owns the underlying server * stream. Present only when the writable was forwarded across a * `start()` boundary (parent → child). When omitted, the writable * belongs to the receiving run (the normal in-run case). */ runId?: string; /** * The deployment that owns the server stream. Carried with `runId` * so a child on a newer deployment can resolve the parent's key. */ deploymentId?: string; }; } type Reducers = { [K in keyof SerializableSpecial]: (value: any) => SerializableSpecial[K] | false; }; type Revivers = { [K in keyof SerializableSpecial]: (value: SerializableSpecial[K]) => any; }; /** * Reducers for serialization boundary from the client side, passing arguments * to the workflow handler. * * @param global * @param ops * @param runId * @param cryptoKey * @param framedByteStreams - When `true`, byte streams (`type: 'bytes'`) * are wrapped in length-prefixed frames on the wire so the consumer * can reconnect on transient errors. Should match the target run's * capability — see `getRunCapabilities` in `capabilities.ts`. Defaults * to `false` for backwards compatibility with older runs. * @returns */ export declare function getExternalReducers(global: Record | undefined, ops: Promise[], runId: string, cryptoKey: EncryptionKeyParam, framedByteStreams?: boolean): Reducers; /** * Reducers for serialization boundary from within the workflow execution * environment, passing return value to the client side and into step arguments. * * @param global * @returns */ export declare function getWorkflowReducers(global?: Record): Reducers; export declare function getCommonRevivers(global?: Record): { readonly ArrayBuffer: (value: string) => any; readonly BigInt: (value: string) => any; readonly BigInt64Array: (value: string) => any; readonly BigUint64Array: (value: string) => any; readonly Date: (value: string) => any; readonly DOMException: (value: { message: string; name: string; stack?: string; cause?: unknown; }) => any; readonly Error: (value: Record) => any; readonly Float32Array: (value: string) => any; readonly Float64Array: (value: string) => any; readonly Headers: (value: [string, string][]) => any; readonly Int8Array: (value: string) => any; readonly Int16Array: (value: string) => any; readonly Int32Array: (value: string) => any; readonly Map: (value: [any, any][]) => any; readonly RegExp: (value: { source: string; flags: string; }) => any; readonly Class: (value: { classId: string; }) => Function; readonly Instance: (value: { classId: string; data: unknown; }) => any; readonly Set: (value: any[]) => any; readonly URL: (value: string) => any; readonly URLSearchParams: (value: string) => any; readonly Uint8Array: (value: string) => any; readonly Uint8ClampedArray: (value: string) => any; readonly Uint16Array: (value: string) => any; readonly Uint32Array: (value: string) => any; }; /** * Revivers for deserialization boundary from the client side, * receiving the return value from the workflow handler. * * @param global * @param ops * @param runId */ export declare function getExternalRevivers(global: Record | undefined, ops: Promise[], runId: string, cryptoKey: EncryptionKeyParam): Revivers; /** * Revivers for deserialization boundary from within the workflow execution * environment, receiving arguments from the client side, and return values * from the steps. * * @param global * @returns */ export declare function getWorkflowRevivers(global?: Record): Revivers; /** * Encrypt data if the world supports encryption. * Returns original data if encryption is not available. * * @param data - Serialized data to encrypt * @param key - Encryption key (undefined to skip encryption) * @param context - Encryption context with runId * @returns Encrypted data if encryption available, original data otherwise */ export declare function maybeEncrypt(data: Uint8Array, key: CryptoKey | undefined): Promise; /** * Decrypt data if it has the 'encr' prefix. * * @param data - Data that may be encrypted * @param key - Encryption key (undefined if no key available) * @returns Decrypted data if encrypted, original data otherwise * @throws {WorkflowRuntimeError} If the data is encrypted but no key is * available. Callers (e.g., `Run.pollReturnValue()`, `hydrateStepReturnValue`) * should be aware this can surface as a rejected promise during key rotation * or misconfiguration scenarios. */ export declare function maybeDecrypt(data: Uint8Array | unknown, key: CryptoKey | undefined): Promise; /** * Called from the `start()` function to serialize the workflow arguments * into a format that can be saved to the database and then hydrated from * within the workflow execution environment. * * @param value - The value to serialize * @param runId - The workflow run ID (required for encryption context) * @param key - Encryption key (undefined to skip encryption) * @param ops - Promise array for stream operations * @param global - Global object for serialization context * @param v1Compat - Enable legacy v1 compatibility mode * @param framedByteStreams - Whether the target run can decode wire-framed * byte streams. Should match the target deployment's capability — see * `getRunCapabilities` in `capabilities.ts`. Defaults to `false` for * backwards compatibility with older runs. * @returns The dehydrated value as binary data (Uint8Array) with format prefix */ export declare function dehydrateWorkflowArguments(value: unknown, runId: string, key: CryptoKey | undefined, ops?: Promise[], global?: Record, v1Compat?: boolean, framedByteStreams?: boolean): Promise; /** * Called from workflow execution environment to hydrate the workflow * arguments from the database at the start of workflow execution. * * @param value - Binary serialized data (Uint8Array) with format prefix * @param _runId - Workflow run ID (reserved for future decryption context; decryption is currently driven solely by the provided key) * @param key - Encryption key (undefined to skip decryption) * @param global - Global object for deserialization context * @param extraRevivers - Additional revivers for custom types * @returns The hydrated value */ export declare function hydrateWorkflowArguments(value: Uint8Array | unknown, _runId: string, key: CryptoKey | undefined, global?: Record, extraRevivers?: Record any>): Promise; /** * Dehydrate workflow return value for storage. * * @param value - The value to serialize * @param runId - Run ID for encryption context * @param key - Encryption key (undefined to skip encryption) * @param global - Global object for serialization context * @returns The dehydrated value as binary data (Uint8Array) with format prefix */ export declare function dehydrateWorkflowReturnValue(value: unknown, _runId: string, key: CryptoKey | undefined, global?: Record, v1Compat?: boolean): Promise; /** * Called from the client side (i.e. the execution environment where * the workflow run was initiated from) to hydrate the workflow * return value of a completed workflow run. * * @param value - Binary serialized data (Uint8Array) with format prefix * @param runId - Run ID for decryption context * @param key - Encryption key (undefined to skip decryption) * @param ops - Promise array for stream operations * @param global - Global object for deserialization context * @param extraRevivers - Additional revivers for custom types * @returns The hydrated return value, ready to be consumed by the client */ export declare function hydrateWorkflowReturnValue(value: Uint8Array | unknown, runId: string, key: CryptoKey | undefined, ops?: Promise[], global?: Record, extraRevivers?: Record any>): Promise; /** * Called from the workflow handler when a step is being created. * Dehydrates values from within the workflow execution environment * into a format that can be saved to the database. * * @param value - The value to serialize * @param runId - Run ID for encryption context * @param key - Encryption key (undefined to skip encryption) * @param global - Global object for serialization context * @param v1Compat - Enable legacy v1 compatibility mode * @returns The dehydrated value as binary data (Uint8Array) with format prefix */ export declare function dehydrateStepArguments(value: unknown, _runId: string, key: CryptoKey | undefined, global?: Record, v1Compat?: boolean): Promise; /** * Called from the step handler to hydrate the arguments of a step * from the database at the start of the step execution. * * @param value - Binary serialized data (Uint8Array) with format prefix * @param runId - Run ID for decryption context * @param key - Encryption key (undefined to skip decryption) * @param ops - Promise array for stream operations * @param global - Global object for deserialization context * @param extraRevivers - Additional revivers for custom types * @returns The hydrated value, ready to be consumed by the step user-code function */ export declare function hydrateStepArguments(value: Uint8Array | unknown, runId: string, key: CryptoKey | undefined, ops?: Promise[], global?: Record, extraRevivers?: Record any>, deploymentId?: string): Promise; /** * Called from the step handler when a step has completed. * Dehydrates values from within the step execution environment * into a format that can be saved to the database. * * @param value - The value to serialize * @param runId - Run ID for encryption context * @param key - Encryption key (undefined to skip encryption) * @param ops - Promise array for stream operations * @param global - Global object for serialization context * @param v1Compat - Enable legacy v1 compatibility mode * @param framedByteStreams - Whether the target run can decode wire-framed * byte streams. Should match the target deployment's capability — see * `getRunCapabilities` in `capabilities.ts`. Defaults to `false` for * backwards compatibility with older runs. * @returns The dehydrated value as binary data (Uint8Array) with format prefix */ export declare function dehydrateStepReturnValue(value: unknown, runId: string, key: CryptoKey | undefined, ops?: Promise[], global?: Record, v1Compat?: boolean, framedByteStreams?: boolean): Promise; /** * Called from the workflow handler when replaying the event log of a `step_completed` event. * Hydrates the return value of a step from the database. * * @param value - Binary serialized data (Uint8Array) with format prefix * @param runId - Run ID for decryption context * @param key - Encryption key (undefined to skip decryption) * @param global - Global object for deserialization context * @param extraRevivers - Additional revivers for custom types * @returns The hydrated return value of a step, ready to be consumed by the workflow handler */ export declare function hydrateStepReturnValue(value: Uint8Array | unknown, _runId: string, key: CryptoKey | undefined, global?: Record, extraRevivers?: Record any>): Promise; export {}; //# sourceMappingURL=serialization.d.ts.map