awaitly 1.32.0 → 1.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/durable.cjs +3 -3
- package/dist/durable.cjs.map +1 -1
- package/dist/durable.js +3 -3
- package/dist/durable.js.map +1 -1
- package/dist/engine.cjs +3 -3
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.js +3 -3
- package/dist/engine.js.map +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/workflow.cjs +1 -1
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.js +1 -1
- package/dist/workflow.js.map +1 -1
- package/package.json +1 -1
package/dist/durable.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/durable-entry.ts","../src/tagged-error.ts","../src/errors.ts","../src/core/index.ts","../src/workflow/guards.ts","../src/persistence.ts","../src/workflow/cache-encoding.ts","../src/workflow/resume-state.ts","../src/streaming/types.ts","../src/streaming/backpressure.ts","../src/duration.ts","../src/workflow/validation.ts","../src/workflow/execute.ts","../src/durable/index.ts"],"sourcesContent":["/**\n * awaitly/durable\n *\n * Durable execution with automatic state persistence.\n * Re-exports from the main durable module.\n */\n\nexport {\n // Main API\n durable,\n\n // Types\n type DurableOptions,\n type DurableWorkflowEvent,\n type VersionMismatchError,\n type ConcurrentExecutionError,\n type PersistenceError,\n type WorkflowLock,\n type DeleteStatesOptions,\n type DeleteStatesResult,\n\n // Type guards\n isVersionMismatch,\n isConcurrentExecution,\n isPersistenceError,\n isLeaseExpired,\n isIdempotencyConflict,\n\n // New error types\n type LeaseExpiredError,\n type IdempotencyConflictError,\n\n // Re-exports from workflow\n isWorkflowCancelled,\n type WorkflowCancelledError,\n\n // Re-exports from persistence (new snapshot API)\n type SnapshotStore,\n} from \"./durable\";\n","/**\n * awaitly/tagged-error\n *\n * Factory for creating tagged error types with exhaustive pattern matching.\n * Enables TypeScript to enforce that all error variants are handled.\n *\n * @example\n * ```typescript\n * // Define error types (Props via generic)\n * class NotFoundError extends TaggedError(\"NotFoundError\")<{\n * id: string;\n * resource: string;\n * }> {}\n *\n * // Define with type-safe message (Props inferred from callback annotation)\n * class ValidationError extends TaggedError(\"ValidationError\", {\n * message: (p: { field: string; reason: string }) => `Invalid ${p.field}: ${p.reason}`,\n * }) {}\n *\n * // Create instances\n * const error = new NotFoundError({ id: \"123\", resource: \"User\" });\n *\n * // Runtime type check: instanceof TaggedError works!\n * console.log(error instanceof TaggedError); // true\n *\n * // Exhaustive matching\n * type AppError = NotFoundError | ValidationError;\n * const message = TaggedError.match(error as AppError, {\n * NotFoundError: (e) => `Missing: ${e.resource} ${e.id}`,\n * ValidationError: (e) => `Invalid ${e.field}: ${e.reason}`,\n * });\n * ```\n */\n\n/**\n * Options for Error constructor (compatible with ES2022 ErrorOptions).\n */\nexport interface TaggedErrorOptions {\n cause?: unknown;\n}\n\n/**\n * Options for TaggedError factory with type-safe message callback.\n */\nexport interface TaggedErrorCreateOptions<Props extends Record<string, unknown>> {\n /** Custom message generator from props. Annotate parameter for type safety. */\n message: (props: Props) => string;\n}\n\n/**\n * Base interface for all tagged errors.\n */\nexport interface TaggedErrorBase extends Error {\n readonly _tag: string;\n}\n\n/**\n * Internal base class for instanceof checks.\n * All TaggedError-created classes extend this.\n * @internal\n */\nclass InternalTaggedErrorBase extends Error implements TaggedErrorBase {\n readonly _tag!: string;\n}\n\n/**\n * Instance type for factory-created TaggedErrors.\n */\ntype TaggedErrorInstance<Tag extends string, Props> = TaggedErrorBase & {\n readonly _tag: Tag;\n} & Readonly<Props>;\n\n/**\n * Constructor args type - conditionally optional based on whether Props has required fields.\n * - If Props is empty or all properties are optional: props argument is optional\n * - If Props has any required properties: props argument is required\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\ntype ConstructorArgs<Props extends Record<string, unknown>> = {} extends Props\n ? [props?: Props | void, options?: TaggedErrorOptions]\n : [props: Props, options?: TaggedErrorOptions];\n\n/**\n * Constructor type returned by TaggedError factory.\n */\nexport interface TaggedErrorConstructor<\n Tag extends string,\n Props extends Record<string, unknown>,\n> {\n new (...args: ConstructorArgs<Props>): TaggedErrorInstance<Tag, Props>;\n readonly prototype: TaggedErrorInstance<Tag, Props>;\n}\n\n/**\n * Generic class factory type that allows `<Props>` parameterization.\n * This enables the Effect.js-style syntax: `class X extends TaggedError(\"X\")<Props> {}`\n * @internal\n */\nexport interface TaggedErrorClassFactory<Tag extends string> {\n new <Props extends Record<string, unknown> = Record<string, never>>(\n ...args: ConstructorArgs<Props>\n ): TaggedErrorInstance<Tag, Props>;\n}\n\n/**\n * Helper type to extract return type from a function type.\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype FnReturnType<T> = T extends (...args: any[]) => infer R ? R : never;\n\n/**\n * Helper type to get union of return types from all handlers.\n * @internal\n */\ntype HandlersReturnType<H> = { [K in keyof H]: FnReturnType<H[K]> }[keyof H];\n\n/**\n * Helper type to extract keys whose values are definitely functions (not undefined).\n * Only excludes a tag from the fallback type if its handler is guaranteed to be\n * a function. Keys where the value type includes undefined are NOT excluded,\n * ensuring type safety with dynamic/conditional handlers.\n * @internal\n */\ntype DefinitelyHandledKeys<H> = {\n [K in keyof H]-?: undefined extends H[K] ? never : K;\n}[keyof H];\n\n/**\n * Factory function to create tagged error classes.\n *\n * Two usage patterns:\n *\n * 1. **Props via generic** (default message is tag name):\n * ```typescript\n * class NotFoundError extends TaggedError(\"NotFoundError\")<{ id: string }> {}\n * ```\n *\n * 2. **Props inferred from message callback** (type-safe message):\n * ```typescript\n * class NotFoundError extends TaggedError(\"NotFoundError\", {\n * message: (p: { id: string }) => `Not found: ${p.id}`,\n * }) {}\n * ```\n *\n * Both support `instanceof TaggedError` checks at runtime.\n *\n * @param tag - The unique tag string for this error type\n * @param options - Optional configuration with message generator (annotate param for type safety)\n * @returns A class constructor that can be extended\n */\n\n// Overload 1: No options - use <Props> generic syntax, default message is tag\nfunction TaggedError<Tag extends string>(\n tag: Tag\n): TaggedErrorClassFactory<Tag>;\n\n// Overload 2: With message option - Props inferred from callback parameter annotation\nfunction TaggedError<Tag extends string, Props extends Record<string, unknown>>(\n tag: Tag,\n options: TaggedErrorCreateOptions<Props>\n): TaggedErrorConstructor<Tag, Props>;\n\n// Implementation\nfunction TaggedError<Tag extends string, Props extends Record<string, unknown>>(\n tag: Tag,\n options?: TaggedErrorCreateOptions<Props>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): any {\n return class extends InternalTaggedErrorBase {\n override readonly _tag: Tag = tag;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n constructor(props?: any, errorOptions?: TaggedErrorOptions) {\n // Generate message: call callback if provided (even for prop-less errors), else use tag\n const message = options?.message ? options.message(props ?? {}) : tag;\n\n super(message);\n this.name = tag;\n\n // Maintains proper prototype chain for instanceof checks\n Object.setPrototypeOf(this, new.target.prototype);\n\n // Assign props to instance, stripping reserved keys:\n // - _tag: discriminant for pattern matching (cannot be forged)\n // - name, message, stack: Error internals (preserve for logging/debugging)\n // Note: 'cause' is allowed as a user prop (common for domain errors)\n if (props && typeof props === \"object\") {\n const {\n _tag: _,\n name: _n,\n message: _m,\n stack: _s,\n ...safeProps\n } = props;\n\n const hasUserCause = Object.prototype.hasOwnProperty.call(\n safeProps,\n \"cause\"\n );\n const userCause = hasUserCause\n ? (safeProps as { cause?: unknown }).cause\n : undefined;\n if (hasUserCause) {\n delete (safeProps as { cause?: unknown }).cause;\n }\n\n const hasOptionsCause = errorOptions?.cause !== undefined;\n if (hasUserCause && hasOptionsCause) {\n throw new TypeError(\n \"TaggedError: cannot provide 'cause' in props when also setting ErrorOptions.cause\"\n );\n }\n\n Object.assign(this, safeProps);\n\n if (hasUserCause) {\n (this as { cause?: unknown }).cause = userCause;\n }\n if (hasOptionsCause) {\n (this as { cause?: unknown }).cause = errorOptions?.cause;\n }\n } else if (errorOptions?.cause !== undefined) {\n (this as { cause?: unknown }).cause = errorOptions.cause;\n }\n }\n };\n}\n\n// Add Symbol.hasInstance so `instanceof TaggedError` works\nObject.defineProperty(TaggedError, Symbol.hasInstance, {\n value: (instance: unknown): boolean => instance instanceof InternalTaggedErrorBase,\n});\n\n/**\n * Namespace for static methods on TaggedError.\n */\n// eslint-disable-next-line @typescript-eslint/no-namespace\nnamespace TaggedError {\n /**\n * Type guard to check if a value is an Error instance.\n */\n export function isError(value: unknown): value is Error {\n return value instanceof Error;\n }\n\n /**\n * Type guard to check if a value is a TaggedError instance.\n * Uses the same check as `instanceof TaggedError` - only genuine\n * TaggedError instances (created via the factory) pass this guard.\n */\n export function isTaggedError(value: unknown): value is TaggedErrorBase {\n return value instanceof InternalTaggedErrorBase;\n }\n\n /**\n * Exhaustively matches on a tagged error, requiring handlers for all variants.\n *\n * TypeScript will error if any variant in the error union is not handled.\n *\n * @remarks When to use: You want compile-time enforcement that every tagged variant is handled.\n *\n * @param error - The tagged error to match\n * @param handlers - Object mapping _tag values to handler functions\n * @returns The return value of the matched handler\n *\n * @example\n * ```typescript\n * type AppError = NotFoundError | ValidationError;\n *\n * const message = TaggedError.match(error, {\n * NotFoundError: (e) => `Not found: ${e.id}`,\n * ValidationError: (e) => `Invalid: ${e.field}`,\n * });\n * ```\n */\n export function match<\n E extends TaggedErrorBase,\n H extends { [K in E[\"_tag\"]]: (e: Extract<E, { _tag: K }>) => unknown },\n >(error: E, handlers: H): HandlersReturnType<H> {\n const tag = error._tag as E[\"_tag\"];\n const handler = handlers[tag];\n return handler(\n error as Extract<E, { _tag: typeof tag }>\n ) as HandlersReturnType<H>;\n }\n\n /**\n * Partially matches on a tagged error with a fallback for unhandled variants.\n *\n * The fallback receives variants that are NOT definitely handled. A tag is\n * considered \"definitely handled\" only if its handler is a function (not\n * `undefined`). This ensures type safety even with dynamic/conditional handlers:\n *\n * ```typescript\n * const maybeHandle = featureFlag ? (e) => e.id : undefined;\n * TaggedError.matchPartial(\n * error,\n * { NotFoundError: maybeHandle }, // maybeHandle might be undefined\n * (e) => e._tag // e correctly includes NotFoundError\n * );\n * ```\n *\n * @param error - The tagged error to match\n * @param handlers - Partial object mapping _tag values to handler functions\n * @param otherwise - Fallback handler for unmatched variants\n * @returns The return value of the matched handler or fallback\n *\n * @example\n * ```typescript\n * const message = TaggedError.matchPartial(\n * error,\n * { NotFoundError: (e) => `Not found: ${e.id}` },\n * (e) => `Other error: ${e.message}`\n * );\n * ```\n */\n export function matchPartial<\n E extends TaggedErrorBase,\n H extends Partial<{\n [K in E[\"_tag\"]]: (e: Extract<E, { _tag: K }>) => unknown;\n }>,\n T,\n >(\n error: E,\n handlers: H,\n otherwise: (e: Exclude<E, { _tag: DefinitelyHandledKeys<H> }>) => T\n ): HandlersReturnType<H> | T {\n const tag = error._tag as E[\"_tag\"];\n const handler = handlers[tag];\n if (handler) {\n return handler(\n error as Extract<E, { _tag: typeof tag }>\n ) as HandlersReturnType<H>;\n }\n return otherwise(error as Exclude<E, { _tag: DefinitelyHandledKeys<H> }>);\n }\n}\n\nexport { TaggedError };\n\n/**\n * Helper type to extract the _tag literal type from a TaggedError.\n *\n * @example\n * ```typescript\n * class MyError extends TaggedError(\"MyError\")<{ id: string }> {}\n * type Tag = TagOf<MyError>; // \"MyError\"\n * ```\n */\nexport type TagOf<E extends TaggedErrorBase> = E[\"_tag\"];\n\n/**\n * Helper type to extract a specific variant from a TaggedError union by tag.\n *\n * @example\n * ```typescript\n * type AppError = NotFoundError | ValidationError;\n * type NotFound = ErrorByTag<AppError, \"NotFoundError\">; // NotFoundError\n * ```\n */\nexport type ErrorByTag<\n E extends TaggedErrorBase,\n Tag extends E[\"_tag\"],\n> = Extract<E, { _tag: Tag }>;\n\n/**\n * Reserved keys that are stripped from user props at runtime.\n * These keys cannot be used as user-defined properties:\n * - _tag: discriminant for pattern matching\n * - name, message, stack: Error internals (preserved for logging/debugging)\n *\n * Note: 'cause' is NOT reserved - it can be used as a user prop.\n */\ntype ReservedErrorKeys = \"_tag\" | \"name\" | \"message\" | \"stack\";\n\n/**\n * Helper type to extract props from a TaggedError.\n * Excludes reserved keys that are stripped at runtime.\n *\n * @example\n * ```typescript\n * class MyError extends TaggedError(\"MyError\")<{ id: string }> {}\n * type Props = PropsOf<MyError>; // { id: string }\n *\n * // 'cause' is allowed as a user prop\n * class DomainError extends TaggedError(\"DomainError\")<{ cause: { field: string } }> {}\n * type DomainProps = PropsOf<DomainError>; // { cause: { field: string } }\n * ```\n */\nexport type PropsOf<E extends TaggedErrorBase> = Omit<E, ReservedErrorKeys>;\n","/**\n * awaitly/errors\n *\n * Pre-built error types for common failure scenarios.\n * Uses TaggedError for type-safe exhaustive matching.\n *\n * @example\n * ```typescript\n * import { TimeoutError, RetryExhaustedError, RateLimitError, CircuitOpenError } from 'awaitly/errors';\n *\n * // Create errors\n * const timeout = new TimeoutError({ operation: 'fetchUser', ms: 5000 });\n * const retryFailed = new RetryExhaustedError({ operation: 'sendEmail', attempts: 3 });\n *\n * // Pattern match\n * TaggedError.match(error, {\n * TimeoutError: (e) => `${e.operation} timed out after ${e.ms}ms`,\n * RetryExhaustedError: (e) => `${e.operation} failed after ${e.attempts} attempts`,\n * RateLimitError: (e) => `Rate limit exceeded, retry after ${e.retryAfterMs}ms`,\n * CircuitOpenError: (e) => `Circuit ${e.circuitName} is open`,\n * });\n * ```\n */\n\nimport { TaggedError } from \"./tagged-error\";\n\n// =============================================================================\n// Error Factory\n// =============================================================================\n\n/**\n * Factory function to create tagged error classes with default values.\n *\n * This is a convenience wrapper around TaggedError that allows specifying\n * default property values for error types.\n *\n * @example\n * ```typescript\n * // Define custom error with defaults\n * const NetworkError = makeError('NetworkError', {\n * defaults: { retryable: true },\n * message: (p) => `Network error: ${p.reason}`,\n * });\n *\n * class MyNetworkError extends NetworkError<{ reason: string; code?: number }> {}\n *\n * const error = new MyNetworkError({ reason: 'Connection refused' });\n * // error.retryable === true (from defaults)\n * ```\n */\nexport function makeError<Tag extends string>(\n tag: Tag,\n options?: {\n message?: (props: Record<string, unknown>) => string;\n defaults?: Record<string, unknown>;\n }\n) {\n const messageGenerator = options?.message ?? (() => tag);\n const defaults = options?.defaults ?? {};\n\n // Create base class using TaggedError\n const BaseClass = TaggedError(tag, {\n message: (props: Record<string, unknown>) =>\n messageGenerator({ ...defaults, ...props }),\n });\n\n // Return a factory that applies defaults\n return class extends BaseClass {\n constructor(props?: Record<string, unknown>) {\n super({ ...defaults, ...props } as Record<string, unknown>);\n // Apply defaults to instance\n Object.assign(this, { ...defaults, ...props });\n }\n };\n}\n\n// =============================================================================\n// Pre-built Error Types\n// =============================================================================\n\n/**\n * Error thrown when an operation times out.\n *\n * @example\n * ```typescript\n * const error = new TimeoutError({\n * operation: 'fetchUser',\n * ms: 5000,\n * });\n * console.log(error.message); // \"TimeoutError: fetchUser timed out after 5000ms\"\n * ```\n */\nexport class TimeoutError extends TaggedError(\"TimeoutError\", {\n message: (p: {\n /** Name of the operation that timed out */\n operation?: string;\n /** Timeout duration in milliseconds */\n ms: number;\n }) =>\n p.operation\n ? `TimeoutError: ${p.operation} timed out after ${p.ms}ms`\n : `TimeoutError: Operation timed out after ${p.ms}ms`,\n}) {}\n\n/**\n * Error thrown when all retry attempts are exhausted.\n *\n * @example\n * ```typescript\n * const error = new RetryExhaustedError({\n * operation: 'sendEmail',\n * attempts: 3,\n * lastError: originalError,\n * });\n * console.log(error.message); // \"RetryExhaustedError: sendEmail failed after 3 attempts\"\n * ```\n */\nexport class RetryExhaustedError extends TaggedError(\"RetryExhaustedError\", {\n message: (p: {\n /** Name of the operation that failed */\n operation?: string;\n /** Total number of retry attempts made */\n attempts: number;\n /** The last error encountered before giving up */\n lastError?: unknown;\n }) =>\n p.operation\n ? `RetryExhaustedError: ${p.operation} failed after ${p.attempts} attempts`\n : `RetryExhaustedError: Operation failed after ${p.attempts} attempts`,\n}) {}\n\n/**\n * Error thrown when a rate limit is exceeded.\n *\n * @example\n * ```typescript\n * const error = new RateLimitError({\n * limiterName: 'api-calls',\n * retryAfterMs: 1000,\n * });\n * console.log(error.message); // \"RateLimitError: Rate limit exceeded for api-calls\"\n * ```\n */\nexport class RateLimitError extends TaggedError(\"RateLimitError\", {\n message: (p: {\n /** Name of the rate limiter that was exceeded */\n limiterName?: string;\n /** Time in milliseconds until the rate limit resets */\n retryAfterMs?: number;\n }) =>\n p.limiterName\n ? `RateLimitError: Rate limit exceeded for ${p.limiterName}${p.retryAfterMs ? `, retry after ${p.retryAfterMs}ms` : \"\"}`\n : `RateLimitError: Rate limit exceeded${p.retryAfterMs ? `, retry after ${p.retryAfterMs}ms` : \"\"}`,\n}) {}\n\n/**\n * Error thrown when a circuit breaker is open.\n *\n * @example\n * ```typescript\n * const error = new CircuitBreakerOpenError({\n * circuitName: 'payment-api',\n * state: 'OPEN',\n * retryAfterMs: 30000,\n * });\n * console.log(error.message); // \"CircuitBreakerOpenError: Circuit payment-api is OPEN\"\n * ```\n */\nexport class CircuitBreakerOpenError extends TaggedError(\n \"CircuitBreakerOpenError\",\n {\n message: (p: {\n /** Name of the circuit breaker */\n circuitName: string;\n /** Current state of the circuit */\n state?: \"OPEN\" | \"HALF_OPEN\";\n /** Time in milliseconds until the circuit may close */\n retryAfterMs?: number;\n }) =>\n `CircuitBreakerOpenError: Circuit ${p.circuitName} is ${p.state ?? \"OPEN\"}${p.retryAfterMs ? `, retry after ${Math.ceil(p.retryAfterMs / 1000)}s` : \"\"}`,\n }\n) {}\n\n/**\n * Error thrown when validation fails.\n *\n * @example\n * ```typescript\n * const error = new ValidationError({\n * field: 'email',\n * reason: 'Invalid email format',\n * });\n * console.log(error.message); // \"ValidationError: Invalid email - Invalid email format\"\n * ```\n */\nexport class ValidationError extends TaggedError(\"ValidationError\", {\n message: (p: {\n /** Field that failed validation */\n field: string;\n /** Reason for validation failure */\n reason: string;\n /** Raw value that failed validation */\n value?: unknown;\n }) => `ValidationError: Invalid ${p.field} - ${p.reason}`,\n}) {}\n\n/**\n * Error thrown when a resource is not found.\n *\n * @example\n * ```typescript\n * const error = new NotFoundError({\n * resource: 'User',\n * id: '123',\n * });\n * console.log(error.message); // \"NotFoundError: User with id 123 not found\"\n * ```\n */\nexport class NotFoundError extends TaggedError(\"NotFoundError\", {\n message: (p: {\n /** Type of resource that was not found */\n resource: string;\n /** Identifier of the missing resource */\n id?: string;\n }) =>\n p.id\n ? `NotFoundError: ${p.resource} with id ${p.id} not found`\n : `NotFoundError: ${p.resource} not found`,\n}) {}\n\n/**\n * Error thrown when access is denied.\n *\n * @example\n * ```typescript\n * const error = new UnauthorizedError({\n * action: 'delete',\n * resource: 'User',\n * });\n * console.log(error.message); // \"UnauthorizedError: Not authorized to delete User\"\n * ```\n */\nexport class UnauthorizedError extends TaggedError(\"UnauthorizedError\", {\n message: (p: {\n /** Action that was attempted */\n action?: string;\n /** Resource that was being accessed */\n resource?: string;\n /** Reason for denial */\n reason?: string;\n }) =>\n p.reason\n ? `UnauthorizedError: ${p.reason}`\n : p.action && p.resource\n ? `UnauthorizedError: Not authorized to ${p.action} ${p.resource}`\n : \"UnauthorizedError: Access denied\",\n}) {}\n\n/**\n * Error thrown for network-related failures.\n *\n * @example\n * ```typescript\n * const error = new NetworkError({\n * url: 'https://api.example.com/users',\n * reason: 'Connection refused',\n * retryable: true,\n * });\n * ```\n */\nexport class NetworkError extends TaggedError(\"NetworkError\", {\n message: (p: {\n /** URL that was being accessed */\n url?: string;\n /** Reason for the network failure */\n reason: string;\n /** Whether this error is retryable */\n retryable?: boolean;\n /** HTTP status code if applicable */\n statusCode?: number;\n }) =>\n p.url\n ? `NetworkError: ${p.reason} (${p.url})`\n : `NetworkError: ${p.reason}`,\n}) {}\n\n/**\n * Error thrown when a saga compensation fails.\n *\n * @example\n * ```typescript\n * const error = new CompensationError({\n * step: 'chargeCard',\n * originalError: paymentError,\n * compensationError: refundError,\n * });\n * ```\n */\nexport class CompensationError extends TaggedError(\"CompensationError\", {\n message: (p: {\n /** Step that triggered compensation */\n step: string;\n /** The original error that caused compensation */\n originalError?: unknown;\n /** Error that occurred during compensation */\n compensationError?: unknown;\n }) => `CompensationError: Failed to compensate step ${p.step}`,\n}) {}\n\n// =============================================================================\n// Unexpected Error\n// =============================================================================\n\n/**\n * Default error type for uncaught exceptions and cancellation in workflows.\n * This is the default `U` type when `catchUnexpected` is not provided.\n *\n * @example\n * ```typescript\n * // Automatically used as the default — no need to pass catchUnexpected:\n * const workflow = createWorkflow(\"checkout\", { chargeCard, sendEmail });\n *\n * // Equivalent to:\n * const workflow = createWorkflow(\"checkout\", { chargeCard, sendEmail }, {\n * catchUnexpected: (cause) => new UnexpectedError({ cause }),\n * });\n * ```\n */\nexport class UnexpectedError extends TaggedError(\"UnexpectedError\", {\n message: (p: {\n /** The original thrown value or cancellation error */\n cause?: unknown;\n }) => `UnexpectedError: ${p.cause instanceof Error ? p.cause.message : String(p.cause ?? \"unknown\")}`,\n}) {}\n\n\n// =============================================================================\n// Union Type for Common Errors\n// =============================================================================\n\n/**\n * Union of all pre-built error types.\n * Useful for exhaustive pattern matching.\n *\n * @example\n * ```typescript\n * function handleError(error: AwaitlyError): string {\n * return TaggedError.match(error, {\n * TimeoutError: (e) => `Timeout: ${e.ms}ms`,\n * RetryExhaustedError: (e) => `Retries: ${e.attempts}`,\n * RateLimitError: (e) => `Rate limited`,\n * CircuitBreakerOpenError: (e) => `Circuit open: ${e.circuitName}`,\n * ValidationError: (e) => `Invalid: ${e.field}`,\n * NotFoundError: (e) => `Not found: ${e.resource}`,\n * UnauthorizedError: (e) => `Unauthorized`,\n * NetworkError: (e) => `Network: ${e.reason}`,\n * CompensationError: (e) => `Compensation failed: ${e.step}`,\n * });\n * }\n * ```\n */\nexport type AwaitlyError =\n | TimeoutError\n | RetryExhaustedError\n | RateLimitError\n | CircuitBreakerOpenError\n | ValidationError\n | NotFoundError\n | UnauthorizedError\n | NetworkError\n | CompensationError;\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Check if an error is a TimeoutError.\n */\nexport function isTimeoutError(error: unknown): error is TimeoutError {\n return TaggedError.isTaggedError(error) && error._tag === \"TimeoutError\";\n}\n\n/**\n * Check if an error is a RetryExhaustedError.\n */\nexport function isRetryExhaustedError(\n error: unknown\n): error is RetryExhaustedError {\n return (\n TaggedError.isTaggedError(error) && error._tag === \"RetryExhaustedError\"\n );\n}\n\n/**\n * Check if an error is a RateLimitError.\n */\nexport function isRateLimitError(error: unknown): error is RateLimitError {\n return TaggedError.isTaggedError(error) && error._tag === \"RateLimitError\";\n}\n\n/**\n * Check if an error is a CircuitBreakerOpenError.\n */\nexport function isCircuitBreakerOpenError(\n error: unknown\n): error is CircuitBreakerOpenError {\n return (\n TaggedError.isTaggedError(error) && error._tag === \"CircuitBreakerOpenError\"\n );\n}\n\n/**\n * Check if an error is a ValidationError.\n */\nexport function isValidationError(error: unknown): error is ValidationError {\n return TaggedError.isTaggedError(error) && error._tag === \"ValidationError\";\n}\n\n/**\n * Check if an error is a NotFoundError.\n */\nexport function isNotFoundError(error: unknown): error is NotFoundError {\n return TaggedError.isTaggedError(error) && error._tag === \"NotFoundError\";\n}\n\n/**\n * Check if an error is an UnauthorizedError.\n */\nexport function isUnauthorizedError(\n error: unknown\n): error is UnauthorizedError {\n return TaggedError.isTaggedError(error) && error._tag === \"UnauthorizedError\";\n}\n\n/**\n * Check if an error is a NetworkError.\n */\nexport function isNetworkError(error: unknown): error is NetworkError {\n return TaggedError.isTaggedError(error) && error._tag === \"NetworkError\";\n}\n\n/**\n * Check if an error is a CompensationError.\n */\nexport function isCompensationError(\n error: unknown\n): error is CompensationError {\n return TaggedError.isTaggedError(error) && error._tag === \"CompensationError\";\n}\n\n/**\n * Check if an error is any AwaitlyError.\n */\nexport function isAwaitlyError(error: unknown): error is AwaitlyError {\n if (!TaggedError.isTaggedError(error)) return false;\n const tag = error._tag;\n return [\n \"TimeoutError\",\n \"RetryExhaustedError\",\n \"RateLimitError\",\n \"CircuitBreakerOpenError\",\n \"ValidationError\",\n \"NotFoundError\",\n \"UnauthorizedError\",\n \"NetworkError\",\n \"CompensationError\",\n ].includes(tag);\n}\n","/**\n * awaitly/core\n *\n * Core Result primitives and run() function.\n * Use this module for minimal bundle size when you don't need the full workflow capabilities\n * (like retries, timeout, or state persistence) provided by `createWorkflow`.\n *\n * This module provides:\n * 1. `Result` types for error handling without try/catch\n * 2. `run()` function for executing steps with standardized error management\n * 3. Utilities for transforming and combining Results\n */\n\n// Inline duration type and parser to avoid importing the full duration module\n// This keeps the core bundle minimal (~1KB saved)\n\n/** Duration object with tagged type for type safety */\ntype DurationObject = { readonly _tag: \"Duration\"; readonly millis: number };\n\n/** Duration input: either a string (\"5s\", \"100ms\") or a Duration object */\ntype DurationInput = string | DurationObject;\n\n/** Parse a duration string like \"100ms\", \"5s\", \"2m\", \"1h\", \"1d\" */\nfunction parseDurationString(input: string): DurationObject | undefined {\n const match = input.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h|d)$/i);\n if (!match) return undefined;\n const value = parseFloat(match[1]);\n const unit = match[2].toLowerCase();\n const multipliers: Record<string, number> = { ms: 1, s: 1000, m: 60000, h: 3600000, d: 86400000 };\n return { _tag: \"Duration\", millis: value * (multipliers[unit] ?? 1) };\n}\n\n// =============================================================================\n// Core Result Types\n// =============================================================================\n\n/**\n * Represents a successful result.\n * Use `ok(value)` to create instances.\n *\n * @template T - The type of the success value\n *\n * @example\n * ```typescript\n * const success = Awaitly.ok(42);\n * // Type shown: Ok<number>\n * ```\n */\nexport type Ok<T> = {\n ok: true;\n value: T;\n};\n\n/**\n * Represents a failed result.\n * Use `err(error)` to create instances.\n *\n * @template E - The type of the error value\n * @template C - The type of the cause (defaults to unknown)\n * @template T - Phantom type for the success value (preserved after narrowing)\n *\n * @example\n * ```typescript\n * const failure = Awaitly.err({ type: \"NOT_FOUND\", message: \"User not found\" });\n * // Type shown: Err<{ type: string; message: string }>\n * ```\n */\nexport type Err<E, C = unknown> = {\n ok: false;\n error: E;\n cause?: C;\n};\n\n/**\n * Represents a successful computation or a failed one.\n * Use this type to represent the outcome of an operation that might fail,\n * instead of throwing exceptions.\n *\n * @template T - The type of the success value\n * @template E - The type of the error value (defaults to unknown)\n * @template C - The type of the cause (defaults to unknown)\n */\nexport type Result<T, E = unknown, C = unknown> = Ok<T> | Err<E, C>;\n\n/**\n * A Promise that resolves to a Result.\n * Use this for asynchronous operations that might fail.\n */\nexport type AsyncResult<T, E = unknown, C = unknown> = Promise<Result<T, E, C>>;\n\n/** Discriminant for PromiseRejectedError type - use in switch statements */\nexport const PROMISE_REJECTED = \"PROMISE_REJECTED\" as const;\n\n// =============================================================================\n// Named Error Constants (for static analysis)\n// =============================================================================\n\n/**\n * Named error constant for unexpected/unhandled errors.\n * Used by the analyzer when a step doesn't declare errors.\n */\nexport const AWAITLY_UNEXPECTED = \"AWAITLY_UNEXPECTED\" as const;\n\n/**\n * Named error constant for cancelled operations.\n */\nexport const AWAITLY_CANCELLED = \"AWAITLY_CANCELLED\" as const;\n\n/**\n * Named error constant for timed-out operations.\n */\nexport const AWAITLY_TIMEOUT = \"AWAITLY_TIMEOUT\" as const;\n\n// =============================================================================\n// Static Analysis Helpers\n// =============================================================================\n\n/**\n * Helper to create a tuple of string literal tags with preserved literal types.\n * Use this when you need to store error tags in a variable while keeping\n * TypeScript's literal type inference (avoiding widening to string[]).\n *\n * @param t - The string literal tags\n * @returns The same array with preserved literal types\n *\n * @example\n * ```typescript\n * // Without tags() - type widens to string[]\n * const errs = ['CART_NOT_FOUND', 'CART_EMPTY']; // string[]\n *\n * // With tags() - literal types preserved\n * const errs = tags('CART_NOT_FOUND', 'CART_EMPTY'); // ['CART_NOT_FOUND', 'CART_EMPTY']\n *\n * await step('getCart', () => getCart(id), {\n * errors: errs, // Analyzer can extract literal types\n * out: 'cart',\n * });\n * ```\n */\nexport const tags = <const T extends readonly string[]>(...t: T): T => t;\n\nimport { UnexpectedError } from \"../errors\";\nexport { UnexpectedError };\n\n/**\n * Default mapper for unexpected causes (uncaught exceptions, cancellation, etc.).\n * Returns an UnexpectedError TaggedError instance.\n * Used when run() is called without catchUnexpected.\n *\n * @param cause - The thrown value\n * @returns An UnexpectedError instance\n */\nexport function defaultCatchUnexpected(cause: unknown): UnexpectedError {\n return new UnexpectedError({ cause });\n}\n\nexport type PromiseRejectedError = { type: typeof PROMISE_REJECTED; cause: unknown };\n/** Cause type for promise rejections in async batch helpers */\nexport type PromiseRejectionCause = { type: \"PROMISE_REJECTION\"; reason: unknown };\nexport type EmptyInputError = { type: \"EMPTY_INPUT\"; message: string };\nexport type MaybeAsyncResult<T, E, C = unknown> = Result<T, E, C> | Promise<Result<T, E, C>>;\n\n// =============================================================================\n// Result Constructors\n// =============================================================================\n\n/**\n * Creates a successful Result.\n * Use this when an operation completes successfully.\n *\n * @remarks When to use: Wrap a successful value in a Result for consistent return types.\n *\n * @param value - The success value to wrap\n * @returns An Ok object with `{ ok: true, value }`\n *\n * @example\n * ```typescript\n * const success = Awaitly.ok(42);\n * // Type: Ok<number>\n *\n * function divide(a: number, b: number): Result<number, string> {\n * if (b === 0) return Awaitly.err(\"Division by zero\");\n * return Awaitly.ok(a / b);\n * }\n * ```\n */\nexport function ok<T>(value: T): Ok<T> {\n return { ok: true as const, value };\n}\n\n/**\n * Creates a failed Result.\n * Use this when an operation fails.\n *\n * @remarks When to use: Return a typed failure without throwing so callers can handle it explicitly.\n *\n * @param error - The error value describing what went wrong (e.g., error code, object)\n * @returns An Err object with `{ ok: false, error }`\n *\n * @example\n * ```typescript\n * // Simple error\n * const r1 = Awaitly.err(\"NOT_FOUND\");\n * // Type: Err<\"NOT_FOUND\">\n *\n * // Error with context (include in error object)\n * const r2 = Awaitly.err({ type: \"PROCESSING_FAILED\", cause: originalError });\n * // Type: Err<{ type: string; cause: Error }>\n * ```\n */\nexport function err<E, C = unknown>(error: E, options?: { cause?: C }): Err<E, C> {\n const cause = options?.cause;\n return { ok: false as const, error, ...(cause !== undefined ? { cause } : {}) } as Err<E, C>;\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Checks if a Result is successful.\n * Use this to narrow the type of a Result to the success case.\n *\n * @remarks When to use: Prefer functional-style checks or array filtering over `result.ok`.\n *\n * @param r - The Result to check\n * @returns `true` if successful, allowing access to `r.value`\n *\n * @example\n * ```typescript\n * const r = someOperation();\n * if (isOk(r)) {\n * // Use r.value (Type is T)\n * processValue(r.value);\n * } else {\n * // Handle r.error (Type is E)\n * handleError(r.error);\n * }\n * ```\n */\nexport const isOk = <T, E, C>(r: Result<T, E, C>): r is Ok<T> => r.ok;\n\n/**\n * Checks if a Result is a failure.\n * Use this to narrow the type of a Result to the error case.\n *\n * @remarks When to use: Prefer functional-style checks or array filtering over `result.ok`.\n *\n * @param r - The Result to check\n * @returns `true` if failed, allowing access to `r.error` and `r.cause`\n *\n * @example\n * ```typescript\n * if (isErr(r)) {\n * // Handle error case early\n * return;\n * }\n * // Proceed with success case\n * ```\n */\nexport const isErr = <T, E, C>(r: Result<T, E, C>): r is Err<E, C> => !r.ok;\n\n/**\n * Checks if an error is an UnexpectedError.\n * Used internally by the framework but exported for advanced custom handling.\n * Indicates an error that wasn't typed/expected in the `run` signature.\n *\n * @remarks When to use: Distinguish unexpected failures from your typed error union.\n */\nexport const isUnexpectedError = (e: unknown): e is UnexpectedError =>\n e instanceof UnexpectedError ||\n (typeof e === \"object\" &&\n e !== null &&\n \"_tag\" in e &&\n (e as { _tag: string })._tag === \"UnexpectedError\");\n\n/**\n * Checks if an error is a PromiseRejectedError.\n * Occurs when a Promise rejects in batch operations (allAsync, anyAsync, zipAsync).\n *\n * @example\n * ```typescript\n * onError: (error): FetchError => {\n * if (isPromiseRejectedError(error)) return 'FETCH_FAILED';\n * return error; // TypeScript narrows to FetchError\n * }\n * ```\n */\nexport const isPromiseRejectedError = (e: unknown): e is PromiseRejectedError =>\n typeof e === \"object\" &&\n e !== null &&\n (e as PromiseRejectedError).type === PROMISE_REJECTED;\n\n// =============================================================================\n// Error Matching\n// =============================================================================\n\n/**\n * Type for exhaustive error handlers mapping string literal errors and UnexpectedError.\n * Each key in E gets a handler, plus UnexpectedError is required.\n */\nexport type MatchErrorHandlers<E extends string, R> = {\n [K in Exclude<E, \"UnexpectedError\">]: (error: K) => R;\n} & {\n UnexpectedError: (error: UnexpectedError) => R;\n};\n\n/**\n * Exhaustive pattern matching for error types.\n * Handles both string literal errors and UnexpectedError, ensuring all cases are covered.\n *\n * @param error - The error to match (string literal or UnexpectedError)\n * @param handlers - Object with a handler for each error case plus UnexpectedError\n * @returns The result of the matched handler\n *\n * @example\n * ```typescript\n * type FetchError = \"NOT_FOUND\" | \"FETCH_ERROR\";\n * const result: Result<User, FetchError | UnexpectedError> = await fetchUser();\n *\n * if (!result.ok) {\n * return matchError(result.error, {\n * NOT_FOUND: () => 404,\n * FETCH_ERROR: () => 500,\n * UnexpectedError: (e) => { throw e.cause; }\n * });\n * }\n * ```\n */\nexport function matchError<E extends string, R>(\n error: E | UnexpectedError,\n handlers: MatchErrorHandlers<E, R>\n): R {\n // Handle UnexpectedError instances\n if (isUnexpectedError(error)) {\n return handlers.UnexpectedError(error as UnexpectedError);\n }\n // Handle string literal errors\n type StringErrors = Exclude<E, \"UnexpectedError\">;\n return handlers[error as StringErrors](error as StringErrors);\n}\n\n// =============================================================================\n// Type Utilities\n// =============================================================================\n\ntype AnyFunction = (...args: never[]) => unknown;\n\n/**\n * Helper to extract the error type from Result or AsyncResult return values.\n * Works even when a function is declared to return a union of both forms.\n */\ntype ErrorOfReturn<R> = Extract<Awaited<R>, { ok: false }> extends { error: infer E }\n ? E\n : never;\n\n/**\n * Extract error type from a single function's return type\n */\nexport type ErrorOf<T extends AnyFunction> = ErrorOfReturn<ReturnType<T>>;\n\n/**\n * Extract union of error types from multiple functions\n */\nexport type Errors<T extends AnyFunction[]> = {\n [K in keyof T]: ErrorOf<T[K]>;\n}[number];\n\n/**\n * Extract value type from Result\n */\nexport type ExtractValue<T> = T extends { ok: true; value: infer U }\n ? U\n : never;\n\n/**\n * Extract error type from Result\n */\nexport type ExtractError<T> = T extends { ok: false; error: infer E }\n ? E\n : never;\n\n/**\n * Extract cause type from Result\n */\nexport type ExtractCause<T> = T extends { ok: false; cause?: infer C }\n ? C\n : never;\n\n/**\n * Helper to extract the cause type from Result or AsyncResult return values.\n * Works even when a function is declared to return a union of both forms.\n */\ntype CauseOfReturn<R> = Extract<Awaited<R>, { ok: false }> extends { cause?: infer C }\n ? C\n : never;\n\n/**\n * Extract cause type from a function's return type\n */\nexport type CauseOf<T extends AnyFunction> = CauseOfReturn<ReturnType<T>>;\n\n// =============================================================================\n// Step Options\n// =============================================================================\n\n/**\n * Options for configuring a step within a workflow.\n * Use these to enable tracing, caching, state persistence, and static analysis.\n */\nexport type StepOptions<\n Errs extends readonly string[] = readonly string[],\n Out extends string | undefined = undefined,\n> = {\n /**\n * Stable identity key for the step.\n * REQUIRED for:\n * 1. Caching: Used as the cache key.\n * 2. Resuming: Used to identify which steps have already completed.\n *\n * Must be unique within the workflow.\n */\n key?: string;\n\n /**\n * Short description for labels/tooltips.\n * Used by static analysis visualization tools.\n */\n description?: string;\n\n /**\n * Full markdown documentation for the step.\n * Used by static analysis visualization tools.\n */\n markdown?: string;\n\n /**\n * Retry configuration for transient failures.\n * When specified, the step will retry on errors according to this config.\n */\n retry?: RetryOptions;\n\n /**\n * Timeout configuration for the operation.\n * When specified, each attempt will be aborted after the timeout duration.\n */\n timeout?: TimeoutOptions;\n\n /**\n * Time-to-live for this step's cache entry in milliseconds.\n * Overrides any global cache TTL. Requires `key` for caching.\n */\n ttl?: number;\n\n // ==========================================================================\n // Static Analysis Options\n // ==========================================================================\n\n /**\n * Declared tagged errors this step may return.\n * Used by the static analyzer to build error flow graphs.\n *\n * Use `tags()` helper when storing in a variable:\n * @example\n * ```typescript\n * const cartErrors = tags('CART_NOT_FOUND', 'CART_EMPTY');\n * await step('getCart', () => getCart(id), { errors: cartErrors });\n *\n * // Or inline (no helper needed)\n * await step('getCart', () => getCart(id), {\n * errors: ['CART_NOT_FOUND', 'CART_EMPTY'],\n * });\n * ```\n */\n errors?: Errs;\n\n /**\n * Write the step's return value to this context key.\n * Replaces manual `ctx.set()` calls for the happy path.\n *\n * @example\n * ```typescript\n * await step('getCart', () => getCart(id), { out: 'cart' });\n * // Now ctx.cart contains the result\n * ```\n */\n out?: Out;\n\n /**\n * Override auto-detected reads from context.\n * Use when the analyzer can't trace complex data dependencies.\n *\n * @example\n * ```typescript\n * await step('charge', () => chargeCard(getCartTotal()), {\n * reads: ['cart'], // Explicitly declare dependency\n * });\n * ```\n */\n reads?: readonly string[];\n\n /**\n * Hint for dependency source tracking.\n * Use when the callback is complex and the analyzer can't detect\n * which dependency function is being called.\n *\n * @example\n * ```typescript\n * await step('getCart', () => {\n * const id = transform(ctx.input.cartId);\n * return deps.getCart(id);\n * }, {\n * dep: 'getCart', // Hint for analyzer\n * });\n * ```\n */\n dep?: string;\n\n // ==========================================================================\n // Agent Metadata — Architecture & Intent\n // ==========================================================================\n\n /**\n * Why this step exists in the business flow.\n * Unlike `description` (which says *what* the step does), `intent` explains\n * the business reason it exists in the workflow.\n *\n * @example\n * ```typescript\n * await step('validateCart', () => validate(cart), {\n * description: 'Validates cart contents and pricing',\n * intent: 'Prevent charging customers for out-of-stock items',\n * });\n * ```\n */\n intent?: string;\n\n /**\n * Business domain this step belongs to.\n * Used by the static analyzer to group steps by bounded context.\n *\n * @example\n * ```typescript\n * await step('chargeCard', () => charge(card, amount), {\n * domain: 'payments',\n * });\n * ```\n */\n domain?: string;\n\n /**\n * Team, service, or bounded-context that owns this step.\n *\n * @example\n * ```typescript\n * await step('shipOrder', () => ship(order), {\n * owner: 'fulfillment-team',\n * });\n * ```\n */\n owner?: string;\n\n /**\n * Classification tags for this step.\n *\n * Recommended vocabulary:\n * `'side-effect'`, `'external-api'`, `'idempotent'`, `'read-only'`,\n * `'cacheable'`, `'pii'`, `'pci'`, `'compensatable'`\n *\n * @example\n * ```typescript\n * await step('chargeCard', () => charge(card, amount), {\n * tags: ['side-effect', 'external-api', 'pci'],\n * });\n * ```\n */\n tags?: readonly string[];\n\n // ==========================================================================\n // Agent Metadata — Effects & Dependencies\n // ==========================================================================\n\n /**\n * Human-oriented descriptions of state mutations this step performs.\n * These are free-text labels for documentation and visualization — they are\n * not machine-parsed at runtime.\n *\n * A future `stateEffects` field will provide structured effect declarations.\n *\n * @example\n * ```typescript\n * await step('placeOrder', () => place(cart), {\n * stateChanges: ['order.status → PLACED', 'inventory.reserved += qty'],\n * });\n * ```\n */\n stateChanges?: readonly string[];\n\n /**\n * Domain events this step produces.\n * Used by the static analyzer to build event flow graphs.\n *\n * @example\n * ```typescript\n * await step('placeOrder', () => place(cart), {\n * emits: ['OrderPlaced', 'InventoryReserved'],\n * });\n * ```\n */\n emits?: readonly string[];\n\n /**\n * External systems or services this step calls.\n * Used by the static analyzer to map external dependencies.\n *\n * @example\n * ```typescript\n * await step('chargeCard', () => charge(card, amount), {\n * calls: ['stripe-api', 'fraud-detection-service'],\n * });\n * ```\n */\n calls?: readonly string[];\n\n // ==========================================================================\n // Agent Metadata — Error Classification\n // ==========================================================================\n\n /**\n * Structured metadata for each error this step may produce.\n * Keys should match entries in the `errors` array.\n *\n * Note: `retryable` classifies the error's nature (whether it CAN be retried),\n * separate from whether this step actually retries it (that's `retry.retryOn`).\n * Both dimensions are useful — \"this error IS retryable\" vs \"this step DOES retry it\".\n * Defaults to `undefined` (unknown), not `true`.\n *\n * @example\n * ```typescript\n * await step('chargeCard', () => charge(card, amount), {\n * errors: ['CARD_DECLINED', 'GATEWAY_TIMEOUT'],\n * errorMeta: {\n * CARD_DECLINED: {\n * retryable: false,\n * severity: 'business',\n * description: 'Card was declined by issuer',\n * },\n * GATEWAY_TIMEOUT: {\n * retryable: true,\n * severity: 'infrastructure',\n * description: 'Payment gateway did not respond in time',\n * },\n * },\n * });\n * ```\n */\n errorMeta?: Record<string, ErrorClassification>;\n};\n\n/** Shared error classification — used in StepOptions.errorMeta, diagnostics, and wide events. */\nexport interface ErrorClassification {\n retryable?: boolean;\n severity?: 'business' | 'infrastructure' | 'validation';\n description?: string;\n}\n\n/** Runtime-visible business context from StepOptions. Does NOT include errorMeta. */\nexport interface StepMetadata {\n intent?: string;\n domain?: string;\n owner?: string;\n tags?: readonly string[];\n stateChanges?: readonly string[];\n emits?: readonly string[];\n calls?: readonly string[];\n}\n\n/** Runtime error diagnostics. classification is the matched ErrorClassification for this error. */\nexport interface StepErrorDiagnostics {\n tag: string;\n classification?: ErrorClassification;\n attempt?: number; // 1-based\n cumulativeDurationMs?: number; // execution only, excludes backoff\n origin: 'result' | 'throw' | 'timeout';\n}\n\n/** Extract canonical error tag. Priority: _tag > tag > code > Error.name > \"unknown\".\n * Tags are case-sensitive, whitespace-trimmed, otherwise raw.\n * Note: Error.name is fallback-grade (often too coarse like \"Error\", \"TypeError\"). */\nexport function extractErrorTag(error: unknown): string {\n if (error == null) return 'unknown';\n\n if (typeof error === 'string') return error.trim() || 'unknown';\n\n if (typeof error === 'object') {\n // Priority 1: _tag (TaggedError pattern)\n const tagged = error as Record<string, unknown>;\n if (typeof tagged._tag === 'string') {\n const trimmed = tagged._tag.trim();\n if (trimmed) return trimmed;\n }\n // Priority 2: tag\n if (typeof tagged.tag === 'string') {\n const trimmed = tagged.tag.trim();\n if (trimmed) return trimmed;\n }\n // Priority 3: code — string used directly, number stringified, anything else skipped\n if (typeof tagged.code === 'string') {\n const trimmed = tagged.code.trim();\n if (trimmed) return trimmed;\n } else if (typeof tagged.code === 'number') {\n return String(tagged.code);\n }\n // Priority 4: Error.name (fallback-grade)\n if (error instanceof Error && error.name) {\n const trimmed = error.name.trim();\n if (trimmed) return trimmed;\n }\n }\n\n return 'unknown';\n}\n\n/** Look up ErrorClassification from errorMeta for a given tag. */\nexport function lookupErrorClassification(\n tag: string,\n errorMeta?: Record<string, ErrorClassification>,\n): ErrorClassification | undefined {\n if (!errorMeta || !tag) return undefined;\n return errorMeta[tag];\n}\n\n/** Extract StepMetadata from StepOptions (returns undefined when empty). */\nexport function extractStepMetadata(options: StepOptions): StepMetadata | undefined {\n const { intent, domain, owner, tags, stateChanges, emits, calls } = options;\n if (!intent && !domain && !owner && !tags?.length && !stateChanges?.length && !emits?.length && !calls?.length) {\n return undefined;\n }\n const metadata: StepMetadata = {};\n if (intent) metadata.intent = intent;\n if (domain) metadata.domain = domain;\n if (owner) metadata.owner = owner;\n if (tags?.length) metadata.tags = tags;\n if (stateChanges?.length) metadata.stateChanges = stateChanges;\n if (emits?.length) metadata.emits = emits;\n if (calls?.length) metadata.calls = calls;\n return metadata;\n}\n\n/** Build StepErrorDiagnostics from error + errorMeta. */\nfunction buildStepErrorPayload(\n error: unknown,\n errorMeta: StepOptions['errorMeta'],\n origin: StepErrorDiagnostics['origin'],\n attempt?: number,\n cumulativeDurationMs?: number,\n): StepErrorDiagnostics {\n const tag = extractErrorTag(error);\n const classification = lookupErrorClassification(tag, errorMeta);\n const diagnostics: StepErrorDiagnostics = { tag, origin };\n if (classification !== undefined) diagnostics.classification = classification;\n if (attempt !== undefined) diagnostics.attempt = attempt;\n if (cumulativeDurationMs !== undefined) diagnostics.cumulativeDurationMs = cumulativeDurationMs;\n return diagnostics;\n}\n\n// =============================================================================\n// Retry and Timeout Types\n// =============================================================================\n\n/**\n * Backoff strategy for retry operations.\n */\nexport type BackoffStrategy = \"fixed\" | \"linear\" | \"exponential\";\n\n/**\n * Configuration for step retry behavior.\n */\nexport type RetryOptions = {\n /**\n * Total number of attempts (1 = no retry, 3 = initial + 2 retries).\n * Must be >= 1.\n */\n attempts: number;\n\n /**\n * Backoff strategy between retries.\n * - 'fixed': Same delay each time (initialDelay)\n * - 'linear': Delay increases linearly (initialDelay * attempt)\n * - 'exponential': Delay doubles each time (initialDelay * 2^(attempt-1))\n * @default 'exponential'\n */\n backoff?: BackoffStrategy;\n\n /**\n * Initial delay in milliseconds before first retry.\n * @default 100\n */\n initialDelay?: number;\n\n /**\n * Maximum delay cap in milliseconds.\n * Prevents exponential backoff from growing too large.\n * @default 30000 (30 seconds)\n */\n maxDelay?: number;\n\n /**\n * Whether to add random jitter (0-25% of delay).\n * Helps prevent thundering herd when multiple workflows retry simultaneously.\n * @default true\n */\n jitter?: boolean;\n\n /**\n * Predicate to determine if a retry should occur.\n * Receives the error and current attempt number (1-indexed).\n * Return true to retry, false to fail immediately.\n * @default Always retry on any error\n */\n retryOn?: (error: unknown, attempt: number) => boolean;\n\n /**\n * Callback invoked before each retry attempt.\n * Useful for logging, metrics, or side effects.\n */\n onRetry?: (error: unknown, attempt: number, delayMs: number) => void;\n};\n\n/**\n * Timeout behavior when the timeout is reached.\n *\n * - 'error' (default): Return an error result with StepTimeoutError\n * - 'option': Return Ok(undefined) instead of an error (useful for optional operations)\n * - 'disconnect': Let the operation complete in background, return timeout error immediately\n * - function: Custom handler to generate the timeout error\n */\nexport type TimeoutBehavior =\n | \"error\"\n | \"option\"\n | \"disconnect\"\n | ((stepInfo: { name?: string; key?: string; ms: number }) => unknown);\n\n/**\n * Configuration for step timeout behavior.\n */\nexport type TimeoutOptions = {\n /**\n * Timeout duration in milliseconds per attempt.\n * When combined with retry, each attempt gets its own timeout.\n */\n ms: number;\n\n /**\n * Custom error to use when timeout occurs.\n * @default StepTimeoutError with step details\n */\n error?: unknown;\n\n /**\n * Whether to pass an AbortSignal to the operation.\n * When true, the operation function receives (signal: AbortSignal) as argument.\n * Useful for fetch() and other APIs that support cancellation.\n * @default false\n */\n signal?: boolean;\n\n /**\n * Behavior when timeout is reached.\n *\n * - 'error' (default): Return StepTimeoutError (or custom error if provided)\n * - 'option': Return Ok(undefined) instead of error (operation treated as optional)\n * - 'disconnect': Let operation complete in background, return error immediately\n * - function: Custom handler `(stepInfo) => customError`\n *\n * @default 'error'\n *\n * @example\n * ```typescript\n * // Default: Return timeout error\n * step.withTimeout(() => slowOp(), { ms: 5000 });\n *\n * // Optional: Return undefined if times out\n * step.withTimeout(() => optionalOp(), { ms: 5000, onTimeout: 'option' });\n *\n * // Disconnect: Don't wait for slow operation\n * step.withTimeout(() => fireAndForget(), { ms: 5000, onTimeout: 'disconnect' });\n *\n * // Custom error\n * step.withTimeout(() => apiCall(), {\n * ms: 5000,\n * onTimeout: ({ name, ms }) => ({ type: 'API_TIMEOUT', name, ms })\n * });\n * ```\n */\n onTimeout?: TimeoutBehavior;\n};\n\n/**\n * Standard timeout error type.\n */\nexport type StepTimeoutError = {\n type: \"STEP_TIMEOUT\";\n stepName?: string;\n stepKey?: string;\n timeoutMs: number;\n attempt?: number;\n};\n\n/**\n * Symbol used to mark any error (including custom errors) as a timeout error.\n * This allows detection of timeout errors even when users provide custom error payloads.\n */\nexport const STEP_TIMEOUT_MARKER: unique symbol = Symbol.for(\"step_timeout_marker\");\n\n/**\n * Metadata attached to timeout-marked errors.\n */\nexport type StepTimeoutMarkerMeta = {\n timeoutMs: number;\n stepName?: string;\n stepKey?: string;\n attempt?: number;\n};\n\n/**\n * Type guard to check if an error is a StepTimeoutError.\n * This checks both the standard type field AND the timeout marker symbol,\n * so custom errors provided via timeout.error are also detected.\n */\nexport function isStepTimeoutError(e: unknown): e is StepTimeoutError {\n if (typeof e !== \"object\" || e === null) {\n return false;\n }\n // Check for standard type field\n if ((e as StepTimeoutError).type === \"STEP_TIMEOUT\") {\n return true;\n }\n // Check for timeout marker (custom errors)\n return STEP_TIMEOUT_MARKER in e;\n}\n\n/**\n * Get timeout metadata from a timeout error (works with both standard and custom errors).\n * Returns undefined if the error is not a timeout error.\n */\nexport function getStepTimeoutMeta(e: unknown): StepTimeoutMarkerMeta | undefined {\n if (typeof e !== \"object\" || e === null) {\n return undefined;\n }\n // Check for standard type field first\n if ((e as StepTimeoutError).type === \"STEP_TIMEOUT\") {\n const err = e as StepTimeoutError;\n return {\n timeoutMs: err.timeoutMs,\n stepName: err.stepName,\n stepKey: err.stepKey,\n attempt: err.attempt,\n };\n }\n // Check for timeout marker (custom errors)\n if (STEP_TIMEOUT_MARKER in e) {\n return (e as Record<symbol, StepTimeoutMarkerMeta>)[STEP_TIMEOUT_MARKER];\n }\n return undefined;\n}\n\n// =============================================================================\n// RunStep Interface\n// =============================================================================\n\n/**\n * The `step` object passed to the function in `run(async ({ step }) => { ... })`.\n * acts as the bridge between your business logic and the workflow engine.\n *\n * It provides methods to:\n * 1. Execute operations that return `Result` types.\n * 2. safely wrap operations that might throw exceptions (using `step.try`).\n * 3. Assign names and keys to operations for tracing and caching.\n *\n * @template E - The union of all known error types expected in this workflow.\n */\nexport interface RunStep<E = unknown> {\n /**\n * Execute a Result-returning operation with explicit step ID.\n *\n * The ID is used for:\n * - Static analysis visualization\n * - Error flow tracking\n * - Step identification in diagrams\n * - Caching and resume (ID is used as the cache key)\n *\n * @param id - Unique step identifier (string literal for static analysis)\n * @param operation - A function that returns a Result or AsyncResult\n * @param options - Step options\n * @returns The success value (unwrapped)\n * @throws {EarlyExit} If the result is an error (stops execution safely)\n *\n * @example\n * ```typescript\n * const cart = await step('getCart', () => getCart(ctx.input.cartId), {\n * errors: ['CART_NOT_FOUND', 'CART_EMPTY'],\n * out: 'cart',\n * });\n * ```\n */\n <T, StepE extends E, StepC = unknown>(\n id: string,\n operation: () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n options?: StepOptions\n ): Promise<T>;\n\n /**\n * Execute a standard throwing operation safely.\n * Catches exceptions and maps them to a typed error, or wraps them if no mapper is provided.\n *\n * Use this when integrating with libraries that throw exceptions.\n *\n * @param id - Unique identifier for this step (required for analysis and caching)\n * @param operation - A function that returns a value or Promise (may throw)\n * @param options - Configuration including error mapping\n * @returns The success value\n * @throws {EarlyExit} If the operation throws (stops execution safely)\n *\n * @example\n * ```typescript\n * const data = await step.try(\n * \"db-query\",\n * () => db.query(),\n * { onError: (e) => ({ type: \"DB_ERROR\", cause: e }) }\n * );\n * ```\n */\n try: <T, const Err extends E>(\n id: string,\n operation: () => T | Promise<T>,\n options:\n | { error: Err; key?: string; ttl?: number }\n | { onError: (cause: unknown) => Err; key?: string; ttl?: number }\n ) => Promise<T>;\n\n /**\n * Execute a Result-returning function and map its error to a typed error.\n *\n * Use this when calling functions that return Result<T, E> and you want to\n * map their typed errors to your workflow's error type. Unlike step.try(),\n * the error passed to onError is typed (not unknown).\n *\n * @param id - Unique identifier for this step (required for analysis and caching)\n * @param operation - A function that returns a Result or AsyncResult\n * @param options - Configuration including error mapping\n * @returns The success value (unwrapped)\n * @throws {EarlyExit} If the result is an error (stops execution safely)\n *\n * @example\n * ```typescript\n * const response = await step.fromResult(\n * \"call-provider\",\n * () => callProvider(input),\n * {\n * onError: (providerError) => ({\n * type: \"PROVIDER_FAILED\",\n * provider: providerError.provider,\n * cause: providerError\n * })\n * }\n * );\n * ```\n */\n fromResult: <T, ResultE, const Err extends E>(\n id: string,\n operation: () => Result<T, ResultE, unknown> | AsyncResult<T, ResultE, unknown>,\n options:\n | { error: Err; key?: string; ttl?: number }\n | { onError: (resultError: ResultE) => Err; key?: string; ttl?: number }\n ) => Promise<T>;\n\n /**\n * Execute an operation that may return null/undefined and convert to a typed error.\n *\n * Shorthand for wrapping `fromNullable()` in a step — avoids boilerplate when\n * looking up optional values (database finds, map lookups, etc.).\n *\n * @param id - Unique step identifier\n * @param operation - A function that returns `T | null | undefined` (or a Promise thereof)\n * @param onNull - Returns the typed error when operation returns null/undefined\n *\n * @example\n * ```typescript\n * const user = await step.fromNullable(\n * 'getUser',\n * () => db.users.findById(id),\n * () => ({ type: 'NOT_FOUND' as const, id })\n * );\n * ```\n */\n fromNullable: <T, const Err extends E>(\n id: string,\n operation: () => T | null | undefined | Promise<T | null | undefined>,\n onNull: () => Err,\n options?: { key?: string; ttl?: number }\n ) => Promise<T>;\n\n /**\n * Execute parallel operations with scope events for visualization.\n *\n * This wraps the operations with scope_start and scope_end events, enabling\n * visualization of parallel execution branches.\n *\n * @overload Object form - step.parallel(name, { key: () => ... })\n * @overload Array form - step.parallel(name, () => allAsync([...]))\n *\n * @example Object form\n * ```typescript\n * const { user, posts } = await step.parallel('Fetch user data', {\n * user: () => fetchUser(id),\n * posts: () => fetchPosts(id),\n * });\n * ```\n *\n * @example Canonical form (strict mode)\n * ```typescript\n * const { user, posts } = await step.parallel('Fetch user data', {\n * user: { fn: () => fetchUser(id), errors: ['NOT_FOUND'] },\n * posts: { fn: () => fetchPosts(id), errors: ['FETCH_ERROR'] },\n * });\n * ```\n *\n * @example Array form\n * ```typescript\n * const [user, posts] = await step.parallel('Fetch all data', () =>\n * allAsync([fetchUser(id), fetchPosts(id)])\n * );\n * ```\n */\n parallel: {\n // Object form: step.parallel(name, { key: () => ... })\n <\n TOperations extends Record<\n string,\n () => MaybeAsyncResult<unknown, E, unknown>\n >\n >(\n name: string,\n operations: TOperations\n ): Promise<{\n [K in keyof TOperations]: TOperations[K] extends () => MaybeAsyncResult<\n infer V,\n E,\n unknown\n >\n ? V\n : never;\n }>;\n\n // Object form canonical: step.parallel(name, { key: { fn, errors } })\n <\n TOperations extends Record<\n string,\n ParallelOperationDescriptor<unknown, readonly string[]>\n >\n >(\n name: string,\n operations: TOperations\n ): Promise<{\n [K in keyof TOperations]: TOperations[K] extends ParallelOperationDescriptor<\n infer V,\n readonly string[]\n >\n ? V\n : never;\n }>;\n\n // Array form: step.parallel(name, () => allAsync([...]))\n <T, StepE extends E, StepC = unknown>(\n name: string,\n operation: () => Result<T[], StepE, StepC> | AsyncResult<T[], StepE, StepC>\n ): Promise<T[]>;\n };\n\n /**\n * Execute a race operation (anyAsync) with scope events for visualization.\n *\n * This wraps the operation with scope_start and scope_end events, enabling\n * visualization of racing execution branches.\n *\n * @param name - Name for this race block (used in visualization)\n * @param operation - A function that returns a Result from anyAsync\n * @returns The success value (first to succeed)\n *\n * @example\n * ```typescript\n * const data = await step.race('Fastest API', () =>\n * anyAsync([fetchFromPrimary(id), fetchFromFallback(id)])\n * );\n * ```\n */\n race: <T, StepE extends E, StepC = unknown>(\n name: string,\n operation: () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>\n ) => Promise<T>;\n\n /**\n * Execute an allSettled operation with scope events for visualization.\n *\n * This wraps the operation with scope_start and scope_end events, enabling\n * visualization of allSettled execution branches. Unlike step.parallel,\n * allSettled collects all results even if some fail.\n *\n * @param name - Name for this allSettled block (used in visualization)\n * @param operation - A function that returns a Result from allSettledAsync\n * @returns The success value (unwrapped array)\n *\n * @example\n * ```typescript\n * const [user, posts] = await step.allSettled('Fetch all data', () =>\n * allSettledAsync([fetchUser(id), fetchPosts(id)])\n * );\n * ```\n */\n allSettled: <T, StepE extends E, StepC = unknown>(\n name: string,\n operation: () => Result<T[], StepE, StepC> | AsyncResult<T[], StepE, StepC>\n ) => Promise<T[]>;\n\n /**\n * Execute a primary operation with a fallback if the primary fails.\n *\n * If the primary operation returns an error, the fallback is executed instead.\n * When `on` is specified, the fallback only runs for that specific error;\n * other errors propagate without invoking the fallback.\n *\n * Returns `Promise<T>` — errors escape via earlyExit into the workflow's error channel.\n * The error union `E1 | E2` is the generic constraint propagated to the workflow.\n *\n * @overload Fallback on ANY error from primary\n * @overload Fallback on SPECIFIC error literal only (via `on`)\n *\n * @param id - Unique step identifier (single step ID for events)\n * @param operation - Primary operation that returns AsyncResult\n * @param options - Fallback configuration\n * @returns The success value from primary or fallback\n *\n * @example\n * ```typescript\n * const user = await step.withFallback(\n * 'getUser',\n * () => fetchFromPrimary(id),\n * { fallback: () => fetchFromCache(id) }\n * );\n *\n * // With specific error filter\n * const data = await step.withFallback(\n * 'getData',\n * () => fetchFromApi(id),\n * { on: 'NOT_FOUND', fallback: () => getDefault(id) }\n * );\n * ```\n */\n withFallback: {\n // Overload 1: fallback on ANY error from primary\n <T, E1 extends E, E2 extends E>(\n id: string,\n operation: () => AsyncResult<T, E1>,\n options: { fallback: () => AsyncResult<T, E2>; key?: string }\n ): Promise<T>;\n\n // Overload 2: fallback on SPECIFIC error literal only\n <T, E1 extends E & string, E2 extends E>(\n id: string,\n operation: () => AsyncResult<T, E1>,\n options: { on: E1; fallback: () => AsyncResult<T, E2>; key?: string }\n ): Promise<T>;\n };\n\n /**\n * Execute an operation with automatic resource lifecycle management.\n *\n * Acquires a resource, uses it, and guarantees release regardless of outcome.\n * Release always runs after use completes (even on error or throw).\n * Release errors are logged via console.warn but never override the use result.\n *\n * No caching support — caching resource-using steps is dangerous.\n *\n * @param id - Unique step identifier\n * @param options - Resource lifecycle configuration\n * @returns The success value from the use function\n *\n * @example\n * ```typescript\n * const data = await step.withResource('useDb', {\n * acquire: () => connectToDb(),\n * use: (db) => db.query('SELECT * FROM users'),\n * release: (db) => db.close(),\n * });\n * ```\n */\n withResource: <T, R, AcquireE extends E, UseE extends E>(\n id: string,\n options: {\n acquire: () => AsyncResult<R, AcquireE>;\n use: (resource: R) => AsyncResult<T, UseE>;\n release: (resource: R) => void | Promise<void>;\n }\n ) => Promise<T>;\n\n /**\n * Execute an operation with retry and optional timeout.\n *\n * Use this for operations that may fail transiently (network issues, rate limits)\n * and benefit from automatic retry with backoff.\n *\n * @param id - Unique identifier for this step (required for analysis and caching)\n * @param operation - A function that returns a Result or AsyncResult\n * @param options - Retry configuration and optional timeout\n * @returns The success value (unwrapped)\n * @throws {EarlyExit} If all retries are exhausted (stops execution safely)\n *\n * @example\n * ```typescript\n * const data = await step.retry(\n * \"fetch-external\",\n * () => fetchFromExternalApi(id),\n * {\n * attempts: 3,\n * backoff: 'exponential',\n * initialDelay: 200,\n * retryOn: (error) => error === 'RATE_LIMITED' || error === 'TRANSIENT',\n * onRetry: (error, attempt, delay) => {\n * console.log(`Retry ${attempt} after ${delay}ms`);\n * },\n * }\n * );\n * ```\n */\n retry: <T, StepE extends E, StepC = unknown>(\n id: string,\n operation: () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n options: RetryOptions & { key?: string; timeout?: TimeoutOptions }\n ) => Promise<T>;\n\n /**\n * Execute an operation with a timeout.\n *\n * Use this for operations that may hang indefinitely (external APIs, connections)\n * and need to be aborted after a certain duration.\n *\n * When `signal: true` is set, an AbortSignal is passed to your operation,\n * which you can use with APIs like fetch() for proper cancellation.\n *\n * @param id - Unique identifier for this step (required for analysis and caching)\n * @param operation - A function that returns a Result (may receive AbortSignal)\n * @param options - Timeout configuration\n * @returns The success value (unwrapped)\n * @throws {EarlyExit} If the operation times out (stops execution safely)\n *\n * @example\n * ```typescript\n * // Without AbortSignal\n * const data = await step.withTimeout(\n * \"fetch-data\",\n * () => fetchData(id),\n * { ms: 5000 }\n * );\n *\n * // With AbortSignal for fetch()\n * const data = await step.withTimeout(\n * \"fetch-url\",\n * (signal) => fetch(url, { signal }).then(r => ok(r.json())),\n * { ms: 5000, signal: true }\n * );\n * ```\n */\n withTimeout: <T, StepE extends E, StepC = unknown>(\n id: string,\n operation:\n | (() => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>)\n | ((signal: AbortSignal) => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>),\n options: TimeoutOptions & { key?: string }\n ) => Promise<T>;\n\n /**\n * Pause execution for a specified duration.\n *\n * Use this for intentional delays between operations (rate limiting,\n * polling intervals, debouncing). Respects workflow cancellation.\n *\n * @param id - Unique identifier for this step (required for analysis and caching)\n * @param duration - Duration as string (\"5s\", \"100ms\") or Duration object\n * @param options - Optional key for per-iteration identity, ttl, description\n * @returns Promise that resolves after the duration\n * @throws {AbortError} If the workflow is cancelled during sleep\n *\n * @example\n * ```typescript\n * // String duration\n * await step.sleep(\"rate-limit-delay\", \"5s\");\n *\n * // Duration object\n * await step.sleep(\"my-sleep\", seconds(5));\n * ```\n */\n sleep(\n id: string,\n duration: DurationInput,\n options?: { key?: string; ttl?: number; description?: string; signal?: AbortSignal }\n ): Promise<void>;\n\n // ===========================================================================\n // Streaming Methods\n // ===========================================================================\n\n /**\n * Get a writable stream for this workflow.\n *\n * Use this to write values that can be consumed by readers\n * (e.g., HTTP response streaming, AI token streaming).\n *\n * @param options - Stream options (namespace, highWaterMark)\n * @returns StreamWriter for writing values\n *\n * @example\n * ```typescript\n * const writer = step.getWritable<string>({ namespace: 'ai-response' });\n *\n * await step(() => generateAI({\n * prompt: 'Hello',\n * onToken: async (token) => { await writer.write(token); }\n * }), { key: 'generate' });\n *\n * await writer.close();\n * ```\n */\n getWritable: <T>(options?: StreamWritableOptions) => StreamWriterInterface<T>;\n\n /**\n * Get a readable stream for this workflow.\n *\n * Use this to consume values from a stream, with support for\n * resuming from a specific position.\n *\n * @param options - Read options (namespace, startIndex)\n * @returns StreamReader for reading values\n *\n * @example\n * ```typescript\n * const reader = step.getReadable<string>({ namespace: 'ai-response' });\n *\n * let result = await reader.read();\n * while (result.ok) {\n * response.write(result.value);\n * result = await reader.read();\n * }\n * ```\n */\n getReadable: <T>(options?: StreamReadableOptions) => StreamReaderInterface<T>;\n\n /**\n * Process stream items with checkpointing.\n *\n * Combines streaming with batch processing - each item is processed\n * and checkpointed, enabling resume from the last successful item.\n *\n * @param source - StreamReader or AsyncIterable to process\n * @param processor - Function to process each item\n * @param options - Processing options\n * @returns Results from all processed items\n *\n * @example\n * ```typescript\n * const reader = step.getReadable<Message>({ namespace: 'messages' });\n *\n * const result = await step.streamForEach(\n * reader,\n * async (message, index) => {\n * const processed = await processMessage(message);\n * return ok(processed);\n * },\n * { name: 'process-messages', checkpointInterval: 10 }\n * );\n *\n * console.log(`Processed ${result.value.processedCount} messages`);\n * ```\n */\n streamForEach: <T, R, StepE extends E>(\n source: StreamReaderInterface<T> | AsyncIterable<T>,\n processor: (item: T, index: number) => AsyncResult<R, StepE>,\n options?: StreamForEachStepOptions\n ) => Promise<StreamForEachResultType<R>>;\n\n // ===========================================================================\n // Static Analysis Methods\n // ===========================================================================\n\n /**\n * Mark a conditional for static analysis with a stable ID and condition label.\n * Runtime: returns the boolean result of condition().\n * Analysis: emits a DecisionNode with stable id and conditionLabel, and attaches\n * the then/else subgraphs from the if/else branches.\n *\n * @param id - Stable identifier for this decision point (string literal for static analysis)\n * @param conditionLabel - Human-readable label describing the condition\n * @param condition - Function that returns the boolean condition\n * @returns The result of the condition function\n *\n * @example\n * ```typescript\n * if (step.if('payment', 'cart.total > 0', () => ctx.ref('cart').total > 0)) {\n * await step('chargeCard', () => deps.chargeCard(ctx.ref('cart').total), {\n * errors: ['CARD_DECLINED'],\n * });\n * } else {\n * await step('skipPayment', async () => ({ skipped: true }), {\n * errors: [],\n * });\n * }\n * ```\n */\n if: <T extends boolean>(\n id: string,\n conditionLabel: string,\n condition: () => T\n ) => T;\n\n /**\n * Alias for `step.if()`. Mark a conditional for static analysis with a stable ID.\n * Use this to label conditionals in strict mode when they contain step calls.\n *\n * @param id - Stable identifier for this decision point\n * @param conditionLabel - Human-readable label describing the condition\n * @param condition - Function that returns the boolean condition\n * @returns The result of the condition function\n *\n * @example\n * ```typescript\n * if (step.label('email-type', 'user.isPremium', () => user.isPremium)) {\n * await step('premium', () => sendPriorityEmail(user), { errors: ['EMAIL_FAILED'] });\n * } else {\n * await step('free', () => sendRegularEmail(user), { errors: ['EMAIL_FAILED'] });\n * }\n * ```\n */\n label: <T extends boolean>(\n id: string,\n conditionLabel: string,\n condition: () => T\n ) => T;\n\n /**\n * Execute a branch with explicit metadata for static analysis.\n * Use when you want richer analyzer metadata (conditionLabel, per-arm errors).\n * For most cases, use natural if/else with step.label() instead.\n *\n * @param id - Stable identifier for this branch point\n * @param options - Branch configuration with condition, then/else arms, and errors\n * @returns The result from the executed arm\n *\n * @example\n * ```typescript\n * const charge = await step.branch('payment', {\n * conditionLabel: 'cart.total > 0',\n * condition: () => ctx.ref('cart').total > 0,\n * out: 'charge',\n * then: () => chargeCard(ctx.ref('cart').total),\n * thenErrors: ['CARD_DECLINED'],\n * else: () => ok({ skipped: true }),\n * elseErrors: [],\n * });\n * ```\n */\n branch: <\n T,\n const ThenErrs extends readonly string[] = readonly [],\n const ElseErrs extends readonly string[] = readonly [],\n const Out extends string | undefined = undefined,\n >(\n id: string,\n options: BranchOptions<T, ThenErrs, ElseErrs, Out>\n ) => Promise<T>;\n\n /**\n * Create an arm definition for use with step.branch().\n * Runtime: returns the arm definition unchanged.\n * Analyzer: extracts arm metadata for visualization.\n *\n * @param fn - The arm function\n * @param errors - Declared errors for this arm\n * @returns The arm definition\n *\n * @example\n * ```typescript\n * const thenArm = step.arm(() => chargeCard(total), ['CARD_DECLINED']);\n * const elseArm = step.arm(() => ok({ skipped: true }), []);\n * ```\n */\n arm: <T, const Errs extends readonly string[] = readonly []>(\n fn: () => T | Promise<T>,\n errors?: Errs\n ) => ArmDefinition<T, Errs>;\n\n /**\n * Execute a forEach loop with static analysis support.\n * Supports both simple (run) and complex (item) forms.\n *\n * @param id - Stable identifier for this loop\n * @param items - Iterable to loop over\n * @param options - Loop configuration\n * @returns Array of results from each iteration\n *\n * @example Simple form:\n * ```typescript\n * await step.forEach('process-items', items, {\n * maxIterations: 100,\n * stepIdPattern: 'process-{i}',\n * errors: ['PROCESS_ERROR'],\n * run: (item) => processItem(item),\n * });\n * ```\n *\n * @example Complex form with multiple steps:\n * ```typescript\n * await step.forEach('process-items', items, {\n * maxIterations: 100,\n * item: step.item((item, i, innerStep) => {\n * await innerStep('validate', () => validate(item), { errors: ['INVALID'] });\n * await innerStep('process', () => process(item), { errors: ['FAILED'] });\n * }),\n * });\n * ```\n */\n forEach: {\n // Simple form with run callback\n <T, R, const Errs extends readonly string[] = readonly []>(\n id: string,\n items: Iterable<T> | AsyncIterable<T>,\n options: ForEachRunOptions<T, R, Errs>\n ): Promise<R[]>;\n\n // Complex form with item callback\n <T, R>(\n id: string,\n items: Iterable<T> | AsyncIterable<T>,\n options: ForEachItemOptions<T, R>\n ): Promise<R[]>;\n };\n\n /**\n * Create an item handler for use with step.forEach().\n * Runtime: returns the handler unchanged.\n * Analyzer: extracts the inner step structure.\n *\n * @param handler - Function to process each item\n * @returns The item handler\n *\n * @example\n * ```typescript\n * step.item((item, index, innerStep) => {\n * await innerStep('validate', () => validate(item));\n * await innerStep('process', () => process(item));\n * });\n * ```\n */\n item: <T, R>(\n handler: (item: T, index: number, step: RunStep<E>) => R | Promise<R>\n ) => ForEachItemHandler<T, R>;\n\n /**\n * Wrap a dependency function for static analysis tracking.\n * Returns the function unchanged but marks it for the analyzer.\n *\n * @param name - Name of the dependency (for analyzer tracking)\n * @param fn - The dependency function to wrap\n * @returns The same function, unchanged\n *\n * @example\n * ```typescript\n * await step('getCart', step.dep('getCart', () => deps.getCart(ctx.input.cartId)), {\n * errors: ['CART_NOT_FOUND'],\n * out: 'cart',\n * });\n * ```\n */\n dep: <T extends (...args: unknown[]) => unknown>(name: string, fn: T) => T;\n\n // ===========================================================================\n // Effect-Style Ergonomics\n // ===========================================================================\n\n /**\n * Unwrap an AsyncResult directly within a workflow step.\n *\n * Use this when you already have an AsyncResult and want to unwrap it\n * without wrapping it in a function. Automatically exits on error.\n *\n * @param id - Unique step identifier\n * @param result - The AsyncResult to unwrap\n * @param options - Step options\n * @returns The success value (unwrapped)\n * @throws {EarlyExit} If the result is an error\n *\n * @example\n * ```typescript\n * const userResult = fetchUser(userId); // AsyncResult<User, 'NOT_FOUND'>\n * const user = await step.run('fetchUser', userResult);\n * // Automatically unwraps and exits on error\n * ```\n */\n run: <T, StepE extends E, StepC = unknown>(\n id: string,\n result: AsyncResult<T, StepE, StepC>,\n options?: StepOptions\n ) => Promise<T>;\n\n /**\n * Run a sub-workflow (or any AsyncResult-returning operation) as a step.\n * Use for workflow composition; the getter's error type (SubE) flows into the parent's error union.\n *\n * @param id - Unique step identifier\n * @param getter - Function that returns AsyncResult (e.g. () => subWorkflow.run(fn))\n * @param options - Step options (key, ttl, etc.)\n * @returns The success value (unwrapped)\n * @throws {EarlyExit} If the result is an error\n *\n * @example\n * ```typescript\n * const authResult = await step.workflow(\"authorize\", () => authorizeWorkflow.run(fn));\n * ```\n */\n workflow: <T, SubE extends E, StepC = unknown>(\n id: string,\n getter: () => AsyncResult<T, SubE, StepC>,\n options?: StepOptions\n ) => Promise<T>;\n\n /**\n * Chain AsyncResult operations with step tracking.\n *\n * Use this for composing AsyncResult operations where each step\n * depends on the previous one's success value.\n *\n * @param id - Unique step identifier\n * @param value - The value to pass to the function\n * @param fn - Function that takes the value and returns an AsyncResult\n * @param options - Step options\n * @returns The final success value (unwrapped)\n * @throws {EarlyExit} If the result is an error\n *\n * @example\n * ```typescript\n * const user = await step.run('fetchUser', fetchUser(id));\n * const enriched = await step.andThen('enrich', user, (user) =>\n * enrichUser(user) // Returns AsyncResult<EnrichedUser, E>\n * );\n * ```\n */\n andThen: <T, U, StepE extends E, StepC = unknown>(\n id: string,\n value: T,\n fn: (value: T) => AsyncResult<U, StepE, StepC>,\n options?: StepOptions\n ) => Promise<U>;\n\n /**\n * Pattern match on a Result with step tracking for both branches.\n *\n * Use this for handling Result values where both success and error\n * paths need to be tracked as separate steps.\n *\n * @param id - Unique step identifier\n * @param result - The Result to match on\n * @param handlers - Object with ok and err handler functions\n * @param options - Step options\n * @returns The value returned by the matched handler\n *\n * @example\n * ```typescript\n * const user = await step.run('fetchUser', fetchUser(id));\n *\n * const message = await step.match('handleUser', user, {\n * ok: async (user) => {\n * await step('sendWelcome', () => sendEmail(user.email));\n * return 'Sent welcome email';\n * },\n * err: async (error) => {\n * await step('logError', () => logError(error));\n * return 'Failed to fetch user';\n * }\n * });\n * ```\n */\n match: <T, StepE extends E, U, StepC = unknown>(\n id: string,\n result: Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n handlers: {\n ok: (value: T) => U | Promise<U>;\n err: (error: StepE, cause?: StepC) => U | Promise<U>;\n },\n options?: StepOptions\n ) => Promise<U>;\n\n /**\n * Alias for step.parallel - Effect.all-style API for parallel execution.\n *\n * Executes multiple operations in parallel and returns named results.\n * Identical to step.parallel but with a name more familiar to Effect users.\n *\n * @param name - Name for this parallel block\n * @param operations - Object mapping keys to operations\n * @returns Object with results mapped to the same keys\n *\n * @example\n * ```typescript\n * const { user, posts, comments } = await step.all('fetchAll', {\n * user: () => fetchUser('1'),\n * posts: () => fetchPosts('1'),\n * comments: () => fetchComments('1')\n * });\n * ```\n */\n all: RunStep<E>[\"parallel\"];\n\n /**\n * Map over an array with parallel execution and error tracking.\n *\n * Similar to Effect.forEach - executes mapper function for each item\n * in parallel and collects results.\n *\n * @param id - Unique step identifier\n * @param items - Array of items to process\n * @param mapper - Function to process each item (returns AsyncResult)\n * @param options - Optional concurrency limit and cache key\n * @returns Array of results in original order\n *\n * @example\n * ```typescript\n * const users = await step.map('fetchUsers', userIds, (id) =>\n * fetchUser(id)\n * );\n * // Automatic parallel execution with error union\n * ```\n */\n map: <T, U, StepE extends E, StepC = unknown>(\n id: string,\n items: T[],\n mapper: (item: T, index: number) => AsyncResult<U, StepE, StepC>,\n options?: { concurrency?: number; key?: string }\n ) => Promise<U[]>;\n\n}\n\n// =============================================================================\n// Parallel Types\n// =============================================================================\n\n/**\n * Operation descriptor for canonical parallel form.\n * Use this for analyzable parallel operations with explicit error declarations.\n */\nexport type ParallelOperationDescriptor<\n T,\n Errs extends readonly string[] = readonly [],\n> = {\n /** The operation function */\n fn: () => MaybeAsyncResult<T, unknown, unknown>;\n /** Declared errors for this operation (for static analysis) */\n errors?: Errs;\n};\n\n// =============================================================================\n// Branch and ForEach Types\n// =============================================================================\n\n/**\n * Options for step.branch().\n */\nexport type BranchOptions<\n T,\n ThenErrs extends readonly string[] = readonly [],\n ElseErrs extends readonly string[] = readonly [],\n Out extends string | undefined = undefined,\n> = {\n /** Human-readable label describing the condition */\n conditionLabel: string;\n /** Function that evaluates the condition */\n condition: () => boolean;\n /** Output key for data flow (writes result to ctx[out]) */\n out?: Out;\n /** Function to execute when condition is true */\n then: () => T | Promise<T>;\n /** Declared errors for the then arm */\n thenErrors?: ThenErrs;\n /** Function to execute when condition is false */\n else?: () => T | Promise<T>;\n /** Declared errors for the else arm */\n elseErrors?: ElseErrs;\n};\n\n/**\n * Arm definition for step.branch().\n */\nexport type ArmDefinition<T, Errs extends readonly string[] = readonly []> = {\n fn: () => T | Promise<T>;\n errors?: Errs;\n};\n\n/**\n * Options for step.forEach() with simple run form.\n */\nexport type ForEachRunOptions<T, R, Errs extends readonly string[] = readonly []> = {\n /** Maximum iterations (for bounded analysis) */\n maxIterations?: number;\n /** Step ID pattern for iterations (e.g., 'process-{i}') */\n stepIdPattern?: string;\n /** Declared errors for the loop body */\n errors?: Errs;\n /** Output key for results (requires collect option in strict mode) */\n out?: string;\n /** How to collect results when out is specified */\n collect?: \"array\" | \"last\";\n /** Simple callback for each item */\n run: (item: T, index: number) => R | Promise<R>;\n};\n\n/**\n * Options for step.forEach() with complex item form.\n */\nexport type ForEachItemOptions<T, R> = {\n /** Maximum iterations (for bounded analysis) */\n maxIterations?: number;\n /** Step ID pattern for iterations (e.g., 'process-{i}') */\n stepIdPattern?: string;\n /** Output key for results (requires collect option in strict mode) */\n out?: string;\n /** How to collect results when out is specified */\n collect?: \"array\" | \"last\";\n /** Complex item handler with inner step access */\n item: ForEachItemHandler<T, R>;\n};\n\n/**\n * Item handler for step.forEach() with inner step access.\n */\nexport type ForEachItemHandler<T, R> = {\n __forEachItemHandler: true;\n handler: (item: T, index: number, step: RunStep<unknown>) => R | Promise<R>;\n};\n\n// =============================================================================\n// Streaming Types (minimal interfaces for RunStep)\n// =============================================================================\n\n/**\n * Options for getWritable.\n */\nexport interface StreamWritableOptions {\n /** Named streams (default: 'default') */\n namespace?: string;\n /** Backpressure threshold (default: 16) */\n highWaterMark?: number;\n}\n\n/**\n * Options for getReadable.\n */\nexport interface StreamReadableOptions {\n /** Named streams (default: 'default') */\n namespace?: string;\n /** Resume from position (0-indexed) */\n startIndex?: number;\n /** Poll interval in ms when waiting for new items (default: 10) */\n pollInterval?: number;\n /** Stop polling after this many ms with no new items (default: 30000) */\n pollTimeout?: number;\n}\n\n/**\n * Options for streamForEach.\n */\nexport interface StreamForEachStepOptions {\n /** Checkpoint after every N items (default: 1) */\n checkpointInterval?: number;\n /** Maximum concurrent processors (default: 1 = sequential) */\n concurrency?: number;\n}\n\n/**\n * Result from streamForEach operation.\n */\nexport interface StreamForEachResultType<R> {\n /** Results from each processed item */\n results: R[];\n /** Total items processed */\n processedCount: number;\n /** Position of last processed item */\n lastPosition: number;\n}\n\n/**\n * Writable stream interface used in RunStep.\n * @see StreamWriter in awaitly/streaming for full interface\n */\nexport interface StreamWriterInterface<T> {\n write(value: T): AsyncResult<void, StreamWriteErrorType>;\n close(): AsyncResult<void, StreamCloseErrorType>;\n abort(reason: unknown): void;\n readonly writable: boolean;\n readonly position: number;\n readonly namespace: string;\n}\n\n/**\n * Readable stream interface used in RunStep.\n * @see StreamReader in awaitly/streaming for full interface\n */\nexport interface StreamReaderInterface<T> {\n read(): AsyncResult<T, StreamReadErrorType | StreamEndedMarkerType>;\n close(): void;\n readonly readable: boolean;\n readonly position: number;\n readonly namespace: string;\n}\n\n/**\n * Stream write error type.\n */\nexport interface StreamWriteErrorType {\n type: \"STREAM_WRITE_ERROR\";\n reason: \"closed\" | \"aborted\" | \"store_error\";\n message: string;\n cause?: unknown;\n}\n\n/**\n * Stream read error type.\n */\nexport interface StreamReadErrorType {\n type: \"STREAM_READ_ERROR\";\n reason: \"closed\" | \"store_error\";\n message: string;\n cause?: unknown;\n}\n\n/**\n * Stream close error type.\n */\nexport interface StreamCloseErrorType {\n type: \"STREAM_CLOSE_ERROR\";\n reason: \"already_closed\" | \"store_error\";\n message: string;\n cause?: unknown;\n}\n\n/**\n * Stream ended marker type.\n */\nexport interface StreamEndedMarkerType {\n type: \"STREAM_ENDED\";\n finalPosition: number;\n}\n\n// =============================================================================\n// Event Types (for run() optional event support)\n// =============================================================================\n\n/**\n * Unified event stream for workflow execution.\n *\n * Note: step_complete.result uses Result<unknown, unknown, unknown> because events\n * aggregate results from heterogeneous steps. At runtime, the actual Result object\n * preserves its original types, but the event type cannot statically represent them.\n * Use runtime checks or the meta field to interpret cause values.\n */\n/**\n * Scope types for parallel and race operations.\n */\nexport type ScopeType = \"parallel\" | \"race\" | \"allSettled\";\n\nexport type WorkflowEvent<E, C = unknown> =\n | { type: \"workflow_start\"; workflowId: string; workflowName?: string; ts: number; context?: C }\n | { type: \"workflow_success\"; workflowId: string; workflowName?: string; ts: number; durationMs: number; context?: C }\n | { type: \"workflow_error\"; workflowId: string; workflowName?: string; ts: number; durationMs: number; error: E; context?: C }\n | { type: \"step_start\"; workflowId: string; workflowName?: string; stepId: string; stepKey?: string; name?: string; description?: string; ts: number; metadata?: StepMetadata; context?: C }\n | { type: \"step_success\"; workflowId: string; workflowName?: string; stepId: string; stepKey?: string; name?: string; description?: string; ts: number; durationMs: number; metadata?: StepMetadata; context?: C }\n | { type: \"step_error\"; workflowId: string; workflowName?: string; stepId: string; stepKey?: string; name?: string; description?: string; ts: number; durationMs: number; error: E; metadata?: StepMetadata; diagnostics?: StepErrorDiagnostics; context?: C }\n | { type: \"step_aborted\"; workflowId: string; workflowName?: string; stepId: string; stepKey?: string; name?: string; description?: string; ts: number; durationMs: number; metadata?: StepMetadata; context?: C }\n | { type: \"step_complete\"; workflowId: string; workflowName?: string; stepKey: string; name?: string; description?: string; ts: number; durationMs: number; result: Result<unknown, unknown, unknown>; meta?: StepFailureMeta; metadata?: StepMetadata; context?: C }\n | { type: \"step_cache_hit\"; workflowId: string; workflowName?: string; stepKey: string; name?: string; ts: number; metadata?: StepMetadata; context?: C }\n | { type: \"step_cache_miss\"; workflowId: string; workflowName?: string; stepKey: string; name?: string; ts: number; metadata?: StepMetadata; context?: C }\n | { type: \"step_skipped\"; workflowId: string; workflowName?: string; stepKey?: string; name?: string; reason?: string; decisionId?: string; ts: number; metadata?: StepMetadata; context?: C }\n | { type: \"scope_start\"; workflowId: string; workflowName?: string; scopeId: string; scopeType: ScopeType; name?: string; ts: number; context?: C }\n | { type: \"scope_end\"; workflowId: string; workflowName?: string; scopeId: string; ts: number; durationMs: number; winnerId?: string; context?: C }\n // Retry events\n | {\n type: \"step_retry\";\n workflowId: string;\n workflowName?: string;\n stepId: string;\n stepKey?: string;\n name?: string;\n ts: number;\n attempt: number;\n maxAttempts: number;\n delayMs: number;\n error: E;\n metadata?: StepMetadata;\n diagnostics?: StepErrorDiagnostics;\n context?: C;\n }\n | {\n type: \"step_retries_exhausted\";\n workflowId: string;\n workflowName?: string;\n stepId: string;\n stepKey?: string;\n name?: string;\n ts: number;\n durationMs: number;\n attempts: number;\n lastError: E;\n metadata?: StepMetadata;\n diagnostics?: StepErrorDiagnostics;\n context?: C;\n }\n // Timeout event\n | {\n type: \"step_timeout\";\n workflowId: string;\n workflowName?: string;\n stepId: string;\n stepKey?: string;\n name?: string;\n ts: number;\n timeoutMs: number;\n attempt?: number;\n metadata?: StepMetadata;\n diagnostics?: StepErrorDiagnostics;\n context?: C;\n }\n // Hook events\n | {\n type: \"hook_should_run\";\n workflowId: string;\n workflowName?: string;\n ts: number;\n durationMs: number;\n result: boolean;\n skipped: boolean;\n context?: C;\n }\n | {\n type: \"hook_should_run_error\";\n workflowId: string;\n workflowName?: string;\n ts: number;\n durationMs: number;\n error: E;\n context?: C;\n }\n | {\n type: \"hook_before_start\";\n workflowId: string;\n workflowName?: string;\n ts: number;\n durationMs: number;\n result: boolean;\n skipped: boolean;\n context?: C;\n }\n | {\n type: \"hook_before_start_error\";\n workflowId: string;\n workflowName?: string;\n ts: number;\n durationMs: number;\n error: E;\n context?: C;\n }\n | {\n type: \"hook_after_step\";\n workflowId: string;\n workflowName?: string;\n stepKey: string;\n ts: number;\n durationMs: number;\n context?: C;\n }\n | {\n type: \"hook_after_step_error\";\n workflowId: string;\n workflowName?: string;\n stepKey: string;\n ts: number;\n durationMs: number;\n error: E;\n context?: C;\n }\n // Stream events\n | {\n type: \"stream_created\";\n workflowId: string;\n workflowName?: string;\n namespace: string;\n ts: number;\n context?: C;\n }\n | {\n type: \"stream_write\";\n workflowId: string;\n workflowName?: string;\n namespace: string;\n position: number;\n ts: number;\n context?: C;\n }\n | {\n type: \"stream_read\";\n workflowId: string;\n workflowName?: string;\n namespace: string;\n position: number;\n ts: number;\n context?: C;\n }\n | {\n type: \"stream_close\";\n workflowId: string;\n workflowName?: string;\n namespace: string;\n finalPosition: number;\n ts: number;\n context?: C;\n }\n | {\n type: \"stream_error\";\n workflowId: string;\n workflowName?: string;\n namespace: string;\n error: unknown;\n position: number;\n ts: number;\n context?: C;\n }\n | {\n type: \"stream_backpressure\";\n workflowId: string;\n workflowName?: string;\n namespace: string;\n bufferedCount: number;\n state: \"paused\" | \"flowing\";\n ts: number;\n context?: C;\n }\n // Workflow cancellation event\n | {\n type: \"workflow_cancelled\";\n workflowId: string;\n workflowName?: string;\n ts: number;\n durationMs: number;\n /** Reason from AbortSignal.reason (if provided) */\n reason?: string;\n /** Last successfully completed keyed step before cancellation (for resume purposes) */\n lastStepKey?: string;\n context?: C;\n };\n\n// =============================================================================\n// Run Options\n// =============================================================================\n\nexport type RunOptionsWithCatch<E, C = void> = {\n /**\n * Handler for expected errors.\n * Called when a step fails with a known error type.\n */\n onError?: (error: E, stepName?: string, ctx?: C) => void;\n /**\n * Listener for workflow events (start, success, error, step events).\n * Use this for logging, telemetry, or debugging.\n *\n * Context is automatically included in `event.context` when provided via the `context` option.\n * The separate `ctx` parameter is provided for convenience.\n */\n onEvent?: (event: WorkflowEvent<E | UnexpectedError, C>, ctx: C) => void;\n /**\n * Catch-all mapper for unexpected exceptions.\n * Converts unknown exceptions (and cancellation) into your typed error union E.\n */\n catchUnexpected: (cause: unknown) => E;\n /**\n * Unique ID for this workflow execution.\n * Defaults to a random UUID.\n * Useful for correlating logs across distributed systems.\n */\n workflowId?: string;\n /**\n * Human-readable workflow name included on emitted events.\n * Useful for observability and visualization.\n */\n workflowName?: string;\n /**\n * Arbitrary context object passed to onEvent and onError.\n * Useful for passing request IDs, user IDs, or loggers.\n */\n context?: C;\n /**\n * @internal External signal for workflow-level cancellation.\n * Used by createWorkflow() to pass the workflow signal to steps.\n */\n _workflowSignal?: AbortSignal;\n};\n\nexport type RunOptionsWithoutCatch<E, C = void> = {\n /**\n * Handler for expected errors AND unexpected errors.\n * Unexpected errors will be wrapped in `UnexpectedError`.\n */\n onError?: (error: E | UnexpectedError, stepName?: string, ctx?: C) => void;\n /**\n * Listener for workflow events (start, success, error, step events).\n *\n * Note: Context is available both on `event.context` and as the separate `ctx` parameter.\n * The `ctx` parameter is provided for convenience and backward compatibility.\n */\n onEvent?: (event: WorkflowEvent<E | UnexpectedError, C>, ctx: C) => void;\n catchUnexpected?: undefined;\n workflowId?: string;\n /**\n * Human-readable workflow name included on emitted events.\n * Useful for observability and visualization.\n */\n workflowName?: string;\n context?: C;\n /**\n * @internal External signal for workflow-level cancellation.\n * Used by createWorkflow() to pass the workflow signal to steps.\n */\n _workflowSignal?: AbortSignal;\n};\n\nexport type RunOptions<E, C = void> = RunOptionsWithCatch<E, C> | RunOptionsWithoutCatch<E, C>;\n\n// =============================================================================\n// Early Exit Mechanism (exported for caching layer)\n// =============================================================================\n\n/**\n * Symbol used to identify early exit throws.\n * Exported for the caching layer in workflow.ts.\n * @internal\n */\nexport const EARLY_EXIT_SYMBOL: unique symbol = Symbol(\"early-exit\");\n\n/**\n * Metadata about how a step failed.\n * @internal\n */\nexport type StepFailureMeta =\n | { origin: \"result\"; resultCause?: unknown }\n | { origin: \"throw\"; thrown: unknown }\n | { origin: \"fallback\"; fallbackUsed: true; fallbackReason: string };\n\n/**\n * Early exit object thrown to short-circuit workflow execution.\n * @internal\n */\nexport type EarlyExit<E> = {\n [EARLY_EXIT_SYMBOL]: true;\n error: E;\n meta: StepFailureMeta;\n};\n\n/**\n * Create an early exit throw object.\n * Used by the caching layer to synthesize early exits for cached errors.\n * @internal\n */\nexport function createEarlyExit<E>(error: E, meta: StepFailureMeta): EarlyExit<E> {\n return {\n [EARLY_EXIT_SYMBOL]: true,\n error,\n meta,\n };\n}\n\n/**\n * Type guard for early exit objects.\n * @internal\n */\nexport function isEarlyExit<E>(e: unknown): e is EarlyExit<E> {\n return (\n typeof e === \"object\" &&\n e !== null &&\n (e as Record<PropertyKey, unknown>)[EARLY_EXIT_SYMBOL] === true\n );\n}\n\n/**\n * Symbol to mark exceptions thrown by catchUnexpected mappers.\n * These should propagate without being re-processed.\n * @internal\n */\nconst MAPPER_EXCEPTION_SYMBOL: unique symbol = Symbol(\"mapper-exception\");\n\ntype MapperException = {\n [MAPPER_EXCEPTION_SYMBOL]: true;\n thrown: unknown;\n};\n\nfunction createMapperException(thrown: unknown): MapperException {\n return { [MAPPER_EXCEPTION_SYMBOL]: true, thrown };\n}\n\nfunction isMapperException(e: unknown): e is MapperException {\n return (\n typeof e === \"object\" &&\n e !== null &&\n (e as Record<PropertyKey, unknown>)[MAPPER_EXCEPTION_SYMBOL] === true\n );\n}\n\n// =============================================================================\n// Retry and Timeout Utilities\n// =============================================================================\n\n/**\n * Calculate the delay for a retry attempt based on the backoff strategy.\n * @internal\n */\nfunction calculateRetryDelay(\n attempt: number,\n options: {\n backoff: BackoffStrategy;\n initialDelay: number;\n maxDelay: number;\n jitter: boolean;\n }\n): number {\n const { backoff, initialDelay, maxDelay, jitter } = options;\n\n let delay: number;\n\n switch (backoff) {\n case \"fixed\":\n delay = initialDelay;\n break;\n case \"linear\":\n delay = initialDelay * attempt;\n break;\n case \"exponential\":\n delay = initialDelay * Math.pow(2, attempt - 1);\n break;\n }\n\n // Apply max cap\n delay = Math.min(delay, maxDelay);\n\n // Apply jitter (0-25% of delay)\n if (jitter) {\n const jitterAmount = delay * 0.25 * Math.random();\n delay = delay + jitterAmount;\n }\n\n return Math.floor(delay);\n}\n\n/**\n * Sleep for a specified number of milliseconds.\n * @internal\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nconst DEFAULT_RETRY_ASYNC_CONFIG = {\n backoff: \"exponential\" as BackoffStrategy,\n initialDelay: 100,\n maxDelay: 30000,\n jitter: true,\n retryOn: (_error: unknown, _attempt: number) => true,\n onRetry: (_error: unknown, _attempt: number, _delayMs: number) => {},\n} as const;\n\n/**\n * Run an async function with retry. Reuses the same backoff and retryOn semantics as step.retry.\n * Use this when you want retries without the workflow/step machinery (e.g. in fetch).\n *\n * @param fn - Function that returns a Promise<Result<T, E>>\n * @param options - Retry configuration (attempts, backoff, retryOn, etc.)\n * @returns Promise that resolves to the last Result (ok or err). Rejects only if fn throws and retryOn returns false.\n */\nexport async function retryAsync<T, E>(\n fn: () => Promise<Result<T, E>>,\n options: RetryOptions\n): Promise<Result<T, E>> {\n const attempts = Math.max(1, options.attempts);\n const effective = {\n backoff: options.backoff ?? DEFAULT_RETRY_ASYNC_CONFIG.backoff,\n initialDelay: options.initialDelay ?? DEFAULT_RETRY_ASYNC_CONFIG.initialDelay,\n maxDelay: options.maxDelay ?? DEFAULT_RETRY_ASYNC_CONFIG.maxDelay,\n jitter: options.jitter ?? DEFAULT_RETRY_ASYNC_CONFIG.jitter,\n retryOn: options.retryOn ?? DEFAULT_RETRY_ASYNC_CONFIG.retryOn,\n onRetry: options.onRetry ?? DEFAULT_RETRY_ASYNC_CONFIG.onRetry,\n };\n\n let lastResult: Result<T, E> | undefined;\n for (let attempt = 1; attempt <= attempts; attempt++) {\n try {\n const result = await fn();\n if (result.ok) return result;\n lastResult = result;\n if (attempt < attempts && effective.retryOn(result.error, attempt)) {\n const delay = calculateRetryDelay(attempt, effective);\n effective.onRetry(result.error, attempt, delay);\n await sleep(delay);\n continue;\n }\n return result;\n } catch (thrown) {\n if (attempt < attempts && effective.retryOn(thrown, attempt)) {\n const delay = calculateRetryDelay(attempt, effective);\n effective.onRetry(thrown, attempt, delay);\n await sleep(delay);\n continue;\n }\n throw thrown;\n }\n }\n return lastResult!;\n}\n\n/**\n * Symbol used internally to identify timeout rejection.\n */\nconst TIMEOUT_SYMBOL: unique symbol = Symbol(\"timeout\");\nconst TIMEOUT_OPTION_SYMBOL: unique symbol = Symbol(\"timeout-option\");\n\n/**\n * Check if an error is a timeout option marker (should return undefined instead of error).\n * @internal\n */\nfunction isTimeoutOptionMarker(\n value: unknown\n): value is { [TIMEOUT_OPTION_SYMBOL]: true; ms: number } {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as Record<symbol, unknown>)[TIMEOUT_OPTION_SYMBOL] === true\n );\n}\n\n/**\n * Execute an operation with a timeout using Promise.race.\n * @internal\n */\nasync function executeWithTimeout<T>(\n operation: (() => Promise<T>) | ((signal: AbortSignal) => Promise<T>),\n options: TimeoutOptions,\n stepInfo: { name?: string; key?: string; attempt?: number },\n /** External signal (e.g., workflow cancellation) to combine with timeout signal */\n externalSignal?: AbortSignal\n): Promise<T> {\n const controller = new AbortController();\n const behavior = options.onTimeout ?? \"error\";\n\n // Create the timeout error based on behavior\n const createTimeoutError = (): unknown => {\n // For function behavior, call the handler to generate the error\n if (typeof behavior === \"function\") {\n return behavior({\n name: stepInfo.name,\n key: stepInfo.key,\n ms: options.ms,\n });\n }\n\n // For other behaviors, use custom error or default StepTimeoutError\n return (\n (options.error as StepTimeoutError) ?? {\n type: \"STEP_TIMEOUT\",\n stepName: stepInfo.name,\n stepKey: stepInfo.key,\n timeoutMs: options.ms,\n attempt: stepInfo.attempt,\n }\n );\n };\n\n // Track the timeout ID for cleanup\n let timeoutId: ReturnType<typeof setTimeout>;\n\n // If external signal is already aborted, abort immediately\n if (externalSignal?.aborted) {\n controller.abort(externalSignal.reason);\n }\n\n // Forward external signal abort to internal controller\n let externalAbortHandler: (() => void) | undefined;\n if (externalSignal && !externalSignal.aborted) {\n externalAbortHandler = () => controller.abort(externalSignal.reason);\n externalSignal.addEventListener(\"abort\", externalAbortHandler, { once: true });\n }\n\n // Create a timeout promise that rejects after the specified duration\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n // For 'disconnect', don't abort - let operation continue in background\n if (behavior !== \"disconnect\") {\n controller.abort();\n }\n\n // For 'option', throw special marker to return undefined\n if (behavior === \"option\") {\n reject({ [TIMEOUT_OPTION_SYMBOL]: true, ms: options.ms });\n return;\n }\n\n // For all other behaviors, throw the timeout error\n reject({ [TIMEOUT_SYMBOL]: true, error: createTimeoutError() });\n }, options.ms);\n });\n\n // Execute the operation\n let operationPromise: Promise<T>;\n if (options.signal) {\n // Operation expects an AbortSignal\n // Pass the internal controller's signal which is linked to both timeout and external signal\n operationPromise = Promise.resolve(\n (operation as (signal: AbortSignal) => Promise<T>)(controller.signal)\n );\n } else {\n // Standard operation\n operationPromise = Promise.resolve((operation as () => Promise<T>)());\n }\n\n try {\n // Race between operation and timeout\n const result = await Promise.race([operationPromise, timeoutPromise]);\n return result;\n } catch (error) {\n // Check if this was an 'option' timeout - return undefined as success\n if (\n typeof error === \"object\" &&\n error !== null &&\n (error as Record<symbol, unknown>)[TIMEOUT_OPTION_SYMBOL] === true\n ) {\n // Throw special marker that step handler will convert to ok(undefined)\n throw { [TIMEOUT_OPTION_SYMBOL]: true, ms: options.ms };\n }\n\n // Check if this was our timeout\n if (\n typeof error === \"object\" &&\n error !== null &&\n (error as Record<symbol, unknown>)[TIMEOUT_SYMBOL] === true\n ) {\n // For 'disconnect' behavior, the operation continues in the background\n // Attach a catch handler to prevent unhandled rejection if it fails later\n if (behavior === \"disconnect\") {\n operationPromise.catch(() => {\n // Intentionally swallowed - operation was disconnected\n });\n }\n\n const errorToThrow = (error as { error: unknown }).error;\n\n // Mark the error with STEP_TIMEOUT_MARKER if it's a custom error (not already a StepTimeoutError)\n // This allows isStepTimeoutError() and getStepTimeoutMeta() to work with custom errors\n // Note: Always update metadata to reflect the current attempt (same error may be reused across retries)\n if (\n typeof errorToThrow === \"object\" &&\n errorToThrow !== null &&\n (errorToThrow as StepTimeoutError).type !== \"STEP_TIMEOUT\"\n ) {\n const meta: StepTimeoutMarkerMeta = {\n timeoutMs: options.ms,\n stepName: stepInfo.name,\n stepKey: stepInfo.key,\n attempt: stepInfo.attempt,\n };\n\n if (STEP_TIMEOUT_MARKER in errorToThrow) {\n // Update existing marker with current attempt's metadata\n (errorToThrow as Record<symbol, StepTimeoutMarkerMeta>)[STEP_TIMEOUT_MARKER] = meta;\n } else {\n // Define new marker (writable so it can be updated on retry)\n Object.defineProperty(errorToThrow, STEP_TIMEOUT_MARKER, {\n value: meta,\n enumerable: false,\n writable: true,\n configurable: false,\n });\n }\n }\n\n throw errorToThrow;\n }\n // Re-throw other errors\n throw error;\n } finally {\n // Always clear the timeout to prevent leaks\n clearTimeout(timeoutId!);\n // Clean up external signal listener\n if (externalAbortHandler && externalSignal) {\n externalSignal.removeEventListener(\"abort\", externalAbortHandler);\n }\n }\n}\n\n/**\n * Default retry configuration values.\n * @internal\n */\nconst DEFAULT_RETRY_CONFIG = {\n backoff: \"exponential\" as BackoffStrategy,\n initialDelay: 100,\n maxDelay: 30000,\n jitter: true,\n retryOn: () => true,\n onRetry: () => {},\n} as const;\n\n// =============================================================================\n// run() Function\n// =============================================================================\n\n/**\n * Execute a workflow with step-based error handling.\n *\n * ## When to Use run()\n *\n * Use `run()` when:\n * - Dependencies are dynamic (passed at runtime, not known at compile time)\n * - You don't need step caching or resume state\n * - Error types are known upfront and can be specified manually\n * - Building lightweight, one-off workflows\n *\n * For automatic error type inference from static dependencies, use `createWorkflow()`.\n *\n * ## Error union\n *\n * `run()` returns:\n * - **`catchUnexpected`**: Maps uncaught exceptions to your type E → `Result<T, E>`\n * - **No catchUnexpected**: Step errors pass through + `UnexpectedError` for exceptions → `Result<T, E | UnexpectedError>`\n *\n * When `E` is not specified, it defaults to `never`, giving `Result<T, UnexpectedError>`.\n *\n * @see createWorkflow - For static dependencies with auto error inference\n */\n\n/**\n * run() with catchUnexpected: closed union Result<T, E>.\n */\nexport function run<T, E, C = void>(\n fn: (context: { step: RunStep<E> }) => Promise<T> | T,\n options: RunOptionsWithCatch<E, C>\n): AsyncResult<T, E, unknown>;\n\n/**\n * run() without catchUnexpected.\n * Always adds UnexpectedError to the error union so callers know\n * uncaught exceptions are possible. Step errors pass through as-is.\n * When E is never (default), step is RunStep<unknown> so any operation is allowed.\n */\nexport function run<T, E = never, C = void>(\n fn: (context: {\n step: [E] extends [never] ? RunStep<unknown> : RunStep<E>;\n }) => Promise<T> | T,\n options?: {\n onError?: (error: E | UnexpectedError, stepName?: string, ctx?: C) => void;\n onEvent?: (event: WorkflowEvent<E | UnexpectedError, C>, ctx: C) => void;\n workflowId?: string;\n workflowName?: string;\n context?: C;\n /** @internal External signal for workflow-level cancellation. */\n _workflowSignal?: AbortSignal;\n }\n): AsyncResult<T, E | UnexpectedError, unknown>;\n\n// Implementation\nexport async function run<T, E, C = void>(\n fn: (context: { step: RunStep<E> }) => Promise<T> | T,\n options?: RunOptions<E, C>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): AsyncResult<T, any> {\n const {\n onError,\n onEvent,\n catchUnexpected,\n workflowId: providedWorkflowId,\n workflowName,\n context,\n _workflowSignal,\n } = options && typeof options === \"object\"\n ? (options as RunOptions<E, C>)\n : ({} as RunOptions<E, C>);\n\n const workflowId = providedWorkflowId ?? crypto.randomUUID();\n const effectiveCatchUnexpected = catchUnexpected ?? defaultCatchUnexpected;\n\n // Track active scopes as a stack for proper nesting\n // When a step succeeds, only the innermost race scope gets the winner\n const activeScopeStack: Array<{ scopeId: string; type: ScopeType; winnerId?: string }> = [];\n\n // Counter for generating unique step IDs\n let stepIdCounter = 0;\n\n // Generate a unique step ID\n // Uses stepKey when provided (for cache stability), otherwise generates a unique ID.\n // Note: name is NOT used for stepId because multiple concurrent steps may share a name,\n // which would cause them to collide in activeSteps tracking and race winner detection.\n const generateStepId = (stepKey?: string): string => {\n return stepKey ?? `step_${++stepIdCounter}`;\n };\n\n const emitEvent = (event: WorkflowEvent<E | UnexpectedError, C>) => {\n // Add context to event only if:\n // 1. Event doesn't already have context (preserves replayed events or per-step overrides)\n // 2. Workflow actually has a context (don't add context: undefined property)\n const eventWithContext =\n event.context !== undefined || context === undefined\n ? event\n : ({ ...event, context: context as C } as WorkflowEvent<E | UnexpectedError, C>);\n\n const eventWithName =\n workflowName !== undefined && eventWithContext.workflowName === undefined\n ? ({ ...eventWithContext, workflowName } as WorkflowEvent<E | UnexpectedError, C>)\n : eventWithContext;\n \n // Track first successful step in the innermost race scope for winnerId\n if (eventWithName.type === \"step_success\") {\n // Use the stepId from the event (already generated at step start)\n const stepId = eventWithName.stepId;\n\n // Find innermost race scope (search from end of stack)\n for (let i = activeScopeStack.length - 1; i >= 0; i--) {\n const scope = activeScopeStack[i];\n if (scope.type === \"race\" && !scope.winnerId) {\n scope.winnerId = stepId;\n break; // Only update innermost race scope\n }\n }\n }\n onEvent?.(eventWithName, context as C);\n };\n\n // Use the exported early exit function with proper type parameter\n const earlyExit = createEarlyExit<E>;\n\n // Local type guard that narrows to EarlyExit<E> specifically\n const isEarlyExitE = (e: unknown): e is EarlyExit<E> => isEarlyExit(e);\n\n // Step errors always pass through — they are typed Result errors.\n // Only truly uncaught exceptions get mapped via effectiveCatchUnexpected.\n const wrapForStep = (\n error: unknown,\n _meta?: StepFailureMeta\n ): E => {\n return error as E;\n };\n\n // Helper to check if a value is a Result (has ok property) vs a function\n const isResultLike = (value: unknown): value is Result<unknown, unknown, unknown> | Promise<Result<unknown, unknown, unknown>> => {\n if (typeof value === 'function') return false;\n if (value && typeof value === 'object' && 'ok' in value) return true;\n // Check for Promise<Result> - it will have a then method\n if (value && typeof value === 'object' && 'then' in value && typeof (value as Promise<unknown>).then === 'function') return true;\n return false;\n };\n\n try {\n // Step function: requires step('id', fn, opts) or step('id', result, opts)\n const stepFn = <T, StepE, StepC = unknown>(\n id: string,\n operationOrResult: (() => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>) | Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n stepOptions?: StepOptions\n ): Promise<T> => {\n return (async () => {\n // Validate required string ID\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step() requires an explicit string ID as the first argument. ' +\n 'Example: step(\"fetchUser\", () => fetchUser(id))'\n );\n }\n\n const parsedOptions: StepOptions = stepOptions ?? {};\n const stepMetadata = extractStepMetadata(parsedOptions);\n\n // Name is always derived from ID\n const stepName = id;\n const stepKey = parsedOptions.key ?? id; // For general events (step_start, step_success, etc.)\n const explicitKey = parsedOptions.key ?? id; // For step_complete and caching (ID is used when no key)\n const { description: stepDescription, retry: retryConfig, timeout: timeoutConfig } = parsedOptions;\n const stepId = generateStepId(stepKey);\n const hasEventListeners = onEvent;\n const overallStartTime = hasEventListeners ? performance.now() : 0;\n\n // Determine if this is a direct Result or a function\n const isDirectResult = isResultLike(operationOrResult);\n const operation = isDirectResult\n ? () => operationOrResult as Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>\n : operationOrResult as () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>;\n\n // Build effective retry config with defaults\n // Ensure at least 1 attempt (0 would skip the loop entirely and crash)\n const maxAttempts = Math.max(1, retryConfig?.attempts ?? 1);\n const effectiveRetry = {\n attempts: maxAttempts,\n backoff: retryConfig?.backoff ?? DEFAULT_RETRY_CONFIG.backoff,\n initialDelay: retryConfig?.initialDelay ?? DEFAULT_RETRY_CONFIG.initialDelay,\n maxDelay: retryConfig?.maxDelay ?? DEFAULT_RETRY_CONFIG.maxDelay,\n jitter: retryConfig?.jitter ?? DEFAULT_RETRY_CONFIG.jitter,\n retryOn: retryConfig?.retryOn ?? DEFAULT_RETRY_CONFIG.retryOn,\n onRetry: retryConfig?.onRetry ?? DEFAULT_RETRY_CONFIG.onRetry,\n };\n\n // Emit step_start only once (before first attempt)\n if (onEvent) {\n emitEvent({\n type: \"step_start\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n\n let lastResult: Result<T, StepE, StepC> | undefined;\n\n for (let attempt = 1; attempt <= effectiveRetry.attempts; attempt++) {\n const attemptStartTime = hasEventListeners ? performance.now() : 0;\n\n try {\n // Execute operation with optional timeout\n let result: Result<T, StepE, StepC>;\n\n if (timeoutConfig) {\n // Wrap with timeout, passing workflow signal for { signal: true } steps\n result = await executeWithTimeout(\n operation as () => Promise<Result<T, StepE, StepC>>,\n timeoutConfig,\n { name: stepName, key: stepKey, attempt },\n _workflowSignal\n );\n } else {\n result = await operation();\n }\n\n // Success case\n if (result.ok) {\n const durationMs = performance.now() - overallStartTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs,\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n if (explicitKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey: explicitKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs,\n result,\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n return result.value;\n }\n\n // Result error case - check if we should retry\n lastResult = result;\n\n if (attempt < effectiveRetry.attempts && effectiveRetry.retryOn(result.error, attempt)) {\n const delay = calculateRetryDelay(attempt, effectiveRetry);\n\n // Emit retry event\n emitEvent({\n type: \"step_retry\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n attempt: attempt + 1,\n maxAttempts: effectiveRetry.attempts,\n delayMs: delay,\n error: result.error as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(result.error, parsedOptions.errorMeta, 'result', attempt, performance.now() - overallStartTime),\n });\n\n effectiveRetry.onRetry(result.error, attempt, delay);\n await sleep(delay);\n continue;\n }\n\n // No more retries or retryOn returned false - emit exhausted event if we retried\n if (effectiveRetry.attempts > 1) {\n emitEvent({\n type: \"step_retries_exhausted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - overallStartTime,\n attempts: attempt,\n lastError: result.error as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(result.error, parsedOptions.errorMeta, 'result', attempt, performance.now() - overallStartTime),\n });\n }\n\n // Fall through to final error handling below\n break;\n\n } catch (thrown) {\n const durationMs = performance.now() - attemptStartTime;\n\n // Handle timeout with 'option' behavior - return undefined as success\n if (isTimeoutOptionMarker(thrown)) {\n const timeoutMs = thrown.ms;\n emitEvent({\n type: \"step_timeout\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n timeoutMs,\n attempt,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'timeout', attempt),\n });\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: performance.now() - overallStartTime,\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n if (explicitKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey: explicitKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: performance.now() - overallStartTime,\n result: ok(undefined),\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n // Return undefined as success value (timeout was treated as optional)\n return undefined as T;\n }\n\n // Handle early exit - propagate immediately\n if (isEarlyExitE(thrown)) {\n emitEvent({\n type: \"step_aborted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs,\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n throw thrown;\n }\n\n // Handle timeout error\n if (isStepTimeoutError(thrown)) {\n // Get timeout metadata from the error (works for both standard and custom errors)\n const timeoutMeta = getStepTimeoutMeta(thrown);\n const timeoutMs = timeoutConfig?.ms ?? timeoutMeta?.timeoutMs ?? 0;\n emitEvent({\n type: \"step_timeout\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n timeoutMs,\n attempt,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'timeout', attempt),\n });\n\n // Check if we should retry after timeout\n if (attempt < effectiveRetry.attempts && effectiveRetry.retryOn(thrown, attempt)) {\n const delay = calculateRetryDelay(attempt, effectiveRetry);\n\n emitEvent({\n type: \"step_retry\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n attempt: attempt + 1,\n maxAttempts: effectiveRetry.attempts,\n delayMs: delay,\n error: thrown as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'timeout', attempt, performance.now() - overallStartTime),\n });\n\n effectiveRetry.onRetry(thrown, attempt, delay);\n await sleep(delay);\n continue;\n }\n\n // No more retries - emit exhausted if we retried\n if (effectiveRetry.attempts > 1) {\n emitEvent({\n type: \"step_retries_exhausted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - overallStartTime,\n attempts: attempt,\n lastError: thrown as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'timeout', attempt, performance.now() - overallStartTime),\n });\n }\n\n // Treat STEP_TIMEOUT as a typed error - exit directly without UnexpectedError wrapper\n // This provides better DX: users get STEP_TIMEOUT directly in result.error\n const totalDurationMs = performance.now() - overallStartTime;\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: totalDurationMs,\n error: thrown as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'timeout', attempt, totalDurationMs),\n });\n if (explicitKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey: explicitKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: totalDurationMs,\n result: err(thrown as unknown as E, { cause: thrown }),\n meta: { origin: \"throw\", thrown },\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n onError?.(thrown as unknown as E, stepName, context);\n throw earlyExit(thrown as unknown as E, { origin: \"throw\", thrown });\n }\n\n // Handle other thrown errors (continue to error handling below)\n\n // Check if we should retry thrown errors\n if (attempt < effectiveRetry.attempts && effectiveRetry.retryOn(thrown, attempt)) {\n const delay = calculateRetryDelay(attempt, effectiveRetry);\n\n emitEvent({\n type: \"step_retry\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n attempt: attempt + 1,\n maxAttempts: effectiveRetry.attempts,\n delayMs: delay,\n error: thrown as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'throw', attempt, performance.now() - overallStartTime),\n });\n\n effectiveRetry.onRetry(thrown, attempt, delay);\n await sleep(delay);\n continue;\n }\n\n // No more retries for thrown errors - emit exhausted if we retried\n if (effectiveRetry.attempts > 1 && !isStepTimeoutError(thrown)) {\n emitEvent({\n type: \"step_retries_exhausted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - overallStartTime,\n attempts: attempt,\n lastError: thrown as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'throw', attempt, performance.now() - overallStartTime),\n });\n }\n\n // Handle the error using effectiveCatchUnexpected\n const totalDurationMs = performance.now() - overallStartTime;\n\n let mappedError: E | UnexpectedError;\n try {\n mappedError = effectiveCatchUnexpected(thrown) as E | UnexpectedError;\n } catch (mapperError) {\n throw createMapperException(mapperError);\n }\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: totalDurationMs,\n error: mappedError,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'throw', attempt, totalDurationMs),\n });\n if (explicitKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey: explicitKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: totalDurationMs,\n result: err(mappedError, { cause: thrown }),\n meta: { origin: \"throw\", thrown },\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n onError?.(mappedError as E, stepName, context);\n throw earlyExit(mappedError as E, { origin: \"throw\", thrown });\n }\n }\n\n // All retries exhausted with Result error - handle final error\n // At this point lastResult must be an error result (we only reach here on error)\n const errorResult = lastResult as Err<StepE, StepC>;\n const totalDurationMs = performance.now() - overallStartTime;\n const wrappedError = wrapForStep(errorResult.error, {\n origin: \"result\",\n resultCause: errorResult.cause,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: totalDurationMs,\n error: wrappedError,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(errorResult.error, parsedOptions.errorMeta, 'result', effectiveRetry.attempts, totalDurationMs),\n });\n if (explicitKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey: explicitKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: totalDurationMs,\n result: errorResult,\n meta: { origin: \"result\", resultCause: errorResult.cause },\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: errorResult.cause,\n });\n })();\n };\n\n stepFn.try = <T, Err>(\n id: string,\n operation: () => T | Promise<T>,\n opts:\n | { error: Err; key?: string }\n | { onError: (cause: unknown) => Err; key?: string }\n ): Promise<T> => {\n // Validate required string ID\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.try() requires an explicit string ID as the first argument. ' +\n 'Example: step.try(\"parse\", () => JSON.parse(str), { error: \"PARSE_ERROR\" })'\n );\n }\n\n const stepKey = opts.key ?? id; // Use id as key if not provided\n const stepName = id; // Name is always the id\n const stepId = id;\n const mapToError = \"error\" in opts ? () => opts.error : opts.onError;\n const hasEventListeners = onEvent;\n\n return (async () => {\n const startTime = hasEventListeners ? performance.now() : 0;\n\n if (onEvent) {\n emitEvent({\n type: \"step_start\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n });\n }\n\n try {\n const value = await operation();\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n });\n // Emit step_complete for keyed steps (for state persistence)\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: ok(value),\n });\n }\n return value;\n } catch (error) {\n const mapped = mapToError(error);\n const durationMs = performance.now() - startTime;\n const wrappedError = wrapForStep(mapped, { origin: \"throw\", thrown: error });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n // Emit step_complete for keyed steps (for state persistence)\n // Note: For step.try errors, we encode the mapped error, not the original thrown\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(mapped, { cause: error }),\n meta: { origin: \"throw\", thrown: error },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, { origin: \"throw\", thrown: error });\n }\n })();\n };\n\n // step.fromResult: Execute a Result-returning function and map its typed error\n stepFn.fromResult = <T, ResultE, Err>(\n id: string,\n operation: () => Result<T, ResultE, unknown> | AsyncResult<T, ResultE, unknown>,\n opts:\n | { error: Err; key?: string }\n | { onError: (resultError: ResultE) => Err; key?: string }\n ): Promise<T> => {\n // Validate required string ID\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.fromResult() requires an explicit string ID as the first argument. ' +\n 'Example: step.fromResult(\"callProvider\", () => callProvider(input), { onError: (e) => ({ type: \"FAILED\" }) })'\n );\n }\n\n const stepKey = opts.key ?? id; // Use id as key if not provided\n const stepName = id; // Name is always the id\n const stepId = id;\n const mapToError = \"error\" in opts ? () => opts.error : opts.onError;\n const hasEventListeners = onEvent;\n\n return (async () => {\n const startTime = hasEventListeners ? performance.now() : 0;\n\n if (onEvent) {\n emitEvent({\n type: \"step_start\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n });\n }\n\n const result = await operation();\n\n if (result.ok) {\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n });\n // Emit step_complete for keyed steps (for state persistence)\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: ok(result.value),\n });\n }\n return result.value;\n } else {\n const mapped = mapToError(result.error);\n const durationMs = performance.now() - startTime;\n // For fromResult, the cause is the original result.error (what got mapped)\n // This is analogous to step.try using thrown exception as cause\n const wrappedError = wrapForStep(mapped, {\n origin: \"result\",\n resultCause: result.error,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n // Emit step_complete for keyed steps (for state persistence)\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(mapped, { cause: result.error }),\n meta: { origin: \"result\", resultCause: result.error },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: result.error,\n });\n }\n })();\n };\n\n // step.fromNullable: Execute an operation returning T | null/undefined and convert to typed error\n stepFn.fromNullable = <T, Err>(\n id: string,\n operation: () => T | null | undefined | Promise<T | null | undefined>,\n onNull: () => Err,\n options?: { key?: string; ttl?: number }\n ): Promise<T> => {\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.fromNullable() requires an explicit string ID as the first argument. ' +\n 'Example: step.fromNullable(\"getUser\", () => db.find(id), () => ({ type: \"NOT_FOUND\" }))'\n );\n }\n return stepFn(\n id,\n async () => {\n const value = await operation();\n return value != null ? ok(value) : err(onNull());\n },\n options\n );\n };\n\n // step.retry: Execute an operation with retry and optional timeout\n stepFn.retry = <T, StepE, StepC = unknown>(\n id: string,\n operation: () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n options: RetryOptions & { key?: string; timeout?: TimeoutOptions }\n ): Promise<T> => {\n // Validate required string ID\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.retry() requires an explicit string ID as the first argument. ' +\n 'Example: step.retry(\"fetchData\", () => fetchData(), { attempts: 3 })'\n );\n }\n\n // Delegate to stepFn with retry options merged into StepOptions\n // Use key for caching if provided, otherwise use id\n return stepFn(id, operation, {\n key: options.key ?? id,\n retry: {\n attempts: options.attempts,\n backoff: options.backoff,\n initialDelay: options.initialDelay,\n maxDelay: options.maxDelay,\n jitter: options.jitter,\n retryOn: options.retryOn,\n onRetry: options.onRetry,\n },\n timeout: options.timeout,\n });\n };\n\n // step.withTimeout: Execute an operation with a timeout\n stepFn.withTimeout = <T, StepE, StepC = unknown>(\n id: string,\n operation:\n | (() => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>)\n | ((signal: AbortSignal) => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>),\n options: TimeoutOptions & { key?: string }\n ): Promise<T> => {\n // Validate required string ID\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.withTimeout() requires an explicit string ID as the first argument. ' +\n 'Example: step.withTimeout(\"slowOp\", () => slowOp(), { ms: 5000 })'\n );\n }\n\n // Delegate to stepFn with timeout options\n // The signal handling happens in executeWithTimeout when timeout.signal is true\n // Use key for caching if provided, otherwise use id\n return stepFn(\n id,\n operation as () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n {\n key: options.key ?? id,\n timeout: options,\n }\n );\n };\n\n // step.sleep: Pause execution for a specified duration\n stepFn.sleep = (\n id: string,\n duration: DurationInput,\n options?: { key?: string; ttl?: number; description?: string; signal?: AbortSignal }\n ): Promise<void> => {\n // Validate required string ID\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.sleep() requires an explicit string ID as the first argument. ' +\n 'Example: step.sleep(\"delay\", \"5s\")'\n );\n }\n\n // Parse duration - inline to avoid importing duration module\n const d = typeof duration === \"string\" ? parseDurationString(duration) : duration;\n if (!d) {\n throw new Error(`step.sleep: invalid duration '${duration}'`);\n }\n const ms = d.millis;\n const userSignal = options?.signal;\n\n // Delegate to stepFn with a cancellation-aware sleep operation\n // Use key for caching if provided, otherwise use id\n return stepFn(\n id,\n async (): AsyncResult<void, never> => {\n // Check if already aborted (workflow or user signal)\n if (_workflowSignal?.aborted || userSignal?.aborted) {\n const e = new Error(\"Sleep aborted\");\n e.name = \"AbortError\";\n throw e;\n }\n\n return new Promise<Result<void, never>>((resolve, reject) => {\n // Using object to avoid prefer-const warning while allowing\n // onAbort to reference the timeout before it's assigned\n const state = { timeoutId: undefined as ReturnType<typeof setTimeout> | undefined };\n\n const onAbort = () => {\n if (state.timeoutId) clearTimeout(state.timeoutId);\n const e = new Error(\"Sleep aborted\");\n e.name = \"AbortError\";\n reject(e);\n };\n\n _workflowSignal?.addEventListener(\"abort\", onAbort, { once: true });\n userSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n state.timeoutId = setTimeout(() => {\n _workflowSignal?.removeEventListener(\"abort\", onAbort);\n userSignal?.removeEventListener(\"abort\", onAbort);\n resolve(ok(undefined));\n }, ms);\n });\n },\n {\n key: options?.key ?? id,\n description: options?.description,\n }\n );\n };\n\n // step.parallel: Execute parallel operations with scope events\n // 1. Object form: step.parallel(name, { key: fn | { fn, errors } })\n // 2. Array form: step.parallel(name, () => allAsync([...]))\n stepFn.parallel = ((...args: unknown[]): Promise<unknown> => {\n if (typeof args[0] !== \"string\") {\n throw new TypeError(\n \"step.parallel(name, ...): first argument must be a string (step name). Example: step.parallel('Fetch data', { user: () => fetchUser(), posts: () => fetchPosts() })\"\n );\n }\n const name = args[0] as string;\n const second = args[1];\n if (typeof second === \"function\") {\n return executeParallelArray(name, second as () => MaybeAsyncResult<unknown[], unknown, unknown>);\n }\n if (second && typeof second === \"object\" && !Array.isArray(second)) {\n const rawOperations = second as Record<string, (() => MaybeAsyncResult<unknown, unknown, unknown>) | ParallelOperationDescriptor<unknown, readonly string[]>>;\n const normalizedOperations = normalizeParallelOperations(rawOperations);\n return executeParallelNamed(normalizedOperations, { name });\n }\n throw new TypeError(\n \"step.parallel(name, ...): second argument must be a function (array form) or an object of operations (object form).\"\n );\n }) as RunStep<E>[\"parallel\"];\n\n function normalizeParallelOperations(\n rawOperations: Record<string, (() => MaybeAsyncResult<unknown, unknown, unknown>) | ParallelOperationDescriptor<unknown, readonly string[]>>\n ): Record<string, () => MaybeAsyncResult<unknown, unknown, unknown>> {\n const out: Record<string, () => MaybeAsyncResult<unknown, unknown, unknown>> = {};\n for (const [key, value] of Object.entries(rawOperations)) {\n if (typeof value === \"function\") {\n out[key] = value;\n } else if (value && typeof value === \"object\" && \"fn\" in value) {\n out[key] = value.fn;\n } else {\n throw new TypeError(`step.parallel: operation \"${key}\" must be a function or { fn, errors? } object`);\n }\n }\n return out;\n }\n\n // Array form implementation\n function executeParallelArray<T>(\n name: string,\n operation: () => MaybeAsyncResult<T[], unknown, unknown>\n ): Promise<T[]> {\n const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n\n return (async () => {\n const startTime = performance.now();\n let scopeEnded = false;\n\n // Push this scope onto the stack for proper nesting tracking\n activeScopeStack.push({ scopeId, type: \"parallel\" });\n\n // Helper to emit scope_end exactly once\n const emitScopeEnd = () => {\n if (scopeEnded) return;\n scopeEnded = true;\n // Pop this scope from the stack\n const idx = activeScopeStack.findIndex(s => s.scopeId === scopeId);\n if (idx !== -1) activeScopeStack.splice(idx, 1);\n emitEvent({\n type: \"scope_end\",\n workflowId,\n scopeId,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n };\n\n // Emit scope_start event\n emitEvent({\n type: \"scope_start\",\n workflowId,\n scopeId,\n scopeType: \"parallel\",\n name,\n ts: Date.now(),\n });\n\n try {\n const result = await operation();\n\n // Emit scope_end before processing result\n emitScopeEnd();\n\n if (!result.ok) {\n onError?.(result.error as unknown as E, name, context);\n throw earlyExit(result.error as unknown as E, {\n origin: \"result\",\n resultCause: result.cause,\n });\n }\n\n return result.value;\n } catch (error) {\n // Always emit scope_end in finally-like fashion\n emitScopeEnd();\n throw error;\n }\n })();\n }\n\n // Named object form implementation - execute each operation in parallel\n function executeParallelNamed<T extends Record<string, unknown>>(\n operations: Record<string, () => MaybeAsyncResult<unknown, unknown, unknown>>,\n options: { name?: string }\n ): Promise<T> {\n const keys = Object.keys(operations);\n const name = options.name ?? `Parallel(${keys.join(\", \")})`;\n const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n\n return (async () => {\n const startTime = performance.now();\n let scopeEnded = false;\n\n // Push this scope onto the stack for proper nesting tracking\n activeScopeStack.push({ scopeId, type: \"parallel\" });\n\n // Helper to emit scope_end exactly once\n const emitScopeEnd = () => {\n if (scopeEnded) return;\n scopeEnded = true;\n const idx = activeScopeStack.findIndex(s => s.scopeId === scopeId);\n if (idx !== -1) activeScopeStack.splice(idx, 1);\n emitEvent({\n type: \"scope_end\",\n workflowId,\n scopeId,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n };\n\n // Emit scope_start event with operation names in metadata\n emitEvent({\n type: \"scope_start\",\n workflowId,\n scopeId,\n scopeType: \"parallel\",\n name,\n ts: Date.now(),\n });\n\n try {\n // Execute all operations in parallel, fail-fast on first error\n const results = await new Promise<{ key: string; result: Result<unknown, unknown, unknown> }[]>((resolve) => {\n if (keys.length === 0) {\n resolve([]);\n return;\n }\n\n let settled = false;\n let pendingCount = keys.length;\n const resultArray: { key: string; result: Result<unknown, unknown, unknown> }[] = new Array(keys.length);\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n const index = i;\n\n Promise.resolve(operations[key]())\n .catch((reason) => err(\n { type: \"PROMISE_REJECTED\" as const, cause: reason },\n { cause: { type: \"PROMISE_REJECTION\" as const, reason } }\n ))\n .then((result) => {\n if (settled) return;\n\n // Fail-fast: if any operation fails, resolve immediately with just the failed entry\n if (!result.ok) {\n settled = true;\n resolve([{ key, result }]);\n return;\n }\n\n resultArray[index] = { key, result };\n pendingCount--;\n\n if (pendingCount === 0) {\n resolve(resultArray);\n }\n });\n }\n });\n\n // Emit scope_end before processing results\n emitScopeEnd();\n\n // Check for errors and build result object\n const output: Record<string, unknown> = {};\n for (const { key, result } of results) {\n if (!result.ok) {\n onError?.(result.error as unknown as E, key, context);\n throw earlyExit(result.error as unknown as E, {\n origin: \"result\",\n resultCause: result.cause,\n });\n }\n output[key] = result.value;\n }\n\n return output as T;\n } catch (error) {\n // Always emit scope_end in finally-like fashion\n emitScopeEnd();\n throw error;\n }\n })();\n }\n\n // step.race: Execute a race operation with scope events\n stepFn.race = <T, StepE, StepC>(\n name: string,\n operation: () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>\n ): Promise<T> => {\n const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n\n return (async () => {\n const startTime = performance.now();\n let scopeEnded = false;\n\n // Push this race scope onto the stack to track the first successful step as winner\n const scopeEntry = { scopeId, type: \"race\" as const, winnerId: undefined as string | undefined };\n activeScopeStack.push(scopeEntry);\n\n // Helper to emit scope_end exactly once, including winnerId\n const emitScopeEnd = () => {\n if (scopeEnded) return;\n scopeEnded = true;\n // Pop this scope from the stack\n const idx = activeScopeStack.findIndex(s => s.scopeId === scopeId);\n if (idx !== -1) activeScopeStack.splice(idx, 1);\n emitEvent({\n type: \"scope_end\",\n workflowId,\n scopeId,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n winnerId: scopeEntry.winnerId,\n });\n };\n\n // Emit scope_start event\n emitEvent({\n type: \"scope_start\",\n workflowId,\n scopeId,\n scopeType: \"race\",\n name,\n ts: Date.now(),\n });\n\n try {\n const result = await operation();\n\n // Emit scope_end before processing result\n emitScopeEnd();\n\n if (!result.ok) {\n onError?.(result.error as unknown as E, name, context);\n throw earlyExit(result.error as unknown as E, {\n origin: \"result\",\n resultCause: result.cause,\n });\n }\n\n return result.value;\n } catch (error) {\n // Always emit scope_end in finally-like fashion\n emitScopeEnd();\n throw error;\n }\n })();\n };\n\n // step.allSettled: Execute an allSettled operation with scope events\n stepFn.allSettled = <T, StepE, StepC>(\n name: string,\n operation: () => Result<T[], StepE, StepC> | AsyncResult<T[], StepE, StepC>\n ): Promise<T[]> => {\n const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n\n return (async () => {\n const startTime = performance.now();\n let scopeEnded = false;\n\n // Push this scope onto the stack for proper nesting tracking\n activeScopeStack.push({ scopeId, type: \"allSettled\" });\n\n // Helper to emit scope_end exactly once\n const emitScopeEnd = () => {\n if (scopeEnded) return;\n scopeEnded = true;\n // Pop this scope from the stack\n const idx = activeScopeStack.findIndex(s => s.scopeId === scopeId);\n if (idx !== -1) activeScopeStack.splice(idx, 1);\n emitEvent({\n type: \"scope_end\",\n workflowId,\n scopeId,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n };\n\n // Emit scope_start event\n emitEvent({\n type: \"scope_start\",\n workflowId,\n scopeId,\n scopeType: \"allSettled\",\n name,\n ts: Date.now(),\n });\n\n try {\n const result = await operation();\n\n // Emit scope_end before processing result\n emitScopeEnd();\n\n if (!result.ok) {\n onError?.(result.error as unknown as E, name, context);\n throw earlyExit(result.error as unknown as E, {\n origin: \"result\",\n resultCause: result.cause,\n });\n }\n\n return result.value;\n } catch (error) {\n // Always emit scope_end in finally-like fashion\n emitScopeEnd();\n throw error;\n }\n })();\n };\n\n // step.if: Mark a conditional for static analysis\n // Runtime: just executes the condition and returns the result\n // Analyzer: extracts the id and conditionLabel for DecisionNode\n stepFn.if = <T extends boolean>(\n _id: string,\n _conditionLabel: string,\n condition: () => T\n ): T => {\n return condition();\n };\n\n // step.label: Alias for step.if - mark a conditional for static analysis\n // Use step.label for strict mode when conditionals contain step calls\n stepFn.label = stepFn.if;\n\n // step.branch: Execute a branch with explicit metadata for static analysis\n // Runtime: evaluates condition and executes appropriate arm\n // Analyzer: extracts branch metadata (conditionLabel, per-arm errors, out)\n stepFn.branch = async <\n T,\n const ThenErrs extends readonly string[] = readonly [],\n const ElseErrs extends readonly string[] = readonly [],\n const Out extends string | undefined = undefined,\n >(\n _id: string,\n options: BranchOptions<T, ThenErrs, ElseErrs, Out>\n ): Promise<T> => {\n const { condition, then: thenFn, else: elseFn } = options;\n const conditionResult = condition();\n if (conditionResult) {\n return await thenFn();\n } else if (elseFn) {\n return await elseFn();\n }\n return undefined as T;\n };\n\n // step.arm: Create an arm definition for use with step.branch\n // Runtime: returns the arm definition unchanged\n // Analyzer: extracts arm metadata\n stepFn.arm = <T, const Errs extends readonly string[] = readonly []>(\n fn: () => T | Promise<T>,\n errors?: Errs\n ): ArmDefinition<T, Errs> => {\n return { fn, errors };\n };\n\n // step.forEach: Execute a forEach loop with static analysis support\n // Supports both simple (run) and complex (item) forms\n stepFn.forEach = async <T, R>(\n _id: string,\n items: Iterable<T> | AsyncIterable<T>,\n options: ForEachRunOptions<T, R, readonly string[]> | ForEachItemOptions<T, R>\n ): Promise<R[]> => {\n const results: R[] = [];\n const maxIterations = options.maxIterations;\n let index = 0;\n\n // Check if this is the run form or item form\n const isRunForm = 'run' in options;\n\n // Convert items to async iterable for uniform handling\n const asyncItems = Symbol.asyncIterator in (items as object)\n ? (items as AsyncIterable<T>)\n : (async function* () { yield* items as Iterable<T>; })();\n\n for await (const item of asyncItems) {\n if (maxIterations !== undefined && index >= maxIterations) {\n break;\n }\n\n let result: R;\n if (isRunForm) {\n const runOptions = options as ForEachRunOptions<T, R, readonly string[]>;\n result = await runOptions.run(item, index);\n } else {\n const itemOptions = options as ForEachItemOptions<T, R>;\n result = await itemOptions.item.handler(item, index, stepFn as unknown as RunStep<unknown>);\n }\n\n results.push(result);\n index++;\n }\n\n return results;\n };\n\n // step.item: Create an item handler for use with step.forEach\n // Runtime: returns the handler wrapped in a marker object\n // Analyzer: extracts the inner step structure\n stepFn.item = <T, R>(\n handler: (item: T, index: number, step: RunStep<unknown>) => R | Promise<R>\n ): ForEachItemHandler<T, R> => {\n return {\n __forEachItemHandler: true as const,\n handler,\n };\n };\n\n // step.dep: Wrap a dependency function for static analysis tracking\n // Runtime: returns the function unchanged\n // Analyzer: records the dependency name\n stepFn.dep = <T extends (...args: unknown[]) => unknown>(\n _name: string,\n fn: T\n ): T => {\n return fn;\n };\n\n // ===========================================================================\n // Effect-Style Ergonomics\n // ===========================================================================\n\n // step.run: Unwrap an AsyncResult directly\n stepFn.run = <T, StepE, StepC = unknown>(\n id: string,\n result: AsyncResult<T, StepE, StepC>,\n options?: StepOptions\n ): Promise<T> => {\n return stepFn(id, () => result, options);\n };\n\n // step.workflow: Run sub-workflow (or any AsyncResult getter) as a step; same engine as step(id, getter, opts)\n stepFn.workflow = <T, SubE, StepC = unknown>(\n id: string,\n getter: () => AsyncResult<T, SubE, StepC>,\n options?: StepOptions\n ): Promise<T> => {\n return stepFn(id, getter as () => AsyncResult<T, E, StepC>, options);\n };\n\n // step.andThen: Chain AsyncResult operations\n stepFn.andThen = <T, U, StepE, StepC = unknown>(\n id: string,\n value: T,\n fn: (value: T) => AsyncResult<U, StepE, StepC>,\n options?: StepOptions\n ): Promise<U> => {\n return stepFn(id, () => fn(value), options);\n };\n\n // step.match: Pattern match on Result with step tracking (runs through step engine for lifecycle events)\n stepFn.match = async <T, StepE, U, StepC = unknown>(\n id: string,\n result: Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n handlers: {\n ok: (value: T) => U | Promise<U>;\n err: (error: StepE, cause?: StepC) => U | Promise<U>;\n },\n options?: StepOptions\n ): Promise<U> => {\n return stepFn(id, async () => {\n const resolved = await result;\n if (resolved.ok) {\n return ok(await handlers.ok(resolved.value));\n } else {\n return ok(await handlers.err(resolved.error, resolved.cause));\n }\n }, options);\n };\n\n // step.all: Alias for step.parallel (Effect.all-style API)\n stepFn.all = stepFn.parallel;\n\n // step.map: Map over array with parallel execution\n stepFn.map = async <T, U, StepE, StepC = unknown>(\n id: string,\n items: T[],\n mapper: (item: T, index: number) => AsyncResult<U, StepE, StepC>,\n options?: { concurrency?: number; key?: string }\n ): Promise<U[]> => {\n const concurrency = options?.concurrency ?? items.length;\n\n // Use allAsync for parallel execution with fail-fast\n return stepFn(\n id,\n () => {\n if (concurrency >= items.length) {\n // Full parallelism - execute all at once\n return allAsync(items.map((item, index) => mapper(item, index)));\n } else {\n // Limited concurrency - batch execution\n return (async () => {\n const results: U[] = [];\n for (let i = 0; i < items.length; i += concurrency) {\n const batch = items.slice(i, i + concurrency);\n const batchResult = await allAsync(\n batch.map((item, batchIndex) => mapper(item, i + batchIndex))\n );\n // allAsync returns Result<U[], E, C>, so we need to check if it's ok\n if (!batchResult.ok) {\n return batchResult; // Propagate the error\n }\n results.push(...batchResult.value);\n }\n return ok(results);\n })();\n }\n },\n { key: options?.key }\n );\n };\n\n // step.withFallback: Execute primary with fallback on error\n stepFn.withFallback = <T, E1, E2>(\n id: string,\n operation: () => AsyncResult<T, E1>,\n options: { on?: E1 & string; fallback: () => AsyncResult<T, E2>; key?: string }\n ): Promise<T> => {\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.withFallback() requires an explicit string ID as the first argument. ' +\n 'Example: step.withFallback(\"getUser\", () => fetchUser(id), { fallback: () => fetchFromCache(id) })'\n );\n }\n\n const stepKey = options.key ?? id;\n const stepName = id;\n const stepId = generateStepId(stepKey);\n const hasEventListeners = onEvent;\n\n return (async () => {\n const startTime = hasEventListeners ? performance.now() : 0;\n\n if (onEvent) {\n emitEvent({\n type: \"step_start\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n });\n }\n\n // Try the primary operation\n let primaryResult: Result<T, E1>;\n try {\n primaryResult = await operation();\n } catch (thrown) {\n // If it's an earlyExit from a nested step, propagate\n if (isEarlyExitE(thrown)) {\n emitEvent({\n type: \"step_aborted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n throw thrown;\n }\n\n // Primary threw — map to UnexpectedError\n let mappedError: E | UnexpectedError;\n try {\n mappedError = effectiveCatchUnexpected(thrown) as E | UnexpectedError;\n } catch (mapperError) {\n throw createMapperException(mapperError);\n }\n\n // If `on` is specified, only run fallback if it matches the mapped error\n if (options.on !== undefined && options.on !== mappedError) {\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: mappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(mappedError, { cause: thrown }),\n meta: { origin: \"throw\", thrown },\n });\n }\n onError?.(mappedError as E, stepName, context);\n throw earlyExit(mappedError as E, { origin: \"throw\", thrown });\n }\n\n // Run fallback for thrown error\n let fallbackResultFromThrow: Result<T, E2>;\n try {\n fallbackResultFromThrow = await options.fallback();\n } catch (fallbackThrown) {\n if (isEarlyExitE(fallbackThrown)) {\n emitEvent({\n type: \"step_aborted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n throw fallbackThrown;\n }\n let fallbackMappedError: E | UnexpectedError;\n try {\n fallbackMappedError = effectiveCatchUnexpected(fallbackThrown) as E | UnexpectedError;\n } catch (mapperError) {\n throw createMapperException(mapperError);\n }\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: fallbackMappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(fallbackMappedError, { cause: fallbackThrown }),\n meta: { origin: \"throw\", thrown: fallbackThrown },\n });\n }\n onError?.(fallbackMappedError as E, stepName, context);\n throw earlyExit(fallbackMappedError as E, { origin: \"throw\", thrown: fallbackThrown });\n }\n\n if (fallbackResultFromThrow.ok) {\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: fallbackResultFromThrow,\n meta: { origin: \"fallback\" as const, fallbackUsed: true as const, fallbackReason: String(mappedError) },\n });\n }\n return fallbackResultFromThrow.value;\n } else {\n // Fallback also failed\n const durationMs = performance.now() - startTime;\n const wrappedError = wrapForStep(fallbackResultFromThrow.error, {\n origin: \"result\",\n resultCause: fallbackResultFromThrow.cause,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: fallbackResultFromThrow,\n meta: { origin: \"result\", resultCause: fallbackResultFromThrow.cause },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: fallbackResultFromThrow.cause,\n });\n }\n }\n\n // Primary returned a result (didn't throw)\n if (primaryResult.ok) {\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: primaryResult,\n });\n }\n return primaryResult.value;\n }\n\n // Primary returned an error\n const primaryError = primaryResult.error;\n\n // If `on` is specified and doesn't match, earlyExit with primary error (no fallback)\n if (options.on !== undefined && options.on !== primaryError) {\n const durationMs = performance.now() - startTime;\n const wrappedError = wrapForStep(primaryError, {\n origin: \"result\",\n resultCause: primaryResult.cause,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: primaryResult,\n meta: { origin: \"result\", resultCause: primaryResult.cause },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: primaryResult.cause,\n });\n }\n\n // Run fallback\n let fallbackResult: Result<T, E2>;\n try {\n fallbackResult = await options.fallback();\n } catch (thrown) {\n if (isEarlyExitE(thrown)) {\n emitEvent({\n type: \"step_aborted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n throw thrown;\n }\n // Fallback threw — map via effectiveCatchUnexpected\n let mappedError: E | UnexpectedError;\n try {\n mappedError = effectiveCatchUnexpected(thrown) as E | UnexpectedError;\n } catch (mapperError) {\n throw createMapperException(mapperError);\n }\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: mappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(mappedError, { cause: thrown }),\n meta: { origin: \"throw\", thrown },\n });\n }\n onError?.(mappedError as E, stepName, context);\n throw earlyExit(mappedError as E, { origin: \"throw\", thrown });\n }\n\n if (fallbackResult.ok) {\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: fallbackResult,\n meta: { origin: \"fallback\" as const, fallbackUsed: true as const, fallbackReason: String(primaryError) },\n });\n }\n return fallbackResult.value;\n }\n\n // Fallback also returned an error\n const durationMs = performance.now() - startTime;\n const wrappedError = wrapForStep(fallbackResult.error, {\n origin: \"result\",\n resultCause: fallbackResult.cause,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: fallbackResult,\n meta: { origin: \"result\", resultCause: fallbackResult.cause },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: fallbackResult.cause,\n });\n })();\n };\n\n // step.withResource: Acquire/use/release lifecycle with guaranteed release\n stepFn.withResource = <T, R, AcquireE, UseE>(\n id: string,\n options: {\n acquire: () => AsyncResult<R, AcquireE>;\n use: (resource: R) => AsyncResult<T, UseE>;\n release: (resource: R) => void | Promise<void>;\n }\n ): Promise<T> => {\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.withResource() requires an explicit string ID as the first argument. ' +\n 'Example: step.withResource(\"useDb\", { acquire: () => connect(), use: (db) => query(db), release: (db) => db.close() })'\n );\n }\n\n const stepKey = id;\n const stepName = id;\n const stepId = generateStepId(stepKey);\n const hasEventListeners = onEvent;\n\n return (async () => {\n const startTime = hasEventListeners ? performance.now() : 0;\n\n if (onEvent) {\n emitEvent({\n type: \"step_start\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n });\n }\n\n // Acquire\n let acquireResult: Result<R, AcquireE>;\n try {\n acquireResult = await options.acquire();\n } catch (thrown) {\n if (isEarlyExitE(thrown)) {\n emitEvent({\n type: \"step_aborted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n throw thrown;\n }\n let mappedError: E | UnexpectedError;\n try {\n mappedError = effectiveCatchUnexpected(thrown) as E | UnexpectedError;\n } catch (mapperError) {\n throw createMapperException(mapperError);\n }\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: mappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(mappedError, { cause: thrown }),\n meta: { origin: \"throw\", thrown },\n });\n }\n onError?.(mappedError as E, stepName, context);\n throw earlyExit(mappedError as E, { origin: \"throw\", thrown });\n }\n\n if (!acquireResult.ok) {\n // Acquire failed — no release needed\n const durationMs = performance.now() - startTime;\n const wrappedError = wrapForStep(acquireResult.error, {\n origin: \"result\",\n resultCause: acquireResult.cause,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: acquireResult,\n meta: { origin: \"result\", resultCause: acquireResult.cause },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: acquireResult.cause,\n });\n }\n\n const resource = acquireResult.value;\n let useResult: Result<T, UseE> | undefined;\n let useThrown: unknown;\n let useThrewNonResult = false;\n\n // Use\n try {\n useResult = await options.use(resource);\n } catch (thrown) {\n if (isEarlyExitE(thrown)) {\n // Release before propagating\n try {\n await options.release(resource);\n } catch (releaseErr) {\n console.warn(\n `[awaitly] step.withResource(\"${id}\"): release threw after earlyExit:`,\n releaseErr\n );\n }\n throw thrown;\n }\n useThrown = thrown;\n useThrewNonResult = true;\n }\n\n // Release — ALWAYS runs after use (unless acquire failed)\n try {\n await options.release(resource);\n } catch (releaseErr) {\n console.warn(\n `[awaitly] step.withResource(\"${id}\"): release threw:`,\n releaseErr\n );\n }\n\n // Emit events AFTER release completes\n if (useThrewNonResult) {\n let mappedError: E | UnexpectedError;\n try {\n mappedError = effectiveCatchUnexpected(useThrown) as E | UnexpectedError;\n } catch (mapperError) {\n throw createMapperException(mapperError);\n }\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: mappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(mappedError, { cause: useThrown }),\n meta: { origin: \"throw\", thrown: useThrown },\n });\n }\n onError?.(mappedError as E, stepName, context);\n throw earlyExit(mappedError as E, { origin: \"throw\", thrown: useThrown });\n }\n\n // useResult is defined if useThrewNonResult is false\n const result = useResult!;\n if (result.ok) {\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result,\n });\n }\n return result.value;\n }\n\n // Use returned an error\n const durationMs = performance.now() - startTime;\n const wrappedError = wrapForStep(result.error, {\n origin: \"result\",\n resultCause: result.cause,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result,\n meta: { origin: \"result\", resultCause: result.cause },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: result.cause,\n });\n })();\n };\n\n const step = stepFn as RunStep<E | UnexpectedError>;\n const value = await fn({ step });\n\n // Dev-only warning: Detect common mistake of returning ok() or err() from executor\n if (\n process.env.NODE_ENV !== \"production\" &&\n value !== null &&\n typeof value === \"object\" &&\n \"ok\" in value &&\n typeof (value as { ok: unknown }).ok === \"boolean\"\n ) {\n const maybeResult = value as { ok: boolean; value?: unknown; error?: unknown };\n if (\n (maybeResult.ok === true && \"value\" in maybeResult) ||\n (maybeResult.ok === false && \"error\" in maybeResult)\n ) {\n console.warn(\n `awaitly: Workflow executor returned a Result-like object. ` +\n `Return raw values, not ok() or err().\\n\\n` +\n ` Incorrect: return ok({ data });\\n` +\n ` Correct: return { data };\\n\\n` +\n `See: https://jagreehal.github.io/awaitly/guides/troubleshooting/#returning-ok-from-workflow-executor-double-wrapping`\n );\n }\n }\n\n return ok(value);\n } catch (error) {\n // If a catchUnexpected mapper threw, propagate without re-processing\n if (isMapperException(error)) {\n throw error.thrown;\n }\n\n if (isEarlyExitE(error)) {\n // Extract original cause from early exit metadata\n const originalCause = error.meta.origin === \"throw\"\n ? error.meta.thrown\n : error.meta.origin === \"result\"\n ? error.meta.resultCause\n : undefined;\n\n return err(error.error, { cause: originalCause });\n }\n\n const mapped = effectiveCatchUnexpected(error);\n onError?.(mapped as E, \"unexpected\", context);\n return err(mapped, { cause: error });\n }\n}\n\n/**\n * Convenience for run() with catchUnexpected: closed union Result<T, E>.\n * You must provide catchUnexpected to map uncaught exceptions to E.\n */\nrun.strict = <T, E, C = void>(\n fn: (context: { step: RunStep<E> }) => Promise<T> | T,\n options: {\n onError?: (error: E, stepName?: string, ctx?: C) => void;\n /**\n * Listener for workflow events (start, success, error, step events).\n *\n * Note: Context is available both on `event.context` and as the separate `ctx` parameter.\n * The `ctx` parameter is provided for convenience and backward compatibility.\n */\n onEvent?: (event: WorkflowEvent<E | UnexpectedError, C>, ctx: C) => void;\n catchUnexpected: (cause: unknown) => E;\n workflowId?: string;\n context?: C;\n /** @internal External signal for workflow-level cancellation. */\n _workflowSignal?: AbortSignal;\n }\n): AsyncResult<T, E, unknown> => {\n return run<T, E, C>(fn, options);\n};\n\n// =============================================================================\n// Unwrap Utilities\n// =============================================================================\n\n/**\n * Error thrown when `unwrap()` is called on an error Result.\n *\n * This error is thrown to prevent silent failures when using `unwrap()`.\n * Prefer using `unwrapOr`, `unwrapOrElse`, or pattern matching with `match` or `isOk`/`isErr`.\n */\nexport class UnwrapError<E = unknown, C = unknown> extends Error {\n constructor(\n public readonly error: E,\n public readonly cause?: C\n ) {\n super(`Unwrap called on an error result: ${String(error)}`);\n this.name = \"UnwrapError\";\n }\n}\n\n/**\n * Unwraps a Result, throwing an error if it's a failure.\n *\n * @remarks When to use: Only at boundaries or tests where a failure should be fatal.\n *\n * ## When to Use\n *\n * Use `unwrap()` when:\n * - You're certain the Result is successful (e.g., after checking with `isOk`)\n * - You're in a context where errors should crash (e.g., tests, initialization)\n * - You need the value immediately and can't handle errors gracefully\n *\n * ## Why Avoid This\n *\n * **Prefer alternatives** in production code:\n * - `unwrapOr(defaultValue)` - Provide a fallback value\n * - `unwrapOrElse(fn)` - Compute fallback from error\n * - `match()` - Handle both cases explicitly\n * - `isOk()` / `isErr()` - Type-safe pattern matching\n *\n * Throwing errors makes error handling harder and can crash your application.\n *\n * @param r - The Result to unwrap\n * @returns The success value if the Result is successful\n * @throws {UnwrapError} If the Result is an error (includes the error and cause)\n *\n * @example\n * ```typescript\n * // Safe usage after checking\n * const result = someOperation();\n * if (isOk(result)) {\n * const value = unwrap(result); // Safe - we know it's ok\n * }\n *\n * // Unsafe usage (not recommended)\n * const value = unwrap(someOperation()); // May throw!\n * ```\n */\nexport const unwrap = <T, E, C>(r: Result<T, E, C>): T => {\n if (r.ok) return r.value;\n throw new UnwrapError<E, C>(r.error, r.cause);\n};\n\n/**\n * Unwraps a Result, returning a default value if it's a failure.\n *\n * @remarks When to use: Provide a safe fallback without branching.\n *\n * ## When to Use\n *\n * Use `unwrapOr()` when:\n * - You have a sensible default value for errors\n * - You want to continue execution even on failure\n * - The default value is cheap to compute (use `unwrapOrElse` if expensive)\n *\n * ## Why Use This\n *\n * - **Safe**: Never throws, always returns a value\n * - **Simple**: One-liner for common error handling\n * - **Type-safe**: TypeScript knows you'll always get a `T`\n *\n * @param r - The Result to unwrap\n * @param defaultValue - The value to return if the Result is an error\n * @returns The success value if successful, otherwise the default value\n *\n * @example\n * ```typescript\n * // Provide default for missing data\n * const user = unwrapOr(fetchUser(id), { id: 'anonymous', name: 'Guest' });\n *\n * // Provide default for numeric operations\n * const count = unwrapOr(parseCount(input), 0);\n *\n * // Provide default for optional features\n * const config = unwrapOr(loadConfig(), getDefaultConfig());\n * ```\n */\nexport const unwrapOr = <T, E, C>(r: Result<T, E, C>, defaultValue: T): T =>\n r.ok ? r.value : defaultValue;\n\n/**\n * Unwraps a Result, computing a default value from the error if it's a failure.\n *\n * @remarks When to use: Compute a fallback from the error (logging, metrics, or derived defaults).\n *\n * ## When to Use\n *\n * Use `unwrapOrElse()` when:\n * - The default value is expensive to compute (lazy evaluation)\n * - You need to log or handle the error before providing a default\n * - The default depends on the error type or cause\n * - You want to transform the error into a success value\n *\n * ## Why Use This Instead of `unwrapOr`\n *\n * - **Lazy**: Default is only computed if needed (better performance)\n * - **Error-aware**: You can inspect the error before providing default\n * - **Flexible**: Default can depend on error type or cause\n *\n * @param r - The Result to unwrap\n * @param fn - Function that receives the error and optional cause, returns the default value\n * @returns The success value if successful, otherwise the result of calling `fn(error, cause)`\n *\n * @example\n * ```typescript\n * // Compute default based on error type\n * const port = unwrapOrElse(parsePort(env.PORT), (error) => {\n * if (error === 'INVALID_FORMAT') return 3000;\n * if (error === 'OUT_OF_RANGE') return 8080;\n * return 4000; // default\n * });\n *\n * // Log error before providing default\n * const data = unwrapOrElse(fetchData(), (error, cause) => {\n * console.error('Failed to fetch:', error, cause);\n * return getCachedData();\n * });\n *\n * // Transform error into success value\n * const result = unwrapOrElse(operation(), (error) => {\n * return { success: false, reason: String(error) };\n * });\n * ```\n */\nexport const unwrapOrElse = <T, E, C>(\n r: Result<T, E, C>,\n fn: (error: E, cause?: C) => T\n): T => (r.ok ? r.value : fn(r.error, r.cause));\n\n/**\n * Alias for `unwrap`. Returns the success value or throws.\n *\n * The Result is already computed; use when you want the value or throw (e.g. at boundaries or in tests).\n *\n * @param r - The Result to unwrap\n * @returns The success value if the Result is successful\n * @throws {UnwrapError} If the Result is an error (includes the error and cause)\n */\nexport const runOrThrow = <T, E, C>(r: Result<T, E, C>): T => unwrap(r);\n\n/**\n * Awaits a Promise of a Result, then returns the success value or rejects.\n *\n * The returned promise **resolves with T** on success and **rejects with UnwrapError** on failure.\n * UnwrapError extends Error and carries the original `error` and `cause` from the Err.\n *\n * @param ar - A Promise or thenable that resolves to a Result\n * @returns A Promise that resolves with the success value or rejects with UnwrapError\n */\nexport const runOrThrowAsync = <T, E, C>(\n ar: PromiseLike<Result<T, E, C>>\n): Promise<T> => Promise.resolve(ar).then(unwrap);\n\n/**\n * Convenience alias for `unwrapOr(r, null)`. Returns the success value or null.\n *\n * @param r - The Result to unwrap\n * @returns The success value if successful, otherwise null\n */\nexport const runOrNull = <T, E, C>(r: Result<T, E, C>): T | null =>\n r.ok ? r.value : null;\n\n/**\n * Convenience alias for `unwrapOr(r, undefined)`. Returns the success value or undefined.\n *\n * @param r - The Result to unwrap\n * @returns The success value if successful, otherwise undefined\n */\nexport const runOrUndefined = <T, E, C>(r: Result<T, E, C>): T | undefined =>\n r.ok ? r.value : undefined;\n\n// =============================================================================\n// Wrapping Functions\n// =============================================================================\n\n/**\n * Wraps a synchronous throwing function in a Result.\n *\n * @remarks When to use: Wrap sync code that might throw so exceptions become Err values.\n *\n * ## When to Use\n *\n * Use `from()` when:\n * - You have a synchronous function that throws exceptions\n * - You want to convert exceptions to typed errors\n * - You're integrating with libraries that throw (e.g., JSON.parse, fs.readFileSync)\n * - You need to handle errors without try/catch blocks\n *\n * ## Why Use This\n *\n * - **Type-safe errors**: Convert thrown exceptions to typed Result errors\n * - **No try/catch**: Cleaner code without nested try/catch blocks\n * - **Composable**: Results can be chained with `andThen`, `map`, etc.\n * - **Explicit errors**: Forces you to handle errors explicitly\n *\n * @param fn - The synchronous function to execute (may throw)\n * @returns A Result with the function's return value or the thrown error\n *\n * @example\n * ```typescript\n * // Wrap JSON.parse\n * const parsed = from(() => JSON.parse('{\"key\": \"value\"}'));\n * // parsed: { ok: true, value: { key: \"value\" } }\n *\n * const error = from(() => JSON.parse('invalid'));\n * // error: { ok: false, error: SyntaxError }\n * ```\n */\nexport function from<T>(fn: () => T): Ok<T> | Err<unknown, unknown>;\n/**\n * Wraps a synchronous throwing function in a Result with custom error mapping.\n *\n * Use this overload when you want to map thrown exceptions to your typed error union.\n *\n * @param fn - The synchronous function to execute (may throw)\n * @param onError - Function to map the thrown exception to a typed error\n * @returns A Result with the function's return value or the mapped error\n *\n * @example\n * ```typescript\n * // Map exceptions to typed errors\n * const parsed = from(\n * () => JSON.parse(input),\n * (cause) => ({ type: 'PARSE_ERROR' as const, cause })\n * );\n * // parsed.error: { type: 'PARSE_ERROR', cause: SyntaxError }\n *\n * // Map to simple error codes\n * const value = from(\n * () => riskyOperation(),\n * () => 'OPERATION_FAILED' as const\n * );\n * ```\n */\nexport function from<T, E>(fn: () => T, onError: (cause: unknown) => E): Ok<T> | Err<E, unknown>;\nexport function from<T, E>(fn: () => T, onError?: (cause: unknown) => E) {\n try {\n return ok(fn());\n } catch (cause) {\n return onError ? err(onError(cause), { cause }) : err(cause);\n }\n}\n\n/**\n * Wraps a Promise in a Result, converting rejections to errors.\n *\n * @remarks When to use: Wrap a Promise and keep the raw rejection as Err; use tryAsync to map errors.\n *\n * ## When to Use\n *\n * Use `fromPromise()` when:\n * - You have an existing Promise that might reject\n * - You want to convert Promise rejections to typed errors\n * - You're working with libraries that return Promises (fetch, database clients)\n * - You need to handle rejections without .catch() chains\n *\n * ## Why Use This\n *\n * - **Type-safe errors**: Convert Promise rejections to typed Result errors\n * - **Composable**: Results can be chained with `andThen`, `map`, etc.\n * - **Explicit handling**: Forces you to handle errors explicitly\n * - **No .catch() chains**: Cleaner than Promise.catch() patterns\n *\n * @param promise - The Promise to await (may reject)\n * @returns A Promise resolving to a Result with the resolved value or rejection reason\n *\n * @example\n * ```typescript\n * // Wrap fetch\n * const result = await fromPromise(\n * fetch('/api').then(r => r.json())\n * );\n * // result.ok: true if fetch succeeded, false if rejected\n * ```\n */\nexport function fromPromise<T>(promise: Promise<T>): Promise<Ok<T> | Err<unknown, unknown>>;\n/**\n * Wraps a Promise in a Result with custom error mapping.\n *\n * Use this overload when you want to map Promise rejections to your typed error union.\n *\n * @param promise - The Promise to await (may reject)\n * @param onError - Function to map the rejection reason to a typed error\n * @returns A Promise resolving to a Result with the resolved value or mapped error\n *\n * @example\n * ```typescript\n * // Map fetch errors to typed errors\n * const result = await fromPromise(\n * fetch('/api').then(r => {\n * if (!r.ok) throw new Error(`HTTP ${r.status}`);\n * return r.json();\n * }),\n * () => 'FETCH_FAILED' as const\n * );\n * // result.error: 'FETCH_FAILED' if fetch failed\n *\n * // Map with error details\n * const data = await fromPromise(\n * db.query(sql),\n * (cause) => ({ type: 'DB_ERROR' as const, message: String(cause) })\n * );\n * ```\n */\nexport function fromPromise<T, E>(\n promise: Promise<T>,\n onError: (cause: unknown) => E\n): Promise<Ok<T> | Err<E, unknown>>;\nexport async function fromPromise<T, E>(\n promise: Promise<T>,\n onError?: (cause: unknown) => E\n): Promise<Ok<T> | Err<E, unknown> | Err<unknown, unknown>> {\n try {\n return ok(await promise);\n } catch (cause) {\n return onError ? err(onError(cause), { cause }) : err(cause);\n }\n}\n\n/**\n * Wraps an async function in a Result, catching both thrown exceptions and Promise rejections.\n *\n * @remarks When to use: Wrap async work and map thrown/rejected values into your typed error union.\n *\n * ## When to Use\n *\n * Use `tryAsync()` when:\n * - You have an async function that might throw or reject\n * - You want to convert both exceptions and rejections to typed errors\n * - You're creating new async functions (use `fromPromise` for existing Promises)\n * - You need to handle errors without try/catch or .catch()\n *\n * ## Why Use This Instead of `fromPromise`\n *\n * - **Function form**: Takes a function, not a Promise (lazy evaluation)\n * - **Catches both**: Handles both thrown exceptions and Promise rejections\n * - **Cleaner syntax**: No need to wrap in Promise manually\n *\n * @param fn - The async function to execute (may throw or reject)\n * @returns A Promise resolving to a Result with the function's return value or error\n *\n * @example\n * ```typescript\n * // Wrap async function\n * const result = await tryAsync(async () => {\n * const data = await fetchData();\n * return processData(data);\n * });\n * ```\n */\nexport function tryAsync<T>(fn: () => Promise<T>): AsyncResult<T, unknown>;\n/**\n * Wraps an async function in a Result with custom error mapping.\n *\n * Use this overload when you want to map errors to your typed error union.\n *\n * @param fn - The async function to execute (may throw or reject)\n * @param onError - Function to map the error (exception or rejection) to a typed error\n * @returns A Promise resolving to a Result with the function's return value or mapped error\n *\n * @example\n * ```typescript\n * // Map errors to typed errors\n * const result = await tryAsync(\n * async () => await fetchData(),\n * () => 'FETCH_ERROR' as const\n * );\n *\n * // Map with error details\n * const data = await tryAsync(\n * async () => await processFile(path),\n * (cause) => ({ type: 'PROCESSING_ERROR' as const, cause })\n * );\n * ```\n */\nexport function tryAsync<T, E>(\n fn: () => Promise<T>,\n onError: (cause: unknown) => E\n): AsyncResult<T, E>;\nexport async function tryAsync<T, E>(\n fn: () => Promise<T>,\n onError?: (cause: unknown) => E\n): AsyncResult<T, E | unknown> {\n try {\n return ok(await fn());\n } catch (cause) {\n return onError ? err(onError(cause), { cause }) : err(cause);\n }\n}\n\n/**\n * Converts a nullable value to a Result.\n *\n * @remarks When to use: Turn null/undefined into a typed error before continuing.\n *\n * ## When to Use\n *\n * Use `fromNullable()` when:\n * - You have a value that might be `null` or `undefined`\n * - You want to treat null/undefined as an error case\n * - You're working with APIs that return nullable values (DOM APIs, optional properties)\n * - You want to avoid null checks scattered throughout your code\n *\n * ## Why Use This\n *\n * - **Type-safe**: Converts nullable types to non-nullable Results\n * - **Explicit errors**: Forces you to handle null/undefined cases\n * - **Composable**: Results can be chained with `andThen`, `map`, etc.\n * - **No null checks**: Eliminates need for `if (value == null)` checks\n *\n * @param value - The value that may be null or undefined\n * @param onNull - Function that returns an error when value is null/undefined\n * @returns A Result with the value if not null/undefined, otherwise the error from `onNull`\n *\n * @example\n * ```typescript\n * // Convert DOM element lookup\n * const element = fromNullable(\n * document.getElementById('app'),\n * () => 'ELEMENT_NOT_FOUND' as const\n * );\n *\n * // Convert optional property\n * const userId = fromNullable(\n * user.id,\n * () => 'USER_ID_MISSING' as const\n * );\n *\n * // Convert database query result\n * const record = fromNullable(\n * await db.find(id),\n * () => ({ type: 'NOT_FOUND' as const, id })\n * );\n * ```\n */\nexport function fromNullable<T, E>(\n value: T | null | undefined,\n onNull: () => E\n): Result<T, E> {\n return value != null ? ok(value) : err(onNull());\n}\n\n// =============================================================================\n// Transformers\n// =============================================================================\n\n/**\n * Transforms the success value of a Result.\n *\n * @remarks When to use: Transform only the Ok value while leaving Err untouched.\n *\n * ## When to Use\n *\n * Use `map()` when:\n * - You need to transform a success value to another type\n * - You want to apply a pure function to the value\n * - You're building a pipeline of transformations\n * - The transformation cannot fail (use `andThen` if it can fail)\n *\n * ## Why Use This\n *\n * - **Functional style**: Composable, chainable transformations\n * - **Error-preserving**: Errors pass through unchanged\n * - **Type-safe**: TypeScript tracks the transformation\n * - **No unwrapping**: Avoids manual `if (r.ok)` checks\n *\n * @param r - The Result to transform\n * @param fn - Pure function that transforms the success value (must not throw)\n * @returns A new Result with the transformed value, or the original error if `r` was an error\n *\n * @example\n * ```typescript\n * // Transform numeric value\n * const doubled = map(ok(21), n => n * 2);\n * // doubled: { ok: true, value: 42 }\n *\n * // Transform object property\n * const name = map(fetchUser(id), user => user.name);\n *\n * // Chain transformations\n * const formatted = map(\n * map(parseNumber(input), n => n * 2),\n * n => `Result: ${n}`\n * );\n * ```\n */\nexport function map<T, U>(r: Ok<T>, fn: (value: T) => U): Ok<U>;\nexport function map<T, U, E, C>(r: Err<E, C>, fn: (value: T) => U): Err<E, C>;\nexport function map<T, U, E, C>(r: Result<T, E, C>, fn: (value: T) => U): Result<U, E, C>;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function map(r: any, fn: any): any {\n return r.ok ? ok(fn(r.value)) : r;\n}\n\n/**\n * Transforms the error value of a Result.\n *\n * @remarks When to use: Retype or normalize errors while leaving Ok values unchanged.\n *\n * ## When to Use\n *\n * Use `mapError()` when:\n * - You need to normalize or transform error types\n * - You want to convert errors to a different error type\n * - You're building error handling pipelines\n * - You need to format error messages or codes\n *\n * ## Why Use This\n *\n * - **Error normalization**: Convert errors to a common format\n * - **Type transformation**: Change error type while preserving value type\n * - **Composable**: Can be chained with other transformers\n * - **Success-preserving**: Success values pass through unchanged\n *\n * @param r - The Result to transform\n * @param fn - Function that transforms the error value (must not throw)\n * @returns A new Result with the original value, or the transformed error if `r` was an error\n *\n * @example\n * ```typescript\n * // Normalize error codes\n * const normalized = mapError(err('not_found'), e => e.toUpperCase());\n * // normalized: { ok: false, error: 'NOT_FOUND' }\n *\n * // Convert error types\n * const typed = mapError(\n * err('404'),\n * code => ({ type: 'HTTP_ERROR' as const, status: parseInt(code) })\n * );\n *\n * // Format error messages\n * const formatted = mapError(\n * err('PARSE_ERROR'),\n * code => `Failed to parse: ${code}`\n * );\n * ```\n */\nexport function mapError<T, E, F, C>(\n r: Result<T, E, C>,\n fn: (error: E) => F\n): Result<T, F, C> {\n return r.ok ? r : err(fn(r.error), { cause: r.cause });\n}\n\n/**\n * Pattern matches on a Result, calling the appropriate handler.\n *\n * @remarks When to use: Handle both Ok and Err in a single expression that returns a value.\n *\n * ## When to Use\n *\n * Use `match()` when:\n * - You need to handle both success and error cases\n * - You want to transform a Result to a different type\n * - You need exhaustive handling (both cases must be handled)\n * - You're building user-facing messages or responses\n *\n * ## Why Use This\n *\n * - **Exhaustive**: Forces you to handle both success and error cases\n * - **Type-safe**: TypeScript ensures both handlers are provided\n * - **Functional**: Pattern matching style, similar to Rust's `match` or Haskell's `case`\n * - **Single expression**: Can be used in expressions, not just statements\n *\n * @param r - The Result to match\n * @param handlers - Object with `ok` and `err` handler functions\n * @param handlers.ok - Function called with the success value\n * @param handlers.err - Function called with the error and optional cause\n * @returns The return value of the appropriate handler (both must return the same type `R`)\n *\n * @example\n * ```typescript\n * // Build user-facing messages\n * const message = match(result, {\n * ok: (user) => `Hello ${user.name}`,\n * err: (error) => `Error: ${error}`,\n * });\n *\n * // Transform to API response\n * const response = match(operation(), {\n * ok: (data) => ({ status: 200, body: data }),\n * err: (error) => ({ status: 400, error: String(error) }),\n * });\n *\n * // Handle with cause\n * const response = match(result, {\n * ok: (value) => ({ status: 'success', data: value }),\n * err: (error, cause) => ({ status: 'error', error, cause }),\n * });\n * ```\n */\nexport function match<T, E, C, R>(r: Ok<T>, handlers: { ok: (value: T) => R; err: (error: E, cause?: C) => R }): R;\nexport function match<T, E, C, R>(r: Err<E, C>, handlers: { ok: (value: T) => R; err: (error: E, cause?: C) => R }): R;\nexport function match<T, E, C, R>(r: Result<T, E, C>, handlers: { ok: (value: T) => R; err: (error: E, cause?: C) => R }): R;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function match(r: any, handlers: any): any {\n return r.ok ? handlers.ok(r.value) : handlers.err(r.error, r.cause);\n}\n\n/**\n * Chains Results together (flatMap/monadic bind).\n *\n * @remarks When to use: Chain dependent operations that return Result without nested branching.\n *\n * ## When to Use\n *\n * Use `andThen()` when:\n * - You need to chain operations that can fail\n * - The next operation depends on the previous success value\n * - You're building a pipeline of dependent operations\n * - You want to avoid nested `if (r.ok)` checks\n *\n * ## Why Use This Instead of `map`\n *\n * - **Can fail**: The chained function returns a Result (can fail)\n * - **Short-circuits**: If first Result fails, second operation never runs\n * - **Error accumulation**: Errors from both operations are in the union\n * - **Composable**: Can chain multiple operations together\n *\n * ## Common Pattern\n *\n * This is the fundamental building block for Result pipelines:\n * ```typescript\n * andThen(operation1(), value1 =>\n * andThen(operation2(value1), value2 =>\n * ok({ value1, value2 })\n * )\n * )\n * ```\n *\n * @param r - The first Result\n * @param fn - Function that takes the success value and returns a new Result (may fail)\n * @returns The Result from `fn` if `r` was successful, otherwise the original error\n *\n * @example\n * ```typescript\n * // Chain dependent operations\n * const userPosts = andThen(\n * fetchUser('1'),\n * user => fetchPosts(user.id)\n * );\n *\n * // Build complex pipelines\n * const result = andThen(parseInput(input), parsed =>\n * andThen(validate(parsed), validated =>\n * process(validated)\n * )\n * );\n *\n * // Chain with different error types\n * const data = andThen(\n * fetchUser(id), // Returns Result<User, 'FETCH_ERROR'>\n * user => fetchPosts(user.id) // Returns Result<Post[], 'NOT_FOUND'>\n * );\n * // data.error: 'FETCH_ERROR' | 'NOT_FOUND'\n * ```\n */\nexport function andThen<T, U>(r: Ok<T>, fn: (value: T) => Ok<U>): Ok<U>;\nexport function andThen<T, F, C2>(r: Ok<T>, fn: (value: T) => Err<F, C2>): Err<F, C2>;\nexport function andThen<T, U, F, C2>(r: Ok<T>, fn: (value: T) => Result<U, F, C2>): Result<U, F, C2>;\nexport function andThen<T, U, E, F, C1, C2>(r: Err<E, C1>, fn: (value: T) => Result<U, F, C2>): Err<E, C1>;\nexport function andThen<T, U, E, F, C1, C2>(r: Result<T, E, C1>, fn: (value: T) => Result<U, F, C2>): Result<U, E | F, C1 | C2>;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function andThen(r: any, fn: any): any {\n return r.ok ? fn(r.value) : r;\n}\n\n/**\n * Executes a side effect on a successful Result without changing it.\n *\n * @remarks When to use: Add side effects (logging, metrics) on Ok without changing the Result.\n *\n * ## When to Use\n *\n * Use `tap()` when:\n * - You need to log, debug, or observe success values\n * - You want to perform side effects in a pipeline\n * - You need to mutate external state based on success\n * - You're debugging and want to inspect values without breaking the chain\n *\n * ## Why Use This\n *\n * - **Non-breaking**: Doesn't change the Result, just performs side effect\n * - **Composable**: Can be inserted anywhere in a pipeline\n * - **Type-preserving**: Returns the same Result type\n * - **Lazy**: Side effect only runs if Result is successful\n *\n * @param r - The Result to tap\n * @param fn - Side effect function called with the success value (return value ignored)\n * @returns The original Result unchanged (for chaining)\n *\n * @example\n * ```typescript\n * // Log success values\n * const logged = tap(result, user => console.log('Got user:', user.name));\n * // logged === result, but console.log was called\n *\n * // Debug in pipeline\n * const debugged = pipe(\n * fetchUser(id),\n * r => tap(r, user => console.log('Fetched:', user)),\n * r => map(r, user => user.name)\n * );\n *\n * // Mutate external state\n * const tracked = tap(result, data => {\n * analytics.track('operation_success', data);\n * });\n * ```\n */\nexport function tap<T, E, C>(\n r: Result<T, E, C>,\n fn: (value: T) => void\n): Result<T, E, C> {\n if (r.ok) fn(r.value);\n return r;\n}\n\n/**\n * Executes a side effect on an error Result without changing it.\n *\n * @remarks When to use: Add side effects (logging, metrics) on Err without changing the Result.\n *\n * ## When to Use\n *\n * Use `tapError()` when:\n * - You need to log, debug, or observe error values\n * - You want to perform side effects on errors in a pipeline\n * - You need to report errors to external systems (logging, monitoring)\n * - You're debugging and want to inspect errors without breaking the chain\n *\n * ## Why Use This\n *\n * - **Non-breaking**: Doesn't change the Result, just performs side effect\n * - **Composable**: Can be inserted anywhere in a pipeline\n * - **Type-preserving**: Returns the same Result type\n * - **Lazy**: Side effect only runs if Result is an error\n *\n * @param r - The Result to tap\n * @param fn - Side effect function called with the error and optional cause (return value ignored)\n * @returns The original Result unchanged (for chaining)\n *\n * @example\n * ```typescript\n * // Log errors\n * const logged = tapError(result, (error, cause) => {\n * console.error('Error:', error, cause);\n * });\n *\n * // Report to error tracking\n * const tracked = tapError(result, (error, cause) => {\n * errorTracker.report(error, cause);\n * });\n *\n * // Debug in pipeline\n * const debugged = pipe(\n * operation(),\n * r => tapError(r, (err, cause) => console.error('Failed:', err)),\n * r => mapError(r, err => 'FORMATTED_ERROR')\n * );\n * ```\n */\nexport function tapError<T, E, C>(\n r: Result<T, E, C>,\n fn: (error: E, cause?: C) => void\n): Result<T, E, C> {\n if (!r.ok) fn(r.error, r.cause);\n return r;\n}\n\n/**\n * Transforms the success value of a Result, catching any errors thrown by the transform.\n *\n * @remarks When to use: Transform Ok values with a function that might throw and capture the failure.\n *\n * ## When to Use\n *\n * Use `mapTry()` when:\n * - Your transform function might throw exceptions\n * - You want to convert transform errors to typed errors\n * - You're working with libraries that throw (e.g., JSON.parse, Date parsing)\n * - You need to handle both Result errors and transform exceptions\n *\n * ## Why Use This Instead of `map`\n *\n * - **Exception-safe**: Catches exceptions from the transform function\n * - **Error mapping**: Converts thrown exceptions to typed errors\n * - **Dual error handling**: Handles both Result errors and transform exceptions\n *\n * @param result - The Result to transform\n * @param transform - Function to transform the success value (may throw exceptions)\n * @param onError - Function to map thrown exceptions to a typed error\n * @returns A Result with:\n * - Transformed value if both Result and transform succeed\n * - Original error if Result was an error\n * - Transform error if transform threw an exception\n *\n * @example\n * ```typescript\n * // Safe JSON parsing\n * const parsed = mapTry(\n * ok('{\"key\": \"value\"}'),\n * JSON.parse,\n * () => 'PARSE_ERROR' as const\n * );\n *\n * // Safe date parsing\n * const date = mapTry(\n * ok('2024-01-01'),\n * str => new Date(str),\n * () => 'INVALID_DATE' as const\n * );\n *\n * // Transform with error details\n * const processed = mapTry(\n * result,\n * value => riskyTransform(value),\n * (cause) => ({ type: 'TRANSFORM_ERROR' as const, cause })\n * );\n * ```\n */\nexport function mapTry<T, U, E, F, C>(\n result: Result<T, E, C>,\n transform: (value: T) => U,\n onError: (cause: unknown) => F\n): Result<U, E | F, C | unknown> {\n if (!result.ok) return result;\n try {\n return ok(transform(result.value));\n } catch (error) {\n return err(onError(error), { cause: error });\n }\n}\n\n/**\n * Transforms the error value of a Result, catching any errors thrown by the transform.\n *\n * @remarks When to use: Transform errors when the mapping might throw and you want that captured.\n *\n * ## When to Use\n *\n * Use `mapErrorTry()` when:\n * - Your error transform function might throw exceptions\n * - You're doing complex error transformations (e.g., string formatting, object construction)\n * - You want to handle both Result errors and transform exceptions\n * - You need to safely normalize error types\n *\n * ## Why Use This Instead of `mapError`\n *\n * - **Exception-safe**: Catches exceptions from the error transform function\n * - **Error mapping**: Converts thrown exceptions to typed errors\n * - **Dual error handling**: Handles both Result errors and transform exceptions\n *\n * @param result - The Result to transform\n * @param transform - Function to transform the error value (may throw exceptions)\n * @param onError - Function to map thrown exceptions to a typed error\n * @returns A Result with:\n * - Original value if Result was successful\n * - Transformed error if both Result was error and transform succeeded\n * - Transform error if transform threw an exception\n *\n * @example\n * ```typescript\n * // Safe error formatting\n * const formatted = mapErrorTry(\n * err('not_found'),\n * e => e.toUpperCase(), // Might throw if e is not a string\n * () => 'FORMAT_ERROR' as const\n * );\n *\n * // Complex error transformation\n * const normalized = mapErrorTry(\n * result,\n * error => ({ type: 'NORMALIZED', message: String(error) }),\n * () => 'TRANSFORM_ERROR' as const\n * );\n * ```\n */\nexport function mapErrorTry<T, E, F, G, C>(\n result: Result<T, E, C>,\n transform: (error: E) => F,\n onError: (cause: unknown) => G\n): Result<T, F | G, C | unknown> {\n if (result.ok) return result;\n try {\n return err(transform(result.error), { cause: result.cause });\n } catch (error) {\n return err(onError(error), { cause: error });\n }\n}\n\n/**\n * Transforms both the success value and error value of a Result simultaneously.\n *\n * ## When to Use\n *\n * Use `bimap()` when:\n * - You need to transform both success and error in one operation\n * - You're normalizing Results to a common format\n * - You want symmetric transformation of both cases\n * - You're building adapters between different Result types\n *\n * ## Why Use This Instead of `map` + `mapError`\n *\n * - **Single operation**: Transforms both cases in one call\n * - **Clearer intent**: Shows you're handling both cases symmetrically\n * - **Less code**: Avoids chaining map and mapError\n *\n * @param r - The Result to transform\n * @param onOk - Function that transforms the success value\n * @param onErr - Function that transforms the error value\n * @returns A new Result with transformed value or transformed error\n *\n * @example\n * ```typescript\n * // Normalize to API response format\n * const response = bimap(\n * fetchUser(id),\n * user => ({ status: 'success', data: user }),\n * error => ({ status: 'error', code: error })\n * );\n *\n * // Transform types\n * const stringified = bimap(\n * parseNumber(input),\n * n => `Value: ${n}`,\n * e => `Error: ${e}`\n * );\n *\n * // Adapt between error types\n * const adapted = bimap(\n * externalResult,\n * value => internalValue(value),\n * error => internalError(error)\n * );\n * ```\n */\nexport function bimap<T, U, E, F, C>(\n r: Result<T, E, C>,\n onOk: (value: T) => U,\n onErr: (error: E) => F\n): Result<U, F, C> {\n return r.ok ? ok(onOk(r.value)) : err(onErr(r.error), { cause: r.cause });\n}\n\n/**\n * Recovers from an error by returning a new Result.\n * Similar to neverthrow's `.orElse()`.\n *\n * @remarks When to use: Recover from Err by returning a fallback Result or retyping the error.\n *\n * ## When to Use\n *\n * Use `orElse()` when:\n * - You want to recover from errors with fallback operations\n * - The recovery might also fail (returns a Result)\n * - You need to chain fallback strategies\n * - You're implementing retry or fallback patterns\n *\n * ## Why Use This\n *\n * - **Fallback chains**: Try alternative operations on failure\n * - **Error recovery**: Convert errors to success with fallback values\n * - **Composable**: Can chain multiple orElse calls for cascading fallbacks\n * - **Type-safe**: TypeScript tracks the error union through recovery\n *\n * @param r - The Result to potentially recover from\n * @param fn - Function that takes the error and returns a new Result (may succeed or fail)\n * @returns The original Result if successful, or the result of the recovery function\n *\n * @example\n * ```typescript\n * // Fallback to default user\n * const user = orElse(\n * fetchUser(id),\n * error => error === 'NOT_FOUND' ? ok(defaultUser) : err(error)\n * );\n *\n * // Try cache, then database, then fail\n * const data = orElse(\n * orElse(\n * fetchFromCache(key),\n * () => fetchFromDatabase(key)\n * ),\n * () => err('DATA_UNAVAILABLE' as const)\n * );\n *\n * // Convert specific errors to success\n * const result = orElse(\n * riskyOperation(),\n * error => error.code === 'RETRY' ? ok(defaultValue) : err(error)\n * );\n * ```\n */\nexport function orElse<T, E, E2, C, C2>(\n r: Result<T, E, C>,\n fn: (error: E, cause?: C) => Result<T, E2, C2>\n): Result<T, E2, C2> {\n return r.ok ? r : fn(r.error, r.cause);\n}\n\n/**\n * Async version of orElse for recovering from errors with async operations.\n *\n * @param r - The Result or AsyncResult to potentially recover from\n * @param fn - Async function that takes the error and returns a new Result\n * @returns Promise of the original Result if successful, or the result of the recovery function\n *\n * @example\n * ```typescript\n * // Try primary API, fall back to secondary\n * const data = await orElseAsync(\n * await fetchFromPrimaryApi(),\n * async (error) => {\n * if (error === 'UNAVAILABLE') {\n * return await fetchFromSecondaryApi();\n * }\n * return err(error);\n * }\n * );\n * ```\n */\nexport async function orElseAsync<T, E, E2, C, C2>(\n r: Result<T, E, C> | Promise<Result<T, E, C>>,\n fn: (error: E, cause?: C) => Result<T, E2, C2> | Promise<Result<T, E2, C2>>\n): Promise<Result<T, E2, C2>> {\n const resolved = await r;\n return resolved.ok ? resolved : fn(resolved.error, resolved.cause);\n}\n\n/**\n * Recovers from an error by returning a plain value (not a Result).\n * Useful when you want to provide a default value on error.\n *\n * ## When to Use\n *\n * Use `recover()` when:\n * - You want to provide a fallback value on error\n * - Recovery cannot fail (unlike orElse which returns a Result)\n * - You're implementing default value patterns\n * - You want to guarantee a successful Result\n *\n * ## Why Use This Instead of `orElse`\n *\n * - **Simpler**: Recovery function returns plain value, not Result\n * - **Guaranteed success**: Always returns ok() after recovery\n * - **Clearer intent**: Shows recovery cannot fail\n *\n * @param r - The Result to potentially recover from\n * @param fn - Function that takes the error and returns a recovery value\n * @returns The original Result if successful, or ok(recoveryValue) if error\n *\n * @example\n * ```typescript\n * // Provide default user on NOT_FOUND\n * const user = recover(\n * fetchUser(id),\n * error => error === 'NOT_FOUND' ? defaultUser : guestUser\n * );\n *\n * // Convert all errors to default\n * const config = recover(\n * loadConfig(),\n * () => defaultConfig\n * );\n *\n * // Recover with error-based defaults\n * const value = recover(\n * parseNumber(input),\n * error => error === 'EMPTY' ? 0 : -1\n * );\n * ```\n */\nexport function recover<T, E, C>(\n r: Result<T, E, C>,\n fn: (error: E, cause?: C) => T\n): Ok<T> {\n return r.ok ? ok(r.value) : ok(fn(r.error, r.cause));\n}\n\n/**\n * Async version of recover for recovering with async operations.\n *\n * @param r - The Result or AsyncResult to potentially recover from\n * @param fn - Async function that takes the error and returns a recovery value\n * @returns Promise of ok(value) - either original or recovered\n *\n * @example\n * ```typescript\n * // Recover by fetching default from API\n * const user = await recoverAsync(\n * await fetchUser(id),\n * async (error) => await fetchDefaultUser()\n * );\n * ```\n */\nexport async function recoverAsync<T, E, C>(\n r: Result<T, E, C> | Promise<Result<T, E, C>>,\n fn: (error: E, cause?: C) => T | Promise<T>\n): Promise<Ok<T>> {\n const resolved = await r;\n if (resolved.ok) return ok(resolved.value);\n return ok(await fn(resolved.error, resolved.cause));\n}\n\n// =============================================================================\n// Result Hydration (Serialization)\n// =============================================================================\n\n/**\n * Validates and type-narrows a value to a Result.\n *\n * Since this library uses plain objects for Results, serialization is trivial -\n * the serialized form IS the Result. This function validates the structure and\n * provides type-safe narrowing.\n *\n * ## When to Use\n *\n * Use `hydrate()` when:\n * - Receiving Results over RPC/network\n * - Deserializing Results from storage\n * - Validating untrusted data as Results\n *\n * @param value - The unknown value to validate as a Result\n * @returns The value as a typed Result, or null if invalid\n *\n * @example\n * ```typescript\n * // Deserialize from JSON\n * const parsed = JSON.parse(jsonString);\n * const result = hydrate<User, ApiError>(parsed);\n * if (result) {\n * // result is Result<User, ApiError>\n * }\n *\n * // Validate RPC response\n * const rpcResponse = await fetchFromService();\n * const result = hydrate<Data, ServiceError>(rpcResponse);\n * ```\n */\nexport function hydrate<T, E, C = unknown>(value: unknown): Result<T, E, C> | null {\n if (\n value !== null &&\n typeof value === \"object\" &&\n \"ok\" in value &&\n typeof value.ok === \"boolean\"\n ) {\n if (value.ok === true && \"value\" in value) {\n return value as Result<T, E, C>;\n }\n if (value.ok === false && \"error\" in value) {\n return value as Result<T, E, C>;\n }\n }\n return null;\n}\n\n/**\n * Type guard to check if a value is a valid serialized Result.\n *\n * @param value - The value to check\n * @returns True if the value is a valid Result structure\n *\n * @example\n * ```typescript\n * if (isSerializedResult(data)) {\n * // data is Result<unknown, unknown, unknown>\n * if (data.ok) {\n * console.log(data.value);\n * }\n * }\n * ```\n */\nexport function isSerializedResult(\n value: unknown\n): value is Result<unknown, unknown, unknown> {\n return hydrate(value) !== null;\n}\n\n// =============================================================================\n// Batch Operations\n// =============================================================================\n\ntype AllValues<T extends readonly Result<unknown, unknown, unknown>[]> = {\n [K in keyof T]: T[K] extends Ok<infer V>\n ? V\n : T[K] extends Err<unknown, unknown>\n ? never\n : T[K] extends Result<infer V, unknown, unknown>\n ? V\n : never;\n};\ntype AllErrors<T extends readonly Result<unknown, unknown, unknown>[]> = {\n [K in keyof T]: T[K] extends Ok<unknown>\n ? never\n : T[K] extends Err<infer E, unknown>\n ? E\n : T[K] extends Result<unknown, infer E, unknown>\n ? E\n : never;\n}[number];\ntype AllCauses<T extends readonly Result<unknown, unknown, unknown>[]> = {\n [K in keyof T]: T[K] extends Ok<unknown>\n ? never\n : T[K] extends Err<unknown, infer C>\n ? C\n : T[K] extends Result<unknown, unknown, infer C>\n ? C\n : never;\n}[number];\n\n// Conditional type: returns Ok<...> when there are no errors, Result<...> otherwise\n// Note: We only check AllErrors, not AllCauses - causes only matter when there are errors\ntype AllResult<T extends readonly Result<unknown, unknown, unknown>[]> =\n [AllErrors<T>] extends [never]\n ? Ok<AllValues<T>>\n : Result<AllValues<T>, AllErrors<T>, AllCauses<T>>;\n\n/**\n * Combines multiple Results into one, requiring all to succeed.\n *\n * ## When to Use\n *\n * Use `all()` when:\n * - You have multiple independent operations that all must succeed\n * - You want to short-circuit on the first error (fail-fast)\n * - You need all values together (e.g., combining API responses)\n * - Performance matters (stops on first error, doesn't wait for all)\n *\n * ## Why Use This\n *\n * - **Fail-fast**: Stops immediately on first error (better performance)\n * - **Type-safe**: TypeScript infers the array type from input\n * - **Short-circuit**: Doesn't evaluate remaining Results after error\n * - **Composable**: Can be chained with other operations\n *\n * ## Important\n *\n * - **Short-circuits**: Returns first error immediately, doesn't wait for all Results\n * - **All must succeed**: If any Result fails, the entire operation fails\n * - **Use `allSettled`**: If you need to collect all errors (e.g., form validation)\n *\n * @param results - Array of Results to combine (all must succeed)\n * @returns A Result with an array of all success values, or the first error encountered\n *\n * @example\n * ```typescript\n * // Combine multiple successful Results\n * const combined = all([Awaitly.ok(1), Awaitly.ok(2), Awaitly.ok(3)]);\n * // combined: { ok: true, value: [1, 2, 3] }\n *\n * // Short-circuits on first error\n * const error = all([Awaitly.ok(1), Awaitly.err('ERROR'), Awaitly.ok(3)]);\n * // error: { ok: false, error: 'ERROR' }\n * // Note: Awaitly.ok(3) is never evaluated\n *\n * // Combine API responses\n * const data = all([\n * fetchUser(id),\n * fetchPosts(id),\n * fetchComments(id)\n * ]);\n * // data.value: [user, posts, comments] if all succeed\n * ```\n */\nexport function all<const T extends readonly Result<unknown, unknown, unknown>[]>(\n results: T\n): AllResult<T> {\n const values: unknown[] = [];\n for (const result of results) {\n if (!result.ok) {\n return result as unknown as AllResult<T>;\n }\n values.push(result.value);\n }\n return ok(values) as AllResult<T>;\n}\n\n/**\n * Combines multiple Results or Promises of Results into one (async version of `all`).\n *\n * ## When to Use\n *\n * Use `allAsync()` when:\n * - You have multiple async operations that all must succeed\n * - You want to run operations in parallel (better performance)\n * - You want to short-circuit on the first error (fail-fast)\n * - You need all values together from parallel operations\n *\n * ## Why Use This Instead of `all`\n *\n * - **Parallel execution**: All Promises start immediately (faster)\n * - **Async support**: Works with Promises and AsyncResults\n * - **Promise rejection handling**: Converts Promise rejections to `PromiseRejectedError`\n *\n * ## Important\n *\n * - **Short-circuits**: Returns first error immediately, cancels remaining operations\n * - **Parallel**: All operations start simultaneously (unlike sequential `andThen`)\n * - **Use `allSettledAsync`**: If you need to collect all errors\n *\n * @param results - Array of Results or Promises of Results to combine (all must succeed)\n * @returns A Promise resolving to a Result with an array of all success values, or the first error\n *\n * @example\n * ```typescript\n * // Parallel API calls\n * const combined = await allAsync([\n * fetchUser('1'),\n * fetchPosts('1'),\n * fetchComments('1')\n * ]);\n * // All three calls start simultaneously\n * // combined: { ok: true, value: [user, posts, comments] } if all succeed\n *\n * // Mix Results and Promises\n * const data = await allAsync([\n * ok(cachedUser), // Already resolved\n * fetchPosts(userId), // Promise\n * ]);\n * ```\n */\nexport async function allAsync<\n const T extends readonly (Result<unknown, unknown, unknown> | Promise<Result<unknown, unknown, unknown>>)[]\n>(\n results: T\n): Promise<\n Result<\n { [K in keyof T]: T[K] extends Result<infer V, unknown, unknown> | Promise<Result<infer V, unknown, unknown>> ? V : never },\n { [K in keyof T]: T[K] extends Result<unknown, infer E, unknown> | Promise<Result<unknown, infer E, unknown>> ? E : never }[number] | PromiseRejectedError,\n { [K in keyof T]: T[K] extends Result<unknown, unknown, infer C> | Promise<Result<unknown, unknown, infer C>> ? C : never }[number] | PromiseRejectionCause\n >\n> {\n type Values = { [K in keyof T]: T[K] extends Result<infer V, unknown, unknown> | Promise<Result<infer V, unknown, unknown>> ? V : never };\n type Errors = { [K in keyof T]: T[K] extends Result<unknown, infer E, unknown> | Promise<Result<unknown, infer E, unknown>> ? E : never }[number] | PromiseRejectedError;\n type Causes = { [K in keyof T]: T[K] extends Result<unknown, unknown, infer C> | Promise<Result<unknown, unknown, infer C>> ? C : never }[number] | PromiseRejectionCause;\n\n if (results.length === 0) {\n return ok([]) as Result<Values, Errors, Causes>;\n }\n\n return new Promise((resolve) => {\n let settled = false;\n let pendingCount = results.length;\n const values: unknown[] = new Array(results.length);\n\n for (let i = 0; i < results.length; i++) {\n const index = i;\n Promise.resolve(results[index])\n .catch((reason) => err(\n { type: \"PROMISE_REJECTED\" as const, cause: reason },\n { cause: { type: \"PROMISE_REJECTION\" as const, reason } as PromiseRejectionCause }\n ))\n .then((result) => {\n if (settled) return;\n\n if (!result.ok) {\n settled = true;\n resolve(result as Result<Values, Errors, Causes>);\n return;\n }\n\n values[index] = result.value;\n pendingCount--;\n\n if (pendingCount === 0) {\n resolve(ok(values) as Result<Values, Errors, Causes>);\n }\n });\n }\n });\n}\n\nexport type SettledError<E, C = unknown> = { error: E; cause?: C };\n\n// Conditional type: returns Ok<...> when there are no errors, Result<...> otherwise\ntype AllSettledResult<T extends readonly Result<unknown, unknown, unknown>[]> =\n [AllErrors<T>] extends [never]\n ? Ok<AllValues<T>>\n : Result<AllValues<T>, SettledError<AllErrors<T>, AllCauses<T>>[]>;\n\n/**\n * Combines multiple Results, collecting all errors instead of short-circuiting.\n *\n * ## When to Use\n *\n * Use `allSettled()` when:\n * - You need to see ALL errors, not just the first one\n * - You're doing form validation (show all field errors)\n * - You want to collect partial results (some succeed, some fail)\n * - You need to process all Results regardless of failures\n *\n * ## Why Use This Instead of `all`\n *\n * - **Collects all errors**: Returns array of all errors, not just first\n * - **No short-circuit**: Evaluates all Results even if some fail\n * - **Partial success**: Can see which operations succeeded and which failed\n * - **Better UX**: Show users all validation errors at once\n *\n * ## Important\n *\n * - **No short-circuit**: All Results are evaluated (slower if many fail early)\n * - **Error array**: Returns array of `{ error, cause }` objects, not single error\n * - **Use `all`**: If you want fail-fast behavior (better performance)\n *\n * @param results - Array of Results to combine (all are evaluated)\n * @returns A Result with:\n * - Array of all success values if all succeed\n * - Array of `{ error, cause }` objects if any fail\n *\n * @example\n * ```typescript\n * // Form validation - show all errors\n * const validated = allSettled([\n * validateEmail(email),\n * validatePassword(password),\n * validateAge(age),\n * ]);\n * // If email and password fail:\n * // { ok: false, error: [\n * // { error: 'INVALID_EMAIL' },\n * // { error: 'WEAK_PASSWORD' }\n * // ]}\n *\n * // Collect partial results\n * const results = allSettled([\n * fetchUser('1'), // succeeds\n * fetchUser('2'), // fails\n * fetchUser('3'), // succeeds\n * ]);\n * // Can see which succeeded and which failed\n * ```\n */\nexport function allSettled<const T extends readonly Result<unknown, unknown, unknown>[]>(\n results: T\n): AllSettledResult<T> {\n const values: unknown[] = [];\n const errors: SettledError<unknown>[] = [];\n\n for (const result of results) {\n if (result.ok) {\n values.push(result.value);\n } else {\n errors.push({ error: result.error, cause: result.cause });\n }\n }\n\n if (errors.length > 0) {\n return err(errors) as unknown as AllSettledResult<T>;\n }\n\n return ok(values) as unknown as AllSettledResult<T>;\n}\n\n/**\n * Splits an array of Results into separate arrays of success values and errors.\n *\n * ## When to Use\n *\n * Use `partition()` when:\n * - You have an array of Results and need to separate successes from failures\n * - You want to process successes and errors separately\n * - You're collecting results from multiple operations (some may fail)\n * - You need to handle partial success scenarios\n *\n * ## Why Use This\n *\n * - **Simple separation**: One call splits successes and errors\n * - **Type-safe**: TypeScript knows `values` is `T[]` and `errors` is `E[]`\n * - **No unwrapping**: Doesn't require manual `if (r.ok)` checks\n * - **Preserves order**: Maintains original array order in both arrays\n *\n * ## Common Pattern\n *\n * Often used after `Promise.all()` with Results:\n * ```typescript\n * const results = await Promise.all(ids.map(id => fetchUser(id)));\n * const { values: users, errors } = partition(results);\n * // Process successful users, handle errors separately\n * ```\n *\n * @param results - Array of Results to partition\n * @returns An object with:\n * - `values`: Array of all success values (type `T[]`)\n * - `errors`: Array of all error values (type `E[]`)\n *\n * @example\n * ```typescript\n * // Split successes and errors\n * const results = [ok(1), err('ERROR_1'), ok(3), err('ERROR_2')];\n * const { values, errors } = partition(results);\n * // values: [1, 3]\n * // errors: ['ERROR_1', 'ERROR_2']\n *\n * // Process batch operations\n * const userResults = await Promise.all(userIds.map(id => fetchUser(id)));\n * const { values: users, errors: fetchErrors } = partition(userResults);\n *\n * // Process successful users\n * users.forEach(user => processUser(user));\n *\n * // Handle errors\n * fetchErrors.forEach(error => logError(error));\n * ```\n */\nexport function partition<T, E, C>(\n results: readonly Result<T, E, C>[]\n): { values: T[]; errors: E[] } {\n const values: T[] = [];\n const errors: E[] = [];\n\n for (const result of results) {\n if (result.ok) {\n values.push(result.value);\n } else {\n errors.push(result.error);\n }\n }\n\n return { values, errors };\n}\n\ntype AnyValue<T extends readonly Result<unknown, unknown, unknown>[]> =\n T[number] extends Result<infer U, unknown, unknown> ? U : never;\ntype AnyErrors<T extends readonly Result<unknown, unknown, unknown>[]> = {\n -readonly [K in keyof T]: T[K] extends Result<unknown, infer E, unknown> ? E : never;\n}[number];\ntype AnyCauses<T extends readonly Result<unknown, unknown, unknown>[]> = {\n -readonly [K in keyof T]: T[K] extends Result<unknown, unknown, infer C> ? C : never;\n}[number];\n\n/**\n * Returns the first successful Result from an array (succeeds fast).\n *\n * ## When to Use\n *\n * Use `any()` when:\n * - You have multiple fallback options and need the first that succeeds\n * - You're trying multiple strategies (e.g., cache → DB → API)\n * - You want fail-fast success (stops on first success)\n * - You have redundant data sources and any one will do\n *\n * ## Why Use This\n *\n * - **Succeeds fast**: Returns immediately on first success (better performance)\n * - **Fallback pattern**: Perfect for trying multiple options\n * - **Short-circuits**: Stops evaluating after first success\n * - **Type-safe**: TypeScript infers the success type\n *\n * ## Important\n *\n * - **First success wins**: Returns first successful Result, ignores rest\n * - **All errors**: If all fail, returns first error (not all errors)\n * - **Empty array**: Returns `EmptyInputError` if array is empty\n * - **Use `all`**: If you need ALL to succeed\n *\n * @param results - Array of Results to check (evaluated in order)\n * @returns The first successful Result, or first error if all fail, or `EmptyInputError` if empty\n *\n * @example\n * ```typescript\n * // Try multiple fallback strategies\n * const data = any([\n * fetchFromCache(id),\n * fetchFromDB(id),\n * fetchFromAPI(id)\n * ]);\n * // Returns first that succeeds\n *\n * // Try multiple formats\n * const parsed = any([\n * parseJSON(input),\n * parseXML(input),\n * parseYAML(input)\n * ]);\n *\n * // All errors case\n * const allErrors = any([err('A'), err('B'), err('C')]);\n * // allErrors: { ok: false, error: 'A' } (first error)\n * ```\n */\nexport function any<const T extends readonly Result<unknown, unknown, unknown>[]>(\n results: T\n): Result<AnyValue<T>, AnyErrors<T> | EmptyInputError, AnyCauses<T>> {\n type ReturnErr = Result<never, AnyErrors<T> | EmptyInputError, AnyCauses<T>>;\n type ReturnOk = Result<AnyValue<T>, never, AnyCauses<T>>;\n\n if (results.length === 0) {\n return err({\n type: \"EMPTY_INPUT\",\n message: \"any() requires at least one Result\",\n }) as ReturnErr;\n }\n let firstError: Result<never, unknown, unknown> | null = null;\n for (const result of results) {\n if (result.ok) return result as ReturnOk;\n if (!firstError) firstError = result;\n }\n return firstError as ReturnErr;\n}\n\ntype AnyAsyncValue<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> =\n Awaited<T[number]> extends Result<infer U, unknown, unknown> ? U : never;\ntype AnyAsyncErrors<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {\n -readonly [K in keyof T]: Awaited<T[K]> extends Result<unknown, infer E, unknown>\n ? E\n : never;\n}[number];\ntype AnyAsyncCauses<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {\n -readonly [K in keyof T]: Awaited<T[K]> extends Result<unknown, unknown, infer C>\n ? C\n : never;\n}[number];\n\n/**\n * Returns the first successful Result from an array of Results or Promises (async version of `any`).\n *\n * ## When to Use\n *\n * Use `anyAsync()` when:\n * - You have multiple async fallback options and need the first that succeeds\n * - You're trying multiple async strategies in parallel (cache → DB → API)\n * - You want fail-fast success from parallel operations\n * - You have redundant async data sources and any one will do\n *\n * ## Why Use This Instead of `any`\n *\n * - **Parallel execution**: All Promises start immediately (faster)\n * - **Async support**: Works with Promises and AsyncResults\n * - **Promise rejection handling**: Converts Promise rejections to `PromiseRejectedError`\n *\n * ## Important\n *\n * - **First success wins**: Returns first successful Result (from any Promise)\n * - **Parallel**: All operations run simultaneously\n * - **All errors**: If all fail, returns first error encountered\n *\n * @param results - Array of Results or Promises of Results to check (all start in parallel)\n * @returns A Promise resolving to the first successful Result, or first error if all fail\n *\n * @example\n * ```typescript\n * // Try multiple async fallbacks in parallel\n * const data = await anyAsync([\n * fetchFromCache(id), // Fastest wins\n * fetchFromDB(id),\n * fetchFromAPI(id)\n * ]);\n *\n * // Try multiple API endpoints\n * const response = await anyAsync([\n * fetch('/api/v1/data'),\n * fetch('/api/v2/data'),\n * fetch('/backup-api/data')\n * ]);\n * ```\n */\nexport async function anyAsync<\n const T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[],\n>(\n results: T\n): Promise<\n Result<AnyAsyncValue<T>, AnyAsyncErrors<T> | EmptyInputError | PromiseRejectedError, AnyAsyncCauses<T> | PromiseRejectionCause>\n> {\n type ReturnErr = Result<\n never,\n AnyAsyncErrors<T> | EmptyInputError | PromiseRejectedError,\n AnyAsyncCauses<T> | PromiseRejectionCause\n >;\n type ReturnOk = Result<AnyAsyncValue<T>, never, AnyAsyncCauses<T>>;\n\n if (results.length === 0) {\n return err({\n type: \"EMPTY_INPUT\",\n message: \"anyAsync() requires at least one Result\",\n }) as ReturnErr;\n }\n\n return new Promise((resolve) => {\n let settled = false;\n let pendingCount = results.length;\n let firstError: Result<never, unknown, unknown> | null = null;\n\n for (const item of results) {\n Promise.resolve(item)\n .catch((reason) =>\n err(\n { type: \"PROMISE_REJECTED\" as const, cause: reason },\n { cause: { type: \"PROMISE_REJECTION\" as const, reason } as PromiseRejectionCause }\n )\n )\n .then((result) => {\n if (settled) return;\n\n if (result.ok) {\n settled = true;\n resolve(result as ReturnOk);\n return;\n }\n\n if (!firstError) firstError = result;\n pendingCount--;\n\n if (pendingCount === 0) {\n resolve(firstError as ReturnErr);\n }\n });\n }\n });\n}\n\ntype AllAsyncValues<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {\n [K in keyof T]: Awaited<T[K]> extends Result<infer V, unknown, unknown> ? V : never;\n};\ntype AllAsyncErrors<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {\n [K in keyof T]: Awaited<T[K]> extends Result<unknown, infer E, unknown> ? E : never;\n}[number];\ntype AllAsyncCauses<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {\n [K in keyof T]: Awaited<T[K]> extends Result<unknown, unknown, infer C> ? C : never;\n}[number];\n\n/**\n * Combines multiple Results or Promises of Results, collecting all errors (async version of `allSettled`).\n *\n * ## When to Use\n *\n * Use `allSettledAsync()` when:\n * - You have multiple async operations and need ALL errors reported\n * - You're doing async form validation (show all field errors at once)\n * - You want to run operations in parallel and collect all results\n *\n * ## Behavior\n *\n * **Note:** Unlike `Promise.allSettled()`, this returns a Result:\n * - `ok(values[])` if ALL succeed\n * - `err(SettledError[])` if ANY fail (with all collected errors)\n *\n * This is consistent with awaitly's philosophy - all functions return Results.\n * `Promise.allSettled()` always succeeds with per-item status objects; this function\n * returns a single Result indicating overall success or failure.\n *\n * ## Why Use This Instead of `allSettled`\n *\n * - **Parallel execution**: All Promises start immediately (faster)\n * - **Async support**: Works with Promises and AsyncResults\n * - **Promise rejection handling**: Converts Promise rejections to `PromiseRejectedError`\n *\n * ## Important\n *\n * - **No short-circuit**: All operations complete (even if some fail)\n * - **Parallel**: All operations run simultaneously\n * - **Error array**: Returns array of `SettledError` objects (`{ error, cause? }`)\n *\n * @param results - Array of Results or Promises of Results to combine (all are evaluated)\n * @returns A Promise resolving to a Result with:\n * - `ok(values[])` - Array of all success values if ALL succeed\n * - `err(errors[])` - Array of `SettledError` objects if ANY fail\n *\n * @example\n * ```typescript\n * // Async form validation - see all errors at once\n * const validated = await allSettledAsync([\n * validateEmailAsync(email),\n * validatePasswordAsync(password),\n * checkUsernameAvailableAsync(username),\n * ]);\n *\n * if (!validated.ok) {\n * // validated.error is array of all validation failures\n * console.log('Errors:', validated.error.map(e => e.error));\n * }\n *\n * // Parallel API calls with error collection\n * const results = await allSettledAsync([\n * fetchUser('1'),\n * fetchUser('2'),\n * fetchUser('3'),\n * ]);\n * ```\n */\nexport async function allSettledAsync<\n const T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[],\n>(\n results: T\n): Promise<Result<AllAsyncValues<T>, SettledError<AllAsyncErrors<T> | PromiseRejectedError, AllAsyncCauses<T> | PromiseRejectionCause>[]>> {\n const settled = await Promise.all(\n results.map((item) =>\n Promise.resolve(item)\n .then((result) => ({ status: \"result\" as const, result }))\n .catch((reason) => ({\n status: \"rejected\" as const,\n error: { type: \"PROMISE_REJECTED\" as const, cause: reason } as PromiseRejectedError,\n cause: { type: \"PROMISE_REJECTION\" as const, reason } as PromiseRejectionCause,\n }))\n )\n );\n\n const values: unknown[] = [];\n const errors: SettledError<unknown, unknown>[] = [];\n\n for (const item of settled) {\n if (item.status === \"rejected\") {\n errors.push({ error: item.error, cause: item.cause });\n } else if (item.result.ok) {\n values.push(item.result.value);\n } else {\n errors.push({ error: item.result.error, cause: item.result.cause });\n }\n }\n\n if (errors.length > 0) {\n return err(errors) as unknown as Result<AllAsyncValues<T>, SettledError<AllAsyncErrors<T> | PromiseRejectedError, AllAsyncCauses<T> | PromiseRejectionCause>[]>;\n }\n return ok(values) as unknown as Result<AllAsyncValues<T>, SettledError<AllAsyncErrors<T> | PromiseRejectedError, AllAsyncCauses<T> | PromiseRejectionCause>[]>;\n}\n\n/**\n * Combines two Results into a tuple Result.\n *\n * ## When to Use\n *\n * Use `zip()` when:\n * - You have two independent Results and need both values together\n * - You want to combine validation results before processing\n * - You need a pair/tuple from two separate operations\n *\n * ## Why Use This Instead of `all()`\n *\n * - **Simpler types**: Returns `[A, B]` instead of array inference\n * - **Two-argument**: Cleaner API for common case of combining two Results\n * - **Compose with andThen**: Chain multiple zips for complex combinations\n *\n * ## Important\n *\n * - **Short-circuits**: Returns first error if either fails\n * - **Order matters**: If both fail, returns error from first argument\n * - **Use `all()`**: For more than 2 Results\n *\n * @param a - First Result\n * @param b - Second Result\n * @returns A Result containing a tuple `[A, B]` if both succeed, or the first error\n *\n * @example\n * ```typescript\n * // Combine two Results\n * const userResult = await fetchUser('1');\n * const postsResult = await fetchPosts('1');\n * const combined = zip(userResult, postsResult);\n * // combined: Result<[User, Post[]], UserError | PostsError>\n *\n * // Use with andThen for chaining\n * const result = andThen(\n * zip(fetchUser('1'), fetchPosts('1')),\n * ([user, posts]) => createDashboard(user, posts)\n * );\n *\n * // Validation combination\n * const validated = zip(\n * validateEmail(email),\n * validatePassword(password)\n * );\n * if (validated.ok) {\n * const [email, password] = validated.value;\n * createAccount(email, password);\n * }\n * ```\n */\nexport function zip<A, EA, CA, B, EB, CB>(\n a: Result<A, EA, CA>,\n b: Result<B, EB, CB>\n): Result<[A, B], EA | EB, CA | CB> {\n if (!a.ok) return a as Result<never, EA, CA>;\n if (!b.ok) return b as Result<never, EB, CB>;\n return ok([a.value, b.value]) as Result<[A, B], never, never>;\n}\n\n/**\n * Async version of `zip()` - combines two Results or Promises of Results into a tuple.\n *\n * ## When to Use\n *\n * Use `zipAsync()` when:\n * - You have two async operations and need both results together\n * - You want to run two fetches in parallel and combine results\n * - You need to combine Promises of Results into a single Result\n *\n * ## Why Use This Instead of `allAsync()`\n *\n * - **Simpler types**: Returns `[A, B]` instead of array inference\n * - **Two-argument**: Cleaner API for common case of combining two async Results\n * - **Parallel execution**: Both Promises start immediately\n *\n * ## Important\n *\n * - **Parallel**: Both operations run simultaneously (faster than sequential)\n * - **Short-circuits result**: Returns first argument's error if it fails, else second's\n * - **Waits for both**: Both Promises complete before returning (unlike `allAsync` fail-fast)\n * - **Rejection handling**: Promise rejections are wrapped as `PromiseRejectedError`\n * - **Use `allAsync()`**: For more than 2 Results\n *\n * @param a - First Result or Promise of Result\n * @param b - Second Result or Promise of Result\n * @returns A Promise of Result containing a tuple `[A, B]` if both succeed\n *\n * @example\n * ```typescript\n * // Parallel async operations\n * const result = await zipAsync(\n * fetchUser('1'),\n * fetchPosts('1')\n * );\n * // Both fetches run in parallel\n * // result: Result<[User, Post[]], UserError | PostsError>\n *\n * // Mix sync and async\n * const combined = await zipAsync(\n * ok({ cached: true }), // Already resolved\n * fetchFromAPI(id), // Async fetch\n * );\n *\n * // With chaining\n * const dashboard = await zipAsync(fetchUser('1'), fetchPosts('1'))\n * .then(result => andThen(result, ([user, posts]) => createDashboard(user, posts)));\n * ```\n */\nexport async function zipAsync<A, EA, CA, B, EB, CB>(\n a: Result<A, EA, CA> | Promise<Result<A, EA, CA>>,\n b: Result<B, EB, CB> | Promise<Result<B, EB, CB>>\n): AsyncResult<[A, B], EA | EB | PromiseRejectedError, CA | CB | PromiseRejectionCause> {\n // Wrap rejections into PromiseRejectedError (consistent with allAsync)\n const wrapRejection = <T, E, C>(\n p: Result<T, E, C> | Promise<Result<T, E, C>>\n ): Promise<Result<T, E | PromiseRejectedError, C | PromiseRejectionCause>> =>\n Promise.resolve(p).catch((reason) =>\n err(\n { type: \"PROMISE_REJECTED\" as const, cause: reason } as PromiseRejectedError,\n { cause: { type: \"PROMISE_REJECTION\" as const, reason } as PromiseRejectionCause }\n )\n );\n\n const [ra, rb] = await Promise.all([wrapRejection(a), wrapRejection(b)]);\n return zip(ra, rb);\n}\n","/**\n * Type guards for workflow events and errors.\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type { WorkflowCancelledError, PendingApproval, ApprovalRejected, PendingHook, ResumeState } from \"./types\";\n\n/**\n * Type guard to check if an event is a step_complete event.\n * Use this to filter events for state persistence.\n *\n * @param event - The workflow event to check\n * @returns `true` if the event is a step_complete event, `false` otherwise\n *\n * @example\n * ```typescript\n * const savedSteps = new Map<string, Result<unknown, unknown>>();\n *\n * const workflow = createWorkflow({ fetchUser }, {\n * onEvent: (event) => {\n * if (isStepComplete(event)) {\n * savedSteps.set(event.stepKey, event.result);\n * }\n * }\n * });\n * ```\n */\n/**\n * Type guard for runtime ResumeState (steps is a Map). Use to discriminate from WorkflowSnapshot when loading.\n */\nexport function isResumeState(x: unknown): x is ResumeState {\n return (\n typeof x === \"object\" &&\n x !== null &&\n \"steps\" in x &&\n (x as ResumeState).steps instanceof Map\n );\n}\n\nexport function isStepComplete(\n event: WorkflowEvent<unknown>\n): event is Extract<WorkflowEvent<unknown>, { type: \"step_complete\" }> {\n return event.type === \"step_complete\";\n}\n\n/**\n * Type guard to check if an error is a WorkflowCancelledError.\n *\n * @param error - The error to check\n * @returns `true` if the error is a WorkflowCancelledError, `false` otherwise\n */\nexport function isWorkflowCancelled(error: unknown): error is WorkflowCancelledError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as WorkflowCancelledError).type === \"WORKFLOW_CANCELLED\"\n );\n}\n\n/**\n * Type guard to check if an error is a PendingApproval.\n *\n * @param error - The error to check\n * @returns `true` if the error is a PendingApproval, `false` otherwise\n *\n * @example\n * ```typescript\n * const result = await workflow(...);\n * if (!result.ok && isPendingApproval(result.error)) {\n * console.log(`Waiting for approval: ${result.error.stepKey}`);\n * }\n * ```\n */\nexport function isPendingApproval(error: unknown): error is PendingApproval {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as PendingApproval).type === \"PENDING_APPROVAL\"\n );\n}\n\n/**\n * Type guard to check if an error is an ApprovalRejected.\n *\n * @param error - The error to check\n * @returns `true` if the error is an ApprovalRejected, `false` otherwise\n */\nexport function isApprovalRejected(error: unknown): error is ApprovalRejected {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as ApprovalRejected).type === \"APPROVAL_REJECTED\"\n );\n}\n\n/**\n * Type guard to check if an error is a PendingHook.\n *\n * @param error - The error to check\n * @returns `true` if the error is a PendingHook, `false` otherwise\n */\nexport function isPendingHook(error: unknown): error is PendingHook {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as PendingHook).type === \"PENDING_HOOK\"\n );\n}\n","/**\n * awaitly/persistence\n *\n * Simplified Persistence API for workflow snapshots.\n * Provides JSON-serializable snapshot format and store adapters.\n */\n\nimport type { Result } from \"./core\";\nimport type { StepCache } from \"./workflow\";\n\n// =============================================================================\n// JSON-Safe Type Enforcement\n// =============================================================================\n\n/**\n * Enforce JSON-safety at type level.\n * Only allows values that can be safely serialized with JSON.stringify.\n */\nexport type JSONValue =\n | null\n | boolean\n | number\n | string\n | JSONValue[]\n | { [k: string]: JSONValue };\n\n// =============================================================================\n// WorkflowSnapshot Types (Simplified API)\n// =============================================================================\n\n/**\n * Canonical error wire format - handles both Error instances and thrown non-Errors.\n * This is the single source of truth for serialized errors in snapshots.\n */\nexport type SerializedCause =\n | { type: \"error\"; name: string; message: string; stack?: string; cause?: SerializedCause }\n | { type: \"thrown\"; originalType?: string; value?: JSONValue; stringRepresentation: string; truncated?: true };\n\n/**\n * Single source of truth for step outcome (no error/cause confusion).\n * Uses discriminated union with `ok` field.\n */\nexport type StepResult =\n | { ok: true; value: JSONValue }\n | { ok: false; error: JSONValue; cause: SerializedCause; meta?: { origin: \"result\" | \"throw\" } };\n\n/**\n * JSON-serializable workflow snapshot.\n * Designed to be passed directly to JSON.stringify without special handling.\n *\n * @example\n * ```typescript\n * // Persist\n * localStorage.setItem('wf-123', JSON.stringify(wf.getSnapshot()));\n *\n * // Restore (safe pattern - storage can be empty/corrupt)\n * const raw = localStorage.getItem('wf-123');\n * const snapshot = raw ? JSON.parse(raw) : null;\n * createWorkflow(deps, { snapshot }); // null = fresh start\n * ```\n */\nexport interface WorkflowSnapshot {\n /** Snapshot format version (literal type - bump when shape changes) */\n formatVersion: 1;\n /** Workflow name (from createWorkflow first argument). */\n workflowName?: string;\n /** Step results keyed by step ID. Uses Object.create(null) internally. */\n steps: Record<string, StepResult>;\n /** Execution state metadata */\n execution: {\n status: \"running\" | \"completed\" | \"failed\";\n /** ISO timestamp (UTC toISOString()) */\n lastUpdated: string;\n /** ISO timestamp if finished */\n completedAt?: string;\n /**\n * For paused/running workflows: the step key of the current step.\n * Aligns with Workflow Diagram DSL step state ids (see awaitly/workflow diagram-dsl)\n * so visualizers can highlight the current node.\n */\n currentStepId?: string;\n };\n /** Optional metadata for workflow identification and replay */\n metadata?: {\n /** Detect wrong snapshot for wrong workflow */\n workflowId?: string;\n /** Optional: detect definition changes (user-supplied, advisory only) */\n definitionHash?: string;\n /** Original input for replay */\n input?: JSONValue;\n [key: string]: JSONValue | undefined;\n };\n /** Warnings for lossy serialization (keeps step results pure) */\n warnings?: Array<{\n type: \"lossy_value\";\n stepId: string;\n path: string;\n reason: \"non-json\" | \"circular\" | \"encode-failed\";\n }>;\n}\n\n/**\n * Warning entry for lossy value serialization.\n */\nexport type SnapshotWarning = NonNullable<WorkflowSnapshot[\"warnings\"]>[number];\n\n// =============================================================================\n// Snapshot Validation\n// =============================================================================\n\n/**\n * Error thrown when snapshot structure is invalid.\n */\nexport class SnapshotFormatError extends Error {\n constructor(\n message: string,\n public readonly errors: string[] = []\n ) {\n super(message);\n this.name = \"SnapshotFormatError\";\n }\n}\n\n/**\n * Error thrown when snapshot doesn't match workflow (unknown steps, workflowId mismatch).\n */\nexport class SnapshotMismatchError extends Error {\n constructor(\n message: string,\n public readonly mismatchType: \"unknown_steps\" | \"workflow_id\" | \"definition_hash\",\n public readonly details?: {\n unknownSteps?: string[];\n snapshotWorkflowId?: string;\n expectedWorkflowId?: string;\n snapshotHash?: string;\n expectedHash?: string;\n }\n ) {\n super(message);\n this.name = \"SnapshotMismatchError\";\n }\n}\n\n/**\n * Error thrown when decode fails during restore.\n */\nexport class SnapshotDecodeError extends Error {\n constructor(\n message: string,\n public readonly stepId: string,\n public readonly originalError?: unknown\n ) {\n super(message);\n this.name = \"SnapshotDecodeError\";\n }\n}\n\n/**\n * Light check to see if an object looks like a WorkflowSnapshot.\n * Cheap check for basic structure - use validateSnapshot() for full validation.\n *\n * @example\n * ```typescript\n * const raw = JSON.parse(localStorage.getItem('wf-123') || 'null');\n * if (looksLikeWorkflowSnapshot(raw)) {\n * createWorkflow(deps, { snapshot: raw });\n * }\n * ```\n */\nexport function looksLikeWorkflowSnapshot(obj: unknown): obj is WorkflowSnapshot {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"formatVersion\" in obj &&\n (obj as { formatVersion: unknown }).formatVersion === 1 &&\n \"steps\" in obj &&\n typeof (obj as { steps: unknown }).steps === \"object\" &&\n (obj as { steps: unknown }).steps !== null &&\n \"execution\" in obj &&\n typeof (obj as { execution: unknown }).execution === \"object\"\n );\n}\n\n/**\n * Type guard for WorkflowSnapshot. Same as looksLikeWorkflowSnapshot; use for consistent naming with isResumeState / isSerializedResumeState.\n */\nexport const isWorkflowSnapshot = looksLikeWorkflowSnapshot;\n\n/**\n * Full validation with detailed errors.\n * Returns either a validated snapshot or an array of validation errors.\n */\nexport function validateSnapshot(obj: unknown): { valid: true; snapshot: WorkflowSnapshot } | { valid: false; errors: string[] } {\n const errors: string[] = [];\n\n if (typeof obj !== \"object\" || obj === null) {\n return { valid: false, errors: [\"Snapshot must be an object\"] };\n }\n\n const snapshot = obj as Record<string, unknown>;\n\n // Check formatVersion\n if (!(\"formatVersion\" in snapshot)) {\n errors.push(\"Missing required field: formatVersion\");\n } else if (snapshot.formatVersion !== 1) {\n errors.push(`Invalid formatVersion: expected 1, got ${snapshot.formatVersion}`);\n }\n\n // Check steps\n if (!(\"steps\" in snapshot)) {\n errors.push(\"Missing required field: steps\");\n } else if (typeof snapshot.steps !== \"object\" || snapshot.steps === null) {\n errors.push(\"steps must be an object\");\n } else {\n // Validate each step result\n const steps = snapshot.steps as Record<string, unknown>;\n for (const [stepId, stepResult] of Object.entries(steps)) {\n if (typeof stepResult !== \"object\" || stepResult === null) {\n errors.push(`steps[\"${stepId}\"] must be an object`);\n continue;\n }\n\n const step = stepResult as Record<string, unknown>;\n if (!(\"ok\" in step)) {\n errors.push(`steps[\"${stepId}\"] missing required field: ok`);\n } else if (typeof step.ok !== \"boolean\") {\n errors.push(`steps[\"${stepId}\"].ok must be a boolean`);\n } else if (step.ok === false) {\n if (!(\"error\" in step)) {\n errors.push(`steps[\"${stepId}\"] is error result but missing error field`);\n }\n if (!(\"cause\" in step)) {\n errors.push(`steps[\"${stepId}\"] is error result but missing cause field`);\n }\n }\n }\n }\n\n // Check execution\n if (!(\"execution\" in snapshot)) {\n errors.push(\"Missing required field: execution\");\n } else if (typeof snapshot.execution !== \"object\" || snapshot.execution === null) {\n errors.push(\"execution must be an object\");\n } else {\n const execution = snapshot.execution as Record<string, unknown>;\n if (!(\"status\" in execution)) {\n errors.push(\"execution missing required field: status\");\n } else if (![\"running\", \"completed\", \"failed\"].includes(execution.status as string)) {\n errors.push(`execution.status must be one of: running, completed, failed`);\n }\n if (!(\"lastUpdated\" in execution)) {\n errors.push(\"execution missing required field: lastUpdated\");\n } else if (typeof execution.lastUpdated !== \"string\") {\n errors.push(\"execution.lastUpdated must be a string (ISO timestamp)\");\n }\n }\n\n if (errors.length > 0) {\n return { valid: false, errors };\n }\n\n return { valid: true, snapshot: obj as WorkflowSnapshot };\n}\n\n/**\n * Throwing helper for cleaner code.\n * Validates a snapshot and throws SnapshotFormatError if invalid.\n *\n * @throws {SnapshotFormatError} If snapshot is invalid\n */\nexport function assertValidSnapshot(obj: unknown): WorkflowSnapshot {\n const result = validateSnapshot(obj);\n if (!result.valid) {\n throw new SnapshotFormatError(`Invalid snapshot format: ${result.errors[0]}`, result.errors);\n }\n return result.snapshot;\n}\n\n// =============================================================================\n// Snapshot Merge Helper\n// =============================================================================\n\n/**\n * Merge two snapshots (for incremental updates).\n * Delta steps overwrite base steps; execution from delta; metadata shallow merge.\n */\nexport function mergeSnapshots(base: WorkflowSnapshot, delta: WorkflowSnapshot): WorkflowSnapshot {\n // Create new steps object using Object.create(null) for prototype safety\n const mergedSteps = Object.create(null) as Record<string, StepResult>;\n\n // Copy base steps (use Object.prototype.hasOwnProperty for ES2020 compat)\n for (const [key, value] of Object.entries(base.steps)) {\n if (Object.prototype.hasOwnProperty.call(base.steps, key)) {\n mergedSteps[key] = value;\n }\n }\n\n // Overlay delta steps\n for (const [key, value] of Object.entries(delta.steps)) {\n if (Object.prototype.hasOwnProperty.call(delta.steps, key)) {\n mergedSteps[key] = value;\n }\n }\n\n // Merge metadata (delta wins for conflicts)\n const mergedMetadata = base.metadata || delta.metadata\n ? { ...base.metadata, ...delta.metadata }\n : undefined;\n\n // Merge warnings: only keep base warnings for steps not re-executed in delta.\n // If a step was re-executed and serialized cleanly, its old warning should disappear.\n const baseWarnings = (base.warnings || []).filter(\n (w) => !Object.prototype.hasOwnProperty.call(delta.steps, w.stepId)\n );\n const mergedWarnings = [...baseWarnings, ...(delta.warnings || [])];\n\n return {\n formatVersion: 1,\n steps: mergedSteps,\n execution: { ...delta.execution },\n metadata: mergedMetadata,\n warnings: mergedWarnings.length > 0 ? mergedWarnings : undefined,\n };\n}\n\n// =============================================================================\n// Serialization Helpers\n// =============================================================================\n\n/**\n * Maximum length for string representation in thrown non-Error values.\n */\nconst MAX_STRING_REPRESENTATION_LENGTH = 1000;\n\n/**\n * Serialize an Error object to SerializedCause format.\n * Preserves Error.cause recursively.\n */\nexport function serializeError(error: Error): SerializedCause {\n const serialized: SerializedCause = {\n type: \"error\",\n name: error.name,\n message: error.message,\n };\n\n if (error.stack) {\n serialized.stack = error.stack;\n }\n\n // Recursively serialize Error.cause if present (ES2022 feature, but commonly available)\n const errorWithCause = error as Error & { cause?: unknown };\n if (errorWithCause.cause !== undefined) {\n if (errorWithCause.cause instanceof Error) {\n serialized.cause = serializeError(errorWithCause.cause);\n } else {\n // cause is not an Error, serialize as thrown value\n serialized.cause = serializeThrown(errorWithCause.cause);\n }\n }\n\n return serialized;\n}\n\n/**\n * Serialize a non-Error thrown value to SerializedCause format.\n */\nexport function serializeThrown(value: unknown): SerializedCause {\n // Get string representation\n let stringRepresentation: string;\n let truncated = false;\n\n try {\n stringRepresentation = String(value);\n if (stringRepresentation.length > MAX_STRING_REPRESENTATION_LENGTH) {\n stringRepresentation = stringRepresentation.slice(0, MAX_STRING_REPRESENTATION_LENGTH);\n truncated = true;\n }\n } catch {\n stringRepresentation = \"[unable to convert to string]\";\n }\n\n // Try to get the original type\n const originalType = value === null\n ? \"null\"\n : typeof value === \"object\"\n ? (value.constructor?.name ?? \"Object\")\n : typeof value;\n\n // Try to serialize the value as JSON\n let jsonValue: JSONValue | undefined;\n try {\n const serialized = JSON.stringify(value);\n if (serialized !== undefined) {\n jsonValue = JSON.parse(serialized) as JSONValue;\n }\n } catch {\n // Non-JSON-serializable, will only use stringRepresentation\n }\n\n const result: SerializedCause = {\n type: \"thrown\",\n originalType,\n stringRepresentation,\n };\n\n if (jsonValue !== undefined) {\n result.value = jsonValue;\n }\n\n if (truncated) {\n result.truncated = true;\n }\n\n return result;\n}\n\n/**\n * Deserialize a SerializedCause back to its original form.\n */\nexport function deserializeCauseNew(serialized: SerializedCause): unknown {\n if (serialized.type === \"error\") {\n const error = new Error(serialized.message);\n error.name = serialized.name;\n if (serialized.stack) {\n error.stack = serialized.stack;\n }\n if (serialized.cause) {\n (error as Error & { cause: unknown }).cause = deserializeCauseNew(serialized.cause);\n }\n return error;\n }\n\n // type === \"thrown\"\n // Return the JSON value if available, otherwise the string representation\n return serialized.value !== undefined ? serialized.value : serialized.stringRepresentation;\n}\n\n// =============================================================================\n// SnapshotStore Interface (New Simplified API)\n// =============================================================================\n\n/**\n * Simplified store interface for workflow snapshot persistence.\n * Works directly with WorkflowSnapshot objects.\n *\n * Adapters may implement an extended contract (see awaitly/workflow): save can accept\n * WorkflowSnapshot | ResumeState; load can return WorkflowSnapshot | ResumeState | null.\n * Use isWorkflowSnapshot / isSerializedResumeState and serializeResumeState / deserializeResumeState\n * when branching. For type-safe restore, use store.loadResumeState(id) or toResumeState(await store.load(id)).\n *\n * @example\n * ```typescript\n * import { postgres } from 'awaitly-postgres';\n * import { createWorkflow } from 'awaitly/workflow';\n *\n * const store = postgres('postgresql://localhost/mydb');\n * const workflow = createWorkflow(deps);\n *\n * // Run and persist resume state\n * const { result, resumeState } = await workflow.runWithState(fn);\n * await store.save('wf-123', resumeState);\n *\n * // Restore\n * const loaded = await store.load('wf-123');\n * const resumeState = toResumeState(loaded);\n * if (resumeState) await workflow.run(fn, { resumeState });\n * ```\n */\nexport interface SnapshotStore {\n /** Save a workflow snapshot (upsert - insert or update). Adapters may also accept ResumeState. */\n save(id: string, snapshot: WorkflowSnapshot): Promise<void>;\n /** Load a workflow snapshot. Returns null if not found. Adapters may return ResumeState when stored as such. */\n load(id: string): Promise<WorkflowSnapshot | null>;\n /** Delete a workflow snapshot. */\n delete(id: string): Promise<void>;\n /** List workflow IDs with their last update time. */\n list(options?: { prefix?: string; limit?: number }): Promise<Array<{ id: string; updatedAt: string }>>;\n /** Clean shutdown for tests/graceful exit. */\n close(): Promise<void>;\n}\n\n// =============================================================================\n// In-Memory Cache Adapter\n// =============================================================================\n\n/**\n * Options for the in-memory cache adapter.\n */\nexport interface MemoryCacheOptions {\n /**\n * Maximum number of entries to store.\n * Oldest entries are evicted when limit is reached.\n */\n maxSize?: number;\n\n /**\n * Time-to-live in milliseconds.\n * Entries are automatically removed after this duration.\n */\n ttl?: number;\n}\n\n/**\n * Create an in-memory StepCache with optional LRU eviction and TTL.\n *\n * @param options - Cache options\n * @returns StepCache implementation\n *\n * @example\n * ```typescript\n * const cache = createMemoryCache({ maxSize: 1000, ttl: 60000 });\n * const workflow = createWorkflow(deps, { cache });\n * ```\n */\nexport function createMemoryCache(options: MemoryCacheOptions = {}): StepCache {\n const { maxSize, ttl } = options;\n const cache = new Map<string, {\n result: Result<unknown, unknown, unknown>;\n timestamp: number;\n entryTtl?: number;\n }>();\n\n const isExpired = (entry: { timestamp: number; entryTtl?: number }): boolean => {\n const effectiveTtl = entry.entryTtl ?? ttl;\n if (!effectiveTtl) return false;\n return Date.now() - entry.timestamp > effectiveTtl;\n };\n\n const evictExpired = (): void => {\n for (const [key, entry] of cache) {\n if (isExpired(entry)) {\n cache.delete(key);\n }\n }\n };\n\n const evictOldest = (): void => {\n if (!maxSize || cache.size < maxSize) return;\n\n // Find oldest entry\n let oldestKey: string | undefined;\n let oldestTime = Infinity;\n\n for (const [key, entry] of cache) {\n if (entry.timestamp < oldestTime) {\n oldestTime = entry.timestamp;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n cache.delete(oldestKey);\n }\n };\n\n return {\n get(key: string): Result<unknown, unknown, unknown> | undefined {\n evictExpired();\n const entry = cache.get(key);\n if (!entry) return undefined;\n if (isExpired(entry)) {\n cache.delete(key);\n return undefined;\n }\n return entry.result;\n },\n\n set(key: string, result: Result<unknown, unknown, unknown>, options?: { ttl?: number }): void {\n evictExpired();\n evictOldest();\n cache.set(key, { result, timestamp: Date.now(), entryTtl: options?.ttl });\n },\n\n has(key: string): boolean {\n evictExpired();\n const entry = cache.get(key);\n if (!entry) return false;\n if (isExpired(entry)) {\n cache.delete(key);\n return false;\n }\n return true;\n },\n\n delete(key: string): boolean {\n return cache.delete(key);\n },\n\n clear(): void {\n cache.clear();\n },\n };\n}\n","/**\n * Cache entry encoding for step results.\n * Preserves StepFailureMeta for proper replay. Internal use only.\n */\n\nimport { err, type StepFailureMeta, type Err } from \"../core\";\n\n/**\n * Marker for cached error entries that include step failure metadata.\n * This allows us to preserve origin:\"throw\" vs origin:\"result\" when replaying,\n * while also preserving the original cause value for direct cache access.\n * @internal\n */\nexport interface CachedErrorCause<C = unknown> {\n __cachedMeta: true;\n /** The original cause from the step result (preserved for direct access) */\n originalCause: C;\n /** Metadata for proper replay behavior */\n meta: StepFailureMeta;\n}\n\nexport function isCachedErrorCause(cause: unknown): cause is CachedErrorCause {\n return (\n typeof cause === \"object\" &&\n cause !== null &&\n (cause as CachedErrorCause).__cachedMeta === true\n );\n}\n\n/**\n * Encode an error result for caching, preserving both the original cause\n * and metadata needed for proper replay.\n */\nexport function encodeCachedError<E, C>(\n error: E,\n meta: StepFailureMeta,\n originalCause: C\n): Err<E, CachedErrorCause<C>> {\n return err(error, {\n cause: { __cachedMeta: true, originalCause, meta } as CachedErrorCause<C>,\n });\n}\n\nexport function decodeCachedMeta(cause: unknown): StepFailureMeta {\n if (isCachedErrorCause(cause)) {\n return cause.meta;\n }\n // Fallback for any non-encoded cause (shouldn't happen, but safe default)\n return { origin: \"result\", resultCause: cause };\n}\n","/**\n * Resume state helpers: collectors and state manipulation for workflow replay.\n */\n\nimport { ok } from \"../core\";\nimport type { WorkflowEvent } from \"../core\";\nimport type { ResumeState, ResumeStateEntry, PendingApproval } from \"./types\";\nimport { isStepComplete, isPendingApproval, isPendingHook } from \"./guards\";\n\n/**\n * Create a collector for step results to build resume state.\n *\n * ## When to Use\n *\n * Use `createResumeStateCollector` when you need to:\n * - **Save workflow state** for later replay/resume\n * - **Persist step results** to a database or file system\n * - **Build resume state** from workflow execution\n * - **Enable workflow replay** after application restarts\n *\n * ## Why Use This Instead of Manual Collection\n *\n * - **Automatic filtering**: Only collects `step_complete` events (ignores other events)\n * - **Metadata preservation**: Captures both result and meta for proper error replay\n * - **Type-safe**: Returns properly typed `ResumeState`\n * - **Convenient API**: Simple `handleEvent` → `getResumeState` pattern\n *\n * ## How It Works\n *\n * 1. Create collector and pass `handleEvent` to workflow's `onEvent` option\n * 2. Workflow emits `step_complete` events for keyed steps\n * 3. Collector automatically captures these events\n * 4. Call `getResumeState()` to get the collected `ResumeState`\n * 5. Persist state (e.g., to database) for later resume\n *\n * ## When step_complete Events Are Emitted\n *\n * Events are emitted for ANY step that has a `key` option, regardless of calling pattern:\n *\n * ```typescript\n * // Function-wrapped pattern - emits step_complete\n * await step(() => fetchUser(\"1\"), { key: \"user:1\" });\n *\n * // Direct AsyncResult pattern - also emits step_complete\n * await step(fetchUser(\"1\"), { key: \"user:1\" });\n * ```\n *\n * Both patterns above will emit `step_complete` events and be captured by the collector.\n *\n * ## Important Notes\n *\n * - Only steps with a `key` option are collected (unkeyed steps are not saved)\n * - The collector preserves error metadata for proper replay behavior\n * - State can be serialized to JSON (but complex cause types may need custom handling)\n *\n * @returns An object with:\n * - `handleEvent`: Function to pass to workflow's `onEvent` option\n * - `getResumeState`: Get collected resume state (call after workflow execution)\n * - `clear`: Clears the collector's internal recorded entries (does not mutate workflow state)\n *\n * @example\n * ```typescript\n * // Collect state during workflow execution\n * const collector = createResumeStateCollector();\n *\n * const workflow = createWorkflow({ fetchUser, fetchPosts }, {\n * onEvent: collector.handleEvent, // Pass collector's handler\n * });\n *\n * await workflow(async ({ step }) => {\n * // Only keyed steps are collected\n * const user = await step(() => fetchUser(\"1\"), { key: \"user:1\" });\n * const posts = await step(() => fetchPosts(user.id), { key: `posts:${user.id}` });\n * return { user, posts };\n * });\n *\n * // Get collected state for persistence\n * const state = collector.getResumeState();\n * // state.steps contains: 'user:1' and 'posts:1' entries\n *\n * // Save to database\n * await db.saveWorkflowState(workflowId, state);\n * ```\n *\n * @example\n * ```typescript\n * // Resume workflow from saved state\n * const savedState = await db.loadWorkflowState(workflowId);\n * const workflow = createWorkflow({ fetchUser, fetchPosts }, {\n * resumeState: savedState // Pre-populate cache from saved state\n * });\n *\n * // Cached steps skip execution, new steps run normally\n * await workflow(async ({ step }) => {\n * const user = await step(() => fetchUser(\"1\"), { key: \"user:1\" }); // Cache hit\n * const posts = await step(() => fetchPosts(user.id), { key: `posts:${user.id}` }); // Cache hit\n * return { user, posts };\n * });\n * ```\n */\nexport function createResumeStateCollector(): {\n /** Handle workflow events. Pass this to workflow's `onEvent` option. */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n /** Get the collected resume state. Call after workflow execution. */\n getResumeState: () => ResumeState;\n /** Clears the collector's internal recorded entries (does not mutate workflow state). */\n clear: () => void;\n} {\n const steps = new Map<string, ResumeStateEntry>();\n\n return {\n handleEvent: (event: WorkflowEvent<unknown>) => {\n if (isStepComplete(event)) {\n steps.set(event.stepKey, { result: event.result, meta: event.meta });\n }\n },\n getResumeState: () => ({ steps: new Map(steps) }),\n clear: () => steps.clear(),\n };\n}\n\n/**\n * Inject an approved value into resume state.\n * Use this when an external approval is granted and you want to resume the workflow.\n *\n * @param state - The resume state to update\n * @param options - Object with stepKey and the approved value\n * @returns A new ResumeState with the approval injected\n *\n * @example\n * ```typescript\n * // When approval is granted externally:\n * const updatedState = injectApproval(savedState, {\n * stepKey: 'deploy:prod',\n * value: { approvedBy: 'admin', approvedAt: Date.now() }\n * });\n *\n * // Resume workflow with the approval injected\n * const workflow = createWorkflow({ ... }, { resumeState: updatedState });\n * ```\n */\nexport function injectApproval<T>(\n state: ResumeState,\n options: { stepKey: string; value: T }\n): ResumeState {\n const newSteps = new Map(state.steps);\n newSteps.set(options.stepKey, {\n result: ok(options.value),\n });\n return { steps: newSteps };\n}\n\n/**\n * Remove a step from resume state (e.g., to force re-execution).\n * This is an immutable operation - returns a new ResumeState without modifying the original.\n *\n * @param state - The resume state to update\n * @param stepKey - The key of the step to remove\n * @returns A new ResumeState with the step removed (original is unchanged)\n *\n * @example\n * ```typescript\n * // Force a step to re-execute on resume\n * const updatedState = clearStep(savedState, 'approval:123');\n * ```\n */\nexport function clearStep(state: ResumeState, stepKey: string): ResumeState {\n const newSteps = new Map(state.steps);\n newSteps.delete(stepKey);\n return { steps: newSteps };\n}\n\n/**\n * Check if a step in resume state has a pending approval error.\n *\n * @param state - The resume state to check\n * @param stepKey - The key of the step to check\n * @returns `true` if the step has a pending approval, `false` otherwise\n *\n * @example\n * ```typescript\n * if (hasPendingApproval(savedState, 'deploy:prod')) {\n * // Show approval UI\n * }\n * ```\n */\nexport function hasPendingApproval(\n state: ResumeState,\n stepKey: string\n): boolean {\n const entry = state.steps.get(stepKey);\n if (!entry || entry.result.ok) return false;\n return isPendingApproval(entry.result.error);\n}\n\n/**\n * Get all pending approval step keys from resume state.\n *\n * @param state - The resume state to check\n * @returns Array of step keys that have pending approvals\n *\n * @example\n * ```typescript\n * const pendingKeys = getPendingApprovals(savedState);\n * // ['deploy:prod', 'deploy:staging']\n * ```\n */\nexport function getPendingApprovals(state: ResumeState): string[] {\n const pending: string[] = [];\n for (const [key, entry] of state.steps) {\n if (!entry.result.ok && isPendingApproval(entry.result.error)) {\n pending.push(key);\n }\n }\n return pending;\n}\n\nconst HOOK_STEP_KEY_PREFIX = \"hook:\";\n\n/**\n * Inject a hook callback value into resume state.\n * Call this when the app receives the HTTP callback (e.g. POST /hook/:hookId) and pass the request body as value.\n *\n * @param state - The resume state to update\n * @param options - hookId (from the callback URL) and value (e.g. request body)\n * @returns A new ResumeState with the hook step set to ok(value)\n */\nexport function injectHook<T>(\n state: ResumeState,\n options: { hookId: string; value: T }\n): ResumeState {\n const newSteps = new Map(state.steps);\n newSteps.set(HOOK_STEP_KEY_PREFIX + options.hookId, {\n result: ok(options.value),\n });\n return { steps: newSteps };\n}\n\n/**\n * Check if a step in resume state has a pending hook error.\n *\n * @param state - The resume state to check\n * @param hookId - The hook id (from createHook() or the callback URL)\n * @returns `true` if that hook step is pending, `false` otherwise\n */\nexport function hasPendingHook(state: ResumeState, hookId: string): boolean {\n const entry = state.steps.get(HOOK_STEP_KEY_PREFIX + hookId);\n if (!entry || entry.result.ok) return false;\n return isPendingHook(entry.result.error);\n}\n\n/**\n * Get all pending hook hookIds from resume state.\n *\n * @param state - The resume state to check\n * @returns Array of hookIds that have pending callbacks\n */\nexport function getPendingHooks(state: ResumeState): string[] {\n const pending: string[] = [];\n for (const entry of state.steps.values()) {\n if (!entry.result.ok && isPendingHook(entry.result.error)) {\n pending.push((entry.result.error as { hookId: string }).hookId);\n }\n }\n return pending;\n}\n\n/**\n * Extended resume state collector that tracks pending approvals.\n * Use this for human-in-the-loop workflows that need to track approval state.\n *\n * @returns An object with methods to handle events, get state, and manage approvals\n *\n * @example\n * ```typescript\n * const collector = createApprovalStateCollector();\n *\n * const workflow = createWorkflow({ fetchUser, requireApproval }, {\n * onEvent: collector.handleEvent,\n * });\n *\n * const result = await workflow(async ({ step }) => {\n * const user = await step(() => fetchUser(\"1\"), { key: \"user:1\" });\n * const approval = await step(requireApproval, { key: \"approval:1\" });\n * return { user, approval };\n * });\n *\n * // Check for pending approvals\n * if (collector.hasPendingApprovals()) {\n * const pending = collector.getPendingApprovals();\n * // pending: [{ stepKey: 'approval:1', error: PendingApproval }]\n * await saveToDatabase(collector.getResumeState());\n * }\n *\n * // Later, when approved:\n * const resumeState = collector.injectApproval('approval:1', { approvedBy: 'admin' });\n * ```\n */\nexport function createApprovalStateCollector(): {\n /** Handle workflow events. Pass this to workflow's `onEvent` option. */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n /** Get the collected resume state. Call after workflow execution. */\n getResumeState: () => ResumeState;\n /** Clears the collector's internal recorded entries (does not mutate workflow state). */\n clear: () => void;\n /** Check if any steps have pending approvals */\n hasPendingApprovals: () => boolean;\n /** Get all pending approval entries with their errors */\n getPendingApprovals: () => Array<{ stepKey: string; error: PendingApproval }>;\n /** Inject an approval result, updating the collector's internal state. Returns a copy for use as resumeState. */\n injectApproval: <T>(stepKey: string, value: T) => ResumeState;\n} {\n const steps = new Map<string, ResumeStateEntry>();\n\n return {\n handleEvent: (event: WorkflowEvent<unknown>) => {\n if (isStepComplete(event)) {\n steps.set(event.stepKey, { result: event.result, meta: event.meta });\n }\n },\n getResumeState: () => ({ steps: new Map(steps) }),\n clear: () => steps.clear(),\n hasPendingApprovals: () => {\n for (const entry of steps.values()) {\n if (!entry.result.ok && isPendingApproval(entry.result.error)) {\n return true;\n }\n }\n return false;\n },\n getPendingApprovals: () => {\n const pending: Array<{ stepKey: string; error: PendingApproval }> = [];\n for (const [key, entry] of steps) {\n if (!entry.result.ok && isPendingApproval(entry.result.error)) {\n pending.push({ stepKey: key, error: entry.result.error as PendingApproval });\n }\n }\n return pending;\n },\n injectApproval: <T>(stepKey: string, value: T): ResumeState => {\n // Mutate internal state so collector reflects the approval\n steps.set(stepKey, { result: ok(value) });\n // Return a copy for use as resumeState\n return { steps: new Map(steps) };\n },\n };\n}\n","/**\n * awaitly/streaming - Types\n *\n * Core types for Result-aware streaming in workflows.\n * All stream operations return Result types, enabling typed error handling\n * throughout the streaming pipeline.\n */\n\nimport type { AsyncResult } from \"../core\";\n\n// =============================================================================\n// Stream Error Types\n// =============================================================================\n\n/** Discriminant for stream write errors */\nexport const STREAM_WRITE_ERROR = \"STREAM_WRITE_ERROR\" as const;\n\n/** Discriminant for stream read errors */\nexport const STREAM_READ_ERROR = \"STREAM_READ_ERROR\" as const;\n\n/** Discriminant for stream close errors */\nexport const STREAM_CLOSE_ERROR = \"STREAM_CLOSE_ERROR\" as const;\n\n/** Discriminant for stream store errors */\nexport const STREAM_STORE_ERROR = \"STREAM_STORE_ERROR\" as const;\n\n/** Discriminant for stream ended marker */\nexport const STREAM_ENDED = \"STREAM_ENDED\" as const;\n\n/** Discriminant for stream backpressure errors */\nexport const STREAM_BACKPRESSURE_ERROR = \"STREAM_BACKPRESSURE_ERROR\" as const;\n\n/**\n * Error returned when a write operation fails.\n */\nexport type StreamWriteError = {\n type: typeof STREAM_WRITE_ERROR;\n reason: \"closed\" | \"aborted\" | \"store_error\";\n message: string;\n cause?: unknown;\n};\n\n/**\n * Error returned when a read operation fails.\n */\nexport type StreamReadError = {\n type: typeof STREAM_READ_ERROR;\n reason: \"closed\" | \"store_error\";\n message: string;\n cause?: unknown;\n};\n\n/**\n * Error returned when closing a stream fails.\n */\nexport type StreamCloseError = {\n type: typeof STREAM_CLOSE_ERROR;\n reason: \"already_closed\" | \"store_error\";\n message: string;\n cause?: unknown;\n};\n\n/**\n * Error returned from StreamStore operations.\n */\nexport type StreamStoreError = {\n type: typeof STREAM_STORE_ERROR;\n reason: \"read_error\" | \"write_error\" | \"metadata_error\" | \"close_error\";\n message: string;\n cause?: unknown;\n};\n\n/**\n * Marker indicating stream has ended (not an error, but a terminal state).\n * Used as the \"error\" type when stream is exhausted.\n */\nexport type StreamEndedMarker = {\n type: typeof STREAM_ENDED;\n finalPosition: number;\n};\n\n/**\n * Backpressure error when writer is paused.\n */\nexport type StreamBackpressureError = {\n type: typeof STREAM_BACKPRESSURE_ERROR;\n bufferedCount: number;\n highWaterMark: number;\n};\n\n/**\n * Union of all stream errors.\n */\nexport type StreamError =\n | StreamWriteError\n | StreamReadError\n | StreamCloseError\n | StreamStoreError\n | StreamBackpressureError;\n\n// =============================================================================\n// Stream Item Types\n// =============================================================================\n\n/**\n * A single item in the stream with metadata.\n */\nexport interface StreamItem<T> {\n /** The value stored in this stream item */\n value: T;\n /** Position in the stream (0-indexed) */\n position: number;\n /** Timestamp when item was written */\n ts: number;\n}\n\n/**\n * Metadata about a stream.\n */\nexport interface StreamMetadata {\n /** Unique identifier for the stream (workflowId + namespace) */\n id: string;\n /** Namespace within the workflow */\n namespace: string;\n /** Workflow ID that owns this stream */\n workflowId: string;\n /** Number of items in the stream */\n length: number;\n /** Whether the stream has been closed */\n closed: boolean;\n /** Timestamp when stream was created */\n createdAt: number;\n /** Timestamp when stream was last written to */\n lastWriteAt?: number;\n /** Timestamp when stream was closed */\n closedAt?: number;\n}\n\n// =============================================================================\n// Stream Options\n// =============================================================================\n\n/**\n * Options for creating a writable stream.\n */\nexport interface StreamOptions {\n /** Named streams (default: 'default') */\n namespace?: string;\n /** Backpressure threshold (default: 16) */\n highWaterMark?: number;\n}\n\n/**\n * Options for creating a readable stream.\n */\nexport interface StreamReadOptions {\n /** Named streams (default: 'default') */\n namespace?: string;\n /** Resume from position (0-indexed) */\n startIndex?: number;\n}\n\n/**\n * Options for streamForEach operation.\n */\nexport interface StreamForEachOptions {\n /** Name for the operation (used in events) */\n name?: string;\n /** Checkpoint after every N items (default: 1 = checkpoint each item) */\n checkpointInterval?: number;\n /** Maximum concurrent processors (default: 1 = sequential) */\n concurrency?: number;\n}\n\n/**\n * Result from streamForEach operation.\n */\nexport interface StreamForEachResult<R> {\n /** Results from each processed item */\n results: R[];\n /** Total items processed */\n processedCount: number;\n /** Position of last processed item */\n lastPosition: number;\n}\n\n// =============================================================================\n// StreamWriter Interface\n// =============================================================================\n\n/**\n * Writable stream interface - never throws, returns Results.\n *\n * Use within a step to write values to a stream that can be consumed\n * by readers (e.g., HTTP response streaming, AI token streaming).\n *\n * @template T - Type of values written to the stream\n *\n * @example\n * ```typescript\n * const writer = step.getWritable<string>({ namespace: 'ai-response' });\n *\n * await step(() => generateAI({\n * prompt: 'Hello',\n * onToken: async (token) => { await writer.write(token); }\n * }), { key: 'generate' });\n *\n * await writer.close();\n * ```\n */\nexport interface StreamWriter<T> {\n /**\n * Write a value to the stream.\n * Returns an error if the stream is closed, aborted, or store fails.\n */\n write(value: T): AsyncResult<void, StreamWriteError>;\n\n /**\n * Close the stream normally.\n * Signals to readers that no more data will be written.\n */\n close(): AsyncResult<void, StreamCloseError>;\n\n /**\n * Abort the stream with a reason.\n * Use for error conditions that should terminate the stream.\n */\n abort(reason: unknown): void;\n\n /** Whether the stream is still writable */\n readonly writable: boolean;\n\n /** Current write position (number of items written) */\n readonly position: number;\n\n /** Stream namespace */\n readonly namespace: string;\n}\n\n/**\n * Readable stream interface - returns STREAM_ENDED marker when complete.\n *\n * Use to consume values from a stream, with support for resuming from\n * a specific position.\n *\n * @template T - Type of values read from the stream\n *\n * @example\n * ```typescript\n * const reader = getStreamReader<string>(runId, { namespace: 'ai-response' });\n *\n * let result = await reader.read();\n * while (result.ok) {\n * response.write(result.value);\n * result = await reader.read();\n * }\n *\n * if (result.error.type === 'STREAM_ENDED') {\n * console.log('Stream complete at position', result.error.finalPosition);\n * }\n * ```\n */\nexport interface StreamReader<T> {\n /**\n * Read the next value from the stream.\n * Returns StreamEndedMarker when stream is exhausted.\n */\n read(): AsyncResult<T, StreamReadError | StreamEndedMarker>;\n\n /**\n * Close the reader (stop consuming).\n * Does not affect the underlying stream.\n */\n close(): void;\n\n /** Whether there may be more data to read */\n readonly readable: boolean;\n\n /** Current read position */\n readonly position: number;\n\n /** Stream namespace */\n readonly namespace: string;\n}\n\n// =============================================================================\n// StreamStore Interface\n// =============================================================================\n\n/** Unsubscribe function returned by subscribe */\nexport type Unsubscribe = () => void;\n\n/**\n * Storage backend for stream data.\n * Follows the same patterns as persistence.ts adapters.\n *\n * @example In-memory store\n * ```typescript\n * const store = createMemoryStreamStore();\n * ```\n *\n * @example File-based store\n * ```typescript\n * const store = createFileStreamStore({ directory: './streams', fs });\n * ```\n */\nexport interface StreamStore {\n /**\n * Append an item to the stream.\n */\n append<T>(\n workflowId: string,\n namespace: string,\n item: StreamItem<T>\n ): AsyncResult<void, StreamStoreError>;\n\n /**\n * Read items from the stream starting at an index.\n * @param startIndex - Position to start reading from (0-indexed)\n * @param limit - Maximum number of items to read (default: all remaining)\n */\n read<T>(\n workflowId: string,\n namespace: string,\n startIndex: number,\n limit?: number\n ): AsyncResult<StreamItem<T>[], StreamStoreError>;\n\n /**\n * Get metadata about a stream.\n * Returns undefined if stream doesn't exist.\n */\n getMetadata(\n workflowId: string,\n namespace: string\n ): AsyncResult<StreamMetadata | undefined, StreamStoreError>;\n\n /**\n * Mark stream as closed.\n */\n closeStream(\n workflowId: string,\n namespace: string\n ): AsyncResult<void, StreamStoreError>;\n\n /**\n * Subscribe to new items in a stream.\n * Callback is invoked for each new item written.\n * Returns unsubscribe function.\n */\n subscribe<T>(\n workflowId: string,\n namespace: string,\n callback: (item: StreamItem<T>) => void\n ): Unsubscribe;\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Check if an error is a StreamEndedMarker.\n */\nexport function isStreamEnded(error: unknown): error is StreamEndedMarker {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as StreamEndedMarker).type === STREAM_ENDED\n );\n}\n\n/**\n * Check if an error is a StreamWriteError.\n */\nexport function isStreamWriteError(error: unknown): error is StreamWriteError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as StreamWriteError).type === STREAM_WRITE_ERROR\n );\n}\n\n/**\n * Check if an error is a StreamReadError.\n */\nexport function isStreamReadError(error: unknown): error is StreamReadError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as StreamReadError).type === STREAM_READ_ERROR\n );\n}\n\n/**\n * Check if an error is a StreamStoreError.\n */\nexport function isStreamStoreError(error: unknown): error is StreamStoreError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as StreamStoreError).type === STREAM_STORE_ERROR\n );\n}\n\n/**\n * Check if an error is a StreamBackpressureError.\n */\nexport function isStreamBackpressureError(\n error: unknown\n): error is StreamBackpressureError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as StreamBackpressureError).type === STREAM_BACKPRESSURE_ERROR\n );\n}\n\n// =============================================================================\n// Error Constructors\n// =============================================================================\n\n/**\n * Create a StreamWriteError.\n */\nexport function streamWriteError(\n reason: StreamWriteError[\"reason\"],\n message: string,\n cause?: unknown\n): StreamWriteError {\n return {\n type: STREAM_WRITE_ERROR,\n reason,\n message,\n ...(cause !== undefined ? { cause } : {}),\n };\n}\n\n/**\n * Create a StreamReadError.\n */\nexport function streamReadError(\n reason: StreamReadError[\"reason\"],\n message: string,\n cause?: unknown\n): StreamReadError {\n return {\n type: STREAM_READ_ERROR,\n reason,\n message,\n ...(cause !== undefined ? { cause } : {}),\n };\n}\n\n/**\n * Create a StreamCloseError.\n */\nexport function streamCloseError(\n reason: StreamCloseError[\"reason\"],\n message: string,\n cause?: unknown\n): StreamCloseError {\n return {\n type: STREAM_CLOSE_ERROR,\n reason,\n message,\n ...(cause !== undefined ? { cause } : {}),\n };\n}\n\n/**\n * Create a StreamStoreError.\n */\nexport function streamStoreError(\n reason: StreamStoreError[\"reason\"],\n message: string,\n cause?: unknown\n): StreamStoreError {\n return {\n type: STREAM_STORE_ERROR,\n reason,\n message,\n ...(cause !== undefined ? { cause } : {}),\n };\n}\n\n/**\n * Create a StreamEndedMarker.\n */\nexport function streamEnded(finalPosition: number): StreamEndedMarker {\n return {\n type: STREAM_ENDED,\n finalPosition,\n };\n}\n\n/**\n * Create a StreamBackpressureError.\n */\nexport function streamBackpressureError(\n bufferedCount: number,\n highWaterMark: number\n): StreamBackpressureError {\n return {\n type: STREAM_BACKPRESSURE_ERROR,\n bufferedCount,\n highWaterMark,\n };\n}\n","/**\n * awaitly/streaming - Backpressure Controller\n *\n * Implements flow control for streams using high-water mark.\n * When buffered items exceed the threshold, writers are paused\n * until consumers catch up.\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * State of the backpressure controller.\n */\nexport type BackpressureState = \"flowing\" | \"paused\";\n\n/**\n * Callback invoked when backpressure state changes.\n */\nexport type BackpressureCallback = (state: BackpressureState) => void;\n\n/**\n * Options for creating a BackpressureController.\n */\nexport interface BackpressureOptions {\n /** High-water mark threshold (default: 16) */\n highWaterMark?: number;\n /** Low-water mark to resume (default: highWaterMark / 2) */\n lowWaterMark?: number;\n /** Callback when state changes */\n onStateChange?: BackpressureCallback;\n}\n\n// =============================================================================\n// BackpressureController\n// =============================================================================\n\n/**\n * Controller for managing stream backpressure.\n *\n * When the number of buffered items exceeds the high-water mark,\n * the controller enters \"paused\" state. It returns to \"flowing\"\n * when items are consumed and the buffer drops below the low-water mark.\n *\n * @example\n * ```typescript\n * const controller = createBackpressureController({ highWaterMark: 16 });\n *\n * // Track writes\n * controller.increment();\n * if (controller.state === 'paused') {\n * await controller.waitForDrain();\n * }\n *\n * // Track reads (consumer)\n * controller.decrement();\n * ```\n */\nexport interface BackpressureController {\n /** Current state */\n readonly state: BackpressureState;\n\n /** Current number of buffered items */\n readonly bufferedCount: number;\n\n /** High-water mark threshold */\n readonly highWaterMark: number;\n\n /** Low-water mark threshold */\n readonly lowWaterMark: number;\n\n /** Increment buffered count (called on write) */\n increment(): void;\n\n /** Decrement buffered count (called on read/consume) */\n decrement(): void;\n\n /** Set buffered count directly (for resuming) */\n setCount(count: number): void;\n\n /**\n * Wait for the buffer to drain below low-water mark.\n * Resolves immediately if already flowing.\n */\n waitForDrain(): Promise<void>;\n\n /** Reset the controller to initial state */\n reset(): void;\n}\n\n/**\n * Create a backpressure controller.\n *\n * @param options - Configuration options\n * @returns BackpressureController instance\n */\nexport function createBackpressureController(\n options: BackpressureOptions = {}\n): BackpressureController {\n const highWaterMark = options.highWaterMark ?? 16;\n const lowWaterMark = options.lowWaterMark ?? Math.floor(highWaterMark / 2);\n const onStateChange = options.onStateChange;\n\n let state: BackpressureState = \"flowing\";\n let bufferedCount = 0;\n let drainResolvers: Array<() => void> = [];\n\n function updateState(newState: BackpressureState): void {\n if (state !== newState) {\n state = newState;\n onStateChange?.(newState);\n\n // Resolve drain waiters when transitioning to flowing\n if (newState === \"flowing\" && drainResolvers.length > 0) {\n const resolvers = drainResolvers;\n drainResolvers = [];\n for (const resolve of resolvers) {\n resolve();\n }\n }\n }\n }\n\n function checkState(): void {\n if (state === \"flowing\" && bufferedCount >= highWaterMark) {\n updateState(\"paused\");\n } else if (state === \"paused\" && bufferedCount <= lowWaterMark) {\n updateState(\"flowing\");\n }\n }\n\n return {\n get state() {\n return state;\n },\n\n get bufferedCount() {\n return bufferedCount;\n },\n\n get highWaterMark() {\n return highWaterMark;\n },\n\n get lowWaterMark() {\n return lowWaterMark;\n },\n\n increment(): void {\n bufferedCount++;\n checkState();\n },\n\n decrement(): void {\n if (bufferedCount > 0) {\n bufferedCount--;\n checkState();\n }\n },\n\n setCount(count: number): void {\n bufferedCount = Math.max(0, count);\n checkState();\n },\n\n waitForDrain(): Promise<void> {\n if (state === \"flowing\") {\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n drainResolvers.push(resolve);\n });\n },\n\n reset(): void {\n bufferedCount = 0;\n drainResolvers = [];\n updateState(\"flowing\");\n },\n };\n}\n\n// =============================================================================\n// Utilities\n// =============================================================================\n\n/**\n * Check if backpressure should be applied.\n */\nexport function shouldApplyBackpressure(\n controller: BackpressureController\n): boolean {\n return controller.state === \"paused\";\n}\n","/**\n * awaitly/duration\n *\n * Type-safe duration handling inspired by Effect's Duration module.\n * Prevents unit confusion (milliseconds vs seconds) with explicit constructors.\n */\n\n// =============================================================================\n// Duration Type\n// =============================================================================\n\n/**\n * A type-safe representation of a time duration.\n * Use the constructor functions (millis, seconds, etc.) to create durations.\n */\nexport interface Duration {\n readonly _tag: \"Duration\";\n readonly millis: number;\n}\n\n// =============================================================================\n// Constructors\n// =============================================================================\n\n/**\n * Create a Duration from milliseconds.\n *\n * @example\n * ```typescript\n * const d = Duration.millis(500)\n * ```\n */\nexport function millis(ms: number): Duration {\n return { _tag: \"Duration\", millis: ms };\n}\n\n/**\n * Create a Duration from seconds.\n *\n * @example\n * ```typescript\n * const d = Duration.seconds(5) // 5000ms\n * ```\n */\nexport function seconds(s: number): Duration {\n return { _tag: \"Duration\", millis: s * 1000 };\n}\n\n/**\n * Create a Duration from minutes.\n *\n * @example\n * ```typescript\n * const d = Duration.minutes(2) // 120000ms\n * ```\n */\nexport function minutes(m: number): Duration {\n return { _tag: \"Duration\", millis: m * 60 * 1000 };\n}\n\n/**\n * Create a Duration from hours.\n *\n * @example\n * ```typescript\n * const d = Duration.hours(1) // 3600000ms\n * ```\n */\nexport function hours(h: number): Duration {\n return { _tag: \"Duration\", millis: h * 60 * 60 * 1000 };\n}\n\n/**\n * Create a Duration from days.\n *\n * @example\n * ```typescript\n * const d = Duration.days(1) // 86400000ms\n * ```\n */\nexport function days(d: number): Duration {\n return { _tag: \"Duration\", millis: d * 24 * 60 * 60 * 1000 };\n}\n\n/**\n * Zero duration.\n */\nexport const zero: Duration = { _tag: \"Duration\", millis: 0 };\n\n/**\n * Infinite duration (represented as Infinity milliseconds).\n */\nexport const infinity: Duration = { _tag: \"Duration\", millis: Infinity };\n\n// =============================================================================\n// Conversions\n// =============================================================================\n\n/**\n * Convert a Duration to milliseconds.\n */\nexport function toMillis(duration: Duration): number {\n return duration.millis;\n}\n\n/**\n * Convert a Duration to seconds.\n */\nexport function toSeconds(duration: Duration): number {\n return duration.millis / 1000;\n}\n\n/**\n * Convert a Duration to minutes.\n */\nexport function toMinutes(duration: Duration): number {\n return duration.millis / (60 * 1000);\n}\n\n/**\n * Convert a Duration to hours.\n */\nexport function toHours(duration: Duration): number {\n return duration.millis / (60 * 60 * 1000);\n}\n\n/**\n * Convert a Duration to days.\n */\nexport function toDays(duration: Duration): number {\n return duration.millis / (24 * 60 * 60 * 1000);\n}\n\n// =============================================================================\n// Operations\n// =============================================================================\n\n/**\n * Add two durations.\n *\n * @example\n * ```typescript\n * const total = Duration.add(Duration.seconds(5), Duration.millis(500))\n * // 5500ms\n * ```\n */\nexport function add(a: Duration, b: Duration): Duration {\n return { _tag: \"Duration\", millis: a.millis + b.millis };\n}\n\n/**\n * Subtract duration b from duration a.\n * Result is clamped to zero (no negative durations).\n *\n * @example\n * ```typescript\n * const remaining = Duration.subtract(Duration.seconds(5), Duration.seconds(2))\n * // 3000ms\n * ```\n */\nexport function subtract(a: Duration, b: Duration): Duration {\n return { _tag: \"Duration\", millis: Math.max(0, a.millis - b.millis) };\n}\n\n/**\n * Multiply a duration by a factor.\n *\n * @example\n * ```typescript\n * const doubled = Duration.multiply(Duration.seconds(5), 2)\n * // 10000ms\n * ```\n */\nexport function multiply(duration: Duration, factor: number): Duration {\n return { _tag: \"Duration\", millis: duration.millis * factor };\n}\n\n/**\n * Divide a duration by a divisor.\n *\n * @example\n * ```typescript\n * const half = Duration.divide(Duration.seconds(10), 2)\n * // 5000ms\n * ```\n */\nexport function divide(duration: Duration, divisor: number): Duration {\n return { _tag: \"Duration\", millis: duration.millis / divisor };\n}\n\n// =============================================================================\n// Comparisons\n// =============================================================================\n\n/**\n * Check if duration a is less than duration b.\n */\nexport function lessThan(a: Duration, b: Duration): boolean {\n return a.millis < b.millis;\n}\n\n/**\n * Check if duration a is less than or equal to duration b.\n */\nexport function lessThanOrEqual(a: Duration, b: Duration): boolean {\n return a.millis <= b.millis;\n}\n\n/**\n * Check if duration a is greater than duration b.\n */\nexport function greaterThan(a: Duration, b: Duration): boolean {\n return a.millis > b.millis;\n}\n\n/**\n * Check if duration a is greater than or equal to duration b.\n */\nexport function greaterThanOrEqual(a: Duration, b: Duration): boolean {\n return a.millis >= b.millis;\n}\n\n/**\n * Check if two durations are equal.\n */\nexport function equals(a: Duration, b: Duration): boolean {\n return a.millis === b.millis;\n}\n\n/**\n * Get the minimum of two durations.\n */\nexport function min(a: Duration, b: Duration): Duration {\n return a.millis <= b.millis ? a : b;\n}\n\n/**\n * Get the maximum of two durations.\n */\nexport function max(a: Duration, b: Duration): Duration {\n return a.millis >= b.millis ? a : b;\n}\n\n/**\n * Clamp a duration between a minimum and maximum.\n */\nexport function clamp(duration: Duration, minimum: Duration, maximum: Duration): Duration {\n return min(max(duration, minimum), maximum);\n}\n\n// =============================================================================\n// Predicates\n// =============================================================================\n\n/**\n * Check if a duration is zero.\n */\nexport function isZero(duration: Duration): boolean {\n return duration.millis === 0;\n}\n\n/**\n * Check if a duration is infinite.\n */\nexport function isInfinite(duration: Duration): boolean {\n return duration.millis === Infinity;\n}\n\n/**\n * Check if a duration is finite and positive.\n */\nexport function isFinite(duration: Duration): boolean {\n return Number.isFinite(duration.millis) && duration.millis > 0;\n}\n\n/**\n * Type guard to check if a value is a Duration.\n */\nexport function isDuration(value: unknown): value is Duration {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"_tag\" in value &&\n value._tag === \"Duration\" &&\n \"millis\" in value &&\n typeof value.millis === \"number\"\n );\n}\n\n// =============================================================================\n// Formatting\n// =============================================================================\n\n/**\n * Format a duration as a human-readable string.\n *\n * @example\n * ```typescript\n * Duration.format(Duration.seconds(90)) // \"1m 30s\"\n * Duration.format(Duration.millis(500)) // \"500ms\"\n * ```\n */\nexport function format(duration: Duration): string {\n const ms = duration.millis;\n\n if (ms === Infinity) return \"∞\";\n if (ms === 0) return \"0ms\";\n\n const days = Math.floor(ms / (24 * 60 * 60 * 1000));\n const hours = Math.floor((ms % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));\n const minutes = Math.floor((ms % (60 * 60 * 1000)) / (60 * 1000));\n const seconds = Math.floor((ms % (60 * 1000)) / 1000);\n const millis = ms % 1000;\n\n const parts: string[] = [];\n if (days > 0) parts.push(`${days}d`);\n if (hours > 0) parts.push(`${hours}h`);\n if (minutes > 0) parts.push(`${minutes}m`);\n if (seconds > 0) parts.push(`${seconds}s`);\n if (millis > 0 && parts.length === 0) parts.push(`${millis}ms`);\n\n return parts.join(\" \") || \"0ms\";\n}\n\n// =============================================================================\n// Parsing\n// =============================================================================\n\n/**\n * Parse a duration from a string like \"100ms\", \"5s\", \"2m\", \"1h\", \"1d\".\n * Returns undefined if parsing fails.\n *\n * @example\n * ```typescript\n * Duration.parse(\"5s\") // Duration.seconds(5)\n * Duration.parse(\"100ms\") // Duration.millis(100)\n * Duration.parse(\"2m\") // Duration.minutes(2)\n * ```\n */\nexport function parse(input: string): Duration | undefined {\n const match = input.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h|d)$/i);\n if (!match) return undefined;\n\n const value = parseFloat(match[1]);\n const unit = match[2].toLowerCase();\n\n switch (unit) {\n case \"ms\":\n return millis(value);\n case \"s\":\n return seconds(value);\n case \"m\":\n return minutes(value);\n case \"h\":\n return hours(value);\n case \"d\":\n return days(value);\n default:\n return undefined;\n }\n}\n\n// =============================================================================\n// Namespace Export\n// =============================================================================\n\n/**\n * Duration namespace with all functions for convenient access.\n *\n * @example\n * ```typescript\n * import { Duration } from \"awaitly\";\n *\n * const timeout = Duration.seconds(30);\n * const delay = Duration.millis(100);\n * const total = Duration.add(timeout, delay);\n *\n * console.log(Duration.format(total)); // \"30s 100ms\"\n * ```\n */\nexport const Duration = {\n // Constructors\n millis,\n seconds,\n minutes,\n hours,\n days,\n zero,\n infinity,\n\n // Conversions\n toMillis,\n toSeconds,\n toMinutes,\n toHours,\n toDays,\n\n // Operations\n add,\n subtract,\n multiply,\n divide,\n\n // Comparisons\n lessThan,\n lessThanOrEqual,\n greaterThan,\n greaterThanOrEqual,\n equals,\n min,\n max,\n clamp,\n\n // Predicates\n isZero,\n isInfinite,\n isFinite,\n isDuration,\n\n // Formatting\n format,\n parse,\n} as const;\n\nexport type { Duration as DurationType };\n","/**\n * Optional input validation using the Standard Schema spec.\n * Works with Zod, Valibot, ArkType, or any Standard Schema-compliant library.\n *\n * @see https://github.com/standard-schema/standard-schema\n */\n\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { ok, err, type Result } from \"../core\";\n\n/**\n * Tagged error returned when workflow input fails schema validation.\n * Follows awaitly's tagged error object pattern (with `type` field).\n */\nexport type InputValidationError = {\n type: \"INPUT_VALIDATION_ERROR\";\n issues: Array<{ message: string; path?: Array<string | number> }>;\n message: string;\n};\n\n/**\n * Type guard for InputValidationError.\n */\nexport function isInputValidationError(e: unknown): e is InputValidationError {\n return (\n typeof e === \"object\" &&\n e !== null &&\n (e as InputValidationError).type === \"INPUT_VALIDATION_ERROR\"\n );\n}\n\n/**\n * Validate input against a Standard Schema.\n * Supports both sync and async schema validation.\n *\n * @param schema - A Standard Schema-compliant schema object\n * @param input - The input value to validate\n * @returns Result with validated value or InputValidationError\n */\nexport async function validateInput<T>(\n schema: StandardSchemaV1<T>,\n input: unknown\n): Promise<Result<T, InputValidationError>> {\n const result = schema[\"~standard\"].validate(input);\n // Standard Schema allows sync or async validation\n const resolved = result instanceof Promise ? await result : result;\n if (resolved.issues) {\n return err({\n type: \"INPUT_VALIDATION_ERROR\" as const,\n issues: resolved.issues.map((i) => ({\n message: i.message,\n path: i.path?.map((p) =>\n typeof p === \"object\" ? (p as { key: string | number }).key : p\n ) as Array<string | number> | undefined,\n })),\n message: `Input validation failed: ${resolved.issues.map((i) => i.message).join(\", \")}`,\n });\n }\n return ok(resolved.value as T);\n}\n","/**\n * createWorkflow implementation and workflow execution logic.\n */\n\nimport {\n run,\n ok,\n err,\n createEarlyExit,\n isEarlyExit,\n isUnexpectedError,\n defaultCatchUnexpected,\n type EarlyExit,\n type StepFailureMeta,\n type Result,\n type AsyncResult,\n type UnexpectedError,\n type RunStep,\n type WorkflowEvent,\n type StepOptions,\n type RetryOptions,\n type TimeoutOptions,\n type StreamWritableOptions,\n type StreamReadableOptions,\n type StreamForEachStepOptions,\n type StreamForEachResultType,\n type StreamWriterInterface,\n type StreamReaderInterface,\n extractStepMetadata,\n} from \"../core\";\n\nimport type {\n StreamStore,\n StreamItem,\n StreamWriter,\n StreamReader,\n StreamWriteError,\n StreamCloseError,\n StreamReadError,\n StreamEndedMarker,\n} from \"../streaming/types\";\n\nimport {\n streamWriteError,\n streamReadError,\n streamCloseError,\n streamEnded,\n} from \"../streaming/types\";\n\nimport {\n createBackpressureController,\n type BackpressureController,\n} from \"../streaming/backpressure\";\n\nimport { parse as parseDuration, toMillis, type Duration as DurationType } from \"../duration\";\n\nimport type {\n StepCache,\n ResumeState,\n AnyResultFn,\n ErrorsOfDeps,\n WorkflowOptions,\n WorkflowContext,\n WorkflowFn,\n RunConfig,\n Workflow,\n WorkflowCancelledError,\n} from \"./types\";\n\nimport { createResumeStateCollector } from \"./resume-state\";\n\nimport {\n encodeCachedError,\n decodeCachedMeta,\n} from \"./cache-encoding\";\n\nimport { isWorkflowCancelled } from \"./guards\";\nimport { validateInput } from \"./validation\";\n\nimport type {\n JSONValue,\n WorkflowSnapshot,\n} from \"../persistence\";\n\nimport {\n deserializeCauseNew,\n SnapshotDecodeError,\n} from \"../persistence\";\n// =============================================================================\n// createWorkflow - Automatic Error Type Inference\n// =============================================================================\n\n/**\n * Create a typed workflow with automatic error inference.\n *\n * ## When to Use `createWorkflow`\n *\n * Use `createWorkflow` when you have:\n * - **Multiple dependent async operations** that need to run sequentially\n * - **Complex error handling** where you want type-safe error unions\n * - **Need for observability** via event streams (onEvent)\n * - **Step caching** requirements for expensive operations\n * - **Resume/replay** capabilities for long-running workflows\n * - **Human-in-the-loop** workflows requiring approvals\n *\n * ## Why Use `createWorkflow` Instead of `run()`\n *\n * 1. **Automatic Error Type Inference**: Errors are computed from your declared functions\n * - No manual error union management\n * - TypeScript ensures all possible errors are handled\n * - Refactoring is safer - adding/removing functions updates error types automatically\n *\n * 2. **Step Caching**: Expensive operations can be cached by key\n * - Prevents duplicate API calls\n * - Useful for idempotent operations\n * - Supports resume state for workflow replay\n *\n * 3. **Event Stream**: Built-in observability via `onEvent`\n * - Track workflow and step lifecycle\n * - Monitor performance (durationMs)\n * - Build dashboards and debugging tools\n *\n * 4. **Resume State**: Save and replay workflows\n * - Useful for long-running processes\n * - Supports human-in-the-loop workflows\n * - Enables workflow persistence across restarts\n *\n * ## How It Works\n *\n * 1. **Declare Dependencies**: Pass an object of Result-returning functions\n * 2. **Automatic Inference**: Error types are extracted from function return types\n * 3. **Execute Workflow**: Call the returned workflow function with your logic\n * 4. **Early Exit**: `step()` unwraps Results - on error, workflow exits immediately\n *\n * ## Error Type Inference\n *\n * The error union is automatically computed from all declared functions:\n * - Each function's error type is extracted\n * - Union of all errors is created\n * - Uncaught exceptions are mapped via `catchUnexpected` (default: `UnexpectedError`).\n *\n * ## Strict Mode\n *\n * Optional `catchUnexpected` maps uncaught exceptions to a typed error (closed union):\n * - When omitted, the default mapper returns an `UnexpectedError` instance.\n * - When provided, your error union is exactly `E | U`.\n *\n * @param deps - Object mapping names to Result-returning functions.\n * These functions must return `Result<T, E>` or `Promise<Result<T, E>>`.\n * The error types (`E`) from all functions are automatically combined into a union.\n * @param options - Optional configuration:\n * - `onEvent`: Callback for workflow/step lifecycle events\n * - `onError`: Callback for error logging/debugging\n * - `cache`: Step result cache (Map or custom StepCache implementation)\n * - `resumeState`: Pre-populated step results for workflow replay\n * - `createContext`: Factory for per-run context (passed to onEvent)\n * - `catchUnexpected`: Optional; map uncaught exceptions to a typed error (default: `UnexpectedError`)\n *\n * @returns A workflow function that accepts your workflow logic and returns an AsyncResult.\n * The error type is automatically inferred from the `deps` parameter.\n *\n * @example\n * ```typescript\n * // Basic usage - automatic error inference\n * const fetchUser = async (id: string): AsyncResult<User, 'NOT_FOUND'> =>\n * id === '1' ? ok({ id, name: 'Alice' }) : err('NOT_FOUND');\n *\n * const fetchPosts = async (userId: string): AsyncResult<Post[], 'FETCH_ERROR'> =>\n * ok([{ id: 1, title: 'Hello' }]);\n *\n * const getPosts = createWorkflow({ fetchUser, fetchPosts });\n *\n * const result = await getPosts(async ({ step }) => {\n * const user = await step(fetchUser('1'));\n * const posts = await step(fetchPosts(user.id));\n * return { user, posts };\n * });\n * // result.error: 'NOT_FOUND' | 'FETCH_ERROR' | UnexpectedError\n * ```\n *\n * @example\n * ```typescript\n * // With destructured deps in callback\n * const result = await getPosts(async ({ step, deps: { fetchUser, fetchPosts } }) => {\n * const user = await step(fetchUser('1'));\n * const posts = await step(fetchPosts(user.id));\n * return { user, posts };\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Strict mode - closed error union (no UnexpectedError)\n * const getPosts = createWorkflow(\n * { fetchUser, fetchPosts },\n * {\n * catchUnexpected: () => 'UNEXPECTED' as const\n * }\n * );\n * // result.error: 'NOT_FOUND' | 'FETCH_ERROR' | 'UNEXPECTED'\n * ```\n *\n * @example\n * ```typescript\n * // With step caching - both patterns work identically\n * const cache = new Map<string, Result<unknown, unknown>>();\n * const workflow = createWorkflow({ fetchUser }, { cache });\n *\n * const result = await workflow(async ({ step }) => {\n * // Function-wrapped pattern with key - cached and emits step_complete\n * const user1 = await step(() => fetchUser('1'), { key: 'user:1' });\n *\n * // Direct AsyncResult pattern with key - also cached and emits step_complete\n * const user2 = await step(fetchUser('1'), { key: 'user:2' });\n *\n * // Same key uses cache (fetchUser not called again)\n * const user3 = await step(() => fetchUser('1'), { key: 'user:1' });\n * return { user1, user2, user3 }; // user1 === user3 (from cache)\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With event stream for observability\n * const workflow = createWorkflow({ fetchUser }, {\n * onEvent: (event) => {\n * if (event.type === 'step_start') {\n * console.log(`Step ${event.name} started`);\n * }\n * if (event.type === 'step_success') {\n * console.log(`Step ${event.name} completed in ${event.durationMs}ms`);\n * }\n * }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With resume state for workflow replay\n * const savedState = { steps: new Map([['user:1', { result: ok({ id: '1', name: 'Alice' }) }]]) };\n * const workflow = createWorkflow({ fetchUser }, { resumeState: savedState });\n *\n * const result = await workflow(async ({ step }) => {\n * // This step uses cached result from savedState (fetchUser not called)\n * const user = await step(() => fetchUser('1'), { key: 'user:1' });\n * return user;\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With typed arguments (new API)\n * const workflow = createWorkflow({ fetchUser, fetchPosts });\n *\n * const result = await workflow(\n * { userId: '1' }, // Typed arguments\n * async ({ step, deps: { fetchUser, fetchPosts }, args: { userId } }) => {\n * const user = await step(fetchUser(userId));\n * const posts = await step(fetchPosts(user.id));\n * return { user, posts };\n * }\n * );\n * ```\n */\n// Overload: no deps (single argument); callback receives deps: unknown\nexport function createWorkflow<\n U = UnexpectedError,\n C = void\n>(\n workflowName: string\n): Workflow<never, U, unknown, C>;\n\n// Overload: with deps\nexport function createWorkflow<\n const Deps extends Readonly<Record<string, AnyResultFn>>,\n U = UnexpectedError,\n C = void\n>(\n workflowName: string,\n deps: Deps,\n options?: WorkflowOptions<ErrorsOfDeps<Deps>, U, C>\n): Workflow<ErrorsOfDeps<Deps>, U, Deps, C>;\n\n// Implementation (deps optional for 1-arg overload compatibility)\nexport function createWorkflow<\n const Deps extends Readonly<Record<string, AnyResultFn>>,\n U = UnexpectedError,\n C = void\n>(\n workflowName: string,\n deps?: Deps,\n options?: WorkflowOptions<ErrorsOfDeps<Deps>, U, C>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): any {\n type E = ErrorsOfDeps<Deps>;\n\n if (typeof workflowName !== \"string\" || workflowName.length === 0) {\n throw new TypeError(\n \"createWorkflow(workflowName, deps, options?): first argument must be a non-empty string. Example: createWorkflow('checkout', { chargeCard, sendEmail })\"\n );\n }\n\n const depsActual = deps ?? ({} as Deps);\n const optionsActual = options;\n\n // ===========================================================================\n\n // ===========================================================================\n // Internal execute function - core workflow execution logic\n // ===========================================================================\n async function internalExecute<T, ExtraE = never>(\n runName: string | undefined,\n userFn: WorkflowFn<T, E | ExtraE, Deps, C>,\n config?: RunConfig<E, U, C, Deps>\n ): Promise<Result<T, E | ExtraE | U, unknown>> {\n // Generate workflowId for this run\n const workflowId = runName ?? crypto.randomUUID();\n\n // Merge deps: config.deps partially overrides creation-time deps\n const effectiveDeps = config?.deps ? { ...depsActual, ...config.deps } as Deps : depsActual;\n\n // ===========================================================================\n // Resolve hooks: config?.x ?? options?.x (run-time overrides creation-time)\n // Note: config.x = undefined does NOT override (uses creation-time)\n // config.x = null DOES override (users asked for it)\n // ===========================================================================\n\n // Create context for this run (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const createContextFn = config?.createContext ?? (optionsActual as any)?.createContext;\n const context = createContextFn ? await createContextFn() : undefined as C;\n\n // Get workflow-level signal (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const workflowSignal = (config?.signal ?? (optionsActual as any)?.signal) as AbortSignal | undefined;\n\n // Get event handler (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const onEventHandler = config?.onEvent ?? (optionsActual as any)?.onEvent;\n\n // Get error handler (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const onErrorHandler = config?.onError ?? (optionsActual as any)?.onError;\n\n // Get shouldRun hook (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const shouldRunHook = (config?.shouldRun ?? (optionsActual as any)?.shouldRun) as\n | ((workflowId: string, context: C) => boolean | Promise<boolean>)\n | undefined;\n\n // Get onBeforeStart hook (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const onBeforeStartHook = (config?.onBeforeStart ?? (optionsActual as any)?.onBeforeStart) as\n | ((workflowId: string, context: C) => boolean | Promise<boolean>)\n | undefined;\n\n // Get onAfterStep hook (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const onAfterStepHook = (config?.onAfterStep ?? (optionsActual as any)?.onAfterStep) as\n | ((\n stepKey: string,\n result: Result<unknown, unknown, unknown>,\n workflowId: string,\n context: C\n ) => void | Promise<void>)\n | undefined;\n\n // Get resumeState (config overrides options) - keep lazy, only evaluate when needed\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const resumeStateOption = (config?.resumeState ?? (optionsActual as any)?.resumeState) as\n | ResumeState\n | (() => ResumeState | Promise<ResumeState>)\n | undefined;\n\n // catchUnexpected: from creation-time options or default (UnexpectedError).\n // When omitted, U = UnexpectedError and we use defaultCatchUnexpected.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const catchUnexpected = (optionsActual as any)?.catchUnexpected ?? defaultCatchUnexpected;\n\n // Create workflow data store for step outputs\n const workflowData: Record<string, unknown> = {};\n\n // Check if dev warnings are enabled (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const devWarnings = (config?.devWarnings ?? (optionsActual as any)?.devWarnings) === true && process.env.NODE_ENV !== 'production';\n const ctxSetWarned = new Set<string>(); // Avoid duplicate warnings per key\n const ctxGetWarned = new Set<string>();\n\n // Create workflow context object to pass to callback\n const workflowContext: WorkflowContext<C> = {\n workflowId,\n onEvent: onEventHandler as ((event: WorkflowEvent<unknown, C>) => void) | undefined,\n context: context !== undefined ? context : undefined,\n signal: workflowSignal,\n // Data store for static analysis\n input: {} as Record<string, unknown>,\n ref: <K extends string>(key: K) => workflowData[key] as never,\n set: <K extends string>(key: K, value: unknown) => {\n if (devWarnings && !ctxSetWarned.has(key)) {\n ctxSetWarned.add(key);\n console.warn(\n `awaitly: ctx.set('${key}', ...) is deprecated for static analysis. ` +\n `Use step('id', fn, { out: '${key}' }) instead.`\n );\n }\n workflowData[key] = value;\n },\n get: <K extends string>(key: K) => {\n if (devWarnings && !ctxGetWarned.has(key)) {\n ctxGetWarned.add(key);\n console.warn(\n `awaitly: ctx.get('${key}') is deprecated for static analysis. ` +\n `Use ctx.ref('${key}') instead for tracked dependencies.`\n );\n }\n return workflowData[key] as never;\n },\n };\n\n // Helper to emit workflow events (error union includes ExtraE from step.workflow/withFallback)\n const emitEvent = (event: WorkflowEvent<E | ExtraE | U, C>) => {\n // Add context to event only if:\n // 1. Event doesn't already have context (preserves replayed events or per-step overrides)\n // 2. Workflow actually has a context (don't add context: undefined property)\n const eventWithContext =\n event.context !== undefined || context === undefined\n ? event\n : ({ ...event, context: context as C } as WorkflowEvent<E | ExtraE | U, C>);\n const eventWithName =\n eventWithContext.workflowName === undefined\n ? ({ ...eventWithContext, workflowName } as WorkflowEvent<E | ExtraE | U, C>)\n : eventWithContext;\n onEventHandler?.(eventWithName as Parameters<NonNullable<typeof onEventHandler>>[0], context);\n };\n\n // Helper to create cancellation result (always map through catchUnexpected)\n const createCancelledResult = (reason?: string, lastStepKey?: string): Result<T, E | ExtraE | U, unknown> => {\n const cancelledError: WorkflowCancelledError = {\n type: \"WORKFLOW_CANCELLED\",\n reason,\n lastStepKey,\n };\n return err(catchUnexpected(cancelledError), { cause: cancelledError }) as Result<T, E | ExtraE | U, unknown>;\n };\n\n // Check if signal is already aborted before starting\n if (workflowSignal?.aborted) {\n const reason = typeof workflowSignal.reason === \"string\"\n ? workflowSignal.reason\n : workflowSignal.reason instanceof Error\n ? workflowSignal.reason.message\n : undefined;\n emitEvent({\n type: \"workflow_cancelled\",\n workflowId,\n ts: Date.now(),\n durationMs: 0,\n reason,\n });\n return createCancelledResult(reason);\n }\n\n if (shouldRunHook) {\n const hookStartTime = performance.now();\n try {\n const shouldRunResult = await shouldRunHook(workflowId, context);\n const hookDuration = performance.now() - hookStartTime;\n // Emit hook event\n emitEvent({\n type: \"hook_should_run\",\n workflowId,\n ts: Date.now(),\n durationMs: hookDuration,\n result: shouldRunResult,\n skipped: !shouldRunResult,\n });\n if (!shouldRunResult) {\n const skipCause = new Error(\"Workflow skipped by shouldRun hook\");\n return err(catchUnexpected(skipCause), { cause: skipCause }) as Result<T, E | ExtraE | U, unknown>;\n }\n } catch (thrown) {\n const hookDuration = performance.now() - hookStartTime;\n // Emit hook error event\n emitEvent({\n type: \"hook_should_run_error\",\n workflowId,\n ts: Date.now(),\n durationMs: hookDuration,\n error: thrown as E,\n });\n // Hook threw - map through catchUnexpected\n return err(catchUnexpected(thrown), { cause: thrown }) as Result<T, E | ExtraE | U, unknown>;\n }\n }\n\n if (onBeforeStartHook) {\n const hookStartTime = performance.now();\n try {\n const beforeStartResult = await onBeforeStartHook(workflowId, context);\n const hookDuration = performance.now() - hookStartTime;\n // Emit hook event\n emitEvent({\n type: \"hook_before_start\",\n workflowId,\n ts: Date.now(),\n durationMs: hookDuration,\n result: beforeStartResult,\n skipped: !beforeStartResult,\n });\n if (!beforeStartResult) {\n const skipCause = new Error(\"Workflow skipped by onBeforeStart hook\");\n return err(catchUnexpected(skipCause), { cause: skipCause }) as Result<T, E | ExtraE | U, unknown>;\n }\n } catch (thrown) {\n const hookDuration = performance.now() - hookStartTime;\n // Emit hook error event\n emitEvent({\n type: \"hook_before_start_error\",\n workflowId,\n ts: Date.now(),\n durationMs: hookDuration,\n error: thrown as E,\n });\n return err(catchUnexpected(thrown), { cause: thrown }) as Result<T, E | ExtraE | U, unknown>;\n }\n }\n\n // Validate input against schema if provided\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const inputSchema = (optionsActual as any)?.inputSchema;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const inputValue = (optionsActual as any)?.input;\n if (inputSchema && inputValue !== undefined) {\n const validationResult = await validateInput(inputSchema, inputValue);\n if (!validationResult.ok) {\n return err(validationResult.error) as Result<T, E | ExtraE | U, unknown>;\n }\n // Assign validated input to workflow context\n (workflowContext as { input: unknown }).input = validationResult.value;\n } else if (inputValue !== undefined) {\n // No schema, just pass input through to context\n (workflowContext as { input: unknown }).input = inputValue;\n }\n\n // Emit workflow_start\n const startTs = Date.now();\n const startTime = performance.now();\n emitEvent({\n type: \"workflow_start\",\n workflowId,\n ts: startTs,\n });\n\n // Get cache from config (overrides creation-time options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let cache = (config?.cache ?? (optionsActual as any)?.cache) as StepCache | undefined;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const streamStore = (config?.streamStore ?? (optionsActual as any)?.streamStore) as StreamStore | undefined;\n\n // If resumeState is provided but cache isn't, auto-create an in-memory cache\n if (resumeStateOption && !cache) {\n cache = new Map<string, Result<unknown, unknown, unknown>>();\n }\n\n // Pre-populate cache from resumeState (lazily evaluated)\n if (resumeStateOption && cache) {\n const resumeState =\n typeof resumeStateOption === \"function\"\n ? await resumeStateOption()\n : resumeStateOption;\n\n // Validate resumeState.steps is a Map (common mistake: JSON serialization loses Map)\n if (!(resumeState.steps instanceof Map)) {\n console.warn(\n `awaitly: resumeState.steps is not a Map (got ${typeof resumeState.steps}). ` +\n `This usually happens when state is serialized with JSON.stringify() directly.\\n` +\n `Use stringifyState() and parseState() from 'awaitly/persistence' instead:\\n` +\n ` import { stringifyState, parseState } from 'awaitly/persistence';\\n` +\n ` const json = stringifyState(state); // Save this\\n` +\n ` const restored = parseState(json); // Load this`\n );\n // Try to recover by converting plain object to Map\n if (typeof resumeState.steps === \"object\" && resumeState.steps !== null) {\n resumeState.steps = new Map(Object.entries(resumeState.steps));\n }\n }\n\n for (const [key, entry] of resumeState.steps) {\n const { result, meta } = entry;\n if (result.ok) {\n cache.set(key, result);\n } else {\n // Encode error results with metadata for proper replay\n // Use provided meta if available, otherwise default to origin:\"result\"\n const effectiveMeta = meta ?? { origin: \"result\" as const, resultCause: result.cause };\n // Preserve original cause alongside metadata\n cache.set(key, encodeCachedError(result.error, effectiveMeta, result.cause));\n }\n }\n }\n\n // Pre-populate cache from snapshot if provided via config (new API)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const snapshotOption = config?.snapshot ?? (optionsActual as any)?.snapshot as WorkflowSnapshot | null | undefined;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const snapshotSerialization = (optionsActual as any)?.serialization as { decode?: (value: JSONValue) => unknown } | undefined;\n if (snapshotOption && !resumeStateOption) {\n // Auto-create cache if needed\n if (!cache) {\n cache = new Map<string, Result<unknown, unknown, unknown>>();\n }\n\n const snapshot = snapshotOption;\n const decode = snapshotSerialization?.decode;\n\n for (const [stepId, stepResult] of Object.entries(snapshot.steps)) {\n if (!Object.prototype.hasOwnProperty.call(snapshot.steps, stepId)) {\n continue;\n }\n\n try {\n if (stepResult.ok) {\n // Decode value if decoder provided\n const value = decode ? decode(stepResult.value) : stepResult.value;\n cache.set(stepId, ok(value));\n } else {\n // Restore the original error value (decode if decoder provided)\n const errorValue = decode ? decode(stepResult.error) : stepResult.error;\n // Deserialize the cause (Error or thrown value)\n const deserializedCause = deserializeCauseNew(stepResult.cause);\n // Construct proper StepFailureMeta from snapshot\n const meta: StepFailureMeta = stepResult.meta?.origin === \"throw\"\n ? { origin: \"throw\", thrown: deserializedCause }\n : { origin: \"result\", resultCause: deserializedCause };\n cache.set(stepId, encodeCachedError(errorValue, meta, deserializedCause));\n }\n } catch (e) {\n throw new SnapshotDecodeError(\n `Failed to decode step \"${stepId}\": ${e instanceof Error ? e.message : String(e)}`,\n stepId,\n e instanceof Error ? e : undefined\n );\n }\n }\n }\n\n\n // Track abort state and last step key for mid-execution cancellation\n let abortedDuringExecution = false;\n let abortReason: string | undefined;\n let lastStepKey: string | undefined;\n\n // Set up abort listener if signal is provided\n const abortHandler = () => {\n abortedDuringExecution = true;\n abortReason = typeof workflowSignal?.reason === \"string\"\n ? workflowSignal.reason\n : workflowSignal?.reason instanceof Error\n ? workflowSignal.reason.message\n : undefined;\n };\n\n if (workflowSignal && !workflowSignal.aborted) {\n workflowSignal.addEventListener(\"abort\", abortHandler, { once: true });\n }\n\n // Helper to check for mid-execution cancellation and throw if aborted\n // lastStepKey = the last successfully completed keyed step (for resume purposes)\n const checkCancellation = (): void => {\n // Check both the flag and the signal directly (in case abort happened synchronously)\n if (abortedDuringExecution || workflowSignal?.aborted) {\n const reason = abortReason ?? (\n typeof workflowSignal?.reason === \"string\"\n ? workflowSignal.reason\n : workflowSignal?.reason instanceof Error\n ? workflowSignal.reason.message\n : undefined\n );\n const cancelledError: WorkflowCancelledError = {\n type: \"WORKFLOW_CANCELLED\",\n reason,\n lastStepKey,\n };\n // Throw to abort the workflow - will be caught by run() error handling\n throw cancelledError;\n }\n };\n\n // Helper to call onAfterStep hook with event emission\n const callOnAfterStepHook = async (\n stepKey: string,\n result: Result<unknown, unknown, unknown>,\n _meta?: StepFailureMeta\n ): Promise<void> => {\n if (!onAfterStepHook) return;\n const hookStartTime = performance.now();\n try {\n await onAfterStepHook(stepKey, result, workflowId, context);\n const hookDuration = performance.now() - hookStartTime;\n emitEvent({\n type: \"hook_after_step\",\n workflowId,\n stepKey,\n ts: Date.now(),\n durationMs: hookDuration,\n });\n } catch (thrown) {\n const hookDuration = performance.now() - hookStartTime;\n emitEvent({\n type: \"hook_after_step_error\",\n workflowId,\n stepKey,\n ts: Date.now(),\n durationMs: hookDuration,\n error: thrown as E,\n });\n // Re-throw to maintain original behavior\n throw thrown;\n }\n };\n\n // Create a cached step wrapper\n const createCachedStep = (realStep: RunStep<E>): RunStep<E> => {\n // NOTE: We always create the wrapper because streaming methods (streamForEach, getWritable,\n // getReadable) are defined on cachedStepFn, not realStep. Even without cache/hooks/signal/\n // streamStore, the workflow may use step.streamForEach with async iterables.\n\n // Wrap the main step function with backward-compatible signature\n // Supports: step('id', fn, opts), step(fn, opts?), step(result, opts?)\n const cachedStepFn = async <StepT, StepE extends E, StepC = unknown>(\n idOrOperationOrResult: string | (() => Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>) | Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>,\n operationOrOptions?: (() => Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>) | StepOptions | string,\n stepOptions?: StepOptions\n ): Promise<StepT> => {\n // Validate required string ID as first argument\n if (typeof idOrOperationOrResult !== 'string') {\n throw new Error(\n '[awaitly] step() requires a string ID as the first argument. ' +\n 'Example: step(\"fetchUser\", () => fetchUser(id))'\n );\n }\n\n // Parse arguments: step('id', fn, opts)\n const id = idOrOperationOrResult;\n const opts = stepOptions ?? {};\n\n // Name is always derived from ID\n const name = id;\n // Use cache by id when key is omitted; when key is explicitly set (including undefined) use that (undefined = don't cache)\n const key = Object.prototype.hasOwnProperty.call(opts, \"key\")\n ? opts.key\n : id;\n const { ttl, out } = opts;\n\n // Check for cancellation before starting step\n // Use lastStepKey (last completed step) for reporting, not the step about to run\n checkCancellation();\n\n // Update lastStepKey AFTER the step completes (moved to success/error handlers below)\n // This ensures lastStepKey always means \"last successfully completed keyed step\"\n\n // Extract metadata for cache events (same extraction as core step function)\n const stepMetadata = extractStepMetadata(opts);\n\n // Only use cache if key is provided and cache exists\n if (key && cache && cache.has(key)) {\n emitEvent({\n type: \"step_cache_hit\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n\n const cached = cache.get(key)!;\n if (cached.ok) {\n // Update lastStepKey for cache hits too (step effectively completed)\n lastStepKey = key;\n // Store result in workflow data if 'out' is specified (even for cache hits)\n if (out) {\n workflowData[out] = cached.value;\n }\n return cached.value as StepT;\n }\n // Cached error - throw early exit with preserved metadata (origin + cause)\n // This bypasses realStep to avoid replaying step_start/step_error events\n const meta = decodeCachedMeta(cached.cause);\n throw createEarlyExit(cached.error as StepE, meta);\n }\n\n // Cache miss - emit event only if caching is enabled\n if (key && cache) {\n emitEvent({\n type: \"step_cache_miss\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n\n try {\n // Pass arguments to realStep: step('id', fn, opts)\n const value = await (realStep as CallableFunction)(\n id,\n operationOrOptions,\n opts\n );\n // Store result in workflow data if 'out' is specified\n if (out) {\n workflowData[out] = value;\n }\n // Cache successful result if key provided\n if (key) {\n // Update lastStepKey on successful completion (for cancellation reporting)\n lastStepKey = key;\n if (cache) {\n cache.set(key, ok(value), ttl ? { ttl } : undefined);\n }\n // Call onAfterStep hook for checkpointing (even without cache)\n await callOnAfterStepHook(key, ok(value));\n }\n return value;\n } catch (thrown) {\n // Cache error results with full metadata if key provided and this is an early exit\n if (key && isEarlyExit(thrown)) {\n const exit = thrown as EarlyExit<StepE>;\n // Extract original cause from metadata for preservation\n const originalCause =\n exit.meta.origin === \"result\"\n ? exit.meta.resultCause\n : exit.meta.origin === \"throw\"\n ? exit.meta.thrown\n : undefined;\n const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);\n if (cache) {\n cache.set(key, errorResult, ttl ? { ttl } : undefined);\n }\n // Call onAfterStep hook for checkpointing (even on error, even without cache)\n await callOnAfterStepHook(key, errorResult, exit.meta);\n }\n throw thrown;\n }\n };\n\n // Wrap step.try\n cachedStepFn.try = async <StepT, Err extends E>(\n id: string,\n operation: () => StepT | Promise<StepT>,\n opts:\n | { error: Err; key?: string; ttl?: number }\n | { onError: (cause: unknown) => Err; key?: string; ttl?: number }\n ): Promise<StepT> => {\n const { ttl } = opts;\n const key = opts.key ?? id; // step.try caches by id when key omitted (for resume)\n const name = id;\n\n if (cache && cache.has(key)) {\n emitEvent({\n type: \"step_cache_hit\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n });\n\n const cached = cache.get(key)!;\n if (cached.ok) {\n return cached.value as StepT;\n }\n const meta = decodeCachedMeta(cached.cause);\n throw createEarlyExit(cached.error as Err, meta);\n }\n\n if (cache) {\n emitEvent({\n type: \"step_cache_miss\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n });\n }\n\n try {\n const value = await realStep.try(id, operation, { ...opts, key });\n if (cache) {\n cache.set(key, ok(value), ttl ? { ttl } : undefined);\n }\n await callOnAfterStepHook(key, ok(value));\n return value;\n } catch (thrown) {\n if (isEarlyExit(thrown)) {\n const exit = thrown as EarlyExit<Err>;\n const originalCause =\n exit.meta.origin === \"result\"\n ? exit.meta.resultCause\n : exit.meta.origin === \"throw\"\n ? exit.meta.thrown\n : undefined;\n const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);\n if (cache) {\n cache.set(key, errorResult, ttl ? { ttl } : undefined);\n }\n await callOnAfterStepHook(key, errorResult, exit.meta);\n }\n throw thrown;\n }\n };\n\n // Wrap step.fromResult - delegate to real step (caching handled by key in opts)\n cachedStepFn.fromResult = async <StepT, ResultE, Err extends E>(\n id: string,\n operation: () => Result<StepT, ResultE, unknown> | AsyncResult<StepT, ResultE, unknown>,\n opts:\n | { error: Err; key?: string; ttl?: number }\n | { onError: (resultError: ResultE) => Err; key?: string; ttl?: number }\n ): Promise<StepT> => {\n const { ttl } = opts;\n const key = opts.key ?? id; // step.fromResult caches by id when key omitted (for resume)\n const name = id;\n\n if (cache && cache.has(key)) {\n emitEvent({\n type: \"step_cache_hit\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n });\n\n const cached = cache.get(key)!;\n if (cached.ok) {\n return cached.value as StepT;\n }\n const meta = decodeCachedMeta(cached.cause);\n throw createEarlyExit(cached.error as Err, meta);\n }\n\n if (cache) {\n emitEvent({\n type: \"step_cache_miss\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n });\n }\n\n try {\n const value = await realStep.fromResult(id, operation, { ...opts, key });\n if (cache) {\n cache.set(key, ok(value), ttl ? { ttl } : undefined);\n }\n await callOnAfterStepHook(key, ok(value));\n return value;\n } catch (thrown) {\n if (isEarlyExit(thrown)) {\n const exit = thrown as EarlyExit<Err>;\n const originalCause =\n exit.meta.origin === \"result\"\n ? exit.meta.resultCause\n : exit.meta.origin === \"throw\"\n ? exit.meta.thrown\n : undefined;\n const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);\n if (cache) {\n cache.set(key, errorResult, ttl ? { ttl } : undefined);\n }\n await callOnAfterStepHook(key, errorResult, exit.meta);\n }\n throw thrown;\n }\n };\n\n // Wrap step.parallel - delegate to real step (no caching for scope wrappers)\n cachedStepFn.parallel = realStep.parallel;\n\n // Wrap step.race - delegate to real step (no caching for scope wrappers)\n cachedStepFn.race = realStep.race;\n\n // Wrap step.allSettled - delegate to real step (no caching for scope wrappers)\n cachedStepFn.allSettled = realStep.allSettled;\n\n // Wrap step.withFallback - preserve fallback semantics while adding workflow cache hooks.\n // Accept any operation/fallback error types (E1, E2) so users never need to cast; cast internally for core.\n cachedStepFn.withFallback = async <StepT, E1, E2>(\n id: string,\n operation: () => AsyncResult<StepT, E1>,\n options: { on?: E1 & string; fallback: () => AsyncResult<StepT, E2>; key?: string }\n ): Promise<StepT> => {\n const key = options.key ?? id; // matches core withFallback cache key behavior\n const name = id;\n\n if (cache && cache.has(key)) {\n emitEvent({\n type: \"step_cache_hit\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n });\n\n const cached = cache.get(key)!;\n if (cached.ok) {\n return cached.value as StepT;\n }\n const meta = decodeCachedMeta(cached.cause);\n throw createEarlyExit(cached.error as E, meta);\n }\n\n if (cache) {\n emitEvent({\n type: \"step_cache_miss\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n });\n }\n\n try {\n const value = await realStep.withFallback(\n id,\n operation as () => AsyncResult<StepT, E>,\n options as { on?: E & string; fallback: () => AsyncResult<StepT, E>; key?: string }\n );\n if (cache) {\n cache.set(key, ok(value));\n }\n await callOnAfterStepHook(key, ok(value));\n return value;\n } catch (thrown) {\n if (isEarlyExit(thrown)) {\n const exit = thrown as EarlyExit<E>;\n const originalCause =\n exit.meta.origin === \"result\"\n ? exit.meta.resultCause\n : exit.meta.origin === \"throw\"\n ? exit.meta.thrown\n : undefined;\n const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);\n if (cache) {\n cache.set(key, errorResult);\n }\n await callOnAfterStepHook(key, errorResult, exit.meta);\n }\n throw thrown;\n }\n };\n\n // Wrap step.withResource - run via core then call onAfterStep (keyed by id, consistent with other keyed steps)\n cachedStepFn.withResource = async <T, R, AcquireE extends E, UseE extends E>(\n id: string,\n options: {\n acquire: () => AsyncResult<R, AcquireE>;\n use: (resource: R) => AsyncResult<T, UseE>;\n release: (resource: R) => void | Promise<void>;\n }\n ): Promise<T> => {\n const key = id;\n try {\n const value = await realStep.withResource(id, options);\n await callOnAfterStepHook(key, ok(value));\n return value;\n } catch (thrown) {\n if (isEarlyExit(thrown)) {\n const exit = thrown as EarlyExit<E>;\n const originalCause =\n exit.meta.origin === \"result\"\n ? exit.meta.resultCause\n : exit.meta.origin === \"throw\"\n ? exit.meta.thrown\n : undefined;\n const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);\n await callOnAfterStepHook(key, errorResult, exit.meta);\n }\n throw thrown;\n }\n };\n\n // Wrap step.retry - pass key explicitly so \"no key\" means don't cache (cachedStepFn treats key: undefined as no cache)\n cachedStepFn.retry = <StepT, StepE extends E, StepC = unknown>(\n id: string,\n operation: () => Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>,\n options: RetryOptions & { key?: string; timeout?: TimeoutOptions; ttl?: number }\n ): Promise<StepT> => {\n const stepOptions = {\n key: options.key, // explicitly pass so undefined = don't cache\n retry: {\n attempts: options.attempts,\n backoff: options.backoff,\n initialDelay: options.initialDelay,\n maxDelay: options.maxDelay,\n jitter: options.jitter,\n retryOn: options.retryOn,\n onRetry: options.onRetry,\n },\n timeout: options.timeout,\n ttl: options.ttl,\n };\n\n return cachedStepFn(id, operation, stepOptions);\n };\n\n // Wrap step.withTimeout - pass key explicitly so \"no key\" means don't cache\n cachedStepFn.withTimeout = <StepT, StepE extends E, StepC = unknown>(\n id: string,\n operation:\n | (() => Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>)\n | ((signal: AbortSignal) => Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>),\n options: TimeoutOptions & { key?: string; ttl?: number }\n ): Promise<StepT> => {\n const stepOptions = {\n key: options.key,\n timeout: options,\n ttl: options.ttl,\n };\n\n return cachedStepFn(\n id,\n operation as () => Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>,\n stepOptions\n );\n };\n\n // Wrap step.sleep - only use cache when explicit key is provided\n cachedStepFn.sleep = (\n id: string,\n duration: string | DurationType,\n options?: { key?: string; ttl?: number; description?: string; signal?: AbortSignal }\n ): Promise<void> => {\n if (typeof id !== \"string\" || id.length === 0) {\n throw new Error(\n \"[awaitly] step.sleep() requires an explicit string ID as the first argument. \" +\n 'Example: step.sleep(\"delay\", \"5s\")'\n );\n }\n const d = typeof duration === \"string\" ? parseDuration(duration) : duration;\n if (!d) {\n throw new Error(`step.sleep: invalid duration '${duration}'`);\n }\n const ms = toMillis(d);\n\n const userSignal = options?.signal;\n\n const sleepOperation = async (): AsyncResult<void, never> => {\n // Check if already aborted (workflow or user signal)\n if (workflowSignal?.aborted || userSignal?.aborted) {\n const e = new Error(\"Sleep aborted\");\n e.name = \"AbortError\";\n throw e;\n }\n\n return new Promise<Result<void, never>>((resolve, reject) => {\n const state = {\n timeoutId: undefined as ReturnType<typeof setTimeout> | undefined,\n };\n\n const onAbort = () => {\n if (state.timeoutId) clearTimeout(state.timeoutId);\n const e = new Error(\"Sleep aborted\");\n e.name = \"AbortError\";\n reject(e);\n };\n\n workflowSignal?.addEventListener(\"abort\", onAbort, { once: true });\n userSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n state.timeoutId = setTimeout(() => {\n workflowSignal?.removeEventListener(\"abort\", onAbort);\n userSignal?.removeEventListener(\"abort\", onAbort);\n resolve(ok(undefined));\n }, ms);\n });\n };\n\n return cachedStepFn(id, sleepOperation, {\n key: options?.key,\n ttl: options?.ttl,\n description: options?.description,\n });\n };\n\n // ===========================================================================\n // Streaming Methods\n // ===========================================================================\n\n // Store active writers and their backpressure controllers\n const activeWriters = new Map<string, {\n writer: StreamWriter<unknown>;\n backpressure: BackpressureController;\n aborted: boolean;\n closed: boolean;\n }>();\n\n // Store active readers\n const activeReaders = new Map<string, {\n reader: StreamReader<unknown>;\n position: number;\n closed: boolean;\n }>();\n\n cachedStepFn.getWritable = <T>(\n options?: StreamWritableOptions\n ): StreamWriterInterface<T> => {\n const namespace = options?.namespace ?? \"default\";\n const highWaterMark = options?.highWaterMark ?? 16;\n\n if (!streamStore) {\n throw new Error(\n \"streamStore is required to use getWritable(). \" +\n \"Pass a streamStore to createWorkflow options.\"\n );\n }\n\n // Check if writer already exists for this namespace\n const existingKey = `${workflowId}:${namespace}`;\n const existing = activeWriters.get(existingKey);\n if (existing && !existing.closed && !existing.aborted) {\n return existing.writer as StreamWriter<T>;\n }\n\n // Create backpressure controller\n const backpressure = createBackpressureController({\n highWaterMark,\n onStateChange: (state) => {\n emitEvent({\n type: \"stream_backpressure\",\n workflowId,\n namespace,\n bufferedCount: backpressure.bufferedCount,\n state,\n ts: Date.now(),\n });\n },\n });\n\n let position = 0;\n let writable = true;\n let aborted = false;\n let closed = false;\n\n // Emit stream_created event\n emitEvent({\n type: \"stream_created\",\n workflowId,\n namespace,\n ts: Date.now(),\n });\n\n const writer: StreamWriter<T> = {\n async write(value: T): AsyncResult<void, StreamWriteError> {\n if (closed) {\n return err(streamWriteError(\"closed\", \"Stream is closed\"));\n }\n if (aborted) {\n return err(streamWriteError(\"aborted\", \"Stream was aborted\"));\n }\n\n // Check backpressure\n if (backpressure.state === \"paused\") {\n await backpressure.waitForDrain();\n }\n\n // Write to store\n const item: StreamItem<T> = {\n value,\n position,\n ts: Date.now(),\n };\n\n const result = await streamStore.append<T>(workflowId, namespace, item);\n if (!result.ok) {\n emitEvent({\n type: \"stream_error\",\n workflowId,\n namespace,\n error: result.error,\n position,\n ts: Date.now(),\n });\n return err(streamWriteError(\"store_error\", result.error.message, result.error));\n }\n\n // Emit write event\n emitEvent({\n type: \"stream_write\",\n workflowId,\n namespace,\n position,\n ts: Date.now(),\n });\n\n position++;\n backpressure.increment();\n\n return ok(undefined);\n },\n\n async close(): AsyncResult<void, StreamCloseError> {\n if (closed) {\n return err(streamCloseError(\"already_closed\", \"Stream is already closed\"));\n }\n\n const result = await streamStore.closeStream(workflowId, namespace);\n if (!result.ok) {\n return err(streamCloseError(\"store_error\", result.error.message, result.error));\n }\n\n closed = true;\n writable = false;\n\n // Emit close event\n emitEvent({\n type: \"stream_close\",\n workflowId,\n namespace,\n finalPosition: position,\n ts: Date.now(),\n });\n\n // Clean up\n activeWriters.delete(existingKey);\n\n return ok(undefined);\n },\n\n abort(reason: unknown): void {\n aborted = true;\n writable = false;\n closed = true;\n\n emitEvent({\n type: \"stream_error\",\n workflowId,\n namespace,\n error: reason,\n position,\n ts: Date.now(),\n });\n\n // Clean up\n activeWriters.delete(existingKey);\n },\n\n get writable() {\n return writable;\n },\n\n get position() {\n return position;\n },\n\n get namespace() {\n return namespace;\n },\n };\n\n activeWriters.set(existingKey, {\n writer: writer as StreamWriter<unknown>,\n backpressure,\n aborted,\n closed,\n });\n\n return writer;\n };\n\n cachedStepFn.getReadable = <T>(\n options?: StreamReadableOptions\n ): StreamReaderInterface<T> => {\n const namespace = options?.namespace ?? \"default\";\n const startIndex = options?.startIndex ?? 0;\n const pollInterval = options?.pollInterval ?? 10;\n const pollTimeout = options?.pollTimeout ?? 30000;\n\n if (!streamStore) {\n throw new Error(\n \"streamStore is required to use getReadable(). \" +\n \"Pass a streamStore to createWorkflow options.\"\n );\n }\n\n const existingKey = `${workflowId}:${namespace}:${startIndex}`;\n const existing = activeReaders.get(existingKey);\n if (existing && !existing.closed) {\n return existing.reader as StreamReader<T>;\n }\n\n // Helper to decrement backpressure when items are consumed\n const decrementBackpressure = () => {\n const writerKey = `${workflowId}:${namespace}`;\n const activeWriter = activeWriters.get(writerKey);\n if (activeWriter) {\n activeWriter.backpressure.decrement();\n }\n };\n\n let position = startIndex;\n let readable = true;\n let closed = false;\n let bufferedItems: StreamItem<T>[] = [];\n let bufferIndex = 0;\n\n const reader: StreamReader<T> = {\n async read(): AsyncResult<T, StreamReadError | StreamEndedMarker> {\n if (closed) {\n return err(streamReadError(\"closed\", \"Reader is closed\"));\n }\n\n // Check if we have buffered items\n if (bufferIndex < bufferedItems.length) {\n const item = bufferedItems[bufferIndex++];\n position = item.position + 1;\n\n // Release backpressure for consumed item\n decrementBackpressure();\n\n emitEvent({\n type: \"stream_read\",\n workflowId,\n namespace,\n position: item.position,\n ts: Date.now(),\n });\n\n return ok(item.value);\n }\n\n // Poll for items from store with timeout\n // We poll even if there's no active writer yet, as one may appear\n const writerKey = `${workflowId}:${namespace}`;\n const pollStart = Date.now();\n let hasSeenWriter = activeWriters.has(writerKey);\n\n // Check initial state\n const initialMetaResult = await streamStore.getMetadata(workflowId, namespace);\n let hasSeenMetadata = initialMetaResult.ok && initialMetaResult.value !== undefined;\n\n while (Date.now() - pollStart < pollTimeout) {\n const result = await streamStore.read<T>(workflowId, namespace, position, 100);\n if (!result.ok) {\n return err(streamReadError(\"store_error\", result.error.message, result.error));\n }\n\n const items = result.value;\n if (items.length > 0) {\n // Buffer items and return first\n bufferedItems = items;\n bufferIndex = 1;\n const item = items[0];\n position = item.position + 1;\n\n // Release backpressure for consumed item\n decrementBackpressure();\n\n emitEvent({\n type: \"stream_read\",\n workflowId,\n namespace,\n position: item.position,\n ts: Date.now(),\n });\n\n return ok(item.value);\n }\n\n // Check current state\n const writerActive = activeWriters.has(writerKey);\n const metaResult = await streamStore.getMetadata(workflowId, namespace);\n const metadataExists = metaResult.ok && metaResult.value !== undefined;\n\n // Track if we've ever seen a writer or metadata\n if (writerActive) hasSeenWriter = true;\n if (metadataExists) hasSeenMetadata = true;\n\n // Stream is closed - no more items coming\n if (metaResult.ok && metaResult.value?.closed) {\n readable = false;\n return err(streamEnded(position));\n }\n\n // If we've seen a writer or metadata but now it's gone and empty,\n // the stream has ended without more items\n if (hasSeenWriter && !writerActive && !metadataExists) {\n // Writer was created and removed without writing anything\n readable = false;\n return err(streamEnded(position));\n }\n\n if (hasSeenMetadata && !writerActive && metaResult.ok && !metaResult.value?.closed) {\n // Stream exists, writer is gone, but stream not closed\n // This means writer finished - wait a bit more for any pending writes\n // then give up\n }\n\n // Stream is still open or writer may still appear - wait and poll again\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n // Poll timeout - treat as stream ended\n readable = false;\n return err(streamEnded(position));\n },\n\n close(): void {\n closed = true;\n readable = false;\n bufferedItems = [];\n activeReaders.delete(existingKey);\n },\n\n get readable() {\n return readable;\n },\n\n get position() {\n return position;\n },\n\n get namespace() {\n return namespace;\n },\n };\n\n activeReaders.set(existingKey, {\n reader: reader as StreamReader<unknown>,\n position,\n closed,\n });\n\n return reader;\n };\n\n cachedStepFn.streamForEach = async <T, R, StepE extends E>(\n source: StreamReaderInterface<T> | AsyncIterable<T>,\n processor: (item: T, index: number) => AsyncResult<R, StepE>,\n options?: StreamForEachStepOptions\n ): Promise<StreamForEachResultType<R>> => {\n const checkpointInterval = options?.checkpointInterval ?? 1;\n const concurrency = options?.concurrency ?? 1;\n const results: R[] = [];\n let processedCount = 0;\n let lastPosition = -1;\n\n // Helper to check if source is a StreamReader\n const isStreamReader = (s: unknown): s is StreamReaderInterface<T> => {\n return (\n typeof s === \"object\" &&\n s !== null &&\n \"read\" in s &&\n typeof (s as StreamReaderInterface<T>).read === \"function\"\n );\n };\n\n // Helper to process a single item with step()\n const processItem = async (\n item: T,\n itemIndex: number,\n itemPosition: number,\n namespace: string\n ): Promise<{ index: number; position: number; result: R }> => {\n const shouldCheckpoint = checkpointInterval > 0 && itemIndex % checkpointInterval === 0;\n const stepKey = shouldCheckpoint\n ? `stream-foreach:${namespace}:pos-${itemPosition}`\n : undefined;\n\n const stepId = stepKey ?? `stream-item-${itemPosition}`;\n const stepResult = await cachedStepFn(\n stepId,\n () => processor(item, itemIndex),\n { key: stepKey }\n );\n\n return { index: itemIndex, position: itemPosition, result: stepResult };\n };\n\n if (isStreamReader(source)) {\n if (concurrency <= 1) {\n // Sequential processing (original behavior)\n let itemPosition = source.position;\n let readResult = await source.read();\n while (readResult.ok) {\n const item = readResult.value;\n const { result } = await processItem(item, processedCount, itemPosition, source.namespace);\n results.push(result);\n lastPosition = itemPosition;\n processedCount++;\n itemPosition = source.position;\n readResult = await source.read();\n }\n } else {\n // Concurrent processing - interleave reading and processing\n const resultsMap = new Map<number, { position: number; result: R }>();\n let itemIndex = 0;\n let totalItems = 0;\n\n // Track slots with wrapped promises that include slot index\n type SlotResult = { slotIndex: number; index: number; position: number; result: R };\n const slots: (Promise<SlotResult> | null)[] = new Array(concurrency).fill(null);\n\n // Helper to find an empty slot, waiting if necessary\n const getSlot = async (): Promise<number> => {\n // First, check for empty slots\n for (let i = 0; i < slots.length; i++) {\n if (slots[i] === null) return i;\n }\n // No empty slots - wait for one to complete\n const activePromises = slots.filter((s): s is Promise<SlotResult> => s !== null);\n const completed = await Promise.race(activePromises);\n resultsMap.set(completed.index, { position: completed.position, result: completed.result });\n // Clear the slot that completed (we know which one from slotIndex)\n slots[completed.slotIndex] = null;\n return completed.slotIndex;\n };\n\n // Read and process items concurrently\n let itemPosition = source.position;\n let readResult = await source.read();\n\n while (readResult.ok) {\n const slotIndex = await getSlot();\n\n // Capture current values for closure\n const currentIndex = itemIndex;\n const currentPosition = itemPosition;\n const currentItem = readResult.value;\n const currentSlot = slotIndex;\n\n // Start processing in this slot, wrapping to include slot index\n slots[slotIndex] = processItem(currentItem, currentIndex, currentPosition, source.namespace)\n .then(r => ({ slotIndex: currentSlot, ...r }));\n totalItems++;\n itemIndex++;\n\n // Read next item\n itemPosition = source.position;\n readResult = await source.read();\n }\n\n // Wait for all remaining slots to complete\n for (let i = 0; i < slots.length; i++) {\n if (slots[i] !== null) {\n const result = await slots[i]!;\n resultsMap.set(result.index, { position: result.position, result: result.result });\n }\n }\n\n // Collect results in order\n for (let i = 0; i < totalItems; i++) {\n const entry = resultsMap.get(i);\n if (entry) {\n results.push(entry.result);\n lastPosition = entry.position;\n processedCount++;\n }\n }\n }\n } else {\n // Process from AsyncIterable\n if (concurrency <= 1) {\n // Sequential processing\n let index = 0;\n for await (const item of source) {\n const { result } = await processItem(item, index, index, \"async-iterable\");\n results.push(result);\n lastPosition = index;\n processedCount++;\n index++;\n }\n } else {\n // Concurrent processing - interleave iteration and processing\n const resultsMap = new Map<number, R>();\n let itemIndex = 0;\n let totalItems = 0;\n\n // Track slots with wrapped promises that include slot index\n type SlotResult = { slotIndex: number; index: number; position: number; result: R };\n const slots: (Promise<SlotResult> | null)[] = new Array(concurrency).fill(null);\n\n // Helper to find an empty slot, waiting if necessary\n const getSlot = async (): Promise<number> => {\n // First, check for empty slots\n for (let i = 0; i < slots.length; i++) {\n if (slots[i] === null) return i;\n }\n // No empty slots - wait for one to complete\n const activePromises = slots.filter((s): s is Promise<SlotResult> => s !== null);\n const completed = await Promise.race(activePromises);\n resultsMap.set(completed.index, completed.result);\n // Clear the slot that completed (we know which one from slotIndex)\n slots[completed.slotIndex] = null;\n return completed.slotIndex;\n };\n\n // Iterate and process items concurrently\n for await (const item of source) {\n const slotIndex = await getSlot();\n\n // Capture current values for closure\n const currentIndex = itemIndex;\n const currentSlot = slotIndex;\n\n // Start processing in this slot, wrapping to include slot index\n slots[slotIndex] = processItem(item, currentIndex, currentIndex, \"async-iterable\")\n .then(r => ({ slotIndex: currentSlot, ...r }));\n totalItems++;\n itemIndex++;\n }\n\n // Wait for all remaining slots to complete\n for (let i = 0; i < slots.length; i++) {\n if (slots[i] !== null) {\n const result = await slots[i]!;\n resultsMap.set(result.index, result.result);\n }\n }\n\n // Collect results in order\n for (let i = 0; i < totalItems; i++) {\n // Use has() instead of checking result !== undefined because\n // the processor may legitimately return ok(undefined)\n if (resultsMap.has(i)) {\n results.push(resultsMap.get(i) as R);\n lastPosition = i;\n processedCount++;\n }\n }\n }\n }\n\n return {\n results,\n processedCount,\n lastPosition,\n };\n };\n\n // step.if: Delegate to real step (no caching needed - just returns condition result)\n cachedStepFn.if = realStep.if;\n\n // step.label: Alias for step.if - delegate to real step\n cachedStepFn.label = realStep.label;\n\n // step.branch: Delegate to real step (evaluates condition and executes arm)\n cachedStepFn.branch = realStep.branch;\n\n // step.arm: Delegate to real step (returns arm definition)\n cachedStepFn.arm = realStep.arm;\n\n // step.forEach: Delegate to real step (executes loop)\n cachedStepFn.forEach = realStep.forEach;\n\n // step.item: Delegate to real step (returns item handler)\n cachedStepFn.item = realStep.item;\n\n // step.dep: Delegate to real step (no caching needed - just returns function unchanged)\n cachedStepFn.dep = realStep.dep;\n\n // Effect-style ergonomics: Route through cached step so cache/onAfterStep apply.\n // Accept either AsyncResult or () => AsyncResult (getter) so cache hits never run the getter.\n cachedStepFn.run = (\n id: string,\n resultOrGetter: AsyncResult<unknown, E, unknown> | (() => AsyncResult<unknown, E, unknown>),\n options?: StepOptions\n ) => {\n const op =\n typeof resultOrGetter === \"function\"\n ? (resultOrGetter as () => AsyncResult<unknown, E, unknown>)\n : () => resultOrGetter as AsyncResult<unknown, E, unknown>;\n return cachedStepFn(id, op, options) as Promise<unknown>;\n };\n // step.workflow: run sub-workflow (or any AsyncResult getter) as a step; cache + onAfterStep apply\n cachedStepFn.workflow = (\n id: string,\n getter: () => AsyncResult<unknown, E, unknown>,\n options?: StepOptions\n ) => cachedStepFn(id, getter, options) as Promise<unknown>;\n cachedStepFn.andThen = (\n id: string,\n value: unknown,\n fn: (value: unknown) => AsyncResult<unknown, E, unknown>,\n options?: StepOptions\n ) => cachedStepFn(id, () => fn(value) as AsyncResult<unknown, E, unknown>, options) as Promise<unknown>;\n cachedStepFn.match = (\n id: string,\n result: Result<unknown, E, unknown> | AsyncResult<unknown, E, unknown>,\n handlers: {\n ok: (value: unknown) => unknown | Promise<unknown>;\n err: (error: E, cause?: unknown) => unknown | Promise<unknown>;\n },\n options?: StepOptions\n ) =>\n cachedStepFn(\n id,\n async () => {\n const resolved = await result;\n if (resolved.ok) {\n return ok(await handlers.ok(resolved.value));\n }\n return ok(await handlers.err(resolved.error, resolved.cause));\n },\n options\n ) as Promise<unknown>;\n // Match core: all() with no key = no cache (core parallel doesn't pass key, so no cache by id)\n cachedStepFn.all = (id: string, shape: Parameters<RunStep<E>[\"all\"]>[1], options?: StepOptions) => {\n const opts =\n options !== undefined && Object.prototype.hasOwnProperty.call(options, \"key\")\n ? options\n : { ...options, key: undefined as string | undefined };\n return cachedStepFn(id, async () => ok(await realStep.all(id, shape)), opts) as Promise<unknown>;\n };\n // Match core: step.map() passes { key: options?.key }, so omitted key = no cache (core never caches by id for map)\n cachedStepFn.map = (\n id: string,\n items: unknown[],\n mapper: (item: unknown, index: number) => AsyncResult<unknown, E, unknown>,\n options?: { concurrency?: number; key?: string }\n ) => {\n const opts =\n options !== undefined && Object.prototype.hasOwnProperty.call(options, \"key\")\n ? options\n : { ...options, key: undefined as string | undefined };\n return cachedStepFn(id, async () => ok(await realStep.map(id, items, mapper, options)), opts) as Promise<unknown>;\n };\n\n return cachedStepFn as RunStep<E>;\n };\n\n // Wrap the user's callback to pass cached step, deps, and workflow context.\n // Cast step to RunStep<E | ExtraE> so callbacks using step.workflow/withFallback get correct error inference.\n const wrappedFn = ({ step }: { step: RunStep<E> }) =>\n userFn({\n step: createCachedStep(step) as RunStep<E | ExtraE>,\n deps: effectiveDeps,\n ctx: workflowContext,\n });\n\n // Always use run() with catchUnexpected (default or user-provided). Closed error union E | ExtraE | U.\n let result: Result<T, E | ExtraE | U | UnexpectedError | WorkflowCancelledError, unknown>;\n\n try {\n result = await run<T, E | ExtraE | U, C>(wrappedFn as (context: { step: RunStep<E | ExtraE | U> }) => Promise<T> | T, {\n onError: onErrorHandler as ((error: E | ExtraE | U, stepName?: string, ctx?: C) => void) | undefined,\n onEvent: onEventHandler as ((event: WorkflowEvent<E | ExtraE | U | UnexpectedError, C>, ctx: C) => void) | undefined,\n catchUnexpected: catchUnexpected as (cause: unknown) => U,\n workflowId,\n workflowName,\n context,\n _workflowSignal: workflowSignal,\n });\n } finally {\n // Clean up abort listener\n if (workflowSignal) {\n workflowSignal.removeEventListener(\"abort\", abortHandler);\n }\n }\n\n const durationMs = performance.now() - startTime;\n\n // Check if the error is a wrapped WorkflowCancelledError\n // There are two paths:\n // 1. result.cause is WorkflowCancelledError (both default and custom catchUnexpected)\n // 2. AbortError thrown during abort - synthesize WorkflowCancelledError\n if (!result.ok) {\n let cancelledError: WorkflowCancelledError | undefined;\n\n // Path 1: result.cause is WorkflowCancelledError (both default and custom catchUnexpected)\n if (isWorkflowCancelled(result.cause)) {\n cancelledError = result.cause as WorkflowCancelledError;\n }\n\n // Path 2: AbortError thrown during abort (e.g. step.sleep) - treat as cancellation\n // The thrown AbortError is in result.cause\n if (\n !cancelledError &&\n abortedDuringExecution &&\n isUnexpectedError(result.error)\n ) {\n const thrown = result.cause;\n const isAbortError =\n thrown != null &&\n typeof thrown === \"object\" &&\n \"name\" in thrown &&\n (thrown as { name: string }).name === \"AbortError\";\n if (isAbortError) {\n const reason =\n abortReason ??\n (typeof workflowSignal?.reason === \"string\"\n ? workflowSignal.reason\n : workflowSignal?.reason instanceof Error\n ? workflowSignal.reason.message\n : undefined);\n cancelledError = {\n type: \"WORKFLOW_CANCELLED\",\n reason,\n lastStepKey,\n };\n }\n }\n\n if (cancelledError) {\n emitEvent({\n type: \"workflow_cancelled\",\n workflowId,\n ts: Date.now(),\n durationMs,\n reason: cancelledError.reason,\n lastStepKey: cancelledError.lastStepKey,\n });\n // Path 2: We synthesized cancelledError from AbortError - ensure result.cause is WorkflowCancelledError\n if (cancelledError && !isWorkflowCancelled(result.cause)) {\n return err(result.error, { cause: cancelledError }) as Result<T, E | ExtraE | U, unknown>;\n }\n return result as Result<T, E | ExtraE | U, unknown>;\n }\n }\n\n // Check for late cancellation: workflow completed successfully but signal was aborted\n // This handles the case where abort happens during the last step but the operation doesn't throw\n // Only check abortedDuringExecution, not workflowSignal?.aborted, to avoid race condition\n // where a pre-aborted signal (aborted before workflow started) incorrectly cancels a successful workflow\n if (result.ok && abortedDuringExecution) {\n const reason = abortReason ?? (\n typeof workflowSignal?.reason === \"string\"\n ? workflowSignal.reason\n : workflowSignal?.reason instanceof Error\n ? workflowSignal.reason.message\n : undefined\n );\n emitEvent({\n type: \"workflow_cancelled\",\n workflowId,\n ts: Date.now(),\n durationMs,\n reason,\n lastStepKey,\n });\n const cancelledError: WorkflowCancelledError = {\n type: \"WORKFLOW_CANCELLED\",\n reason,\n lastStepKey,\n };\n return err(catchUnexpected(cancelledError), { cause: cancelledError }) as Result<T, E | ExtraE | U, unknown>;\n }\n\n // Emit workflow_success or workflow_error\n if (result.ok) {\n emitEvent({\n type: \"workflow_success\",\n workflowId,\n ts: Date.now(),\n durationMs,\n });\n } else {\n // At this point, WorkflowCancelledError has already been handled and returned above,\n // so result.error is not WorkflowCancelledError\n emitEvent({\n type: \"workflow_error\",\n workflowId,\n ts: Date.now(),\n durationMs,\n error: result.error as E | ExtraE | U,\n });\n }\n\n // NOTE: We intentionally do NOT check for unknown steps after workflow completes.\n // This is because workflows can have conditional branches - a step from a skipped branch\n // would appear \"unused\" but is still a valid step. We can't distinguish between:\n // 1. Steps that are truly unknown (from a different workflow)\n // 2. Steps that are defined but not executed in this particular run\n // Use workflowId matching in snapshot metadata to detect wrong snapshots instead.\n\n return result as Result<T, E | ExtraE | U, unknown>;\n }\n\n // ==========================================================================\n // workflow.run() - public method\n // ==========================================================================\n function runMethod<T, ExtraE = never>(\n fnOrName: string | WorkflowFn<T, E | ExtraE, Deps, C>,\n maybeFnOrConfig?: WorkflowFn<T, E | ExtraE, Deps, C> | RunConfig<E, U, C, Deps>,\n maybeConfig?: RunConfig<E, U, C, Deps>\n ): Promise<Result<T, E | ExtraE | U, unknown>> {\n let runName: string | undefined;\n let fn: WorkflowFn<T, E | ExtraE, Deps, C>;\n let config: RunConfig<E, U, C, Deps> | undefined;\n\n if (typeof fnOrName === \"string\") {\n runName = fnOrName;\n fn = maybeFnOrConfig as WorkflowFn<T, E | ExtraE, Deps, C>;\n config = maybeConfig;\n } else {\n fn = fnOrName;\n config = maybeFnOrConfig as RunConfig<E, U, C, Deps> | undefined;\n }\n\n return internalExecute<T, ExtraE>(runName, fn, config);\n }\n\n // ==========================================================================\n // workflow.runWithState() - run and return result + resume state for persistence\n // ==========================================================================\n async function runWithStateMethod<T, ExtraE = never>(\n fnOrName: string | WorkflowFn<T, E | ExtraE, Deps, C>,\n maybeFnOrConfig?: WorkflowFn<T, E | ExtraE, Deps, C> | RunConfig<E, U, C, Deps>,\n maybeConfig?: RunConfig<E, U, C, Deps>\n ): Promise<{ result: Result<T, E | ExtraE | U, unknown>; resumeState: ResumeState }> {\n let runName: string | undefined;\n let fn: WorkflowFn<T, E | ExtraE, Deps, C>;\n let config: RunConfig<E, U, C, Deps> | undefined;\n\n if (typeof fnOrName === \"string\") {\n runName = fnOrName;\n fn = maybeFnOrConfig as WorkflowFn<T, E | ExtraE, Deps, C>;\n config = maybeConfig;\n } else {\n fn = fnOrName;\n config = maybeFnOrConfig as RunConfig<E, U, C, Deps> | undefined;\n }\n\n const collector = createResumeStateCollector();\n const userOnEvent = config?.onEvent;\n const mergedOnEvent = (event: WorkflowEvent<E | ExtraE | U, C>, ctx: C) => {\n collector.handleEvent(event);\n try {\n userOnEvent?.(event as WorkflowEvent<E | U, C>, ctx);\n } catch {\n // Observability shouldn't crash runs\n }\n };\n const mergedConfig: RunConfig<E, U, C, Deps> = {\n ...config,\n onEvent: mergedOnEvent as RunConfig<E, U, C, Deps>[\"onEvent\"],\n };\n\n let result: Result<T, E | ExtraE | U, unknown>;\n let resumeState: ResumeState;\n try {\n result = await internalExecute<T, ExtraE>(runName, fn, mergedConfig);\n } catch (thrown) {\n // runWithState follows \"never throw, always Result\"; map thrown to Result\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const catchUnexpected = (optionsActual as any)?.catchUnexpected ?? defaultCatchUnexpected;\n result = err(catchUnexpected(thrown), { cause: thrown }) as Result<T, E | ExtraE | U, unknown>;\n } finally {\n resumeState = collector.getResumeState();\n }\n return { result, resumeState };\n }\n\n const workflow: Workflow<E, U, Deps, C> = {\n run: runMethod as Workflow<E, U, Deps, C>[\"run\"],\n runWithState: runWithStateMethod as Workflow<E, U, Deps, C>[\"runWithState\"],\n };\n\n return workflow;\n}\n","/**\n * awaitly/durable\n *\n * Durable execution with automatic state persistence.\n * Workflows automatically checkpoint after each keyed step and can resume from any point.\n */\n\nimport {\n err,\n type Result,\n type WorkflowEvent,\n type RunStep,\n type UnexpectedError,\n} from \"../core\";\nimport {\n createWorkflow,\n createResumeStateCollector,\n} from \"../workflow\";\nimport type {\n AnyResultFn,\n ErrorsOfDeps,\n WorkflowOptions,\n WorkflowContext,\n WorkflowCancelledError,\n Workflow,\n} from \"../workflow/types\";\nimport {\n type SnapshotStore,\n type WorkflowSnapshot,\n type StepResult,\n type JSONValue,\n mergeSnapshots,\n assertValidSnapshot,\n SnapshotFormatError,\n SnapshotDecodeError,\n serializeError,\n serializeThrown,\n} from \"../persistence\";\n\n// Re-export for convenience\nexport { type SnapshotStore } from \"../persistence\";\nexport { isWorkflowCancelled } from \"../workflow\";\nexport type { WorkflowCancelledError } from \"../workflow/types\";\n\n// In-memory store for zero-config usage\nlet defaultStore: SnapshotStore | undefined;\n\nfunction createMemorySnapshotStore(): SnapshotStore {\n const store = new Map<string, { snapshot: WorkflowSnapshot; updatedAt: Date }>();\n\n return {\n async save(id: string, snapshot: WorkflowSnapshot): Promise<void> {\n store.set(id, { snapshot, updatedAt: new Date() });\n },\n\n async load(id: string): Promise<WorkflowSnapshot | null> {\n const entry = store.get(id);\n return entry?.snapshot ?? null;\n },\n\n async delete(id: string): Promise<void> {\n store.delete(id);\n },\n\n async list(options?: { prefix?: string; limit?: number }): Promise<Array<{ id: string; updatedAt: string }>> {\n const prefix = options?.prefix ?? \"\";\n const limit = options?.limit ?? 100;\n const results: Array<{ id: string; updatedAt: string }> = [];\n\n for (const [id, entry] of store.entries()) {\n if (prefix && !id.startsWith(prefix)) continue;\n results.push({ id, updatedAt: entry.updatedAt.toISOString() });\n if (results.length >= limit) break;\n }\n\n // Sort by updatedAt descending\n results.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));\n return results;\n },\n\n async close(): Promise<void> {\n // No-op for memory store\n },\n };\n}\n\nfunction getDefaultStore(): SnapshotStore {\n if (defaultStore === undefined) {\n defaultStore = createMemorySnapshotStore();\n }\n return defaultStore;\n}\n\n// =============================================================================\n// Durable Execution Types\n// =============================================================================\n\n/**\n * Error returned when workflow cannot resume due to version mismatch.\n * Indicates the stored state was created with a different workflow version.\n * Fail-fast contract: bump version when you change step keys, order, or outputs.\n */\nexport type VersionMismatchError = {\n type: \"VERSION_MISMATCH\";\n /** Workflow execution ID */\n workflowId: string;\n /** Version stored in persisted state */\n storedVersion: number;\n /** Version requested by this run */\n requestedVersion: number;\n /** Guidance message with suggested actions */\n message: string;\n /** Use requestedVersion. */\n currentVersion?: number;\n};\n\n/**\n * Error returned when workflow execution is rejected due to concurrent run.\n */\nexport type ConcurrentExecutionError = {\n type: \"CONCURRENT_EXECUTION\";\n /** The workflow ID that is already running */\n workflowId: string;\n /** Guidance message */\n message: string;\n /**\n * Distinguishes in-process (activeWorkflows) from cross-process (lock held).\n * Enables debuggability and branching without parsing the message.\n */\n reason?: \"in-process\" | \"cross-process\";\n};\n\n/**\n * Error returned when a persistence store operation fails.\n */\nexport type PersistenceError = {\n type: \"PERSISTENCE_ERROR\";\n /** The operation that failed */\n operation: \"load\" | \"save\" | \"delete\";\n /** The workflow ID */\n workflowId: string;\n /** The underlying error */\n cause: unknown;\n /** Guidance message */\n message: string;\n};\n\n/**\n * Type guard to check if an error is a VersionMismatchError.\n */\nexport function isVersionMismatch(error: unknown): error is VersionMismatchError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as VersionMismatchError).type === \"VERSION_MISMATCH\"\n );\n}\n\n/**\n * Type guard to check if an error is a ConcurrentExecutionError.\n */\nexport function isConcurrentExecution(error: unknown): error is ConcurrentExecutionError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as ConcurrentExecutionError).type === \"CONCURRENT_EXECUTION\"\n );\n}\n\n/**\n * Type guard to check if an error is a PersistenceError.\n */\nexport function isPersistenceError(error: unknown): error is PersistenceError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as PersistenceError).type === \"PERSISTENCE_ERROR\"\n );\n}\n\n/**\n * Error returned when a workflow's lease expires mid-execution.\n * Indicates the lock was lost and another process may have reclaimed the workflow.\n */\nexport type LeaseExpiredError = {\n type: \"LEASE_EXPIRED\";\n /** The workflow ID whose lease expired */\n workflowId: string;\n /** Guidance message */\n message: string;\n};\n\n/**\n * Type guard to check if an error is a LeaseExpiredError.\n */\nexport function isLeaseExpired(error: unknown): error is LeaseExpiredError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as LeaseExpiredError).type === \"LEASE_EXPIRED\"\n );\n}\n\n/**\n * Error returned when an idempotency key is reused with different input.\n */\nexport type IdempotencyConflictError = {\n type: \"IDEMPOTENCY_CONFLICT\";\n idempotencyKey: string;\n workflowId: string;\n message: string;\n};\n\nexport function isIdempotencyConflict(error: unknown): error is IdempotencyConflictError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as IdempotencyConflictError).type === \"IDEMPOTENCY_CONFLICT\"\n );\n}\n\n/**\n * Optional cross-process lock interface.\n * When a store implements this, durable.run uses it to ensure only one process\n * runs a given workflow ID at a time (when allowConcurrent is false).\n *\n * Uses a lease (TTL) + owner token so a crashed worker does not wedge a workflow\n * indefinitely. Release must verify the owner token so one process never\n * unlocks another's lease.\n *\n * Mid-run lock loss (e.g. lease expires during a long workflow) is handled\n * adapter-side; core assumes the lock is held until release in finally.\n * Adapters may implement heartbeats/renewal.\n */\nexport interface WorkflowLock {\n /**\n * Try to acquire a lease for the workflow ID.\n * @param id - Workflow execution ID\n * @param options - Optional TTL for the lease (adapter default if omitted)\n * @returns Owner token if acquired, null if already held by another\n */\n tryAcquire(\n id: string,\n options?: { ttlMs?: number }\n ): Promise<{ ownerToken: string } | null>;\n\n /**\n * Release the lease. Must verify owner token; no-op or ignore if token\n * does not match (e.g. lease already expired or taken by another).\n */\n release(id: string, ownerToken: string): Promise<void>;\n\n /**\n * Extend the lease for an already-held lock.\n * Returns true if renewed, false if lost.\n * Optional — when not implemented, no heartbeat runs.\n */\n renew?(id: string, ownerToken: string, options?: { ttlMs?: number }): Promise<boolean>;\n}\n\n/**\n * Check if a store implements the optional WorkflowLock interface.\n */\nfunction hasWorkflowLock(\n store: SnapshotStore\n): store is SnapshotStore & WorkflowLock {\n return (\n typeof (store as SnapshotStore & WorkflowLock).tryAcquire === \"function\" &&\n typeof (store as SnapshotStore & WorkflowLock).release === \"function\"\n );\n}\n\n/**\n * Options for durable workflow execution.\n */\nexport interface DurableOptions<C = void> {\n /**\n * Unique workflow execution ID.\n * Used as the key for state persistence.\n *\n * @example 'order-checkout-123', 'user-onboarding-abc'\n */\n id: string;\n\n /**\n * Snapshot store for persistence. Optional. When omitted, an in-memory store is used (per process).\n * Same-process resume/retry works; state is lost on restart. Override with postgres/mongo/libsql for persistence.\n *\n * @example\n * ```typescript\n * // Zero-config: uses in-memory store (per process)\n * await durable.run(deps, fn, { id: 'my-id' });\n *\n * // Override: pass a store for persistence across restarts\n * import { postgres } from 'awaitly-postgres';\n * const store = postgres('postgresql://localhost/mydb');\n * await durable.run(deps, fn, { id: 'my-id', store });\n * ```\n */\n store?: SnapshotStore;\n\n /**\n * Workflow logic version.\n * If stored state has a different version, workflow will reject resume with VersionMismatchError\n * unless onVersionMismatch is used to clear or migrate.\n *\n * Bump when you change step keys, reorder steps, or change step outputs in a way old checkpoints can't satisfy.\n *\n * @default 1\n */\n version?: number;\n\n /**\n * When stored state version differs from requested version, either throw (default), clear state and run from scratch, or supply migrated snapshot.\n * Use for migration or one-off clear without wrapping durable.run.\n *\n * @default 'throw'\n */\n onVersionMismatch?: (ctx: {\n id: string;\n storedVersion: number;\n requestedVersion: number;\n }) => \"throw\" | \"clear\" | { migratedSnapshot: WorkflowSnapshot } | Promise<\"throw\" | \"clear\" | { migratedSnapshot: WorkflowSnapshot }>;\n\n /**\n * Allow concurrent executions with the same workflow ID.\n * When `false` (default), a second run with the same ID will be rejected while one is active.\n *\n * @default false\n */\n allowConcurrent?: boolean;\n\n /**\n * Lease TTL in milliseconds for cross-process locking.\n * Only used when the store implements WorkflowLock and allowConcurrent is false.\n * A crashed worker's lease expires after this duration so the workflow can be picked up again.\n *\n * @default 60000 (1 minute)\n */\n lockTtlMs?: number;\n\n /**\n * Heartbeat interval for lease renewal (ms).\n * Only active when store implements WorkflowLock with renew().\n * @default lockTtlMs / 3\n */\n heartbeatIntervalMs?: number;\n\n /**\n * Whether to abort the workflow when lease is lost mid-execution.\n * @default true\n */\n abortOnLeaseLoss?: boolean;\n\n /**\n * Metadata to store alongside workflow state.\n * Useful for debugging, auditing, or filtering workflows.\n *\n * @example { userId: 'user-123', source: 'api' }\n */\n metadata?: Record<string, unknown>;\n\n /**\n * External AbortSignal for workflow-level cancellation.\n * Cancellation persists state up to the last completed step.\n */\n signal?: AbortSignal;\n\n /**\n * Create per-run context for event correlation.\n */\n createContext?: () => C;\n\n /**\n * Unified event stream for workflow and step lifecycle.\n * Includes durable-specific events: `persist_success` and `persist_error`.\n */\n onEvent?: (event: DurableWorkflowEvent<unknown, C>, ctx: C) => void;\n\n /**\n * Handler for expected and unexpected errors.\n */\n onError?: (error: unknown, stepName?: string, ctx?: C) => void;\n\n /**\n * Idempotency key for deduplication.\n * If provided and a completed workflow with this key exists in the store,\n * the stored result is returned without re-execution.\n * If the stored input differs, an IdempotencyConflictError is returned.\n */\n idempotencyKey?: string;\n\n /**\n * Workflow input for idempotency conflict detection.\n * When idempotencyKey is set, this is compared against stored input.\n * Must be JSON-serializable.\n */\n input?: unknown;\n}\n\n/**\n * Extended workflow event type that includes durable-specific events.\n * E is the deps error type - the full error type includes E | UnexpectedError.\n */\nexport type DurableWorkflowEvent<E, C = void> =\n | WorkflowEvent<E | UnexpectedError, C>\n | {\n type: \"persist_success\";\n workflowId: string;\n stepKey: string;\n ts: number;\n context?: C;\n }\n | {\n type: \"persist_error\";\n workflowId: string;\n stepKey: string;\n error: unknown;\n ts: number;\n context?: C;\n };\n\n/**\n * Options for bulk delete of workflow state.\n */\nexport interface DeleteStatesOptions {\n /**\n * Max number of concurrent delete calls when store has no deleteMany.\n * @default 10\n */\n concurrency?: number;\n /**\n * When true, collect errors and return them; when false, throw on first error.\n * @default true\n */\n continueOnError?: boolean;\n}\n\n/**\n * Result of bulk delete of workflow state.\n */\nexport interface DeleteStatesResult {\n /** Number of entries successfully deleted. */\n deleted: number;\n /** Per-id errors when continueOnError was true and some deletes failed. */\n errors?: Array<{ id: string; error: unknown }>;\n}\n\n// Track active workflow executions for concurrency control\nconst activeWorkflows = new Set<string>();\n\n/**\n * Durable workflow execution namespace.\n */\nexport const durable = {\n /**\n * Execute a workflow with automatic state persistence.\n *\n * Features:\n * - **Automatic checkpointing**: State is saved after each keyed step\n * - **Crash recovery**: Resume from the last completed step on restart\n * - **Version checking**: Reject resume if workflow logic version changed\n * - **Concurrency control**: Prevent duplicate executions of the same workflow ID\n * - **Cancellation support**: Integrates with AbortSignal for graceful shutdown\n *\n * ## How It Works\n *\n * 1. On start: Load existing state from store (if any)\n * 2. Check version compatibility (reject if mismatch)\n * 3. Pre-populate cache from loaded state (skip completed steps)\n * 4. Execute workflow, persisting state after each keyed step\n * 5. On completion: Delete stored state (clean up)\n * 6. On error/cancellation: State remains for future resume\n *\n * ## Important Notes\n *\n * - **Only keyed steps are durable**: Use `{ key: 'step-name' }` option\n * - **Steps should be idempotent**: They may be retried on resume\n * - **Serialization**: State is JSON-serialized; complex objects may lose fidelity\n *\n * @param deps - Workflow dependencies (Result-returning functions)\n * @param fn - Workflow function receiving ({ step, deps, ctx })\n * @param options - Durable execution options\n * @returns AsyncResult with workflow result or error\n *\n * @example\n * ```typescript\n * import { durable } from 'awaitly/durable';\n *\n * // Zero-config: uses in-memory store (per process)\n * const result = await durable.run(\n * { fetchUser, createOrder, sendEmail },\n * async ({ step, deps: { fetchUser, createOrder, sendEmail } }) => {\n * const user = await step(() => fetchUser('123'), { key: 'fetch-user' });\n * const order = await step(() => createOrder(user), { key: 'create-order' });\n * await step(() => sendEmail(order), { key: 'send-email' });\n * return order;\n * },\n * { id: 'checkout-123' }\n * );\n *\n * // Override: pass a store for persistence across restarts\n * import { createMemoryStatePersistence } from 'awaitly/persistence';\n * const store = createMemoryStatePersistence();\n * await durable.run(deps, fn, { id: 'checkout-123', store });\n *\n * if (result.ok) {\n * console.log('Order completed:', result.value);\n * } else if (isWorkflowCancelled(result.error)) {\n * console.log('Workflow cancelled at:', result.error.lastStepKey);\n * }\n * ```\n */\n async run<\n const Deps extends Readonly<Record<string, AnyResultFn>>,\n T,\n C = void\n >(\n deps: Deps,\n fn: (\n context: { step: RunStep<ErrorsOfDeps<Deps>>; deps: Deps; ctx: WorkflowContext<C> }\n ) => T | Promise<T>,\n options: DurableOptions<C>\n ): Promise<\n Result<\n T,\n | ErrorsOfDeps<Deps>\n | UnexpectedError\n | WorkflowCancelledError\n | VersionMismatchError\n | ConcurrentExecutionError\n | PersistenceError\n | LeaseExpiredError\n | IdempotencyConflictError,\n unknown\n >\n > {\n const {\n id,\n store: storeOption,\n version = 1,\n allowConcurrent = false,\n lockTtlMs = 60_000,\n heartbeatIntervalMs,\n abortOnLeaseLoss,\n metadata,\n signal,\n createContext,\n onEvent,\n onError,\n onVersionMismatch,\n idempotencyKey,\n input,\n } = options;\n\n const effectiveStore = storeOption ?? getDefaultStore();\n\n // Idempotency check — before concurrency and lock\n if (idempotencyKey) {\n const idemId = `idem:${idempotencyKey}`;\n try {\n const idemSnapshot = await effectiveStore.load(idemId);\n if (idemSnapshot) {\n // Check for input conflict\n if (input !== undefined && idemSnapshot.metadata?.input !== undefined) {\n const storedInput = JSON.stringify(idemSnapshot.metadata.input);\n const currentInput = JSON.stringify(input);\n if (storedInput !== currentInput) {\n return err({\n type: \"IDEMPOTENCY_CONFLICT\" as const,\n idempotencyKey,\n workflowId: id,\n message: `Idempotency key '${idempotencyKey}' already used with different input for workflow '${id}'.`,\n });\n }\n }\n\n // If completed with a stored result, return it\n if (idemSnapshot.execution.status === \"completed\" && idemSnapshot.metadata?.finalResult !== undefined) {\n // Return the stored result directly\n return idemSnapshot.metadata.finalResult as Result<T, ErrorsOfDeps<Deps> | UnexpectedError | WorkflowCancelledError | VersionMismatchError | ConcurrentExecutionError | PersistenceError | LeaseExpiredError | IdempotencyConflictError, unknown>;\n }\n\n // If still running, treat as concurrent\n if (idemSnapshot.execution.status === \"running\") {\n return err({\n type: \"CONCURRENT_EXECUTION\" as const,\n workflowId: id,\n message: `Workflow '${id}' with idempotency key '${idempotencyKey}' is already running.`,\n reason: \"cross-process\" as const,\n });\n }\n }\n } catch {\n // If we can't check idempotency, continue with normal execution\n // (don't block on idempotency check failure)\n }\n }\n\n // In-process concurrency check\n if (!allowConcurrent && activeWorkflows.has(id)) {\n const error: ConcurrentExecutionError = {\n type: \"CONCURRENT_EXECUTION\",\n workflowId: id,\n message: `Workflow '${id}' is already running. Set allowConcurrent: true to allow parallel executions.`,\n reason: \"in-process\",\n };\n return err(error);\n }\n\n // Cross-process lock (optional): try acquire lease when store implements WorkflowLock\n let leaseOwnerToken: string | null = null;\n if (!allowConcurrent && hasWorkflowLock(effectiveStore)) {\n let lease: { ownerToken: string } | null;\n try {\n lease = await effectiveStore.tryAcquire(id, { ttlMs: lockTtlMs });\n } catch (lockError) {\n const error: PersistenceError = {\n type: \"PERSISTENCE_ERROR\",\n operation: \"load\",\n workflowId: id,\n cause: lockError,\n message: `Failed to acquire lock for workflow '${id}': ${lockError instanceof Error ? lockError.message : String(lockError)}`,\n };\n return err(error);\n }\n if (lease === null) {\n const error: ConcurrentExecutionError = {\n type: \"CONCURRENT_EXECUTION\",\n workflowId: id,\n message: `Workflow '${id}' is already running (lease held by another process). Set allowConcurrent: true to allow parallel executions.`,\n reason: \"cross-process\",\n };\n return err(error);\n }\n leaseOwnerToken = lease.ownerToken;\n }\n\n // Start heartbeat if store supports renew\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n let leaseAbortController: AbortController | undefined;\n\n const lockStore = effectiveStore as SnapshotStore & WorkflowLock;\n if (leaseOwnerToken && typeof lockStore.renew === \"function\") {\n const heartbeatMs = heartbeatIntervalMs ?? Math.floor(lockTtlMs / 3);\n leaseAbortController = new AbortController();\n\n heartbeatTimer = setInterval(async () => {\n try {\n const renewed = await lockStore.renew!(id, leaseOwnerToken!, { ttlMs: lockTtlMs });\n if (!renewed) {\n leaseAbortController!.abort(new Error(\"Lease expired\"));\n }\n } catch {\n leaseAbortController!.abort(new Error(\"Lease renewal failed\"));\n }\n }, heartbeatMs);\n }\n\n // Mark as active (in-process)\n activeWorkflows.add(id);\n\n try {\n // Load existing snapshot (wrap in try-catch to return Result on store errors)\n let existingSnapshot: WorkflowSnapshot | null = null;\n try {\n existingSnapshot = await effectiveStore.load(id);\n } catch (loadError) {\n const error: PersistenceError = {\n type: \"PERSISTENCE_ERROR\",\n operation: \"load\",\n workflowId: id,\n cause: loadError,\n message: `Failed to load state for workflow '${id}': ${loadError instanceof Error ? loadError.message : String(loadError)}`,\n };\n return err(error);\n }\n\n // Validate snapshot format if it exists\n if (existingSnapshot) {\n try {\n assertValidSnapshot(existingSnapshot);\n } catch (validationError) {\n if (validationError instanceof SnapshotFormatError) {\n const error: PersistenceError = {\n type: \"PERSISTENCE_ERROR\",\n operation: \"load\",\n workflowId: id,\n cause: validationError,\n message: `Invalid snapshot format for workflow '${id}': ${validationError.message}`,\n };\n return err(error);\n }\n throw validationError;\n }\n }\n\n // Version check if snapshot exists\n if (existingSnapshot) {\n // Check metadata.version (workflow logic version)\n // Snapshots without version metadata default to version 1\n const storedVersion =\n typeof existingSnapshot.metadata?.version === \"number\"\n ? existingSnapshot.metadata.version\n : 1;\n if (storedVersion !== version) {\n const error: VersionMismatchError = {\n type: \"VERSION_MISMATCH\",\n workflowId: id,\n storedVersion,\n requestedVersion: version,\n currentVersion: version,\n message: `Workflow '${id}' has stored state at version ${storedVersion} but this run requested version ${version}. Migrate the stored state to the new version, or clear state for this id (e.g. durable.deleteState(store, '${id}')) and re-run.`,\n };\n if (!onVersionMismatch) {\n return err(error);\n }\n const resolution = await Promise.resolve(\n onVersionMismatch({ id, storedVersion, requestedVersion: version })\n );\n if (resolution === \"throw\") {\n return err(error);\n }\n if (resolution === \"clear\") {\n try {\n await effectiveStore.delete(id);\n } catch {\n // ignore delete errors\n }\n existingSnapshot = null;\n } else {\n existingSnapshot = resolution.migratedSnapshot;\n }\n }\n }\n\n // Define error type for this workflow\n type E = ErrorsOfDeps<Deps>;\n\n // Wrapper to emit durable-specific events\n const emitDurableEvent = (event: DurableWorkflowEvent<E, C>, ctx: C): void => {\n if (onEvent) {\n onEvent(event, ctx);\n }\n };\n\n // Collect step results via onEvent for snapshot building\n const resumeCollector = createResumeStateCollector();\n\n // Build workflow options with proper types (U = UnexpectedError by default)\n const workflowOptions: WorkflowOptions<E, UnexpectedError, C> = {\n // Restore from existing snapshot\n snapshot: existingSnapshot,\n\n // Persist after each keyed step\n onAfterStep: async (stepKey, result, wfId, ctx) => {\n try {\n // Build a snapshot from collected step results\n const collectedState = resumeCollector.getResumeState();\n const steps: Record<string, StepResult> = {};\n for (const [key, entry] of collectedState.steps) {\n if (entry.result.ok) {\n steps[key] = { ok: true, value: entry.result.value as JSONValue };\n } else {\n // Serialize cause for proper snapshot format\n const cause = entry.result.cause;\n const serializedCause = cause instanceof Error\n ? serializeError(cause)\n : serializeThrown(cause);\n const origin: \"result\" | \"throw\" = entry.meta?.origin === \"throw\" ? \"throw\" : \"result\";\n steps[key] = {\n ok: false,\n error: entry.result.error as JSONValue,\n cause: serializedCause,\n meta: { origin },\n };\n }\n }\n\n const currentSnapshot: WorkflowSnapshot = {\n formatVersion: 1,\n workflowName: id,\n steps,\n execution: {\n status: \"running\",\n lastUpdated: new Date().toISOString(),\n currentStepId: stepKey,\n },\n metadata: {\n ...(existingSnapshot?.metadata ?? {}),\n ...metadata,\n version,\n lastStepKey: stepKey,\n } as Record<string, JSONValue>,\n };\n\n // If we have an existing snapshot, merge it with the current one\n // This preserves steps from previous runs\n let snapshotToSave = existingSnapshot\n ? mergeSnapshots(existingSnapshot, currentSnapshot)\n : currentSnapshot;\n\n // Clear stale warnings for steps that were re-executed in this run\n if (snapshotToSave.warnings && snapshotToSave.warnings.length > 0) {\n const currentStepKeys = new Set(Object.keys(currentSnapshot.steps));\n const filtered = snapshotToSave.warnings.filter(\n w => !currentStepKeys.has(w.stepId)\n );\n snapshotToSave = {\n ...snapshotToSave,\n warnings: filtered.length > 0 ? filtered : undefined,\n };\n }\n\n // Persist to store\n await effectiveStore.save(id, snapshotToSave);\n\n // Emit success event\n emitDurableEvent(\n {\n type: \"persist_success\",\n workflowId: wfId,\n stepKey,\n ts: Date.now(),\n context: ctx as C,\n },\n ctx as C\n );\n } catch (persistError) {\n // Emit error event but continue workflow (per Temporal/Cloudflare pattern)\n emitDurableEvent(\n {\n type: \"persist_error\",\n workflowId: wfId,\n stepKey,\n error: persistError,\n ts: Date.now(),\n context: ctx as C,\n },\n ctx as C\n );\n }\n },\n\n // Forward events and collect step results for snapshot building\n onEvent: (event, ctx) => {\n resumeCollector.handleEvent(event);\n emitDurableEvent(event as DurableWorkflowEvent<E, C>, ctx as C);\n },\n\n onError: onError as (error: E | UnexpectedError, stepName?: string, ctx?: C) => void,\n signal: leaseAbortController && signal\n ? AbortSignal.any([signal, leaseAbortController.signal])\n : leaseAbortController?.signal ?? signal,\n createContext,\n };\n\n // Create workflow instance (U = UnexpectedError by default)\n let workflowInstance: Workflow<E, UnexpectedError, Deps, C>;\n try {\n workflowInstance = createWorkflow<Deps, UnexpectedError, C>(id, deps, workflowOptions);\n } catch (createError) {\n if (createError instanceof SnapshotFormatError) {\n const error: PersistenceError = {\n type: \"PERSISTENCE_ERROR\",\n operation: \"load\",\n workflowId: id,\n cause: createError,\n message: `Invalid snapshot format for workflow '${id}': ${createError.message}`,\n };\n return err(error);\n }\n throw createError;\n }\n\n // Execute workflow (snapshot validation may throw SnapshotFormatError at run time)\n let result: Result<T, E | UnexpectedError | PersistenceError, unknown>;\n try {\n result = await workflowInstance!.run(fn);\n } catch (runError) {\n if (runError instanceof SnapshotFormatError || runError instanceof SnapshotDecodeError) {\n const error: PersistenceError = {\n type: \"PERSISTENCE_ERROR\",\n operation: \"load\",\n workflowId: id,\n cause: runError,\n message: `Invalid snapshot format for workflow '${id}': ${runError.message}`,\n };\n return err(error);\n }\n throw runError;\n }\n\n // Check if lease was lost during execution\n if (abortOnLeaseLoss !== false && leaseAbortController?.signal.aborted) {\n return err({\n type: \"LEASE_EXPIRED\" as const,\n workflowId: id,\n message: `Lease expired for workflow '${id}' during execution. The workflow may have been reclaimed by another process.`,\n });\n }\n\n // On success: clean up stored state\n if (result.ok) {\n try {\n await effectiveStore.delete(id);\n } catch (deleteError) {\n const error: PersistenceError = {\n type: \"PERSISTENCE_ERROR\",\n operation: \"delete\",\n workflowId: id,\n cause: deleteError,\n message: `Failed to delete state for workflow '${id}': ${deleteError instanceof Error ? deleteError.message : String(deleteError)}`,\n };\n return err(error);\n }\n\n // Save idempotency record on success\n if (idempotencyKey) {\n const idemId = `idem:${idempotencyKey}`;\n try {\n await effectiveStore.save(idemId, {\n formatVersion: 1,\n steps: {},\n execution: {\n status: \"completed\",\n lastUpdated: new Date().toISOString(),\n completedAt: new Date().toISOString(),\n },\n metadata: {\n workflowId: id,\n idempotencyKey,\n input: input as JSONValue,\n finalResult: result as JSONValue,\n },\n } satisfies WorkflowSnapshot);\n } catch {\n // Non-fatal: workflow succeeded but idempotency record failed to save\n }\n }\n }\n // On error/cancellation: state remains for resume\n\n // Workflow result is structurally compatible with our return type\n // (workflow returns E | UnexpectedError, we return that plus our durable-specific errors)\n return result;\n } finally {\n // Always remove from active set\n activeWorkflows.delete(id);\n // Clear heartbeat timer before releasing lock\n if (heartbeatTimer) {\n clearInterval(heartbeatTimer);\n }\n // Release cross-process lease if we acquired one (verify owner in adapter)\n // Guard the await so a failing release doesn't turn a successful run into a rejection\n if (leaseOwnerToken !== null && hasWorkflowLock(effectiveStore)) {\n try {\n await effectiveStore.release(id, leaseOwnerToken);\n } catch {\n // Swallow release errors - the workflow result is already determined\n // and we don't want to mask it with a lock release failure\n }\n }\n }\n },\n\n /**\n * Clear all persisted workflow state from the store.\n * Use for admin/testing. If the store implements `clear()`, that is used;\n * otherwise clears by listing and deleting in pages.\n *\n * @param store - Snapshot store\n */\n async clearState(store: SnapshotStore): Promise<void> {\n const storeWithClear = store as SnapshotStore & { clear?(): Promise<void> };\n if (typeof storeWithClear.clear === \"function\") {\n await storeWithClear.clear();\n return;\n }\n const limit = 100;\n for (;;) {\n const entries = await store.list({ limit });\n if (entries.length === 0) break;\n const ids = entries.map(e => e.id);\n await this.deleteStates(store, ids, { continueOnError: true });\n if (entries.length < limit) break;\n }\n },\n\n /**\n * Check if a workflow ID has persisted state (can be resumed).\n *\n * @param store - Snapshot store\n * @param id - Workflow execution ID\n * @returns `true` if state exists, `false` otherwise (including on store errors)\n */\n async hasState(store: SnapshotStore, id: string): Promise<boolean> {\n try {\n const snapshot = await store.load(id);\n return snapshot !== null;\n } catch {\n return false;\n }\n },\n\n /**\n * Delete persisted state for a workflow (cancel resume capability).\n * Deleting is effectively an ack/reset: the workflow can no longer resume from that state.\n * If you delete while a run is in flight, the run continues; on success it may delete again (no-op) or save (recreating state).\n * For multi-worker safety, prefer deleting only when the workflow is not running or when you hold the lock.\n *\n * @param store - Snapshot store\n * @param id - Workflow execution ID\n * @returns `true` on success, `false` on store errors\n */\n async deleteState(store: SnapshotStore, id: string): Promise<boolean> {\n try {\n await store.delete(id);\n return true;\n } catch {\n return false;\n }\n },\n\n /**\n * Bulk delete persisted state for multiple workflow IDs (best-effort).\n * Use for admin/cleanup. Deletes in a loop with optional concurrency.\n *\n * @param store - Snapshot store\n * @param ids - Workflow execution IDs to delete\n * @param options - Optional concurrency and error handling\n * @returns Count of deleted entries and any errors when continueOnError is true\n */\n async deleteStates(\n store: SnapshotStore,\n ids: string[],\n options: DeleteStatesOptions = {}\n ): Promise<DeleteStatesResult> {\n const { concurrency = 10, continueOnError = true } = options;\n if (ids.length === 0) {\n return { deleted: 0 };\n }\n const errors: Array<{ id: string; error: unknown }> = [];\n let deleted = 0;\n const run = async (id: string): Promise<void> => {\n try {\n await store.delete(id);\n deleted++;\n } catch (error) {\n if (continueOnError) errors.push({ id, error });\n else throw error;\n }\n };\n const limit = Math.max(1, concurrency);\n for (let i = 0; i < ids.length; i += limit) {\n const batch = ids.slice(i, i + limit);\n await Promise.all(batch.map((id) => run(id)));\n }\n return errors.length > 0 ? { deleted, errors } : { deleted };\n },\n\n /**\n * List workflow IDs with persisted state.\n *\n * @param store - Snapshot store\n * @param options - Optional prefix and limit\n * @returns Array of { id, updatedAt } entries\n */\n async listPending(\n store: SnapshotStore,\n options?: { prefix?: string; limit?: number }\n ): Promise<Array<{ id: string; updatedAt: string }>> {\n try {\n return await store.list(options);\n } catch {\n return [];\n }\n },\n};\n"],"mappings":"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","names":["durable_entry_exports","__export","durable","isConcurrentExecution","isIdempotencyConflict","isLeaseExpired","isPersistenceError","isVersionMismatch","isWorkflowCancelled","__toCommonJS","InternalTaggedErrorBase","TaggedError","tag","options","props","errorOptions","message","_","_n","_m","_s","safeProps","hasUserCause","userCause","hasOptionsCause","instance","isError","value","isTaggedError","match","error","handlers","handler","matchPartial","otherwise","TimeoutError","TaggedError","p","RetryExhaustedError","RateLimitError","CircuitBreakerOpenError","ValidationError","NotFoundError","UnauthorizedError","NetworkError","CompensationError","UnexpectedError","parseDurationString","input","match","value","unit","defaultCatchUnexpected","cause","UnexpectedError","ok","value","err","error","options","isUnexpectedError","UnexpectedError","extractErrorTag","error","tagged","trimmed","lookupErrorClassification","tag","errorMeta","extractStepMetadata","options","intent","domain","owner","tags","stateChanges","emits","calls","metadata","buildStepErrorPayload","origin","attempt","cumulativeDurationMs","classification","diagnostics","STEP_TIMEOUT_MARKER","isStepTimeoutError","getStepTimeoutMeta","err","EARLY_EXIT_SYMBOL","createEarlyExit","meta","isEarlyExit","MAPPER_EXCEPTION_SYMBOL","createMapperException","thrown","isMapperException","calculateRetryDelay","backoff","initialDelay","maxDelay","jitter","delay","jitterAmount","sleep","ms","resolve","TIMEOUT_SYMBOL","TIMEOUT_OPTION_SYMBOL","isTimeoutOptionMarker","value","executeWithTimeout","operation","options","stepInfo","externalSignal","controller","behavior","createTimeoutError","timeoutId","externalAbortHandler","timeoutPromise","_","reject","operationPromise","error","errorToThrow","meta","STEP_TIMEOUT_MARKER","DEFAULT_RETRY_CONFIG","run","fn","onError","onEvent","catchUnexpected","providedWorkflowId","workflowName","context","_workflowSignal","workflowId","effectiveCatchUnexpected","defaultCatchUnexpected","activeScopeStack","stepIdCounter","generateStepId","stepKey","emitEvent","event","eventWithContext","eventWithName","stepId","i","scope","earlyExit","createEarlyExit","isEarlyExitE","e","isEarlyExit","wrapForStep","_meta","isResultLike","normalizeParallelOperations","rawOperations","out","key","executeParallelArray","name","scopeId","startTime","scopeEnded","emitScopeEnd","idx","s","result","executeParallelNamed","operations","keys","results","resolve","settled","pendingCount","resultArray","index","reason","err","output","stepFn","id","operationOrResult","stepOptions","parsedOptions","stepMetadata","extractStepMetadata","stepName","explicitKey","stepDescription","retryConfig","timeoutConfig","hasEventListeners","overallStartTime","effectiveRetry","lastResult","attempt","attemptStartTime","durationMs","delay","calculateRetryDelay","buildStepErrorPayload","sleep","thrown","timeoutMs","ok","isStepTimeoutError","timeoutMeta","getStepTimeoutMeta","totalDurationMs","mappedError","mapperError","createMapperException","errorResult","wrappedError","opts","mapToError","mapped","onNull","duration","d","parseDurationString","ms","userSignal","state","onAbort","args","second","normalizedOperations","scopeEntry","_id","_conditionLabel","condition","thenFn","elseFn","errors","items","maxIterations","isRunForm","asyncItems","item","handler","_name","getter","handlers","resolved","mapper","concurrency","allAsync","batch","batchResult","batchIndex","primaryResult","fallbackResultFromThrow","fallbackThrown","fallbackMappedError","primaryError","fallbackResult","acquireResult","resource","useResult","useThrown","useThrewNonResult","releaseErr","maybeResult","isMapperException","originalCause","allAsync","results","ok","resolve","settled","pendingCount","values","i","index","reason","err","result","isStepComplete","event","isWorkflowCancelled","error","SnapshotFormatError","message","errors","SnapshotDecodeError","message","stepId","originalError","validateSnapshot","obj","errors","snapshot","steps","stepId","stepResult","step","execution","assertValidSnapshot","result","SnapshotFormatError","mergeSnapshots","base","delta","mergedSteps","key","value","mergedMetadata","mergedWarnings","w","MAX_STRING_REPRESENTATION_LENGTH","serializeError","error","serialized","errorWithCause","serializeThrown","stringRepresentation","truncated","originalType","jsonValue","deserializeCauseNew","isCachedErrorCause","cause","encodeCachedError","error","meta","originalCause","err","decodeCachedMeta","createResumeStateCollector","steps","event","isStepComplete","STREAM_WRITE_ERROR","STREAM_READ_ERROR","STREAM_CLOSE_ERROR","STREAM_ENDED","streamWriteError","reason","message","cause","STREAM_WRITE_ERROR","streamReadError","STREAM_READ_ERROR","streamCloseError","STREAM_CLOSE_ERROR","streamEnded","finalPosition","STREAM_ENDED","createBackpressureController","options","highWaterMark","lowWaterMark","onStateChange","state","bufferedCount","drainResolvers","updateState","newState","resolvers","resolve","checkState","count","millis","ms","seconds","s","minutes","m","hours","h","days","d","toMillis","duration","parse","input","match","value","millis","seconds","minutes","hours","days","validateInput","schema","input","result","resolved","err","i","p","ok","createWorkflow","workflowName","deps","options","depsActual","optionsActual","internalExecute","runName","userFn","config","workflowId","effectiveDeps","createContextFn","context","workflowSignal","onEventHandler","onErrorHandler","shouldRunHook","onBeforeStartHook","onAfterStepHook","resumeStateOption","catchUnexpected","defaultCatchUnexpected","workflowData","devWarnings","ctxSetWarned","ctxGetWarned","workflowContext","key","value","emitEvent","event","eventWithContext","eventWithName","createCancelledResult","reason","lastStepKey","cancelledError","err","hookStartTime","shouldRunResult","hookDuration","skipCause","thrown","beforeStartResult","inputSchema","inputValue","validationResult","validateInput","startTs","startTime","cache","streamStore","resumeState","entry","result","meta","effectiveMeta","encodeCachedError","snapshotOption","snapshotSerialization","snapshot","decode","stepId","stepResult","ok","errorValue","deserializedCause","deserializeCauseNew","e","SnapshotDecodeError","abortedDuringExecution","abortReason","abortHandler","checkCancellation","callOnAfterStepHook","stepKey","_meta","createCachedStep","realStep","cachedStepFn","idOrOperationOrResult","operationOrOptions","stepOptions","id","opts","name","ttl","out","stepMetadata","extractStepMetadata","cached","decodeCachedMeta","createEarlyExit","isEarlyExit","exit","originalCause","errorResult","operation","duration","d","parse","ms","toMillis","userSignal","resolve","reject","state","onAbort","activeWriters","activeReaders","namespace","highWaterMark","existingKey","existing","backpressure","createBackpressureController","position","writable","aborted","closed","writer","streamWriteError","item","streamCloseError","startIndex","pollInterval","pollTimeout","decrementBackpressure","writerKey","activeWriter","readable","bufferedItems","bufferIndex","reader","streamReadError","pollStart","hasSeenWriter","initialMetaResult","hasSeenMetadata","items","writerActive","metaResult","metadataExists","streamEnded","source","processor","checkpointInterval","concurrency","results","processedCount","lastPosition","isStreamReader","s","processItem","itemIndex","itemPosition","readResult","resultsMap","totalItems","slots","getSlot","i","activePromises","completed","slotIndex","currentIndex","currentPosition","currentItem","currentSlot","r","index","resultOrGetter","getter","fn","handlers","resolved","shape","mapper","wrappedFn","step","run","durationMs","isWorkflowCancelled","isUnexpectedError","runMethod","fnOrName","maybeFnOrConfig","maybeConfig","runWithStateMethod","collector","createResumeStateCollector","userOnEvent","mergedConfig","ctx","defaultStore","createMemorySnapshotStore","store","id","snapshot","options","prefix","limit","results","entry","a","b","getDefaultStore","isVersionMismatch","error","isConcurrentExecution","isPersistenceError","isLeaseExpired","isIdempotencyConflict","hasWorkflowLock","activeWorkflows","durable","deps","fn","storeOption","version","allowConcurrent","lockTtlMs","heartbeatIntervalMs","abortOnLeaseLoss","metadata","signal","createContext","onEvent","onError","onVersionMismatch","idempotencyKey","input","effectiveStore","idemId","idemSnapshot","storedInput","currentInput","err","leaseOwnerToken","lease","lockError","heartbeatTimer","leaseAbortController","lockStore","heartbeatMs","existingSnapshot","loadError","assertValidSnapshot","validationError","SnapshotFormatError","storedVersion","resolution","emitDurableEvent","event","ctx","resumeCollector","createResumeStateCollector","workflowOptions","stepKey","result","wfId","collectedState","steps","key","cause","serializedCause","serializeError","serializeThrown","origin","currentSnapshot","snapshotToSave","mergeSnapshots","currentStepKeys","filtered","w","persistError","workflowInstance","createWorkflow","createError","runError","SnapshotDecodeError","deleteError","storeWithClear","entries","ids","e","concurrency","continueOnError","errors","deleted","run","i","batch"]}
|
|
1
|
+
{"version":3,"sources":["../src/durable-entry.ts","../src/tagged-error.ts","../src/errors.ts","../src/core/index.ts","../src/workflow/guards.ts","../src/persistence.ts","../src/workflow/cache-encoding.ts","../src/workflow/resume-state.ts","../src/streaming/types.ts","../src/streaming/backpressure.ts","../src/duration.ts","../src/workflow/validation.ts","../src/workflow/execute.ts","../src/durable/index.ts"],"sourcesContent":["/**\n * awaitly/durable\n *\n * Durable execution with automatic state persistence.\n * Re-exports from the main durable module.\n */\n\nexport {\n // Main API\n durable,\n\n // Types\n type DurableOptions,\n type DurableWorkflowEvent,\n type VersionMismatchError,\n type ConcurrentExecutionError,\n type PersistenceError,\n type WorkflowLock,\n type DeleteStatesOptions,\n type DeleteStatesResult,\n\n // Type guards\n isVersionMismatch,\n isConcurrentExecution,\n isPersistenceError,\n isLeaseExpired,\n isIdempotencyConflict,\n\n // New error types\n type LeaseExpiredError,\n type IdempotencyConflictError,\n\n // Re-exports from workflow\n isWorkflowCancelled,\n type WorkflowCancelledError,\n\n // Re-exports from persistence (new snapshot API)\n type SnapshotStore,\n} from \"./durable\";\n","/**\n * awaitly/tagged-error\n *\n * Factory for creating tagged error types with exhaustive pattern matching.\n * Enables TypeScript to enforce that all error variants are handled.\n *\n * @example\n * ```typescript\n * // Define error types (Props via generic)\n * class NotFoundError extends TaggedError(\"NotFoundError\")<{\n * id: string;\n * resource: string;\n * }> {}\n *\n * // Define with type-safe message (Props inferred from callback annotation)\n * class ValidationError extends TaggedError(\"ValidationError\", {\n * message: (p: { field: string; reason: string }) => `Invalid ${p.field}: ${p.reason}`,\n * }) {}\n *\n * // Create instances\n * const error = new NotFoundError({ id: \"123\", resource: \"User\" });\n *\n * // Runtime type check: instanceof TaggedError works!\n * console.log(error instanceof TaggedError); // true\n *\n * // Exhaustive matching\n * type AppError = NotFoundError | ValidationError;\n * const message = TaggedError.match(error as AppError, {\n * NotFoundError: (e) => `Missing: ${e.resource} ${e.id}`,\n * ValidationError: (e) => `Invalid ${e.field}: ${e.reason}`,\n * });\n * ```\n */\n\n/**\n * Options for Error constructor (compatible with ES2022 ErrorOptions).\n */\nexport interface TaggedErrorOptions {\n cause?: unknown;\n}\n\n/**\n * Options for TaggedError factory with type-safe message callback.\n */\nexport interface TaggedErrorCreateOptions<Props extends Record<string, unknown>> {\n /** Custom message generator from props. Annotate parameter for type safety. */\n message: (props: Props) => string;\n}\n\n/**\n * Base interface for all tagged errors.\n */\nexport interface TaggedErrorBase extends Error {\n readonly _tag: string;\n}\n\n/**\n * Internal base class for instanceof checks.\n * All TaggedError-created classes extend this.\n * @internal\n */\nclass InternalTaggedErrorBase extends Error implements TaggedErrorBase {\n readonly _tag!: string;\n}\n\n/**\n * Instance type for factory-created TaggedErrors.\n */\ntype TaggedErrorInstance<Tag extends string, Props> = TaggedErrorBase & {\n readonly _tag: Tag;\n} & Readonly<Props>;\n\n/**\n * Constructor args type - conditionally optional based on whether Props has required fields.\n * - If Props is empty or all properties are optional: props argument is optional\n * - If Props has any required properties: props argument is required\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\ntype ConstructorArgs<Props extends Record<string, unknown>> = {} extends Props\n ? [props?: Props | void, options?: TaggedErrorOptions]\n : [props: Props, options?: TaggedErrorOptions];\n\n/**\n * Constructor type returned by TaggedError factory.\n */\nexport interface TaggedErrorConstructor<\n Tag extends string,\n Props extends Record<string, unknown>,\n> {\n new (...args: ConstructorArgs<Props>): TaggedErrorInstance<Tag, Props>;\n readonly prototype: TaggedErrorInstance<Tag, Props>;\n}\n\n/**\n * Generic class factory type that allows `<Props>` parameterization.\n * This enables the Effect.js-style syntax: `class X extends TaggedError(\"X\")<Props> {}`\n * @internal\n */\nexport interface TaggedErrorClassFactory<Tag extends string> {\n new <Props extends Record<string, unknown> = Record<string, never>>(\n ...args: ConstructorArgs<Props>\n ): TaggedErrorInstance<Tag, Props>;\n}\n\n/**\n * Helper type to extract return type from a function type.\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype FnReturnType<T> = T extends (...args: any[]) => infer R ? R : never;\n\n/**\n * Helper type to get union of return types from all handlers.\n * @internal\n */\ntype HandlersReturnType<H> = { [K in keyof H]: FnReturnType<H[K]> }[keyof H];\n\n/**\n * Helper type to extract keys whose values are definitely functions (not undefined).\n * Only excludes a tag from the fallback type if its handler is guaranteed to be\n * a function. Keys where the value type includes undefined are NOT excluded,\n * ensuring type safety with dynamic/conditional handlers.\n * @internal\n */\ntype DefinitelyHandledKeys<H> = {\n [K in keyof H]-?: undefined extends H[K] ? never : K;\n}[keyof H];\n\n/**\n * Factory function to create tagged error classes.\n *\n * Two usage patterns:\n *\n * 1. **Props via generic** (default message is tag name):\n * ```typescript\n * class NotFoundError extends TaggedError(\"NotFoundError\")<{ id: string }> {}\n * ```\n *\n * 2. **Props inferred from message callback** (type-safe message):\n * ```typescript\n * class NotFoundError extends TaggedError(\"NotFoundError\", {\n * message: (p: { id: string }) => `Not found: ${p.id}`,\n * }) {}\n * ```\n *\n * Both support `instanceof TaggedError` checks at runtime.\n *\n * @param tag - The unique tag string for this error type\n * @param options - Optional configuration with message generator (annotate param for type safety)\n * @returns A class constructor that can be extended\n */\n\n// Overload 1: No options - use <Props> generic syntax, default message is tag\nfunction TaggedError<Tag extends string>(\n tag: Tag\n): TaggedErrorClassFactory<Tag>;\n\n// Overload 2: With message option - Props inferred from callback parameter annotation\nfunction TaggedError<Tag extends string, Props extends Record<string, unknown>>(\n tag: Tag,\n options: TaggedErrorCreateOptions<Props>\n): TaggedErrorConstructor<Tag, Props>;\n\n// Implementation\nfunction TaggedError<Tag extends string, Props extends Record<string, unknown>>(\n tag: Tag,\n options?: TaggedErrorCreateOptions<Props>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): any {\n return class extends InternalTaggedErrorBase {\n override readonly _tag: Tag = tag;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n constructor(props?: any, errorOptions?: TaggedErrorOptions) {\n // Generate message: call callback if provided (even for prop-less errors), else use tag\n const message = options?.message ? options.message(props ?? {}) : tag;\n\n super(message);\n this.name = tag;\n\n // Maintains proper prototype chain for instanceof checks\n Object.setPrototypeOf(this, new.target.prototype);\n\n // Assign props to instance, stripping reserved keys:\n // - _tag: discriminant for pattern matching (cannot be forged)\n // - name, message, stack: Error internals (preserve for logging/debugging)\n // Note: 'cause' is allowed as a user prop (common for domain errors)\n if (props && typeof props === \"object\") {\n const {\n _tag: _,\n name: _n,\n message: _m,\n stack: _s,\n ...safeProps\n } = props;\n\n const hasUserCause = Object.prototype.hasOwnProperty.call(\n safeProps,\n \"cause\"\n );\n const userCause = hasUserCause\n ? (safeProps as { cause?: unknown }).cause\n : undefined;\n if (hasUserCause) {\n delete (safeProps as { cause?: unknown }).cause;\n }\n\n const hasOptionsCause = errorOptions?.cause !== undefined;\n if (hasUserCause && hasOptionsCause) {\n throw new TypeError(\n \"TaggedError: cannot provide 'cause' in props when also setting ErrorOptions.cause\"\n );\n }\n\n Object.assign(this, safeProps);\n\n if (hasUserCause) {\n (this as { cause?: unknown }).cause = userCause;\n }\n if (hasOptionsCause) {\n (this as { cause?: unknown }).cause = errorOptions?.cause;\n }\n } else if (errorOptions?.cause !== undefined) {\n (this as { cause?: unknown }).cause = errorOptions.cause;\n }\n }\n };\n}\n\n// Add Symbol.hasInstance so `instanceof TaggedError` works\nObject.defineProperty(TaggedError, Symbol.hasInstance, {\n value: (instance: unknown): boolean => instance instanceof InternalTaggedErrorBase,\n});\n\n/**\n * Namespace for static methods on TaggedError.\n */\n// eslint-disable-next-line @typescript-eslint/no-namespace\nnamespace TaggedError {\n /**\n * Type guard to check if a value is an Error instance.\n */\n export function isError(value: unknown): value is Error {\n return value instanceof Error;\n }\n\n /**\n * Type guard to check if a value is a TaggedError instance.\n * Uses the same check as `instanceof TaggedError` - only genuine\n * TaggedError instances (created via the factory) pass this guard.\n */\n export function isTaggedError(value: unknown): value is TaggedErrorBase {\n return value instanceof InternalTaggedErrorBase;\n }\n\n /**\n * Exhaustively matches on a tagged error, requiring handlers for all variants.\n *\n * TypeScript will error if any variant in the error union is not handled.\n *\n * @remarks When to use: You want compile-time enforcement that every tagged variant is handled.\n *\n * @param error - The tagged error to match\n * @param handlers - Object mapping _tag values to handler functions\n * @returns The return value of the matched handler\n *\n * @example\n * ```typescript\n * type AppError = NotFoundError | ValidationError;\n *\n * const message = TaggedError.match(error, {\n * NotFoundError: (e) => `Not found: ${e.id}`,\n * ValidationError: (e) => `Invalid: ${e.field}`,\n * });\n * ```\n */\n export function match<\n E extends TaggedErrorBase,\n H extends { [K in E[\"_tag\"]]: (e: Extract<E, { _tag: K }>) => unknown },\n >(error: E, handlers: H): HandlersReturnType<H> {\n const tag = error._tag as E[\"_tag\"];\n const handler = handlers[tag];\n return handler(\n error as Extract<E, { _tag: typeof tag }>\n ) as HandlersReturnType<H>;\n }\n\n /**\n * Partially matches on a tagged error with a fallback for unhandled variants.\n *\n * The fallback receives variants that are NOT definitely handled. A tag is\n * considered \"definitely handled\" only if its handler is a function (not\n * `undefined`). This ensures type safety even with dynamic/conditional handlers:\n *\n * ```typescript\n * const maybeHandle = featureFlag ? (e) => e.id : undefined;\n * TaggedError.matchPartial(\n * error,\n * { NotFoundError: maybeHandle }, // maybeHandle might be undefined\n * (e) => e._tag // e correctly includes NotFoundError\n * );\n * ```\n *\n * @param error - The tagged error to match\n * @param handlers - Partial object mapping _tag values to handler functions\n * @param otherwise - Fallback handler for unmatched variants\n * @returns The return value of the matched handler or fallback\n *\n * @example\n * ```typescript\n * const message = TaggedError.matchPartial(\n * error,\n * { NotFoundError: (e) => `Not found: ${e.id}` },\n * (e) => `Other error: ${e.message}`\n * );\n * ```\n */\n export function matchPartial<\n E extends TaggedErrorBase,\n H extends Partial<{\n [K in E[\"_tag\"]]: (e: Extract<E, { _tag: K }>) => unknown;\n }>,\n T,\n >(\n error: E,\n handlers: H,\n otherwise: (e: Exclude<E, { _tag: DefinitelyHandledKeys<H> }>) => T\n ): HandlersReturnType<H> | T {\n const tag = error._tag as E[\"_tag\"];\n const handler = handlers[tag];\n if (handler) {\n return handler(\n error as Extract<E, { _tag: typeof tag }>\n ) as HandlersReturnType<H>;\n }\n return otherwise(error as Exclude<E, { _tag: DefinitelyHandledKeys<H> }>);\n }\n}\n\nexport { TaggedError };\n\n/**\n * Helper type to extract the _tag literal type from a TaggedError.\n *\n * @example\n * ```typescript\n * class MyError extends TaggedError(\"MyError\")<{ id: string }> {}\n * type Tag = TagOf<MyError>; // \"MyError\"\n * ```\n */\nexport type TagOf<E extends TaggedErrorBase> = E[\"_tag\"];\n\n/**\n * Helper type to extract a specific variant from a TaggedError union by tag.\n *\n * @example\n * ```typescript\n * type AppError = NotFoundError | ValidationError;\n * type NotFound = ErrorByTag<AppError, \"NotFoundError\">; // NotFoundError\n * ```\n */\nexport type ErrorByTag<\n E extends TaggedErrorBase,\n Tag extends E[\"_tag\"],\n> = Extract<E, { _tag: Tag }>;\n\n/**\n * Reserved keys that are stripped from user props at runtime.\n * These keys cannot be used as user-defined properties:\n * - _tag: discriminant for pattern matching\n * - name, message, stack: Error internals (preserved for logging/debugging)\n *\n * Note: 'cause' is NOT reserved - it can be used as a user prop.\n */\ntype ReservedErrorKeys = \"_tag\" | \"name\" | \"message\" | \"stack\";\n\n/**\n * Helper type to extract props from a TaggedError.\n * Excludes reserved keys that are stripped at runtime.\n *\n * @example\n * ```typescript\n * class MyError extends TaggedError(\"MyError\")<{ id: string }> {}\n * type Props = PropsOf<MyError>; // { id: string }\n *\n * // 'cause' is allowed as a user prop\n * class DomainError extends TaggedError(\"DomainError\")<{ cause: { field: string } }> {}\n * type DomainProps = PropsOf<DomainError>; // { cause: { field: string } }\n * ```\n */\nexport type PropsOf<E extends TaggedErrorBase> = Omit<E, ReservedErrorKeys>;\n","/**\n * awaitly/errors\n *\n * Pre-built error types for common failure scenarios.\n * Uses TaggedError for type-safe exhaustive matching.\n *\n * @example\n * ```typescript\n * import { TimeoutError, RetryExhaustedError, RateLimitError, CircuitOpenError } from 'awaitly/errors';\n *\n * // Create errors\n * const timeout = new TimeoutError({ operation: 'fetchUser', ms: 5000 });\n * const retryFailed = new RetryExhaustedError({ operation: 'sendEmail', attempts: 3 });\n *\n * // Pattern match\n * TaggedError.match(error, {\n * TimeoutError: (e) => `${e.operation} timed out after ${e.ms}ms`,\n * RetryExhaustedError: (e) => `${e.operation} failed after ${e.attempts} attempts`,\n * RateLimitError: (e) => `Rate limit exceeded, retry after ${e.retryAfterMs}ms`,\n * CircuitOpenError: (e) => `Circuit ${e.circuitName} is open`,\n * });\n * ```\n */\n\nimport { TaggedError } from \"./tagged-error\";\n\n// =============================================================================\n// Error Factory\n// =============================================================================\n\n/**\n * Factory function to create tagged error classes with default values.\n *\n * This is a convenience wrapper around TaggedError that allows specifying\n * default property values for error types.\n *\n * @example\n * ```typescript\n * // Define custom error with defaults\n * const NetworkError = makeError('NetworkError', {\n * defaults: { retryable: true },\n * message: (p) => `Network error: ${p.reason}`,\n * });\n *\n * class MyNetworkError extends NetworkError<{ reason: string; code?: number }> {}\n *\n * const error = new MyNetworkError({ reason: 'Connection refused' });\n * // error.retryable === true (from defaults)\n * ```\n */\nexport function makeError<Tag extends string>(\n tag: Tag,\n options?: {\n message?: (props: Record<string, unknown>) => string;\n defaults?: Record<string, unknown>;\n }\n) {\n const messageGenerator = options?.message ?? (() => tag);\n const defaults = options?.defaults ?? {};\n\n // Create base class using TaggedError\n const BaseClass = TaggedError(tag, {\n message: (props: Record<string, unknown>) =>\n messageGenerator({ ...defaults, ...props }),\n });\n\n // Return a factory that applies defaults\n return class extends BaseClass {\n constructor(props?: Record<string, unknown>) {\n super({ ...defaults, ...props } as Record<string, unknown>);\n // Apply defaults to instance\n Object.assign(this, { ...defaults, ...props });\n }\n };\n}\n\n// =============================================================================\n// Pre-built Error Types\n// =============================================================================\n\n/**\n * Error thrown when an operation times out.\n *\n * @example\n * ```typescript\n * const error = new TimeoutError({\n * operation: 'fetchUser',\n * ms: 5000,\n * });\n * console.log(error.message); // \"TimeoutError: fetchUser timed out after 5000ms\"\n * ```\n */\nexport class TimeoutError extends TaggedError(\"TimeoutError\", {\n message: (p: {\n /** Name of the operation that timed out */\n operation?: string;\n /** Timeout duration in milliseconds */\n ms: number;\n }) =>\n p.operation\n ? `TimeoutError: ${p.operation} timed out after ${p.ms}ms`\n : `TimeoutError: Operation timed out after ${p.ms}ms`,\n}) {}\n\n/**\n * Error thrown when all retry attempts are exhausted.\n *\n * @example\n * ```typescript\n * const error = new RetryExhaustedError({\n * operation: 'sendEmail',\n * attempts: 3,\n * lastError: originalError,\n * });\n * console.log(error.message); // \"RetryExhaustedError: sendEmail failed after 3 attempts\"\n * ```\n */\nexport class RetryExhaustedError extends TaggedError(\"RetryExhaustedError\", {\n message: (p: {\n /** Name of the operation that failed */\n operation?: string;\n /** Total number of retry attempts made */\n attempts: number;\n /** The last error encountered before giving up */\n lastError?: unknown;\n }) =>\n p.operation\n ? `RetryExhaustedError: ${p.operation} failed after ${p.attempts} attempts`\n : `RetryExhaustedError: Operation failed after ${p.attempts} attempts`,\n}) {}\n\n/**\n * Error thrown when a rate limit is exceeded.\n *\n * @example\n * ```typescript\n * const error = new RateLimitError({\n * limiterName: 'api-calls',\n * retryAfterMs: 1000,\n * });\n * console.log(error.message); // \"RateLimitError: Rate limit exceeded for api-calls\"\n * ```\n */\nexport class RateLimitError extends TaggedError(\"RateLimitError\", {\n message: (p: {\n /** Name of the rate limiter that was exceeded */\n limiterName?: string;\n /** Time in milliseconds until the rate limit resets */\n retryAfterMs?: number;\n }) =>\n p.limiterName\n ? `RateLimitError: Rate limit exceeded for ${p.limiterName}${p.retryAfterMs ? `, retry after ${p.retryAfterMs}ms` : \"\"}`\n : `RateLimitError: Rate limit exceeded${p.retryAfterMs ? `, retry after ${p.retryAfterMs}ms` : \"\"}`,\n}) {}\n\n/**\n * Error thrown when a circuit breaker is open.\n *\n * @example\n * ```typescript\n * const error = new CircuitBreakerOpenError({\n * circuitName: 'payment-api',\n * state: 'OPEN',\n * retryAfterMs: 30000,\n * });\n * console.log(error.message); // \"CircuitBreakerOpenError: Circuit payment-api is OPEN\"\n * ```\n */\nexport class CircuitBreakerOpenError extends TaggedError(\n \"CircuitBreakerOpenError\",\n {\n message: (p: {\n /** Name of the circuit breaker */\n circuitName: string;\n /** Current state of the circuit */\n state?: \"OPEN\" | \"HALF_OPEN\";\n /** Time in milliseconds until the circuit may close */\n retryAfterMs?: number;\n }) =>\n `CircuitBreakerOpenError: Circuit ${p.circuitName} is ${p.state ?? \"OPEN\"}${p.retryAfterMs ? `, retry after ${Math.ceil(p.retryAfterMs / 1000)}s` : \"\"}`,\n }\n) {}\n\n/**\n * Error thrown when validation fails.\n *\n * @example\n * ```typescript\n * const error = new ValidationError({\n * field: 'email',\n * reason: 'Invalid email format',\n * });\n * console.log(error.message); // \"ValidationError: Invalid email - Invalid email format\"\n * ```\n */\nexport class ValidationError extends TaggedError(\"ValidationError\", {\n message: (p: {\n /** Field that failed validation */\n field: string;\n /** Reason for validation failure */\n reason: string;\n /** Raw value that failed validation */\n value?: unknown;\n }) => `ValidationError: Invalid ${p.field} - ${p.reason}`,\n}) {}\n\n/**\n * Error thrown when a resource is not found.\n *\n * @example\n * ```typescript\n * const error = new NotFoundError({\n * resource: 'User',\n * id: '123',\n * });\n * console.log(error.message); // \"NotFoundError: User with id 123 not found\"\n * ```\n */\nexport class NotFoundError extends TaggedError(\"NotFoundError\", {\n message: (p: {\n /** Type of resource that was not found */\n resource: string;\n /** Identifier of the missing resource */\n id?: string;\n }) =>\n p.id\n ? `NotFoundError: ${p.resource} with id ${p.id} not found`\n : `NotFoundError: ${p.resource} not found`,\n}) {}\n\n/**\n * Error thrown when access is denied.\n *\n * @example\n * ```typescript\n * const error = new UnauthorizedError({\n * action: 'delete',\n * resource: 'User',\n * });\n * console.log(error.message); // \"UnauthorizedError: Not authorized to delete User\"\n * ```\n */\nexport class UnauthorizedError extends TaggedError(\"UnauthorizedError\", {\n message: (p: {\n /** Action that was attempted */\n action?: string;\n /** Resource that was being accessed */\n resource?: string;\n /** Reason for denial */\n reason?: string;\n }) =>\n p.reason\n ? `UnauthorizedError: ${p.reason}`\n : p.action && p.resource\n ? `UnauthorizedError: Not authorized to ${p.action} ${p.resource}`\n : \"UnauthorizedError: Access denied\",\n}) {}\n\n/**\n * Error thrown for network-related failures.\n *\n * @example\n * ```typescript\n * const error = new NetworkError({\n * url: 'https://api.example.com/users',\n * reason: 'Connection refused',\n * retryable: true,\n * });\n * ```\n */\nexport class NetworkError extends TaggedError(\"NetworkError\", {\n message: (p: {\n /** URL that was being accessed */\n url?: string;\n /** Reason for the network failure */\n reason: string;\n /** Whether this error is retryable */\n retryable?: boolean;\n /** HTTP status code if applicable */\n statusCode?: number;\n }) =>\n p.url\n ? `NetworkError: ${p.reason} (${p.url})`\n : `NetworkError: ${p.reason}`,\n}) {}\n\n/**\n * Error thrown when a saga compensation fails.\n *\n * @example\n * ```typescript\n * const error = new CompensationError({\n * step: 'chargeCard',\n * originalError: paymentError,\n * compensationError: refundError,\n * });\n * ```\n */\nexport class CompensationError extends TaggedError(\"CompensationError\", {\n message: (p: {\n /** Step that triggered compensation */\n step: string;\n /** The original error that caused compensation */\n originalError?: unknown;\n /** Error that occurred during compensation */\n compensationError?: unknown;\n }) => `CompensationError: Failed to compensate step ${p.step}`,\n}) {}\n\n// =============================================================================\n// Unexpected Error\n// =============================================================================\n\n/**\n * Default error type for uncaught exceptions and cancellation in workflows.\n * This is the default `U` type when `catchUnexpected` is not provided.\n *\n * @example\n * ```typescript\n * // Automatically used as the default — no need to pass catchUnexpected:\n * const workflow = createWorkflow(\"checkout\", { chargeCard, sendEmail });\n *\n * // Equivalent to:\n * const workflow = createWorkflow(\"checkout\", { chargeCard, sendEmail }, {\n * catchUnexpected: (cause) => new UnexpectedError({ cause }),\n * });\n * ```\n */\nexport class UnexpectedError extends TaggedError(\"UnexpectedError\", {\n message: (p: {\n /** The original thrown value or cancellation error */\n cause?: unknown;\n }) => `UnexpectedError: ${p.cause instanceof Error ? p.cause.message : String(p.cause ?? \"unknown\")}`,\n}) {}\n\n\n// =============================================================================\n// Union Type for Common Errors\n// =============================================================================\n\n/**\n * Union of all pre-built error types.\n * Useful for exhaustive pattern matching.\n *\n * @example\n * ```typescript\n * function handleError(error: AwaitlyError): string {\n * return TaggedError.match(error, {\n * TimeoutError: (e) => `Timeout: ${e.ms}ms`,\n * RetryExhaustedError: (e) => `Retries: ${e.attempts}`,\n * RateLimitError: (e) => `Rate limited`,\n * CircuitBreakerOpenError: (e) => `Circuit open: ${e.circuitName}`,\n * ValidationError: (e) => `Invalid: ${e.field}`,\n * NotFoundError: (e) => `Not found: ${e.resource}`,\n * UnauthorizedError: (e) => `Unauthorized`,\n * NetworkError: (e) => `Network: ${e.reason}`,\n * CompensationError: (e) => `Compensation failed: ${e.step}`,\n * });\n * }\n * ```\n */\nexport type AwaitlyError =\n | TimeoutError\n | RetryExhaustedError\n | RateLimitError\n | CircuitBreakerOpenError\n | ValidationError\n | NotFoundError\n | UnauthorizedError\n | NetworkError\n | CompensationError;\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Check if an error is a TimeoutError.\n */\nexport function isTimeoutError(error: unknown): error is TimeoutError {\n return TaggedError.isTaggedError(error) && error._tag === \"TimeoutError\";\n}\n\n/**\n * Check if an error is a RetryExhaustedError.\n */\nexport function isRetryExhaustedError(\n error: unknown\n): error is RetryExhaustedError {\n return (\n TaggedError.isTaggedError(error) && error._tag === \"RetryExhaustedError\"\n );\n}\n\n/**\n * Check if an error is a RateLimitError.\n */\nexport function isRateLimitError(error: unknown): error is RateLimitError {\n return TaggedError.isTaggedError(error) && error._tag === \"RateLimitError\";\n}\n\n/**\n * Check if an error is a CircuitBreakerOpenError.\n */\nexport function isCircuitBreakerOpenError(\n error: unknown\n): error is CircuitBreakerOpenError {\n return (\n TaggedError.isTaggedError(error) && error._tag === \"CircuitBreakerOpenError\"\n );\n}\n\n/**\n * Check if an error is a ValidationError.\n */\nexport function isValidationError(error: unknown): error is ValidationError {\n return TaggedError.isTaggedError(error) && error._tag === \"ValidationError\";\n}\n\n/**\n * Check if an error is a NotFoundError.\n */\nexport function isNotFoundError(error: unknown): error is NotFoundError {\n return TaggedError.isTaggedError(error) && error._tag === \"NotFoundError\";\n}\n\n/**\n * Check if an error is an UnauthorizedError.\n */\nexport function isUnauthorizedError(\n error: unknown\n): error is UnauthorizedError {\n return TaggedError.isTaggedError(error) && error._tag === \"UnauthorizedError\";\n}\n\n/**\n * Check if an error is a NetworkError.\n */\nexport function isNetworkError(error: unknown): error is NetworkError {\n return TaggedError.isTaggedError(error) && error._tag === \"NetworkError\";\n}\n\n/**\n * Check if an error is a CompensationError.\n */\nexport function isCompensationError(\n error: unknown\n): error is CompensationError {\n return TaggedError.isTaggedError(error) && error._tag === \"CompensationError\";\n}\n\n/**\n * Check if an error is any AwaitlyError.\n */\nexport function isAwaitlyError(error: unknown): error is AwaitlyError {\n if (!TaggedError.isTaggedError(error)) return false;\n const tag = error._tag;\n return [\n \"TimeoutError\",\n \"RetryExhaustedError\",\n \"RateLimitError\",\n \"CircuitBreakerOpenError\",\n \"ValidationError\",\n \"NotFoundError\",\n \"UnauthorizedError\",\n \"NetworkError\",\n \"CompensationError\",\n ].includes(tag);\n}\n","/**\n * awaitly/core\n *\n * Core Result primitives and run() function.\n * Use this module for minimal bundle size when you don't need the full workflow capabilities\n * (like retries, timeout, or state persistence) provided by `createWorkflow`.\n *\n * This module provides:\n * 1. `Result` types for error handling without try/catch\n * 2. `run()` function for executing steps with standardized error management\n * 3. Utilities for transforming and combining Results\n */\n\n// Inline duration type and parser to avoid importing the full duration module\n// This keeps the core bundle minimal (~1KB saved)\n\n/** Duration object with tagged type for type safety */\ntype DurationObject = { readonly _tag: \"Duration\"; readonly millis: number };\n\n/** Duration input: either a string (\"5s\", \"100ms\") or a Duration object */\ntype DurationInput = string | DurationObject;\n\n/** Parse a duration string like \"100ms\", \"5s\", \"2m\", \"1h\", \"1d\" */\nfunction parseDurationString(input: string): DurationObject | undefined {\n const match = input.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h|d)$/i);\n if (!match) return undefined;\n const value = parseFloat(match[1]);\n const unit = match[2].toLowerCase();\n const multipliers: Record<string, number> = { ms: 1, s: 1000, m: 60000, h: 3600000, d: 86400000 };\n return { _tag: \"Duration\", millis: value * (multipliers[unit] ?? 1) };\n}\n\n// =============================================================================\n// Core Result Types\n// =============================================================================\n\n/**\n * Represents a successful result.\n * Use `ok(value)` to create instances.\n *\n * @template T - The type of the success value\n *\n * @example\n * ```typescript\n * const success = Awaitly.ok(42);\n * // Type shown: Ok<number>\n * ```\n */\nexport type Ok<T> = {\n ok: true;\n value: T;\n};\n\n/**\n * Represents a failed result.\n * Use `err(error)` to create instances.\n *\n * @template E - The type of the error value\n * @template C - The type of the cause (defaults to unknown)\n * @template T - Phantom type for the success value (preserved after narrowing)\n *\n * @example\n * ```typescript\n * const failure = Awaitly.err({ type: \"NOT_FOUND\", message: \"User not found\" });\n * // Type shown: Err<{ type: string; message: string }>\n * ```\n */\nexport type Err<E, C = unknown> = {\n ok: false;\n error: E;\n cause?: C;\n};\n\n/**\n * Represents a successful computation or a failed one.\n * Use this type to represent the outcome of an operation that might fail,\n * instead of throwing exceptions.\n *\n * @template T - The type of the success value\n * @template E - The type of the error value (defaults to unknown)\n * @template C - The type of the cause (defaults to unknown)\n */\nexport type Result<T, E = unknown, C = unknown> = Ok<T> | Err<E, C>;\n\n/**\n * A Promise that resolves to a Result.\n * Use this for asynchronous operations that might fail.\n */\nexport type AsyncResult<T, E = unknown, C = unknown> = Promise<Result<T, E, C>>;\n\n/** Discriminant for PromiseRejectedError type - use in switch statements */\nexport const PROMISE_REJECTED = \"PROMISE_REJECTED\" as const;\n\n// =============================================================================\n// Named Error Constants (for static analysis)\n// =============================================================================\n\n/**\n * Named error constant for unexpected/unhandled errors.\n * Used by the analyzer when a step doesn't declare errors.\n */\nexport const AWAITLY_UNEXPECTED = \"AWAITLY_UNEXPECTED\" as const;\n\n/**\n * Named error constant for cancelled operations.\n */\nexport const AWAITLY_CANCELLED = \"AWAITLY_CANCELLED\" as const;\n\n/**\n * Named error constant for timed-out operations.\n */\nexport const AWAITLY_TIMEOUT = \"AWAITLY_TIMEOUT\" as const;\n\n// =============================================================================\n// Static Analysis Helpers\n// =============================================================================\n\n/**\n * Helper to create a tuple of string literal tags with preserved literal types.\n * Use this when you need to store error tags in a variable while keeping\n * TypeScript's literal type inference (avoiding widening to string[]).\n *\n * @param t - The string literal tags\n * @returns The same array with preserved literal types\n *\n * @example\n * ```typescript\n * // Without tags() - type widens to string[]\n * const errs = ['CART_NOT_FOUND', 'CART_EMPTY']; // string[]\n *\n * // With tags() - literal types preserved\n * const errs = tags('CART_NOT_FOUND', 'CART_EMPTY'); // ['CART_NOT_FOUND', 'CART_EMPTY']\n *\n * await step('getCart', () => getCart(id), {\n * errors: errs, // Analyzer can extract literal types\n * out: 'cart',\n * });\n * ```\n */\nexport const tags = <const T extends readonly string[]>(...t: T): T => t;\n\nimport { UnexpectedError } from \"../errors\";\nexport { UnexpectedError };\n\n/**\n * Default mapper for unexpected causes (uncaught exceptions, cancellation, etc.).\n * Returns an UnexpectedError TaggedError instance.\n * Used when run() is called without catchUnexpected.\n *\n * @param cause - The thrown value\n * @returns An UnexpectedError instance\n */\nexport function defaultCatchUnexpected(cause: unknown): UnexpectedError {\n return new UnexpectedError({ cause });\n}\n\nexport type PromiseRejectedError = { type: typeof PROMISE_REJECTED; cause: unknown };\n/** Cause type for promise rejections in async batch helpers */\nexport type PromiseRejectionCause = { type: \"PROMISE_REJECTION\"; reason: unknown };\nexport type EmptyInputError = { type: \"EMPTY_INPUT\"; message: string };\nexport type MaybeAsyncResult<T, E, C = unknown> = Result<T, E, C> | Promise<Result<T, E, C>>;\n\n// =============================================================================\n// Result Constructors\n// =============================================================================\n\n/**\n * Creates a successful Result.\n * Use this when an operation completes successfully.\n *\n * @remarks When to use: Wrap a successful value in a Result for consistent return types.\n *\n * @param value - The success value to wrap\n * @returns An Ok object with `{ ok: true, value }`\n *\n * @example\n * ```typescript\n * const success = Awaitly.ok(42);\n * // Type: Ok<number>\n *\n * function divide(a: number, b: number): Result<number, string> {\n * if (b === 0) return Awaitly.err(\"Division by zero\");\n * return Awaitly.ok(a / b);\n * }\n * ```\n */\nexport function ok<T>(value: T): Ok<T> {\n return { ok: true as const, value };\n}\n\n/**\n * Creates a failed Result.\n * Use this when an operation fails.\n *\n * @remarks When to use: Return a typed failure without throwing so callers can handle it explicitly.\n *\n * @param error - The error value describing what went wrong (e.g., error code, object)\n * @returns An Err object with `{ ok: false, error }`\n *\n * @example\n * ```typescript\n * // Simple error\n * const r1 = Awaitly.err(\"NOT_FOUND\");\n * // Type: Err<\"NOT_FOUND\">\n *\n * // Error with context (include in error object)\n * const r2 = Awaitly.err({ type: \"PROCESSING_FAILED\", cause: originalError });\n * // Type: Err<{ type: string; cause: Error }>\n * ```\n */\nexport function err<E, C = unknown>(error: E, options?: { cause?: C }): Err<E, C> {\n const cause = options?.cause;\n return { ok: false as const, error, ...(cause !== undefined ? { cause } : {}) } as Err<E, C>;\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Checks if a Result is successful.\n * Use this to narrow the type of a Result to the success case.\n *\n * @remarks When to use: Prefer functional-style checks or array filtering over `result.ok`.\n *\n * @param r - The Result to check\n * @returns `true` if successful, allowing access to `r.value`\n *\n * @example\n * ```typescript\n * const r = someOperation();\n * if (isOk(r)) {\n * // Use r.value (Type is T)\n * processValue(r.value);\n * } else {\n * // Handle r.error (Type is E)\n * handleError(r.error);\n * }\n * ```\n */\nexport const isOk = <T, E, C>(r: Result<T, E, C>): r is Ok<T> => r.ok;\n\n/**\n * Checks if a Result is a failure.\n * Use this to narrow the type of a Result to the error case.\n *\n * @remarks When to use: Prefer functional-style checks or array filtering over `result.ok`.\n *\n * @param r - The Result to check\n * @returns `true` if failed, allowing access to `r.error` and `r.cause`\n *\n * @example\n * ```typescript\n * if (isErr(r)) {\n * // Handle error case early\n * return;\n * }\n * // Proceed with success case\n * ```\n */\nexport const isErr = <T, E, C>(r: Result<T, E, C>): r is Err<E, C> => !r.ok;\n\n/**\n * Checks if an error is an UnexpectedError.\n * Used internally by the framework but exported for advanced custom handling.\n * Indicates an error that wasn't typed/expected in the `run` signature.\n *\n * @remarks When to use: Distinguish unexpected failures from your typed error union.\n */\nexport const isUnexpectedError = (e: unknown): e is UnexpectedError =>\n e instanceof UnexpectedError ||\n (typeof e === \"object\" &&\n e !== null &&\n \"_tag\" in e &&\n (e as { _tag: string })._tag === \"UnexpectedError\");\n\n/**\n * Checks if an error is a PromiseRejectedError.\n * Occurs when a Promise rejects in batch operations (allAsync, anyAsync, zipAsync).\n *\n * @example\n * ```typescript\n * onError: (error): FetchError => {\n * if (isPromiseRejectedError(error)) return 'FETCH_FAILED';\n * return error; // TypeScript narrows to FetchError\n * }\n * ```\n */\nexport const isPromiseRejectedError = (e: unknown): e is PromiseRejectedError =>\n typeof e === \"object\" &&\n e !== null &&\n (e as PromiseRejectedError).type === PROMISE_REJECTED;\n\n// =============================================================================\n// Error Matching\n// =============================================================================\n\n/**\n * Type for exhaustive error handlers mapping string literal errors and UnexpectedError.\n * Each key in E gets a handler, plus UnexpectedError is required.\n */\nexport type MatchErrorHandlers<E extends string, R> = {\n [K in Exclude<E, \"UnexpectedError\">]: (error: K) => R;\n} & {\n UnexpectedError: (error: UnexpectedError) => R;\n};\n\n/**\n * Exhaustive pattern matching for error types.\n * Handles both string literal errors and UnexpectedError, ensuring all cases are covered.\n *\n * @param error - The error to match (string literal or UnexpectedError)\n * @param handlers - Object with a handler for each error case plus UnexpectedError\n * @returns The result of the matched handler\n *\n * @example\n * ```typescript\n * type FetchError = \"NOT_FOUND\" | \"FETCH_ERROR\";\n * const result: Result<User, FetchError | UnexpectedError> = await fetchUser();\n *\n * if (!result.ok) {\n * return matchError(result.error, {\n * NOT_FOUND: () => 404,\n * FETCH_ERROR: () => 500,\n * UnexpectedError: (e) => { throw e.cause; }\n * });\n * }\n * ```\n */\nexport function matchError<E extends string, R>(\n error: E | UnexpectedError,\n handlers: MatchErrorHandlers<E, R>\n): R {\n // Handle UnexpectedError instances\n if (isUnexpectedError(error)) {\n return handlers.UnexpectedError(error as UnexpectedError);\n }\n // Handle string literal errors\n type StringErrors = Exclude<E, \"UnexpectedError\">;\n return handlers[error as StringErrors](error as StringErrors);\n}\n\n// =============================================================================\n// Type Utilities\n// =============================================================================\n\ntype AnyFunction = (...args: never[]) => unknown;\n\n/**\n * Helper to extract the error type from Result or AsyncResult return values.\n * Works even when a function is declared to return a union of both forms.\n */\ntype ErrorOfReturn<R> = Extract<Awaited<R>, { ok: false }> extends { error: infer E }\n ? E\n : never;\n\n/**\n * Extract error type from a single function's return type\n */\nexport type ErrorOf<T extends AnyFunction> = ErrorOfReturn<ReturnType<T>>;\n\n/**\n * Extract union of error types from multiple functions\n */\nexport type Errors<T extends AnyFunction[]> = {\n [K in keyof T]: ErrorOf<T[K]>;\n}[number];\n\n/**\n * Extract value type from Result\n */\nexport type ExtractValue<T> = T extends { ok: true; value: infer U }\n ? U\n : never;\n\n/**\n * Extract error type from Result\n */\nexport type ExtractError<T> = T extends { ok: false; error: infer E }\n ? E\n : never;\n\n/**\n * Extract cause type from Result\n */\nexport type ExtractCause<T> = T extends { ok: false; cause?: infer C }\n ? C\n : never;\n\n/**\n * Helper to extract the cause type from Result or AsyncResult return values.\n * Works even when a function is declared to return a union of both forms.\n */\ntype CauseOfReturn<R> = Extract<Awaited<R>, { ok: false }> extends { cause?: infer C }\n ? C\n : never;\n\n/**\n * Extract cause type from a function's return type\n */\nexport type CauseOf<T extends AnyFunction> = CauseOfReturn<ReturnType<T>>;\n\n// =============================================================================\n// Step Options\n// =============================================================================\n\n/**\n * Options for configuring a step within a workflow.\n * Use these to enable tracing, caching, state persistence, and static analysis.\n */\nexport type StepOptions<\n Errs extends readonly string[] = readonly string[],\n Out extends string | undefined = undefined,\n> = {\n /**\n * Stable identity key for the step.\n * REQUIRED for:\n * 1. Caching: Used as the cache key.\n * 2. Resuming: Used to identify which steps have already completed.\n *\n * Must be unique within the workflow.\n */\n key?: string;\n\n /**\n * Short description for labels/tooltips.\n * Used by static analysis visualization tools.\n */\n description?: string;\n\n /**\n * Full markdown documentation for the step.\n * Used by static analysis visualization tools.\n */\n markdown?: string;\n\n /**\n * Retry configuration for transient failures.\n * When specified, the step will retry on errors according to this config.\n */\n retry?: RetryOptions;\n\n /**\n * Timeout configuration for the operation.\n * When specified, each attempt will be aborted after the timeout duration.\n */\n timeout?: TimeoutOptions;\n\n /**\n * Time-to-live for this step's cache entry in milliseconds.\n * Overrides any global cache TTL. Requires `key` for caching.\n */\n ttl?: number;\n\n // ==========================================================================\n // Static Analysis Options\n // ==========================================================================\n\n /**\n * Declared tagged errors this step may return.\n * Used by the static analyzer to build error flow graphs.\n *\n * Use `tags()` helper when storing in a variable:\n * @example\n * ```typescript\n * const cartErrors = tags('CART_NOT_FOUND', 'CART_EMPTY');\n * await step('getCart', () => getCart(id), { errors: cartErrors });\n *\n * // Or inline (no helper needed)\n * await step('getCart', () => getCart(id), {\n * errors: ['CART_NOT_FOUND', 'CART_EMPTY'],\n * });\n * ```\n */\n errors?: Errs;\n\n /**\n * Write the step's return value to this context key.\n * Replaces manual `ctx.set()` calls for the happy path.\n *\n * @example\n * ```typescript\n * await step('getCart', () => getCart(id), { out: 'cart' });\n * // Now ctx.cart contains the result\n * ```\n */\n out?: Out;\n\n /**\n * Override auto-detected reads from context.\n * Use when the analyzer can't trace complex data dependencies.\n *\n * @example\n * ```typescript\n * await step('charge', () => chargeCard(getCartTotal()), {\n * reads: ['cart'], // Explicitly declare dependency\n * });\n * ```\n */\n reads?: readonly string[];\n\n /**\n * Hint for dependency source tracking.\n * Use when the callback is complex and the analyzer can't detect\n * which dependency function is being called.\n *\n * @example\n * ```typescript\n * await step('getCart', () => {\n * const id = transform(ctx.input.cartId);\n * return deps.getCart(id);\n * }, {\n * dep: 'getCart', // Hint for analyzer\n * });\n * ```\n */\n dep?: string;\n\n // ==========================================================================\n // Agent Metadata — Architecture & Intent\n // ==========================================================================\n\n /**\n * Why this step exists in the business flow.\n * Unlike `description` (which says *what* the step does), `intent` explains\n * the business reason it exists in the workflow.\n *\n * @example\n * ```typescript\n * await step('validateCart', () => validate(cart), {\n * description: 'Validates cart contents and pricing',\n * intent: 'Prevent charging customers for out-of-stock items',\n * });\n * ```\n */\n intent?: string;\n\n /**\n * Business domain this step belongs to.\n * Used by the static analyzer to group steps by bounded context.\n *\n * @example\n * ```typescript\n * await step('chargeCard', () => charge(card, amount), {\n * domain: 'payments',\n * });\n * ```\n */\n domain?: string;\n\n /**\n * Team, service, or bounded-context that owns this step.\n *\n * @example\n * ```typescript\n * await step('shipOrder', () => ship(order), {\n * owner: 'fulfillment-team',\n * });\n * ```\n */\n owner?: string;\n\n /**\n * Classification tags for this step.\n *\n * Recommended vocabulary:\n * `'side-effect'`, `'external-api'`, `'idempotent'`, `'read-only'`,\n * `'cacheable'`, `'pii'`, `'pci'`, `'compensatable'`\n *\n * @example\n * ```typescript\n * await step('chargeCard', () => charge(card, amount), {\n * tags: ['side-effect', 'external-api', 'pci'],\n * });\n * ```\n */\n tags?: readonly string[];\n\n // ==========================================================================\n // Agent Metadata — Effects & Dependencies\n // ==========================================================================\n\n /**\n * Human-oriented descriptions of state mutations this step performs.\n * These are free-text labels for documentation and visualization — they are\n * not machine-parsed at runtime.\n *\n * A future `stateEffects` field will provide structured effect declarations.\n *\n * @example\n * ```typescript\n * await step('placeOrder', () => place(cart), {\n * stateChanges: ['order.status → PLACED', 'inventory.reserved += qty'],\n * });\n * ```\n */\n stateChanges?: readonly string[];\n\n /**\n * Domain events this step produces.\n * Used by the static analyzer to build event flow graphs.\n *\n * @example\n * ```typescript\n * await step('placeOrder', () => place(cart), {\n * emits: ['OrderPlaced', 'InventoryReserved'],\n * });\n * ```\n */\n emits?: readonly string[];\n\n /**\n * External systems or services this step calls.\n * Used by the static analyzer to map external dependencies.\n *\n * @example\n * ```typescript\n * await step('chargeCard', () => charge(card, amount), {\n * calls: ['stripe-api', 'fraud-detection-service'],\n * });\n * ```\n */\n calls?: readonly string[];\n\n // ==========================================================================\n // Agent Metadata — Error Classification\n // ==========================================================================\n\n /**\n * Structured metadata for each error this step may produce.\n * Keys should match entries in the `errors` array.\n *\n * Note: `retryable` classifies the error's nature (whether it CAN be retried),\n * separate from whether this step actually retries it (that's `retry.retryOn`).\n * Both dimensions are useful — \"this error IS retryable\" vs \"this step DOES retry it\".\n * Defaults to `undefined` (unknown), not `true`.\n *\n * @example\n * ```typescript\n * await step('chargeCard', () => charge(card, amount), {\n * errors: ['CARD_DECLINED', 'GATEWAY_TIMEOUT'],\n * errorMeta: {\n * CARD_DECLINED: {\n * retryable: false,\n * severity: 'business',\n * description: 'Card was declined by issuer',\n * },\n * GATEWAY_TIMEOUT: {\n * retryable: true,\n * severity: 'infrastructure',\n * description: 'Payment gateway did not respond in time',\n * },\n * },\n * });\n * ```\n */\n errorMeta?: Record<string, ErrorClassification>;\n};\n\n/** Shared error classification — used in StepOptions.errorMeta, diagnostics, and wide events. */\nexport interface ErrorClassification {\n retryable?: boolean;\n severity?: 'business' | 'infrastructure' | 'validation';\n description?: string;\n}\n\n/** Runtime-visible business context from StepOptions. Does NOT include errorMeta. */\nexport interface StepMetadata {\n intent?: string;\n domain?: string;\n owner?: string;\n tags?: readonly string[];\n stateChanges?: readonly string[];\n emits?: readonly string[];\n calls?: readonly string[];\n}\n\n/** Runtime error diagnostics. classification is the matched ErrorClassification for this error. */\nexport interface StepErrorDiagnostics {\n tag: string;\n classification?: ErrorClassification;\n attempt?: number; // 1-based\n cumulativeDurationMs?: number; // execution only, excludes backoff\n origin: 'result' | 'throw' | 'timeout';\n}\n\n/** Extract canonical error tag. Priority: _tag > tag > code > Error.name > \"unknown\".\n * Tags are case-sensitive, whitespace-trimmed, otherwise raw.\n * Note: Error.name is fallback-grade (often too coarse like \"Error\", \"TypeError\"). */\nexport function extractErrorTag(error: unknown): string {\n if (error == null) return 'unknown';\n\n if (typeof error === 'string') return error.trim() || 'unknown';\n\n if (typeof error === 'object') {\n // Priority 1: _tag (TaggedError pattern)\n const tagged = error as Record<string, unknown>;\n if (typeof tagged._tag === 'string') {\n const trimmed = tagged._tag.trim();\n if (trimmed) return trimmed;\n }\n // Priority 2: tag\n if (typeof tagged.tag === 'string') {\n const trimmed = tagged.tag.trim();\n if (trimmed) return trimmed;\n }\n // Priority 3: code — string used directly, number stringified, anything else skipped\n if (typeof tagged.code === 'string') {\n const trimmed = tagged.code.trim();\n if (trimmed) return trimmed;\n } else if (typeof tagged.code === 'number') {\n return String(tagged.code);\n }\n // Priority 4: Error.name (fallback-grade)\n if (error instanceof Error && error.name) {\n const trimmed = error.name.trim();\n if (trimmed) return trimmed;\n }\n }\n\n return 'unknown';\n}\n\n/** Look up ErrorClassification from errorMeta for a given tag. */\nexport function lookupErrorClassification(\n tag: string,\n errorMeta?: Record<string, ErrorClassification>,\n): ErrorClassification | undefined {\n if (!errorMeta || !tag) return undefined;\n return errorMeta[tag];\n}\n\n/** Extract StepMetadata from StepOptions (returns undefined when empty). */\nexport function extractStepMetadata(options: StepOptions): StepMetadata | undefined {\n const { intent, domain, owner, tags, stateChanges, emits, calls } = options;\n if (!intent && !domain && !owner && !tags?.length && !stateChanges?.length && !emits?.length && !calls?.length) {\n return undefined;\n }\n const metadata: StepMetadata = {};\n if (intent) metadata.intent = intent;\n if (domain) metadata.domain = domain;\n if (owner) metadata.owner = owner;\n if (tags?.length) metadata.tags = tags;\n if (stateChanges?.length) metadata.stateChanges = stateChanges;\n if (emits?.length) metadata.emits = emits;\n if (calls?.length) metadata.calls = calls;\n return metadata;\n}\n\n/** Build StepErrorDiagnostics from error + errorMeta. */\nfunction buildStepErrorPayload(\n error: unknown,\n errorMeta: StepOptions['errorMeta'],\n origin: StepErrorDiagnostics['origin'],\n attempt?: number,\n cumulativeDurationMs?: number,\n): StepErrorDiagnostics {\n const tag = extractErrorTag(error);\n const classification = lookupErrorClassification(tag, errorMeta);\n const diagnostics: StepErrorDiagnostics = { tag, origin };\n if (classification !== undefined) diagnostics.classification = classification;\n if (attempt !== undefined) diagnostics.attempt = attempt;\n if (cumulativeDurationMs !== undefined) diagnostics.cumulativeDurationMs = cumulativeDurationMs;\n return diagnostics;\n}\n\n// =============================================================================\n// Retry and Timeout Types\n// =============================================================================\n\n/**\n * Backoff strategy for retry operations.\n */\nexport type BackoffStrategy = \"fixed\" | \"linear\" | \"exponential\";\n\n/**\n * Configuration for step retry behavior.\n */\nexport type RetryOptions = {\n /**\n * Total number of attempts (1 = no retry, 3 = initial + 2 retries).\n * Must be >= 1.\n */\n attempts: number;\n\n /**\n * Backoff strategy between retries.\n * - 'fixed': Same delay each time (initialDelay)\n * - 'linear': Delay increases linearly (initialDelay * attempt)\n * - 'exponential': Delay doubles each time (initialDelay * 2^(attempt-1))\n * @default 'exponential'\n */\n backoff?: BackoffStrategy;\n\n /**\n * Initial delay in milliseconds before first retry.\n * @default 100\n */\n initialDelay?: number;\n\n /**\n * Maximum delay cap in milliseconds.\n * Prevents exponential backoff from growing too large.\n * @default 30000 (30 seconds)\n */\n maxDelay?: number;\n\n /**\n * Whether to add random jitter (0-25% of delay).\n * Helps prevent thundering herd when multiple workflows retry simultaneously.\n * @default true\n */\n jitter?: boolean;\n\n /**\n * Predicate to determine if a retry should occur.\n * Receives the error and current attempt number (1-indexed).\n * Return true to retry, false to fail immediately.\n * @default Always retry on any error\n */\n retryOn?: (error: unknown, attempt: number) => boolean;\n\n /**\n * Callback invoked before each retry attempt.\n * Useful for logging, metrics, or side effects.\n */\n onRetry?: (error: unknown, attempt: number, delayMs: number) => void;\n};\n\n/**\n * Timeout behavior when the timeout is reached.\n *\n * - 'error' (default): Return an error result with StepTimeoutError\n * - 'option': Return Ok(undefined) instead of an error (useful for optional operations)\n * - 'disconnect': Let the operation complete in background, return timeout error immediately\n * - function: Custom handler to generate the timeout error\n */\nexport type TimeoutBehavior =\n | \"error\"\n | \"option\"\n | \"disconnect\"\n | ((stepInfo: { name?: string; key?: string; ms: number }) => unknown);\n\n/**\n * Configuration for step timeout behavior.\n */\nexport type TimeoutOptions = {\n /**\n * Timeout duration in milliseconds per attempt.\n * When combined with retry, each attempt gets its own timeout.\n */\n ms: number;\n\n /**\n * Custom error to use when timeout occurs.\n * @default StepTimeoutError with step details\n */\n error?: unknown;\n\n /**\n * Whether to pass an AbortSignal to the operation.\n * When true, the operation function receives (signal: AbortSignal) as argument.\n * Useful for fetch() and other APIs that support cancellation.\n * @default false\n */\n signal?: boolean;\n\n /**\n * Behavior when timeout is reached.\n *\n * - 'error' (default): Return StepTimeoutError (or custom error if provided)\n * - 'option': Return Ok(undefined) instead of error (operation treated as optional)\n * - 'disconnect': Let operation complete in background, return error immediately\n * - function: Custom handler `(stepInfo) => customError`\n *\n * @default 'error'\n *\n * @example\n * ```typescript\n * // Default: Return timeout error\n * step.withTimeout(() => slowOp(), { ms: 5000 });\n *\n * // Optional: Return undefined if times out\n * step.withTimeout(() => optionalOp(), { ms: 5000, onTimeout: 'option' });\n *\n * // Disconnect: Don't wait for slow operation\n * step.withTimeout(() => fireAndForget(), { ms: 5000, onTimeout: 'disconnect' });\n *\n * // Custom error\n * step.withTimeout(() => apiCall(), {\n * ms: 5000,\n * onTimeout: ({ name, ms }) => ({ type: 'API_TIMEOUT', name, ms })\n * });\n * ```\n */\n onTimeout?: TimeoutBehavior;\n};\n\n/**\n * Standard timeout error type.\n */\nexport type StepTimeoutError = {\n type: \"STEP_TIMEOUT\";\n stepName?: string;\n stepKey?: string;\n timeoutMs: number;\n attempt?: number;\n};\n\n/**\n * Symbol used to mark any error (including custom errors) as a timeout error.\n * This allows detection of timeout errors even when users provide custom error payloads.\n */\nexport const STEP_TIMEOUT_MARKER: unique symbol = Symbol.for(\"step_timeout_marker\");\n\n/**\n * Metadata attached to timeout-marked errors.\n */\nexport type StepTimeoutMarkerMeta = {\n timeoutMs: number;\n stepName?: string;\n stepKey?: string;\n attempt?: number;\n};\n\n/**\n * Type guard to check if an error is a StepTimeoutError.\n * This checks both the standard type field AND the timeout marker symbol,\n * so custom errors provided via timeout.error are also detected.\n */\nexport function isStepTimeoutError(e: unknown): e is StepTimeoutError {\n if (typeof e !== \"object\" || e === null) {\n return false;\n }\n // Check for standard type field\n if ((e as StepTimeoutError).type === \"STEP_TIMEOUT\") {\n return true;\n }\n // Check for timeout marker (custom errors)\n return STEP_TIMEOUT_MARKER in e;\n}\n\n/**\n * Get timeout metadata from a timeout error (works with both standard and custom errors).\n * Returns undefined if the error is not a timeout error.\n */\nexport function getStepTimeoutMeta(e: unknown): StepTimeoutMarkerMeta | undefined {\n if (typeof e !== \"object\" || e === null) {\n return undefined;\n }\n // Check for standard type field first\n if ((e as StepTimeoutError).type === \"STEP_TIMEOUT\") {\n const err = e as StepTimeoutError;\n return {\n timeoutMs: err.timeoutMs,\n stepName: err.stepName,\n stepKey: err.stepKey,\n attempt: err.attempt,\n };\n }\n // Check for timeout marker (custom errors)\n if (STEP_TIMEOUT_MARKER in e) {\n return (e as Record<symbol, StepTimeoutMarkerMeta>)[STEP_TIMEOUT_MARKER];\n }\n return undefined;\n}\n\n// =============================================================================\n// RunStep Interface\n// =============================================================================\n\n/**\n * The `step` object passed to the function in `run(async ({ step }) => { ... })`.\n * acts as the bridge between your business logic and the workflow engine.\n *\n * It provides methods to:\n * 1. Execute operations that return `Result` types.\n * 2. safely wrap operations that might throw exceptions (using `step.try`).\n * 3. Assign names and keys to operations for tracing and caching.\n *\n * @template E - The union of all known error types expected in this workflow.\n */\nexport interface RunStep<E = unknown> {\n /**\n * Execute a Result-returning operation with explicit step ID.\n *\n * The ID is used for:\n * - Static analysis visualization\n * - Error flow tracking\n * - Step identification in diagrams\n * - Caching and resume (ID is used as the cache key)\n *\n * @param id - Unique step identifier (string literal for static analysis)\n * @param operation - A function that returns a Result or AsyncResult\n * @param options - Step options\n * @returns The success value (unwrapped)\n * @throws {EarlyExit} If the result is an error (stops execution safely)\n *\n * @example\n * ```typescript\n * const cart = await step('getCart', () => getCart(ctx.input.cartId), {\n * errors: ['CART_NOT_FOUND', 'CART_EMPTY'],\n * out: 'cart',\n * });\n * ```\n */\n <T, StepE extends E, StepC = unknown>(\n id: string,\n operation: () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n options?: StepOptions\n ): Promise<T>;\n\n /**\n * Execute a standard throwing operation safely.\n * Catches exceptions and maps them to a typed error, or wraps them if no mapper is provided.\n *\n * Use this when integrating with libraries that throw exceptions.\n *\n * @param id - Unique identifier for this step (required for analysis and caching)\n * @param operation - A function that returns a value or Promise (may throw)\n * @param options - Configuration including error mapping\n * @returns The success value\n * @throws {EarlyExit} If the operation throws (stops execution safely)\n *\n * @example\n * ```typescript\n * const data = await step.try(\n * \"db-query\",\n * () => db.query(),\n * { onError: (e) => ({ type: \"DB_ERROR\", cause: e }) }\n * );\n * ```\n */\n try: <T, const Err extends E>(\n id: string,\n operation: () => T | Promise<T>,\n options:\n | { error: Err; key?: string; ttl?: number }\n | { onError: (cause: unknown) => Err; key?: string; ttl?: number }\n ) => Promise<T>;\n\n /**\n * Execute a Result-returning function and map its error to a typed error.\n *\n * Use this when calling functions that return Result<T, E> and you want to\n * map their typed errors to your workflow's error type. Unlike step.try(),\n * the error passed to onError is typed (not unknown).\n *\n * @param id - Unique identifier for this step (required for analysis and caching)\n * @param operation - A function that returns a Result or AsyncResult\n * @param options - Configuration including error mapping\n * @returns The success value (unwrapped)\n * @throws {EarlyExit} If the result is an error (stops execution safely)\n *\n * @example\n * ```typescript\n * const response = await step.fromResult(\n * \"call-provider\",\n * () => callProvider(input),\n * {\n * onError: (providerError) => ({\n * type: \"PROVIDER_FAILED\",\n * provider: providerError.provider,\n * cause: providerError\n * })\n * }\n * );\n * ```\n */\n fromResult: <T, ResultE, const Err extends E>(\n id: string,\n operation: () => Result<T, ResultE, unknown> | AsyncResult<T, ResultE, unknown>,\n options:\n | { error: Err; key?: string; ttl?: number }\n | { onError: (resultError: ResultE) => Err; key?: string; ttl?: number }\n ) => Promise<T>;\n\n /**\n * Execute an operation that may return null/undefined and convert to a typed error.\n *\n * Shorthand for wrapping `fromNullable()` in a step — avoids boilerplate when\n * looking up optional values (database finds, map lookups, etc.).\n *\n * @param id - Unique step identifier\n * @param operation - A function that returns `T | null | undefined` (or a Promise thereof)\n * @param onNull - Returns the typed error when operation returns null/undefined\n *\n * @example\n * ```typescript\n * const user = await step.fromNullable(\n * 'getUser',\n * () => db.users.findById(id),\n * () => ({ type: 'NOT_FOUND' as const, id })\n * );\n * ```\n */\n fromNullable: <T, const Err extends E>(\n id: string,\n operation: () => T | null | undefined | Promise<T | null | undefined>,\n onNull: () => Err,\n options?: { key?: string; ttl?: number }\n ) => Promise<T>;\n\n /**\n * Execute parallel operations with scope events for visualization.\n *\n * This wraps the operations with scope_start and scope_end events, enabling\n * visualization of parallel execution branches.\n *\n * @overload Object form - step.parallel(name, { key: () => ... })\n * @overload Array form - step.parallel(name, () => allAsync([...]))\n *\n * @example Object form\n * ```typescript\n * const { user, posts } = await step.parallel('Fetch user data', {\n * user: () => fetchUser(id),\n * posts: () => fetchPosts(id),\n * });\n * ```\n *\n * @example Canonical form (strict mode)\n * ```typescript\n * const { user, posts } = await step.parallel('Fetch user data', {\n * user: { fn: () => fetchUser(id), errors: ['NOT_FOUND'] },\n * posts: { fn: () => fetchPosts(id), errors: ['FETCH_ERROR'] },\n * });\n * ```\n *\n * @example Array form\n * ```typescript\n * const [user, posts] = await step.parallel('Fetch all data', () =>\n * allAsync([fetchUser(id), fetchPosts(id)])\n * );\n * ```\n */\n parallel: {\n // Object form: step.parallel(name, { key: () => ... })\n <\n TOperations extends Record<\n string,\n () => MaybeAsyncResult<unknown, E, unknown>\n >\n >(\n name: string,\n operations: TOperations\n ): Promise<{\n [K in keyof TOperations]: TOperations[K] extends () => MaybeAsyncResult<\n infer V,\n E,\n unknown\n >\n ? V\n : never;\n }>;\n\n // Object form canonical: step.parallel(name, { key: { fn, errors } })\n <\n TOperations extends Record<\n string,\n ParallelOperationDescriptor<unknown, readonly string[]>\n >\n >(\n name: string,\n operations: TOperations\n ): Promise<{\n [K in keyof TOperations]: TOperations[K] extends ParallelOperationDescriptor<\n infer V,\n readonly string[]\n >\n ? V\n : never;\n }>;\n\n // Array form: step.parallel(name, () => allAsync([...]))\n <T, StepE extends E, StepC = unknown>(\n name: string,\n operation: () => Result<T[], StepE, StepC> | AsyncResult<T[], StepE, StepC>\n ): Promise<T[]>;\n };\n\n /**\n * Execute a race operation (anyAsync) with scope events for visualization.\n *\n * This wraps the operation with scope_start and scope_end events, enabling\n * visualization of racing execution branches.\n *\n * @param name - Name for this race block (used in visualization)\n * @param operation - A function that returns a Result from anyAsync\n * @returns The success value (first to succeed)\n *\n * @example\n * ```typescript\n * const data = await step.race('Fastest API', () =>\n * anyAsync([fetchFromPrimary(id), fetchFromFallback(id)])\n * );\n * ```\n */\n race: <T, StepE extends E, StepC = unknown>(\n name: string,\n operation: () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>\n ) => Promise<T>;\n\n /**\n * Execute an allSettled operation with scope events for visualization.\n *\n * This wraps the operation with scope_start and scope_end events, enabling\n * visualization of allSettled execution branches. Unlike step.parallel,\n * allSettled collects all results even if some fail.\n *\n * @param name - Name for this allSettled block (used in visualization)\n * @param operation - A function that returns a Result from allSettledAsync\n * @returns The success value (unwrapped array)\n *\n * @example\n * ```typescript\n * const [user, posts] = await step.allSettled('Fetch all data', () =>\n * allSettledAsync([fetchUser(id), fetchPosts(id)])\n * );\n * ```\n */\n allSettled: <T, StepE extends E, StepC = unknown>(\n name: string,\n operation: () => Result<T[], StepE, StepC> | AsyncResult<T[], StepE, StepC>\n ) => Promise<T[]>;\n\n /**\n * Execute a primary operation with a fallback if the primary fails.\n *\n * If the primary operation returns an error, the fallback is executed instead.\n * When `on` is specified, the fallback only runs for that specific error;\n * other errors propagate without invoking the fallback.\n *\n * Returns `Promise<T>` — errors escape via earlyExit into the workflow's error channel.\n * The error union `E1 | E2` is the generic constraint propagated to the workflow.\n *\n * @overload Fallback on ANY error from primary\n * @overload Fallback on SPECIFIC error literal only (via `on`)\n *\n * @param id - Unique step identifier (single step ID for events)\n * @param operation - Primary operation that returns AsyncResult\n * @param options - Fallback configuration\n * @returns The success value from primary or fallback\n *\n * @example\n * ```typescript\n * const user = await step.withFallback(\n * 'getUser',\n * () => fetchFromPrimary(id),\n * { fallback: () => fetchFromCache(id) }\n * );\n *\n * // With specific error filter\n * const data = await step.withFallback(\n * 'getData',\n * () => fetchFromApi(id),\n * { on: 'NOT_FOUND', fallback: () => getDefault(id) }\n * );\n * ```\n */\n withFallback: {\n // Overload 1: fallback on ANY error from primary\n <T, E1 extends E, E2 extends E>(\n id: string,\n operation: () => AsyncResult<T, E1>,\n options: { fallback: () => AsyncResult<T, E2>; key?: string }\n ): Promise<T>;\n\n // Overload 2: fallback on SPECIFIC error literal only\n <T, E1 extends E & string, E2 extends E>(\n id: string,\n operation: () => AsyncResult<T, E1>,\n options: { on: E1; fallback: () => AsyncResult<T, E2>; key?: string }\n ): Promise<T>;\n };\n\n /**\n * Execute an operation with automatic resource lifecycle management.\n *\n * Acquires a resource, uses it, and guarantees release regardless of outcome.\n * Release always runs after use completes (even on error or throw).\n * Release errors are logged via console.warn but never override the use result.\n *\n * No caching support — caching resource-using steps is dangerous.\n *\n * @param id - Unique step identifier\n * @param options - Resource lifecycle configuration\n * @returns The success value from the use function\n *\n * @example\n * ```typescript\n * const data = await step.withResource('useDb', {\n * acquire: () => connectToDb(),\n * use: (db) => db.query('SELECT * FROM users'),\n * release: (db) => db.close(),\n * });\n * ```\n */\n withResource: <T, R, AcquireE extends E, UseE extends E>(\n id: string,\n options: {\n acquire: () => AsyncResult<R, AcquireE>;\n use: (resource: R) => AsyncResult<T, UseE>;\n release: (resource: R) => void | Promise<void>;\n }\n ) => Promise<T>;\n\n /**\n * Execute an operation with retry and optional timeout.\n *\n * Use this for operations that may fail transiently (network issues, rate limits)\n * and benefit from automatic retry with backoff.\n *\n * @param id - Unique identifier for this step (required for analysis and caching)\n * @param operation - A function that returns a Result or AsyncResult\n * @param options - Retry configuration and optional timeout\n * @returns The success value (unwrapped)\n * @throws {EarlyExit} If all retries are exhausted (stops execution safely)\n *\n * @example\n * ```typescript\n * const data = await step.retry(\n * \"fetch-external\",\n * () => fetchFromExternalApi(id),\n * {\n * attempts: 3,\n * backoff: 'exponential',\n * initialDelay: 200,\n * retryOn: (error) => error === 'RATE_LIMITED' || error === 'TRANSIENT',\n * onRetry: (error, attempt, delay) => {\n * console.log(`Retry ${attempt} after ${delay}ms`);\n * },\n * }\n * );\n * ```\n */\n retry: <T, StepE extends E, StepC = unknown>(\n id: string,\n operation: () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n options: RetryOptions & { key?: string; timeout?: TimeoutOptions }\n ) => Promise<T>;\n\n /**\n * Execute an operation with a timeout.\n *\n * Use this for operations that may hang indefinitely (external APIs, connections)\n * and need to be aborted after a certain duration.\n *\n * When `signal: true` is set, an AbortSignal is passed to your operation,\n * which you can use with APIs like fetch() for proper cancellation.\n *\n * @param id - Unique identifier for this step (required for analysis and caching)\n * @param operation - A function that returns a Result (may receive AbortSignal)\n * @param options - Timeout configuration\n * @returns The success value (unwrapped)\n * @throws {EarlyExit} If the operation times out (stops execution safely)\n *\n * @example\n * ```typescript\n * // Without AbortSignal\n * const data = await step.withTimeout(\n * \"fetch-data\",\n * () => fetchData(id),\n * { ms: 5000 }\n * );\n *\n * // With AbortSignal for fetch()\n * const data = await step.withTimeout(\n * \"fetch-url\",\n * (signal) => fetch(url, { signal }).then(r => ok(r.json())),\n * { ms: 5000, signal: true }\n * );\n * ```\n */\n withTimeout: <T, StepE extends E, StepC = unknown>(\n id: string,\n operation:\n | (() => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>)\n | ((signal: AbortSignal) => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>),\n options: TimeoutOptions & { key?: string }\n ) => Promise<T>;\n\n /**\n * Pause execution for a specified duration.\n *\n * Use this for intentional delays between operations (rate limiting,\n * polling intervals, debouncing). Respects workflow cancellation.\n *\n * @param id - Unique identifier for this step (required for analysis and caching)\n * @param duration - Duration as string (\"5s\", \"100ms\") or Duration object\n * @param options - Optional key for per-iteration identity, ttl, description\n * @returns Promise that resolves after the duration\n * @throws {AbortError} If the workflow is cancelled during sleep\n *\n * @example\n * ```typescript\n * // String duration\n * await step.sleep(\"rate-limit-delay\", \"5s\");\n *\n * // Duration object\n * await step.sleep(\"my-sleep\", seconds(5));\n * ```\n */\n sleep(\n id: string,\n duration: DurationInput,\n options?: { key?: string; ttl?: number; description?: string; signal?: AbortSignal }\n ): Promise<void>;\n\n // ===========================================================================\n // Streaming Methods\n // ===========================================================================\n\n /**\n * Get a writable stream for this workflow.\n *\n * Use this to write values that can be consumed by readers\n * (e.g., HTTP response streaming, AI token streaming).\n *\n * @param options - Stream options (namespace, highWaterMark)\n * @returns StreamWriter for writing values\n *\n * @example\n * ```typescript\n * const writer = step.getWritable<string>({ namespace: 'ai-response' });\n *\n * await step(() => generateAI({\n * prompt: 'Hello',\n * onToken: async (token) => { await writer.write(token); }\n * }), { key: 'generate' });\n *\n * await writer.close();\n * ```\n */\n getWritable: <T>(options?: StreamWritableOptions) => StreamWriterInterface<T>;\n\n /**\n * Get a readable stream for this workflow.\n *\n * Use this to consume values from a stream, with support for\n * resuming from a specific position.\n *\n * @param options - Read options (namespace, startIndex)\n * @returns StreamReader for reading values\n *\n * @example\n * ```typescript\n * const reader = step.getReadable<string>({ namespace: 'ai-response' });\n *\n * let result = await reader.read();\n * while (result.ok) {\n * response.write(result.value);\n * result = await reader.read();\n * }\n * ```\n */\n getReadable: <T>(options?: StreamReadableOptions) => StreamReaderInterface<T>;\n\n /**\n * Process stream items with checkpointing.\n *\n * Combines streaming with batch processing - each item is processed\n * and checkpointed, enabling resume from the last successful item.\n *\n * @param source - StreamReader or AsyncIterable to process\n * @param processor - Function to process each item\n * @param options - Processing options\n * @returns Results from all processed items\n *\n * @example\n * ```typescript\n * const reader = step.getReadable<Message>({ namespace: 'messages' });\n *\n * const result = await step.streamForEach(\n * reader,\n * async (message, index) => {\n * const processed = await processMessage(message);\n * return ok(processed);\n * },\n * { name: 'process-messages', checkpointInterval: 10 }\n * );\n *\n * console.log(`Processed ${result.value.processedCount} messages`);\n * ```\n */\n streamForEach: <T, R, StepE extends E>(\n source: StreamReaderInterface<T> | AsyncIterable<T>,\n processor: (item: T, index: number) => AsyncResult<R, StepE>,\n options?: StreamForEachStepOptions\n ) => Promise<StreamForEachResultType<R>>;\n\n // ===========================================================================\n // Static Analysis Methods\n // ===========================================================================\n\n /**\n * Mark a conditional for static analysis with a stable ID and condition label.\n * Runtime: returns the boolean result of condition().\n * Analysis: emits a DecisionNode with stable id and conditionLabel, and attaches\n * the then/else subgraphs from the if/else branches.\n *\n * @param id - Stable identifier for this decision point (string literal for static analysis)\n * @param conditionLabel - Human-readable label describing the condition\n * @param condition - Function that returns the boolean condition\n * @returns The result of the condition function\n *\n * @example\n * ```typescript\n * if (step.if('payment', 'cart.total > 0', () => ctx.ref('cart').total > 0)) {\n * await step('chargeCard', () => deps.chargeCard(ctx.ref('cart').total), {\n * errors: ['CARD_DECLINED'],\n * });\n * } else {\n * await step('skipPayment', async () => ({ skipped: true }), {\n * errors: [],\n * });\n * }\n * ```\n */\n if: <T extends boolean>(\n id: string,\n conditionLabel: string,\n condition: () => T\n ) => T;\n\n /**\n * Alias for `step.if()`. Mark a conditional for static analysis with a stable ID.\n * Use this to label conditionals in strict mode when they contain step calls.\n *\n * @param id - Stable identifier for this decision point\n * @param conditionLabel - Human-readable label describing the condition\n * @param condition - Function that returns the boolean condition\n * @returns The result of the condition function\n *\n * @example\n * ```typescript\n * if (step.label('email-type', 'user.isPremium', () => user.isPremium)) {\n * await step('premium', () => sendPriorityEmail(user), { errors: ['EMAIL_FAILED'] });\n * } else {\n * await step('free', () => sendRegularEmail(user), { errors: ['EMAIL_FAILED'] });\n * }\n * ```\n */\n label: <T extends boolean>(\n id: string,\n conditionLabel: string,\n condition: () => T\n ) => T;\n\n /**\n * Execute a branch with explicit metadata for static analysis.\n * Use when you want richer analyzer metadata (conditionLabel, per-arm errors).\n * For most cases, use natural if/else with step.label() instead.\n *\n * @param id - Stable identifier for this branch point\n * @param options - Branch configuration with condition, then/else arms, and errors\n * @returns The result from the executed arm\n *\n * @example\n * ```typescript\n * const charge = await step.branch('payment', {\n * conditionLabel: 'cart.total > 0',\n * condition: () => ctx.ref('cart').total > 0,\n * out: 'charge',\n * then: () => chargeCard(ctx.ref('cart').total),\n * thenErrors: ['CARD_DECLINED'],\n * else: () => ok({ skipped: true }),\n * elseErrors: [],\n * });\n * ```\n */\n branch: <\n T,\n const ThenErrs extends readonly string[] = readonly [],\n const ElseErrs extends readonly string[] = readonly [],\n const Out extends string | undefined = undefined,\n >(\n id: string,\n options: BranchOptions<T, ThenErrs, ElseErrs, Out>\n ) => Promise<T>;\n\n /**\n * Create an arm definition for use with step.branch().\n * Runtime: returns the arm definition unchanged.\n * Analyzer: extracts arm metadata for visualization.\n *\n * @param fn - The arm function\n * @param errors - Declared errors for this arm\n * @returns The arm definition\n *\n * @example\n * ```typescript\n * const thenArm = step.arm(() => chargeCard(total), ['CARD_DECLINED']);\n * const elseArm = step.arm(() => ok({ skipped: true }), []);\n * ```\n */\n arm: <T, const Errs extends readonly string[] = readonly []>(\n fn: () => T | Promise<T>,\n errors?: Errs\n ) => ArmDefinition<T, Errs>;\n\n /**\n * Execute a forEach loop with static analysis support.\n * Supports both simple (run) and complex (item) forms.\n *\n * @param id - Stable identifier for this loop\n * @param items - Iterable to loop over\n * @param options - Loop configuration\n * @returns Array of results from each iteration\n *\n * @example Simple form:\n * ```typescript\n * await step.forEach('process-items', items, {\n * maxIterations: 100,\n * stepIdPattern: 'process-{i}',\n * errors: ['PROCESS_ERROR'],\n * run: (item) => processItem(item),\n * });\n * ```\n *\n * @example Complex form with multiple steps:\n * ```typescript\n * await step.forEach('process-items', items, {\n * maxIterations: 100,\n * item: step.item((item, i, innerStep) => {\n * await innerStep('validate', () => validate(item), { errors: ['INVALID'] });\n * await innerStep('process', () => process(item), { errors: ['FAILED'] });\n * }),\n * });\n * ```\n */\n forEach: {\n // Simple form with run callback\n <T, R, const Errs extends readonly string[] = readonly []>(\n id: string,\n items: Iterable<T> | AsyncIterable<T>,\n options: ForEachRunOptions<T, R, Errs>\n ): Promise<R[]>;\n\n // Complex form with item callback\n <T, R>(\n id: string,\n items: Iterable<T> | AsyncIterable<T>,\n options: ForEachItemOptions<T, R>\n ): Promise<R[]>;\n };\n\n /**\n * Create an item handler for use with step.forEach().\n * Runtime: returns the handler unchanged.\n * Analyzer: extracts the inner step structure.\n *\n * @param handler - Function to process each item\n * @returns The item handler\n *\n * @example\n * ```typescript\n * step.item((item, index, innerStep) => {\n * await innerStep('validate', () => validate(item));\n * await innerStep('process', () => process(item));\n * });\n * ```\n */\n item: <T, R>(\n handler: (item: T, index: number, step: RunStep<E>) => R | Promise<R>\n ) => ForEachItemHandler<T, R>;\n\n /**\n * Wrap a dependency function for static analysis tracking.\n * Returns the function unchanged but marks it for the analyzer.\n *\n * @param name - Name of the dependency (for analyzer tracking)\n * @param fn - The dependency function to wrap\n * @returns The same function, unchanged\n *\n * @example\n * ```typescript\n * await step('getCart', step.dep('getCart', () => deps.getCart(ctx.input.cartId)), {\n * errors: ['CART_NOT_FOUND'],\n * out: 'cart',\n * });\n * ```\n */\n dep: <T extends (...args: unknown[]) => unknown>(name: string, fn: T) => T;\n\n // ===========================================================================\n // Effect-Style Ergonomics\n // ===========================================================================\n\n /**\n * Unwrap an AsyncResult directly within a workflow step.\n *\n * Use this when you already have an AsyncResult and want to unwrap it\n * without wrapping it in a function. Automatically exits on error.\n *\n * @param id - Unique step identifier\n * @param result - The AsyncResult to unwrap\n * @param options - Step options\n * @returns The success value (unwrapped)\n * @throws {EarlyExit} If the result is an error\n *\n * @example\n * ```typescript\n * const userResult = fetchUser(userId); // AsyncResult<User, 'NOT_FOUND'>\n * const user = await step.run('fetchUser', userResult);\n * // Automatically unwraps and exits on error\n * ```\n */\n run: <T, StepE extends E, StepC = unknown>(\n id: string,\n result: AsyncResult<T, StepE, StepC>,\n options?: StepOptions\n ) => Promise<T>;\n\n /**\n * Run a sub-workflow (or any AsyncResult-returning operation) as a step.\n * Use for workflow composition; the getter's error type (SubE) flows into the parent's error union.\n *\n * @param id - Unique step identifier\n * @param getter - Function that returns AsyncResult (e.g. () => subWorkflow.run(fn))\n * @param options - Step options (key, ttl, etc.)\n * @returns The success value (unwrapped)\n * @throws {EarlyExit} If the result is an error\n *\n * @example\n * ```typescript\n * const authResult = await step.workflow(\"authorize\", () => authorizeWorkflow.run(fn));\n * ```\n */\n workflow: <T, SubE extends E, StepC = unknown>(\n id: string,\n getter: () => AsyncResult<T, SubE, StepC>,\n options?: StepOptions\n ) => Promise<T>;\n\n /**\n * Chain AsyncResult operations with step tracking.\n *\n * Use this for composing AsyncResult operations where each step\n * depends on the previous one's success value.\n *\n * @param id - Unique step identifier\n * @param value - The value to pass to the function\n * @param fn - Function that takes the value and returns an AsyncResult\n * @param options - Step options\n * @returns The final success value (unwrapped)\n * @throws {EarlyExit} If the result is an error\n *\n * @example\n * ```typescript\n * const user = await step.run('fetchUser', fetchUser(id));\n * const enriched = await step.andThen('enrich', user, (user) =>\n * enrichUser(user) // Returns AsyncResult<EnrichedUser, E>\n * );\n * ```\n */\n andThen: <T, U, StepE extends E, StepC = unknown>(\n id: string,\n value: T,\n fn: (value: T) => AsyncResult<U, StepE, StepC>,\n options?: StepOptions\n ) => Promise<U>;\n\n /**\n * Pattern match on a Result with step tracking for both branches.\n *\n * Use this for handling Result values where both success and error\n * paths need to be tracked as separate steps.\n *\n * @param id - Unique step identifier\n * @param result - The Result to match on\n * @param handlers - Object with ok and err handler functions\n * @param options - Step options\n * @returns The value returned by the matched handler\n *\n * @example\n * ```typescript\n * const user = await step.run('fetchUser', fetchUser(id));\n *\n * const message = await step.match('handleUser', user, {\n * ok: async (user) => {\n * await step('sendWelcome', () => sendEmail(user.email));\n * return 'Sent welcome email';\n * },\n * err: async (error) => {\n * await step('logError', () => logError(error));\n * return 'Failed to fetch user';\n * }\n * });\n * ```\n */\n match: <T, StepE extends E, U, StepC = unknown>(\n id: string,\n result: Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n handlers: {\n ok: (value: T) => U | Promise<U>;\n err: (error: StepE, cause?: StepC) => U | Promise<U>;\n },\n options?: StepOptions\n ) => Promise<U>;\n\n /**\n * Alias for step.parallel - Effect.all-style API for parallel execution.\n *\n * Executes multiple operations in parallel and returns named results.\n * Identical to step.parallel but with a name more familiar to Effect users.\n *\n * @param name - Name for this parallel block\n * @param operations - Object mapping keys to operations\n * @returns Object with results mapped to the same keys\n *\n * @example\n * ```typescript\n * const { user, posts, comments } = await step.all('fetchAll', {\n * user: () => fetchUser('1'),\n * posts: () => fetchPosts('1'),\n * comments: () => fetchComments('1')\n * });\n * ```\n */\n all: RunStep<E>[\"parallel\"];\n\n /**\n * Map over an array with parallel execution and error tracking.\n *\n * Similar to Effect.forEach - executes mapper function for each item\n * in parallel and collects results.\n *\n * @param id - Unique step identifier\n * @param items - Array of items to process\n * @param mapper - Function to process each item (returns AsyncResult)\n * @param options - Optional concurrency limit and cache key\n * @returns Array of results in original order\n *\n * @example\n * ```typescript\n * const users = await step.map('fetchUsers', userIds, (id) =>\n * fetchUser(id)\n * );\n * // Automatic parallel execution with error union\n * ```\n */\n map: <T, U, StepE extends E, StepC = unknown>(\n id: string,\n items: T[],\n mapper: (item: T, index: number) => AsyncResult<U, StepE, StepC>,\n options?: { concurrency?: number; key?: string }\n ) => Promise<U[]>;\n\n}\n\n// =============================================================================\n// Parallel Types\n// =============================================================================\n\n/**\n * Operation descriptor for canonical parallel form.\n * Use this for analyzable parallel operations with explicit error declarations.\n */\nexport type ParallelOperationDescriptor<\n T,\n Errs extends readonly string[] = readonly [],\n> = {\n /** The operation function */\n fn: () => MaybeAsyncResult<T, unknown, unknown>;\n /** Declared errors for this operation (for static analysis) */\n errors?: Errs;\n};\n\n// =============================================================================\n// Branch and ForEach Types\n// =============================================================================\n\n/**\n * Options for step.branch().\n */\nexport type BranchOptions<\n T,\n ThenErrs extends readonly string[] = readonly [],\n ElseErrs extends readonly string[] = readonly [],\n Out extends string | undefined = undefined,\n> = {\n /** Human-readable label describing the condition */\n conditionLabel: string;\n /** Function that evaluates the condition */\n condition: () => boolean;\n /** Output key for data flow (writes result to ctx[out]) */\n out?: Out;\n /** Function to execute when condition is true */\n then: () => T | Promise<T>;\n /** Declared errors for the then arm */\n thenErrors?: ThenErrs;\n /** Function to execute when condition is false */\n else?: () => T | Promise<T>;\n /** Declared errors for the else arm */\n elseErrors?: ElseErrs;\n};\n\n/**\n * Arm definition for step.branch().\n */\nexport type ArmDefinition<T, Errs extends readonly string[] = readonly []> = {\n fn: () => T | Promise<T>;\n errors?: Errs;\n};\n\n/**\n * Options for step.forEach() with simple run form.\n */\nexport type ForEachRunOptions<T, R, Errs extends readonly string[] = readonly []> = {\n /** Maximum iterations (for bounded analysis) */\n maxIterations?: number;\n /** Step ID pattern for iterations (e.g., 'process-{i}') */\n stepIdPattern?: string;\n /** Declared errors for the loop body */\n errors?: Errs;\n /** Output key for results (requires collect option in strict mode) */\n out?: string;\n /** How to collect results when out is specified */\n collect?: \"array\" | \"last\";\n /** Simple callback for each item */\n run: (item: T, index: number) => R | Promise<R>;\n};\n\n/**\n * Options for step.forEach() with complex item form.\n */\nexport type ForEachItemOptions<T, R> = {\n /** Maximum iterations (for bounded analysis) */\n maxIterations?: number;\n /** Step ID pattern for iterations (e.g., 'process-{i}') */\n stepIdPattern?: string;\n /** Output key for results (requires collect option in strict mode) */\n out?: string;\n /** How to collect results when out is specified */\n collect?: \"array\" | \"last\";\n /** Complex item handler with inner step access */\n item: ForEachItemHandler<T, R>;\n};\n\n/**\n * Item handler for step.forEach() with inner step access.\n */\nexport type ForEachItemHandler<T, R> = {\n __forEachItemHandler: true;\n handler: (item: T, index: number, step: RunStep<unknown>) => R | Promise<R>;\n};\n\n// =============================================================================\n// Streaming Types (minimal interfaces for RunStep)\n// =============================================================================\n\n/**\n * Options for getWritable.\n */\nexport interface StreamWritableOptions {\n /** Named streams (default: 'default') */\n namespace?: string;\n /** Backpressure threshold (default: 16) */\n highWaterMark?: number;\n}\n\n/**\n * Options for getReadable.\n */\nexport interface StreamReadableOptions {\n /** Named streams (default: 'default') */\n namespace?: string;\n /** Resume from position (0-indexed) */\n startIndex?: number;\n /** Poll interval in ms when waiting for new items (default: 10) */\n pollInterval?: number;\n /** Stop polling after this many ms with no new items (default: 30000) */\n pollTimeout?: number;\n}\n\n/**\n * Options for streamForEach.\n */\nexport interface StreamForEachStepOptions {\n /** Checkpoint after every N items (default: 1) */\n checkpointInterval?: number;\n /** Maximum concurrent processors (default: 1 = sequential) */\n concurrency?: number;\n}\n\n/**\n * Result from streamForEach operation.\n */\nexport interface StreamForEachResultType<R> {\n /** Results from each processed item */\n results: R[];\n /** Total items processed */\n processedCount: number;\n /** Position of last processed item */\n lastPosition: number;\n}\n\n/**\n * Writable stream interface used in RunStep.\n * @see StreamWriter in awaitly/streaming for full interface\n */\nexport interface StreamWriterInterface<T> {\n write(value: T): AsyncResult<void, StreamWriteErrorType>;\n close(): AsyncResult<void, StreamCloseErrorType>;\n abort(reason: unknown): void;\n readonly writable: boolean;\n readonly position: number;\n readonly namespace: string;\n}\n\n/**\n * Readable stream interface used in RunStep.\n * @see StreamReader in awaitly/streaming for full interface\n */\nexport interface StreamReaderInterface<T> {\n read(): AsyncResult<T, StreamReadErrorType | StreamEndedMarkerType>;\n close(): void;\n readonly readable: boolean;\n readonly position: number;\n readonly namespace: string;\n}\n\n/**\n * Stream write error type.\n */\nexport interface StreamWriteErrorType {\n type: \"STREAM_WRITE_ERROR\";\n reason: \"closed\" | \"aborted\" | \"store_error\";\n message: string;\n cause?: unknown;\n}\n\n/**\n * Stream read error type.\n */\nexport interface StreamReadErrorType {\n type: \"STREAM_READ_ERROR\";\n reason: \"closed\" | \"store_error\";\n message: string;\n cause?: unknown;\n}\n\n/**\n * Stream close error type.\n */\nexport interface StreamCloseErrorType {\n type: \"STREAM_CLOSE_ERROR\";\n reason: \"already_closed\" | \"store_error\";\n message: string;\n cause?: unknown;\n}\n\n/**\n * Stream ended marker type.\n */\nexport interface StreamEndedMarkerType {\n type: \"STREAM_ENDED\";\n finalPosition: number;\n}\n\n// =============================================================================\n// Event Types (for run() optional event support)\n// =============================================================================\n\n/**\n * Unified event stream for workflow execution.\n *\n * Note: step_complete.result uses Result<unknown, unknown, unknown> because events\n * aggregate results from heterogeneous steps. At runtime, the actual Result object\n * preserves its original types, but the event type cannot statically represent them.\n * Use runtime checks or the meta field to interpret cause values.\n */\n/**\n * Scope types for parallel and race operations.\n */\nexport type ScopeType = \"parallel\" | \"race\" | \"allSettled\";\n\nexport type WorkflowEvent<E, C = unknown> =\n | { type: \"workflow_start\"; workflowId: string; workflowName?: string; ts: number; context?: C }\n | { type: \"workflow_success\"; workflowId: string; workflowName?: string; ts: number; durationMs: number; context?: C }\n | { type: \"workflow_error\"; workflowId: string; workflowName?: string; ts: number; durationMs: number; error: E; context?: C }\n | { type: \"step_start\"; workflowId: string; workflowName?: string; stepId: string; stepKey?: string; name?: string; description?: string; ts: number; metadata?: StepMetadata; context?: C }\n | { type: \"step_success\"; workflowId: string; workflowName?: string; stepId: string; stepKey?: string; name?: string; description?: string; ts: number; durationMs: number; metadata?: StepMetadata; context?: C }\n | { type: \"step_error\"; workflowId: string; workflowName?: string; stepId: string; stepKey?: string; name?: string; description?: string; ts: number; durationMs: number; error: E; metadata?: StepMetadata; diagnostics?: StepErrorDiagnostics; context?: C }\n | { type: \"step_aborted\"; workflowId: string; workflowName?: string; stepId: string; stepKey?: string; name?: string; description?: string; ts: number; durationMs: number; metadata?: StepMetadata; context?: C }\n | { type: \"step_complete\"; workflowId: string; workflowName?: string; stepKey: string; name?: string; description?: string; ts: number; durationMs: number; result: Result<unknown, unknown, unknown>; meta?: StepFailureMeta; metadata?: StepMetadata; context?: C }\n | { type: \"step_cache_hit\"; workflowId: string; workflowName?: string; stepKey: string; name?: string; ts: number; metadata?: StepMetadata; context?: C }\n | { type: \"step_cache_miss\"; workflowId: string; workflowName?: string; stepKey: string; name?: string; ts: number; metadata?: StepMetadata; context?: C }\n | { type: \"step_skipped\"; workflowId: string; workflowName?: string; stepKey?: string; name?: string; reason?: string; decisionId?: string; ts: number; metadata?: StepMetadata; context?: C }\n | { type: \"scope_start\"; workflowId: string; workflowName?: string; scopeId: string; scopeType: ScopeType; name?: string; ts: number; context?: C }\n | { type: \"scope_end\"; workflowId: string; workflowName?: string; scopeId: string; ts: number; durationMs: number; winnerId?: string; context?: C }\n // Retry events\n | {\n type: \"step_retry\";\n workflowId: string;\n workflowName?: string;\n stepId: string;\n stepKey?: string;\n name?: string;\n ts: number;\n attempt: number;\n maxAttempts: number;\n delayMs: number;\n error: E;\n metadata?: StepMetadata;\n diagnostics?: StepErrorDiagnostics;\n context?: C;\n }\n | {\n type: \"step_retries_exhausted\";\n workflowId: string;\n workflowName?: string;\n stepId: string;\n stepKey?: string;\n name?: string;\n ts: number;\n durationMs: number;\n attempts: number;\n lastError: E;\n metadata?: StepMetadata;\n diagnostics?: StepErrorDiagnostics;\n context?: C;\n }\n // Timeout event\n | {\n type: \"step_timeout\";\n workflowId: string;\n workflowName?: string;\n stepId: string;\n stepKey?: string;\n name?: string;\n ts: number;\n timeoutMs: number;\n attempt?: number;\n metadata?: StepMetadata;\n diagnostics?: StepErrorDiagnostics;\n context?: C;\n }\n // Hook events\n | {\n type: \"hook_should_run\";\n workflowId: string;\n workflowName?: string;\n ts: number;\n durationMs: number;\n result: boolean;\n skipped: boolean;\n context?: C;\n }\n | {\n type: \"hook_should_run_error\";\n workflowId: string;\n workflowName?: string;\n ts: number;\n durationMs: number;\n error: E;\n context?: C;\n }\n | {\n type: \"hook_before_start\";\n workflowId: string;\n workflowName?: string;\n ts: number;\n durationMs: number;\n result: boolean;\n skipped: boolean;\n context?: C;\n }\n | {\n type: \"hook_before_start_error\";\n workflowId: string;\n workflowName?: string;\n ts: number;\n durationMs: number;\n error: E;\n context?: C;\n }\n | {\n type: \"hook_after_step\";\n workflowId: string;\n workflowName?: string;\n stepKey: string;\n ts: number;\n durationMs: number;\n context?: C;\n }\n | {\n type: \"hook_after_step_error\";\n workflowId: string;\n workflowName?: string;\n stepKey: string;\n ts: number;\n durationMs: number;\n error: E;\n context?: C;\n }\n // Stream events\n | {\n type: \"stream_created\";\n workflowId: string;\n workflowName?: string;\n namespace: string;\n ts: number;\n context?: C;\n }\n | {\n type: \"stream_write\";\n workflowId: string;\n workflowName?: string;\n namespace: string;\n position: number;\n ts: number;\n context?: C;\n }\n | {\n type: \"stream_read\";\n workflowId: string;\n workflowName?: string;\n namespace: string;\n position: number;\n ts: number;\n context?: C;\n }\n | {\n type: \"stream_close\";\n workflowId: string;\n workflowName?: string;\n namespace: string;\n finalPosition: number;\n ts: number;\n context?: C;\n }\n | {\n type: \"stream_error\";\n workflowId: string;\n workflowName?: string;\n namespace: string;\n error: unknown;\n position: number;\n ts: number;\n context?: C;\n }\n | {\n type: \"stream_backpressure\";\n workflowId: string;\n workflowName?: string;\n namespace: string;\n bufferedCount: number;\n state: \"paused\" | \"flowing\";\n ts: number;\n context?: C;\n }\n // Workflow cancellation event\n | {\n type: \"workflow_cancelled\";\n workflowId: string;\n workflowName?: string;\n ts: number;\n durationMs: number;\n /** Reason from AbortSignal.reason (if provided) */\n reason?: string;\n /** Last successfully completed keyed step before cancellation (for resume purposes) */\n lastStepKey?: string;\n context?: C;\n };\n\n// =============================================================================\n// Run Options\n// =============================================================================\n\nexport type RunOptionsWithCatch<E, C = void> = {\n /**\n * Handler for expected errors.\n * Called when a step fails with a known error type.\n */\n onError?: (error: E, stepName?: string, ctx?: C) => void;\n /**\n * Listener for workflow events (start, success, error, step events).\n * Use this for logging, telemetry, or debugging.\n *\n * Context is automatically included in `event.context` when provided via the `context` option.\n * The separate `ctx` parameter is provided for convenience.\n */\n onEvent?: (event: WorkflowEvent<E | UnexpectedError, C>, ctx: C) => void;\n /**\n * Catch-all mapper for unexpected exceptions.\n * Converts unknown exceptions (and cancellation) into your typed error union E.\n */\n catchUnexpected: (cause: unknown) => E;\n /**\n * Unique ID for this workflow execution.\n * Defaults to a random UUID.\n * Useful for correlating logs across distributed systems.\n */\n workflowId?: string;\n /**\n * Human-readable workflow name included on emitted events.\n * Useful for observability and visualization.\n */\n workflowName?: string;\n /**\n * Arbitrary context object passed to onEvent and onError.\n * Useful for passing request IDs, user IDs, or loggers.\n */\n context?: C;\n /**\n * @internal External signal for workflow-level cancellation.\n * Used by createWorkflow() to pass the workflow signal to steps.\n */\n _workflowSignal?: AbortSignal;\n};\n\nexport type RunOptionsWithoutCatch<E, C = void> = {\n /**\n * Handler for expected errors AND unexpected errors.\n * Unexpected errors will be wrapped in `UnexpectedError`.\n */\n onError?: (error: E | UnexpectedError, stepName?: string, ctx?: C) => void;\n /**\n * Listener for workflow events (start, success, error, step events).\n *\n * Note: Context is available both on `event.context` and as the separate `ctx` parameter.\n * The `ctx` parameter is provided for convenience and backward compatibility.\n */\n onEvent?: (event: WorkflowEvent<E | UnexpectedError, C>, ctx: C) => void;\n catchUnexpected?: undefined;\n workflowId?: string;\n /**\n * Human-readable workflow name included on emitted events.\n * Useful for observability and visualization.\n */\n workflowName?: string;\n context?: C;\n /**\n * @internal External signal for workflow-level cancellation.\n * Used by createWorkflow() to pass the workflow signal to steps.\n */\n _workflowSignal?: AbortSignal;\n};\n\nexport type RunOptions<E, C = void> = RunOptionsWithCatch<E, C> | RunOptionsWithoutCatch<E, C>;\n\n// =============================================================================\n// Early Exit Mechanism (exported for caching layer)\n// =============================================================================\n\n/**\n * Symbol used to identify early exit throws.\n * Exported for the caching layer in workflow.ts.\n * @internal\n */\nexport const EARLY_EXIT_SYMBOL: unique symbol = Symbol(\"early-exit\");\n\n/**\n * Metadata about how a step failed.\n * @internal\n */\nexport type StepFailureMeta =\n | { origin: \"result\"; resultCause?: unknown }\n | { origin: \"throw\"; thrown: unknown }\n | { origin: \"fallback\"; fallbackUsed: true; fallbackReason: string };\n\n/**\n * Early exit object thrown to short-circuit workflow execution.\n * @internal\n */\nexport type EarlyExit<E> = {\n [EARLY_EXIT_SYMBOL]: true;\n error: E;\n meta: StepFailureMeta;\n};\n\n/**\n * Create an early exit throw object.\n * Used by the caching layer to synthesize early exits for cached errors.\n * @internal\n */\nexport function createEarlyExit<E>(error: E, meta: StepFailureMeta): EarlyExit<E> {\n return {\n [EARLY_EXIT_SYMBOL]: true,\n error,\n meta,\n };\n}\n\n/**\n * Type guard for early exit objects.\n * @internal\n */\nexport function isEarlyExit<E>(e: unknown): e is EarlyExit<E> {\n return (\n typeof e === \"object\" &&\n e !== null &&\n (e as Record<PropertyKey, unknown>)[EARLY_EXIT_SYMBOL] === true\n );\n}\n\n/**\n * Symbol to mark exceptions thrown by catchUnexpected mappers.\n * These should propagate without being re-processed.\n * @internal\n */\nconst MAPPER_EXCEPTION_SYMBOL: unique symbol = Symbol(\"mapper-exception\");\n\ntype MapperException = {\n [MAPPER_EXCEPTION_SYMBOL]: true;\n thrown: unknown;\n};\n\nfunction createMapperException(thrown: unknown): MapperException {\n return { [MAPPER_EXCEPTION_SYMBOL]: true, thrown };\n}\n\nfunction isMapperException(e: unknown): e is MapperException {\n return (\n typeof e === \"object\" &&\n e !== null &&\n (e as Record<PropertyKey, unknown>)[MAPPER_EXCEPTION_SYMBOL] === true\n );\n}\n\n// =============================================================================\n// Retry and Timeout Utilities\n// =============================================================================\n\n/**\n * Calculate the delay for a retry attempt based on the backoff strategy.\n * @internal\n */\nfunction calculateRetryDelay(\n attempt: number,\n options: {\n backoff: BackoffStrategy;\n initialDelay: number;\n maxDelay: number;\n jitter: boolean;\n }\n): number {\n const { backoff, initialDelay, maxDelay, jitter } = options;\n\n let delay: number;\n\n switch (backoff) {\n case \"fixed\":\n delay = initialDelay;\n break;\n case \"linear\":\n delay = initialDelay * attempt;\n break;\n case \"exponential\":\n delay = initialDelay * Math.pow(2, attempt - 1);\n break;\n }\n\n // Apply max cap\n delay = Math.min(delay, maxDelay);\n\n // Apply jitter (0-25% of delay)\n if (jitter) {\n const jitterAmount = delay * 0.25 * Math.random();\n delay = delay + jitterAmount;\n }\n\n return Math.floor(delay);\n}\n\n/**\n * Sleep for a specified number of milliseconds.\n * @internal\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nconst DEFAULT_RETRY_ASYNC_CONFIG = {\n backoff: \"exponential\" as BackoffStrategy,\n initialDelay: 100,\n maxDelay: 30000,\n jitter: true,\n retryOn: (_error: unknown, _attempt: number) => true,\n onRetry: (_error: unknown, _attempt: number, _delayMs: number) => {},\n} as const;\n\n/**\n * Run an async function with retry. Reuses the same backoff and retryOn semantics as step.retry.\n * Use this when you want retries without the workflow/step machinery (e.g. in fetch).\n *\n * @param fn - Function that returns a Promise<Result<T, E>>\n * @param options - Retry configuration (attempts, backoff, retryOn, etc.)\n * @returns Promise that resolves to the last Result (ok or err). Rejects only if fn throws and retryOn returns false.\n */\nexport async function retryAsync<T, E>(\n fn: () => Promise<Result<T, E>>,\n options: RetryOptions\n): Promise<Result<T, E>> {\n const attempts = Math.max(1, options.attempts);\n const effective = {\n backoff: options.backoff ?? DEFAULT_RETRY_ASYNC_CONFIG.backoff,\n initialDelay: options.initialDelay ?? DEFAULT_RETRY_ASYNC_CONFIG.initialDelay,\n maxDelay: options.maxDelay ?? DEFAULT_RETRY_ASYNC_CONFIG.maxDelay,\n jitter: options.jitter ?? DEFAULT_RETRY_ASYNC_CONFIG.jitter,\n retryOn: options.retryOn ?? DEFAULT_RETRY_ASYNC_CONFIG.retryOn,\n onRetry: options.onRetry ?? DEFAULT_RETRY_ASYNC_CONFIG.onRetry,\n };\n\n let lastResult: Result<T, E> | undefined;\n for (let attempt = 1; attempt <= attempts; attempt++) {\n try {\n const result = await fn();\n if (result.ok) return result;\n lastResult = result;\n if (attempt < attempts && effective.retryOn(result.error, attempt)) {\n const delay = calculateRetryDelay(attempt, effective);\n effective.onRetry(result.error, attempt, delay);\n await sleep(delay);\n continue;\n }\n return result;\n } catch (thrown) {\n if (attempt < attempts && effective.retryOn(thrown, attempt)) {\n const delay = calculateRetryDelay(attempt, effective);\n effective.onRetry(thrown, attempt, delay);\n await sleep(delay);\n continue;\n }\n throw thrown;\n }\n }\n return lastResult!;\n}\n\n/**\n * Symbol used internally to identify timeout rejection.\n */\nconst TIMEOUT_SYMBOL: unique symbol = Symbol(\"timeout\");\nconst TIMEOUT_OPTION_SYMBOL: unique symbol = Symbol(\"timeout-option\");\n\n/**\n * Check if an error is a timeout option marker (should return undefined instead of error).\n * @internal\n */\nfunction isTimeoutOptionMarker(\n value: unknown\n): value is { [TIMEOUT_OPTION_SYMBOL]: true; ms: number } {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as Record<symbol, unknown>)[TIMEOUT_OPTION_SYMBOL] === true\n );\n}\n\n/**\n * Execute an operation with a timeout using Promise.race.\n * @internal\n */\nasync function executeWithTimeout<T>(\n operation: (() => Promise<T>) | ((signal: AbortSignal) => Promise<T>),\n options: TimeoutOptions,\n stepInfo: { name?: string; key?: string; attempt?: number },\n /** External signal (e.g., workflow cancellation) to combine with timeout signal */\n externalSignal?: AbortSignal\n): Promise<T> {\n const controller = new AbortController();\n const behavior = options.onTimeout ?? \"error\";\n\n // Create the timeout error based on behavior\n const createTimeoutError = (): unknown => {\n // For function behavior, call the handler to generate the error\n if (typeof behavior === \"function\") {\n return behavior({\n name: stepInfo.name,\n key: stepInfo.key,\n ms: options.ms,\n });\n }\n\n // For other behaviors, use custom error or default StepTimeoutError\n return (\n (options.error as StepTimeoutError) ?? {\n type: \"STEP_TIMEOUT\",\n stepName: stepInfo.name,\n stepKey: stepInfo.key,\n timeoutMs: options.ms,\n attempt: stepInfo.attempt,\n }\n );\n };\n\n // Track the timeout ID for cleanup\n let timeoutId: ReturnType<typeof setTimeout>;\n\n // If external signal is already aborted, abort immediately\n if (externalSignal?.aborted) {\n controller.abort(externalSignal.reason);\n }\n\n // Forward external signal abort to internal controller\n let externalAbortHandler: (() => void) | undefined;\n if (externalSignal && !externalSignal.aborted) {\n externalAbortHandler = () => controller.abort(externalSignal.reason);\n externalSignal.addEventListener(\"abort\", externalAbortHandler, { once: true });\n }\n\n // Create a timeout promise that rejects after the specified duration\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n // For 'disconnect', don't abort - let operation continue in background\n if (behavior !== \"disconnect\") {\n controller.abort();\n }\n\n // For 'option', throw special marker to return undefined\n if (behavior === \"option\") {\n reject({ [TIMEOUT_OPTION_SYMBOL]: true, ms: options.ms });\n return;\n }\n\n // For all other behaviors, throw the timeout error\n reject({ [TIMEOUT_SYMBOL]: true, error: createTimeoutError() });\n }, options.ms);\n });\n\n // Execute the operation\n let operationPromise: Promise<T>;\n if (options.signal) {\n // Operation expects an AbortSignal\n // Pass the internal controller's signal which is linked to both timeout and external signal\n operationPromise = Promise.resolve(\n (operation as (signal: AbortSignal) => Promise<T>)(controller.signal)\n );\n } else {\n // Standard operation\n operationPromise = Promise.resolve((operation as () => Promise<T>)());\n }\n\n try {\n // Race between operation and timeout\n const result = await Promise.race([operationPromise, timeoutPromise]);\n return result;\n } catch (error) {\n // Check if this was an 'option' timeout - return undefined as success\n if (\n typeof error === \"object\" &&\n error !== null &&\n (error as Record<symbol, unknown>)[TIMEOUT_OPTION_SYMBOL] === true\n ) {\n // Throw special marker that step handler will convert to ok(undefined)\n throw { [TIMEOUT_OPTION_SYMBOL]: true, ms: options.ms };\n }\n\n // Check if this was our timeout\n if (\n typeof error === \"object\" &&\n error !== null &&\n (error as Record<symbol, unknown>)[TIMEOUT_SYMBOL] === true\n ) {\n // For 'disconnect' behavior, the operation continues in the background\n // Attach a catch handler to prevent unhandled rejection if it fails later\n if (behavior === \"disconnect\") {\n operationPromise.catch(() => {\n // Intentionally swallowed - operation was disconnected\n });\n }\n\n const errorToThrow = (error as { error: unknown }).error;\n\n // Mark the error with STEP_TIMEOUT_MARKER if it's a custom error (not already a StepTimeoutError)\n // This allows isStepTimeoutError() and getStepTimeoutMeta() to work with custom errors\n // Note: Always update metadata to reflect the current attempt (same error may be reused across retries)\n if (\n typeof errorToThrow === \"object\" &&\n errorToThrow !== null &&\n (errorToThrow as StepTimeoutError).type !== \"STEP_TIMEOUT\"\n ) {\n const meta: StepTimeoutMarkerMeta = {\n timeoutMs: options.ms,\n stepName: stepInfo.name,\n stepKey: stepInfo.key,\n attempt: stepInfo.attempt,\n };\n\n if (STEP_TIMEOUT_MARKER in errorToThrow) {\n // Update existing marker with current attempt's metadata\n (errorToThrow as Record<symbol, StepTimeoutMarkerMeta>)[STEP_TIMEOUT_MARKER] = meta;\n } else {\n // Define new marker (writable so it can be updated on retry)\n Object.defineProperty(errorToThrow, STEP_TIMEOUT_MARKER, {\n value: meta,\n enumerable: false,\n writable: true,\n configurable: false,\n });\n }\n }\n\n throw errorToThrow;\n }\n // Re-throw other errors\n throw error;\n } finally {\n // Always clear the timeout to prevent leaks\n clearTimeout(timeoutId!);\n // Clean up external signal listener\n if (externalAbortHandler && externalSignal) {\n externalSignal.removeEventListener(\"abort\", externalAbortHandler);\n }\n }\n}\n\n/**\n * Default retry configuration values.\n * @internal\n */\nconst DEFAULT_RETRY_CONFIG = {\n backoff: \"exponential\" as BackoffStrategy,\n initialDelay: 100,\n maxDelay: 30000,\n jitter: true,\n retryOn: () => true,\n onRetry: () => {},\n} as const;\n\n// =============================================================================\n// run() Function\n// =============================================================================\n\n/**\n * Execute a workflow with step-based error handling.\n *\n * ## When to Use run()\n *\n * Use `run()` when:\n * - Dependencies are dynamic (passed at runtime, not known at compile time)\n * - You don't need step caching or resume state\n * - Error types are known upfront and can be specified manually\n * - Building lightweight, one-off workflows\n *\n * For automatic error type inference from static dependencies, use `createWorkflow()`.\n *\n * ## Error union\n *\n * `run()` returns:\n * - **`catchUnexpected`**: Maps uncaught exceptions to your type E → `Result<T, E>`\n * - **No catchUnexpected**: Step errors pass through + `UnexpectedError` for exceptions → `Result<T, E | UnexpectedError>`\n *\n * When `E` is not specified, it defaults to `never`, giving `Result<T, UnexpectedError>`.\n *\n * @see createWorkflow - For static dependencies with auto error inference\n */\n\n/**\n * run() with catchUnexpected: closed union Result<T, E>.\n */\nexport function run<T, E, C = void>(\n fn: (context: { step: RunStep<E> }) => Promise<T> | T,\n options: RunOptionsWithCatch<E, C>\n): AsyncResult<T, E, unknown>;\n\n/**\n * run() without catchUnexpected.\n * Always adds UnexpectedError to the error union so callers know\n * uncaught exceptions are possible. Step errors pass through as-is.\n * When E is never (default), step is RunStep<unknown> so any operation is allowed.\n */\nexport function run<T, E = never, C = void>(\n fn: (context: {\n step: [E] extends [never] ? RunStep<unknown> : RunStep<E>;\n }) => Promise<T> | T,\n options?: {\n onError?: (error: E | UnexpectedError, stepName?: string, ctx?: C) => void;\n onEvent?: (event: WorkflowEvent<E | UnexpectedError, C>, ctx: C) => void;\n workflowId?: string;\n workflowName?: string;\n context?: C;\n /** @internal External signal for workflow-level cancellation. */\n _workflowSignal?: AbortSignal;\n }\n): AsyncResult<T, E | UnexpectedError, unknown>;\n\n// Implementation\nexport async function run<T, E, C = void>(\n fn: (context: { step: RunStep<E> }) => Promise<T> | T,\n options?: RunOptions<E, C>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): AsyncResult<T, any> {\n const {\n onError,\n onEvent,\n catchUnexpected,\n workflowId: providedWorkflowId,\n workflowName,\n context,\n _workflowSignal,\n } = options && typeof options === \"object\"\n ? (options as RunOptions<E, C>)\n : ({} as RunOptions<E, C>);\n\n const workflowId = providedWorkflowId ?? crypto.randomUUID();\n const effectiveCatchUnexpected = catchUnexpected ?? defaultCatchUnexpected;\n\n // Track active scopes as a stack for proper nesting\n // When a step succeeds, only the innermost race scope gets the winner\n const activeScopeStack: Array<{ scopeId: string; type: ScopeType; winnerId?: string }> = [];\n\n // Counter for generating unique step IDs\n let stepIdCounter = 0;\n\n // Generate a unique step ID\n // Uses stepKey when provided (for cache stability), otherwise generates a unique ID.\n // Note: name is NOT used for stepId because multiple concurrent steps may share a name,\n // which would cause them to collide in activeSteps tracking and race winner detection.\n const generateStepId = (stepKey?: string): string => {\n return stepKey ?? `step_${++stepIdCounter}`;\n };\n\n const emitEvent = (event: WorkflowEvent<E | UnexpectedError, C>) => {\n // Add context to event only if:\n // 1. Event doesn't already have context (preserves replayed events or per-step overrides)\n // 2. Workflow actually has a context (don't add context: undefined property)\n const eventWithContext =\n event.context !== undefined || context === undefined\n ? event\n : ({ ...event, context: context as C } as WorkflowEvent<E | UnexpectedError, C>);\n\n const eventWithName =\n workflowName !== undefined && eventWithContext.workflowName === undefined\n ? ({ ...eventWithContext, workflowName } as WorkflowEvent<E | UnexpectedError, C>)\n : eventWithContext;\n \n // Track first successful step in the innermost race scope for winnerId\n if (eventWithName.type === \"step_success\") {\n // Use the stepId from the event (already generated at step start)\n const stepId = eventWithName.stepId;\n\n // Find innermost race scope (search from end of stack)\n for (let i = activeScopeStack.length - 1; i >= 0; i--) {\n const scope = activeScopeStack[i];\n if (scope.type === \"race\" && !scope.winnerId) {\n scope.winnerId = stepId;\n break; // Only update innermost race scope\n }\n }\n }\n onEvent?.(eventWithName, context as C);\n };\n\n // Use the exported early exit function with proper type parameter\n const earlyExit = createEarlyExit<E>;\n\n // Local type guard that narrows to EarlyExit<E> specifically\n const isEarlyExitE = (e: unknown): e is EarlyExit<E> => isEarlyExit(e);\n\n // Step errors always pass through — they are typed Result errors.\n // Only truly uncaught exceptions get mapped via effectiveCatchUnexpected.\n const wrapForStep = (\n error: unknown,\n _meta?: StepFailureMeta\n ): E => {\n return error as E;\n };\n\n // Helper to check if a value is a Result (has ok property) vs a function\n const isResultLike = (value: unknown): value is Result<unknown, unknown, unknown> | Promise<Result<unknown, unknown, unknown>> => {\n if (typeof value === 'function') return false;\n if (value && typeof value === 'object' && 'ok' in value) return true;\n // Check for Promise<Result> - it will have a then method\n if (value && typeof value === 'object' && 'then' in value && typeof (value as Promise<unknown>).then === 'function') return true;\n return false;\n };\n\n try {\n // Step function: requires step('id', fn, opts) or step('id', result, opts)\n const stepFn = <T, StepE, StepC = unknown>(\n id: string,\n operationOrResult: (() => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>) | Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n stepOptions?: StepOptions\n ): Promise<T> => {\n return (async () => {\n // Validate required string ID\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step() requires an explicit string ID as the first argument. ' +\n 'Example: step(\"fetchUser\", () => fetchUser(id))'\n );\n }\n\n const parsedOptions: StepOptions = stepOptions ?? {};\n const stepMetadata = extractStepMetadata(parsedOptions);\n\n // Name is always derived from ID\n const stepName = id;\n const stepKey = parsedOptions.key ?? id; // For general events (step_start, step_success, etc.)\n const explicitKey = parsedOptions.key ?? id; // For step_complete and caching (ID is used when no key)\n const { description: stepDescription, retry: retryConfig, timeout: timeoutConfig } = parsedOptions;\n const stepId = generateStepId(stepKey);\n const hasEventListeners = onEvent;\n const overallStartTime = hasEventListeners ? performance.now() : 0;\n\n // Determine if this is a direct Result or a function\n const isDirectResult = isResultLike(operationOrResult);\n const operation = isDirectResult\n ? () => operationOrResult as Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>\n : operationOrResult as () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>;\n\n // Build effective retry config with defaults\n // Ensure at least 1 attempt (0 would skip the loop entirely and crash)\n const maxAttempts = Math.max(1, retryConfig?.attempts ?? 1);\n const effectiveRetry = {\n attempts: maxAttempts,\n backoff: retryConfig?.backoff ?? DEFAULT_RETRY_CONFIG.backoff,\n initialDelay: retryConfig?.initialDelay ?? DEFAULT_RETRY_CONFIG.initialDelay,\n maxDelay: retryConfig?.maxDelay ?? DEFAULT_RETRY_CONFIG.maxDelay,\n jitter: retryConfig?.jitter ?? DEFAULT_RETRY_CONFIG.jitter,\n retryOn: retryConfig?.retryOn ?? DEFAULT_RETRY_CONFIG.retryOn,\n onRetry: retryConfig?.onRetry ?? DEFAULT_RETRY_CONFIG.onRetry,\n };\n\n // Emit step_start only once (before first attempt)\n if (onEvent) {\n emitEvent({\n type: \"step_start\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n\n let lastResult: Result<T, StepE, StepC> | undefined;\n\n for (let attempt = 1; attempt <= effectiveRetry.attempts; attempt++) {\n const attemptStartTime = hasEventListeners ? performance.now() : 0;\n\n try {\n // Execute operation with optional timeout\n let result: Result<T, StepE, StepC>;\n\n if (timeoutConfig) {\n // Wrap with timeout, passing workflow signal for { signal: true } steps\n result = await executeWithTimeout(\n operation as () => Promise<Result<T, StepE, StepC>>,\n timeoutConfig,\n { name: stepName, key: stepKey, attempt },\n _workflowSignal\n );\n } else {\n result = await operation();\n }\n\n // Success case\n if (result.ok) {\n const durationMs = performance.now() - overallStartTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs,\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n if (explicitKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey: explicitKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs,\n result,\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n return result.value;\n }\n\n // Result error case - check if we should retry\n lastResult = result;\n\n if (attempt < effectiveRetry.attempts && effectiveRetry.retryOn(result.error, attempt)) {\n const delay = calculateRetryDelay(attempt, effectiveRetry);\n\n // Emit retry event\n emitEvent({\n type: \"step_retry\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n attempt: attempt + 1,\n maxAttempts: effectiveRetry.attempts,\n delayMs: delay,\n error: result.error as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(result.error, parsedOptions.errorMeta, 'result', attempt, performance.now() - overallStartTime),\n });\n\n effectiveRetry.onRetry(result.error, attempt, delay);\n await sleep(delay);\n continue;\n }\n\n // No more retries or retryOn returned false - emit exhausted event if we retried\n if (effectiveRetry.attempts > 1) {\n emitEvent({\n type: \"step_retries_exhausted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - overallStartTime,\n attempts: attempt,\n lastError: result.error as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(result.error, parsedOptions.errorMeta, 'result', attempt, performance.now() - overallStartTime),\n });\n }\n\n // Fall through to final error handling below\n break;\n\n } catch (thrown) {\n const durationMs = performance.now() - attemptStartTime;\n\n // Handle timeout with 'option' behavior - return undefined as success\n if (isTimeoutOptionMarker(thrown)) {\n const timeoutMs = thrown.ms;\n emitEvent({\n type: \"step_timeout\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n timeoutMs,\n attempt,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'timeout', attempt),\n });\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: performance.now() - overallStartTime,\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n if (explicitKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey: explicitKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: performance.now() - overallStartTime,\n result: ok(undefined),\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n // Return undefined as success value (timeout was treated as optional)\n return undefined as T;\n }\n\n // Handle early exit - propagate immediately\n if (isEarlyExitE(thrown)) {\n emitEvent({\n type: \"step_aborted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs,\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n throw thrown;\n }\n\n // Handle timeout error\n if (isStepTimeoutError(thrown)) {\n // Get timeout metadata from the error (works for both standard and custom errors)\n const timeoutMeta = getStepTimeoutMeta(thrown);\n const timeoutMs = timeoutConfig?.ms ?? timeoutMeta?.timeoutMs ?? 0;\n emitEvent({\n type: \"step_timeout\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n timeoutMs,\n attempt,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'timeout', attempt),\n });\n\n // Check if we should retry after timeout\n if (attempt < effectiveRetry.attempts && effectiveRetry.retryOn(thrown, attempt)) {\n const delay = calculateRetryDelay(attempt, effectiveRetry);\n\n emitEvent({\n type: \"step_retry\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n attempt: attempt + 1,\n maxAttempts: effectiveRetry.attempts,\n delayMs: delay,\n error: thrown as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'timeout', attempt, performance.now() - overallStartTime),\n });\n\n effectiveRetry.onRetry(thrown, attempt, delay);\n await sleep(delay);\n continue;\n }\n\n // No more retries - emit exhausted if we retried\n if (effectiveRetry.attempts > 1) {\n emitEvent({\n type: \"step_retries_exhausted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - overallStartTime,\n attempts: attempt,\n lastError: thrown as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'timeout', attempt, performance.now() - overallStartTime),\n });\n }\n\n // Treat STEP_TIMEOUT as a typed error - exit directly without UnexpectedError wrapper\n // This provides better DX: users get STEP_TIMEOUT directly in result.error\n const totalDurationMs = performance.now() - overallStartTime;\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: totalDurationMs,\n error: thrown as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'timeout', attempt, totalDurationMs),\n });\n if (explicitKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey: explicitKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: totalDurationMs,\n result: err(thrown as unknown as E, { cause: thrown }),\n meta: { origin: \"throw\", thrown },\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n onError?.(thrown as unknown as E, stepName, context);\n throw earlyExit(thrown as unknown as E, { origin: \"throw\", thrown });\n }\n\n // Handle other thrown errors (continue to error handling below)\n\n // Check if we should retry thrown errors\n if (attempt < effectiveRetry.attempts && effectiveRetry.retryOn(thrown, attempt)) {\n const delay = calculateRetryDelay(attempt, effectiveRetry);\n\n emitEvent({\n type: \"step_retry\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n attempt: attempt + 1,\n maxAttempts: effectiveRetry.attempts,\n delayMs: delay,\n error: thrown as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'throw', attempt, performance.now() - overallStartTime),\n });\n\n effectiveRetry.onRetry(thrown, attempt, delay);\n await sleep(delay);\n continue;\n }\n\n // No more retries for thrown errors - emit exhausted if we retried\n if (effectiveRetry.attempts > 1 && !isStepTimeoutError(thrown)) {\n emitEvent({\n type: \"step_retries_exhausted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - overallStartTime,\n attempts: attempt,\n lastError: thrown as unknown as E,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'throw', attempt, performance.now() - overallStartTime),\n });\n }\n\n // Handle the error using effectiveCatchUnexpected\n const totalDurationMs = performance.now() - overallStartTime;\n\n let mappedError: E | UnexpectedError;\n try {\n mappedError = effectiveCatchUnexpected(thrown) as E | UnexpectedError;\n } catch (mapperError) {\n throw createMapperException(mapperError);\n }\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: totalDurationMs,\n error: mappedError,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, 'throw', attempt, totalDurationMs),\n });\n if (explicitKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey: explicitKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: totalDurationMs,\n result: err(mappedError, { cause: thrown }),\n meta: { origin: \"throw\", thrown },\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n onError?.(mappedError as E, stepName, context);\n throw earlyExit(mappedError as E, { origin: \"throw\", thrown });\n }\n }\n\n // All retries exhausted with Result error - handle final error\n // At this point lastResult must be an error result (we only reach here on error)\n const errorResult = lastResult as Err<StepE, StepC>;\n const totalDurationMs = performance.now() - overallStartTime;\n const wrappedError = wrapForStep(errorResult.error, {\n origin: \"result\",\n resultCause: errorResult.cause,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: totalDurationMs,\n error: wrappedError,\n ...(stepMetadata && { metadata: stepMetadata }),\n diagnostics: buildStepErrorPayload(errorResult.error, parsedOptions.errorMeta, 'result', effectiveRetry.attempts, totalDurationMs),\n });\n if (explicitKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey: explicitKey,\n name: stepName,\n description: stepDescription,\n ts: Date.now(),\n durationMs: totalDurationMs,\n result: errorResult,\n meta: { origin: \"result\", resultCause: errorResult.cause },\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: errorResult.cause,\n });\n })();\n };\n\n stepFn.try = <T, Err>(\n id: string,\n operation: () => T | Promise<T>,\n opts:\n | { error: Err; key?: string }\n | { onError: (cause: unknown) => Err; key?: string }\n ): Promise<T> => {\n // Validate required string ID\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.try() requires an explicit string ID as the first argument. ' +\n 'Example: step.try(\"parse\", () => JSON.parse(str), { error: \"PARSE_ERROR\" })'\n );\n }\n\n const stepKey = opts.key ?? id; // Use id as key if not provided\n const stepName = id; // Name is always the id\n const stepId = id;\n const mapToError = \"error\" in opts ? () => opts.error : opts.onError;\n const hasEventListeners = onEvent;\n\n return (async () => {\n const startTime = hasEventListeners ? performance.now() : 0;\n\n if (onEvent) {\n emitEvent({\n type: \"step_start\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n });\n }\n\n try {\n const value = await operation();\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n });\n // Emit step_complete for keyed steps (for state persistence)\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: ok(value),\n });\n }\n return value;\n } catch (error) {\n const mapped = mapToError(error);\n const durationMs = performance.now() - startTime;\n const wrappedError = wrapForStep(mapped, { origin: \"throw\", thrown: error });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n // Emit step_complete for keyed steps (for state persistence)\n // Note: For step.try errors, we encode the mapped error, not the original thrown\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(mapped, { cause: error }),\n meta: { origin: \"throw\", thrown: error },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, { origin: \"throw\", thrown: error });\n }\n })();\n };\n\n // step.fromResult: Execute a Result-returning function and map its typed error\n stepFn.fromResult = <T, ResultE, Err>(\n id: string,\n operation: () => Result<T, ResultE, unknown> | AsyncResult<T, ResultE, unknown>,\n opts:\n | { error: Err; key?: string }\n | { onError: (resultError: ResultE) => Err; key?: string }\n ): Promise<T> => {\n // Validate required string ID\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.fromResult() requires an explicit string ID as the first argument. ' +\n 'Example: step.fromResult(\"callProvider\", () => callProvider(input), { onError: (e) => ({ type: \"FAILED\" }) })'\n );\n }\n\n const stepKey = opts.key ?? id; // Use id as key if not provided\n const stepName = id; // Name is always the id\n const stepId = id;\n const mapToError = \"error\" in opts ? () => opts.error : opts.onError;\n const hasEventListeners = onEvent;\n\n return (async () => {\n const startTime = hasEventListeners ? performance.now() : 0;\n\n if (onEvent) {\n emitEvent({\n type: \"step_start\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n });\n }\n\n const result = await operation();\n\n if (result.ok) {\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n });\n // Emit step_complete for keyed steps (for state persistence)\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: ok(result.value),\n });\n }\n return result.value;\n } else {\n const mapped = mapToError(result.error);\n const durationMs = performance.now() - startTime;\n // For fromResult, the cause is the original result.error (what got mapped)\n // This is analogous to step.try using thrown exception as cause\n const wrappedError = wrapForStep(mapped, {\n origin: \"result\",\n resultCause: result.error,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n // Emit step_complete for keyed steps (for state persistence)\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(mapped, { cause: result.error }),\n meta: { origin: \"result\", resultCause: result.error },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: result.error,\n });\n }\n })();\n };\n\n // step.fromNullable: Execute an operation returning T | null/undefined and convert to typed error\n stepFn.fromNullable = <T, Err>(\n id: string,\n operation: () => T | null | undefined | Promise<T | null | undefined>,\n onNull: () => Err,\n options?: { key?: string; ttl?: number }\n ): Promise<T> => {\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.fromNullable() requires an explicit string ID as the first argument. ' +\n 'Example: step.fromNullable(\"getUser\", () => db.find(id), () => ({ type: \"NOT_FOUND\" }))'\n );\n }\n return stepFn(\n id,\n async () => {\n const value = await operation();\n return value != null ? ok(value) : err(onNull());\n },\n options\n );\n };\n\n // step.retry: Execute an operation with retry and optional timeout\n stepFn.retry = <T, StepE, StepC = unknown>(\n id: string,\n operation: () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n options: RetryOptions & { key?: string; timeout?: TimeoutOptions }\n ): Promise<T> => {\n // Validate required string ID\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.retry() requires an explicit string ID as the first argument. ' +\n 'Example: step.retry(\"fetchData\", () => fetchData(), { attempts: 3 })'\n );\n }\n\n // Delegate to stepFn with retry options merged into StepOptions\n // Use key for caching if provided, otherwise use id\n return stepFn(id, operation, {\n key: options.key ?? id,\n retry: {\n attempts: options.attempts,\n backoff: options.backoff,\n initialDelay: options.initialDelay,\n maxDelay: options.maxDelay,\n jitter: options.jitter,\n retryOn: options.retryOn,\n onRetry: options.onRetry,\n },\n timeout: options.timeout,\n });\n };\n\n // step.withTimeout: Execute an operation with a timeout\n stepFn.withTimeout = <T, StepE, StepC = unknown>(\n id: string,\n operation:\n | (() => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>)\n | ((signal: AbortSignal) => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>),\n options: TimeoutOptions & { key?: string }\n ): Promise<T> => {\n // Validate required string ID\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.withTimeout() requires an explicit string ID as the first argument. ' +\n 'Example: step.withTimeout(\"slowOp\", () => slowOp(), { ms: 5000 })'\n );\n }\n\n // Delegate to stepFn with timeout options\n // The signal handling happens in executeWithTimeout when timeout.signal is true\n // Use key for caching if provided, otherwise use id\n return stepFn(\n id,\n operation as () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n {\n key: options.key ?? id,\n timeout: options,\n }\n );\n };\n\n // step.sleep: Pause execution for a specified duration\n stepFn.sleep = (\n id: string,\n duration: DurationInput,\n options?: { key?: string; ttl?: number; description?: string; signal?: AbortSignal }\n ): Promise<void> => {\n // Validate required string ID\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.sleep() requires an explicit string ID as the first argument. ' +\n 'Example: step.sleep(\"delay\", \"5s\")'\n );\n }\n\n // Parse duration - inline to avoid importing duration module\n const d = typeof duration === \"string\" ? parseDurationString(duration) : duration;\n if (!d) {\n throw new Error(`step.sleep: invalid duration '${duration}'`);\n }\n const ms = d.millis;\n const userSignal = options?.signal;\n\n // Delegate to stepFn with a cancellation-aware sleep operation\n // Use key for caching if provided, otherwise use id\n return stepFn(\n id,\n async (): AsyncResult<void, never> => {\n // Check if already aborted (workflow or user signal)\n if (_workflowSignal?.aborted || userSignal?.aborted) {\n const e = new Error(\"Sleep aborted\");\n e.name = \"AbortError\";\n throw e;\n }\n\n return new Promise<Result<void, never>>((resolve, reject) => {\n // Using object to avoid prefer-const warning while allowing\n // onAbort to reference the timeout before it's assigned\n const state = { timeoutId: undefined as ReturnType<typeof setTimeout> | undefined };\n\n const onAbort = () => {\n if (state.timeoutId) clearTimeout(state.timeoutId);\n const e = new Error(\"Sleep aborted\");\n e.name = \"AbortError\";\n reject(e);\n };\n\n _workflowSignal?.addEventListener(\"abort\", onAbort, { once: true });\n userSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n state.timeoutId = setTimeout(() => {\n _workflowSignal?.removeEventListener(\"abort\", onAbort);\n userSignal?.removeEventListener(\"abort\", onAbort);\n resolve(ok(undefined));\n }, ms);\n });\n },\n {\n key: options?.key ?? id,\n description: options?.description,\n }\n );\n };\n\n // step.parallel: Execute parallel operations with scope events\n // 1. Object form: step.parallel(name, { key: fn | { fn, errors } })\n // 2. Array form: step.parallel(name, () => allAsync([...]))\n stepFn.parallel = ((...args: unknown[]): Promise<unknown> => {\n if (typeof args[0] !== \"string\") {\n throw new TypeError(\n \"step.parallel(name, ...): first argument must be a string (step name). Example: step.parallel('Fetch data', { user: () => fetchUser(), posts: () => fetchPosts() })\"\n );\n }\n const name = args[0] as string;\n const second = args[1];\n if (typeof second === \"function\") {\n return executeParallelArray(name, second as () => MaybeAsyncResult<unknown[], unknown, unknown>);\n }\n if (second && typeof second === \"object\" && !Array.isArray(second)) {\n const rawOperations = second as Record<string, (() => MaybeAsyncResult<unknown, unknown, unknown>) | ParallelOperationDescriptor<unknown, readonly string[]>>;\n const normalizedOperations = normalizeParallelOperations(rawOperations);\n return executeParallelNamed(normalizedOperations, { name });\n }\n throw new TypeError(\n \"step.parallel(name, ...): second argument must be a function (array form) or an object of operations (object form).\"\n );\n }) as RunStep<E>[\"parallel\"];\n\n function normalizeParallelOperations(\n rawOperations: Record<string, (() => MaybeAsyncResult<unknown, unknown, unknown>) | ParallelOperationDescriptor<unknown, readonly string[]>>\n ): Record<string, () => MaybeAsyncResult<unknown, unknown, unknown>> {\n const out: Record<string, () => MaybeAsyncResult<unknown, unknown, unknown>> = {};\n for (const [key, value] of Object.entries(rawOperations)) {\n if (typeof value === \"function\") {\n out[key] = value;\n } else if (value && typeof value === \"object\" && \"fn\" in value) {\n out[key] = value.fn;\n } else {\n throw new TypeError(`step.parallel: operation \"${key}\" must be a function or { fn, errors? } object`);\n }\n }\n return out;\n }\n\n // Array form implementation\n function executeParallelArray<T>(\n name: string,\n operation: () => MaybeAsyncResult<T[], unknown, unknown>\n ): Promise<T[]> {\n const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n\n return (async () => {\n const startTime = performance.now();\n let scopeEnded = false;\n\n // Push this scope onto the stack for proper nesting tracking\n activeScopeStack.push({ scopeId, type: \"parallel\" });\n\n // Helper to emit scope_end exactly once\n const emitScopeEnd = () => {\n if (scopeEnded) return;\n scopeEnded = true;\n // Pop this scope from the stack\n const idx = activeScopeStack.findIndex(s => s.scopeId === scopeId);\n if (idx !== -1) activeScopeStack.splice(idx, 1);\n emitEvent({\n type: \"scope_end\",\n workflowId,\n scopeId,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n };\n\n // Emit scope_start event\n emitEvent({\n type: \"scope_start\",\n workflowId,\n scopeId,\n scopeType: \"parallel\",\n name,\n ts: Date.now(),\n });\n\n try {\n const result = await operation();\n\n // Emit scope_end before processing result\n emitScopeEnd();\n\n if (!result.ok) {\n onError?.(result.error as unknown as E, name, context);\n throw earlyExit(result.error as unknown as E, {\n origin: \"result\",\n resultCause: result.cause,\n });\n }\n\n return result.value;\n } catch (error) {\n // Always emit scope_end in finally-like fashion\n emitScopeEnd();\n throw error;\n }\n })();\n }\n\n // Named object form implementation - execute each operation in parallel\n function executeParallelNamed<T extends Record<string, unknown>>(\n operations: Record<string, () => MaybeAsyncResult<unknown, unknown, unknown>>,\n options: { name?: string }\n ): Promise<T> {\n const keys = Object.keys(operations);\n const name = options.name ?? `Parallel(${keys.join(\", \")})`;\n const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n\n return (async () => {\n const startTime = performance.now();\n let scopeEnded = false;\n\n // Push this scope onto the stack for proper nesting tracking\n activeScopeStack.push({ scopeId, type: \"parallel\" });\n\n // Helper to emit scope_end exactly once\n const emitScopeEnd = () => {\n if (scopeEnded) return;\n scopeEnded = true;\n const idx = activeScopeStack.findIndex(s => s.scopeId === scopeId);\n if (idx !== -1) activeScopeStack.splice(idx, 1);\n emitEvent({\n type: \"scope_end\",\n workflowId,\n scopeId,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n };\n\n // Emit scope_start event with operation names in metadata\n emitEvent({\n type: \"scope_start\",\n workflowId,\n scopeId,\n scopeType: \"parallel\",\n name,\n ts: Date.now(),\n });\n\n try {\n // Execute all operations in parallel, fail-fast on first error\n const results = await new Promise<{ key: string; result: Result<unknown, unknown, unknown> }[]>((resolve) => {\n if (keys.length === 0) {\n resolve([]);\n return;\n }\n\n let settled = false;\n let pendingCount = keys.length;\n const resultArray: { key: string; result: Result<unknown, unknown, unknown> }[] = new Array(keys.length);\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n const index = i;\n\n Promise.resolve(operations[key]())\n .catch((reason) => err(\n { type: \"PROMISE_REJECTED\" as const, cause: reason },\n { cause: { type: \"PROMISE_REJECTION\" as const, reason } }\n ))\n .then((result) => {\n if (settled) return;\n\n // Fail-fast: if any operation fails, resolve immediately with just the failed entry\n if (!result.ok) {\n settled = true;\n resolve([{ key, result }]);\n return;\n }\n\n resultArray[index] = { key, result };\n pendingCount--;\n\n if (pendingCount === 0) {\n resolve(resultArray);\n }\n });\n }\n });\n\n // Emit scope_end before processing results\n emitScopeEnd();\n\n // Check for errors and build result object\n const output: Record<string, unknown> = {};\n for (const { key, result } of results) {\n if (!result.ok) {\n onError?.(result.error as unknown as E, key, context);\n throw earlyExit(result.error as unknown as E, {\n origin: \"result\",\n resultCause: result.cause,\n });\n }\n output[key] = result.value;\n }\n\n return output as T;\n } catch (error) {\n // Always emit scope_end in finally-like fashion\n emitScopeEnd();\n throw error;\n }\n })();\n }\n\n // step.race: Execute a race operation with scope events\n stepFn.race = <T, StepE, StepC>(\n name: string,\n operation: () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>\n ): Promise<T> => {\n const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n\n return (async () => {\n const startTime = performance.now();\n let scopeEnded = false;\n\n // Push this race scope onto the stack to track the first successful step as winner\n const scopeEntry = { scopeId, type: \"race\" as const, winnerId: undefined as string | undefined };\n activeScopeStack.push(scopeEntry);\n\n // Helper to emit scope_end exactly once, including winnerId\n const emitScopeEnd = () => {\n if (scopeEnded) return;\n scopeEnded = true;\n // Pop this scope from the stack\n const idx = activeScopeStack.findIndex(s => s.scopeId === scopeId);\n if (idx !== -1) activeScopeStack.splice(idx, 1);\n emitEvent({\n type: \"scope_end\",\n workflowId,\n scopeId,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n winnerId: scopeEntry.winnerId,\n });\n };\n\n // Emit scope_start event\n emitEvent({\n type: \"scope_start\",\n workflowId,\n scopeId,\n scopeType: \"race\",\n name,\n ts: Date.now(),\n });\n\n try {\n const result = await operation();\n\n // Emit scope_end before processing result\n emitScopeEnd();\n\n if (!result.ok) {\n onError?.(result.error as unknown as E, name, context);\n throw earlyExit(result.error as unknown as E, {\n origin: \"result\",\n resultCause: result.cause,\n });\n }\n\n return result.value;\n } catch (error) {\n // Always emit scope_end in finally-like fashion\n emitScopeEnd();\n throw error;\n }\n })();\n };\n\n // step.allSettled: Execute an allSettled operation with scope events\n stepFn.allSettled = <T, StepE, StepC>(\n name: string,\n operation: () => Result<T[], StepE, StepC> | AsyncResult<T[], StepE, StepC>\n ): Promise<T[]> => {\n const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n\n return (async () => {\n const startTime = performance.now();\n let scopeEnded = false;\n\n // Push this scope onto the stack for proper nesting tracking\n activeScopeStack.push({ scopeId, type: \"allSettled\" });\n\n // Helper to emit scope_end exactly once\n const emitScopeEnd = () => {\n if (scopeEnded) return;\n scopeEnded = true;\n // Pop this scope from the stack\n const idx = activeScopeStack.findIndex(s => s.scopeId === scopeId);\n if (idx !== -1) activeScopeStack.splice(idx, 1);\n emitEvent({\n type: \"scope_end\",\n workflowId,\n scopeId,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n };\n\n // Emit scope_start event\n emitEvent({\n type: \"scope_start\",\n workflowId,\n scopeId,\n scopeType: \"allSettled\",\n name,\n ts: Date.now(),\n });\n\n try {\n const result = await operation();\n\n // Emit scope_end before processing result\n emitScopeEnd();\n\n if (!result.ok) {\n onError?.(result.error as unknown as E, name, context);\n throw earlyExit(result.error as unknown as E, {\n origin: \"result\",\n resultCause: result.cause,\n });\n }\n\n return result.value;\n } catch (error) {\n // Always emit scope_end in finally-like fashion\n emitScopeEnd();\n throw error;\n }\n })();\n };\n\n // step.if: Mark a conditional for static analysis\n // Runtime: just executes the condition and returns the result\n // Analyzer: extracts the id and conditionLabel for DecisionNode\n stepFn.if = <T extends boolean>(\n _id: string,\n _conditionLabel: string,\n condition: () => T\n ): T => {\n return condition();\n };\n\n // step.label: Alias for step.if - mark a conditional for static analysis\n // Use step.label for strict mode when conditionals contain step calls\n stepFn.label = stepFn.if;\n\n // step.branch: Execute a branch with explicit metadata for static analysis\n // Runtime: evaluates condition and executes appropriate arm\n // Analyzer: extracts branch metadata (conditionLabel, per-arm errors, out)\n stepFn.branch = async <\n T,\n const ThenErrs extends readonly string[] = readonly [],\n const ElseErrs extends readonly string[] = readonly [],\n const Out extends string | undefined = undefined,\n >(\n _id: string,\n options: BranchOptions<T, ThenErrs, ElseErrs, Out>\n ): Promise<T> => {\n const { condition, then: thenFn, else: elseFn } = options;\n const conditionResult = condition();\n if (conditionResult) {\n return await thenFn();\n } else if (elseFn) {\n return await elseFn();\n }\n return undefined as T;\n };\n\n // step.arm: Create an arm definition for use with step.branch\n // Runtime: returns the arm definition unchanged\n // Analyzer: extracts arm metadata\n stepFn.arm = <T, const Errs extends readonly string[] = readonly []>(\n fn: () => T | Promise<T>,\n errors?: Errs\n ): ArmDefinition<T, Errs> => {\n return { fn, errors };\n };\n\n // step.forEach: Execute a forEach loop with static analysis support\n // Supports both simple (run) and complex (item) forms\n stepFn.forEach = async <T, R>(\n _id: string,\n items: Iterable<T> | AsyncIterable<T>,\n options: ForEachRunOptions<T, R, readonly string[]> | ForEachItemOptions<T, R>\n ): Promise<R[]> => {\n const results: R[] = [];\n const maxIterations = options.maxIterations;\n let index = 0;\n\n // Check if this is the run form or item form\n const isRunForm = 'run' in options;\n\n // Convert items to async iterable for uniform handling\n const asyncItems = Symbol.asyncIterator in (items as object)\n ? (items as AsyncIterable<T>)\n : (async function* () { yield* items as Iterable<T>; })();\n\n for await (const item of asyncItems) {\n if (maxIterations !== undefined && index >= maxIterations) {\n break;\n }\n\n let result: R;\n if (isRunForm) {\n const runOptions = options as ForEachRunOptions<T, R, readonly string[]>;\n result = await runOptions.run(item, index);\n } else {\n const itemOptions = options as ForEachItemOptions<T, R>;\n result = await itemOptions.item.handler(item, index, stepFn as unknown as RunStep<unknown>);\n }\n\n results.push(result);\n index++;\n }\n\n return results;\n };\n\n // step.item: Create an item handler for use with step.forEach\n // Runtime: returns the handler wrapped in a marker object\n // Analyzer: extracts the inner step structure\n stepFn.item = <T, R>(\n handler: (item: T, index: number, step: RunStep<unknown>) => R | Promise<R>\n ): ForEachItemHandler<T, R> => {\n return {\n __forEachItemHandler: true as const,\n handler,\n };\n };\n\n // step.dep: Wrap a dependency function for static analysis tracking\n // Runtime: returns the function unchanged\n // Analyzer: records the dependency name\n stepFn.dep = <T extends (...args: unknown[]) => unknown>(\n _name: string,\n fn: T\n ): T => {\n return fn;\n };\n\n // ===========================================================================\n // Effect-Style Ergonomics\n // ===========================================================================\n\n // step.run: Unwrap an AsyncResult directly\n stepFn.run = <T, StepE, StepC = unknown>(\n id: string,\n result: AsyncResult<T, StepE, StepC>,\n options?: StepOptions\n ): Promise<T> => {\n return stepFn(id, () => result, options);\n };\n\n // step.workflow: Run sub-workflow (or any AsyncResult getter) as a step; same engine as step(id, getter, opts)\n stepFn.workflow = <T, SubE, StepC = unknown>(\n id: string,\n getter: () => AsyncResult<T, SubE, StepC>,\n options?: StepOptions\n ): Promise<T> => {\n return stepFn(id, getter as () => AsyncResult<T, E, StepC>, options);\n };\n\n // step.andThen: Chain AsyncResult operations\n stepFn.andThen = <T, U, StepE, StepC = unknown>(\n id: string,\n value: T,\n fn: (value: T) => AsyncResult<U, StepE, StepC>,\n options?: StepOptions\n ): Promise<U> => {\n return stepFn(id, () => fn(value), options);\n };\n\n // step.match: Pattern match on Result with step tracking (runs through step engine for lifecycle events)\n stepFn.match = async <T, StepE, U, StepC = unknown>(\n id: string,\n result: Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>,\n handlers: {\n ok: (value: T) => U | Promise<U>;\n err: (error: StepE, cause?: StepC) => U | Promise<U>;\n },\n options?: StepOptions\n ): Promise<U> => {\n return stepFn(id, async () => {\n const resolved = await result;\n if (resolved.ok) {\n return ok(await handlers.ok(resolved.value));\n } else {\n return ok(await handlers.err(resolved.error, resolved.cause));\n }\n }, options);\n };\n\n // step.all: Alias for step.parallel (Effect.all-style API)\n stepFn.all = stepFn.parallel;\n\n // step.map: Map over array with parallel execution\n stepFn.map = async <T, U, StepE, StepC = unknown>(\n id: string,\n items: T[],\n mapper: (item: T, index: number) => AsyncResult<U, StepE, StepC>,\n options?: { concurrency?: number; key?: string }\n ): Promise<U[]> => {\n const concurrency = options?.concurrency ?? items.length;\n\n // Use allAsync for parallel execution with fail-fast\n return stepFn(\n id,\n () => {\n if (concurrency >= items.length) {\n // Full parallelism - execute all at once\n return allAsync(items.map((item, index) => mapper(item, index)));\n } else {\n // Limited concurrency - batch execution\n return (async () => {\n const results: U[] = [];\n for (let i = 0; i < items.length; i += concurrency) {\n const batch = items.slice(i, i + concurrency);\n const batchResult = await allAsync(\n batch.map((item, batchIndex) => mapper(item, i + batchIndex))\n );\n // allAsync returns Result<U[], E, C>, so we need to check if it's ok\n if (!batchResult.ok) {\n return batchResult; // Propagate the error\n }\n results.push(...batchResult.value);\n }\n return ok(results);\n })();\n }\n },\n { key: options?.key }\n );\n };\n\n // step.withFallback: Execute primary with fallback on error\n stepFn.withFallback = <T, E1, E2>(\n id: string,\n operation: () => AsyncResult<T, E1>,\n options: { on?: E1 & string; fallback: () => AsyncResult<T, E2>; key?: string }\n ): Promise<T> => {\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.withFallback() requires an explicit string ID as the first argument. ' +\n 'Example: step.withFallback(\"getUser\", () => fetchUser(id), { fallback: () => fetchFromCache(id) })'\n );\n }\n\n const stepKey = options.key ?? id;\n const stepName = id;\n const stepId = generateStepId(stepKey);\n const hasEventListeners = onEvent;\n\n return (async () => {\n const startTime = hasEventListeners ? performance.now() : 0;\n\n if (onEvent) {\n emitEvent({\n type: \"step_start\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n });\n }\n\n // Try the primary operation\n let primaryResult: Result<T, E1>;\n try {\n primaryResult = await operation();\n } catch (thrown) {\n // If it's an earlyExit from a nested step, propagate\n if (isEarlyExitE(thrown)) {\n emitEvent({\n type: \"step_aborted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n throw thrown;\n }\n\n // Primary threw — map to UnexpectedError\n let mappedError: E | UnexpectedError;\n try {\n mappedError = effectiveCatchUnexpected(thrown) as E | UnexpectedError;\n } catch (mapperError) {\n throw createMapperException(mapperError);\n }\n\n // If `on` is specified, only run fallback if it matches the mapped error\n if (options.on !== undefined && options.on !== mappedError) {\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: mappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(mappedError, { cause: thrown }),\n meta: { origin: \"throw\", thrown },\n });\n }\n onError?.(mappedError as E, stepName, context);\n throw earlyExit(mappedError as E, { origin: \"throw\", thrown });\n }\n\n // Run fallback for thrown error\n let fallbackResultFromThrow: Result<T, E2>;\n try {\n fallbackResultFromThrow = await options.fallback();\n } catch (fallbackThrown) {\n if (isEarlyExitE(fallbackThrown)) {\n emitEvent({\n type: \"step_aborted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n throw fallbackThrown;\n }\n let fallbackMappedError: E | UnexpectedError;\n try {\n fallbackMappedError = effectiveCatchUnexpected(fallbackThrown) as E | UnexpectedError;\n } catch (mapperError) {\n throw createMapperException(mapperError);\n }\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: fallbackMappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(fallbackMappedError, { cause: fallbackThrown }),\n meta: { origin: \"throw\", thrown: fallbackThrown },\n });\n }\n onError?.(fallbackMappedError as E, stepName, context);\n throw earlyExit(fallbackMappedError as E, { origin: \"throw\", thrown: fallbackThrown });\n }\n\n if (fallbackResultFromThrow.ok) {\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: fallbackResultFromThrow,\n meta: { origin: \"fallback\" as const, fallbackUsed: true as const, fallbackReason: String(mappedError) },\n });\n }\n return fallbackResultFromThrow.value;\n } else {\n // Fallback also failed\n const durationMs = performance.now() - startTime;\n const wrappedError = wrapForStep(fallbackResultFromThrow.error, {\n origin: \"result\",\n resultCause: fallbackResultFromThrow.cause,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: fallbackResultFromThrow,\n meta: { origin: \"result\", resultCause: fallbackResultFromThrow.cause },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: fallbackResultFromThrow.cause,\n });\n }\n }\n\n // Primary returned a result (didn't throw)\n if (primaryResult.ok) {\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: primaryResult,\n });\n }\n return primaryResult.value;\n }\n\n // Primary returned an error\n const primaryError = primaryResult.error;\n\n // If `on` is specified and doesn't match, earlyExit with primary error (no fallback)\n if (options.on !== undefined && options.on !== primaryError) {\n const durationMs = performance.now() - startTime;\n const wrappedError = wrapForStep(primaryError, {\n origin: \"result\",\n resultCause: primaryResult.cause,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: primaryResult,\n meta: { origin: \"result\", resultCause: primaryResult.cause },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: primaryResult.cause,\n });\n }\n\n // Run fallback\n let fallbackResult: Result<T, E2>;\n try {\n fallbackResult = await options.fallback();\n } catch (thrown) {\n if (isEarlyExitE(thrown)) {\n emitEvent({\n type: \"step_aborted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n throw thrown;\n }\n // Fallback threw — map via effectiveCatchUnexpected\n let mappedError: E | UnexpectedError;\n try {\n mappedError = effectiveCatchUnexpected(thrown) as E | UnexpectedError;\n } catch (mapperError) {\n throw createMapperException(mapperError);\n }\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: mappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(mappedError, { cause: thrown }),\n meta: { origin: \"throw\", thrown },\n });\n }\n onError?.(mappedError as E, stepName, context);\n throw earlyExit(mappedError as E, { origin: \"throw\", thrown });\n }\n\n if (fallbackResult.ok) {\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: fallbackResult,\n meta: { origin: \"fallback\" as const, fallbackUsed: true as const, fallbackReason: String(primaryError) },\n });\n }\n return fallbackResult.value;\n }\n\n // Fallback also returned an error\n const durationMs = performance.now() - startTime;\n const wrappedError = wrapForStep(fallbackResult.error, {\n origin: \"result\",\n resultCause: fallbackResult.cause,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: fallbackResult,\n meta: { origin: \"result\", resultCause: fallbackResult.cause },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: fallbackResult.cause,\n });\n })();\n };\n\n // step.withResource: Acquire/use/release lifecycle with guaranteed release\n stepFn.withResource = <T, R, AcquireE, UseE>(\n id: string,\n options: {\n acquire: () => AsyncResult<R, AcquireE>;\n use: (resource: R) => AsyncResult<T, UseE>;\n release: (resource: R) => void | Promise<void>;\n }\n ): Promise<T> => {\n if (typeof id !== 'string' || id.length === 0) {\n throw new Error(\n '[awaitly] step.withResource() requires an explicit string ID as the first argument. ' +\n 'Example: step.withResource(\"useDb\", { acquire: () => connect(), use: (db) => query(db), release: (db) => db.close() })'\n );\n }\n\n const stepKey = id;\n const stepName = id;\n const stepId = generateStepId(stepKey);\n const hasEventListeners = onEvent;\n\n return (async () => {\n const startTime = hasEventListeners ? performance.now() : 0;\n\n if (onEvent) {\n emitEvent({\n type: \"step_start\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n });\n }\n\n // Acquire\n let acquireResult: Result<R, AcquireE>;\n try {\n acquireResult = await options.acquire();\n } catch (thrown) {\n if (isEarlyExitE(thrown)) {\n emitEvent({\n type: \"step_aborted\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs: performance.now() - startTime,\n });\n throw thrown;\n }\n let mappedError: E | UnexpectedError;\n try {\n mappedError = effectiveCatchUnexpected(thrown) as E | UnexpectedError;\n } catch (mapperError) {\n throw createMapperException(mapperError);\n }\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: mappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(mappedError, { cause: thrown }),\n meta: { origin: \"throw\", thrown },\n });\n }\n onError?.(mappedError as E, stepName, context);\n throw earlyExit(mappedError as E, { origin: \"throw\", thrown });\n }\n\n if (!acquireResult.ok) {\n // Acquire failed — no release needed\n const durationMs = performance.now() - startTime;\n const wrappedError = wrapForStep(acquireResult.error, {\n origin: \"result\",\n resultCause: acquireResult.cause,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: acquireResult,\n meta: { origin: \"result\", resultCause: acquireResult.cause },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: acquireResult.cause,\n });\n }\n\n const resource = acquireResult.value;\n let useResult: Result<T, UseE> | undefined;\n let useThrown: unknown;\n let useThrewNonResult = false;\n\n // Use\n try {\n useResult = await options.use(resource);\n } catch (thrown) {\n if (isEarlyExitE(thrown)) {\n // Release before propagating\n try {\n await options.release(resource);\n } catch (releaseErr) {\n console.warn(\n `[awaitly] step.withResource(\"${id}\"): release threw after earlyExit:`,\n releaseErr\n );\n }\n throw thrown;\n }\n useThrown = thrown;\n useThrewNonResult = true;\n }\n\n // Release — ALWAYS runs after use (unless acquire failed)\n try {\n await options.release(resource);\n } catch (releaseErr) {\n console.warn(\n `[awaitly] step.withResource(\"${id}\"): release threw:`,\n releaseErr\n );\n }\n\n // Emit events AFTER release completes\n if (useThrewNonResult) {\n let mappedError: E | UnexpectedError;\n try {\n mappedError = effectiveCatchUnexpected(useThrown) as E | UnexpectedError;\n } catch (mapperError) {\n throw createMapperException(mapperError);\n }\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: mappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result: err(mappedError, { cause: useThrown }),\n meta: { origin: \"throw\", thrown: useThrown },\n });\n }\n onError?.(mappedError as E, stepName, context);\n throw earlyExit(mappedError as E, { origin: \"throw\", thrown: useThrown });\n }\n\n // useResult is defined if useThrewNonResult is false\n const result = useResult!;\n if (result.ok) {\n const durationMs = performance.now() - startTime;\n emitEvent({\n type: \"step_success\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result,\n });\n }\n return result.value;\n }\n\n // Use returned an error\n const durationMs = performance.now() - startTime;\n const wrappedError = wrapForStep(result.error, {\n origin: \"result\",\n resultCause: result.cause,\n });\n emitEvent({\n type: \"step_error\",\n workflowId,\n stepId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n error: wrappedError,\n });\n if (stepKey) {\n emitEvent({\n type: \"step_complete\",\n workflowId,\n stepKey,\n name: stepName,\n ts: Date.now(),\n durationMs,\n result,\n meta: { origin: \"result\", resultCause: result.cause },\n });\n }\n onError?.(wrappedError as unknown as E, stepName, context);\n throw earlyExit(wrappedError as unknown as E, {\n origin: \"result\",\n resultCause: result.cause,\n });\n })();\n };\n\n const step = stepFn as RunStep<E | UnexpectedError>;\n const value = await fn({ step });\n\n // Dev-only warning: Detect common mistake of returning ok() or err() from executor\n if (\n process.env.NODE_ENV !== \"production\" &&\n value !== null &&\n typeof value === \"object\" &&\n \"ok\" in value &&\n typeof (value as { ok: unknown }).ok === \"boolean\"\n ) {\n const maybeResult = value as { ok: boolean; value?: unknown; error?: unknown };\n if (\n (maybeResult.ok === true && \"value\" in maybeResult) ||\n (maybeResult.ok === false && \"error\" in maybeResult)\n ) {\n console.warn(\n `awaitly: Workflow executor returned a Result-like object. ` +\n `Return raw values, not ok() or err().\\n\\n` +\n ` Incorrect: return ok({ data });\\n` +\n ` Correct: return { data };\\n\\n` +\n `See: https://jagreehal.github.io/awaitly/guides/troubleshooting/#returning-ok-from-workflow-executor-double-wrapping`\n );\n }\n }\n\n return ok(value);\n } catch (error) {\n // If a catchUnexpected mapper threw, propagate without re-processing\n if (isMapperException(error)) {\n throw error.thrown;\n }\n\n if (isEarlyExitE(error)) {\n // Extract original cause from early exit metadata\n const originalCause = error.meta.origin === \"throw\"\n ? error.meta.thrown\n : error.meta.origin === \"result\"\n ? error.meta.resultCause\n : undefined;\n\n return err(error.error, { cause: originalCause });\n }\n\n const mapped = effectiveCatchUnexpected(error);\n onError?.(mapped as E, \"unexpected\", context);\n return err(mapped, { cause: error });\n }\n}\n\n/**\n * Convenience for run() with catchUnexpected: closed union Result<T, E>.\n * You must provide catchUnexpected to map uncaught exceptions to E.\n */\nrun.strict = <T, E, C = void>(\n fn: (context: { step: RunStep<E> }) => Promise<T> | T,\n options: {\n onError?: (error: E, stepName?: string, ctx?: C) => void;\n /**\n * Listener for workflow events (start, success, error, step events).\n *\n * Note: Context is available both on `event.context` and as the separate `ctx` parameter.\n * The `ctx` parameter is provided for convenience and backward compatibility.\n */\n onEvent?: (event: WorkflowEvent<E | UnexpectedError, C>, ctx: C) => void;\n catchUnexpected: (cause: unknown) => E;\n workflowId?: string;\n context?: C;\n /** @internal External signal for workflow-level cancellation. */\n _workflowSignal?: AbortSignal;\n }\n): AsyncResult<T, E, unknown> => {\n return run<T, E, C>(fn, options);\n};\n\n// =============================================================================\n// Unwrap Utilities\n// =============================================================================\n\n/**\n * Error thrown when `unwrap()` is called on an error Result.\n *\n * This error is thrown to prevent silent failures when using `unwrap()`.\n * Prefer using `unwrapOr`, `unwrapOrElse`, or pattern matching with `match` or `isOk`/`isErr`.\n */\nexport class UnwrapError<E = unknown, C = unknown> extends Error {\n constructor(\n public readonly error: E,\n public readonly cause?: C\n ) {\n super(`Unwrap called on an error result: ${String(error)}`);\n this.name = \"UnwrapError\";\n }\n}\n\n/**\n * Unwraps a Result, throwing an error if it's a failure.\n *\n * @remarks When to use: Only at boundaries or tests where a failure should be fatal.\n *\n * ## When to Use\n *\n * Use `unwrap()` when:\n * - You're certain the Result is successful (e.g., after checking with `isOk`)\n * - You're in a context where errors should crash (e.g., tests, initialization)\n * - You need the value immediately and can't handle errors gracefully\n *\n * ## Why Avoid This\n *\n * **Prefer alternatives** in production code:\n * - `unwrapOr(defaultValue)` - Provide a fallback value\n * - `unwrapOrElse(fn)` - Compute fallback from error\n * - `match()` - Handle both cases explicitly\n * - `isOk()` / `isErr()` - Type-safe pattern matching\n *\n * Throwing errors makes error handling harder and can crash your application.\n *\n * @param r - The Result to unwrap\n * @returns The success value if the Result is successful\n * @throws {UnwrapError} If the Result is an error (includes the error and cause)\n *\n * @example\n * ```typescript\n * // Safe usage after checking\n * const result = someOperation();\n * if (isOk(result)) {\n * const value = unwrap(result); // Safe - we know it's ok\n * }\n *\n * // Unsafe usage (not recommended)\n * const value = unwrap(someOperation()); // May throw!\n * ```\n */\nexport const unwrap = <T, E, C>(r: Result<T, E, C>): T => {\n if (r.ok) return r.value;\n throw new UnwrapError<E, C>(r.error, r.cause);\n};\n\n/**\n * Unwraps a Result, returning a default value if it's a failure.\n *\n * @remarks When to use: Provide a safe fallback without branching.\n *\n * ## When to Use\n *\n * Use `unwrapOr()` when:\n * - You have a sensible default value for errors\n * - You want to continue execution even on failure\n * - The default value is cheap to compute (use `unwrapOrElse` if expensive)\n *\n * ## Why Use This\n *\n * - **Safe**: Never throws, always returns a value\n * - **Simple**: One-liner for common error handling\n * - **Type-safe**: TypeScript knows you'll always get a `T`\n *\n * @param r - The Result to unwrap\n * @param defaultValue - The value to return if the Result is an error\n * @returns The success value if successful, otherwise the default value\n *\n * @example\n * ```typescript\n * // Provide default for missing data\n * const user = unwrapOr(fetchUser(id), { id: 'anonymous', name: 'Guest' });\n *\n * // Provide default for numeric operations\n * const count = unwrapOr(parseCount(input), 0);\n *\n * // Provide default for optional features\n * const config = unwrapOr(loadConfig(), getDefaultConfig());\n * ```\n */\nexport const unwrapOr = <T, E, C>(r: Result<T, E, C>, defaultValue: T): T =>\n r.ok ? r.value : defaultValue;\n\n/**\n * Unwraps a Result, computing a default value from the error if it's a failure.\n *\n * @remarks When to use: Compute a fallback from the error (logging, metrics, or derived defaults).\n *\n * ## When to Use\n *\n * Use `unwrapOrElse()` when:\n * - The default value is expensive to compute (lazy evaluation)\n * - You need to log or handle the error before providing a default\n * - The default depends on the error type or cause\n * - You want to transform the error into a success value\n *\n * ## Why Use This Instead of `unwrapOr`\n *\n * - **Lazy**: Default is only computed if needed (better performance)\n * - **Error-aware**: You can inspect the error before providing default\n * - **Flexible**: Default can depend on error type or cause\n *\n * @param r - The Result to unwrap\n * @param fn - Function that receives the error and optional cause, returns the default value\n * @returns The success value if successful, otherwise the result of calling `fn(error, cause)`\n *\n * @example\n * ```typescript\n * // Compute default based on error type\n * const port = unwrapOrElse(parsePort(env.PORT), (error) => {\n * if (error === 'INVALID_FORMAT') return 3000;\n * if (error === 'OUT_OF_RANGE') return 8080;\n * return 4000; // default\n * });\n *\n * // Log error before providing default\n * const data = unwrapOrElse(fetchData(), (error, cause) => {\n * console.error('Failed to fetch:', error, cause);\n * return getCachedData();\n * });\n *\n * // Transform error into success value\n * const result = unwrapOrElse(operation(), (error) => {\n * return { success: false, reason: String(error) };\n * });\n * ```\n */\nexport const unwrapOrElse = <T, E, C>(\n r: Result<T, E, C>,\n fn: (error: E, cause?: C) => T\n): T => (r.ok ? r.value : fn(r.error, r.cause));\n\n/**\n * Alias for `unwrap`. Returns the success value or throws.\n *\n * The Result is already computed; use when you want the value or throw (e.g. at boundaries or in tests).\n *\n * @param r - The Result to unwrap\n * @returns The success value if the Result is successful\n * @throws {UnwrapError} If the Result is an error (includes the error and cause)\n */\nexport const runOrThrow = <T, E, C>(r: Result<T, E, C>): T => unwrap(r);\n\n/**\n * Awaits a Promise of a Result, then returns the success value or rejects.\n *\n * The returned promise **resolves with T** on success and **rejects with UnwrapError** on failure.\n * UnwrapError extends Error and carries the original `error` and `cause` from the Err.\n *\n * @param ar - A Promise or thenable that resolves to a Result\n * @returns A Promise that resolves with the success value or rejects with UnwrapError\n */\nexport const runOrThrowAsync = <T, E, C>(\n ar: PromiseLike<Result<T, E, C>>\n): Promise<T> => Promise.resolve(ar).then(unwrap);\n\n/**\n * Convenience alias for `unwrapOr(r, null)`. Returns the success value or null.\n *\n * @param r - The Result to unwrap\n * @returns The success value if successful, otherwise null\n */\nexport const runOrNull = <T, E, C>(r: Result<T, E, C>): T | null =>\n r.ok ? r.value : null;\n\n/**\n * Convenience alias for `unwrapOr(r, undefined)`. Returns the success value or undefined.\n *\n * @param r - The Result to unwrap\n * @returns The success value if successful, otherwise undefined\n */\nexport const runOrUndefined = <T, E, C>(r: Result<T, E, C>): T | undefined =>\n r.ok ? r.value : undefined;\n\n// =============================================================================\n// Wrapping Functions\n// =============================================================================\n\n/**\n * Wraps a synchronous throwing function in a Result.\n *\n * @remarks When to use: Wrap sync code that might throw so exceptions become Err values.\n *\n * ## When to Use\n *\n * Use `from()` when:\n * - You have a synchronous function that throws exceptions\n * - You want to convert exceptions to typed errors\n * - You're integrating with libraries that throw (e.g., JSON.parse, fs.readFileSync)\n * - You need to handle errors without try/catch blocks\n *\n * ## Why Use This\n *\n * - **Type-safe errors**: Convert thrown exceptions to typed Result errors\n * - **No try/catch**: Cleaner code without nested try/catch blocks\n * - **Composable**: Results can be chained with `andThen`, `map`, etc.\n * - **Explicit errors**: Forces you to handle errors explicitly\n *\n * @param fn - The synchronous function to execute (may throw)\n * @returns A Result with the function's return value or the thrown error\n *\n * @example\n * ```typescript\n * // Wrap JSON.parse\n * const parsed = from(() => JSON.parse('{\"key\": \"value\"}'));\n * // parsed: { ok: true, value: { key: \"value\" } }\n *\n * const error = from(() => JSON.parse('invalid'));\n * // error: { ok: false, error: SyntaxError }\n * ```\n */\nexport function from<T>(fn: () => T): Ok<T> | Err<unknown, unknown>;\n/**\n * Wraps a synchronous throwing function in a Result with custom error mapping.\n *\n * Use this overload when you want to map thrown exceptions to your typed error union.\n *\n * @param fn - The synchronous function to execute (may throw)\n * @param onError - Function to map the thrown exception to a typed error\n * @returns A Result with the function's return value or the mapped error\n *\n * @example\n * ```typescript\n * // Map exceptions to typed errors\n * const parsed = from(\n * () => JSON.parse(input),\n * (cause) => ({ type: 'PARSE_ERROR' as const, cause })\n * );\n * // parsed.error: { type: 'PARSE_ERROR', cause: SyntaxError }\n *\n * // Map to simple error codes\n * const value = from(\n * () => riskyOperation(),\n * () => 'OPERATION_FAILED' as const\n * );\n * ```\n */\nexport function from<T, E>(fn: () => T, onError: (cause: unknown) => E): Ok<T> | Err<E, unknown>;\nexport function from<T, E>(fn: () => T, onError?: (cause: unknown) => E) {\n try {\n return ok(fn());\n } catch (cause) {\n return onError ? err(onError(cause), { cause }) : err(cause);\n }\n}\n\n/**\n * Wraps a Promise in a Result, converting rejections to errors.\n *\n * @remarks When to use: Wrap a Promise and keep the raw rejection as Err; use tryAsync to map errors.\n *\n * ## When to Use\n *\n * Use `fromPromise()` when:\n * - You have an existing Promise that might reject\n * - You want to convert Promise rejections to typed errors\n * - You're working with libraries that return Promises (fetch, database clients)\n * - You need to handle rejections without .catch() chains\n *\n * ## Why Use This\n *\n * - **Type-safe errors**: Convert Promise rejections to typed Result errors\n * - **Composable**: Results can be chained with `andThen`, `map`, etc.\n * - **Explicit handling**: Forces you to handle errors explicitly\n * - **No .catch() chains**: Cleaner than Promise.catch() patterns\n *\n * @param promise - The Promise to await (may reject)\n * @returns A Promise resolving to a Result with the resolved value or rejection reason\n *\n * @example\n * ```typescript\n * // Wrap fetch\n * const result = await fromPromise(\n * fetch('/api').then(r => r.json())\n * );\n * // result.ok: true if fetch succeeded, false if rejected\n * ```\n */\nexport function fromPromise<T>(promise: Promise<T>): Promise<Ok<T> | Err<unknown, unknown>>;\n/**\n * Wraps a Promise in a Result with custom error mapping.\n *\n * Use this overload when you want to map Promise rejections to your typed error union.\n *\n * @param promise - The Promise to await (may reject)\n * @param onError - Function to map the rejection reason to a typed error\n * @returns A Promise resolving to a Result with the resolved value or mapped error\n *\n * @example\n * ```typescript\n * // Map fetch errors to typed errors\n * const result = await fromPromise(\n * fetch('/api').then(r => {\n * if (!r.ok) throw new Error(`HTTP ${r.status}`);\n * return r.json();\n * }),\n * () => 'FETCH_FAILED' as const\n * );\n * // result.error: 'FETCH_FAILED' if fetch failed\n *\n * // Map with error details\n * const data = await fromPromise(\n * db.query(sql),\n * (cause) => ({ type: 'DB_ERROR' as const, message: String(cause) })\n * );\n * ```\n */\nexport function fromPromise<T, E>(\n promise: Promise<T>,\n onError: (cause: unknown) => E\n): Promise<Ok<T> | Err<E, unknown>>;\nexport async function fromPromise<T, E>(\n promise: Promise<T>,\n onError?: (cause: unknown) => E\n): Promise<Ok<T> | Err<E, unknown> | Err<unknown, unknown>> {\n try {\n return ok(await promise);\n } catch (cause) {\n return onError ? err(onError(cause), { cause }) : err(cause);\n }\n}\n\n/**\n * Wraps an async function in a Result, catching both thrown exceptions and Promise rejections.\n *\n * @remarks When to use: Wrap async work and map thrown/rejected values into your typed error union.\n *\n * ## When to Use\n *\n * Use `tryAsync()` when:\n * - You have an async function that might throw or reject\n * - You want to convert both exceptions and rejections to typed errors\n * - You're creating new async functions (use `fromPromise` for existing Promises)\n * - You need to handle errors without try/catch or .catch()\n *\n * ## Why Use This Instead of `fromPromise`\n *\n * - **Function form**: Takes a function, not a Promise (lazy evaluation)\n * - **Catches both**: Handles both thrown exceptions and Promise rejections\n * - **Cleaner syntax**: No need to wrap in Promise manually\n *\n * @param fn - The async function to execute (may throw or reject)\n * @returns A Promise resolving to a Result with the function's return value or error\n *\n * @example\n * ```typescript\n * // Wrap async function\n * const result = await tryAsync(async () => {\n * const data = await fetchData();\n * return processData(data);\n * });\n * ```\n */\nexport function tryAsync<T>(fn: () => Promise<T>): AsyncResult<T, unknown>;\n/**\n * Wraps an async function in a Result with custom error mapping.\n *\n * Use this overload when you want to map errors to your typed error union.\n *\n * @param fn - The async function to execute (may throw or reject)\n * @param onError - Function to map the error (exception or rejection) to a typed error\n * @returns A Promise resolving to a Result with the function's return value or mapped error\n *\n * @example\n * ```typescript\n * // Map errors to typed errors\n * const result = await tryAsync(\n * async () => await fetchData(),\n * () => 'FETCH_ERROR' as const\n * );\n *\n * // Map with error details\n * const data = await tryAsync(\n * async () => await processFile(path),\n * (cause) => ({ type: 'PROCESSING_ERROR' as const, cause })\n * );\n * ```\n */\nexport function tryAsync<T, E>(\n fn: () => Promise<T>,\n onError: (cause: unknown) => E\n): AsyncResult<T, E>;\nexport async function tryAsync<T, E>(\n fn: () => Promise<T>,\n onError?: (cause: unknown) => E\n): AsyncResult<T, E | unknown> {\n try {\n return ok(await fn());\n } catch (cause) {\n return onError ? err(onError(cause), { cause }) : err(cause);\n }\n}\n\n/**\n * Converts a nullable value to a Result.\n *\n * @remarks When to use: Turn null/undefined into a typed error before continuing.\n *\n * ## When to Use\n *\n * Use `fromNullable()` when:\n * - You have a value that might be `null` or `undefined`\n * - You want to treat null/undefined as an error case\n * - You're working with APIs that return nullable values (DOM APIs, optional properties)\n * - You want to avoid null checks scattered throughout your code\n *\n * ## Why Use This\n *\n * - **Type-safe**: Converts nullable types to non-nullable Results\n * - **Explicit errors**: Forces you to handle null/undefined cases\n * - **Composable**: Results can be chained with `andThen`, `map`, etc.\n * - **No null checks**: Eliminates need for `if (value == null)` checks\n *\n * @param value - The value that may be null or undefined\n * @param onNull - Function that returns an error when value is null/undefined\n * @returns A Result with the value if not null/undefined, otherwise the error from `onNull`\n *\n * @example\n * ```typescript\n * // Convert DOM element lookup\n * const element = fromNullable(\n * document.getElementById('app'),\n * () => 'ELEMENT_NOT_FOUND' as const\n * );\n *\n * // Convert optional property\n * const userId = fromNullable(\n * user.id,\n * () => 'USER_ID_MISSING' as const\n * );\n *\n * // Convert database query result\n * const record = fromNullable(\n * await db.find(id),\n * () => ({ type: 'NOT_FOUND' as const, id })\n * );\n * ```\n */\nexport function fromNullable<T, E>(\n value: T | null | undefined,\n onNull: () => E\n): Result<T, E> {\n return value != null ? ok(value) : err(onNull());\n}\n\n// =============================================================================\n// Transformers\n// =============================================================================\n\n/**\n * Transforms the success value of a Result.\n *\n * @remarks When to use: Transform only the Ok value while leaving Err untouched.\n *\n * ## When to Use\n *\n * Use `map()` when:\n * - You need to transform a success value to another type\n * - You want to apply a pure function to the value\n * - You're building a pipeline of transformations\n * - The transformation cannot fail (use `andThen` if it can fail)\n *\n * ## Why Use This\n *\n * - **Functional style**: Composable, chainable transformations\n * - **Error-preserving**: Errors pass through unchanged\n * - **Type-safe**: TypeScript tracks the transformation\n * - **No unwrapping**: Avoids manual `if (r.ok)` checks\n *\n * @param r - The Result to transform\n * @param fn - Pure function that transforms the success value (must not throw)\n * @returns A new Result with the transformed value, or the original error if `r` was an error\n *\n * @example\n * ```typescript\n * // Transform numeric value\n * const doubled = map(ok(21), n => n * 2);\n * // doubled: { ok: true, value: 42 }\n *\n * // Transform object property\n * const name = map(fetchUser(id), user => user.name);\n *\n * // Chain transformations\n * const formatted = map(\n * map(parseNumber(input), n => n * 2),\n * n => `Result: ${n}`\n * );\n * ```\n */\nexport function map<T, U>(r: Ok<T>, fn: (value: T) => U): Ok<U>;\nexport function map<T, U, E, C>(r: Err<E, C>, fn: (value: T) => U): Err<E, C>;\nexport function map<T, U, E, C>(r: Result<T, E, C>, fn: (value: T) => U): Result<U, E, C>;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function map(r: any, fn: any): any {\n return r.ok ? ok(fn(r.value)) : r;\n}\n\n/**\n * Transforms the error value of a Result.\n *\n * @remarks When to use: Retype or normalize errors while leaving Ok values unchanged.\n *\n * ## When to Use\n *\n * Use `mapError()` when:\n * - You need to normalize or transform error types\n * - You want to convert errors to a different error type\n * - You're building error handling pipelines\n * - You need to format error messages or codes\n *\n * ## Why Use This\n *\n * - **Error normalization**: Convert errors to a common format\n * - **Type transformation**: Change error type while preserving value type\n * - **Composable**: Can be chained with other transformers\n * - **Success-preserving**: Success values pass through unchanged\n *\n * @param r - The Result to transform\n * @param fn - Function that transforms the error value (must not throw)\n * @returns A new Result with the original value, or the transformed error if `r` was an error\n *\n * @example\n * ```typescript\n * // Normalize error codes\n * const normalized = mapError(err('not_found'), e => e.toUpperCase());\n * // normalized: { ok: false, error: 'NOT_FOUND' }\n *\n * // Convert error types\n * const typed = mapError(\n * err('404'),\n * code => ({ type: 'HTTP_ERROR' as const, status: parseInt(code) })\n * );\n *\n * // Format error messages\n * const formatted = mapError(\n * err('PARSE_ERROR'),\n * code => `Failed to parse: ${code}`\n * );\n * ```\n */\nexport function mapError<T, E, F, C>(\n r: Result<T, E, C>,\n fn: (error: E) => F\n): Result<T, F, C> {\n return r.ok ? r : err(fn(r.error), { cause: r.cause });\n}\n\n/**\n * Pattern matches on a Result, calling the appropriate handler.\n *\n * @remarks When to use: Handle both Ok and Err in a single expression that returns a value.\n *\n * ## When to Use\n *\n * Use `match()` when:\n * - You need to handle both success and error cases\n * - You want to transform a Result to a different type\n * - You need exhaustive handling (both cases must be handled)\n * - You're building user-facing messages or responses\n *\n * ## Why Use This\n *\n * - **Exhaustive**: Forces you to handle both success and error cases\n * - **Type-safe**: TypeScript ensures both handlers are provided\n * - **Functional**: Pattern matching style, similar to Rust's `match` or Haskell's `case`\n * - **Single expression**: Can be used in expressions, not just statements\n *\n * @param r - The Result to match\n * @param handlers - Object with `ok` and `err` handler functions\n * @param handlers.ok - Function called with the success value\n * @param handlers.err - Function called with the error and optional cause\n * @returns The return value of the appropriate handler (both must return the same type `R`)\n *\n * @example\n * ```typescript\n * // Build user-facing messages\n * const message = match(result, {\n * ok: (user) => `Hello ${user.name}`,\n * err: (error) => `Error: ${error}`,\n * });\n *\n * // Transform to API response\n * const response = match(operation(), {\n * ok: (data) => ({ status: 200, body: data }),\n * err: (error) => ({ status: 400, error: String(error) }),\n * });\n *\n * // Handle with cause\n * const response = match(result, {\n * ok: (value) => ({ status: 'success', data: value }),\n * err: (error, cause) => ({ status: 'error', error, cause }),\n * });\n * ```\n */\nexport function match<T, E, C, R>(r: Ok<T>, handlers: { ok: (value: T) => R; err: (error: E, cause?: C) => R }): R;\nexport function match<T, E, C, R>(r: Err<E, C>, handlers: { ok: (value: T) => R; err: (error: E, cause?: C) => R }): R;\nexport function match<T, E, C, R>(r: Result<T, E, C>, handlers: { ok: (value: T) => R; err: (error: E, cause?: C) => R }): R;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function match(r: any, handlers: any): any {\n return r.ok ? handlers.ok(r.value) : handlers.err(r.error, r.cause);\n}\n\n/**\n * Chains Results together (flatMap/monadic bind).\n *\n * @remarks When to use: Chain dependent operations that return Result without nested branching.\n *\n * ## When to Use\n *\n * Use `andThen()` when:\n * - You need to chain operations that can fail\n * - The next operation depends on the previous success value\n * - You're building a pipeline of dependent operations\n * - You want to avoid nested `if (r.ok)` checks\n *\n * ## Why Use This Instead of `map`\n *\n * - **Can fail**: The chained function returns a Result (can fail)\n * - **Short-circuits**: If first Result fails, second operation never runs\n * - **Error accumulation**: Errors from both operations are in the union\n * - **Composable**: Can chain multiple operations together\n *\n * ## Common Pattern\n *\n * This is the fundamental building block for Result pipelines:\n * ```typescript\n * andThen(operation1(), value1 =>\n * andThen(operation2(value1), value2 =>\n * ok({ value1, value2 })\n * )\n * )\n * ```\n *\n * @param r - The first Result\n * @param fn - Function that takes the success value and returns a new Result (may fail)\n * @returns The Result from `fn` if `r` was successful, otherwise the original error\n *\n * @example\n * ```typescript\n * // Chain dependent operations\n * const userPosts = andThen(\n * fetchUser('1'),\n * user => fetchPosts(user.id)\n * );\n *\n * // Build complex pipelines\n * const result = andThen(parseInput(input), parsed =>\n * andThen(validate(parsed), validated =>\n * process(validated)\n * )\n * );\n *\n * // Chain with different error types\n * const data = andThen(\n * fetchUser(id), // Returns Result<User, 'FETCH_ERROR'>\n * user => fetchPosts(user.id) // Returns Result<Post[], 'NOT_FOUND'>\n * );\n * // data.error: 'FETCH_ERROR' | 'NOT_FOUND'\n * ```\n */\nexport function andThen<T, U>(r: Ok<T>, fn: (value: T) => Ok<U>): Ok<U>;\nexport function andThen<T, F, C2>(r: Ok<T>, fn: (value: T) => Err<F, C2>): Err<F, C2>;\nexport function andThen<T, U, F, C2>(r: Ok<T>, fn: (value: T) => Result<U, F, C2>): Result<U, F, C2>;\nexport function andThen<T, U, E, F, C1, C2>(r: Err<E, C1>, fn: (value: T) => Result<U, F, C2>): Err<E, C1>;\nexport function andThen<T, U, E, F, C1, C2>(r: Result<T, E, C1>, fn: (value: T) => Result<U, F, C2>): Result<U, E | F, C1 | C2>;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function andThen(r: any, fn: any): any {\n return r.ok ? fn(r.value) : r;\n}\n\n/**\n * Executes a side effect on a successful Result without changing it.\n *\n * @remarks When to use: Add side effects (logging, metrics) on Ok without changing the Result.\n *\n * ## When to Use\n *\n * Use `tap()` when:\n * - You need to log, debug, or observe success values\n * - You want to perform side effects in a pipeline\n * - You need to mutate external state based on success\n * - You're debugging and want to inspect values without breaking the chain\n *\n * ## Why Use This\n *\n * - **Non-breaking**: Doesn't change the Result, just performs side effect\n * - **Composable**: Can be inserted anywhere in a pipeline\n * - **Type-preserving**: Returns the same Result type\n * - **Lazy**: Side effect only runs if Result is successful\n *\n * @param r - The Result to tap\n * @param fn - Side effect function called with the success value (return value ignored)\n * @returns The original Result unchanged (for chaining)\n *\n * @example\n * ```typescript\n * // Log success values\n * const logged = tap(result, user => console.log('Got user:', user.name));\n * // logged === result, but console.log was called\n *\n * // Debug in pipeline\n * const debugged = pipe(\n * fetchUser(id),\n * r => tap(r, user => console.log('Fetched:', user)),\n * r => map(r, user => user.name)\n * );\n *\n * // Mutate external state\n * const tracked = tap(result, data => {\n * analytics.track('operation_success', data);\n * });\n * ```\n */\nexport function tap<T, E, C>(\n r: Result<T, E, C>,\n fn: (value: T) => void\n): Result<T, E, C> {\n if (r.ok) fn(r.value);\n return r;\n}\n\n/**\n * Executes a side effect on an error Result without changing it.\n *\n * @remarks When to use: Add side effects (logging, metrics) on Err without changing the Result.\n *\n * ## When to Use\n *\n * Use `tapError()` when:\n * - You need to log, debug, or observe error values\n * - You want to perform side effects on errors in a pipeline\n * - You need to report errors to external systems (logging, monitoring)\n * - You're debugging and want to inspect errors without breaking the chain\n *\n * ## Why Use This\n *\n * - **Non-breaking**: Doesn't change the Result, just performs side effect\n * - **Composable**: Can be inserted anywhere in a pipeline\n * - **Type-preserving**: Returns the same Result type\n * - **Lazy**: Side effect only runs if Result is an error\n *\n * @param r - The Result to tap\n * @param fn - Side effect function called with the error and optional cause (return value ignored)\n * @returns The original Result unchanged (for chaining)\n *\n * @example\n * ```typescript\n * // Log errors\n * const logged = tapError(result, (error, cause) => {\n * console.error('Error:', error, cause);\n * });\n *\n * // Report to error tracking\n * const tracked = tapError(result, (error, cause) => {\n * errorTracker.report(error, cause);\n * });\n *\n * // Debug in pipeline\n * const debugged = pipe(\n * operation(),\n * r => tapError(r, (err, cause) => console.error('Failed:', err)),\n * r => mapError(r, err => 'FORMATTED_ERROR')\n * );\n * ```\n */\nexport function tapError<T, E, C>(\n r: Result<T, E, C>,\n fn: (error: E, cause?: C) => void\n): Result<T, E, C> {\n if (!r.ok) fn(r.error, r.cause);\n return r;\n}\n\n/**\n * Transforms the success value of a Result, catching any errors thrown by the transform.\n *\n * @remarks When to use: Transform Ok values with a function that might throw and capture the failure.\n *\n * ## When to Use\n *\n * Use `mapTry()` when:\n * - Your transform function might throw exceptions\n * - You want to convert transform errors to typed errors\n * - You're working with libraries that throw (e.g., JSON.parse, Date parsing)\n * - You need to handle both Result errors and transform exceptions\n *\n * ## Why Use This Instead of `map`\n *\n * - **Exception-safe**: Catches exceptions from the transform function\n * - **Error mapping**: Converts thrown exceptions to typed errors\n * - **Dual error handling**: Handles both Result errors and transform exceptions\n *\n * @param result - The Result to transform\n * @param transform - Function to transform the success value (may throw exceptions)\n * @param onError - Function to map thrown exceptions to a typed error\n * @returns A Result with:\n * - Transformed value if both Result and transform succeed\n * - Original error if Result was an error\n * - Transform error if transform threw an exception\n *\n * @example\n * ```typescript\n * // Safe JSON parsing\n * const parsed = mapTry(\n * ok('{\"key\": \"value\"}'),\n * JSON.parse,\n * () => 'PARSE_ERROR' as const\n * );\n *\n * // Safe date parsing\n * const date = mapTry(\n * ok('2024-01-01'),\n * str => new Date(str),\n * () => 'INVALID_DATE' as const\n * );\n *\n * // Transform with error details\n * const processed = mapTry(\n * result,\n * value => riskyTransform(value),\n * (cause) => ({ type: 'TRANSFORM_ERROR' as const, cause })\n * );\n * ```\n */\nexport function mapTry<T, U, E, F, C>(\n result: Result<T, E, C>,\n transform: (value: T) => U,\n onError: (cause: unknown) => F\n): Result<U, E | F, C | unknown> {\n if (!result.ok) return result;\n try {\n return ok(transform(result.value));\n } catch (error) {\n return err(onError(error), { cause: error });\n }\n}\n\n/**\n * Transforms the error value of a Result, catching any errors thrown by the transform.\n *\n * @remarks When to use: Transform errors when the mapping might throw and you want that captured.\n *\n * ## When to Use\n *\n * Use `mapErrorTry()` when:\n * - Your error transform function might throw exceptions\n * - You're doing complex error transformations (e.g., string formatting, object construction)\n * - You want to handle both Result errors and transform exceptions\n * - You need to safely normalize error types\n *\n * ## Why Use This Instead of `mapError`\n *\n * - **Exception-safe**: Catches exceptions from the error transform function\n * - **Error mapping**: Converts thrown exceptions to typed errors\n * - **Dual error handling**: Handles both Result errors and transform exceptions\n *\n * @param result - The Result to transform\n * @param transform - Function to transform the error value (may throw exceptions)\n * @param onError - Function to map thrown exceptions to a typed error\n * @returns A Result with:\n * - Original value if Result was successful\n * - Transformed error if both Result was error and transform succeeded\n * - Transform error if transform threw an exception\n *\n * @example\n * ```typescript\n * // Safe error formatting\n * const formatted = mapErrorTry(\n * err('not_found'),\n * e => e.toUpperCase(), // Might throw if e is not a string\n * () => 'FORMAT_ERROR' as const\n * );\n *\n * // Complex error transformation\n * const normalized = mapErrorTry(\n * result,\n * error => ({ type: 'NORMALIZED', message: String(error) }),\n * () => 'TRANSFORM_ERROR' as const\n * );\n * ```\n */\nexport function mapErrorTry<T, E, F, G, C>(\n result: Result<T, E, C>,\n transform: (error: E) => F,\n onError: (cause: unknown) => G\n): Result<T, F | G, C | unknown> {\n if (result.ok) return result;\n try {\n return err(transform(result.error), { cause: result.cause });\n } catch (error) {\n return err(onError(error), { cause: error });\n }\n}\n\n/**\n * Transforms both the success value and error value of a Result simultaneously.\n *\n * ## When to Use\n *\n * Use `bimap()` when:\n * - You need to transform both success and error in one operation\n * - You're normalizing Results to a common format\n * - You want symmetric transformation of both cases\n * - You're building adapters between different Result types\n *\n * ## Why Use This Instead of `map` + `mapError`\n *\n * - **Single operation**: Transforms both cases in one call\n * - **Clearer intent**: Shows you're handling both cases symmetrically\n * - **Less code**: Avoids chaining map and mapError\n *\n * @param r - The Result to transform\n * @param onOk - Function that transforms the success value\n * @param onErr - Function that transforms the error value\n * @returns A new Result with transformed value or transformed error\n *\n * @example\n * ```typescript\n * // Normalize to API response format\n * const response = bimap(\n * fetchUser(id),\n * user => ({ status: 'success', data: user }),\n * error => ({ status: 'error', code: error })\n * );\n *\n * // Transform types\n * const stringified = bimap(\n * parseNumber(input),\n * n => `Value: ${n}`,\n * e => `Error: ${e}`\n * );\n *\n * // Adapt between error types\n * const adapted = bimap(\n * externalResult,\n * value => internalValue(value),\n * error => internalError(error)\n * );\n * ```\n */\nexport function bimap<T, U, E, F, C>(\n r: Result<T, E, C>,\n onOk: (value: T) => U,\n onErr: (error: E) => F\n): Result<U, F, C> {\n return r.ok ? ok(onOk(r.value)) : err(onErr(r.error), { cause: r.cause });\n}\n\n/**\n * Recovers from an error by returning a new Result.\n * Similar to neverthrow's `.orElse()`.\n *\n * @remarks When to use: Recover from Err by returning a fallback Result or retyping the error.\n *\n * ## When to Use\n *\n * Use `orElse()` when:\n * - You want to recover from errors with fallback operations\n * - The recovery might also fail (returns a Result)\n * - You need to chain fallback strategies\n * - You're implementing retry or fallback patterns\n *\n * ## Why Use This\n *\n * - **Fallback chains**: Try alternative operations on failure\n * - **Error recovery**: Convert errors to success with fallback values\n * - **Composable**: Can chain multiple orElse calls for cascading fallbacks\n * - **Type-safe**: TypeScript tracks the error union through recovery\n *\n * @param r - The Result to potentially recover from\n * @param fn - Function that takes the error and returns a new Result (may succeed or fail)\n * @returns The original Result if successful, or the result of the recovery function\n *\n * @example\n * ```typescript\n * // Fallback to default user\n * const user = orElse(\n * fetchUser(id),\n * error => error === 'NOT_FOUND' ? ok(defaultUser) : err(error)\n * );\n *\n * // Try cache, then database, then fail\n * const data = orElse(\n * orElse(\n * fetchFromCache(key),\n * () => fetchFromDatabase(key)\n * ),\n * () => err('DATA_UNAVAILABLE' as const)\n * );\n *\n * // Convert specific errors to success\n * const result = orElse(\n * riskyOperation(),\n * error => error.code === 'RETRY' ? ok(defaultValue) : err(error)\n * );\n * ```\n */\nexport function orElse<T, E, E2, C, C2>(\n r: Result<T, E, C>,\n fn: (error: E, cause?: C) => Result<T, E2, C2>\n): Result<T, E2, C2> {\n return r.ok ? r : fn(r.error, r.cause);\n}\n\n/**\n * Async version of orElse for recovering from errors with async operations.\n *\n * @param r - The Result or AsyncResult to potentially recover from\n * @param fn - Async function that takes the error and returns a new Result\n * @returns Promise of the original Result if successful, or the result of the recovery function\n *\n * @example\n * ```typescript\n * // Try primary API, fall back to secondary\n * const data = await orElseAsync(\n * await fetchFromPrimaryApi(),\n * async (error) => {\n * if (error === 'UNAVAILABLE') {\n * return await fetchFromSecondaryApi();\n * }\n * return err(error);\n * }\n * );\n * ```\n */\nexport async function orElseAsync<T, E, E2, C, C2>(\n r: Result<T, E, C> | Promise<Result<T, E, C>>,\n fn: (error: E, cause?: C) => Result<T, E2, C2> | Promise<Result<T, E2, C2>>\n): Promise<Result<T, E2, C2>> {\n const resolved = await r;\n return resolved.ok ? resolved : fn(resolved.error, resolved.cause);\n}\n\n/**\n * Recovers from an error by returning a plain value (not a Result).\n * Useful when you want to provide a default value on error.\n *\n * ## When to Use\n *\n * Use `recover()` when:\n * - You want to provide a fallback value on error\n * - Recovery cannot fail (unlike orElse which returns a Result)\n * - You're implementing default value patterns\n * - You want to guarantee a successful Result\n *\n * ## Why Use This Instead of `orElse`\n *\n * - **Simpler**: Recovery function returns plain value, not Result\n * - **Guaranteed success**: Always returns ok() after recovery\n * - **Clearer intent**: Shows recovery cannot fail\n *\n * @param r - The Result to potentially recover from\n * @param fn - Function that takes the error and returns a recovery value\n * @returns The original Result if successful, or ok(recoveryValue) if error\n *\n * @example\n * ```typescript\n * // Provide default user on NOT_FOUND\n * const user = recover(\n * fetchUser(id),\n * error => error === 'NOT_FOUND' ? defaultUser : guestUser\n * );\n *\n * // Convert all errors to default\n * const config = recover(\n * loadConfig(),\n * () => defaultConfig\n * );\n *\n * // Recover with error-based defaults\n * const value = recover(\n * parseNumber(input),\n * error => error === 'EMPTY' ? 0 : -1\n * );\n * ```\n */\nexport function recover<T, E, C>(\n r: Result<T, E, C>,\n fn: (error: E, cause?: C) => T\n): Ok<T> {\n return r.ok ? ok(r.value) : ok(fn(r.error, r.cause));\n}\n\n/**\n * Async version of recover for recovering with async operations.\n *\n * @param r - The Result or AsyncResult to potentially recover from\n * @param fn - Async function that takes the error and returns a recovery value\n * @returns Promise of ok(value) - either original or recovered\n *\n * @example\n * ```typescript\n * // Recover by fetching default from API\n * const user = await recoverAsync(\n * await fetchUser(id),\n * async (error) => await fetchDefaultUser()\n * );\n * ```\n */\nexport async function recoverAsync<T, E, C>(\n r: Result<T, E, C> | Promise<Result<T, E, C>>,\n fn: (error: E, cause?: C) => T | Promise<T>\n): Promise<Ok<T>> {\n const resolved = await r;\n if (resolved.ok) return ok(resolved.value);\n return ok(await fn(resolved.error, resolved.cause));\n}\n\n// =============================================================================\n// Result Hydration (Serialization)\n// =============================================================================\n\n/**\n * Validates and type-narrows a value to a Result.\n *\n * Since this library uses plain objects for Results, serialization is trivial -\n * the serialized form IS the Result. This function validates the structure and\n * provides type-safe narrowing.\n *\n * ## When to Use\n *\n * Use `hydrate()` when:\n * - Receiving Results over RPC/network\n * - Deserializing Results from storage\n * - Validating untrusted data as Results\n *\n * @param value - The unknown value to validate as a Result\n * @returns The value as a typed Result, or null if invalid\n *\n * @example\n * ```typescript\n * // Deserialize from JSON\n * const parsed = JSON.parse(jsonString);\n * const result = hydrate<User, ApiError>(parsed);\n * if (result) {\n * // result is Result<User, ApiError>\n * }\n *\n * // Validate RPC response\n * const rpcResponse = await fetchFromService();\n * const result = hydrate<Data, ServiceError>(rpcResponse);\n * ```\n */\nexport function hydrate<T, E, C = unknown>(value: unknown): Result<T, E, C> | null {\n if (\n value !== null &&\n typeof value === \"object\" &&\n \"ok\" in value &&\n typeof value.ok === \"boolean\"\n ) {\n if (value.ok === true && \"value\" in value) {\n return value as Result<T, E, C>;\n }\n if (value.ok === false && \"error\" in value) {\n return value as Result<T, E, C>;\n }\n }\n return null;\n}\n\n/**\n * Type guard to check if a value is a valid serialized Result.\n *\n * @param value - The value to check\n * @returns True if the value is a valid Result structure\n *\n * @example\n * ```typescript\n * if (isSerializedResult(data)) {\n * // data is Result<unknown, unknown, unknown>\n * if (data.ok) {\n * console.log(data.value);\n * }\n * }\n * ```\n */\nexport function isSerializedResult(\n value: unknown\n): value is Result<unknown, unknown, unknown> {\n return hydrate(value) !== null;\n}\n\n// =============================================================================\n// Batch Operations\n// =============================================================================\n\ntype AllValues<T extends readonly Result<unknown, unknown, unknown>[]> = {\n [K in keyof T]: T[K] extends Ok<infer V>\n ? V\n : T[K] extends Err<unknown, unknown>\n ? never\n : T[K] extends Result<infer V, unknown, unknown>\n ? V\n : never;\n};\ntype AllErrors<T extends readonly Result<unknown, unknown, unknown>[]> = {\n [K in keyof T]: T[K] extends Ok<unknown>\n ? never\n : T[K] extends Err<infer E, unknown>\n ? E\n : T[K] extends Result<unknown, infer E, unknown>\n ? E\n : never;\n}[number];\ntype AllCauses<T extends readonly Result<unknown, unknown, unknown>[]> = {\n [K in keyof T]: T[K] extends Ok<unknown>\n ? never\n : T[K] extends Err<unknown, infer C>\n ? C\n : T[K] extends Result<unknown, unknown, infer C>\n ? C\n : never;\n}[number];\n\n// Conditional type: returns Ok<...> when there are no errors, Result<...> otherwise\n// Note: We only check AllErrors, not AllCauses - causes only matter when there are errors\ntype AllResult<T extends readonly Result<unknown, unknown, unknown>[]> =\n [AllErrors<T>] extends [never]\n ? Ok<AllValues<T>>\n : Result<AllValues<T>, AllErrors<T>, AllCauses<T>>;\n\n/**\n * Combines multiple Results into one, requiring all to succeed.\n *\n * ## When to Use\n *\n * Use `all()` when:\n * - You have multiple independent operations that all must succeed\n * - You want to short-circuit on the first error (fail-fast)\n * - You need all values together (e.g., combining API responses)\n * - Performance matters (stops on first error, doesn't wait for all)\n *\n * ## Why Use This\n *\n * - **Fail-fast**: Stops immediately on first error (better performance)\n * - **Type-safe**: TypeScript infers the array type from input\n * - **Short-circuit**: Doesn't evaluate remaining Results after error\n * - **Composable**: Can be chained with other operations\n *\n * ## Important\n *\n * - **Short-circuits**: Returns first error immediately, doesn't wait for all Results\n * - **All must succeed**: If any Result fails, the entire operation fails\n * - **Use `allSettled`**: If you need to collect all errors (e.g., form validation)\n *\n * @param results - Array of Results to combine (all must succeed)\n * @returns A Result with an array of all success values, or the first error encountered\n *\n * @example\n * ```typescript\n * // Combine multiple successful Results\n * const combined = all([Awaitly.ok(1), Awaitly.ok(2), Awaitly.ok(3)]);\n * // combined: { ok: true, value: [1, 2, 3] }\n *\n * // Short-circuits on first error\n * const error = all([Awaitly.ok(1), Awaitly.err('ERROR'), Awaitly.ok(3)]);\n * // error: { ok: false, error: 'ERROR' }\n * // Note: Awaitly.ok(3) is never evaluated\n *\n * // Combine API responses\n * const data = all([\n * fetchUser(id),\n * fetchPosts(id),\n * fetchComments(id)\n * ]);\n * // data.value: [user, posts, comments] if all succeed\n * ```\n */\nexport function all<const T extends readonly Result<unknown, unknown, unknown>[]>(\n results: T\n): AllResult<T> {\n const values: unknown[] = [];\n for (const result of results) {\n if (!result.ok) {\n return result as unknown as AllResult<T>;\n }\n values.push(result.value);\n }\n return ok(values) as AllResult<T>;\n}\n\n/**\n * Combines multiple Results or Promises of Results into one (async version of `all`).\n *\n * ## When to Use\n *\n * Use `allAsync()` when:\n * - You have multiple async operations that all must succeed\n * - You want to run operations in parallel (better performance)\n * - You want to short-circuit on the first error (fail-fast)\n * - You need all values together from parallel operations\n *\n * ## Why Use This Instead of `all`\n *\n * - **Parallel execution**: All Promises start immediately (faster)\n * - **Async support**: Works with Promises and AsyncResults\n * - **Promise rejection handling**: Converts Promise rejections to `PromiseRejectedError`\n *\n * ## Important\n *\n * - **Short-circuits**: Returns first error immediately, cancels remaining operations\n * - **Parallel**: All operations start simultaneously (unlike sequential `andThen`)\n * - **Use `allSettledAsync`**: If you need to collect all errors\n *\n * @param results - Array of Results or Promises of Results to combine (all must succeed)\n * @returns A Promise resolving to a Result with an array of all success values, or the first error\n *\n * @example\n * ```typescript\n * // Parallel API calls\n * const combined = await allAsync([\n * fetchUser('1'),\n * fetchPosts('1'),\n * fetchComments('1')\n * ]);\n * // All three calls start simultaneously\n * // combined: { ok: true, value: [user, posts, comments] } if all succeed\n *\n * // Mix Results and Promises\n * const data = await allAsync([\n * ok(cachedUser), // Already resolved\n * fetchPosts(userId), // Promise\n * ]);\n * ```\n */\nexport async function allAsync<\n const T extends readonly (Result<unknown, unknown, unknown> | Promise<Result<unknown, unknown, unknown>>)[]\n>(\n results: T\n): Promise<\n Result<\n { [K in keyof T]: T[K] extends Result<infer V, unknown, unknown> | Promise<Result<infer V, unknown, unknown>> ? V : never },\n { [K in keyof T]: T[K] extends Result<unknown, infer E, unknown> | Promise<Result<unknown, infer E, unknown>> ? E : never }[number] | PromiseRejectedError,\n { [K in keyof T]: T[K] extends Result<unknown, unknown, infer C> | Promise<Result<unknown, unknown, infer C>> ? C : never }[number] | PromiseRejectionCause\n >\n> {\n type Values = { [K in keyof T]: T[K] extends Result<infer V, unknown, unknown> | Promise<Result<infer V, unknown, unknown>> ? V : never };\n type Errors = { [K in keyof T]: T[K] extends Result<unknown, infer E, unknown> | Promise<Result<unknown, infer E, unknown>> ? E : never }[number] | PromiseRejectedError;\n type Causes = { [K in keyof T]: T[K] extends Result<unknown, unknown, infer C> | Promise<Result<unknown, unknown, infer C>> ? C : never }[number] | PromiseRejectionCause;\n\n if (results.length === 0) {\n return ok([]) as Result<Values, Errors, Causes>;\n }\n\n return new Promise((resolve) => {\n let settled = false;\n let pendingCount = results.length;\n const values: unknown[] = new Array(results.length);\n\n for (let i = 0; i < results.length; i++) {\n const index = i;\n Promise.resolve(results[index])\n .catch((reason) => err(\n { type: \"PROMISE_REJECTED\" as const, cause: reason },\n { cause: { type: \"PROMISE_REJECTION\" as const, reason } as PromiseRejectionCause }\n ))\n .then((result) => {\n if (settled) return;\n\n if (!result.ok) {\n settled = true;\n resolve(result as Result<Values, Errors, Causes>);\n return;\n }\n\n values[index] = result.value;\n pendingCount--;\n\n if (pendingCount === 0) {\n resolve(ok(values) as Result<Values, Errors, Causes>);\n }\n });\n }\n });\n}\n\nexport type SettledError<E, C = unknown> = { error: E; cause?: C };\n\n// Conditional type: returns Ok<...> when there are no errors, Result<...> otherwise\ntype AllSettledResult<T extends readonly Result<unknown, unknown, unknown>[]> =\n [AllErrors<T>] extends [never]\n ? Ok<AllValues<T>>\n : Result<AllValues<T>, SettledError<AllErrors<T>, AllCauses<T>>[]>;\n\n/**\n * Combines multiple Results, collecting all errors instead of short-circuiting.\n *\n * ## When to Use\n *\n * Use `allSettled()` when:\n * - You need to see ALL errors, not just the first one\n * - You're doing form validation (show all field errors)\n * - You want to collect partial results (some succeed, some fail)\n * - You need to process all Results regardless of failures\n *\n * ## Why Use This Instead of `all`\n *\n * - **Collects all errors**: Returns array of all errors, not just first\n * - **No short-circuit**: Evaluates all Results even if some fail\n * - **Partial success**: Can see which operations succeeded and which failed\n * - **Better UX**: Show users all validation errors at once\n *\n * ## Important\n *\n * - **No short-circuit**: All Results are evaluated (slower if many fail early)\n * - **Error array**: Returns array of `{ error, cause }` objects, not single error\n * - **Use `all`**: If you want fail-fast behavior (better performance)\n *\n * @param results - Array of Results to combine (all are evaluated)\n * @returns A Result with:\n * - Array of all success values if all succeed\n * - Array of `{ error, cause }` objects if any fail\n *\n * @example\n * ```typescript\n * // Form validation - show all errors\n * const validated = allSettled([\n * validateEmail(email),\n * validatePassword(password),\n * validateAge(age),\n * ]);\n * // If email and password fail:\n * // { ok: false, error: [\n * // { error: 'INVALID_EMAIL' },\n * // { error: 'WEAK_PASSWORD' }\n * // ]}\n *\n * // Collect partial results\n * const results = allSettled([\n * fetchUser('1'), // succeeds\n * fetchUser('2'), // fails\n * fetchUser('3'), // succeeds\n * ]);\n * // Can see which succeeded and which failed\n * ```\n */\nexport function allSettled<const T extends readonly Result<unknown, unknown, unknown>[]>(\n results: T\n): AllSettledResult<T> {\n const values: unknown[] = [];\n const errors: SettledError<unknown>[] = [];\n\n for (const result of results) {\n if (result.ok) {\n values.push(result.value);\n } else {\n errors.push({ error: result.error, cause: result.cause });\n }\n }\n\n if (errors.length > 0) {\n return err(errors) as unknown as AllSettledResult<T>;\n }\n\n return ok(values) as unknown as AllSettledResult<T>;\n}\n\n/**\n * Splits an array of Results into separate arrays of success values and errors.\n *\n * ## When to Use\n *\n * Use `partition()` when:\n * - You have an array of Results and need to separate successes from failures\n * - You want to process successes and errors separately\n * - You're collecting results from multiple operations (some may fail)\n * - You need to handle partial success scenarios\n *\n * ## Why Use This\n *\n * - **Simple separation**: One call splits successes and errors\n * - **Type-safe**: TypeScript knows `values` is `T[]` and `errors` is `E[]`\n * - **No unwrapping**: Doesn't require manual `if (r.ok)` checks\n * - **Preserves order**: Maintains original array order in both arrays\n *\n * ## Common Pattern\n *\n * Often used after `Promise.all()` with Results:\n * ```typescript\n * const results = await Promise.all(ids.map(id => fetchUser(id)));\n * const { values: users, errors } = partition(results);\n * // Process successful users, handle errors separately\n * ```\n *\n * @param results - Array of Results to partition\n * @returns An object with:\n * - `values`: Array of all success values (type `T[]`)\n * - `errors`: Array of all error values (type `E[]`)\n *\n * @example\n * ```typescript\n * // Split successes and errors\n * const results = [ok(1), err('ERROR_1'), ok(3), err('ERROR_2')];\n * const { values, errors } = partition(results);\n * // values: [1, 3]\n * // errors: ['ERROR_1', 'ERROR_2']\n *\n * // Process batch operations\n * const userResults = await Promise.all(userIds.map(id => fetchUser(id)));\n * const { values: users, errors: fetchErrors } = partition(userResults);\n *\n * // Process successful users\n * users.forEach(user => processUser(user));\n *\n * // Handle errors\n * fetchErrors.forEach(error => logError(error));\n * ```\n */\nexport function partition<T, E, C>(\n results: readonly Result<T, E, C>[]\n): { values: T[]; errors: E[] } {\n const values: T[] = [];\n const errors: E[] = [];\n\n for (const result of results) {\n if (result.ok) {\n values.push(result.value);\n } else {\n errors.push(result.error);\n }\n }\n\n return { values, errors };\n}\n\ntype AnyValue<T extends readonly Result<unknown, unknown, unknown>[]> =\n T[number] extends Result<infer U, unknown, unknown> ? U : never;\ntype AnyErrors<T extends readonly Result<unknown, unknown, unknown>[]> = {\n -readonly [K in keyof T]: T[K] extends Result<unknown, infer E, unknown> ? E : never;\n}[number];\ntype AnyCauses<T extends readonly Result<unknown, unknown, unknown>[]> = {\n -readonly [K in keyof T]: T[K] extends Result<unknown, unknown, infer C> ? C : never;\n}[number];\n\n/**\n * Returns the first successful Result from an array (succeeds fast).\n *\n * ## When to Use\n *\n * Use `any()` when:\n * - You have multiple fallback options and need the first that succeeds\n * - You're trying multiple strategies (e.g., cache → DB → API)\n * - You want fail-fast success (stops on first success)\n * - You have redundant data sources and any one will do\n *\n * ## Why Use This\n *\n * - **Succeeds fast**: Returns immediately on first success (better performance)\n * - **Fallback pattern**: Perfect for trying multiple options\n * - **Short-circuits**: Stops evaluating after first success\n * - **Type-safe**: TypeScript infers the success type\n *\n * ## Important\n *\n * - **First success wins**: Returns first successful Result, ignores rest\n * - **All errors**: If all fail, returns first error (not all errors)\n * - **Empty array**: Returns `EmptyInputError` if array is empty\n * - **Use `all`**: If you need ALL to succeed\n *\n * @param results - Array of Results to check (evaluated in order)\n * @returns The first successful Result, or first error if all fail, or `EmptyInputError` if empty\n *\n * @example\n * ```typescript\n * // Try multiple fallback strategies\n * const data = any([\n * fetchFromCache(id),\n * fetchFromDB(id),\n * fetchFromAPI(id)\n * ]);\n * // Returns first that succeeds\n *\n * // Try multiple formats\n * const parsed = any([\n * parseJSON(input),\n * parseXML(input),\n * parseYAML(input)\n * ]);\n *\n * // All errors case\n * const allErrors = any([err('A'), err('B'), err('C')]);\n * // allErrors: { ok: false, error: 'A' } (first error)\n * ```\n */\nexport function any<const T extends readonly Result<unknown, unknown, unknown>[]>(\n results: T\n): Result<AnyValue<T>, AnyErrors<T> | EmptyInputError, AnyCauses<T>> {\n type ReturnErr = Result<never, AnyErrors<T> | EmptyInputError, AnyCauses<T>>;\n type ReturnOk = Result<AnyValue<T>, never, AnyCauses<T>>;\n\n if (results.length === 0) {\n return err({\n type: \"EMPTY_INPUT\",\n message: \"any() requires at least one Result\",\n }) as ReturnErr;\n }\n let firstError: Result<never, unknown, unknown> | null = null;\n for (const result of results) {\n if (result.ok) return result as ReturnOk;\n if (!firstError) firstError = result;\n }\n return firstError as ReturnErr;\n}\n\ntype AnyAsyncValue<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> =\n Awaited<T[number]> extends Result<infer U, unknown, unknown> ? U : never;\ntype AnyAsyncErrors<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {\n -readonly [K in keyof T]: Awaited<T[K]> extends Result<unknown, infer E, unknown>\n ? E\n : never;\n}[number];\ntype AnyAsyncCauses<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {\n -readonly [K in keyof T]: Awaited<T[K]> extends Result<unknown, unknown, infer C>\n ? C\n : never;\n}[number];\n\n/**\n * Returns the first successful Result from an array of Results or Promises (async version of `any`).\n *\n * ## When to Use\n *\n * Use `anyAsync()` when:\n * - You have multiple async fallback options and need the first that succeeds\n * - You're trying multiple async strategies in parallel (cache → DB → API)\n * - You want fail-fast success from parallel operations\n * - You have redundant async data sources and any one will do\n *\n * ## Why Use This Instead of `any`\n *\n * - **Parallel execution**: All Promises start immediately (faster)\n * - **Async support**: Works with Promises and AsyncResults\n * - **Promise rejection handling**: Converts Promise rejections to `PromiseRejectedError`\n *\n * ## Important\n *\n * - **First success wins**: Returns first successful Result (from any Promise)\n * - **Parallel**: All operations run simultaneously\n * - **All errors**: If all fail, returns first error encountered\n *\n * @param results - Array of Results or Promises of Results to check (all start in parallel)\n * @returns A Promise resolving to the first successful Result, or first error if all fail\n *\n * @example\n * ```typescript\n * // Try multiple async fallbacks in parallel\n * const data = await anyAsync([\n * fetchFromCache(id), // Fastest wins\n * fetchFromDB(id),\n * fetchFromAPI(id)\n * ]);\n *\n * // Try multiple API endpoints\n * const response = await anyAsync([\n * fetch('/api/v1/data'),\n * fetch('/api/v2/data'),\n * fetch('/backup-api/data')\n * ]);\n * ```\n */\nexport async function anyAsync<\n const T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[],\n>(\n results: T\n): Promise<\n Result<AnyAsyncValue<T>, AnyAsyncErrors<T> | EmptyInputError | PromiseRejectedError, AnyAsyncCauses<T> | PromiseRejectionCause>\n> {\n type ReturnErr = Result<\n never,\n AnyAsyncErrors<T> | EmptyInputError | PromiseRejectedError,\n AnyAsyncCauses<T> | PromiseRejectionCause\n >;\n type ReturnOk = Result<AnyAsyncValue<T>, never, AnyAsyncCauses<T>>;\n\n if (results.length === 0) {\n return err({\n type: \"EMPTY_INPUT\",\n message: \"anyAsync() requires at least one Result\",\n }) as ReturnErr;\n }\n\n return new Promise((resolve) => {\n let settled = false;\n let pendingCount = results.length;\n let firstError: Result<never, unknown, unknown> | null = null;\n\n for (const item of results) {\n Promise.resolve(item)\n .catch((reason) =>\n err(\n { type: \"PROMISE_REJECTED\" as const, cause: reason },\n { cause: { type: \"PROMISE_REJECTION\" as const, reason } as PromiseRejectionCause }\n )\n )\n .then((result) => {\n if (settled) return;\n\n if (result.ok) {\n settled = true;\n resolve(result as ReturnOk);\n return;\n }\n\n if (!firstError) firstError = result;\n pendingCount--;\n\n if (pendingCount === 0) {\n resolve(firstError as ReturnErr);\n }\n });\n }\n });\n}\n\ntype AllAsyncValues<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {\n [K in keyof T]: Awaited<T[K]> extends Result<infer V, unknown, unknown> ? V : never;\n};\ntype AllAsyncErrors<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {\n [K in keyof T]: Awaited<T[K]> extends Result<unknown, infer E, unknown> ? E : never;\n}[number];\ntype AllAsyncCauses<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {\n [K in keyof T]: Awaited<T[K]> extends Result<unknown, unknown, infer C> ? C : never;\n}[number];\n\n/**\n * Combines multiple Results or Promises of Results, collecting all errors (async version of `allSettled`).\n *\n * ## When to Use\n *\n * Use `allSettledAsync()` when:\n * - You have multiple async operations and need ALL errors reported\n * - You're doing async form validation (show all field errors at once)\n * - You want to run operations in parallel and collect all results\n *\n * ## Behavior\n *\n * **Note:** Unlike `Promise.allSettled()`, this returns a Result:\n * - `ok(values[])` if ALL succeed\n * - `err(SettledError[])` if ANY fail (with all collected errors)\n *\n * This is consistent with awaitly's philosophy - all functions return Results.\n * `Promise.allSettled()` always succeeds with per-item status objects; this function\n * returns a single Result indicating overall success or failure.\n *\n * ## Why Use This Instead of `allSettled`\n *\n * - **Parallel execution**: All Promises start immediately (faster)\n * - **Async support**: Works with Promises and AsyncResults\n * - **Promise rejection handling**: Converts Promise rejections to `PromiseRejectedError`\n *\n * ## Important\n *\n * - **No short-circuit**: All operations complete (even if some fail)\n * - **Parallel**: All operations run simultaneously\n * - **Error array**: Returns array of `SettledError` objects (`{ error, cause? }`)\n *\n * @param results - Array of Results or Promises of Results to combine (all are evaluated)\n * @returns A Promise resolving to a Result with:\n * - `ok(values[])` - Array of all success values if ALL succeed\n * - `err(errors[])` - Array of `SettledError` objects if ANY fail\n *\n * @example\n * ```typescript\n * // Async form validation - see all errors at once\n * const validated = await allSettledAsync([\n * validateEmailAsync(email),\n * validatePasswordAsync(password),\n * checkUsernameAvailableAsync(username),\n * ]);\n *\n * if (!validated.ok) {\n * // validated.error is array of all validation failures\n * console.log('Errors:', validated.error.map(e => e.error));\n * }\n *\n * // Parallel API calls with error collection\n * const results = await allSettledAsync([\n * fetchUser('1'),\n * fetchUser('2'),\n * fetchUser('3'),\n * ]);\n * ```\n */\nexport async function allSettledAsync<\n const T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[],\n>(\n results: T\n): Promise<Result<AllAsyncValues<T>, SettledError<AllAsyncErrors<T> | PromiseRejectedError, AllAsyncCauses<T> | PromiseRejectionCause>[]>> {\n const settled = await Promise.all(\n results.map((item) =>\n Promise.resolve(item)\n .then((result) => ({ status: \"result\" as const, result }))\n .catch((reason) => ({\n status: \"rejected\" as const,\n error: { type: \"PROMISE_REJECTED\" as const, cause: reason } as PromiseRejectedError,\n cause: { type: \"PROMISE_REJECTION\" as const, reason } as PromiseRejectionCause,\n }))\n )\n );\n\n const values: unknown[] = [];\n const errors: SettledError<unknown, unknown>[] = [];\n\n for (const item of settled) {\n if (item.status === \"rejected\") {\n errors.push({ error: item.error, cause: item.cause });\n } else if (item.result.ok) {\n values.push(item.result.value);\n } else {\n errors.push({ error: item.result.error, cause: item.result.cause });\n }\n }\n\n if (errors.length > 0) {\n return err(errors) as unknown as Result<AllAsyncValues<T>, SettledError<AllAsyncErrors<T> | PromiseRejectedError, AllAsyncCauses<T> | PromiseRejectionCause>[]>;\n }\n return ok(values) as unknown as Result<AllAsyncValues<T>, SettledError<AllAsyncErrors<T> | PromiseRejectedError, AllAsyncCauses<T> | PromiseRejectionCause>[]>;\n}\n\n/**\n * Combines two Results into a tuple Result.\n *\n * ## When to Use\n *\n * Use `zip()` when:\n * - You have two independent Results and need both values together\n * - You want to combine validation results before processing\n * - You need a pair/tuple from two separate operations\n *\n * ## Why Use This Instead of `all()`\n *\n * - **Simpler types**: Returns `[A, B]` instead of array inference\n * - **Two-argument**: Cleaner API for common case of combining two Results\n * - **Compose with andThen**: Chain multiple zips for complex combinations\n *\n * ## Important\n *\n * - **Short-circuits**: Returns first error if either fails\n * - **Order matters**: If both fail, returns error from first argument\n * - **Use `all()`**: For more than 2 Results\n *\n * @param a - First Result\n * @param b - Second Result\n * @returns A Result containing a tuple `[A, B]` if both succeed, or the first error\n *\n * @example\n * ```typescript\n * // Combine two Results\n * const userResult = await fetchUser('1');\n * const postsResult = await fetchPosts('1');\n * const combined = zip(userResult, postsResult);\n * // combined: Result<[User, Post[]], UserError | PostsError>\n *\n * // Use with andThen for chaining\n * const result = andThen(\n * zip(fetchUser('1'), fetchPosts('1')),\n * ([user, posts]) => createDashboard(user, posts)\n * );\n *\n * // Validation combination\n * const validated = zip(\n * validateEmail(email),\n * validatePassword(password)\n * );\n * if (validated.ok) {\n * const [email, password] = validated.value;\n * createAccount(email, password);\n * }\n * ```\n */\nexport function zip<A, EA, CA, B, EB, CB>(\n a: Result<A, EA, CA>,\n b: Result<B, EB, CB>\n): Result<[A, B], EA | EB, CA | CB> {\n if (!a.ok) return a as Result<never, EA, CA>;\n if (!b.ok) return b as Result<never, EB, CB>;\n return ok([a.value, b.value]) as Result<[A, B], never, never>;\n}\n\n/**\n * Async version of `zip()` - combines two Results or Promises of Results into a tuple.\n *\n * ## When to Use\n *\n * Use `zipAsync()` when:\n * - You have two async operations and need both results together\n * - You want to run two fetches in parallel and combine results\n * - You need to combine Promises of Results into a single Result\n *\n * ## Why Use This Instead of `allAsync()`\n *\n * - **Simpler types**: Returns `[A, B]` instead of array inference\n * - **Two-argument**: Cleaner API for common case of combining two async Results\n * - **Parallel execution**: Both Promises start immediately\n *\n * ## Important\n *\n * - **Parallel**: Both operations run simultaneously (faster than sequential)\n * - **Short-circuits result**: Returns first argument's error if it fails, else second's\n * - **Waits for both**: Both Promises complete before returning (unlike `allAsync` fail-fast)\n * - **Rejection handling**: Promise rejections are wrapped as `PromiseRejectedError`\n * - **Use `allAsync()`**: For more than 2 Results\n *\n * @param a - First Result or Promise of Result\n * @param b - Second Result or Promise of Result\n * @returns A Promise of Result containing a tuple `[A, B]` if both succeed\n *\n * @example\n * ```typescript\n * // Parallel async operations\n * const result = await zipAsync(\n * fetchUser('1'),\n * fetchPosts('1')\n * );\n * // Both fetches run in parallel\n * // result: Result<[User, Post[]], UserError | PostsError>\n *\n * // Mix sync and async\n * const combined = await zipAsync(\n * ok({ cached: true }), // Already resolved\n * fetchFromAPI(id), // Async fetch\n * );\n *\n * // With chaining\n * const dashboard = await zipAsync(fetchUser('1'), fetchPosts('1'))\n * .then(result => andThen(result, ([user, posts]) => createDashboard(user, posts)));\n * ```\n */\nexport async function zipAsync<A, EA, CA, B, EB, CB>(\n a: Result<A, EA, CA> | Promise<Result<A, EA, CA>>,\n b: Result<B, EB, CB> | Promise<Result<B, EB, CB>>\n): AsyncResult<[A, B], EA | EB | PromiseRejectedError, CA | CB | PromiseRejectionCause> {\n // Wrap rejections into PromiseRejectedError (consistent with allAsync)\n const wrapRejection = <T, E, C>(\n p: Result<T, E, C> | Promise<Result<T, E, C>>\n ): Promise<Result<T, E | PromiseRejectedError, C | PromiseRejectionCause>> =>\n Promise.resolve(p).catch((reason) =>\n err(\n { type: \"PROMISE_REJECTED\" as const, cause: reason } as PromiseRejectedError,\n { cause: { type: \"PROMISE_REJECTION\" as const, reason } as PromiseRejectionCause }\n )\n );\n\n const [ra, rb] = await Promise.all([wrapRejection(a), wrapRejection(b)]);\n return zip(ra, rb);\n}\n","/**\n * Type guards for workflow events and errors.\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type { WorkflowCancelledError, PendingApproval, ApprovalRejected, PendingHook, ResumeState } from \"./types\";\n\n/**\n * Type guard to check if an event is a step_complete event.\n * Use this to filter events for state persistence.\n *\n * @param event - The workflow event to check\n * @returns `true` if the event is a step_complete event, `false` otherwise\n *\n * @example\n * ```typescript\n * const savedSteps = new Map<string, Result<unknown, unknown>>();\n *\n * const workflow = createWorkflow({ fetchUser }, {\n * onEvent: (event) => {\n * if (isStepComplete(event)) {\n * savedSteps.set(event.stepKey, event.result);\n * }\n * }\n * });\n * ```\n */\n/**\n * Type guard for runtime ResumeState (steps is a Map). Use to discriminate from WorkflowSnapshot when loading.\n */\nexport function isResumeState(x: unknown): x is ResumeState {\n return (\n typeof x === \"object\" &&\n x !== null &&\n \"steps\" in x &&\n (x as ResumeState).steps instanceof Map\n );\n}\n\nexport function isStepComplete(\n event: WorkflowEvent<unknown>\n): event is Extract<WorkflowEvent<unknown>, { type: \"step_complete\" }> {\n return event.type === \"step_complete\";\n}\n\n/**\n * Type guard to check if an error is a WorkflowCancelledError.\n *\n * @param error - The error to check\n * @returns `true` if the error is a WorkflowCancelledError, `false` otherwise\n */\nexport function isWorkflowCancelled(error: unknown): error is WorkflowCancelledError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as WorkflowCancelledError).type === \"WORKFLOW_CANCELLED\"\n );\n}\n\n/**\n * Type guard to check if an error is a PendingApproval.\n *\n * @param error - The error to check\n * @returns `true` if the error is a PendingApproval, `false` otherwise\n *\n * @example\n * ```typescript\n * const result = await workflow(...);\n * if (!result.ok && isPendingApproval(result.error)) {\n * console.log(`Waiting for approval: ${result.error.stepKey}`);\n * }\n * ```\n */\nexport function isPendingApproval(error: unknown): error is PendingApproval {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as PendingApproval).type === \"PENDING_APPROVAL\"\n );\n}\n\n/**\n * Type guard to check if an error is an ApprovalRejected.\n *\n * @param error - The error to check\n * @returns `true` if the error is an ApprovalRejected, `false` otherwise\n */\nexport function isApprovalRejected(error: unknown): error is ApprovalRejected {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as ApprovalRejected).type === \"APPROVAL_REJECTED\"\n );\n}\n\n/**\n * Type guard to check if an error is a PendingHook.\n *\n * @param error - The error to check\n * @returns `true` if the error is a PendingHook, `false` otherwise\n */\nexport function isPendingHook(error: unknown): error is PendingHook {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as PendingHook).type === \"PENDING_HOOK\"\n );\n}\n","/**\n * awaitly/persistence\n *\n * Simplified Persistence API for workflow snapshots.\n * Provides JSON-serializable snapshot format and store adapters.\n */\n\nimport type { Result } from \"./core\";\nimport type { StepCache } from \"./workflow\";\n\n// =============================================================================\n// JSON-Safe Type Enforcement\n// =============================================================================\n\n/**\n * Enforce JSON-safety at type level.\n * Only allows values that can be safely serialized with JSON.stringify.\n */\nexport type JSONValue =\n | null\n | boolean\n | number\n | string\n | JSONValue[]\n | { [k: string]: JSONValue };\n\n// =============================================================================\n// WorkflowSnapshot Types (Simplified API)\n// =============================================================================\n\n/**\n * Canonical error wire format - handles both Error instances and thrown non-Errors.\n * This is the single source of truth for serialized errors in snapshots.\n */\nexport type SerializedCause =\n | { type: \"error\"; name: string; message: string; stack?: string; cause?: SerializedCause }\n | { type: \"thrown\"; originalType?: string; value?: JSONValue; stringRepresentation: string; truncated?: true };\n\n/**\n * Single source of truth for step outcome (no error/cause confusion).\n * Uses discriminated union with `ok` field.\n */\nexport type StepResult =\n | { ok: true; value: JSONValue }\n | { ok: false; error: JSONValue; cause: SerializedCause; meta?: { origin: \"result\" | \"throw\" } };\n\n/**\n * JSON-serializable workflow snapshot.\n * Designed to be passed directly to JSON.stringify without special handling.\n *\n * @example\n * ```typescript\n * // Persist\n * localStorage.setItem('wf-123', JSON.stringify(wf.getSnapshot()));\n *\n * // Restore (safe pattern - storage can be empty/corrupt)\n * const raw = localStorage.getItem('wf-123');\n * const snapshot = raw ? JSON.parse(raw) : null;\n * createWorkflow(deps, { snapshot }); // null = fresh start\n * ```\n */\nexport interface WorkflowSnapshot {\n /** Snapshot format version (literal type - bump when shape changes) */\n formatVersion: 1;\n /** Workflow name (from createWorkflow first argument). */\n workflowName?: string;\n /** Step results keyed by step ID. Uses Object.create(null) internally. */\n steps: Record<string, StepResult>;\n /** Execution state metadata */\n execution: {\n status: \"running\" | \"completed\" | \"failed\";\n /** ISO timestamp (UTC toISOString()) */\n lastUpdated: string;\n /** ISO timestamp if finished */\n completedAt?: string;\n /**\n * For paused/running workflows: the step key of the current step.\n * Aligns with Workflow Diagram DSL step state ids (see awaitly/workflow diagram-dsl)\n * so visualizers can highlight the current node.\n */\n currentStepId?: string;\n };\n /** Optional metadata for workflow identification and replay */\n metadata?: {\n /** Detect wrong snapshot for wrong workflow */\n workflowId?: string;\n /** Optional: detect definition changes (user-supplied, advisory only) */\n definitionHash?: string;\n /** Original input for replay */\n input?: JSONValue;\n [key: string]: JSONValue | undefined;\n };\n /** Warnings for lossy serialization (keeps step results pure) */\n warnings?: Array<{\n type: \"lossy_value\";\n stepId: string;\n path: string;\n reason: \"non-json\" | \"circular\" | \"encode-failed\";\n }>;\n}\n\n/**\n * Warning entry for lossy value serialization.\n */\nexport type SnapshotWarning = NonNullable<WorkflowSnapshot[\"warnings\"]>[number];\n\n// =============================================================================\n// Snapshot Validation\n// =============================================================================\n\n/**\n * Error thrown when snapshot structure is invalid.\n */\nexport class SnapshotFormatError extends Error {\n constructor(\n message: string,\n public readonly errors: string[] = []\n ) {\n super(message);\n this.name = \"SnapshotFormatError\";\n }\n}\n\n/**\n * Error thrown when snapshot doesn't match workflow (unknown steps, workflowId mismatch).\n */\nexport class SnapshotMismatchError extends Error {\n constructor(\n message: string,\n public readonly mismatchType: \"unknown_steps\" | \"workflow_id\" | \"definition_hash\",\n public readonly details?: {\n unknownSteps?: string[];\n snapshotWorkflowId?: string;\n expectedWorkflowId?: string;\n snapshotHash?: string;\n expectedHash?: string;\n }\n ) {\n super(message);\n this.name = \"SnapshotMismatchError\";\n }\n}\n\n/**\n * Error thrown when decode fails during restore.\n */\nexport class SnapshotDecodeError extends Error {\n constructor(\n message: string,\n public readonly stepId: string,\n public readonly originalError?: unknown\n ) {\n super(message);\n this.name = \"SnapshotDecodeError\";\n }\n}\n\n/**\n * Light check to see if an object looks like a WorkflowSnapshot.\n * Cheap check for basic structure - use validateSnapshot() for full validation.\n *\n * @example\n * ```typescript\n * const raw = JSON.parse(localStorage.getItem('wf-123') || 'null');\n * if (looksLikeWorkflowSnapshot(raw)) {\n * createWorkflow(deps, { snapshot: raw });\n * }\n * ```\n */\nexport function looksLikeWorkflowSnapshot(obj: unknown): obj is WorkflowSnapshot {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"formatVersion\" in obj &&\n (obj as { formatVersion: unknown }).formatVersion === 1 &&\n \"steps\" in obj &&\n typeof (obj as { steps: unknown }).steps === \"object\" &&\n (obj as { steps: unknown }).steps !== null &&\n \"execution\" in obj &&\n typeof (obj as { execution: unknown }).execution === \"object\"\n );\n}\n\n/**\n * Type guard for WorkflowSnapshot. Same as looksLikeWorkflowSnapshot; use for consistent naming with isResumeState / isSerializedResumeState.\n */\nexport const isWorkflowSnapshot = looksLikeWorkflowSnapshot;\n\n/**\n * Full validation with detailed errors.\n * Returns either a validated snapshot or an array of validation errors.\n */\nexport function validateSnapshot(obj: unknown): { valid: true; snapshot: WorkflowSnapshot } | { valid: false; errors: string[] } {\n const errors: string[] = [];\n\n if (typeof obj !== \"object\" || obj === null) {\n return { valid: false, errors: [\"Snapshot must be an object\"] };\n }\n\n const snapshot = obj as Record<string, unknown>;\n\n // Check formatVersion\n if (!(\"formatVersion\" in snapshot)) {\n errors.push(\"Missing required field: formatVersion\");\n } else if (snapshot.formatVersion !== 1) {\n errors.push(`Invalid formatVersion: expected 1, got ${snapshot.formatVersion}`);\n }\n\n // Check steps\n if (!(\"steps\" in snapshot)) {\n errors.push(\"Missing required field: steps\");\n } else if (typeof snapshot.steps !== \"object\" || snapshot.steps === null) {\n errors.push(\"steps must be an object\");\n } else {\n // Validate each step result\n const steps = snapshot.steps as Record<string, unknown>;\n for (const [stepId, stepResult] of Object.entries(steps)) {\n if (typeof stepResult !== \"object\" || stepResult === null) {\n errors.push(`steps[\"${stepId}\"] must be an object`);\n continue;\n }\n\n const step = stepResult as Record<string, unknown>;\n if (!(\"ok\" in step)) {\n errors.push(`steps[\"${stepId}\"] missing required field: ok`);\n } else if (typeof step.ok !== \"boolean\") {\n errors.push(`steps[\"${stepId}\"].ok must be a boolean`);\n } else if (step.ok === false) {\n if (!(\"error\" in step)) {\n errors.push(`steps[\"${stepId}\"] is error result but missing error field`);\n }\n if (!(\"cause\" in step)) {\n errors.push(`steps[\"${stepId}\"] is error result but missing cause field`);\n }\n }\n }\n }\n\n // Check execution\n if (!(\"execution\" in snapshot)) {\n errors.push(\"Missing required field: execution\");\n } else if (typeof snapshot.execution !== \"object\" || snapshot.execution === null) {\n errors.push(\"execution must be an object\");\n } else {\n const execution = snapshot.execution as Record<string, unknown>;\n if (!(\"status\" in execution)) {\n errors.push(\"execution missing required field: status\");\n } else if (![\"running\", \"completed\", \"failed\"].includes(execution.status as string)) {\n errors.push(`execution.status must be one of: running, completed, failed`);\n }\n if (!(\"lastUpdated\" in execution)) {\n errors.push(\"execution missing required field: lastUpdated\");\n } else if (typeof execution.lastUpdated !== \"string\") {\n errors.push(\"execution.lastUpdated must be a string (ISO timestamp)\");\n }\n }\n\n if (errors.length > 0) {\n return { valid: false, errors };\n }\n\n return { valid: true, snapshot: obj as WorkflowSnapshot };\n}\n\n/**\n * Throwing helper for cleaner code.\n * Validates a snapshot and throws SnapshotFormatError if invalid.\n *\n * @throws {SnapshotFormatError} If snapshot is invalid\n */\nexport function assertValidSnapshot(obj: unknown): WorkflowSnapshot {\n const result = validateSnapshot(obj);\n if (!result.valid) {\n throw new SnapshotFormatError(`Invalid snapshot format: ${result.errors[0]}`, result.errors);\n }\n return result.snapshot;\n}\n\n// =============================================================================\n// Snapshot Merge Helper\n// =============================================================================\n\n/**\n * Merge two snapshots (for incremental updates).\n * Delta steps overwrite base steps; execution from delta; metadata shallow merge.\n */\nexport function mergeSnapshots(base: WorkflowSnapshot, delta: WorkflowSnapshot): WorkflowSnapshot {\n // Create new steps object using Object.create(null) for prototype safety\n const mergedSteps = Object.create(null) as Record<string, StepResult>;\n\n // Copy base steps (use Object.prototype.hasOwnProperty for ES2020 compat)\n for (const [key, value] of Object.entries(base.steps)) {\n if (Object.prototype.hasOwnProperty.call(base.steps, key)) {\n mergedSteps[key] = value;\n }\n }\n\n // Overlay delta steps\n for (const [key, value] of Object.entries(delta.steps)) {\n if (Object.prototype.hasOwnProperty.call(delta.steps, key)) {\n mergedSteps[key] = value;\n }\n }\n\n // Merge metadata (delta wins for conflicts)\n const mergedMetadata = base.metadata || delta.metadata\n ? { ...base.metadata, ...delta.metadata }\n : undefined;\n\n // Merge warnings: only keep base warnings for steps not re-executed in delta.\n // If a step was re-executed and serialized cleanly, its old warning should disappear.\n const baseWarnings = (base.warnings || []).filter(\n (w) => !Object.prototype.hasOwnProperty.call(delta.steps, w.stepId)\n );\n const mergedWarnings = [...baseWarnings, ...(delta.warnings || [])];\n\n return {\n formatVersion: 1,\n steps: mergedSteps,\n execution: { ...delta.execution },\n metadata: mergedMetadata,\n warnings: mergedWarnings.length > 0 ? mergedWarnings : undefined,\n };\n}\n\n// =============================================================================\n// Serialization Helpers\n// =============================================================================\n\n/**\n * Maximum length for string representation in thrown non-Error values.\n */\nconst MAX_STRING_REPRESENTATION_LENGTH = 1000;\n\n/**\n * Serialize an Error object to SerializedCause format.\n * Preserves Error.cause recursively.\n */\nexport function serializeError(error: Error): SerializedCause {\n const serialized: SerializedCause = {\n type: \"error\",\n name: error.name,\n message: error.message,\n };\n\n if (error.stack) {\n serialized.stack = error.stack;\n }\n\n // Recursively serialize Error.cause if present (ES2022 feature, but commonly available)\n const errorWithCause = error as Error & { cause?: unknown };\n if (errorWithCause.cause !== undefined) {\n if (errorWithCause.cause instanceof Error) {\n serialized.cause = serializeError(errorWithCause.cause);\n } else {\n // cause is not an Error, serialize as thrown value\n serialized.cause = serializeThrown(errorWithCause.cause);\n }\n }\n\n return serialized;\n}\n\n/**\n * Serialize a non-Error thrown value to SerializedCause format.\n */\nexport function serializeThrown(value: unknown): SerializedCause {\n // Get string representation\n let stringRepresentation: string;\n let truncated = false;\n\n try {\n stringRepresentation = String(value);\n if (stringRepresentation.length > MAX_STRING_REPRESENTATION_LENGTH) {\n stringRepresentation = stringRepresentation.slice(0, MAX_STRING_REPRESENTATION_LENGTH);\n truncated = true;\n }\n } catch {\n stringRepresentation = \"[unable to convert to string]\";\n }\n\n // Try to get the original type\n const originalType = value === null\n ? \"null\"\n : typeof value === \"object\"\n ? (value.constructor?.name ?? \"Object\")\n : typeof value;\n\n // Try to serialize the value as JSON\n let jsonValue: JSONValue | undefined;\n try {\n const serialized = JSON.stringify(value);\n if (serialized !== undefined) {\n jsonValue = JSON.parse(serialized) as JSONValue;\n }\n } catch {\n // Non-JSON-serializable, will only use stringRepresentation\n }\n\n const result: SerializedCause = {\n type: \"thrown\",\n originalType,\n stringRepresentation,\n };\n\n if (jsonValue !== undefined) {\n result.value = jsonValue;\n }\n\n if (truncated) {\n result.truncated = true;\n }\n\n return result;\n}\n\n/**\n * Deserialize a SerializedCause back to its original form.\n */\nexport function deserializeCauseNew(serialized: SerializedCause): unknown {\n if (serialized.type === \"error\") {\n const error = new Error(serialized.message);\n error.name = serialized.name;\n if (serialized.stack) {\n error.stack = serialized.stack;\n }\n if (serialized.cause) {\n (error as Error & { cause: unknown }).cause = deserializeCauseNew(serialized.cause);\n }\n return error;\n }\n\n // type === \"thrown\"\n // Return the JSON value if available, otherwise the string representation\n return serialized.value !== undefined ? serialized.value : serialized.stringRepresentation;\n}\n\n// =============================================================================\n// SnapshotStore Interface (New Simplified API)\n// =============================================================================\n\n/**\n * Simplified store interface for workflow snapshot persistence.\n * Works directly with WorkflowSnapshot objects.\n *\n * Adapters may implement an extended contract (see awaitly/workflow): save can accept\n * WorkflowSnapshot | ResumeState; load can return WorkflowSnapshot | ResumeState | null.\n * Use isWorkflowSnapshot / isSerializedResumeState and serializeResumeState / deserializeResumeState\n * when branching. For type-safe restore, use store.loadResumeState(id) or toResumeState(await store.load(id)).\n *\n * @example\n * ```typescript\n * import { postgres } from 'awaitly-postgres';\n * import { createWorkflow } from 'awaitly/workflow';\n *\n * const store = postgres('postgresql://localhost/mydb');\n * const workflow = createWorkflow(deps);\n *\n * // Run and persist resume state\n * const { result, resumeState } = await workflow.runWithState(fn);\n * await store.save('wf-123', resumeState);\n *\n * // Restore\n * const loaded = await store.load('wf-123');\n * const resumeState = toResumeState(loaded);\n * if (resumeState) await workflow.run(fn, { resumeState });\n * ```\n */\nexport interface SnapshotStore {\n /** Save a workflow snapshot (upsert - insert or update). Adapters may also accept ResumeState. */\n save(id: string, snapshot: WorkflowSnapshot): Promise<void>;\n /** Load a workflow snapshot. Returns null if not found. Adapters may return ResumeState when stored as such. */\n load(id: string): Promise<WorkflowSnapshot | null>;\n /** Delete a workflow snapshot. */\n delete(id: string): Promise<void>;\n /** List workflow IDs with their last update time. */\n list(options?: { prefix?: string; limit?: number }): Promise<Array<{ id: string; updatedAt: string }>>;\n /** Clean shutdown for tests/graceful exit. */\n close(): Promise<void>;\n}\n\n// =============================================================================\n// In-Memory Cache Adapter\n// =============================================================================\n\n/**\n * Options for the in-memory cache adapter.\n */\nexport interface MemoryCacheOptions {\n /**\n * Maximum number of entries to store.\n * Oldest entries are evicted when limit is reached.\n */\n maxSize?: number;\n\n /**\n * Time-to-live in milliseconds.\n * Entries are automatically removed after this duration.\n */\n ttl?: number;\n}\n\n/**\n * Create an in-memory StepCache with optional LRU eviction and TTL.\n *\n * @param options - Cache options\n * @returns StepCache implementation\n *\n * @example\n * ```typescript\n * const cache = createMemoryCache({ maxSize: 1000, ttl: 60000 });\n * const workflow = createWorkflow(deps, { cache });\n * ```\n */\nexport function createMemoryCache(options: MemoryCacheOptions = {}): StepCache {\n const { maxSize, ttl } = options;\n const cache = new Map<string, {\n result: Result<unknown, unknown, unknown>;\n timestamp: number;\n entryTtl?: number;\n }>();\n\n const isExpired = (entry: { timestamp: number; entryTtl?: number }): boolean => {\n const effectiveTtl = entry.entryTtl ?? ttl;\n if (!effectiveTtl) return false;\n return Date.now() - entry.timestamp > effectiveTtl;\n };\n\n const evictExpired = (): void => {\n for (const [key, entry] of cache) {\n if (isExpired(entry)) {\n cache.delete(key);\n }\n }\n };\n\n const evictOldest = (): void => {\n if (!maxSize || cache.size < maxSize) return;\n\n // Find oldest entry\n let oldestKey: string | undefined;\n let oldestTime = Infinity;\n\n for (const [key, entry] of cache) {\n if (entry.timestamp < oldestTime) {\n oldestTime = entry.timestamp;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n cache.delete(oldestKey);\n }\n };\n\n return {\n get(key: string): Result<unknown, unknown, unknown> | undefined {\n evictExpired();\n const entry = cache.get(key);\n if (!entry) return undefined;\n if (isExpired(entry)) {\n cache.delete(key);\n return undefined;\n }\n return entry.result;\n },\n\n set(key: string, result: Result<unknown, unknown, unknown>, options?: { ttl?: number }): void {\n evictExpired();\n evictOldest();\n cache.set(key, { result, timestamp: Date.now(), entryTtl: options?.ttl });\n },\n\n has(key: string): boolean {\n evictExpired();\n const entry = cache.get(key);\n if (!entry) return false;\n if (isExpired(entry)) {\n cache.delete(key);\n return false;\n }\n return true;\n },\n\n delete(key: string): boolean {\n return cache.delete(key);\n },\n\n clear(): void {\n cache.clear();\n },\n };\n}\n","/**\n * Cache entry encoding for step results.\n * Preserves StepFailureMeta for proper replay. Internal use only.\n */\n\nimport { err, type StepFailureMeta, type Err } from \"../core\";\n\n/**\n * Marker for cached error entries that include step failure metadata.\n * This allows us to preserve origin:\"throw\" vs origin:\"result\" when replaying,\n * while also preserving the original cause value for direct cache access.\n * @internal\n */\nexport interface CachedErrorCause<C = unknown> {\n __cachedMeta: true;\n /** The original cause from the step result (preserved for direct access) */\n originalCause: C;\n /** Metadata for proper replay behavior */\n meta: StepFailureMeta;\n}\n\nexport function isCachedErrorCause(cause: unknown): cause is CachedErrorCause {\n return (\n typeof cause === \"object\" &&\n cause !== null &&\n (cause as CachedErrorCause).__cachedMeta === true\n );\n}\n\n/**\n * Encode an error result for caching, preserving both the original cause\n * and metadata needed for proper replay.\n */\nexport function encodeCachedError<E, C>(\n error: E,\n meta: StepFailureMeta,\n originalCause: C\n): Err<E, CachedErrorCause<C>> {\n return err(error, {\n cause: { __cachedMeta: true, originalCause, meta } as CachedErrorCause<C>,\n });\n}\n\nexport function decodeCachedMeta(cause: unknown): StepFailureMeta {\n if (isCachedErrorCause(cause)) {\n return cause.meta;\n }\n // Fallback for any non-encoded cause (shouldn't happen, but safe default)\n return { origin: \"result\", resultCause: cause };\n}\n","/**\n * Resume state helpers: collectors and state manipulation for workflow replay.\n */\n\nimport { ok } from \"../core\";\nimport type { WorkflowEvent } from \"../core\";\nimport type { ResumeState, ResumeStateEntry, PendingApproval } from \"./types\";\nimport { isStepComplete, isPendingApproval, isPendingHook } from \"./guards\";\n\n/**\n * Create a collector for step results to build resume state.\n *\n * ## When to Use\n *\n * Use `createResumeStateCollector` when you need to:\n * - **Save workflow state** for later replay/resume\n * - **Persist step results** to a database or file system\n * - **Build resume state** from workflow execution\n * - **Enable workflow replay** after application restarts\n *\n * ## Why Use This Instead of Manual Collection\n *\n * - **Automatic filtering**: Only collects `step_complete` events (ignores other events)\n * - **Metadata preservation**: Captures both result and meta for proper error replay\n * - **Type-safe**: Returns properly typed `ResumeState`\n * - **Convenient API**: Simple `handleEvent` → `getResumeState` pattern\n *\n * ## How It Works\n *\n * 1. Create collector and pass `handleEvent` to workflow's `onEvent` option\n * 2. Workflow emits `step_complete` events for keyed steps\n * 3. Collector automatically captures these events\n * 4. Call `getResumeState()` to get the collected `ResumeState`\n * 5. Persist state (e.g., to database) for later resume\n *\n * ## When step_complete Events Are Emitted\n *\n * Events are emitted for ANY step that has a `key` option, regardless of calling pattern:\n *\n * ```typescript\n * // Function-wrapped pattern - emits step_complete\n * await step(() => fetchUser(\"1\"), { key: \"user:1\" });\n *\n * // Direct AsyncResult pattern - also emits step_complete\n * await step(fetchUser(\"1\"), { key: \"user:1\" });\n * ```\n *\n * Both patterns above will emit `step_complete` events and be captured by the collector.\n *\n * ## Important Notes\n *\n * - Only steps with a `key` option are collected (unkeyed steps are not saved)\n * - The collector preserves error metadata for proper replay behavior\n * - State can be serialized to JSON (but complex cause types may need custom handling)\n *\n * @returns An object with:\n * - `handleEvent`: Function to pass to workflow's `onEvent` option\n * - `getResumeState`: Get collected resume state (call after workflow execution)\n * - `clear`: Clears the collector's internal recorded entries (does not mutate workflow state)\n *\n * @example\n * ```typescript\n * // Collect state during workflow execution\n * const collector = createResumeStateCollector();\n *\n * const workflow = createWorkflow({ fetchUser, fetchPosts }, {\n * onEvent: collector.handleEvent, // Pass collector's handler\n * });\n *\n * await workflow(async ({ step }) => {\n * // Only keyed steps are collected\n * const user = await step(() => fetchUser(\"1\"), { key: \"user:1\" });\n * const posts = await step(() => fetchPosts(user.id), { key: `posts:${user.id}` });\n * return { user, posts };\n * });\n *\n * // Get collected state for persistence\n * const state = collector.getResumeState();\n * // state.steps contains: 'user:1' and 'posts:1' entries\n *\n * // Save to database\n * await db.saveWorkflowState(workflowId, state);\n * ```\n *\n * @example\n * ```typescript\n * // Resume workflow from saved state\n * const savedState = await db.loadWorkflowState(workflowId);\n * const workflow = createWorkflow({ fetchUser, fetchPosts }, {\n * resumeState: savedState // Pre-populate cache from saved state\n * });\n *\n * // Cached steps skip execution, new steps run normally\n * await workflow(async ({ step }) => {\n * const user = await step(() => fetchUser(\"1\"), { key: \"user:1\" }); // Cache hit\n * const posts = await step(() => fetchPosts(user.id), { key: `posts:${user.id}` }); // Cache hit\n * return { user, posts };\n * });\n * ```\n */\nexport function createResumeStateCollector(): {\n /** Handle workflow events. Pass this to workflow's `onEvent` option. */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n /** Get the collected resume state. Call after workflow execution. */\n getResumeState: () => ResumeState;\n /** Clears the collector's internal recorded entries (does not mutate workflow state). */\n clear: () => void;\n} {\n const steps = new Map<string, ResumeStateEntry>();\n\n return {\n handleEvent: (event: WorkflowEvent<unknown>) => {\n if (isStepComplete(event)) {\n steps.set(event.stepKey, { result: event.result, meta: event.meta });\n }\n },\n getResumeState: () => ({ steps: new Map(steps) }),\n clear: () => steps.clear(),\n };\n}\n\n/**\n * Inject an approved value into resume state.\n * Use this when an external approval is granted and you want to resume the workflow.\n *\n * @param state - The resume state to update\n * @param options - Object with stepKey and the approved value\n * @returns A new ResumeState with the approval injected\n *\n * @example\n * ```typescript\n * // When approval is granted externally:\n * const updatedState = injectApproval(savedState, {\n * stepKey: 'deploy:prod',\n * value: { approvedBy: 'admin', approvedAt: Date.now() }\n * });\n *\n * // Resume workflow with the approval injected\n * const workflow = createWorkflow({ ... }, { resumeState: updatedState });\n * ```\n */\nexport function injectApproval<T>(\n state: ResumeState,\n options: { stepKey: string; value: T }\n): ResumeState {\n const newSteps = new Map(state.steps);\n newSteps.set(options.stepKey, {\n result: ok(options.value),\n });\n return { steps: newSteps };\n}\n\n/**\n * Remove a step from resume state (e.g., to force re-execution).\n * This is an immutable operation - returns a new ResumeState without modifying the original.\n *\n * @param state - The resume state to update\n * @param stepKey - The key of the step to remove\n * @returns A new ResumeState with the step removed (original is unchanged)\n *\n * @example\n * ```typescript\n * // Force a step to re-execute on resume\n * const updatedState = clearStep(savedState, 'approval:123');\n * ```\n */\nexport function clearStep(state: ResumeState, stepKey: string): ResumeState {\n const newSteps = new Map(state.steps);\n newSteps.delete(stepKey);\n return { steps: newSteps };\n}\n\n/**\n * Check if a step in resume state has a pending approval error.\n *\n * @param state - The resume state to check\n * @param stepKey - The key of the step to check\n * @returns `true` if the step has a pending approval, `false` otherwise\n *\n * @example\n * ```typescript\n * if (hasPendingApproval(savedState, 'deploy:prod')) {\n * // Show approval UI\n * }\n * ```\n */\nexport function hasPendingApproval(\n state: ResumeState,\n stepKey: string\n): boolean {\n const entry = state.steps.get(stepKey);\n if (!entry || entry.result.ok) return false;\n return isPendingApproval(entry.result.error);\n}\n\n/**\n * Get all pending approval step keys from resume state.\n *\n * @param state - The resume state to check\n * @returns Array of step keys that have pending approvals\n *\n * @example\n * ```typescript\n * const pendingKeys = getPendingApprovals(savedState);\n * // ['deploy:prod', 'deploy:staging']\n * ```\n */\nexport function getPendingApprovals(state: ResumeState): string[] {\n const pending: string[] = [];\n for (const [key, entry] of state.steps) {\n if (!entry.result.ok && isPendingApproval(entry.result.error)) {\n pending.push(key);\n }\n }\n return pending;\n}\n\nconst HOOK_STEP_KEY_PREFIX = \"hook:\";\n\n/**\n * Inject a hook callback value into resume state.\n * Call this when the app receives the HTTP callback (e.g. POST /hook/:hookId) and pass the request body as value.\n *\n * @param state - The resume state to update\n * @param options - hookId (from the callback URL) and value (e.g. request body)\n * @returns A new ResumeState with the hook step set to ok(value)\n */\nexport function injectHook<T>(\n state: ResumeState,\n options: { hookId: string; value: T }\n): ResumeState {\n const newSteps = new Map(state.steps);\n newSteps.set(HOOK_STEP_KEY_PREFIX + options.hookId, {\n result: ok(options.value),\n });\n return { steps: newSteps };\n}\n\n/**\n * Check if a step in resume state has a pending hook error.\n *\n * @param state - The resume state to check\n * @param hookId - The hook id (from createHook() or the callback URL)\n * @returns `true` if that hook step is pending, `false` otherwise\n */\nexport function hasPendingHook(state: ResumeState, hookId: string): boolean {\n const entry = state.steps.get(HOOK_STEP_KEY_PREFIX + hookId);\n if (!entry || entry.result.ok) return false;\n return isPendingHook(entry.result.error);\n}\n\n/**\n * Get all pending hook hookIds from resume state.\n *\n * @param state - The resume state to check\n * @returns Array of hookIds that have pending callbacks\n */\nexport function getPendingHooks(state: ResumeState): string[] {\n const pending: string[] = [];\n for (const entry of state.steps.values()) {\n if (!entry.result.ok && isPendingHook(entry.result.error)) {\n pending.push((entry.result.error as { hookId: string }).hookId);\n }\n }\n return pending;\n}\n\n/**\n * Extended resume state collector that tracks pending approvals.\n * Use this for human-in-the-loop workflows that need to track approval state.\n *\n * @returns An object with methods to handle events, get state, and manage approvals\n *\n * @example\n * ```typescript\n * const collector = createApprovalStateCollector();\n *\n * const workflow = createWorkflow({ fetchUser, requireApproval }, {\n * onEvent: collector.handleEvent,\n * });\n *\n * const result = await workflow(async ({ step }) => {\n * const user = await step(() => fetchUser(\"1\"), { key: \"user:1\" });\n * const approval = await step(requireApproval, { key: \"approval:1\" });\n * return { user, approval };\n * });\n *\n * // Check for pending approvals\n * if (collector.hasPendingApprovals()) {\n * const pending = collector.getPendingApprovals();\n * // pending: [{ stepKey: 'approval:1', error: PendingApproval }]\n * await saveToDatabase(collector.getResumeState());\n * }\n *\n * // Later, when approved:\n * const resumeState = collector.injectApproval('approval:1', { approvedBy: 'admin' });\n * ```\n */\nexport function createApprovalStateCollector(): {\n /** Handle workflow events. Pass this to workflow's `onEvent` option. */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n /** Get the collected resume state. Call after workflow execution. */\n getResumeState: () => ResumeState;\n /** Clears the collector's internal recorded entries (does not mutate workflow state). */\n clear: () => void;\n /** Check if any steps have pending approvals */\n hasPendingApprovals: () => boolean;\n /** Get all pending approval entries with their errors */\n getPendingApprovals: () => Array<{ stepKey: string; error: PendingApproval }>;\n /** Inject an approval result, updating the collector's internal state. Returns a copy for use as resumeState. */\n injectApproval: <T>(stepKey: string, value: T) => ResumeState;\n} {\n const steps = new Map<string, ResumeStateEntry>();\n\n return {\n handleEvent: (event: WorkflowEvent<unknown>) => {\n if (isStepComplete(event)) {\n steps.set(event.stepKey, { result: event.result, meta: event.meta });\n }\n },\n getResumeState: () => ({ steps: new Map(steps) }),\n clear: () => steps.clear(),\n hasPendingApprovals: () => {\n for (const entry of steps.values()) {\n if (!entry.result.ok && isPendingApproval(entry.result.error)) {\n return true;\n }\n }\n return false;\n },\n getPendingApprovals: () => {\n const pending: Array<{ stepKey: string; error: PendingApproval }> = [];\n for (const [key, entry] of steps) {\n if (!entry.result.ok && isPendingApproval(entry.result.error)) {\n pending.push({ stepKey: key, error: entry.result.error as PendingApproval });\n }\n }\n return pending;\n },\n injectApproval: <T>(stepKey: string, value: T): ResumeState => {\n // Mutate internal state so collector reflects the approval\n steps.set(stepKey, { result: ok(value) });\n // Return a copy for use as resumeState\n return { steps: new Map(steps) };\n },\n };\n}\n","/**\n * awaitly/streaming - Types\n *\n * Core types for Result-aware streaming in workflows.\n * All stream operations return Result types, enabling typed error handling\n * throughout the streaming pipeline.\n */\n\nimport type { AsyncResult } from \"../core\";\n\n// =============================================================================\n// Stream Error Types\n// =============================================================================\n\n/** Discriminant for stream write errors */\nexport const STREAM_WRITE_ERROR = \"STREAM_WRITE_ERROR\" as const;\n\n/** Discriminant for stream read errors */\nexport const STREAM_READ_ERROR = \"STREAM_READ_ERROR\" as const;\n\n/** Discriminant for stream close errors */\nexport const STREAM_CLOSE_ERROR = \"STREAM_CLOSE_ERROR\" as const;\n\n/** Discriminant for stream store errors */\nexport const STREAM_STORE_ERROR = \"STREAM_STORE_ERROR\" as const;\n\n/** Discriminant for stream ended marker */\nexport const STREAM_ENDED = \"STREAM_ENDED\" as const;\n\n/** Discriminant for stream backpressure errors */\nexport const STREAM_BACKPRESSURE_ERROR = \"STREAM_BACKPRESSURE_ERROR\" as const;\n\n/**\n * Error returned when a write operation fails.\n */\nexport type StreamWriteError = {\n type: typeof STREAM_WRITE_ERROR;\n reason: \"closed\" | \"aborted\" | \"store_error\";\n message: string;\n cause?: unknown;\n};\n\n/**\n * Error returned when a read operation fails.\n */\nexport type StreamReadError = {\n type: typeof STREAM_READ_ERROR;\n reason: \"closed\" | \"store_error\";\n message: string;\n cause?: unknown;\n};\n\n/**\n * Error returned when closing a stream fails.\n */\nexport type StreamCloseError = {\n type: typeof STREAM_CLOSE_ERROR;\n reason: \"already_closed\" | \"store_error\";\n message: string;\n cause?: unknown;\n};\n\n/**\n * Error returned from StreamStore operations.\n */\nexport type StreamStoreError = {\n type: typeof STREAM_STORE_ERROR;\n reason: \"read_error\" | \"write_error\" | \"metadata_error\" | \"close_error\";\n message: string;\n cause?: unknown;\n};\n\n/**\n * Marker indicating stream has ended (not an error, but a terminal state).\n * Used as the \"error\" type when stream is exhausted.\n */\nexport type StreamEndedMarker = {\n type: typeof STREAM_ENDED;\n finalPosition: number;\n};\n\n/**\n * Backpressure error when writer is paused.\n */\nexport type StreamBackpressureError = {\n type: typeof STREAM_BACKPRESSURE_ERROR;\n bufferedCount: number;\n highWaterMark: number;\n};\n\n/**\n * Union of all stream errors.\n */\nexport type StreamError =\n | StreamWriteError\n | StreamReadError\n | StreamCloseError\n | StreamStoreError\n | StreamBackpressureError;\n\n// =============================================================================\n// Stream Item Types\n// =============================================================================\n\n/**\n * A single item in the stream with metadata.\n */\nexport interface StreamItem<T> {\n /** The value stored in this stream item */\n value: T;\n /** Position in the stream (0-indexed) */\n position: number;\n /** Timestamp when item was written */\n ts: number;\n}\n\n/**\n * Metadata about a stream.\n */\nexport interface StreamMetadata {\n /** Unique identifier for the stream (workflowId + namespace) */\n id: string;\n /** Namespace within the workflow */\n namespace: string;\n /** Workflow ID that owns this stream */\n workflowId: string;\n /** Number of items in the stream */\n length: number;\n /** Whether the stream has been closed */\n closed: boolean;\n /** Timestamp when stream was created */\n createdAt: number;\n /** Timestamp when stream was last written to */\n lastWriteAt?: number;\n /** Timestamp when stream was closed */\n closedAt?: number;\n}\n\n// =============================================================================\n// Stream Options\n// =============================================================================\n\n/**\n * Options for creating a writable stream.\n */\nexport interface StreamOptions {\n /** Named streams (default: 'default') */\n namespace?: string;\n /** Backpressure threshold (default: 16) */\n highWaterMark?: number;\n}\n\n/**\n * Options for creating a readable stream.\n */\nexport interface StreamReadOptions {\n /** Named streams (default: 'default') */\n namespace?: string;\n /** Resume from position (0-indexed) */\n startIndex?: number;\n}\n\n/**\n * Options for streamForEach operation.\n */\nexport interface StreamForEachOptions {\n /** Name for the operation (used in events) */\n name?: string;\n /** Checkpoint after every N items (default: 1 = checkpoint each item) */\n checkpointInterval?: number;\n /** Maximum concurrent processors (default: 1 = sequential) */\n concurrency?: number;\n}\n\n/**\n * Result from streamForEach operation.\n */\nexport interface StreamForEachResult<R> {\n /** Results from each processed item */\n results: R[];\n /** Total items processed */\n processedCount: number;\n /** Position of last processed item */\n lastPosition: number;\n}\n\n// =============================================================================\n// StreamWriter Interface\n// =============================================================================\n\n/**\n * Writable stream interface - never throws, returns Results.\n *\n * Use within a step to write values to a stream that can be consumed\n * by readers (e.g., HTTP response streaming, AI token streaming).\n *\n * @template T - Type of values written to the stream\n *\n * @example\n * ```typescript\n * const writer = step.getWritable<string>({ namespace: 'ai-response' });\n *\n * await step(() => generateAI({\n * prompt: 'Hello',\n * onToken: async (token) => { await writer.write(token); }\n * }), { key: 'generate' });\n *\n * await writer.close();\n * ```\n */\nexport interface StreamWriter<T> {\n /**\n * Write a value to the stream.\n * Returns an error if the stream is closed, aborted, or store fails.\n */\n write(value: T): AsyncResult<void, StreamWriteError>;\n\n /**\n * Close the stream normally.\n * Signals to readers that no more data will be written.\n */\n close(): AsyncResult<void, StreamCloseError>;\n\n /**\n * Abort the stream with a reason.\n * Use for error conditions that should terminate the stream.\n */\n abort(reason: unknown): void;\n\n /** Whether the stream is still writable */\n readonly writable: boolean;\n\n /** Current write position (number of items written) */\n readonly position: number;\n\n /** Stream namespace */\n readonly namespace: string;\n}\n\n/**\n * Readable stream interface - returns STREAM_ENDED marker when complete.\n *\n * Use to consume values from a stream, with support for resuming from\n * a specific position.\n *\n * @template T - Type of values read from the stream\n *\n * @example\n * ```typescript\n * const reader = getStreamReader<string>(runId, { namespace: 'ai-response' });\n *\n * let result = await reader.read();\n * while (result.ok) {\n * response.write(result.value);\n * result = await reader.read();\n * }\n *\n * if (result.error.type === 'STREAM_ENDED') {\n * console.log('Stream complete at position', result.error.finalPosition);\n * }\n * ```\n */\nexport interface StreamReader<T> {\n /**\n * Read the next value from the stream.\n * Returns StreamEndedMarker when stream is exhausted.\n */\n read(): AsyncResult<T, StreamReadError | StreamEndedMarker>;\n\n /**\n * Close the reader (stop consuming).\n * Does not affect the underlying stream.\n */\n close(): void;\n\n /** Whether there may be more data to read */\n readonly readable: boolean;\n\n /** Current read position */\n readonly position: number;\n\n /** Stream namespace */\n readonly namespace: string;\n}\n\n// =============================================================================\n// StreamStore Interface\n// =============================================================================\n\n/** Unsubscribe function returned by subscribe */\nexport type Unsubscribe = () => void;\n\n/**\n * Storage backend for stream data.\n * Follows the same patterns as persistence.ts adapters.\n *\n * @example In-memory store\n * ```typescript\n * const store = createMemoryStreamStore();\n * ```\n *\n * @example File-based store\n * ```typescript\n * const store = createFileStreamStore({ directory: './streams', fs });\n * ```\n */\nexport interface StreamStore {\n /**\n * Append an item to the stream.\n */\n append<T>(\n workflowId: string,\n namespace: string,\n item: StreamItem<T>\n ): AsyncResult<void, StreamStoreError>;\n\n /**\n * Read items from the stream starting at an index.\n * @param startIndex - Position to start reading from (0-indexed)\n * @param limit - Maximum number of items to read (default: all remaining)\n */\n read<T>(\n workflowId: string,\n namespace: string,\n startIndex: number,\n limit?: number\n ): AsyncResult<StreamItem<T>[], StreamStoreError>;\n\n /**\n * Get metadata about a stream.\n * Returns undefined if stream doesn't exist.\n */\n getMetadata(\n workflowId: string,\n namespace: string\n ): AsyncResult<StreamMetadata | undefined, StreamStoreError>;\n\n /**\n * Mark stream as closed.\n */\n closeStream(\n workflowId: string,\n namespace: string\n ): AsyncResult<void, StreamStoreError>;\n\n /**\n * Subscribe to new items in a stream.\n * Callback is invoked for each new item written.\n * Returns unsubscribe function.\n */\n subscribe<T>(\n workflowId: string,\n namespace: string,\n callback: (item: StreamItem<T>) => void\n ): Unsubscribe;\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Check if an error is a StreamEndedMarker.\n */\nexport function isStreamEnded(error: unknown): error is StreamEndedMarker {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as StreamEndedMarker).type === STREAM_ENDED\n );\n}\n\n/**\n * Check if an error is a StreamWriteError.\n */\nexport function isStreamWriteError(error: unknown): error is StreamWriteError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as StreamWriteError).type === STREAM_WRITE_ERROR\n );\n}\n\n/**\n * Check if an error is a StreamReadError.\n */\nexport function isStreamReadError(error: unknown): error is StreamReadError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as StreamReadError).type === STREAM_READ_ERROR\n );\n}\n\n/**\n * Check if an error is a StreamStoreError.\n */\nexport function isStreamStoreError(error: unknown): error is StreamStoreError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as StreamStoreError).type === STREAM_STORE_ERROR\n );\n}\n\n/**\n * Check if an error is a StreamBackpressureError.\n */\nexport function isStreamBackpressureError(\n error: unknown\n): error is StreamBackpressureError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as StreamBackpressureError).type === STREAM_BACKPRESSURE_ERROR\n );\n}\n\n// =============================================================================\n// Error Constructors\n// =============================================================================\n\n/**\n * Create a StreamWriteError.\n */\nexport function streamWriteError(\n reason: StreamWriteError[\"reason\"],\n message: string,\n cause?: unknown\n): StreamWriteError {\n return {\n type: STREAM_WRITE_ERROR,\n reason,\n message,\n ...(cause !== undefined ? { cause } : {}),\n };\n}\n\n/**\n * Create a StreamReadError.\n */\nexport function streamReadError(\n reason: StreamReadError[\"reason\"],\n message: string,\n cause?: unknown\n): StreamReadError {\n return {\n type: STREAM_READ_ERROR,\n reason,\n message,\n ...(cause !== undefined ? { cause } : {}),\n };\n}\n\n/**\n * Create a StreamCloseError.\n */\nexport function streamCloseError(\n reason: StreamCloseError[\"reason\"],\n message: string,\n cause?: unknown\n): StreamCloseError {\n return {\n type: STREAM_CLOSE_ERROR,\n reason,\n message,\n ...(cause !== undefined ? { cause } : {}),\n };\n}\n\n/**\n * Create a StreamStoreError.\n */\nexport function streamStoreError(\n reason: StreamStoreError[\"reason\"],\n message: string,\n cause?: unknown\n): StreamStoreError {\n return {\n type: STREAM_STORE_ERROR,\n reason,\n message,\n ...(cause !== undefined ? { cause } : {}),\n };\n}\n\n/**\n * Create a StreamEndedMarker.\n */\nexport function streamEnded(finalPosition: number): StreamEndedMarker {\n return {\n type: STREAM_ENDED,\n finalPosition,\n };\n}\n\n/**\n * Create a StreamBackpressureError.\n */\nexport function streamBackpressureError(\n bufferedCount: number,\n highWaterMark: number\n): StreamBackpressureError {\n return {\n type: STREAM_BACKPRESSURE_ERROR,\n bufferedCount,\n highWaterMark,\n };\n}\n","/**\n * awaitly/streaming - Backpressure Controller\n *\n * Implements flow control for streams using high-water mark.\n * When buffered items exceed the threshold, writers are paused\n * until consumers catch up.\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * State of the backpressure controller.\n */\nexport type BackpressureState = \"flowing\" | \"paused\";\n\n/**\n * Callback invoked when backpressure state changes.\n */\nexport type BackpressureCallback = (state: BackpressureState) => void;\n\n/**\n * Options for creating a BackpressureController.\n */\nexport interface BackpressureOptions {\n /** High-water mark threshold (default: 16) */\n highWaterMark?: number;\n /** Low-water mark to resume (default: highWaterMark / 2) */\n lowWaterMark?: number;\n /** Callback when state changes */\n onStateChange?: BackpressureCallback;\n}\n\n// =============================================================================\n// BackpressureController\n// =============================================================================\n\n/**\n * Controller for managing stream backpressure.\n *\n * When the number of buffered items exceeds the high-water mark,\n * the controller enters \"paused\" state. It returns to \"flowing\"\n * when items are consumed and the buffer drops below the low-water mark.\n *\n * @example\n * ```typescript\n * const controller = createBackpressureController({ highWaterMark: 16 });\n *\n * // Track writes\n * controller.increment();\n * if (controller.state === 'paused') {\n * await controller.waitForDrain();\n * }\n *\n * // Track reads (consumer)\n * controller.decrement();\n * ```\n */\nexport interface BackpressureController {\n /** Current state */\n readonly state: BackpressureState;\n\n /** Current number of buffered items */\n readonly bufferedCount: number;\n\n /** High-water mark threshold */\n readonly highWaterMark: number;\n\n /** Low-water mark threshold */\n readonly lowWaterMark: number;\n\n /** Increment buffered count (called on write) */\n increment(): void;\n\n /** Decrement buffered count (called on read/consume) */\n decrement(): void;\n\n /** Set buffered count directly (for resuming) */\n setCount(count: number): void;\n\n /**\n * Wait for the buffer to drain below low-water mark.\n * Resolves immediately if already flowing.\n */\n waitForDrain(): Promise<void>;\n\n /** Reset the controller to initial state */\n reset(): void;\n}\n\n/**\n * Create a backpressure controller.\n *\n * @param options - Configuration options\n * @returns BackpressureController instance\n */\nexport function createBackpressureController(\n options: BackpressureOptions = {}\n): BackpressureController {\n const highWaterMark = options.highWaterMark ?? 16;\n const lowWaterMark = options.lowWaterMark ?? Math.floor(highWaterMark / 2);\n const onStateChange = options.onStateChange;\n\n let state: BackpressureState = \"flowing\";\n let bufferedCount = 0;\n let drainResolvers: Array<() => void> = [];\n\n function updateState(newState: BackpressureState): void {\n if (state !== newState) {\n state = newState;\n onStateChange?.(newState);\n\n // Resolve drain waiters when transitioning to flowing\n if (newState === \"flowing\" && drainResolvers.length > 0) {\n const resolvers = drainResolvers;\n drainResolvers = [];\n for (const resolve of resolvers) {\n resolve();\n }\n }\n }\n }\n\n function checkState(): void {\n if (state === \"flowing\" && bufferedCount >= highWaterMark) {\n updateState(\"paused\");\n } else if (state === \"paused\" && bufferedCount <= lowWaterMark) {\n updateState(\"flowing\");\n }\n }\n\n return {\n get state() {\n return state;\n },\n\n get bufferedCount() {\n return bufferedCount;\n },\n\n get highWaterMark() {\n return highWaterMark;\n },\n\n get lowWaterMark() {\n return lowWaterMark;\n },\n\n increment(): void {\n bufferedCount++;\n checkState();\n },\n\n decrement(): void {\n if (bufferedCount > 0) {\n bufferedCount--;\n checkState();\n }\n },\n\n setCount(count: number): void {\n bufferedCount = Math.max(0, count);\n checkState();\n },\n\n waitForDrain(): Promise<void> {\n if (state === \"flowing\") {\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n drainResolvers.push(resolve);\n });\n },\n\n reset(): void {\n bufferedCount = 0;\n drainResolvers = [];\n updateState(\"flowing\");\n },\n };\n}\n\n// =============================================================================\n// Utilities\n// =============================================================================\n\n/**\n * Check if backpressure should be applied.\n */\nexport function shouldApplyBackpressure(\n controller: BackpressureController\n): boolean {\n return controller.state === \"paused\";\n}\n","/**\n * awaitly/duration\n *\n * Type-safe duration handling inspired by Effect's Duration module.\n * Prevents unit confusion (milliseconds vs seconds) with explicit constructors.\n */\n\n// =============================================================================\n// Duration Type\n// =============================================================================\n\n/**\n * A type-safe representation of a time duration.\n * Use the constructor functions (millis, seconds, etc.) to create durations.\n */\nexport interface Duration {\n readonly _tag: \"Duration\";\n readonly millis: number;\n}\n\n// =============================================================================\n// Constructors\n// =============================================================================\n\n/**\n * Create a Duration from milliseconds.\n *\n * @example\n * ```typescript\n * const d = Duration.millis(500)\n * ```\n */\nexport function millis(ms: number): Duration {\n return { _tag: \"Duration\", millis: ms };\n}\n\n/**\n * Create a Duration from seconds.\n *\n * @example\n * ```typescript\n * const d = Duration.seconds(5) // 5000ms\n * ```\n */\nexport function seconds(s: number): Duration {\n return { _tag: \"Duration\", millis: s * 1000 };\n}\n\n/**\n * Create a Duration from minutes.\n *\n * @example\n * ```typescript\n * const d = Duration.minutes(2) // 120000ms\n * ```\n */\nexport function minutes(m: number): Duration {\n return { _tag: \"Duration\", millis: m * 60 * 1000 };\n}\n\n/**\n * Create a Duration from hours.\n *\n * @example\n * ```typescript\n * const d = Duration.hours(1) // 3600000ms\n * ```\n */\nexport function hours(h: number): Duration {\n return { _tag: \"Duration\", millis: h * 60 * 60 * 1000 };\n}\n\n/**\n * Create a Duration from days.\n *\n * @example\n * ```typescript\n * const d = Duration.days(1) // 86400000ms\n * ```\n */\nexport function days(d: number): Duration {\n return { _tag: \"Duration\", millis: d * 24 * 60 * 60 * 1000 };\n}\n\n/**\n * Zero duration.\n */\nexport const zero: Duration = { _tag: \"Duration\", millis: 0 };\n\n/**\n * Infinite duration (represented as Infinity milliseconds).\n */\nexport const infinity: Duration = { _tag: \"Duration\", millis: Infinity };\n\n// =============================================================================\n// Conversions\n// =============================================================================\n\n/**\n * Convert a Duration to milliseconds.\n */\nexport function toMillis(duration: Duration): number {\n return duration.millis;\n}\n\n/**\n * Convert a Duration to seconds.\n */\nexport function toSeconds(duration: Duration): number {\n return duration.millis / 1000;\n}\n\n/**\n * Convert a Duration to minutes.\n */\nexport function toMinutes(duration: Duration): number {\n return duration.millis / (60 * 1000);\n}\n\n/**\n * Convert a Duration to hours.\n */\nexport function toHours(duration: Duration): number {\n return duration.millis / (60 * 60 * 1000);\n}\n\n/**\n * Convert a Duration to days.\n */\nexport function toDays(duration: Duration): number {\n return duration.millis / (24 * 60 * 60 * 1000);\n}\n\n// =============================================================================\n// Operations\n// =============================================================================\n\n/**\n * Add two durations.\n *\n * @example\n * ```typescript\n * const total = Duration.add(Duration.seconds(5), Duration.millis(500))\n * // 5500ms\n * ```\n */\nexport function add(a: Duration, b: Duration): Duration {\n return { _tag: \"Duration\", millis: a.millis + b.millis };\n}\n\n/**\n * Subtract duration b from duration a.\n * Result is clamped to zero (no negative durations).\n *\n * @example\n * ```typescript\n * const remaining = Duration.subtract(Duration.seconds(5), Duration.seconds(2))\n * // 3000ms\n * ```\n */\nexport function subtract(a: Duration, b: Duration): Duration {\n return { _tag: \"Duration\", millis: Math.max(0, a.millis - b.millis) };\n}\n\n/**\n * Multiply a duration by a factor.\n *\n * @example\n * ```typescript\n * const doubled = Duration.multiply(Duration.seconds(5), 2)\n * // 10000ms\n * ```\n */\nexport function multiply(duration: Duration, factor: number): Duration {\n return { _tag: \"Duration\", millis: duration.millis * factor };\n}\n\n/**\n * Divide a duration by a divisor.\n *\n * @example\n * ```typescript\n * const half = Duration.divide(Duration.seconds(10), 2)\n * // 5000ms\n * ```\n */\nexport function divide(duration: Duration, divisor: number): Duration {\n return { _tag: \"Duration\", millis: duration.millis / divisor };\n}\n\n// =============================================================================\n// Comparisons\n// =============================================================================\n\n/**\n * Check if duration a is less than duration b.\n */\nexport function lessThan(a: Duration, b: Duration): boolean {\n return a.millis < b.millis;\n}\n\n/**\n * Check if duration a is less than or equal to duration b.\n */\nexport function lessThanOrEqual(a: Duration, b: Duration): boolean {\n return a.millis <= b.millis;\n}\n\n/**\n * Check if duration a is greater than duration b.\n */\nexport function greaterThan(a: Duration, b: Duration): boolean {\n return a.millis > b.millis;\n}\n\n/**\n * Check if duration a is greater than or equal to duration b.\n */\nexport function greaterThanOrEqual(a: Duration, b: Duration): boolean {\n return a.millis >= b.millis;\n}\n\n/**\n * Check if two durations are equal.\n */\nexport function equals(a: Duration, b: Duration): boolean {\n return a.millis === b.millis;\n}\n\n/**\n * Get the minimum of two durations.\n */\nexport function min(a: Duration, b: Duration): Duration {\n return a.millis <= b.millis ? a : b;\n}\n\n/**\n * Get the maximum of two durations.\n */\nexport function max(a: Duration, b: Duration): Duration {\n return a.millis >= b.millis ? a : b;\n}\n\n/**\n * Clamp a duration between a minimum and maximum.\n */\nexport function clamp(duration: Duration, minimum: Duration, maximum: Duration): Duration {\n return min(max(duration, minimum), maximum);\n}\n\n// =============================================================================\n// Predicates\n// =============================================================================\n\n/**\n * Check if a duration is zero.\n */\nexport function isZero(duration: Duration): boolean {\n return duration.millis === 0;\n}\n\n/**\n * Check if a duration is infinite.\n */\nexport function isInfinite(duration: Duration): boolean {\n return duration.millis === Infinity;\n}\n\n/**\n * Check if a duration is finite and positive.\n */\nexport function isFinite(duration: Duration): boolean {\n return Number.isFinite(duration.millis) && duration.millis > 0;\n}\n\n/**\n * Type guard to check if a value is a Duration.\n */\nexport function isDuration(value: unknown): value is Duration {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"_tag\" in value &&\n value._tag === \"Duration\" &&\n \"millis\" in value &&\n typeof value.millis === \"number\"\n );\n}\n\n// =============================================================================\n// Formatting\n// =============================================================================\n\n/**\n * Format a duration as a human-readable string.\n *\n * @example\n * ```typescript\n * Duration.format(Duration.seconds(90)) // \"1m 30s\"\n * Duration.format(Duration.millis(500)) // \"500ms\"\n * ```\n */\nexport function format(duration: Duration): string {\n const ms = duration.millis;\n\n if (ms === Infinity) return \"∞\";\n if (ms === 0) return \"0ms\";\n\n const days = Math.floor(ms / (24 * 60 * 60 * 1000));\n const hours = Math.floor((ms % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));\n const minutes = Math.floor((ms % (60 * 60 * 1000)) / (60 * 1000));\n const seconds = Math.floor((ms % (60 * 1000)) / 1000);\n const millis = ms % 1000;\n\n const parts: string[] = [];\n if (days > 0) parts.push(`${days}d`);\n if (hours > 0) parts.push(`${hours}h`);\n if (minutes > 0) parts.push(`${minutes}m`);\n if (seconds > 0) parts.push(`${seconds}s`);\n if (millis > 0 && parts.length === 0) parts.push(`${millis}ms`);\n\n return parts.join(\" \") || \"0ms\";\n}\n\n// =============================================================================\n// Parsing\n// =============================================================================\n\n/**\n * Parse a duration from a string like \"100ms\", \"5s\", \"2m\", \"1h\", \"1d\".\n * Returns undefined if parsing fails.\n *\n * @example\n * ```typescript\n * Duration.parse(\"5s\") // Duration.seconds(5)\n * Duration.parse(\"100ms\") // Duration.millis(100)\n * Duration.parse(\"2m\") // Duration.minutes(2)\n * ```\n */\nexport function parse(input: string): Duration | undefined {\n const match = input.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h|d)$/i);\n if (!match) return undefined;\n\n const value = parseFloat(match[1]);\n const unit = match[2].toLowerCase();\n\n switch (unit) {\n case \"ms\":\n return millis(value);\n case \"s\":\n return seconds(value);\n case \"m\":\n return minutes(value);\n case \"h\":\n return hours(value);\n case \"d\":\n return days(value);\n default:\n return undefined;\n }\n}\n\n// =============================================================================\n// Namespace Export\n// =============================================================================\n\n/**\n * Duration namespace with all functions for convenient access.\n *\n * @example\n * ```typescript\n * import { Duration } from \"awaitly\";\n *\n * const timeout = Duration.seconds(30);\n * const delay = Duration.millis(100);\n * const total = Duration.add(timeout, delay);\n *\n * console.log(Duration.format(total)); // \"30s 100ms\"\n * ```\n */\nexport const Duration = {\n // Constructors\n millis,\n seconds,\n minutes,\n hours,\n days,\n zero,\n infinity,\n\n // Conversions\n toMillis,\n toSeconds,\n toMinutes,\n toHours,\n toDays,\n\n // Operations\n add,\n subtract,\n multiply,\n divide,\n\n // Comparisons\n lessThan,\n lessThanOrEqual,\n greaterThan,\n greaterThanOrEqual,\n equals,\n min,\n max,\n clamp,\n\n // Predicates\n isZero,\n isInfinite,\n isFinite,\n isDuration,\n\n // Formatting\n format,\n parse,\n} as const;\n\nexport type { Duration as DurationType };\n","/**\n * Optional input validation using the Standard Schema spec.\n * Works with Zod, Valibot, ArkType, or any Standard Schema-compliant library.\n *\n * @see https://github.com/standard-schema/standard-schema\n */\n\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { ok, err, type Result } from \"../core\";\n\n/**\n * Tagged error returned when workflow input fails schema validation.\n * Follows awaitly's tagged error object pattern (with `type` field).\n */\nexport type InputValidationError = {\n type: \"INPUT_VALIDATION_ERROR\";\n issues: Array<{ message: string; path?: Array<string | number> }>;\n message: string;\n};\n\n/**\n * Type guard for InputValidationError.\n */\nexport function isInputValidationError(e: unknown): e is InputValidationError {\n return (\n typeof e === \"object\" &&\n e !== null &&\n (e as InputValidationError).type === \"INPUT_VALIDATION_ERROR\"\n );\n}\n\n/**\n * Validate input against a Standard Schema.\n * Supports both sync and async schema validation.\n *\n * @param schema - A Standard Schema-compliant schema object\n * @param input - The input value to validate\n * @returns Result with validated value or InputValidationError\n */\nexport async function validateInput<T>(\n schema: StandardSchemaV1<T>,\n input: unknown\n): Promise<Result<T, InputValidationError>> {\n const result = schema[\"~standard\"].validate(input);\n // Standard Schema allows sync or async validation\n const resolved = result instanceof Promise ? await result : result;\n if (resolved.issues) {\n return err({\n type: \"INPUT_VALIDATION_ERROR\" as const,\n issues: resolved.issues.map((i) => ({\n message: i.message,\n path: i.path?.map((p) =>\n typeof p === \"object\" ? (p as { key: string | number }).key : p\n ) as Array<string | number> | undefined,\n })),\n message: `Input validation failed: ${resolved.issues.map((i) => i.message).join(\", \")}`,\n });\n }\n return ok(resolved.value as T);\n}\n","/**\n * createWorkflow implementation and workflow execution logic.\n */\n\nimport {\n run,\n ok,\n err,\n createEarlyExit,\n isEarlyExit,\n isUnexpectedError,\n defaultCatchUnexpected,\n type EarlyExit,\n type StepFailureMeta,\n type Result,\n type AsyncResult,\n type UnexpectedError,\n type RunStep,\n type WorkflowEvent,\n type StepOptions,\n type RetryOptions,\n type TimeoutOptions,\n type StreamWritableOptions,\n type StreamReadableOptions,\n type StreamForEachStepOptions,\n type StreamForEachResultType,\n type StreamWriterInterface,\n type StreamReaderInterface,\n extractStepMetadata,\n} from \"../core\";\n\nimport type {\n StreamStore,\n StreamItem,\n StreamWriter,\n StreamReader,\n StreamWriteError,\n StreamCloseError,\n StreamReadError,\n StreamEndedMarker,\n} from \"../streaming/types\";\n\nimport {\n streamWriteError,\n streamReadError,\n streamCloseError,\n streamEnded,\n} from \"../streaming/types\";\n\nimport {\n createBackpressureController,\n type BackpressureController,\n} from \"../streaming/backpressure\";\n\nimport { parse as parseDuration, toMillis, type Duration as DurationType } from \"../duration\";\n\nimport type {\n StepCache,\n ResumeState,\n AnyResultFn,\n ErrorsOfDeps,\n WorkflowOptions,\n WorkflowContext,\n WorkflowFn,\n RunConfig,\n Workflow,\n WorkflowCancelledError,\n} from \"./types\";\n\nimport { createResumeStateCollector } from \"./resume-state\";\n\nimport {\n encodeCachedError,\n decodeCachedMeta,\n} from \"./cache-encoding\";\n\nimport { isWorkflowCancelled } from \"./guards\";\nimport { validateInput } from \"./validation\";\n\nimport type {\n JSONValue,\n WorkflowSnapshot,\n} from \"../persistence\";\n\nimport {\n deserializeCauseNew,\n SnapshotDecodeError,\n} from \"../persistence\";\n// =============================================================================\n// createWorkflow - Automatic Error Type Inference\n// =============================================================================\n\n/**\n * Create a typed workflow with automatic error inference.\n *\n * ## When to Use `createWorkflow`\n *\n * Use `createWorkflow` when you have:\n * - **Multiple dependent async operations** that need to run sequentially\n * - **Complex error handling** where you want type-safe error unions\n * - **Need for observability** via event streams (onEvent)\n * - **Step caching** requirements for expensive operations\n * - **Resume/replay** capabilities for long-running workflows\n * - **Human-in-the-loop** workflows requiring approvals\n *\n * ## Why Use `createWorkflow` Instead of `run()`\n *\n * 1. **Automatic Error Type Inference**: Errors are computed from your declared functions\n * - No manual error union management\n * - TypeScript ensures all possible errors are handled\n * - Refactoring is safer - adding/removing functions updates error types automatically\n *\n * 2. **Step Caching**: Expensive operations can be cached by key\n * - Prevents duplicate API calls\n * - Useful for idempotent operations\n * - Supports resume state for workflow replay\n *\n * 3. **Event Stream**: Built-in observability via `onEvent`\n * - Track workflow and step lifecycle\n * - Monitor performance (durationMs)\n * - Build dashboards and debugging tools\n *\n * 4. **Resume State**: Save and replay workflows\n * - Useful for long-running processes\n * - Supports human-in-the-loop workflows\n * - Enables workflow persistence across restarts\n *\n * ## How It Works\n *\n * 1. **Declare Dependencies**: Pass an object of Result-returning functions\n * 2. **Automatic Inference**: Error types are extracted from function return types\n * 3. **Execute Workflow**: Call the returned workflow function with your logic\n * 4. **Early Exit**: `step()` unwraps Results - on error, workflow exits immediately\n *\n * ## Error Type Inference\n *\n * The error union is automatically computed from all declared functions:\n * - Each function's error type is extracted\n * - Union of all errors is created\n * - Uncaught exceptions are mapped via `catchUnexpected` (default: `UnexpectedError`).\n *\n * ## Strict Mode\n *\n * Optional `catchUnexpected` maps uncaught exceptions to a typed error (closed union):\n * - When omitted, the default mapper returns an `UnexpectedError` instance.\n * - When provided, your error union is exactly `E | U`.\n *\n * @param deps - Object mapping names to Result-returning functions.\n * These functions must return `Result<T, E>` or `Promise<Result<T, E>>`.\n * The error types (`E`) from all functions are automatically combined into a union.\n * @param options - Optional configuration:\n * - `onEvent`: Callback for workflow/step lifecycle events\n * - `onError`: Callback for error logging/debugging\n * - `cache`: Step result cache (Map or custom StepCache implementation)\n * - `resumeState`: Pre-populated step results for workflow replay\n * - `createContext`: Factory for per-run context (passed to onEvent)\n * - `catchUnexpected`: Optional; map uncaught exceptions to a typed error (default: `UnexpectedError`)\n *\n * @returns A workflow function that accepts your workflow logic and returns an AsyncResult.\n * The error type is automatically inferred from the `deps` parameter.\n *\n * @example\n * ```typescript\n * // Basic usage - automatic error inference\n * const fetchUser = async (id: string): AsyncResult<User, 'NOT_FOUND'> =>\n * id === '1' ? ok({ id, name: 'Alice' }) : err('NOT_FOUND');\n *\n * const fetchPosts = async (userId: string): AsyncResult<Post[], 'FETCH_ERROR'> =>\n * ok([{ id: 1, title: 'Hello' }]);\n *\n * const getPosts = createWorkflow({ fetchUser, fetchPosts });\n *\n * const result = await getPosts(async ({ step }) => {\n * const user = await step(fetchUser('1'));\n * const posts = await step(fetchPosts(user.id));\n * return { user, posts };\n * });\n * // result.error: 'NOT_FOUND' | 'FETCH_ERROR' | UnexpectedError\n * ```\n *\n * @example\n * ```typescript\n * // With destructured deps in callback\n * const result = await getPosts(async ({ step, deps: { fetchUser, fetchPosts } }) => {\n * const user = await step(fetchUser('1'));\n * const posts = await step(fetchPosts(user.id));\n * return { user, posts };\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Strict mode - closed error union (no UnexpectedError)\n * const getPosts = createWorkflow(\n * { fetchUser, fetchPosts },\n * {\n * catchUnexpected: () => 'UNEXPECTED' as const\n * }\n * );\n * // result.error: 'NOT_FOUND' | 'FETCH_ERROR' | 'UNEXPECTED'\n * ```\n *\n * @example\n * ```typescript\n * // With step caching - both patterns work identically\n * const cache = new Map<string, Result<unknown, unknown>>();\n * const workflow = createWorkflow({ fetchUser }, { cache });\n *\n * const result = await workflow(async ({ step }) => {\n * // Function-wrapped pattern with key - cached and emits step_complete\n * const user1 = await step(() => fetchUser('1'), { key: 'user:1' });\n *\n * // Direct AsyncResult pattern with key - also cached and emits step_complete\n * const user2 = await step(fetchUser('1'), { key: 'user:2' });\n *\n * // Same key uses cache (fetchUser not called again)\n * const user3 = await step(() => fetchUser('1'), { key: 'user:1' });\n * return { user1, user2, user3 }; // user1 === user3 (from cache)\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With event stream for observability\n * const workflow = createWorkflow({ fetchUser }, {\n * onEvent: (event) => {\n * if (event.type === 'step_start') {\n * console.log(`Step ${event.name} started`);\n * }\n * if (event.type === 'step_success') {\n * console.log(`Step ${event.name} completed in ${event.durationMs}ms`);\n * }\n * }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With resume state for workflow replay\n * const savedState = { steps: new Map([['user:1', { result: ok({ id: '1', name: 'Alice' }) }]]) };\n * const workflow = createWorkflow({ fetchUser }, { resumeState: savedState });\n *\n * const result = await workflow(async ({ step }) => {\n * // This step uses cached result from savedState (fetchUser not called)\n * const user = await step(() => fetchUser('1'), { key: 'user:1' });\n * return user;\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With typed arguments (new API)\n * const workflow = createWorkflow({ fetchUser, fetchPosts });\n *\n * const result = await workflow(\n * { userId: '1' }, // Typed arguments\n * async ({ step, deps: { fetchUser, fetchPosts }, args: { userId } }) => {\n * const user = await step(fetchUser(userId));\n * const posts = await step(fetchPosts(user.id));\n * return { user, posts };\n * }\n * );\n * ```\n */\n// Overload: no deps (single argument); callback receives deps: unknown\nexport function createWorkflow<\n U = UnexpectedError,\n C = void\n>(\n workflowName: string\n): Workflow<never, U, unknown, C>;\n\n// Overload: with deps\nexport function createWorkflow<\n const Deps extends Readonly<Record<string, AnyResultFn>>,\n U = UnexpectedError,\n C = void\n>(\n workflowName: string,\n deps: Deps,\n options?: WorkflowOptions<ErrorsOfDeps<Deps>, U, C>\n): Workflow<ErrorsOfDeps<Deps>, U, Deps, C>;\n\n// Implementation (deps optional for 1-arg overload compatibility)\nexport function createWorkflow<\n const Deps extends Readonly<Record<string, AnyResultFn>>,\n U = UnexpectedError,\n C = void\n>(\n workflowName: string,\n deps?: Deps,\n options?: WorkflowOptions<ErrorsOfDeps<Deps>, U, C>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): any {\n type E = ErrorsOfDeps<Deps>;\n\n if (typeof workflowName !== \"string\" || workflowName.length === 0) {\n throw new TypeError(\n \"createWorkflow(workflowName, deps, options?): first argument must be a non-empty string. Example: createWorkflow('checkout', { chargeCard, sendEmail })\"\n );\n }\n\n const depsActual = deps ?? ({} as Deps);\n const optionsActual = options;\n\n // ===========================================================================\n\n // ===========================================================================\n // Internal execute function - core workflow execution logic\n // ===========================================================================\n async function internalExecute<T, ExtraE = never>(\n runName: string | undefined,\n userFn: WorkflowFn<T, E | ExtraE, Deps, C>,\n config?: RunConfig<E, U, C, Deps>\n ): Promise<Result<T, E | ExtraE | U, unknown>> {\n // Generate workflowId for this run\n const workflowId = runName ?? crypto.randomUUID();\n\n // Merge deps: config.deps partially overrides creation-time deps\n const effectiveDeps = config?.deps ? { ...depsActual, ...config.deps } as Deps : depsActual;\n\n // ===========================================================================\n // Resolve hooks: config?.x ?? options?.x (run-time overrides creation-time)\n // Note: config.x = undefined does NOT override (uses creation-time)\n // config.x = null DOES override (users asked for it)\n // ===========================================================================\n\n // Create context for this run (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const createContextFn = config?.createContext ?? (optionsActual as any)?.createContext;\n const context = createContextFn ? await createContextFn() : undefined as C;\n\n // Get workflow-level signal (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const workflowSignal = (config?.signal ?? (optionsActual as any)?.signal) as AbortSignal | undefined;\n\n // Get event handler (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const onEventHandler = config?.onEvent ?? (optionsActual as any)?.onEvent;\n\n // Get error handler (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const onErrorHandler = config?.onError ?? (optionsActual as any)?.onError;\n\n // Get shouldRun hook (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const shouldRunHook = (config?.shouldRun ?? (optionsActual as any)?.shouldRun) as\n | ((workflowId: string, context: C) => boolean | Promise<boolean>)\n | undefined;\n\n // Get onBeforeStart hook (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const onBeforeStartHook = (config?.onBeforeStart ?? (optionsActual as any)?.onBeforeStart) as\n | ((workflowId: string, context: C) => boolean | Promise<boolean>)\n | undefined;\n\n // Get onAfterStep hook (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const onAfterStepHook = (config?.onAfterStep ?? (optionsActual as any)?.onAfterStep) as\n | ((\n stepKey: string,\n result: Result<unknown, unknown, unknown>,\n workflowId: string,\n context: C\n ) => void | Promise<void>)\n | undefined;\n\n // Get resumeState (config overrides options) - keep lazy, only evaluate when needed\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const resumeStateOption = (config?.resumeState ?? (optionsActual as any)?.resumeState) as\n | ResumeState\n | (() => ResumeState | Promise<ResumeState>)\n | undefined;\n\n // catchUnexpected: from creation-time options or default (UnexpectedError).\n // When omitted, U = UnexpectedError and we use defaultCatchUnexpected.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const catchUnexpected = (optionsActual as any)?.catchUnexpected ?? defaultCatchUnexpected;\n\n // Create workflow data store for step outputs\n const workflowData: Record<string, unknown> = {};\n\n // Check if dev warnings are enabled (config overrides options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const devWarnings = (config?.devWarnings ?? (optionsActual as any)?.devWarnings) === true && process.env.NODE_ENV !== 'production';\n const ctxSetWarned = new Set<string>(); // Avoid duplicate warnings per key\n const ctxGetWarned = new Set<string>();\n\n // Create workflow context object to pass to callback\n const workflowContext: WorkflowContext<C> = {\n workflowId,\n onEvent: onEventHandler as ((event: WorkflowEvent<unknown, C>) => void) | undefined,\n context: context !== undefined ? context : undefined,\n signal: workflowSignal,\n // Data store for static analysis\n input: {} as Record<string, unknown>,\n ref: <K extends string>(key: K) => workflowData[key] as never,\n set: <K extends string>(key: K, value: unknown) => {\n if (devWarnings && !ctxSetWarned.has(key)) {\n ctxSetWarned.add(key);\n console.warn(\n `awaitly: ctx.set('${key}', ...) is deprecated for static analysis. ` +\n `Use step('id', fn, { out: '${key}' }) instead.`\n );\n }\n workflowData[key] = value;\n },\n get: <K extends string>(key: K) => {\n if (devWarnings && !ctxGetWarned.has(key)) {\n ctxGetWarned.add(key);\n console.warn(\n `awaitly: ctx.get('${key}') is deprecated for static analysis. ` +\n `Use ctx.ref('${key}') instead for tracked dependencies.`\n );\n }\n return workflowData[key] as never;\n },\n };\n\n // Helper to emit workflow events (error union includes ExtraE from step.workflow/withFallback)\n const emitEvent = (event: WorkflowEvent<E | ExtraE | U, C>) => {\n // Add context to event only if:\n // 1. Event doesn't already have context (preserves replayed events or per-step overrides)\n // 2. Workflow actually has a context (don't add context: undefined property)\n const eventWithContext =\n event.context !== undefined || context === undefined\n ? event\n : ({ ...event, context: context as C } as WorkflowEvent<E | ExtraE | U, C>);\n const eventWithName =\n eventWithContext.workflowName === undefined\n ? ({ ...eventWithContext, workflowName } as WorkflowEvent<E | ExtraE | U, C>)\n : eventWithContext;\n onEventHandler?.(eventWithName as Parameters<NonNullable<typeof onEventHandler>>[0], context);\n };\n\n // Helper to create cancellation result (always map through catchUnexpected)\n const createCancelledResult = (reason?: string, lastStepKey?: string): Result<T, E | ExtraE | U, unknown> => {\n const cancelledError: WorkflowCancelledError = {\n type: \"WORKFLOW_CANCELLED\",\n reason,\n lastStepKey,\n };\n return err(catchUnexpected(cancelledError), { cause: cancelledError }) as Result<T, E | ExtraE | U, unknown>;\n };\n\n // Check if signal is already aborted before starting\n if (workflowSignal?.aborted) {\n const reason = typeof workflowSignal.reason === \"string\"\n ? workflowSignal.reason\n : workflowSignal.reason instanceof Error\n ? workflowSignal.reason.message\n : undefined;\n emitEvent({\n type: \"workflow_cancelled\",\n workflowId,\n ts: Date.now(),\n durationMs: 0,\n reason,\n });\n return createCancelledResult(reason);\n }\n\n if (shouldRunHook) {\n const hookStartTime = performance.now();\n try {\n const shouldRunResult = await shouldRunHook(workflowId, context);\n const hookDuration = performance.now() - hookStartTime;\n // Emit hook event\n emitEvent({\n type: \"hook_should_run\",\n workflowId,\n ts: Date.now(),\n durationMs: hookDuration,\n result: shouldRunResult,\n skipped: !shouldRunResult,\n });\n if (!shouldRunResult) {\n const skipCause = new Error(\"Workflow skipped by shouldRun hook\");\n return err(catchUnexpected(skipCause), { cause: skipCause }) as Result<T, E | ExtraE | U, unknown>;\n }\n } catch (thrown) {\n const hookDuration = performance.now() - hookStartTime;\n // Emit hook error event\n emitEvent({\n type: \"hook_should_run_error\",\n workflowId,\n ts: Date.now(),\n durationMs: hookDuration,\n error: thrown as E,\n });\n // Hook threw - map through catchUnexpected\n return err(catchUnexpected(thrown), { cause: thrown }) as Result<T, E | ExtraE | U, unknown>;\n }\n }\n\n if (onBeforeStartHook) {\n const hookStartTime = performance.now();\n try {\n const beforeStartResult = await onBeforeStartHook(workflowId, context);\n const hookDuration = performance.now() - hookStartTime;\n // Emit hook event\n emitEvent({\n type: \"hook_before_start\",\n workflowId,\n ts: Date.now(),\n durationMs: hookDuration,\n result: beforeStartResult,\n skipped: !beforeStartResult,\n });\n if (!beforeStartResult) {\n const skipCause = new Error(\"Workflow skipped by onBeforeStart hook\");\n return err(catchUnexpected(skipCause), { cause: skipCause }) as Result<T, E | ExtraE | U, unknown>;\n }\n } catch (thrown) {\n const hookDuration = performance.now() - hookStartTime;\n // Emit hook error event\n emitEvent({\n type: \"hook_before_start_error\",\n workflowId,\n ts: Date.now(),\n durationMs: hookDuration,\n error: thrown as E,\n });\n return err(catchUnexpected(thrown), { cause: thrown }) as Result<T, E | ExtraE | U, unknown>;\n }\n }\n\n // Validate input against schema if provided\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const inputSchema = (optionsActual as any)?.inputSchema;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const inputValue = (optionsActual as any)?.input;\n if (inputSchema) {\n const validationResult = await validateInput(inputSchema, inputValue);\n if (!validationResult.ok) {\n return err(validationResult.error) as Result<T, E | ExtraE | U, unknown>;\n }\n // Assign validated input to workflow context\n (workflowContext as { input: unknown }).input = validationResult.value;\n } else if (inputValue !== undefined) {\n // No schema, just pass input through to context\n (workflowContext as { input: unknown }).input = inputValue;\n }\n\n // Emit workflow_start\n const startTs = Date.now();\n const startTime = performance.now();\n emitEvent({\n type: \"workflow_start\",\n workflowId,\n ts: startTs,\n });\n\n // Get cache from config (overrides creation-time options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let cache = (config?.cache ?? (optionsActual as any)?.cache) as StepCache | undefined;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const streamStore = (config?.streamStore ?? (optionsActual as any)?.streamStore) as StreamStore | undefined;\n\n // If resumeState is provided but cache isn't, auto-create an in-memory cache\n if (resumeStateOption && !cache) {\n cache = new Map<string, Result<unknown, unknown, unknown>>();\n }\n\n // Pre-populate cache from resumeState (lazily evaluated)\n if (resumeStateOption && cache) {\n const resumeState =\n typeof resumeStateOption === \"function\"\n ? await resumeStateOption()\n : resumeStateOption;\n\n // Validate resumeState.steps is a Map (common mistake: JSON serialization loses Map)\n if (!(resumeState.steps instanceof Map)) {\n console.warn(\n `awaitly: resumeState.steps is not a Map (got ${typeof resumeState.steps}). ` +\n `This usually happens when state is serialized with JSON.stringify() directly.\\n` +\n `Use stringifyState() and parseState() from 'awaitly/persistence' instead:\\n` +\n ` import { stringifyState, parseState } from 'awaitly/persistence';\\n` +\n ` const json = stringifyState(state); // Save this\\n` +\n ` const restored = parseState(json); // Load this`\n );\n // Try to recover by converting plain object to Map\n if (typeof resumeState.steps === \"object\" && resumeState.steps !== null) {\n resumeState.steps = new Map(Object.entries(resumeState.steps));\n }\n }\n\n for (const [key, entry] of resumeState.steps) {\n const { result, meta } = entry;\n if (result.ok) {\n cache.set(key, result);\n } else {\n // Encode error results with metadata for proper replay\n // Use provided meta if available, otherwise default to origin:\"result\"\n const effectiveMeta = meta ?? { origin: \"result\" as const, resultCause: result.cause };\n // Preserve original cause alongside metadata\n cache.set(key, encodeCachedError(result.error, effectiveMeta, result.cause));\n }\n }\n }\n\n // Pre-populate cache from snapshot if provided via config (new API)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const snapshotOption = config?.snapshot ?? (optionsActual as any)?.snapshot as WorkflowSnapshot | null | undefined;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const snapshotSerialization = (optionsActual as any)?.serialization as { decode?: (value: JSONValue) => unknown } | undefined;\n if (snapshotOption && !resumeStateOption) {\n // Auto-create cache if needed\n if (!cache) {\n cache = new Map<string, Result<unknown, unknown, unknown>>();\n }\n\n const snapshot = snapshotOption;\n const decode = snapshotSerialization?.decode;\n\n for (const [stepId, stepResult] of Object.entries(snapshot.steps)) {\n if (!Object.prototype.hasOwnProperty.call(snapshot.steps, stepId)) {\n continue;\n }\n\n try {\n if (stepResult.ok) {\n // Decode value if decoder provided\n const value = decode ? decode(stepResult.value) : stepResult.value;\n cache.set(stepId, ok(value));\n } else {\n // Restore the original error value (decode if decoder provided)\n const errorValue = decode ? decode(stepResult.error) : stepResult.error;\n // Deserialize the cause (Error or thrown value)\n const deserializedCause = deserializeCauseNew(stepResult.cause);\n // Construct proper StepFailureMeta from snapshot\n const meta: StepFailureMeta = stepResult.meta?.origin === \"throw\"\n ? { origin: \"throw\", thrown: deserializedCause }\n : { origin: \"result\", resultCause: deserializedCause };\n cache.set(stepId, encodeCachedError(errorValue, meta, deserializedCause));\n }\n } catch (e) {\n throw new SnapshotDecodeError(\n `Failed to decode step \"${stepId}\": ${e instanceof Error ? e.message : String(e)}`,\n stepId,\n e instanceof Error ? e : undefined\n );\n }\n }\n }\n\n\n // Track abort state and last step key for mid-execution cancellation\n let abortedDuringExecution = false;\n let abortReason: string | undefined;\n let lastStepKey: string | undefined;\n\n // Set up abort listener if signal is provided\n const abortHandler = () => {\n abortedDuringExecution = true;\n abortReason = typeof workflowSignal?.reason === \"string\"\n ? workflowSignal.reason\n : workflowSignal?.reason instanceof Error\n ? workflowSignal.reason.message\n : undefined;\n };\n\n if (workflowSignal && !workflowSignal.aborted) {\n workflowSignal.addEventListener(\"abort\", abortHandler, { once: true });\n }\n\n // Helper to check for mid-execution cancellation and throw if aborted\n // lastStepKey = the last successfully completed keyed step (for resume purposes)\n const checkCancellation = (): void => {\n // Check both the flag and the signal directly (in case abort happened synchronously)\n if (abortedDuringExecution || workflowSignal?.aborted) {\n const reason = abortReason ?? (\n typeof workflowSignal?.reason === \"string\"\n ? workflowSignal.reason\n : workflowSignal?.reason instanceof Error\n ? workflowSignal.reason.message\n : undefined\n );\n const cancelledError: WorkflowCancelledError = {\n type: \"WORKFLOW_CANCELLED\",\n reason,\n lastStepKey,\n };\n // Throw to abort the workflow - will be caught by run() error handling\n throw cancelledError;\n }\n };\n\n // Helper to call onAfterStep hook with event emission\n const callOnAfterStepHook = async (\n stepKey: string,\n result: Result<unknown, unknown, unknown>,\n _meta?: StepFailureMeta\n ): Promise<void> => {\n if (!onAfterStepHook) return;\n const hookStartTime = performance.now();\n try {\n await onAfterStepHook(stepKey, result, workflowId, context);\n const hookDuration = performance.now() - hookStartTime;\n emitEvent({\n type: \"hook_after_step\",\n workflowId,\n stepKey,\n ts: Date.now(),\n durationMs: hookDuration,\n });\n } catch (thrown) {\n const hookDuration = performance.now() - hookStartTime;\n emitEvent({\n type: \"hook_after_step_error\",\n workflowId,\n stepKey,\n ts: Date.now(),\n durationMs: hookDuration,\n error: thrown as E,\n });\n // Re-throw to maintain original behavior\n throw thrown;\n }\n };\n\n // Create a cached step wrapper\n const createCachedStep = (realStep: RunStep<E>): RunStep<E> => {\n // NOTE: We always create the wrapper because streaming methods (streamForEach, getWritable,\n // getReadable) are defined on cachedStepFn, not realStep. Even without cache/hooks/signal/\n // streamStore, the workflow may use step.streamForEach with async iterables.\n\n // Wrap the main step function with backward-compatible signature\n // Supports: step('id', fn, opts), step(fn, opts?), step(result, opts?)\n const cachedStepFn = async <StepT, StepE extends E, StepC = unknown>(\n idOrOperationOrResult: string | (() => Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>) | Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>,\n operationOrOptions?: (() => Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>) | StepOptions | string,\n stepOptions?: StepOptions\n ): Promise<StepT> => {\n // Validate required string ID as first argument\n if (typeof idOrOperationOrResult !== 'string') {\n throw new Error(\n '[awaitly] step() requires a string ID as the first argument. ' +\n 'Example: step(\"fetchUser\", () => fetchUser(id))'\n );\n }\n\n // Parse arguments: step('id', fn, opts)\n const id = idOrOperationOrResult;\n const opts = stepOptions ?? {};\n\n // Name is always derived from ID\n const name = id;\n // Use cache by id when key is omitted; when key is explicitly set (including undefined) use that (undefined = don't cache)\n const key = Object.prototype.hasOwnProperty.call(opts, \"key\")\n ? opts.key\n : id;\n const { ttl, out } = opts;\n\n // Check for cancellation before starting step\n // Use lastStepKey (last completed step) for reporting, not the step about to run\n checkCancellation();\n\n // Update lastStepKey AFTER the step completes (moved to success/error handlers below)\n // This ensures lastStepKey always means \"last successfully completed keyed step\"\n\n // Extract metadata for cache events (same extraction as core step function)\n const stepMetadata = extractStepMetadata(opts);\n\n // Only use cache if key is provided and cache exists\n if (key && cache && cache.has(key)) {\n emitEvent({\n type: \"step_cache_hit\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n\n const cached = cache.get(key)!;\n if (cached.ok) {\n // Update lastStepKey for cache hits too (step effectively completed)\n lastStepKey = key;\n // Store result in workflow data if 'out' is specified (even for cache hits)\n if (out) {\n workflowData[out] = cached.value;\n }\n return cached.value as StepT;\n }\n // Cached error - throw early exit with preserved metadata (origin + cause)\n // This bypasses realStep to avoid replaying step_start/step_error events\n const meta = decodeCachedMeta(cached.cause);\n throw createEarlyExit(cached.error as StepE, meta);\n }\n\n // Cache miss - emit event only if caching is enabled\n if (key && cache) {\n emitEvent({\n type: \"step_cache_miss\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n ...(stepMetadata && { metadata: stepMetadata }),\n });\n }\n\n try {\n // Pass arguments to realStep: step('id', fn, opts)\n const value = await (realStep as CallableFunction)(\n id,\n operationOrOptions,\n opts\n );\n // Store result in workflow data if 'out' is specified\n if (out) {\n workflowData[out] = value;\n }\n // Cache successful result if key provided\n if (key) {\n // Update lastStepKey on successful completion (for cancellation reporting)\n lastStepKey = key;\n if (cache) {\n cache.set(key, ok(value), ttl ? { ttl } : undefined);\n }\n // Call onAfterStep hook for checkpointing (even without cache)\n await callOnAfterStepHook(key, ok(value));\n }\n return value;\n } catch (thrown) {\n // Cache error results with full metadata if key provided and this is an early exit\n if (key && isEarlyExit(thrown)) {\n const exit = thrown as EarlyExit<StepE>;\n // Extract original cause from metadata for preservation\n const originalCause =\n exit.meta.origin === \"result\"\n ? exit.meta.resultCause\n : exit.meta.origin === \"throw\"\n ? exit.meta.thrown\n : undefined;\n const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);\n if (cache) {\n cache.set(key, errorResult, ttl ? { ttl } : undefined);\n }\n // Call onAfterStep hook for checkpointing (even on error, even without cache)\n await callOnAfterStepHook(key, errorResult, exit.meta);\n }\n throw thrown;\n }\n };\n\n // Wrap step.try\n cachedStepFn.try = async <StepT, Err extends E>(\n id: string,\n operation: () => StepT | Promise<StepT>,\n opts:\n | { error: Err; key?: string; ttl?: number }\n | { onError: (cause: unknown) => Err; key?: string; ttl?: number }\n ): Promise<StepT> => {\n const { ttl } = opts;\n const key = opts.key ?? id; // step.try caches by id when key omitted (for resume)\n const name = id;\n\n if (cache && cache.has(key)) {\n emitEvent({\n type: \"step_cache_hit\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n });\n\n const cached = cache.get(key)!;\n if (cached.ok) {\n return cached.value as StepT;\n }\n const meta = decodeCachedMeta(cached.cause);\n throw createEarlyExit(cached.error as Err, meta);\n }\n\n if (cache) {\n emitEvent({\n type: \"step_cache_miss\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n });\n }\n\n try {\n const value = await realStep.try(id, operation, { ...opts, key });\n if (cache) {\n cache.set(key, ok(value), ttl ? { ttl } : undefined);\n }\n await callOnAfterStepHook(key, ok(value));\n return value;\n } catch (thrown) {\n if (isEarlyExit(thrown)) {\n const exit = thrown as EarlyExit<Err>;\n const originalCause =\n exit.meta.origin === \"result\"\n ? exit.meta.resultCause\n : exit.meta.origin === \"throw\"\n ? exit.meta.thrown\n : undefined;\n const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);\n if (cache) {\n cache.set(key, errorResult, ttl ? { ttl } : undefined);\n }\n await callOnAfterStepHook(key, errorResult, exit.meta);\n }\n throw thrown;\n }\n };\n\n // Wrap step.fromResult - delegate to real step (caching handled by key in opts)\n cachedStepFn.fromResult = async <StepT, ResultE, Err extends E>(\n id: string,\n operation: () => Result<StepT, ResultE, unknown> | AsyncResult<StepT, ResultE, unknown>,\n opts:\n | { error: Err; key?: string; ttl?: number }\n | { onError: (resultError: ResultE) => Err; key?: string; ttl?: number }\n ): Promise<StepT> => {\n const { ttl } = opts;\n const key = opts.key ?? id; // step.fromResult caches by id when key omitted (for resume)\n const name = id;\n\n if (cache && cache.has(key)) {\n emitEvent({\n type: \"step_cache_hit\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n });\n\n const cached = cache.get(key)!;\n if (cached.ok) {\n return cached.value as StepT;\n }\n const meta = decodeCachedMeta(cached.cause);\n throw createEarlyExit(cached.error as Err, meta);\n }\n\n if (cache) {\n emitEvent({\n type: \"step_cache_miss\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n });\n }\n\n try {\n const value = await realStep.fromResult(id, operation, { ...opts, key });\n if (cache) {\n cache.set(key, ok(value), ttl ? { ttl } : undefined);\n }\n await callOnAfterStepHook(key, ok(value));\n return value;\n } catch (thrown) {\n if (isEarlyExit(thrown)) {\n const exit = thrown as EarlyExit<Err>;\n const originalCause =\n exit.meta.origin === \"result\"\n ? exit.meta.resultCause\n : exit.meta.origin === \"throw\"\n ? exit.meta.thrown\n : undefined;\n const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);\n if (cache) {\n cache.set(key, errorResult, ttl ? { ttl } : undefined);\n }\n await callOnAfterStepHook(key, errorResult, exit.meta);\n }\n throw thrown;\n }\n };\n\n // Wrap step.parallel - delegate to real step (no caching for scope wrappers)\n cachedStepFn.parallel = realStep.parallel;\n\n // Wrap step.race - delegate to real step (no caching for scope wrappers)\n cachedStepFn.race = realStep.race;\n\n // Wrap step.allSettled - delegate to real step (no caching for scope wrappers)\n cachedStepFn.allSettled = realStep.allSettled;\n\n // Wrap step.withFallback - preserve fallback semantics while adding workflow cache hooks.\n // Accept any operation/fallback error types (E1, E2) so users never need to cast; cast internally for core.\n cachedStepFn.withFallback = async <StepT, E1, E2>(\n id: string,\n operation: () => AsyncResult<StepT, E1>,\n options: { on?: E1 & string; fallback: () => AsyncResult<StepT, E2>; key?: string }\n ): Promise<StepT> => {\n const key = options.key ?? id; // matches core withFallback cache key behavior\n const name = id;\n\n if (cache && cache.has(key)) {\n emitEvent({\n type: \"step_cache_hit\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n });\n\n const cached = cache.get(key)!;\n if (cached.ok) {\n return cached.value as StepT;\n }\n const meta = decodeCachedMeta(cached.cause);\n throw createEarlyExit(cached.error as E, meta);\n }\n\n if (cache) {\n emitEvent({\n type: \"step_cache_miss\",\n workflowId,\n stepKey: key,\n name,\n ts: Date.now(),\n });\n }\n\n try {\n const value = await realStep.withFallback(\n id,\n operation as () => AsyncResult<StepT, E>,\n options as { on?: E & string; fallback: () => AsyncResult<StepT, E>; key?: string }\n );\n if (cache) {\n cache.set(key, ok(value));\n }\n await callOnAfterStepHook(key, ok(value));\n return value;\n } catch (thrown) {\n if (isEarlyExit(thrown)) {\n const exit = thrown as EarlyExit<E>;\n const originalCause =\n exit.meta.origin === \"result\"\n ? exit.meta.resultCause\n : exit.meta.origin === \"throw\"\n ? exit.meta.thrown\n : undefined;\n const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);\n if (cache) {\n cache.set(key, errorResult);\n }\n await callOnAfterStepHook(key, errorResult, exit.meta);\n }\n throw thrown;\n }\n };\n\n // Wrap step.withResource - run via core then call onAfterStep (keyed by id, consistent with other keyed steps)\n cachedStepFn.withResource = async <T, R, AcquireE extends E, UseE extends E>(\n id: string,\n options: {\n acquire: () => AsyncResult<R, AcquireE>;\n use: (resource: R) => AsyncResult<T, UseE>;\n release: (resource: R) => void | Promise<void>;\n }\n ): Promise<T> => {\n const key = id;\n try {\n const value = await realStep.withResource(id, options);\n await callOnAfterStepHook(key, ok(value));\n return value;\n } catch (thrown) {\n if (isEarlyExit(thrown)) {\n const exit = thrown as EarlyExit<E>;\n const originalCause =\n exit.meta.origin === \"result\"\n ? exit.meta.resultCause\n : exit.meta.origin === \"throw\"\n ? exit.meta.thrown\n : undefined;\n const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);\n await callOnAfterStepHook(key, errorResult, exit.meta);\n }\n throw thrown;\n }\n };\n\n // Wrap step.retry - pass key explicitly so \"no key\" means don't cache (cachedStepFn treats key: undefined as no cache)\n cachedStepFn.retry = <StepT, StepE extends E, StepC = unknown>(\n id: string,\n operation: () => Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>,\n options: RetryOptions & { key?: string; timeout?: TimeoutOptions; ttl?: number }\n ): Promise<StepT> => {\n const stepOptions = {\n key: options.key, // explicitly pass so undefined = don't cache\n retry: {\n attempts: options.attempts,\n backoff: options.backoff,\n initialDelay: options.initialDelay,\n maxDelay: options.maxDelay,\n jitter: options.jitter,\n retryOn: options.retryOn,\n onRetry: options.onRetry,\n },\n timeout: options.timeout,\n ttl: options.ttl,\n };\n\n return cachedStepFn(id, operation, stepOptions);\n };\n\n // Wrap step.withTimeout - pass key explicitly so \"no key\" means don't cache\n cachedStepFn.withTimeout = <StepT, StepE extends E, StepC = unknown>(\n id: string,\n operation:\n | (() => Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>)\n | ((signal: AbortSignal) => Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>),\n options: TimeoutOptions & { key?: string; ttl?: number }\n ): Promise<StepT> => {\n const stepOptions = {\n key: options.key,\n timeout: options,\n ttl: options.ttl,\n };\n\n return cachedStepFn(\n id,\n operation as () => Result<StepT, StepE, StepC> | AsyncResult<StepT, StepE, StepC>,\n stepOptions\n );\n };\n\n // Wrap step.sleep - only use cache when explicit key is provided\n cachedStepFn.sleep = (\n id: string,\n duration: string | DurationType,\n options?: { key?: string; ttl?: number; description?: string; signal?: AbortSignal }\n ): Promise<void> => {\n if (typeof id !== \"string\" || id.length === 0) {\n throw new Error(\n \"[awaitly] step.sleep() requires an explicit string ID as the first argument. \" +\n 'Example: step.sleep(\"delay\", \"5s\")'\n );\n }\n const d = typeof duration === \"string\" ? parseDuration(duration) : duration;\n if (!d) {\n throw new Error(`step.sleep: invalid duration '${duration}'`);\n }\n const ms = toMillis(d);\n\n const userSignal = options?.signal;\n\n const sleepOperation = async (): AsyncResult<void, never> => {\n // Check if already aborted (workflow or user signal)\n if (workflowSignal?.aborted || userSignal?.aborted) {\n const e = new Error(\"Sleep aborted\");\n e.name = \"AbortError\";\n throw e;\n }\n\n return new Promise<Result<void, never>>((resolve, reject) => {\n const state = {\n timeoutId: undefined as ReturnType<typeof setTimeout> | undefined,\n };\n\n const onAbort = () => {\n if (state.timeoutId) clearTimeout(state.timeoutId);\n const e = new Error(\"Sleep aborted\");\n e.name = \"AbortError\";\n reject(e);\n };\n\n workflowSignal?.addEventListener(\"abort\", onAbort, { once: true });\n userSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n state.timeoutId = setTimeout(() => {\n workflowSignal?.removeEventListener(\"abort\", onAbort);\n userSignal?.removeEventListener(\"abort\", onAbort);\n resolve(ok(undefined));\n }, ms);\n });\n };\n\n return cachedStepFn(id, sleepOperation, {\n key: options?.key,\n ttl: options?.ttl,\n description: options?.description,\n });\n };\n\n // ===========================================================================\n // Streaming Methods\n // ===========================================================================\n\n // Store active writers and their backpressure controllers\n const activeWriters = new Map<string, {\n writer: StreamWriter<unknown>;\n backpressure: BackpressureController;\n aborted: boolean;\n closed: boolean;\n }>();\n\n // Store active readers\n const activeReaders = new Map<string, {\n reader: StreamReader<unknown>;\n position: number;\n closed: boolean;\n }>();\n\n cachedStepFn.getWritable = <T>(\n options?: StreamWritableOptions\n ): StreamWriterInterface<T> => {\n const namespace = options?.namespace ?? \"default\";\n const highWaterMark = options?.highWaterMark ?? 16;\n\n if (!streamStore) {\n throw new Error(\n \"streamStore is required to use getWritable(). \" +\n \"Pass a streamStore to createWorkflow options.\"\n );\n }\n\n // Check if writer already exists for this namespace\n const existingKey = `${workflowId}:${namespace}`;\n const existing = activeWriters.get(existingKey);\n if (existing && !existing.closed && !existing.aborted) {\n return existing.writer as StreamWriter<T>;\n }\n\n // Create backpressure controller\n const backpressure = createBackpressureController({\n highWaterMark,\n onStateChange: (state) => {\n emitEvent({\n type: \"stream_backpressure\",\n workflowId,\n namespace,\n bufferedCount: backpressure.bufferedCount,\n state,\n ts: Date.now(),\n });\n },\n });\n\n let position = 0;\n let writable = true;\n let aborted = false;\n let closed = false;\n\n // Emit stream_created event\n emitEvent({\n type: \"stream_created\",\n workflowId,\n namespace,\n ts: Date.now(),\n });\n\n const writer: StreamWriter<T> = {\n async write(value: T): AsyncResult<void, StreamWriteError> {\n if (closed) {\n return err(streamWriteError(\"closed\", \"Stream is closed\"));\n }\n if (aborted) {\n return err(streamWriteError(\"aborted\", \"Stream was aborted\"));\n }\n\n // Check backpressure\n if (backpressure.state === \"paused\") {\n await backpressure.waitForDrain();\n }\n\n // Write to store\n const item: StreamItem<T> = {\n value,\n position,\n ts: Date.now(),\n };\n\n const result = await streamStore.append<T>(workflowId, namespace, item);\n if (!result.ok) {\n emitEvent({\n type: \"stream_error\",\n workflowId,\n namespace,\n error: result.error,\n position,\n ts: Date.now(),\n });\n return err(streamWriteError(\"store_error\", result.error.message, result.error));\n }\n\n // Emit write event\n emitEvent({\n type: \"stream_write\",\n workflowId,\n namespace,\n position,\n ts: Date.now(),\n });\n\n position++;\n backpressure.increment();\n\n return ok(undefined);\n },\n\n async close(): AsyncResult<void, StreamCloseError> {\n if (closed) {\n return err(streamCloseError(\"already_closed\", \"Stream is already closed\"));\n }\n\n const result = await streamStore.closeStream(workflowId, namespace);\n if (!result.ok) {\n return err(streamCloseError(\"store_error\", result.error.message, result.error));\n }\n\n closed = true;\n writable = false;\n\n // Emit close event\n emitEvent({\n type: \"stream_close\",\n workflowId,\n namespace,\n finalPosition: position,\n ts: Date.now(),\n });\n\n // Clean up\n activeWriters.delete(existingKey);\n\n return ok(undefined);\n },\n\n abort(reason: unknown): void {\n aborted = true;\n writable = false;\n closed = true;\n\n emitEvent({\n type: \"stream_error\",\n workflowId,\n namespace,\n error: reason,\n position,\n ts: Date.now(),\n });\n\n // Clean up\n activeWriters.delete(existingKey);\n },\n\n get writable() {\n return writable;\n },\n\n get position() {\n return position;\n },\n\n get namespace() {\n return namespace;\n },\n };\n\n activeWriters.set(existingKey, {\n writer: writer as StreamWriter<unknown>,\n backpressure,\n aborted,\n closed,\n });\n\n return writer;\n };\n\n cachedStepFn.getReadable = <T>(\n options?: StreamReadableOptions\n ): StreamReaderInterface<T> => {\n const namespace = options?.namespace ?? \"default\";\n const startIndex = options?.startIndex ?? 0;\n const pollInterval = options?.pollInterval ?? 10;\n const pollTimeout = options?.pollTimeout ?? 30000;\n\n if (!streamStore) {\n throw new Error(\n \"streamStore is required to use getReadable(). \" +\n \"Pass a streamStore to createWorkflow options.\"\n );\n }\n\n const existingKey = `${workflowId}:${namespace}:${startIndex}`;\n const existing = activeReaders.get(existingKey);\n if (existing && !existing.closed) {\n return existing.reader as StreamReader<T>;\n }\n\n // Helper to decrement backpressure when items are consumed\n const decrementBackpressure = () => {\n const writerKey = `${workflowId}:${namespace}`;\n const activeWriter = activeWriters.get(writerKey);\n if (activeWriter) {\n activeWriter.backpressure.decrement();\n }\n };\n\n let position = startIndex;\n let readable = true;\n let closed = false;\n let bufferedItems: StreamItem<T>[] = [];\n let bufferIndex = 0;\n\n const reader: StreamReader<T> = {\n async read(): AsyncResult<T, StreamReadError | StreamEndedMarker> {\n if (closed) {\n return err(streamReadError(\"closed\", \"Reader is closed\"));\n }\n\n // Check if we have buffered items\n if (bufferIndex < bufferedItems.length) {\n const item = bufferedItems[bufferIndex++];\n position = item.position + 1;\n\n // Release backpressure for consumed item\n decrementBackpressure();\n\n emitEvent({\n type: \"stream_read\",\n workflowId,\n namespace,\n position: item.position,\n ts: Date.now(),\n });\n\n return ok(item.value);\n }\n\n // Poll for items from store with timeout\n // We poll even if there's no active writer yet, as one may appear\n const writerKey = `${workflowId}:${namespace}`;\n const pollStart = Date.now();\n let hasSeenWriter = activeWriters.has(writerKey);\n\n // Check initial state\n const initialMetaResult = await streamStore.getMetadata(workflowId, namespace);\n let hasSeenMetadata = initialMetaResult.ok && initialMetaResult.value !== undefined;\n\n while (Date.now() - pollStart < pollTimeout) {\n const result = await streamStore.read<T>(workflowId, namespace, position, 100);\n if (!result.ok) {\n return err(streamReadError(\"store_error\", result.error.message, result.error));\n }\n\n const items = result.value;\n if (items.length > 0) {\n // Buffer items and return first\n bufferedItems = items;\n bufferIndex = 1;\n const item = items[0];\n position = item.position + 1;\n\n // Release backpressure for consumed item\n decrementBackpressure();\n\n emitEvent({\n type: \"stream_read\",\n workflowId,\n namespace,\n position: item.position,\n ts: Date.now(),\n });\n\n return ok(item.value);\n }\n\n // Check current state\n const writerActive = activeWriters.has(writerKey);\n const metaResult = await streamStore.getMetadata(workflowId, namespace);\n const metadataExists = metaResult.ok && metaResult.value !== undefined;\n\n // Track if we've ever seen a writer or metadata\n if (writerActive) hasSeenWriter = true;\n if (metadataExists) hasSeenMetadata = true;\n\n // Stream is closed - no more items coming\n if (metaResult.ok && metaResult.value?.closed) {\n readable = false;\n return err(streamEnded(position));\n }\n\n // If we've seen a writer or metadata but now it's gone and empty,\n // the stream has ended without more items\n if (hasSeenWriter && !writerActive && !metadataExists) {\n // Writer was created and removed without writing anything\n readable = false;\n return err(streamEnded(position));\n }\n\n if (hasSeenMetadata && !writerActive && metaResult.ok && !metaResult.value?.closed) {\n // Stream exists, writer is gone, but stream not closed\n // This means writer finished - wait a bit more for any pending writes\n // then give up\n }\n\n // Stream is still open or writer may still appear - wait and poll again\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n // Poll timeout - treat as stream ended\n readable = false;\n return err(streamEnded(position));\n },\n\n close(): void {\n closed = true;\n readable = false;\n bufferedItems = [];\n activeReaders.delete(existingKey);\n },\n\n get readable() {\n return readable;\n },\n\n get position() {\n return position;\n },\n\n get namespace() {\n return namespace;\n },\n };\n\n activeReaders.set(existingKey, {\n reader: reader as StreamReader<unknown>,\n position,\n closed,\n });\n\n return reader;\n };\n\n cachedStepFn.streamForEach = async <T, R, StepE extends E>(\n source: StreamReaderInterface<T> | AsyncIterable<T>,\n processor: (item: T, index: number) => AsyncResult<R, StepE>,\n options?: StreamForEachStepOptions\n ): Promise<StreamForEachResultType<R>> => {\n const checkpointInterval = options?.checkpointInterval ?? 1;\n const concurrency = options?.concurrency ?? 1;\n const results: R[] = [];\n let processedCount = 0;\n let lastPosition = -1;\n\n // Helper to check if source is a StreamReader\n const isStreamReader = (s: unknown): s is StreamReaderInterface<T> => {\n return (\n typeof s === \"object\" &&\n s !== null &&\n \"read\" in s &&\n typeof (s as StreamReaderInterface<T>).read === \"function\"\n );\n };\n\n // Helper to process a single item with step()\n const processItem = async (\n item: T,\n itemIndex: number,\n itemPosition: number,\n namespace: string\n ): Promise<{ index: number; position: number; result: R }> => {\n const shouldCheckpoint = checkpointInterval > 0 && itemIndex % checkpointInterval === 0;\n const stepKey = shouldCheckpoint\n ? `stream-foreach:${namespace}:pos-${itemPosition}`\n : undefined;\n\n const stepId = stepKey ?? `stream-item-${itemPosition}`;\n const stepResult = await cachedStepFn(\n stepId,\n () => processor(item, itemIndex),\n { key: stepKey }\n );\n\n return { index: itemIndex, position: itemPosition, result: stepResult };\n };\n\n if (isStreamReader(source)) {\n if (concurrency <= 1) {\n // Sequential processing (original behavior)\n let itemPosition = source.position;\n let readResult = await source.read();\n while (readResult.ok) {\n const item = readResult.value;\n const { result } = await processItem(item, processedCount, itemPosition, source.namespace);\n results.push(result);\n lastPosition = itemPosition;\n processedCount++;\n itemPosition = source.position;\n readResult = await source.read();\n }\n } else {\n // Concurrent processing - interleave reading and processing\n const resultsMap = new Map<number, { position: number; result: R }>();\n let itemIndex = 0;\n let totalItems = 0;\n\n // Track slots with wrapped promises that include slot index\n type SlotResult = { slotIndex: number; index: number; position: number; result: R };\n const slots: (Promise<SlotResult> | null)[] = new Array(concurrency).fill(null);\n\n // Helper to find an empty slot, waiting if necessary\n const getSlot = async (): Promise<number> => {\n // First, check for empty slots\n for (let i = 0; i < slots.length; i++) {\n if (slots[i] === null) return i;\n }\n // No empty slots - wait for one to complete\n const activePromises = slots.filter((s): s is Promise<SlotResult> => s !== null);\n const completed = await Promise.race(activePromises);\n resultsMap.set(completed.index, { position: completed.position, result: completed.result });\n // Clear the slot that completed (we know which one from slotIndex)\n slots[completed.slotIndex] = null;\n return completed.slotIndex;\n };\n\n // Read and process items concurrently\n let itemPosition = source.position;\n let readResult = await source.read();\n\n while (readResult.ok) {\n const slotIndex = await getSlot();\n\n // Capture current values for closure\n const currentIndex = itemIndex;\n const currentPosition = itemPosition;\n const currentItem = readResult.value;\n const currentSlot = slotIndex;\n\n // Start processing in this slot, wrapping to include slot index\n slots[slotIndex] = processItem(currentItem, currentIndex, currentPosition, source.namespace)\n .then(r => ({ slotIndex: currentSlot, ...r }));\n totalItems++;\n itemIndex++;\n\n // Read next item\n itemPosition = source.position;\n readResult = await source.read();\n }\n\n // Wait for all remaining slots to complete\n for (let i = 0; i < slots.length; i++) {\n if (slots[i] !== null) {\n const result = await slots[i]!;\n resultsMap.set(result.index, { position: result.position, result: result.result });\n }\n }\n\n // Collect results in order\n for (let i = 0; i < totalItems; i++) {\n const entry = resultsMap.get(i);\n if (entry) {\n results.push(entry.result);\n lastPosition = entry.position;\n processedCount++;\n }\n }\n }\n } else {\n // Process from AsyncIterable\n if (concurrency <= 1) {\n // Sequential processing\n let index = 0;\n for await (const item of source) {\n const { result } = await processItem(item, index, index, \"async-iterable\");\n results.push(result);\n lastPosition = index;\n processedCount++;\n index++;\n }\n } else {\n // Concurrent processing - interleave iteration and processing\n const resultsMap = new Map<number, R>();\n let itemIndex = 0;\n let totalItems = 0;\n\n // Track slots with wrapped promises that include slot index\n type SlotResult = { slotIndex: number; index: number; position: number; result: R };\n const slots: (Promise<SlotResult> | null)[] = new Array(concurrency).fill(null);\n\n // Helper to find an empty slot, waiting if necessary\n const getSlot = async (): Promise<number> => {\n // First, check for empty slots\n for (let i = 0; i < slots.length; i++) {\n if (slots[i] === null) return i;\n }\n // No empty slots - wait for one to complete\n const activePromises = slots.filter((s): s is Promise<SlotResult> => s !== null);\n const completed = await Promise.race(activePromises);\n resultsMap.set(completed.index, completed.result);\n // Clear the slot that completed (we know which one from slotIndex)\n slots[completed.slotIndex] = null;\n return completed.slotIndex;\n };\n\n // Iterate and process items concurrently\n for await (const item of source) {\n const slotIndex = await getSlot();\n\n // Capture current values for closure\n const currentIndex = itemIndex;\n const currentSlot = slotIndex;\n\n // Start processing in this slot, wrapping to include slot index\n slots[slotIndex] = processItem(item, currentIndex, currentIndex, \"async-iterable\")\n .then(r => ({ slotIndex: currentSlot, ...r }));\n totalItems++;\n itemIndex++;\n }\n\n // Wait for all remaining slots to complete\n for (let i = 0; i < slots.length; i++) {\n if (slots[i] !== null) {\n const result = await slots[i]!;\n resultsMap.set(result.index, result.result);\n }\n }\n\n // Collect results in order\n for (let i = 0; i < totalItems; i++) {\n // Use has() instead of checking result !== undefined because\n // the processor may legitimately return ok(undefined)\n if (resultsMap.has(i)) {\n results.push(resultsMap.get(i) as R);\n lastPosition = i;\n processedCount++;\n }\n }\n }\n }\n\n return {\n results,\n processedCount,\n lastPosition,\n };\n };\n\n // step.if: Delegate to real step (no caching needed - just returns condition result)\n cachedStepFn.if = realStep.if;\n\n // step.label: Alias for step.if - delegate to real step\n cachedStepFn.label = realStep.label;\n\n // step.branch: Delegate to real step (evaluates condition and executes arm)\n cachedStepFn.branch = realStep.branch;\n\n // step.arm: Delegate to real step (returns arm definition)\n cachedStepFn.arm = realStep.arm;\n\n // step.forEach: Delegate to real step (executes loop)\n cachedStepFn.forEach = realStep.forEach;\n\n // step.item: Delegate to real step (returns item handler)\n cachedStepFn.item = realStep.item;\n\n // step.dep: Delegate to real step (no caching needed - just returns function unchanged)\n cachedStepFn.dep = realStep.dep;\n\n // Effect-style ergonomics: Route through cached step so cache/onAfterStep apply.\n // Accept either AsyncResult or () => AsyncResult (getter) so cache hits never run the getter.\n cachedStepFn.run = (\n id: string,\n resultOrGetter: AsyncResult<unknown, E, unknown> | (() => AsyncResult<unknown, E, unknown>),\n options?: StepOptions\n ) => {\n const op =\n typeof resultOrGetter === \"function\"\n ? (resultOrGetter as () => AsyncResult<unknown, E, unknown>)\n : () => resultOrGetter as AsyncResult<unknown, E, unknown>;\n return cachedStepFn(id, op, options) as Promise<unknown>;\n };\n // step.workflow: run sub-workflow (or any AsyncResult getter) as a step; cache + onAfterStep apply\n cachedStepFn.workflow = (\n id: string,\n getter: () => AsyncResult<unknown, E, unknown>,\n options?: StepOptions\n ) => cachedStepFn(id, getter, options) as Promise<unknown>;\n cachedStepFn.andThen = (\n id: string,\n value: unknown,\n fn: (value: unknown) => AsyncResult<unknown, E, unknown>,\n options?: StepOptions\n ) => cachedStepFn(id, () => fn(value) as AsyncResult<unknown, E, unknown>, options) as Promise<unknown>;\n cachedStepFn.match = (\n id: string,\n result: Result<unknown, E, unknown> | AsyncResult<unknown, E, unknown>,\n handlers: {\n ok: (value: unknown) => unknown | Promise<unknown>;\n err: (error: E, cause?: unknown) => unknown | Promise<unknown>;\n },\n options?: StepOptions\n ) =>\n cachedStepFn(\n id,\n async () => {\n const resolved = await result;\n if (resolved.ok) {\n return ok(await handlers.ok(resolved.value));\n }\n return ok(await handlers.err(resolved.error, resolved.cause));\n },\n options\n ) as Promise<unknown>;\n // Match core: all() with no key = no cache (core parallel doesn't pass key, so no cache by id)\n cachedStepFn.all = (id: string, shape: Parameters<RunStep<E>[\"all\"]>[1], options?: StepOptions) => {\n const opts =\n options !== undefined && Object.prototype.hasOwnProperty.call(options, \"key\")\n ? options\n : { ...options, key: undefined as string | undefined };\n return cachedStepFn(id, async () => ok(await realStep.all(id, shape)), opts) as Promise<unknown>;\n };\n // Match core: step.map() passes { key: options?.key }, so omitted key = no cache (core never caches by id for map)\n cachedStepFn.map = (\n id: string,\n items: unknown[],\n mapper: (item: unknown, index: number) => AsyncResult<unknown, E, unknown>,\n options?: { concurrency?: number; key?: string }\n ) => {\n const opts =\n options !== undefined && Object.prototype.hasOwnProperty.call(options, \"key\")\n ? options\n : { ...options, key: undefined as string | undefined };\n return cachedStepFn(id, async () => ok(await realStep.map(id, items, mapper, options)), opts) as Promise<unknown>;\n };\n\n return cachedStepFn as RunStep<E>;\n };\n\n // Wrap the user's callback to pass cached step, deps, and workflow context.\n // Cast step to RunStep<E | ExtraE> so callbacks using step.workflow/withFallback get correct error inference.\n const wrappedFn = ({ step }: { step: RunStep<E> }) =>\n userFn({\n step: createCachedStep(step) as RunStep<E | ExtraE>,\n deps: effectiveDeps,\n ctx: workflowContext,\n });\n\n // Always use run() with catchUnexpected (default or user-provided). Closed error union E | ExtraE | U.\n let result: Result<T, E | ExtraE | U | UnexpectedError | WorkflowCancelledError, unknown>;\n\n try {\n result = await run<T, E | ExtraE | U, C>(wrappedFn as (context: { step: RunStep<E | ExtraE | U> }) => Promise<T> | T, {\n onError: onErrorHandler as ((error: E | ExtraE | U, stepName?: string, ctx?: C) => void) | undefined,\n onEvent: onEventHandler as ((event: WorkflowEvent<E | ExtraE | U | UnexpectedError, C>, ctx: C) => void) | undefined,\n catchUnexpected: catchUnexpected as (cause: unknown) => U,\n workflowId,\n workflowName,\n context,\n _workflowSignal: workflowSignal,\n });\n } finally {\n // Clean up abort listener\n if (workflowSignal) {\n workflowSignal.removeEventListener(\"abort\", abortHandler);\n }\n }\n\n const durationMs = performance.now() - startTime;\n\n // Check if the error is a wrapped WorkflowCancelledError\n // There are two paths:\n // 1. result.cause is WorkflowCancelledError (both default and custom catchUnexpected)\n // 2. AbortError thrown during abort - synthesize WorkflowCancelledError\n if (!result.ok) {\n let cancelledError: WorkflowCancelledError | undefined;\n\n // Path 1: result.cause is WorkflowCancelledError (both default and custom catchUnexpected)\n if (isWorkflowCancelled(result.cause)) {\n cancelledError = result.cause as WorkflowCancelledError;\n }\n\n // Path 2: AbortError thrown during abort (e.g. step.sleep) - treat as cancellation\n // The thrown AbortError is in result.cause\n if (\n !cancelledError &&\n abortedDuringExecution &&\n isUnexpectedError(result.error)\n ) {\n const thrown = result.cause;\n const isAbortError =\n thrown != null &&\n typeof thrown === \"object\" &&\n \"name\" in thrown &&\n (thrown as { name: string }).name === \"AbortError\";\n if (isAbortError) {\n const reason =\n abortReason ??\n (typeof workflowSignal?.reason === \"string\"\n ? workflowSignal.reason\n : workflowSignal?.reason instanceof Error\n ? workflowSignal.reason.message\n : undefined);\n cancelledError = {\n type: \"WORKFLOW_CANCELLED\",\n reason,\n lastStepKey,\n };\n }\n }\n\n if (cancelledError) {\n emitEvent({\n type: \"workflow_cancelled\",\n workflowId,\n ts: Date.now(),\n durationMs,\n reason: cancelledError.reason,\n lastStepKey: cancelledError.lastStepKey,\n });\n // Path 2: We synthesized cancelledError from AbortError - ensure result.cause is WorkflowCancelledError\n if (cancelledError && !isWorkflowCancelled(result.cause)) {\n return err(result.error, { cause: cancelledError }) as Result<T, E | ExtraE | U, unknown>;\n }\n return result as Result<T, E | ExtraE | U, unknown>;\n }\n }\n\n // Check for late cancellation: workflow completed successfully but signal was aborted\n // This handles the case where abort happens during the last step but the operation doesn't throw\n // Only check abortedDuringExecution, not workflowSignal?.aborted, to avoid race condition\n // where a pre-aborted signal (aborted before workflow started) incorrectly cancels a successful workflow\n if (result.ok && abortedDuringExecution) {\n const reason = abortReason ?? (\n typeof workflowSignal?.reason === \"string\"\n ? workflowSignal.reason\n : workflowSignal?.reason instanceof Error\n ? workflowSignal.reason.message\n : undefined\n );\n emitEvent({\n type: \"workflow_cancelled\",\n workflowId,\n ts: Date.now(),\n durationMs,\n reason,\n lastStepKey,\n });\n const cancelledError: WorkflowCancelledError = {\n type: \"WORKFLOW_CANCELLED\",\n reason,\n lastStepKey,\n };\n return err(catchUnexpected(cancelledError), { cause: cancelledError }) as Result<T, E | ExtraE | U, unknown>;\n }\n\n // Emit workflow_success or workflow_error\n if (result.ok) {\n emitEvent({\n type: \"workflow_success\",\n workflowId,\n ts: Date.now(),\n durationMs,\n });\n } else {\n // At this point, WorkflowCancelledError has already been handled and returned above,\n // so result.error is not WorkflowCancelledError\n emitEvent({\n type: \"workflow_error\",\n workflowId,\n ts: Date.now(),\n durationMs,\n error: result.error as E | ExtraE | U,\n });\n }\n\n // NOTE: We intentionally do NOT check for unknown steps after workflow completes.\n // This is because workflows can have conditional branches - a step from a skipped branch\n // would appear \"unused\" but is still a valid step. We can't distinguish between:\n // 1. Steps that are truly unknown (from a different workflow)\n // 2. Steps that are defined but not executed in this particular run\n // Use workflowId matching in snapshot metadata to detect wrong snapshots instead.\n\n return result as Result<T, E | ExtraE | U, unknown>;\n }\n\n // ==========================================================================\n // workflow.run() - public method\n // ==========================================================================\n function runMethod<T, ExtraE = never>(\n fnOrName: string | WorkflowFn<T, E | ExtraE, Deps, C>,\n maybeFnOrConfig?: WorkflowFn<T, E | ExtraE, Deps, C> | RunConfig<E, U, C, Deps>,\n maybeConfig?: RunConfig<E, U, C, Deps>\n ): Promise<Result<T, E | ExtraE | U, unknown>> {\n let runName: string | undefined;\n let fn: WorkflowFn<T, E | ExtraE, Deps, C>;\n let config: RunConfig<E, U, C, Deps> | undefined;\n\n if (typeof fnOrName === \"string\") {\n runName = fnOrName;\n fn = maybeFnOrConfig as WorkflowFn<T, E | ExtraE, Deps, C>;\n config = maybeConfig;\n } else {\n fn = fnOrName;\n config = maybeFnOrConfig as RunConfig<E, U, C, Deps> | undefined;\n }\n\n return internalExecute<T, ExtraE>(runName, fn, config);\n }\n\n // ==========================================================================\n // workflow.runWithState() - run and return result + resume state for persistence\n // ==========================================================================\n async function runWithStateMethod<T, ExtraE = never>(\n fnOrName: string | WorkflowFn<T, E | ExtraE, Deps, C>,\n maybeFnOrConfig?: WorkflowFn<T, E | ExtraE, Deps, C> | RunConfig<E, U, C, Deps>,\n maybeConfig?: RunConfig<E, U, C, Deps>\n ): Promise<{ result: Result<T, E | ExtraE | U, unknown>; resumeState: ResumeState }> {\n let runName: string | undefined;\n let fn: WorkflowFn<T, E | ExtraE, Deps, C>;\n let config: RunConfig<E, U, C, Deps> | undefined;\n\n if (typeof fnOrName === \"string\") {\n runName = fnOrName;\n fn = maybeFnOrConfig as WorkflowFn<T, E | ExtraE, Deps, C>;\n config = maybeConfig;\n } else {\n fn = fnOrName;\n config = maybeFnOrConfig as RunConfig<E, U, C, Deps> | undefined;\n }\n\n const collector = createResumeStateCollector();\n const userOnEvent = config?.onEvent;\n const mergedOnEvent = (event: WorkflowEvent<E | ExtraE | U, C>, ctx: C) => {\n collector.handleEvent(event);\n try {\n userOnEvent?.(event as WorkflowEvent<E | U, C>, ctx);\n } catch {\n // Observability shouldn't crash runs\n }\n };\n const mergedConfig: RunConfig<E, U, C, Deps> = {\n ...config,\n onEvent: mergedOnEvent as RunConfig<E, U, C, Deps>[\"onEvent\"],\n };\n\n let result: Result<T, E | ExtraE | U, unknown>;\n let resumeState: ResumeState;\n try {\n result = await internalExecute<T, ExtraE>(runName, fn, mergedConfig);\n } catch (thrown) {\n // runWithState follows \"never throw, always Result\"; map thrown to Result\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const catchUnexpected = (optionsActual as any)?.catchUnexpected ?? defaultCatchUnexpected;\n result = err(catchUnexpected(thrown), { cause: thrown }) as Result<T, E | ExtraE | U, unknown>;\n } finally {\n resumeState = collector.getResumeState();\n }\n return { result, resumeState };\n }\n\n const workflow: Workflow<E, U, Deps, C> = {\n run: runMethod as Workflow<E, U, Deps, C>[\"run\"],\n runWithState: runWithStateMethod as Workflow<E, U, Deps, C>[\"runWithState\"],\n };\n\n return workflow;\n}\n","/**\n * awaitly/durable\n *\n * Durable execution with automatic state persistence.\n * Workflows automatically checkpoint after each keyed step and can resume from any point.\n */\n\nimport {\n err,\n type Result,\n type WorkflowEvent,\n type RunStep,\n type UnexpectedError,\n} from \"../core\";\nimport {\n createWorkflow,\n createResumeStateCollector,\n} from \"../workflow\";\nimport type {\n AnyResultFn,\n ErrorsOfDeps,\n WorkflowOptions,\n WorkflowContext,\n WorkflowCancelledError,\n Workflow,\n} from \"../workflow/types\";\nimport {\n type SnapshotStore,\n type WorkflowSnapshot,\n type StepResult,\n type JSONValue,\n mergeSnapshots,\n assertValidSnapshot,\n SnapshotFormatError,\n SnapshotDecodeError,\n serializeError,\n serializeThrown,\n} from \"../persistence\";\n\n// Re-export for convenience\nexport { type SnapshotStore } from \"../persistence\";\nexport { isWorkflowCancelled } from \"../workflow\";\nexport type { WorkflowCancelledError } from \"../workflow/types\";\n\n// In-memory store for zero-config usage\nlet defaultStore: SnapshotStore | undefined;\n\nfunction createMemorySnapshotStore(): SnapshotStore {\n const store = new Map<string, { snapshot: WorkflowSnapshot; updatedAt: Date }>();\n\n return {\n async save(id: string, snapshot: WorkflowSnapshot): Promise<void> {\n store.set(id, { snapshot, updatedAt: new Date() });\n },\n\n async load(id: string): Promise<WorkflowSnapshot | null> {\n const entry = store.get(id);\n return entry?.snapshot ?? null;\n },\n\n async delete(id: string): Promise<void> {\n store.delete(id);\n },\n\n async list(options?: { prefix?: string; limit?: number }): Promise<Array<{ id: string; updatedAt: string }>> {\n const prefix = options?.prefix ?? \"\";\n const limit = options?.limit ?? 100;\n const results: Array<{ id: string; updatedAt: string }> = [];\n\n for (const [id, entry] of store.entries()) {\n if (prefix && !id.startsWith(prefix)) continue;\n results.push({ id, updatedAt: entry.updatedAt.toISOString() });\n if (results.length >= limit) break;\n }\n\n // Sort by updatedAt descending\n results.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));\n return results;\n },\n\n async close(): Promise<void> {\n // No-op for memory store\n },\n };\n}\n\nfunction getDefaultStore(): SnapshotStore {\n if (defaultStore === undefined) {\n defaultStore = createMemorySnapshotStore();\n }\n return defaultStore;\n}\n\n// =============================================================================\n// Durable Execution Types\n// =============================================================================\n\n/**\n * Error returned when workflow cannot resume due to version mismatch.\n * Indicates the stored state was created with a different workflow version.\n * Fail-fast contract: bump version when you change step keys, order, or outputs.\n */\nexport type VersionMismatchError = {\n type: \"VERSION_MISMATCH\";\n /** Workflow execution ID */\n workflowId: string;\n /** Version stored in persisted state */\n storedVersion: number;\n /** Version requested by this run */\n requestedVersion: number;\n /** Guidance message with suggested actions */\n message: string;\n /** Use requestedVersion. */\n currentVersion?: number;\n};\n\n/**\n * Error returned when workflow execution is rejected due to concurrent run.\n */\nexport type ConcurrentExecutionError = {\n type: \"CONCURRENT_EXECUTION\";\n /** The workflow ID that is already running */\n workflowId: string;\n /** Guidance message */\n message: string;\n /**\n * Distinguishes in-process (activeWorkflows) from cross-process (lock held).\n * Enables debuggability and branching without parsing the message.\n */\n reason?: \"in-process\" | \"cross-process\";\n};\n\n/**\n * Error returned when a persistence store operation fails.\n */\nexport type PersistenceError = {\n type: \"PERSISTENCE_ERROR\";\n /** The operation that failed */\n operation: \"load\" | \"save\" | \"delete\";\n /** The workflow ID */\n workflowId: string;\n /** The underlying error */\n cause: unknown;\n /** Guidance message */\n message: string;\n};\n\n/**\n * Type guard to check if an error is a VersionMismatchError.\n */\nexport function isVersionMismatch(error: unknown): error is VersionMismatchError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as VersionMismatchError).type === \"VERSION_MISMATCH\"\n );\n}\n\n/**\n * Type guard to check if an error is a ConcurrentExecutionError.\n */\nexport function isConcurrentExecution(error: unknown): error is ConcurrentExecutionError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as ConcurrentExecutionError).type === \"CONCURRENT_EXECUTION\"\n );\n}\n\n/**\n * Type guard to check if an error is a PersistenceError.\n */\nexport function isPersistenceError(error: unknown): error is PersistenceError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as PersistenceError).type === \"PERSISTENCE_ERROR\"\n );\n}\n\n/**\n * Error returned when a workflow's lease expires mid-execution.\n * Indicates the lock was lost and another process may have reclaimed the workflow.\n */\nexport type LeaseExpiredError = {\n type: \"LEASE_EXPIRED\";\n /** The workflow ID whose lease expired */\n workflowId: string;\n /** Guidance message */\n message: string;\n};\n\n/**\n * Type guard to check if an error is a LeaseExpiredError.\n */\nexport function isLeaseExpired(error: unknown): error is LeaseExpiredError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as LeaseExpiredError).type === \"LEASE_EXPIRED\"\n );\n}\n\n/**\n * Error returned when an idempotency key is reused with different input.\n */\nexport type IdempotencyConflictError = {\n type: \"IDEMPOTENCY_CONFLICT\";\n idempotencyKey: string;\n workflowId: string;\n message: string;\n};\n\nexport function isIdempotencyConflict(error: unknown): error is IdempotencyConflictError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as IdempotencyConflictError).type === \"IDEMPOTENCY_CONFLICT\"\n );\n}\n\n/**\n * Optional cross-process lock interface.\n * When a store implements this, durable.run uses it to ensure only one process\n * runs a given workflow ID at a time (when allowConcurrent is false).\n *\n * Uses a lease (TTL) + owner token so a crashed worker does not wedge a workflow\n * indefinitely. Release must verify the owner token so one process never\n * unlocks another's lease.\n *\n * Mid-run lock loss (e.g. lease expires during a long workflow) is handled\n * adapter-side; core assumes the lock is held until release in finally.\n * Adapters may implement heartbeats/renewal.\n */\nexport interface WorkflowLock {\n /**\n * Try to acquire a lease for the workflow ID.\n * @param id - Workflow execution ID\n * @param options - Optional TTL for the lease (adapter default if omitted)\n * @returns Owner token if acquired, null if already held by another\n */\n tryAcquire(\n id: string,\n options?: { ttlMs?: number }\n ): Promise<{ ownerToken: string } | null>;\n\n /**\n * Release the lease. Must verify owner token; no-op or ignore if token\n * does not match (e.g. lease already expired or taken by another).\n */\n release(id: string, ownerToken: string): Promise<void>;\n\n /**\n * Extend the lease for an already-held lock.\n * Returns true if renewed, false if lost.\n * Optional — when not implemented, no heartbeat runs.\n */\n renew?(id: string, ownerToken: string, options?: { ttlMs?: number }): Promise<boolean>;\n}\n\n/**\n * Check if a store implements the optional WorkflowLock interface.\n */\nfunction hasWorkflowLock(\n store: SnapshotStore\n): store is SnapshotStore & WorkflowLock {\n return (\n typeof (store as SnapshotStore & WorkflowLock).tryAcquire === \"function\" &&\n typeof (store as SnapshotStore & WorkflowLock).release === \"function\"\n );\n}\n\n/**\n * Options for durable workflow execution.\n */\nexport interface DurableOptions<C = void> {\n /**\n * Unique workflow execution ID.\n * Used as the key for state persistence.\n *\n * @example 'order-checkout-123', 'user-onboarding-abc'\n */\n id: string;\n\n /**\n * Snapshot store for persistence. Optional. When omitted, an in-memory store is used (per process).\n * Same-process resume/retry works; state is lost on restart. Override with postgres/mongo/libsql for persistence.\n *\n * @example\n * ```typescript\n * // Zero-config: uses in-memory store (per process)\n * await durable.run(deps, fn, { id: 'my-id' });\n *\n * // Override: pass a store for persistence across restarts\n * import { postgres } from 'awaitly-postgres';\n * const store = postgres('postgresql://localhost/mydb');\n * await durable.run(deps, fn, { id: 'my-id', store });\n * ```\n */\n store?: SnapshotStore;\n\n /**\n * Workflow logic version.\n * If stored state has a different version, workflow will reject resume with VersionMismatchError\n * unless onVersionMismatch is used to clear or migrate.\n *\n * Bump when you change step keys, reorder steps, or change step outputs in a way old checkpoints can't satisfy.\n *\n * @default 1\n */\n version?: number;\n\n /**\n * When stored state version differs from requested version, either throw (default), clear state and run from scratch, or supply migrated snapshot.\n * Use for migration or one-off clear without wrapping durable.run.\n *\n * @default 'throw'\n */\n onVersionMismatch?: (ctx: {\n id: string;\n storedVersion: number;\n requestedVersion: number;\n }) => \"throw\" | \"clear\" | { migratedSnapshot: WorkflowSnapshot } | Promise<\"throw\" | \"clear\" | { migratedSnapshot: WorkflowSnapshot }>;\n\n /**\n * Allow concurrent executions with the same workflow ID.\n * When `false` (default), a second run with the same ID will be rejected while one is active.\n *\n * @default false\n */\n allowConcurrent?: boolean;\n\n /**\n * Lease TTL in milliseconds for cross-process locking.\n * Only used when the store implements WorkflowLock and allowConcurrent is false.\n * A crashed worker's lease expires after this duration so the workflow can be picked up again.\n *\n * @default 60000 (1 minute)\n */\n lockTtlMs?: number;\n\n /**\n * Heartbeat interval for lease renewal (ms).\n * Only active when store implements WorkflowLock with renew().\n * @default lockTtlMs / 3\n */\n heartbeatIntervalMs?: number;\n\n /**\n * Whether to abort the workflow when lease is lost mid-execution.\n * @default true\n */\n abortOnLeaseLoss?: boolean;\n\n /**\n * Metadata to store alongside workflow state.\n * Useful for debugging, auditing, or filtering workflows.\n *\n * @example { userId: 'user-123', source: 'api' }\n */\n metadata?: Record<string, unknown>;\n\n /**\n * External AbortSignal for workflow-level cancellation.\n * Cancellation persists state up to the last completed step.\n */\n signal?: AbortSignal;\n\n /**\n * Create per-run context for event correlation.\n */\n createContext?: () => C;\n\n /**\n * Unified event stream for workflow and step lifecycle.\n * Includes durable-specific events: `persist_success` and `persist_error`.\n */\n onEvent?: (event: DurableWorkflowEvent<unknown, C>, ctx: C) => void;\n\n /**\n * Handler for expected and unexpected errors.\n */\n onError?: (error: unknown, stepName?: string, ctx?: C) => void;\n\n /**\n * Idempotency key for deduplication.\n * If provided and a completed workflow with this key exists in the store,\n * the stored result is returned without re-execution.\n * If the stored input differs, an IdempotencyConflictError is returned.\n */\n idempotencyKey?: string;\n\n /**\n * Workflow input for idempotency conflict detection.\n * When idempotencyKey is set, this is compared against stored input.\n * Must be JSON-serializable.\n */\n input?: unknown;\n}\n\n/**\n * Extended workflow event type that includes durable-specific events.\n * E is the deps error type - the full error type includes E | UnexpectedError.\n */\nexport type DurableWorkflowEvent<E, C = void> =\n | WorkflowEvent<E | UnexpectedError, C>\n | {\n type: \"persist_success\";\n workflowId: string;\n stepKey: string;\n ts: number;\n context?: C;\n }\n | {\n type: \"persist_error\";\n workflowId: string;\n stepKey: string;\n error: unknown;\n ts: number;\n context?: C;\n };\n\n/**\n * Options for bulk delete of workflow state.\n */\nexport interface DeleteStatesOptions {\n /**\n * Max number of concurrent delete calls when store has no deleteMany.\n * @default 10\n */\n concurrency?: number;\n /**\n * When true, collect errors and return them; when false, throw on first error.\n * @default true\n */\n continueOnError?: boolean;\n}\n\n/**\n * Result of bulk delete of workflow state.\n */\nexport interface DeleteStatesResult {\n /** Number of entries successfully deleted. */\n deleted: number;\n /** Per-id errors when continueOnError was true and some deletes failed. */\n errors?: Array<{ id: string; error: unknown }>;\n}\n\n// Track active workflow executions for concurrency control\nconst activeWorkflows = new Set<string>();\n// Track in-flight idempotency key executions so concurrent in-process callers\n// can await the first execution's result instead of racing through the store load.\nconst pendingIdempotencyRuns = new Map<string, Promise<unknown>>();\n\n/**\n * Durable workflow execution namespace.\n */\nexport const durable = {\n /**\n * Execute a workflow with automatic state persistence.\n *\n * Features:\n * - **Automatic checkpointing**: State is saved after each keyed step\n * - **Crash recovery**: Resume from the last completed step on restart\n * - **Version checking**: Reject resume if workflow logic version changed\n * - **Concurrency control**: Prevent duplicate executions of the same workflow ID\n * - **Cancellation support**: Integrates with AbortSignal for graceful shutdown\n *\n * ## How It Works\n *\n * 1. On start: Load existing state from store (if any)\n * 2. Check version compatibility (reject if mismatch)\n * 3. Pre-populate cache from loaded state (skip completed steps)\n * 4. Execute workflow, persisting state after each keyed step\n * 5. On completion: Delete stored state (clean up)\n * 6. On error/cancellation: State remains for future resume\n *\n * ## Important Notes\n *\n * - **Only keyed steps are durable**: Use `{ key: 'step-name' }` option\n * - **Steps should be idempotent**: They may be retried on resume\n * - **Serialization**: State is JSON-serialized; complex objects may lose fidelity\n *\n * @param deps - Workflow dependencies (Result-returning functions)\n * @param fn - Workflow function receiving ({ step, deps, ctx })\n * @param options - Durable execution options\n * @returns AsyncResult with workflow result or error\n *\n * @example\n * ```typescript\n * import { durable } from 'awaitly/durable';\n *\n * // Zero-config: uses in-memory store (per process)\n * const result = await durable.run(\n * { fetchUser, createOrder, sendEmail },\n * async ({ step, deps: { fetchUser, createOrder, sendEmail } }) => {\n * const user = await step(() => fetchUser('123'), { key: 'fetch-user' });\n * const order = await step(() => createOrder(user), { key: 'create-order' });\n * await step(() => sendEmail(order), { key: 'send-email' });\n * return order;\n * },\n * { id: 'checkout-123' }\n * );\n *\n * // Override: pass a store for persistence across restarts\n * import { createMemoryStatePersistence } from 'awaitly/persistence';\n * const store = createMemoryStatePersistence();\n * await durable.run(deps, fn, { id: 'checkout-123', store });\n *\n * if (result.ok) {\n * console.log('Order completed:', result.value);\n * } else if (isWorkflowCancelled(result.error)) {\n * console.log('Workflow cancelled at:', result.error.lastStepKey);\n * }\n * ```\n */\n async run<\n const Deps extends Readonly<Record<string, AnyResultFn>>,\n T,\n C = void\n >(\n deps: Deps,\n fn: (\n context: { step: RunStep<ErrorsOfDeps<Deps>>; deps: Deps; ctx: WorkflowContext<C> }\n ) => T | Promise<T>,\n options: DurableOptions<C>\n ): Promise<\n Result<\n T,\n | ErrorsOfDeps<Deps>\n | UnexpectedError\n | WorkflowCancelledError\n | VersionMismatchError\n | ConcurrentExecutionError\n | PersistenceError\n | LeaseExpiredError\n | IdempotencyConflictError,\n unknown\n >\n > {\n const {\n id,\n store: storeOption,\n version = 1,\n allowConcurrent = false,\n lockTtlMs = 60_000,\n heartbeatIntervalMs,\n abortOnLeaseLoss,\n metadata,\n signal,\n createContext,\n onEvent,\n onError,\n onVersionMismatch,\n idempotencyKey,\n input,\n } = options;\n\n const effectiveStore = storeOption ?? getDefaultStore();\n\n // Idempotency check — before concurrency and lock\n // resolveIdempotencyRun is set when this caller wins the in-process race\n // and must be resolved in the finally block so waiters get the result.\n let resolveIdempotencyRun: ((v: unknown) => void) | undefined;\n if (idempotencyKey) {\n const idemId = `idem:${idempotencyKey}`;\n\n // In-process dedup (synchronous check — prevents TOCTOU race between concurrent async loads)\n const pending = pendingIdempotencyRuns.get(idemId);\n if (pending) {\n return (await pending) as Result<T, ErrorsOfDeps<Deps> | UnexpectedError | WorkflowCancelledError | VersionMismatchError | ConcurrentExecutionError | PersistenceError | LeaseExpiredError | IdempotencyConflictError, unknown>;\n }\n\n // Register ourselves synchronously before any async work\n pendingIdempotencyRuns.set(idemId, new Promise<unknown>((r) => { resolveIdempotencyRun = r; }));\n\n try {\n const idemSnapshot = await effectiveStore.load(idemId);\n if (idemSnapshot) {\n // Check for input conflict\n if (input !== undefined && idemSnapshot.metadata?.input !== undefined) {\n const storedInput = JSON.stringify(idemSnapshot.metadata.input);\n const currentInput = JSON.stringify(input);\n if (storedInput !== currentInput) {\n const result = err({\n type: \"IDEMPOTENCY_CONFLICT\" as const,\n idempotencyKey,\n workflowId: id,\n message: `Idempotency key '${idempotencyKey}' already used with different input for workflow '${id}'.`,\n });\n resolveIdempotencyRun!(result);\n pendingIdempotencyRuns.delete(idemId);\n resolveIdempotencyRun = undefined;\n return result;\n }\n }\n\n // If completed with a stored result, return it\n if (idemSnapshot.execution.status === \"completed\" && idemSnapshot.metadata?.finalResult !== undefined) {\n // Return the stored result directly\n const result = idemSnapshot.metadata.finalResult as Result<T, ErrorsOfDeps<Deps> | UnexpectedError | WorkflowCancelledError | VersionMismatchError | ConcurrentExecutionError | PersistenceError | LeaseExpiredError | IdempotencyConflictError, unknown>;\n resolveIdempotencyRun!(result);\n pendingIdempotencyRuns.delete(idemId);\n resolveIdempotencyRun = undefined;\n return result;\n }\n\n // If still running, treat as concurrent\n if (idemSnapshot.execution.status === \"running\") {\n const result = err({\n type: \"CONCURRENT_EXECUTION\" as const,\n workflowId: id,\n message: `Workflow '${id}' with idempotency key '${idempotencyKey}' is already running.`,\n reason: \"cross-process\" as const,\n });\n resolveIdempotencyRun!(result);\n pendingIdempotencyRuns.delete(idemId);\n resolveIdempotencyRun = undefined;\n return result;\n }\n }\n } catch {\n // If we can't check idempotency, continue with normal execution\n // (don't block on idempotency check failure)\n }\n\n // Save \"running\" marker for cross-process safety\n try {\n await effectiveStore.save(idemId, {\n formatVersion: 1,\n steps: {},\n execution: {\n status: \"running\",\n lastUpdated: new Date().toISOString(),\n },\n metadata: {\n workflowId: id,\n idempotencyKey,\n input: input as JSONValue,\n },\n } satisfies WorkflowSnapshot);\n } catch {\n // Non-fatal: best-effort cross-process marker\n }\n }\n\n // In-process concurrency check\n if (!allowConcurrent && activeWorkflows.has(id)) {\n const error: ConcurrentExecutionError = {\n type: \"CONCURRENT_EXECUTION\",\n workflowId: id,\n message: `Workflow '${id}' is already running. Set allowConcurrent: true to allow parallel executions.`,\n reason: \"in-process\",\n };\n return err(error);\n }\n\n // Cross-process lock (optional): try acquire lease when store implements WorkflowLock\n let leaseOwnerToken: string | null = null;\n if (!allowConcurrent && hasWorkflowLock(effectiveStore)) {\n let lease: { ownerToken: string } | null;\n try {\n lease = await effectiveStore.tryAcquire(id, { ttlMs: lockTtlMs });\n } catch (lockError) {\n const error: PersistenceError = {\n type: \"PERSISTENCE_ERROR\",\n operation: \"load\",\n workflowId: id,\n cause: lockError,\n message: `Failed to acquire lock for workflow '${id}': ${lockError instanceof Error ? lockError.message : String(lockError)}`,\n };\n return err(error);\n }\n if (lease === null) {\n const error: ConcurrentExecutionError = {\n type: \"CONCURRENT_EXECUTION\",\n workflowId: id,\n message: `Workflow '${id}' is already running (lease held by another process). Set allowConcurrent: true to allow parallel executions.`,\n reason: \"cross-process\",\n };\n return err(error);\n }\n leaseOwnerToken = lease.ownerToken;\n }\n\n // Start heartbeat if store supports renew\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n let leaseAbortController: AbortController | undefined;\n\n const lockStore = effectiveStore as SnapshotStore & WorkflowLock;\n if (leaseOwnerToken && typeof lockStore.renew === \"function\") {\n const heartbeatMs = heartbeatIntervalMs ?? Math.floor(lockTtlMs / 3);\n leaseAbortController = new AbortController();\n\n heartbeatTimer = setInterval(async () => {\n try {\n const renewed = await lockStore.renew!(id, leaseOwnerToken!, { ttlMs: lockTtlMs });\n if (!renewed) {\n leaseAbortController!.abort(new Error(\"Lease expired\"));\n }\n } catch {\n leaseAbortController!.abort(new Error(\"Lease renewal failed\"));\n }\n }, heartbeatMs);\n }\n\n // Mark as active (in-process)\n activeWorkflows.add(id);\n\n // Tracks the final result so the idempotency deferred can be resolved in finally.\n let durableResult: unknown;\n try {\n // Load existing snapshot (wrap in try-catch to return Result on store errors)\n let existingSnapshot: WorkflowSnapshot | null = null;\n try {\n existingSnapshot = await effectiveStore.load(id);\n } catch (loadError) {\n const error: PersistenceError = {\n type: \"PERSISTENCE_ERROR\",\n operation: \"load\",\n workflowId: id,\n cause: loadError,\n message: `Failed to load state for workflow '${id}': ${loadError instanceof Error ? loadError.message : String(loadError)}`,\n };\n durableResult = err(error); return err(error);\n }\n\n // Validate snapshot format if it exists\n if (existingSnapshot) {\n try {\n assertValidSnapshot(existingSnapshot);\n } catch (validationError) {\n if (validationError instanceof SnapshotFormatError) {\n const error: PersistenceError = {\n type: \"PERSISTENCE_ERROR\",\n operation: \"load\",\n workflowId: id,\n cause: validationError,\n message: `Invalid snapshot format for workflow '${id}': ${validationError.message}`,\n };\n durableResult = err(error); return err(error);\n }\n throw validationError;\n }\n }\n\n // Version check if snapshot exists\n if (existingSnapshot) {\n // Check metadata.version (workflow logic version)\n // Snapshots without version metadata default to version 1\n const storedVersion =\n typeof existingSnapshot.metadata?.version === \"number\"\n ? existingSnapshot.metadata.version\n : 1;\n if (storedVersion !== version) {\n const error: VersionMismatchError = {\n type: \"VERSION_MISMATCH\",\n workflowId: id,\n storedVersion,\n requestedVersion: version,\n currentVersion: version,\n message: `Workflow '${id}' has stored state at version ${storedVersion} but this run requested version ${version}. Migrate the stored state to the new version, or clear state for this id (e.g. durable.deleteState(store, '${id}')) and re-run.`,\n };\n if (!onVersionMismatch) {\n durableResult = err(error); return err(error);\n }\n const resolution = await Promise.resolve(\n onVersionMismatch({ id, storedVersion, requestedVersion: version })\n );\n if (resolution === \"throw\") {\n durableResult = err(error); return err(error);\n }\n if (resolution === \"clear\") {\n try {\n await effectiveStore.delete(id);\n } catch {\n // ignore delete errors\n }\n existingSnapshot = null;\n } else {\n existingSnapshot = resolution.migratedSnapshot;\n }\n }\n }\n\n // Define error type for this workflow\n type E = ErrorsOfDeps<Deps>;\n\n // Wrapper to emit durable-specific events\n const emitDurableEvent = (event: DurableWorkflowEvent<E, C>, ctx: C): void => {\n if (onEvent) {\n onEvent(event, ctx);\n }\n };\n\n // Collect step results via onEvent for snapshot building\n const resumeCollector = createResumeStateCollector();\n\n // Build workflow options with proper types (U = UnexpectedError by default)\n const workflowOptions: WorkflowOptions<E, UnexpectedError, C> = {\n // Restore from existing snapshot\n snapshot: existingSnapshot,\n\n // Persist after each keyed step\n onAfterStep: async (stepKey, result, wfId, ctx) => {\n try {\n // Build a snapshot from collected step results\n const collectedState = resumeCollector.getResumeState();\n const steps: Record<string, StepResult> = {};\n for (const [key, entry] of collectedState.steps) {\n if (entry.result.ok) {\n steps[key] = { ok: true, value: entry.result.value as JSONValue };\n } else {\n // Serialize cause for proper snapshot format\n const cause = entry.result.cause;\n const serializedCause = cause instanceof Error\n ? serializeError(cause)\n : serializeThrown(cause);\n const origin: \"result\" | \"throw\" = entry.meta?.origin === \"throw\" ? \"throw\" : \"result\";\n steps[key] = {\n ok: false,\n error: entry.result.error as JSONValue,\n cause: serializedCause,\n meta: { origin },\n };\n }\n }\n\n const currentSnapshot: WorkflowSnapshot = {\n formatVersion: 1,\n workflowName: id,\n steps,\n execution: {\n status: \"running\",\n lastUpdated: new Date().toISOString(),\n currentStepId: stepKey,\n },\n metadata: {\n ...(existingSnapshot?.metadata ?? {}),\n ...metadata,\n version,\n lastStepKey: stepKey,\n } as Record<string, JSONValue>,\n };\n\n // If we have an existing snapshot, merge it with the current one\n // This preserves steps from previous runs\n let snapshotToSave = existingSnapshot\n ? mergeSnapshots(existingSnapshot, currentSnapshot)\n : currentSnapshot;\n\n // Clear stale warnings for steps that were re-executed in this run\n if (snapshotToSave.warnings && snapshotToSave.warnings.length > 0) {\n const currentStepKeys = new Set(Object.keys(currentSnapshot.steps));\n const filtered = snapshotToSave.warnings.filter(\n w => !currentStepKeys.has(w.stepId)\n );\n snapshotToSave = {\n ...snapshotToSave,\n warnings: filtered.length > 0 ? filtered : undefined,\n };\n }\n\n // Persist to store\n await effectiveStore.save(id, snapshotToSave);\n\n // Emit success event\n emitDurableEvent(\n {\n type: \"persist_success\",\n workflowId: wfId,\n stepKey,\n ts: Date.now(),\n context: ctx as C,\n },\n ctx as C\n );\n } catch (persistError) {\n // Emit error event but continue workflow (per Temporal/Cloudflare pattern)\n emitDurableEvent(\n {\n type: \"persist_error\",\n workflowId: wfId,\n stepKey,\n error: persistError,\n ts: Date.now(),\n context: ctx as C,\n },\n ctx as C\n );\n }\n },\n\n // Forward events and collect step results for snapshot building\n onEvent: (event, ctx) => {\n resumeCollector.handleEvent(event);\n emitDurableEvent(event as DurableWorkflowEvent<E, C>, ctx as C);\n },\n\n onError: onError as (error: E | UnexpectedError, stepName?: string, ctx?: C) => void,\n signal: leaseAbortController && signal\n ? AbortSignal.any([signal, leaseAbortController.signal])\n : leaseAbortController?.signal ?? signal,\n createContext,\n };\n\n // Create workflow instance (U = UnexpectedError by default)\n let workflowInstance: Workflow<E, UnexpectedError, Deps, C>;\n try {\n workflowInstance = createWorkflow<Deps, UnexpectedError, C>(id, deps, workflowOptions);\n } catch (createError) {\n if (createError instanceof SnapshotFormatError) {\n const error: PersistenceError = {\n type: \"PERSISTENCE_ERROR\",\n operation: \"load\",\n workflowId: id,\n cause: createError,\n message: `Invalid snapshot format for workflow '${id}': ${createError.message}`,\n };\n durableResult = err(error); return err(error);\n }\n throw createError;\n }\n\n // Execute workflow (snapshot validation may throw SnapshotFormatError at run time)\n let result: Result<T, E | UnexpectedError | PersistenceError, unknown>;\n try {\n result = await workflowInstance!.run(fn);\n } catch (runError) {\n if (runError instanceof SnapshotFormatError || runError instanceof SnapshotDecodeError) {\n const error: PersistenceError = {\n type: \"PERSISTENCE_ERROR\",\n operation: \"load\",\n workflowId: id,\n cause: runError,\n message: `Invalid snapshot format for workflow '${id}': ${runError.message}`,\n };\n durableResult = err(error); return err(error);\n }\n throw runError;\n }\n\n // Check if lease was lost during execution\n if (abortOnLeaseLoss !== false && leaseAbortController?.signal.aborted) {\n const leaseErr = err({\n type: \"LEASE_EXPIRED\" as const,\n workflowId: id,\n message: `Lease expired for workflow '${id}' during execution. The workflow may have been reclaimed by another process.`,\n });\n durableResult = leaseErr;\n return leaseErr;\n }\n\n // On success: clean up stored state\n if (result.ok) {\n try {\n await effectiveStore.delete(id);\n } catch (deleteError) {\n const error: PersistenceError = {\n type: \"PERSISTENCE_ERROR\",\n operation: \"delete\",\n workflowId: id,\n cause: deleteError,\n message: `Failed to delete state for workflow '${id}': ${deleteError instanceof Error ? deleteError.message : String(deleteError)}`,\n };\n durableResult = err(error); return err(error);\n }\n\n // Save idempotency record on success\n if (idempotencyKey) {\n const idemId = `idem:${idempotencyKey}`;\n try {\n await effectiveStore.save(idemId, {\n formatVersion: 1,\n steps: {},\n execution: {\n status: \"completed\",\n lastUpdated: new Date().toISOString(),\n completedAt: new Date().toISOString(),\n },\n metadata: {\n workflowId: id,\n idempotencyKey,\n input: input as JSONValue,\n finalResult: result as JSONValue,\n },\n } satisfies WorkflowSnapshot);\n } catch {\n // Non-fatal: workflow succeeded but idempotency record failed to save\n }\n }\n }\n // On error/cancellation: state remains for resume\n\n // Workflow result is structurally compatible with our return type\n // (workflow returns E | UnexpectedError, we return that plus our durable-specific errors)\n durableResult = result;\n return result;\n } finally {\n // Always remove from active set\n activeWorkflows.delete(id);\n // Resolve in-process idempotency deferred so concurrent waiters get the result\n if (resolveIdempotencyRun) {\n resolveIdempotencyRun(durableResult);\n pendingIdempotencyRuns.delete(`idem:${idempotencyKey}`);\n }\n // Clear heartbeat timer before releasing lock\n if (heartbeatTimer) {\n clearInterval(heartbeatTimer);\n }\n // Release cross-process lease if we acquired one (verify owner in adapter)\n // Guard the await so a failing release doesn't turn a successful run into a rejection\n if (leaseOwnerToken !== null && hasWorkflowLock(effectiveStore)) {\n try {\n await effectiveStore.release(id, leaseOwnerToken);\n } catch {\n // Swallow release errors - the workflow result is already determined\n // and we don't want to mask it with a lock release failure\n }\n }\n }\n },\n\n /**\n * Clear all persisted workflow state from the store.\n * Use for admin/testing. If the store implements `clear()`, that is used;\n * otherwise clears by listing and deleting in pages.\n *\n * @param store - Snapshot store\n */\n async clearState(store: SnapshotStore): Promise<void> {\n const storeWithClear = store as SnapshotStore & { clear?(): Promise<void> };\n if (typeof storeWithClear.clear === \"function\") {\n await storeWithClear.clear();\n return;\n }\n const limit = 100;\n for (;;) {\n const entries = await store.list({ limit });\n if (entries.length === 0) break;\n const ids = entries.map(e => e.id);\n await this.deleteStates(store, ids, { continueOnError: true });\n if (entries.length < limit) break;\n }\n },\n\n /**\n * Check if a workflow ID has persisted state (can be resumed).\n *\n * @param store - Snapshot store\n * @param id - Workflow execution ID\n * @returns `true` if state exists, `false` otherwise (including on store errors)\n */\n async hasState(store: SnapshotStore, id: string): Promise<boolean> {\n try {\n const snapshot = await store.load(id);\n return snapshot !== null;\n } catch {\n return false;\n }\n },\n\n /**\n * Delete persisted state for a workflow (cancel resume capability).\n * Deleting is effectively an ack/reset: the workflow can no longer resume from that state.\n * If you delete while a run is in flight, the run continues; on success it may delete again (no-op) or save (recreating state).\n * For multi-worker safety, prefer deleting only when the workflow is not running or when you hold the lock.\n *\n * @param store - Snapshot store\n * @param id - Workflow execution ID\n * @returns `true` on success, `false` on store errors\n */\n async deleteState(store: SnapshotStore, id: string): Promise<boolean> {\n try {\n await store.delete(id);\n return true;\n } catch {\n return false;\n }\n },\n\n /**\n * Bulk delete persisted state for multiple workflow IDs (best-effort).\n * Use for admin/cleanup. Deletes in a loop with optional concurrency.\n *\n * @param store - Snapshot store\n * @param ids - Workflow execution IDs to delete\n * @param options - Optional concurrency and error handling\n * @returns Count of deleted entries and any errors when continueOnError is true\n */\n async deleteStates(\n store: SnapshotStore,\n ids: string[],\n options: DeleteStatesOptions = {}\n ): Promise<DeleteStatesResult> {\n const { concurrency = 10, continueOnError = true } = options;\n if (ids.length === 0) {\n return { deleted: 0 };\n }\n const errors: Array<{ id: string; error: unknown }> = [];\n let deleted = 0;\n const run = async (id: string): Promise<void> => {\n try {\n await store.delete(id);\n deleted++;\n } catch (error) {\n if (continueOnError) errors.push({ id, error });\n else throw error;\n }\n };\n const limit = Math.max(1, concurrency);\n for (let i = 0; i < ids.length; i += limit) {\n const batch = ids.slice(i, i + limit);\n await Promise.all(batch.map((id) => run(id)));\n }\n return errors.length > 0 ? { deleted, errors } : { deleted };\n },\n\n /**\n * List workflow IDs with persisted state.\n *\n * @param store - Snapshot store\n * @param options - Optional prefix and limit\n * @returns Array of { id, updatedAt } entries\n */\n async listPending(\n store: SnapshotStore,\n options?: { prefix?: string; limit?: number }\n ): Promise<Array<{ id: string; updatedAt: string }>> {\n try {\n return await store.list(options);\n } catch {\n return [];\n }\n },\n};\n"],"mappings":"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","names":["durable_entry_exports","__export","durable","isConcurrentExecution","isIdempotencyConflict","isLeaseExpired","isPersistenceError","isVersionMismatch","isWorkflowCancelled","__toCommonJS","InternalTaggedErrorBase","TaggedError","tag","options","props","errorOptions","message","_","_n","_m","_s","safeProps","hasUserCause","userCause","hasOptionsCause","instance","isError","value","isTaggedError","match","error","handlers","handler","matchPartial","otherwise","TimeoutError","TaggedError","p","RetryExhaustedError","RateLimitError","CircuitBreakerOpenError","ValidationError","NotFoundError","UnauthorizedError","NetworkError","CompensationError","UnexpectedError","parseDurationString","input","match","value","unit","defaultCatchUnexpected","cause","UnexpectedError","ok","value","err","error","options","isUnexpectedError","UnexpectedError","extractErrorTag","error","tagged","trimmed","lookupErrorClassification","tag","errorMeta","extractStepMetadata","options","intent","domain","owner","tags","stateChanges","emits","calls","metadata","buildStepErrorPayload","origin","attempt","cumulativeDurationMs","classification","diagnostics","STEP_TIMEOUT_MARKER","isStepTimeoutError","getStepTimeoutMeta","err","EARLY_EXIT_SYMBOL","createEarlyExit","meta","isEarlyExit","MAPPER_EXCEPTION_SYMBOL","createMapperException","thrown","isMapperException","calculateRetryDelay","backoff","initialDelay","maxDelay","jitter","delay","jitterAmount","sleep","ms","resolve","TIMEOUT_SYMBOL","TIMEOUT_OPTION_SYMBOL","isTimeoutOptionMarker","value","executeWithTimeout","operation","options","stepInfo","externalSignal","controller","behavior","createTimeoutError","timeoutId","externalAbortHandler","timeoutPromise","_","reject","operationPromise","error","errorToThrow","meta","STEP_TIMEOUT_MARKER","DEFAULT_RETRY_CONFIG","run","fn","onError","onEvent","catchUnexpected","providedWorkflowId","workflowName","context","_workflowSignal","workflowId","effectiveCatchUnexpected","defaultCatchUnexpected","activeScopeStack","stepIdCounter","generateStepId","stepKey","emitEvent","event","eventWithContext","eventWithName","stepId","i","scope","earlyExit","createEarlyExit","isEarlyExitE","e","isEarlyExit","wrapForStep","_meta","isResultLike","normalizeParallelOperations","rawOperations","out","key","executeParallelArray","name","scopeId","startTime","scopeEnded","emitScopeEnd","idx","s","result","executeParallelNamed","operations","keys","results","resolve","settled","pendingCount","resultArray","index","reason","err","output","stepFn","id","operationOrResult","stepOptions","parsedOptions","stepMetadata","extractStepMetadata","stepName","explicitKey","stepDescription","retryConfig","timeoutConfig","hasEventListeners","overallStartTime","effectiveRetry","lastResult","attempt","attemptStartTime","durationMs","delay","calculateRetryDelay","buildStepErrorPayload","sleep","thrown","timeoutMs","ok","isStepTimeoutError","timeoutMeta","getStepTimeoutMeta","totalDurationMs","mappedError","mapperError","createMapperException","errorResult","wrappedError","opts","mapToError","mapped","onNull","duration","d","parseDurationString","ms","userSignal","state","onAbort","args","second","normalizedOperations","scopeEntry","_id","_conditionLabel","condition","thenFn","elseFn","errors","items","maxIterations","isRunForm","asyncItems","item","handler","_name","getter","handlers","resolved","mapper","concurrency","allAsync","batch","batchResult","batchIndex","primaryResult","fallbackResultFromThrow","fallbackThrown","fallbackMappedError","primaryError","fallbackResult","acquireResult","resource","useResult","useThrown","useThrewNonResult","releaseErr","maybeResult","isMapperException","originalCause","allAsync","results","ok","resolve","settled","pendingCount","values","i","index","reason","err","result","isStepComplete","event","isWorkflowCancelled","error","SnapshotFormatError","message","errors","SnapshotDecodeError","message","stepId","originalError","validateSnapshot","obj","errors","snapshot","steps","stepId","stepResult","step","execution","assertValidSnapshot","result","SnapshotFormatError","mergeSnapshots","base","delta","mergedSteps","key","value","mergedMetadata","mergedWarnings","w","MAX_STRING_REPRESENTATION_LENGTH","serializeError","error","serialized","errorWithCause","serializeThrown","stringRepresentation","truncated","originalType","jsonValue","deserializeCauseNew","isCachedErrorCause","cause","encodeCachedError","error","meta","originalCause","err","decodeCachedMeta","createResumeStateCollector","steps","event","isStepComplete","STREAM_WRITE_ERROR","STREAM_READ_ERROR","STREAM_CLOSE_ERROR","STREAM_ENDED","streamWriteError","reason","message","cause","STREAM_WRITE_ERROR","streamReadError","STREAM_READ_ERROR","streamCloseError","STREAM_CLOSE_ERROR","streamEnded","finalPosition","STREAM_ENDED","createBackpressureController","options","highWaterMark","lowWaterMark","onStateChange","state","bufferedCount","drainResolvers","updateState","newState","resolvers","resolve","checkState","count","millis","ms","seconds","s","minutes","m","hours","h","days","d","toMillis","duration","parse","input","match","value","millis","seconds","minutes","hours","days","validateInput","schema","input","result","resolved","err","i","p","ok","createWorkflow","workflowName","deps","options","depsActual","optionsActual","internalExecute","runName","userFn","config","workflowId","effectiveDeps","createContextFn","context","workflowSignal","onEventHandler","onErrorHandler","shouldRunHook","onBeforeStartHook","onAfterStepHook","resumeStateOption","catchUnexpected","defaultCatchUnexpected","workflowData","devWarnings","ctxSetWarned","ctxGetWarned","workflowContext","key","value","emitEvent","event","eventWithContext","eventWithName","createCancelledResult","reason","lastStepKey","cancelledError","err","hookStartTime","shouldRunResult","hookDuration","skipCause","thrown","beforeStartResult","inputSchema","inputValue","validationResult","validateInput","startTs","startTime","cache","streamStore","resumeState","entry","result","meta","effectiveMeta","encodeCachedError","snapshotOption","snapshotSerialization","snapshot","decode","stepId","stepResult","ok","errorValue","deserializedCause","deserializeCauseNew","e","SnapshotDecodeError","abortedDuringExecution","abortReason","abortHandler","checkCancellation","callOnAfterStepHook","stepKey","_meta","createCachedStep","realStep","cachedStepFn","idOrOperationOrResult","operationOrOptions","stepOptions","id","opts","name","ttl","out","stepMetadata","extractStepMetadata","cached","decodeCachedMeta","createEarlyExit","isEarlyExit","exit","originalCause","errorResult","operation","duration","d","parse","ms","toMillis","userSignal","resolve","reject","state","onAbort","activeWriters","activeReaders","namespace","highWaterMark","existingKey","existing","backpressure","createBackpressureController","position","writable","aborted","closed","writer","streamWriteError","item","streamCloseError","startIndex","pollInterval","pollTimeout","decrementBackpressure","writerKey","activeWriter","readable","bufferedItems","bufferIndex","reader","streamReadError","pollStart","hasSeenWriter","initialMetaResult","hasSeenMetadata","items","writerActive","metaResult","metadataExists","streamEnded","source","processor","checkpointInterval","concurrency","results","processedCount","lastPosition","isStreamReader","s","processItem","itemIndex","itemPosition","readResult","resultsMap","totalItems","slots","getSlot","i","activePromises","completed","slotIndex","currentIndex","currentPosition","currentItem","currentSlot","r","index","resultOrGetter","getter","fn","handlers","resolved","shape","mapper","wrappedFn","step","run","durationMs","isWorkflowCancelled","isUnexpectedError","runMethod","fnOrName","maybeFnOrConfig","maybeConfig","runWithStateMethod","collector","createResumeStateCollector","userOnEvent","mergedConfig","ctx","defaultStore","createMemorySnapshotStore","store","id","snapshot","options","prefix","limit","results","entry","a","getDefaultStore","isVersionMismatch","error","isConcurrentExecution","isPersistenceError","isLeaseExpired","isIdempotencyConflict","hasWorkflowLock","activeWorkflows","pendingIdempotencyRuns","durable","deps","fn","storeOption","version","allowConcurrent","lockTtlMs","heartbeatIntervalMs","abortOnLeaseLoss","metadata","signal","createContext","onEvent","onError","onVersionMismatch","idempotencyKey","input","effectiveStore","resolveIdempotencyRun","idemId","pending","r","idemSnapshot","storedInput","currentInput","result","err","leaseOwnerToken","lease","lockError","heartbeatTimer","leaseAbortController","lockStore","heartbeatMs","durableResult","existingSnapshot","loadError","assertValidSnapshot","validationError","SnapshotFormatError","storedVersion","resolution","emitDurableEvent","event","ctx","resumeCollector","createResumeStateCollector","workflowOptions","stepKey","wfId","collectedState","steps","key","cause","serializedCause","serializeError","serializeThrown","origin","currentSnapshot","snapshotToSave","mergeSnapshots","currentStepKeys","filtered","w","persistError","workflowInstance","createWorkflow","createError","runError","SnapshotDecodeError","leaseErr","deleteError","storeWithClear","entries","ids","e","concurrency","continueOnError","errors","deleted","run","i","batch"]}
|