import type { Logger } from "pino"; /** * Index into the entry name registry. * Names are stored once and referenced by this index to avoid repetition. */ export type NameIndex = number; /** * A segment in a location path. * Either a name index (for named entries) or a loop iteration marker. */ export type PathSegment = NameIndex | LoopIterationMarker; /** * Marker for a loop iteration in a location path. */ export interface LoopIterationMarker { loop: NameIndex; iteration: number; } /** * Location identifies where an entry exists in the workflow execution tree. * It forms a path from the root through loops, joins, and branches. */ export type Location = PathSegment[]; /** * Current state of a sleep entry. */ export type SleepState = "pending" | "completed" | "interrupted"; /** * Status of an entry in the workflow. */ export type EntryStatus = | "pending" | "running" | "completed" | "failed" | "exhausted"; /** * Status of a branch in join/race. */ export type BranchStatusType = | "pending" | "running" | "completed" | "failed" | "cancelled"; /** * Current state of the workflow. */ export type WorkflowState = | "pending" | "running" | "sleeping" | "failed" | "completed" | "cancelled" | "rolling_back"; /** * Step entry data. */ export interface StepEntry { output?: unknown; error?: string; } /** * Loop entry data. */ export interface LoopEntry { state: unknown; iteration: number; output?: unknown; } /** * Sleep entry data. */ export interface SleepEntry { deadline: number; state: SleepState; } /** * Message entry data. */ export interface MessageEntry { name: string; data: unknown; } /** * Rollback checkpoint entry data. */ export interface RollbackCheckpointEntry { name: string; } /** * Branch status for join/race entries. */ export interface BranchStatus { status: BranchStatusType; output?: unknown; error?: string; } /** * Join entry data. */ export interface JoinEntry { branches: Record; } /** * Race entry data. */ export interface RaceEntry { winner: string | null; branches: Record; } /** * Removed entry data - placeholder for removed steps in workflow migrations. */ export interface RemovedEntry { originalType: EntryKindType; originalName?: string; } /** * Version check entry data - records which version of a code path this * workflow instance is pinned to at a given location. */ export interface VersionCheckEntry { /** The version this instance resolved to at this location. */ resolved: number; /** The `latest` value seen when this entry was first resolved (diagnostics). */ latest: number; } /** * All possible entry kind types. */ export type EntryKindType = | "step" | "loop" | "sleep" | "message" | "rollback_checkpoint" | "join" | "race" | "removed" | "version_check"; /** * Type-specific entry data. */ export type EntryKind = | { type: "step"; data: StepEntry } | { type: "loop"; data: LoopEntry } | { type: "sleep"; data: SleepEntry } | { type: "message"; data: MessageEntry } | { type: "rollback_checkpoint"; data: RollbackCheckpointEntry } | { type: "join"; data: JoinEntry } | { type: "race"; data: RaceEntry } | { type: "removed"; data: RemovedEntry } | { type: "version_check"; data: VersionCheckEntry }; /** * An entry in the workflow history. */ export interface Entry { id: string; location: Location; kind: EntryKind; dirty: boolean; } /** * Metadata for an entry (stored separately, lazily loaded). */ export interface EntryMetadata { status: EntryStatus; error?: string; attempts: number; lastAttemptAt: number; createdAt: number; completedAt?: number; rollbackCompletedAt?: number; rollbackError?: string; dirty: boolean; } /** * A message in the queue. */ export interface Message { /** Unique message ID. */ id: string; name: string; data: unknown; sentAt: number; /** * Optional completion callback for queue-backed drivers. * * This is runtime-only and is not persisted. */ complete?: (response?: unknown) => Promise; } /** * Options for receiving queue messages in workflows. */ export interface WorkflowQueueNextOptions { /** * Queue names to receive from. * If omitted, receives from all queue names. */ names?: readonly string[]; /** * Timeout in milliseconds. * Omit to wait indefinitely. */ timeout?: number; /** Whether returned messages must be manually completed. */ completable?: boolean; } /** * Options for receiving a batch of queue messages in workflows. */ export interface WorkflowQueueNextBatchOptions extends WorkflowQueueNextOptions { /** Maximum number of messages to receive. Defaults to 1. */ count?: number; } /** * Message returned by workflow queue operations. */ export interface WorkflowQueueMessage { id: string | bigint; name: string; body: TBody; createdAt: number; complete?(response?: unknown): Promise; } /** * Workflow queue interface. */ export interface WorkflowQueue { next( name: string, opts?: WorkflowQueueNextOptions, ): Promise>; nextBatch( name: string, opts?: WorkflowQueueNextBatchOptions, ): Promise>>; send(name: string, body: unknown): Promise; } /** * Workflow history - maps location keys to entries. */ export interface History { entries: Map; } /** * History entry snapshot without internal dirty flags. */ export type WorkflowHistoryEntry = Omit; /** * Entry metadata snapshot without internal dirty flags. */ export type WorkflowEntryMetadataSnapshot = Omit; /** * Snapshot of workflow history for observers. */ export interface WorkflowHistorySnapshot { nameRegistry: string[]; entries: WorkflowHistoryEntry[]; entryMetadata: ReadonlyMap; } /** * Structured error information for workflow failures. */ export interface WorkflowError { /** Error name/type (e.g., "TypeError", "CriticalError") */ name: string; /** Error message */ message: string; /** Stack trace if available */ stack?: string; /** Custom error properties (for structured errors) */ metadata?: Record; } /** * Error event emitted while a workflow is running. */ export interface WorkflowStepErrorEvent { workflowId: string; stepName: string; attempt: number; maxRetries: number; remainingRetries: number; willRetry: boolean; retryDelay?: number; retryAt?: number; error: WorkflowError; } /** * Error event emitted when a rollback handler fails. */ export interface WorkflowRollbackErrorEvent { workflowId: string; stepName: string; error: WorkflowError; } /** * Error event emitted for workflow-level failures outside individual steps. */ export interface WorkflowRunErrorEvent { workflowId: string; error: WorkflowError; } export type WorkflowErrorEvent = | { step: WorkflowStepErrorEvent } | { rollback: WorkflowRollbackErrorEvent } | { workflow: WorkflowRunErrorEvent }; export type WorkflowErrorHandler = ( event: WorkflowErrorEvent, ) => void | Promise; /** * Complete storage state for a workflow. */ export interface Storage { nameRegistry: string[]; flushedNameCount: number; history: History; entryMetadata: Map; output?: unknown; state: WorkflowState; flushedState?: WorkflowState; error?: WorkflowError; flushedError?: WorkflowError; flushedOutput?: unknown; } /** * Driver interface for workflow message persistence. */ export interface WorkflowMessageDriver { addMessage(message: Message): Promise; /** * Receive messages directly from the host queue implementation. * The operation must be non-blocking and return immediately. */ receiveMessages(opts: { names?: readonly string[]; count: number; completable: boolean; }): Promise; /** * Complete a previously consumed message with an optional response payload. */ completeMessage(messageId: string, response?: unknown): Promise; } /** * Context available to rollback handlers. */ export interface RollbackContextInterface { readonly workflowId: string; readonly abortSignal: AbortSignal; isEvicted(): boolean; } /** * Configuration for a step. */ export interface StepConfig { name: string; run: () => Promise; rollback?: (ctx: RollbackContextInterface, output: T) => Promise; /** If true, step result is not persisted (use for idempotent operations). */ ephemeral?: boolean; /** Maximum number of retry attempts (default: 3). */ maxRetries?: number; /** Base delay in ms for exponential backoff (default: 100). */ retryBackoffBase?: number; /** Maximum delay in ms for exponential backoff (default: 30000). */ retryBackoffMax?: number; /** Timeout in ms for step execution (default: 30000). Set to 0 to disable. */ timeout?: number; /** If true, step timeouts retry like any other error instead of failing immediately as critical. Default: false. */ retryOnTimeout?: boolean; } export type TryStepCatchKind = | "critical" | "timeout" | "exhausted" | "rollback"; export interface TryStepFailure { kind: TryStepCatchKind; stepName: string; attempts: number; error: WorkflowError; } export type TryStepResult = | { ok: true; value: T } | { ok: false; failure: TryStepFailure }; export interface TryStepConfig extends StepConfig { catch?: readonly TryStepCatchKind[]; } export type TryBlockCatchKind = "step" | "join" | "race" | "rollback"; export interface TryBlockFailure { source: "step" | "join" | "race" | "block"; name: string; error: WorkflowError; step?: TryStepFailure; } export type TryBlockResult = | { ok: true; value: T } | { ok: false; failure: TryBlockFailure }; export interface TryBlockConfig { name: string; run: (ctx: WorkflowContextInterface) => Promise; catch?: readonly TryBlockCatchKind[]; } /** * Result from a loop iteration. */ export type LoopResult = | { continue: true; state: S } | { break: true; value: T }; /** * Return type for a loop iteration callback. * * Stateless loops (state = undefined) may return void/undefined, which is treated as * `Loop.continue(undefined)`. */ export type LoopIterationResult = Promise< LoopResult | (S extends undefined ? undefined : never) >; /** * Configuration for a loop. */ export interface LoopConfig { name: string; state?: S; run: (ctx: WorkflowContextInterface, state: S) => LoopIterationResult; /** Prune old loop iterations every N iterations. Default: 20. */ historyPruneInterval?: number; /** Number of past iterations to retain when pruning. Defaults to historyPruneInterval. */ historySize?: number; /** @deprecated Use historyPruneInterval. */ commitInterval?: number; /** @deprecated Use historyPruneInterval. */ historyEvery?: number; /** @deprecated Use historySize. */ historyKeep?: number; } /** * Configuration for a branch in join/race. */ export interface BranchConfig { run: (ctx: WorkflowContextInterface) => Promise; } /** * Extract the output type from a BranchConfig. */ export type BranchOutput = T extends BranchConfig ? O : never; /** * The workflow context interface exposed to workflow functions. */ export interface WorkflowContextInterface { readonly workflowId: string; readonly abortSignal: AbortSignal; readonly queue: WorkflowQueue; step(name: string, run: () => Promise): Promise; step(config: StepConfig): Promise; tryStep(name: string, run: () => Promise): Promise>; tryStep(config: TryStepConfig): Promise>; try( name: string, run: (ctx: WorkflowContextInterface) => Promise, ): Promise>; try(config: TryBlockConfig): Promise>; loop( name: string, run: ( ctx: WorkflowContextInterface, ) => LoopIterationResult, ): Promise; loop(config: LoopConfig): Promise; sleep(name: string, durationMs: number): Promise; sleepUntil(name: string, timestampMs: number): Promise; rollbackCheckpoint(name: string): Promise; join>>( name: string, branches: T, ): Promise<{ [K in keyof T]: BranchOutput }>; race( name: string, branches: Array<{ name: string; run: (ctx: WorkflowContextInterface) => Promise; }>, ): Promise<{ winner: string; value: T }>; removed(name: string, originalType: EntryKindType): Promise; getVersion(name: string, latest: number): Promise; isEvicted(): boolean; } /** * Workflow function type. */ export type WorkflowRunMode = "yield" | "live"; export interface RunWorkflowOptions { mode?: WorkflowRunMode; logger?: Logger; onHistoryUpdated?: (history: WorkflowHistorySnapshot) => void; onError?: WorkflowErrorHandler; } export type WorkflowFunction = ( ctx: WorkflowContextInterface, input: TInput, ) => Promise; /** * Result returned when a workflow run completes or yields. */ export interface WorkflowResult { state: WorkflowState; output?: TOutput; sleepUntil?: number; waitingForMessages?: string[]; } /** * Handle for managing a running workflow. * * Returned by `runWorkflow()`. The workflow starts executing immediately. * Use `.result` to await completion, and other methods to interact with * the running workflow. */ export interface WorkflowHandle { readonly workflowId: string; /** * Promise that resolves when the workflow completes or yields. */ readonly result: Promise>; /** * Send a message to the workflow. * The message is delegated to the runtime message driver. * In live mode, this wakes workflows waiting on queue messages. */ message(name: string, data: unknown): Promise; /** * Wake the workflow immediately by setting an alarm for now. */ wake(): Promise; /** * Reset exhausted retries and schedule the workflow to run again. */ recover(): Promise; /** * Request the workflow to stop gracefully. * The workflow will throw EvictedError at its next yield point, * flush its state, and resolve the result promise. */ evict(): void; /** * Cancel the workflow permanently. * Sets the workflow state to "cancelled" and clears any pending alarms. * Unlike evict(), this marks the workflow as permanently stopped. */ cancel(): Promise; /** * Get the workflow output if completed. */ getOutput(): Promise; /** * Get the current workflow state. */ getState(): Promise; }