/** * Continuation stack serialization and deserialization. * * When a host handler calls `suspend(meta?)`, the trampoline captures the * continuation stack (an array of Frame objects). This module converts that * stack to/from a JSON string (the "suspension blob") that can be stored, * transferred, and later resumed in a new process. * * The main challenge is that Frame objects contain `ContextStack` class * instances (which hold lexical scope chains). These are not plain data * and may form circular references (e.g., a global context containing a * UserDefinedFunction whose captured env references the same global context). * * The serialization approach: * 1. Walk the frame tree and collect all unique ContextStack instances (by identity) * 2. Assign each a numeric ID * 3. Serialize ContextStacks separately as plain objects * 4. In the frame tree, replace ContextStack references with `{ __csRef: id }` * 5. First occurrence of each ContextStack gets `{ __csDef: id, ... }` in the * contextStacks array — circular refs just become `{ __csRef: id }` * * Deserialization reverses this: * 1. Parse the blob and create placeholder ContextStack instances * 2. Deep-resolve all `__csRef` markers back to real instances * 3. Fill in host bindings (values, modules) on each instance */ import type { Any } from '../interface'; import type { DvalaModule } from '../builtin/modules/interface'; import type { Context } from './interface'; import type { Snapshot } from './effectTypes'; import type { ContinuationStack } from './frames'; import type { Step } from './step'; interface SerializedContextStack { id: number; contexts: unknown[]; globalContextIndex: number; pure: boolean; } interface SuspensionBlobData { /** Brand marker to distinguish real blobs from objects that happen to have similar fields */ __suspensionBlob: true; version: number; contextStacks: SerializedContextStack[]; k: unknown; initialStep?: unknown; meta?: Any; snapshots?: unknown[]; nextSnapshotIndex?: number; pool?: Record; } /** * Serialize a continuation stack and optional metadata into a plain * JSON-compatible object tree. * * The returned object is the "continuation" stored inside a `Snapshot`. * It is intentionally typed as `SuspensionBlobData` internally but * exposed as `unknown` via the `Snapshot` interface. * * Validates that all values are serializable. * Throws a descriptive `DvalaError` if non-serializable values are found. */ export declare function serializeToObject(k: ContinuationStack, meta?: unknown, initialStep?: Step): SuspensionBlobData; /** * Build a complete suspension blob that includes both the continuation * and the accumulated snapshot state. Snapshots are already plain * JSON-compatible objects (their `continuation` fields were produced by * earlier `serializeToObject` calls), so they're embedded as-is. * * Runs sub-tree deduplication across all serialized continuations to * reduce blob size when snapshots share identical AST sub-trees. */ export declare function serializeSuspensionBlob(k: ContinuationStack, snapshots: unknown[], nextSnapshotIndex: number, meta?: unknown): SuspensionBlobData; /** * Create a terminal snapshot for completed or errored program states. * The continuation is empty (cannot resume), but checkpoints are preserved * for time travel debugging. */ export declare function serializeTerminalSnapshot(snapshots: unknown[], nextSnapshotIndex: number): SuspensionBlobData; /** Options for deserialization on resume. */ export interface DeserializeOptions { modules?: Map; /** New scope values to inject into the globalContext of all deserialized ContextStacks. */ scope?: Context; } /** * Deserialize a plain object (as produced by `serializeToObject`) back into * a continuation stack and metadata. * * Reconstructs `ContextStack` instances. * Handles circular references between ContextStacks and their contained values. */ export declare function deserializeFromObject(blobData: unknown, options?: DeserializeOptions): { k: ContinuationStack; meta?: Any; snapshots: Snapshot[]; nextSnapshotIndex: number; initialStep?: Step; }; /** * Extract checkpoint snapshots from a serialized continuation blob, * expanding any pool references so each snapshot is a self-contained blob * that can be passed directly to `resume()`. */ export declare function extractCheckpointSnapshots(continuation: unknown): Snapshot[]; export {};