//#region src/dispatcher.d.ts /** * Shared iteration budget for cooperating dispatchers. * * A Lease is a plain mutable record. Dispatchers mutate its fields * directly; no methods. When `depth` goes 0→1 a dispatcher becomes the * owner and resets `iterations`/`history`/`counts`/`originStack` on its * eventual 1→0 exit. * * Diagnostic instrumentation (history, counts, originStack) supports * `BudgetExhaustedError`'s message: * - `history` — bounded ring buffer of recent `{label, type}` events. * - `counts` — cumulative `${label}:${type}` → count over the whole drain. * - `originStack` — captured at the cascade's entry point (depth 0→1). * Names the boundary where the dispatch system was re-entered from * outside (userland for client-side flows, transport for server-side). */ type Lease = { depth: number; iterations: number; readonly budget: number; history: { label: string; type: string; }[]; readonly historyCapacity: number; counts: Map; originStack: string | undefined; }; type LeaseOptions = { budget?: number; historyCapacity?: number; }; declare function createLease(options?: LeaseOptions): Lease; declare class BudgetExhaustedError extends Error { readonly lease: Lease; readonly label: string; constructor(label: string, lease: Lease); } type DispatcherOptions = { lease?: Lease; label?: string; }; interface DispatcherHandle { dispatch(msg: Msg): void; readonly queueDepth: number; } /** * Drain-to-quiescence dispatcher with optional shared budget. * * Re-entrant `dispatch(msg)` from inside the handler — including from * another `DispatcherHandle.dispatch(...)` sharing the same Lease — * joins the current drain rather than recursing. This is the property * that lets cooperating dispatchers compose: an A→B→A oscillation is * one cascade in one lease, not a stack overflow. */ declare function createDispatcher(handler: (msg: Msg, dispatch: (msg: Msg) => void) => void, options?: DispatcherOptions): DispatcherHandle; //#endregion //#region src/machine.d.ts /** Dispatch a message into a running program. */ type Dispatch = (msg: Msg) => void; /** An effect is a continuation that may dispatch messages. */ type Effect = (dispatch: Dispatch) => void; /** * A Mealy machine — pure state transitions with effect outputs. * * `Fx` defaults to `Effect` (closure effects) but can be any * data type for programs with custom effect executors. * * - `init`: initial state and zero or more effects to execute at startup. * - `update`: pure transition — given a message and the current state, * return the new state and zero or more effects. * - `done`: optional teardown hook, called with the final state when * the runtime is disposed. */ type Program> = { init: [Model, ...Fx[]]; update(msg: Msg, model: Model): [Model, ...Fx[]]; done?(model: Model): void; }; /** Dispose a running program — stops message processing and calls `done`. */ type Disposer = () => void; /** * Run a program whose effects are `Effect` closures. * * The runtime: * 1. Extracts `[model, ...effects]` from `program.init`. * 2. Executes each initial effect with `dispatch`. * 3. Calls `view(model, dispatch)` if provided. * 4. On `dispatch(msg)`: calls `update(msg, state)`, updates state, * executes effects, calls `view`. * 5. Returns a `Disposer` that stops dispatch and calls `program.done`. * * Effects are executed synchronously in order. An effect may call * `dispatch` re-entrantly — the runtime processes re-entrant messages * after the current dispatch cycle completes (queue-based). */ declare function runtime(program: Program, view?: (model: Model, dispatch: Dispatch) => void): Disposer; //#endregion //#region src/observable.d.ts /** * A state transition event — from one model to another. * * Generic over the model type. This is the machine-level primitive; * transport packages re-export or alias it for their specific state types. */ type StateTransition = { from: S; to: S; timestamp: number; }; /** * Listener for state transitions. */ type TransitionListener = (transition: StateTransition) => void; /** * Handle for a running observable program. * * Provides dispatch, state access, transition observation, and disposal. * The observation API (`subscribeToTransitions`, `waitForState`, `waitForStatus`) * matches the surface of the former `ClientStateMachine`. */ interface ObservableHandle { /** Dispatch a message into the program. */ dispatch: Dispatch; /** Get the current model synchronously. */ getState(): Model; /** * Subscribe to state transitions. * * Transitions are delivered synchronously after each update. * Returns an unsubscribe function. */ subscribeToTransitions(listener: TransitionListener): () => void; /** * Wait for a specific state. * * Resolves immediately if the current state matches the predicate. * Otherwise waits for a transition that matches. */ waitForState(predicate: (state: Model) => boolean, options?: { timeoutMs?: number; }): Promise; /** * Wait for a specific status string on a model with a `status` discriminant. * * Convenience wrapper around `waitForState()`. */ waitForStatus(this: ObservableHandle, status: S["status"], options?: { timeoutMs?: number; }): Promise; /** * Dispose the program — stops dispatch and calls `program.done`. */ dispose(): void; } /** * Run a program with data effects and state observation. * * Like `runtime()`, but instead of executing closure effects directly, * it delegates to a custom `executor` for each data effect. This enables * programs whose effects are inspectable data types (not opaque closures). * * The runtime: * 1. Extracts `[model, ...effects]` from `program.init`. * 2. Executes each initial effect via `executor(effect, dispatch)`. * 3. On `dispatch(msg)`: calls `update(msg, state)`, updates state, * notifies transition listeners, executes effects. * 4. Re-entrant dispatch (effect calls dispatch) is queued and processed * after the current dispatch cycle completes. * 5. `dispose()` stops dispatch and calls `program.done`. * * @param program - The program algebra: init, update, done. * @param executor - Interprets data effects as I/O. * @returns An observable handle for the running program. */ declare function createObservableProgram(program: Program, executor: (effect: Fx, dispatch: Dispatch) => void, options?: { lease?: Lease; label?: string; }): ObservableHandle; //#endregion export { BudgetExhaustedError, type Dispatch, type DispatcherHandle, type DispatcherOptions, type Disposer, type Effect, type Lease, type LeaseOptions, type ObservableHandle, type Program, type StateTransition, type TransitionListener, createDispatcher, createLease, createObservableProgram, runtime }; //# sourceMappingURL=index.d.ts.map