/** * Utils used by the bundler when transforming code */ import type { CryptoKey } from './encryption.js'; import type { EventsConsumer } from './events-consumer.js'; import type { QueueItem } from './global.js'; import type { Serializable } from './schemas.js'; export type StepFunction = ((...args: Args) => Promise) & { maxRetries?: number; stepId?: string; }; /** * Register a step function to be served in the server bundle. * Also sets the stepId property on the function for serialization support. * * Note: The SWC compiler plugin no longer generates calls to this function. * Step registration is now inlined as a self-contained IIFE that writes * directly to the global Map at Symbol.for("@workflow/core//registeredSteps"). * This function is kept for internal/test use only. */ export declare function registerStepFunction(stepId: string, stepFn: StepFunction): void; /** * Find a registered step function by name */ export declare function getStepFunction(stepId: string): StepFunction | undefined; export interface WorkflowOrchestratorContext { runId: string; encryptionKey: CryptoKey | undefined; globalThis: typeof globalThis; eventsConsumer: EventsConsumer; /** * Map of pending invocations keyed by correlationId. * Using Map instead of Array for O(1) lookup/delete operations. */ invocationsQueue: Map; onWorkflowError: (error: Error) => void; generateUlid: () => string; generateNanoid: () => string; /** * Sequential promise queue that ensures all event-driven promise resolutions * (step results, hook payloads, failures, suspensions) happen in event log * order. Every resolve, reject, or workflow error is chained through this * queue so that even if individual operations take variable time (e.g., * async decryption), promises resolve deterministically. */ promiseQueue: Promise; /** * Counter of in-flight async data delivery operations (step result * hydration, hook payload hydration). Suspensions must wait for this * to reach 0 before firing, to avoid preempting data delivery. */ pendingDeliveries: number; /** * Ordered registry of in-flight "branch-deciding" deliveries — the * resolutions a workflow typically `Promise.race`s on: buffered hook * payloads (`hook_received`) and wait completions (`wait_completed`). * Keyed by the delivery's position (index) in the consumed event log. * * The problem: a buffered hook payload is observed via the async hook * iterator (`yield await this`), costing extra microtask hops, while a * `wait_completed` resolves with fewer hops — and a reused sleep can * resolve in an entirely earlier loop iteration. Either way, the * resolution that the committed event log ordered first can lose a * `Promise.race` to a faster- or already-resolved competitor, diverging * from the log and surfacing as `CorruptedEventLogError`. * * The fix is a strict, deterministic delivery order anchored on * event-log position: a delivery does not resolve to the workflow until * every earlier-in-log delivery of the OPPOSITE kind has been delivered. * (Opposite kind only: sequential same-kind hook payloads must not block * one another, and a wait need not wait behind a later wait.) Because the * gate is "the earlier delivery resolved", not "won a timing race", the * outcome is independent of microtask hops, hydration/decryption time, * and `Promise.race` argument order. * * Index is used rather than the `eventId` string because `eventId` is an * opaque, world-assigned value not guaranteed to sort in creation order * (only the bundled ULID worlds happen to). * * Optional so older/out-of-tree contexts (and lightweight test harnesses) * that do not initialize it degrade gracefully to the previous behavior. */ pendingDeliveryBarriers?: Map; } /** The kind of branch-deciding delivery a barrier represents. */ export type DeliveryKind = 'hook' | 'wait'; interface DeliveryBarrierEntry { kind: DeliveryKind; /** Resolves once this delivery has resolved to the workflow. */ delivered: Promise; } /** * Awaits, in strict event-log order, every still-registered delivery whose * index is earlier than `eventIndex` AND whose kind is in `deferBehindKinds`, * so that this resolution is handed to the workflow only after all relevant * earlier-in-log deliveries have been. This is what keeps a `Promise.race` * deterministic and aligned with the committed event log, independent of * microtask-hop counts, hydration time, or race-argument order. * * `deferBehindKinds` is the opposite kind(s): a hook defers behind earlier * WAITS (not earlier hooks — those are sequential same-entity payloads), a * wait defers behind earlier HOOKS. */ export declare function awaitEarlierDeliveries(ctx: WorkflowOrchestratorContext, eventIndex: number | undefined, deferBehindKinds: readonly DeliveryKind[]): Promise; /** Handle for a registered branch-deciding delivery barrier. */ export interface DeliveryBarrier { /** * Mark this delivery as delivered to the workflow. Resolves its * `delivered` promise so any later-in-log opposite-kind delivery gated on * it (via {@link awaitEarlierDeliveries}) may proceed, and removes it from * the registry. Idempotent. */ markDelivered: () => void; } /** * Register a branch-deciding delivery at its event-log index so that later * opposite-kind deliveries can be ordered strictly after it. Returns an inert * handle when `pendingDeliveryBarriers` is not initialized. * * To guarantee a later delivery gated on this one can never hang when this * delivery is abandoned (the workflow took a different branch or is * suspending and never observes it), the barrier auto-resolves at idle. */ export declare function registerDeliveryBarrier(ctx: WorkflowOrchestratorContext, eventIndex: number | undefined, kind: DeliveryKind): DeliveryBarrier; /** * Schedule a callback to fire only after all pending data deliveries * (step results, hook payloads) and async deserialization have completed. * Uses a polling loop: setTimeout(0) → check pendingDeliveries → * if > 0, wait for promiseQueue → repeat. This handles the multi-round * delivery pattern where each hook payload delivery cycle appends new * async work to the promiseQueue. */ export declare function scheduleWhenIdle(ctx: WorkflowOrchestratorContext, fn: () => void): void; export {}; //# sourceMappingURL=private.d.ts.map