/** * @module event-sourcing * @category Internal * * Pure event-sourcing primitives: `snap` persists state checkpoints, `load` * reconstructs state by folding events through reducers, and `action` * validates an action, runs invariants, emits events, and commits them * atomically. `tombstone` commits the close-the-books guard with optimistic * concurrency. * * These are the bare implementations — observability is layered on top in * {@link "tracing"} and wired by the orchestrator at construction time. * No tracing imports here, no module-level mutable state. * * @internal */ import { type Patch } from "@rotorsoft/act-patch"; import type { Committed, DoOptions, EventSource, LoadTarget, ScanOptions, ScanResult, Schema, Schemas, Snapshot, State, Target } from "../types/index.js"; /** * The reduction pipeline names three distinct things, and each word means * exactly one of them: * * - a **reducer** is a state's `.patch()` handler — it takes one event and * returns a {@link Patch} *partial*; * - a **patch step** ({@link bare_patch} / {@link validating_patch}) merges * that partial into the current state, yielding the next full state; * - the **fold** is the loop that applies the patch step across a stream's * events (the reader loop in {@link load} / {@link action}, and the * projection engine in {@link "projection-fold"}). * * `PatchFn` is the per-event patch step. The fold loop calls one of two * implementations, selected **once** at construction (in * {@link "tracing".build_es}) — never branched per event: * * - {@link bare_patch} — the default. Literally `patch(state, partial)`, * no wrapper. This is the pre-ACT-1238 hot path, byte-for-byte. * - {@link validating_patch} — the opt-in `ActOptions.validateFoldedState` * path. Merges, then parses the merged full state against the state's * declared Zod schema. * * The `me`/`event` arguments are unused by the bare implementation but * carried on the shared signature so the fold loop is call-shape-identical * regardless of which patch step was selected — the validating * implementation needs them to name the failing reduction. * * @internal */ export type PatchFn = (me: State, state: TState, partial: Readonly>, event: Committed) => TState; /** * The default patch step: a bare `patch()` merge with no wrapper and no * branch. The off-path is byte-for-byte the pre-ACT-1238 reduction, so an * app that leaves `validateFoldedState` off pays nothing — not even a * comparison. * * @internal */ export declare const bare_patch: PatchFn; /** * The opt-in patch step (ACT-1238): merge the partial into state, then * parse the merged full state against the owning state's declared Zod * schema. A reducer that produces schema-violating state (the calculator * divide-by-zero NaN class, #1230) fails here, at the triggering event, * instead of propagating and surfacing hops later as a confusing * downstream error. * * The `target` string names the state and the triggering event * (`".#"`) so the resulting {@link ValidationError} * points straight at the reduction that produced bad state. A debugging / * CI aid, not a production guard — selected only when the operator opts * in. * * @internal */ export declare const validating_patch: PatchFn; /** * Internal action signature seen by the orchestrator — the {@link Correlator} * is bound at `build_es` time, so callers don't pass it through. * * @internal */ export type BoundAction = (me: State, action: TKey, target: Target, payload: Readonly, options?: DoOptions) => Promise[]>; /** @internal */ export interface EsOps { snap: typeof snap; load: typeof load; action: BoundAction; tombstone: typeof tombstone; } /** * Event sourcing utilities for snapshotting, loading, and committing actions/events. * Used internally by Act and state machines. */ /** * Saves a snapshot of the state to the store. * * Snapshots are used to optimize state reconstruction for aggregates with long event streams. * * @template TState The type of state * @template TEvents The type of events * @param snapshot The snapshot to save * @returns Promise that resolves when the snapshot is saved * * @example * await snap(snapshot); */ export declare function snap(snapshot: Snapshot): Promise | undefined>; /** * Commits a tombstone event with optimistic concurrency, returning the * committed record on success or `undefined` if the stream moved past * `expectedVersion` (concurrent write detected). Other store errors * propagate. * * Used by `close()` to guard a stream while archive/truncate runs: * subsequent `action()` calls see the tombstone at head and reject with * {@link StreamClosedError} until the close completes. * * @internal */ export declare function tombstone(stream: string, expectedVersion: number, correlation: string): Promise | undefined>; /** * Scan a restore source event by event. Owns pagination, validation, * the `drop_snapshots` filter, the `on_progress` callback, and the * causation remap; adapters supply only the per-event insert * `callback` via the driver pattern (see {@link Store.restore}). * * Walks the source in chunks of {@link BATCH} via the existing * `EventSource.query` interface — `limit: BATCH` and `after: ` per batch (ACT-1133). Stores that respect `limit` * (`PostgresStore`) return at most `BATCH` rows per call; sources * that ignore the filter (`CsvFile`) stream everything in one call * and the loop exits after the first batch when `got > BATCH`. The * source's own per-event `await Promise.resolve(callback(event))` * provides backpressure — no separate mailbox needed. * * Throws on the first invalid event (negative version, malformed * `created`) with the running index in the message. * * Returns the partial {@link ScanResult} (without `duration_ms`) * — {@link Act.restore} wraps the call with its own timing so the * duration covers transaction setup and commit, not just iteration. * * @internal */ export declare function scan(source: EventSource, opts?: ScanOptions, callback?: (event: Committed) => Promise): Promise>; /** * Loads a snapshot of the state from the store by folding events through the * state's patch reducers. * * First checks the cache for a checkpoint, then queries the store for events * committed after the cached position. On cache miss, replays from the store * (using snapshots if available to avoid full replay). * * @template TState The type of state * @template TEvents The type of events * @template TActions The type of actions * @param me The state machine definition. * @param stream The stream (instance) to load * @param callback (Optional) Callback to receive the loaded snapshot as it is built * @param asOf (Optional) Time-travel cursor; bypasses the cache. * @param actor (Optional) Passed through to the state's `view` delegate * when constructing the snapshot.event — semantics are the state's to * define (see {@link state}). * @returns The snapshot of the loaded state * * @example * const snapshot = await load(Counter, "counter1"); */ export declare function load(me: State, target: LoadTarget, callback?: (snapshot: Snapshot) => void, patch_fn?: PatchFn): Promise>; /** * Executes an action and emits an event to be committed by the store. * * Validates the action, applies business invariants, emits events, and * commits them to the event store. When the action's * {@link ActionOptions} declare a retry budget, the orchestrator owns * the loop on {@link ConcurrencyError}: cache is invalidated, optional * `backoff` delay is applied, and the action re-runs from `load`. Any * other error rethrows immediately and does not consume the budget. * * Reactions skip optimistic concurrency (commit below passes * `undefined` as `expectedVersion` when `reactingTo` is set), so * `ConcurrencyError` cannot fire on the reaction-driven path — the * loop is naturally a no-op there. * * @template TState The type of state * @template TEvents The type of events * @template TActions The type of action_schemas * @template TKey The type of action to execute * @param me The state machine definition * @param action The action to execute * @param target The target (stream, actor, etc.) * @param payload The payload of the action * @param options Per-call dispatch options ({@link DoOptions}) — * `reactingTo` to thread correlation, `correlator` to override the * framework or orchestrator-level correlator for this call only. * @returns The snapshot of the committed event * * @example * const snapshot = await action(Counter, "increment", { stream: "counter1", actor }, { by: 1 }); */ export declare function action(me: State, action: TKey, target: Target, payload: Readonly, options?: DoOptions, patch_fn?: PatchFn): Promise[]>; //# sourceMappingURL=event-sourcing.d.ts.map