/** * Low-level reactive DAG runtime for parameter propagation. * * `GraphRuntime` is the scheduling engine behind `ParamRuntime`. It owns: * 1. Writable source nodes (`base` and `selection`). * 2. Derived/computed nodes with explicit dependencies. * 3. Side-effect nodes that run after computed stabilization. * 4. Transaction-aware batching and deterministic topological flushing. * * Typical usage: * 1. Create writable refs using `createWritable(...)`. * 2. Build derived refs with `computed(...)` from existing refs. * 3. Attach side effects with `effect(...)` when external work is needed. * 4. Batch writes with `runInTransaction(...)` when multiple updates belong to * one logical state transition. * 5. Await `whenPropagated(...)` when callers need a "graph is settled" barrier. * * Notes: * 1. This class is intended for runtime internals; most call sites should use * `ParamRuntime` / `ViewParamRuntime`. * 2. Equality is referential (`!==`), so object writes must use new identities * to trigger propagation. */ export default class GraphRuntime { /** * Creates a graph runtime. * * @param {object} [options] * @param {import("./lifecycleRegistry.js").default} [options.lifecycleRegistry] * Optional lifecycle owner registry. When provided, all created nodes * are bound to owners and disposed automatically on owner disposal. */ constructor(options?: { lifecycleRegistry?: import("./lifecycleRegistry.js").default; }); /** * Registers a writable source node and returns a writable param ref. * * Write semantics: * 1. A write triggers propagation only when `value !== currentValue`. * 2. If `options.notify` is `false`, local listeners are not notified and * downstream scheduling is skipped for writes to this ref. * 3. Writing to a disposed ref throws. * * Lifecycle: * 1. The node is owner-bound via `ownerId`. * 2. Owner disposal marks the node disposed and clears listeners. * * @template T * @param {string} ownerId * @param {string} name * @param {"base" | "selection"} kind * @param {T} initialValue * @param {{ notify?: boolean }} [options] * @returns {import("./types.js").WritableParamRef} */ createWritable(ownerId: string, name: string, kind: "base" | "selection", initialValue: T, options?: { notify?: boolean; }): import("./types.js").WritableParamRef; /** * Registers a derived node whose value is computed from dependencies. * * Compute semantics: * 1. Initial value is computed eagerly at registration time. * 2. On dependency changes, recomputation is queued (deduplicated per flush). * 3. Downstream listeners are notified only if computed value identity changes. * * Lifecycle: * 1. Dependency subscriptions are created immediately. * 2. Owner disposal unsubscribes dependencies and detaches the node. * * @template T * @param {string} ownerId * @param {string} name * @param {import("./types.js").ParamRef[]} deps * @param {() => T} fn * @returns {import("./types.js").ParamRef} */ computed(ownerId: string, name: string, deps: import("./types.js").ParamRef[], fn: () => T): import("./types.js").ParamRef; /** * Registers an effect node that runs after computed propagation. * * Effect semantics: * 1. Effect callbacks are queued on dependency changes. * 2. Effects run after computed nodes for the same flush epoch. * 3. Multiple dependency changes before a flush coalesce to one queued run. * * @param {string} ownerId * @param {import("./types.js").ParamRef[]} deps * @param {() => void} fn * @returns {() => void} explicit disposer for manual teardown */ effect(ownerId: string, deps: import("./types.js").ParamRef[], fn: () => void): () => void; /** * Runs `fn` as an atomic update transaction for this runtime graph. * * Transaction intent: * 1. Batch multiple source writes so downstream computeds/effects observe * the final state for the batch, not each intermediate write. * 2. Defer scheduling/flush until the outermost transaction exits. * 3. Preserve deterministic propagation order by running one flush pass * after the transaction boundary. * * Semantics: * 1. Nested transactions are supported via depth counting. * 2. Only the outermost transaction exit triggers scheduling. * 3. If `fn` throws, the error is rethrown after transaction depth is * restored; pending propagation is still scheduled from `finally`. * 4. The scheduled flush runs in a microtask (`queueMicrotask`) after the * outermost transaction exits. * 5. This method does not force immediate synchronous propagation. Use * `flushNow()` when the caller explicitly requires immediate flushing. * * @template T * @param {() => T} fn * @returns {T} */ runInTransaction(fn: () => T): T; /** * Flushes currently queued computed/effect work immediately. * * Behavior: * 1. No-op if called while a transaction is open. * 2. No-op during re-entrant flush calls. * 3. Runs computeds first, then effects, until the graph reaches a fixed * point for the current queued work. */ flushNow(): void; /** * Returns a promise that resolves when currently pending graph propagation * has completed (computed queue and effect queue are settled). * * This is a synchronization barrier for reactive propagation only. It does * not include animation/time-based convergence semantics. * * @param {{ signal?: AbortSignal, timeoutMs?: number }} [options] * Optional cancellation/timeout controls for waiting callers. * @returns {Promise} */ whenPropagated(options?: { signal?: AbortSignal; timeoutMs?: number; }): Promise; #private; } export type SubscribeFn = (listener: () => void) => () => void; export type RuntimeNodeBase = { id: string; rank: number; disposed: boolean; listeners: Set<() => void>; subscribe: SubscribeFn; }; export type WritableNode = RuntimeNodeBase & { value: T; kind: "base" | "selection"; name: string; }; export type ComputedNode = RuntimeNodeBase & { value: T; kind: "derived"; name: string; fn: () => T; }; export type EffectNode = { id: string; rank: number; disposed: boolean; fn: () => void; }; /** * @param {import("./types.js").ParamRef} ref * @returns {RuntimeNodeBase} */ export function getNode(ref: import("./types.js").ParamRef): RuntimeNodeBase; //# sourceMappingURL=graphRuntime.d.ts.map