{"version":3,"file":"index.mjs","names":[],"sources":["../src/core/workflow.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec'\nimport { ConfigError, DuplicateStepError, ValidationError } from './errors'\nimport type { PersistedValue, RetryConfig } from './types'\n\n/** Context passed to every step handler. */\nexport interface StepContext<\n  TInput extends PersistedValue,\n  TPrev extends PersistedValue,\n  TStepsSoFar extends Record<string, PersistedValue> = Record<string, PersistedValue>,\n> {\n  /** The validated workflow input (same for every step in the run). */\n  input: TInput\n  /** The return value of the previous step (`undefined` for the first step). */\n  prev: TPrev\n  /** Aborted on cancellation, lease loss, or step timeout. */\n  signal: AbortSignal\n  /** Complete the workflow early, skipping remaining steps. Optionally persist a value as the final result. */\n  complete: (value?: PersistedValue) => never\n  /** Results of all previously completed steps, keyed by step name. */\n  steps: TStepsSoFar\n}\n\n/** Internal representation of a step used by the engine. */\nexport interface StepDefinition {\n  name: string\n  handler: (ctx: StepContext<PersistedValue, PersistedValue, Record<string, PersistedValue>>) => Promise<PersistedValue | void>\n  retry?: RetryConfig\n  timeoutMs?: number\n}\n\n/** A single execution unit: either a sequential step or a parallel group. */\nexport type ExecutionUnit =\n  | { readonly kind: 'step'; readonly definition: StepDefinition }\n  | { readonly kind: 'parallel'; readonly branches: readonly StepDefinition[] }\n\n/** Configuration object form for `.step()` when you need retry or timeout options. */\nexport interface StepConfig<\n  TInput extends PersistedValue,\n  TPrev extends PersistedValue,\n  TOutput extends PersistedValue | void,\n  TStepsSoFar extends Record<string, PersistedValue> = Record<string, PersistedValue>,\n> {\n  retry?: RetryConfig\n  /** Timeout per attempt in milliseconds. Takes precedence over `retry.timeoutMs`. */\n  timeoutMs?: number\n  handler: (ctx: StepContext<TInput, TPrev, TStepsSoFar>) => Promise<TOutput>\n}\n\n/** A parallel branch: either a bare handler or a StepConfig with retry/timeout. */\nexport type ParallelBranch<\n  TInput extends PersistedValue,\n  TPrev extends PersistedValue,\n  TOutput extends PersistedValue | void = PersistedValue | void,\n  TStepsSoFar extends Record<string, PersistedValue> = Record<string, PersistedValue>,\n> =\n  | ((ctx: StepContext<TInput, TPrev, TStepsSoFar>) => Promise<TOutput>)\n  | StepConfig<TInput, TPrev, TOutput, TStepsSoFar>\n\n/** Extract the output type from a ParallelBranch. */\nexport type InferBranchOutput<B> =\n  B extends (ctx: never) => Promise<infer O> ? O :\n  B extends { handler: (ctx: never) => Promise<infer O> } ? O :\n  never\n\n/** Context passed to the `onFailure` handler when a workflow run fails. */\nexport interface FailureContext<TInput extends PersistedValue = PersistedValue> {\n  /** The error that caused the failure. */\n  error: Error\n  /** The name of the step that failed. */\n  stepName: string\n  /** The original validated workflow input. */\n  input: TInput\n}\n\n/**\n * A typed workflow definition.\n *\n * @typeParam TName - Literal string name of the workflow (e.g. `'order-fulfillment'`)\n * @typeParam TInput - The validated input schema type\n * @typeParam TPrev - The output type of the most recently added step (used for chaining)\n * @typeParam TSteps - Accumulated map of `{ stepName: outputType }` across `.step()` calls\n */\nexport interface Workflow<\n  TName extends string = string,\n  TInput extends PersistedValue = PersistedValue,\n  TPrev extends PersistedValue = PersistedValue,\n  TSteps extends Record<string, PersistedValue> = Record<string, PersistedValue>,\n> {\n  readonly name: TName\n  readonly inputSchema: StandardSchemaV1<TInput>\n  readonly executionUnits: readonly ExecutionUnit[]\n  readonly failureHandler?: (ctx: FailureContext<TInput>) => Promise<void>\n\n  step<TStepName extends string, TOutput extends PersistedValue | void>(\n    name: TStepName,\n    handler: (ctx: StepContext<TInput, TPrev, TSteps>) => Promise<TOutput>,\n  ): Workflow<TName, TInput, NormalizeOutput<TOutput>, TSteps & Record<TStepName, NormalizeOutput<TOutput>>>\n\n  step<TStepName extends string, TOutput extends PersistedValue | void>(\n    name: TStepName,\n    config: StepConfig<TInput, TPrev, TOutput, TSteps>,\n  ): Workflow<TName, TInput, NormalizeOutput<TOutput>, TSteps & Record<TStepName, NormalizeOutput<TOutput>>>\n\n  parallel<TBranches extends Record<string, ParallelBranch<TInput, TPrev, PersistedValue | void, TSteps>>>(\n    branches: TBranches,\n  ): Workflow<\n    TName,\n    TInput,\n    Prettify<{ [K in keyof TBranches & string]: NormalizeOutput<InferBranchOutput<TBranches[K]>> }>,\n    TSteps & { [K in keyof TBranches & string]: NormalizeOutput<InferBranchOutput<TBranches[K]>> }\n  >\n\n  onFailure(\n    handler: (ctx: FailureContext<TInput>) => Promise<void>,\n  ): Workflow<TName, TInput, TPrev, TSteps>\n\n  parseInput(input: unknown): TInput\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyWorkflow = Workflow<string, any, any, any>\n\n/** Extract the input type from a Workflow */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type InferInput<W> = W extends Workflow<any, infer I, any, any> ? I : never\n\n/** Extract the accumulated steps map from a Workflow */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type InferSteps<W> = W extends Workflow<any, any, any, infer S> ? S : never\n\n/** Map a workflow tuple/array to `{ workflowName: inputType }` */\nexport type WorkflowInputMap<T extends readonly AnyWorkflow[]> = {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  [W in T[number] as W extends Workflow<infer N, any, any, any> ? N : never]: InferInput<W>\n}\n\n/** Map a workflow tuple/array to `{ workflowName: stepsRecord }` */\nexport type WorkflowStepsMap<T extends readonly AnyWorkflow[]> = {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  [W in T[number] as W extends Workflow<infer N, any, any, any> ? N : never]: InferSteps<W>\n}\n\n/** Flatten intersection types for readable IDE tooltips */\ntype Prettify<T> = { [K in keyof T]: T[K] } & {}\ntype NormalizeOutput<T extends PersistedValue | void> = Exclude<T, void> | (void extends T ? undefined : never)\n\nexport type PrettyStepsMap<T extends Record<string, unknown>> = Prettify<T>\n\n/**\n * Create a new workflow definition.\n *\n * @example\n * ```ts\n * const workflow = createWorkflow({\n *   name: 'process-content',\n *   input: z.object({ url: z.string() }),\n * })\n *   .step('scrape', async ({ input }) => { ... })\n *   .step('summarize', async ({ prev }) => { ... })\n * ```\n */\nexport function createWorkflow<TName extends string, TInput extends PersistedValue>(config: {\n  name: TName\n  input: StandardSchemaV1<TInput>\n}): Workflow<TName, TInput, undefined, {}> {\n  return buildWorkflow(config.name, config.input, [])\n}\n\nfunction getAllStepNames(units: readonly ExecutionUnit[]): Set<string> {\n  const names = new Set<string>()\n  for (const unit of units) {\n    if (unit.kind === 'step') {\n      names.add(unit.definition.name)\n    } else {\n      for (const branch of unit.branches) {\n        names.add(branch.name)\n      }\n    }\n  }\n  return names\n}\n\nfunction buildWorkflow<\n  TName extends string,\n  TInput extends PersistedValue,\n  TPrev extends PersistedValue,\n  TSteps extends Record<string, PersistedValue>,\n>(\n  name: TName,\n  inputSchema: StandardSchemaV1<TInput>,\n  executionUnits: ExecutionUnit[],\n  failureHandler?: (ctx: FailureContext<TInput>) => Promise<void>,\n): Workflow<TName, TInput, TPrev, TSteps> {\n  return {\n    name,\n    inputSchema,\n    executionUnits,\n    failureHandler,\n\n    step<TStepName extends string, TOutput extends PersistedValue | void>(\n      stepName: TStepName,\n      handlerOrConfig:\n        | ((ctx: StepContext<TInput, TPrev, TSteps>) => Promise<TOutput>)\n        | StepConfig<TInput, TPrev, TOutput, TSteps>,\n    ): Workflow<\n      TName,\n      TInput,\n      NormalizeOutput<TOutput>,\n      TSteps & Record<TStepName, NormalizeOutput<TOutput>>\n    > {\n      if (getAllStepNames(executionUnits).has(stepName)) {\n        throw new DuplicateStepError(name, stepName)\n      }\n\n      const isConfig = typeof handlerOrConfig === 'object' && 'handler' in handlerOrConfig\n      const handler = isConfig ? handlerOrConfig.handler : handlerOrConfig\n      const retry = isConfig ? handlerOrConfig.retry : undefined\n      const timeoutMs = isConfig ? handlerOrConfig.timeoutMs : undefined\n\n      const newStep: StepDefinition = {\n        name: stepName,\n        handler: handler as unknown as StepDefinition['handler'],\n        retry,\n        timeoutMs,\n      }\n      return buildWorkflow<\n        TName,\n        TInput,\n        NormalizeOutput<TOutput>,\n        TSteps & Record<TStepName, NormalizeOutput<TOutput>>\n      >(\n        name,\n        inputSchema,\n        [...executionUnits, { kind: 'step', definition: newStep }],\n        failureHandler,\n      )\n    },\n\n    parallel<TBranches extends Record<string, ParallelBranch<TInput, TPrev, PersistedValue | void, TSteps>>>(\n      branches: TBranches,\n    ): Workflow<\n      TName,\n      TInput,\n      Prettify<{ [K in keyof TBranches & string]: NormalizeOutput<InferBranchOutput<TBranches[K]>> }>,\n      TSteps & { [K in keyof TBranches & string]: NormalizeOutput<InferBranchOutput<TBranches[K]>> }\n    > {\n      const branchEntries = Object.entries(branches)\n      if (branchEntries.length === 0) {\n        throw new ConfigError('parallel() requires at least one branch')\n      }\n\n      const existingNames = getAllStepNames(executionUnits)\n      for (const [branchName] of branchEntries) {\n        if (existingNames.has(branchName)) {\n          throw new DuplicateStepError(name, branchName)\n        }\n      }\n\n      const branchDefs: StepDefinition[] = branchEntries.map(([branchName, handlerOrConfig]) => {\n        if (typeof handlerOrConfig === 'object' && handlerOrConfig !== null && 'handler' in handlerOrConfig) {\n          return {\n            name: branchName,\n            handler: handlerOrConfig.handler as unknown as StepDefinition['handler'],\n            retry: handlerOrConfig.retry,\n            timeoutMs: handlerOrConfig.timeoutMs,\n          }\n        }\n        return {\n          name: branchName,\n          handler: handlerOrConfig as unknown as StepDefinition['handler'],\n          retry: undefined,\n          timeoutMs: undefined,\n        }\n      })\n\n      return buildWorkflow<\n        TName,\n        TInput,\n        Prettify<{ [K in keyof TBranches & string]: NormalizeOutput<InferBranchOutput<TBranches[K]>> }>,\n        TSteps & { [K in keyof TBranches & string]: NormalizeOutput<InferBranchOutput<TBranches[K]>> }\n      >(\n        name,\n        inputSchema,\n        [...executionUnits, { kind: 'parallel', branches: branchDefs }],\n        failureHandler,\n      )\n    },\n\n    onFailure(\n      handler: (ctx: FailureContext<TInput>) => Promise<void>,\n    ): Workflow<TName, TInput, TPrev, TSteps> {\n      return buildWorkflow(name, inputSchema, executionUnits, handler)\n    },\n\n    parseInput(input: unknown): TInput {\n      const result = inputSchema['~standard'].validate(input)\n      if (result instanceof Promise) {\n        throw new TypeError('Async schema validation is not supported')\n      }\n      if (result.issues) {\n        const messages = result.issues.map((i) => i.message).join(', ')\n        throw new ValidationError(`Input validation failed: ${messages}`, result.issues)\n      }\n      return result.value as TInput\n    },\n  }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiKA,SAAgB,eAAoE,QAGzC;AACzC,QAAO,cAAc,OAAO,MAAM,OAAO,OAAO,EAAE,CAAC;;AAGrD,SAAS,gBAAgB,OAA8C;CACrE,MAAM,wBAAQ,IAAI,KAAa;AAC/B,MAAK,MAAM,QAAQ,MACjB,KAAI,KAAK,SAAS,OAChB,OAAM,IAAI,KAAK,WAAW,KAAK;KAE/B,MAAK,MAAM,UAAU,KAAK,SACxB,OAAM,IAAI,OAAO,KAAK;AAI5B,QAAO;;AAGT,SAAS,cAMP,MACA,aACA,gBACA,gBACwC;AACxC,QAAO;EACL;EACA;EACA;EACA;EAEA,KACE,UACA,iBAQA;AACA,OAAI,gBAAgB,eAAe,CAAC,IAAI,SAAS,CAC/C,OAAM,IAAI,mBAAmB,MAAM,SAAS;GAG9C,MAAM,WAAW,OAAO,oBAAoB,YAAY,aAAa;GAKrE,MAAM,UAA0B;IAC9B,MAAM;IACN,SANc,WAAW,gBAAgB,UAAU;IAOnD,OANY,WAAW,gBAAgB,QAAQ,KAAA;IAO/C,WANgB,WAAW,gBAAgB,YAAY,KAAA;IAOxD;AACD,UAAO,cAML,MACA,aACA,CAAC,GAAG,gBAAgB;IAAE,MAAM;IAAQ,YAAY;IAAS,CAAC,EAC1D,eACD;;EAGH,SACE,UAMA;GACA,MAAM,gBAAgB,OAAO,QAAQ,SAAS;AAC9C,OAAI,cAAc,WAAW,EAC3B,OAAM,IAAI,YAAY,0CAA0C;GAGlE,MAAM,gBAAgB,gBAAgB,eAAe;AACrD,QAAK,MAAM,CAAC,eAAe,cACzB,KAAI,cAAc,IAAI,WAAW,CAC/B,OAAM,IAAI,mBAAmB,MAAM,WAAW;GAIlD,MAAM,aAA+B,cAAc,KAAK,CAAC,YAAY,qBAAqB;AACxF,QAAI,OAAO,oBAAoB,YAAY,oBAAoB,QAAQ,aAAa,gBAClF,QAAO;KACL,MAAM;KACN,SAAS,gBAAgB;KACzB,OAAO,gBAAgB;KACvB,WAAW,gBAAgB;KAC5B;AAEH,WAAO;KACL,MAAM;KACN,SAAS;KACT,OAAO,KAAA;KACP,WAAW,KAAA;KACZ;KACD;AAEF,UAAO,cAML,MACA,aACA,CAAC,GAAG,gBAAgB;IAAE,MAAM;IAAY,UAAU;IAAY,CAAC,EAC/D,eACD;;EAGH,UACE,SACwC;AACxC,UAAO,cAAc,MAAM,aAAa,gBAAgB,QAAQ;;EAGlE,WAAW,OAAwB;GACjC,MAAM,SAAS,YAAY,aAAa,SAAS,MAAM;AACvD,OAAI,kBAAkB,QACpB,OAAM,IAAI,UAAU,2CAA2C;AAEjE,OAAI,OAAO,OAET,OAAM,IAAI,gBAAgB,4BADT,OAAO,OAAO,KAAK,MAAM,EAAE,QAAQ,CAAC,KAAK,KAAK,IACG,OAAO,OAAO;AAElF,UAAO,OAAO;;EAEjB"}