runsheet 0.0.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/LICENSE +21 -0
- package/README.md +370 -0
- package/dist/index.cjs +280 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +600 -0
- package/dist/index.d.ts +600 -0
- package/dist/index.js +249 -0
- package/dist/index.js.map +1 -0
- package/llms.txt +243 -0
- package/package.json +109 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/define-step.ts","../src/errors.ts","../src/middleware.ts","../src/when.ts","../src/pipeline.ts","../src/builder.ts"],"sourcesContent":["export { defineStep } from './define-step.js';\nexport { RunsheetError } from './errors.js';\nexport type { RunsheetErrorCode } from './errors.js';\nexport { buildPipeline } from './pipeline.js';\nexport type { Pipeline, PipelineConfig } from './pipeline.js';\nexport { when } from './when.js';\nexport type { ConditionalStep } from './when.js';\nexport type { StepMiddleware, StepInfo, StepExecutor } from './middleware.js';\nexport { createPipeline } from './builder.js';\nexport type { PipelineBuilder } from './builder.js';\n\nexport type {\n Step,\n TypedStep,\n StepConfig,\n StepContext,\n StepOutput,\n PipelineResult,\n PipelineSuccess,\n PipelineFailure,\n PipelineExecutionMeta,\n RollbackReport,\n RollbackFailure,\n} from './types.js';\n\n// Re-export Result types so consumers never need to import composable-functions\nexport type { Result, Success, Failure } from 'composable-functions';\n","import { composable } from 'composable-functions';\nimport type { StepConfig, StepContext, Step, TypedStep } from './types.js';\n\n/**\n * Define a pipeline step.\n *\n * Returns a frozen {@link TypedStep} with concrete types for `run`,\n * `rollback`, `requires`, and `provides`. The `run` function can be\n * sync or async — both are supported.\n *\n * **With schemas** (runtime validation + type inference):\n * ```ts\n * const charge = defineStep({\n * name: 'charge',\n * requires: z.object({ amount: z.number() }),\n * provides: z.object({ chargeId: z.string() }),\n * run: async (ctx) => ({ chargeId: 'ch_123' }),\n * });\n * ```\n *\n * **With generics only** (no runtime validation):\n * ```ts\n * const log = defineStep<{ order: Order }, { loggedAt: Date }>({\n * name: 'log',\n * run: async (ctx) => ({ loggedAt: new Date() }),\n * });\n * ```\n *\n * **Invariants:**\n * - The returned step object is always frozen (immutable).\n * - The `run` function is wrapped with `composable()` from\n * composable-functions, which catches thrown errors and produces\n * `Result` values. Step authors should throw to signal failure.\n * - This is the single type-erasure cast point in the library.\n *\n * @typeParam Requires - The context shape this step reads from.\n * @typeParam Provides - The output shape this step produces.\n * @param config - The step configuration. See {@link StepConfig}.\n * @returns A frozen {@link TypedStep} ready for use in pipelines.\n */\nexport function defineStep<Requires extends StepContext, Provides extends StepContext>(\n config: StepConfig<Requires, Provides>,\n): TypedStep<Requires, Provides> {\n const wrappedRun = composable(config.run);\n\n // The cast below is the single point where typed step functions are erased\n // to the runtime Step representation. This is safe because:\n // 1. Schema validation at step boundaries (requires/provides) enforces\n // correct types at runtime before and after each step executes.\n // 2. The pipeline accumulates context immutably, so the runtime object\n // structurally matches what the typed function expects.\n // 3. The phantom brands on TypedStep preserve compile-time type tracking\n // through the builder API without affecting runtime behavior.\n return Object.freeze({\n name: config.name,\n requires: config.requires ?? undefined,\n provides: config.provides ?? undefined,\n run: wrappedRun as unknown as Step['run'],\n rollback: config.rollback\n ? async (ctx: Readonly<StepContext>, output: Readonly<StepContext>) => {\n await (config.rollback as NonNullable<typeof config.rollback>)(\n ctx as Readonly<Requires>,\n output as Readonly<Provides>,\n );\n }\n : undefined,\n }) as TypedStep<Requires, Provides>;\n}\n","/**\n * Error codes for errors produced by the runsheet library itself.\n *\n * Use these to distinguish library errors from application errors\n * in a pipeline's `errors` array:\n *\n * ```ts\n * if (!result.success) {\n * for (const error of result.errors) {\n * if (error instanceof RunsheetError) {\n * console.log(error.code); // 'REQUIRES_VALIDATION', etc.\n * }\n * }\n * }\n * ```\n */\nexport type RunsheetErrorCode =\n | 'REQUIRES_VALIDATION'\n | 'PROVIDES_VALIDATION'\n | 'ARGS_VALIDATION'\n | 'PREDICATE';\n\n/**\n * Base error class for all errors produced by the runsheet library.\n *\n * Application errors (thrown by step `run` or `rollback` functions)\n * are never wrapped in `RunsheetError` — they pass through as-is.\n * If you see a `RunsheetError` in a result's `errors` array, the\n * library itself produced it.\n *\n * Use `instanceof RunsheetError` to distinguish library errors from\n * application errors, and the `code` property to identify the\n * specific failure.\n */\nexport class RunsheetError extends Error {\n /** Discriminant code identifying the type of library error. */\n readonly code: RunsheetErrorCode;\n\n /**\n * @param code - The error code.\n * @param message - A human-readable description of the failure.\n */\n constructor(code: RunsheetErrorCode, message: string) {\n super(message);\n this.name = 'RunsheetError';\n this.code = code;\n }\n}\n","import type { Result } from 'composable-functions';\nimport type { Step, StepContext, StepOutput } from './types.js';\n\n/**\n * Metadata about the step being executed, passed to middleware.\n *\n * This is a read-only view of the step's public configuration.\n * Middleware can use it for logging, metrics, or conditional behavior.\n */\nexport type StepInfo = {\n /** The step's name. */\n readonly name: string;\n /** The step's requires schema, or `undefined` if not provided. */\n readonly requires: Step['requires'];\n /** The step's provides schema, or `undefined` if not provided. */\n readonly provides: Step['provides'];\n};\n\n/**\n * A function that executes a step (or the next middleware in the chain).\n *\n * Receives the frozen accumulated context and returns a `Result` — either\n * `{ success: true, data }` or `{ success: false, errors }`.\n */\nexport type StepExecutor = (ctx: Readonly<StepContext>) => Promise<Result<StepOutput>>;\n\n/**\n * Middleware that wraps the entire step lifecycle, including schema\n * validation.\n *\n * A middleware receives the step metadata and a `next` function, and\n * returns a new executor. Call `next(ctx)` to proceed to the next\n * middleware (or the actual step execution). You can:\n *\n * - **Observe**: read the context or result for logging/metrics.\n * - **Transform**: modify the result before returning it.\n * - **Short-circuit**: return a `Result` without calling `next`.\n *\n * If a middleware throws, the pipeline catches it and treats it as a\n * step failure (triggering rollback for previously completed steps).\n *\n * @example\n * ```ts\n * const timing: StepMiddleware = (step, next) => async (ctx) => {\n * const start = performance.now();\n * const result = await next(ctx);\n * console.log(`${step.name}: ${performance.now() - start}ms`);\n * return result;\n * };\n * ```\n *\n * @param step - Metadata about the step being wrapped.\n * @param next - The next executor in the chain. Call it to continue.\n * @returns A new executor that wraps `next`.\n */\nexport type StepMiddleware = (step: StepInfo, next: StepExecutor) => StepExecutor;\n\n/**\n * Compose an array of middlewares around a step executor.\n *\n * First middleware in the array is the outermost wrapper (executes\n * first on the way in, last on the way out).\n *\n * @param middlewares - Middleware functions, in declaration order.\n * @param step - Metadata about the step being wrapped.\n * @param executor - The base step executor to wrap.\n * @returns A composed executor with all middleware applied.\n */\nexport function applyMiddleware(\n middlewares: readonly StepMiddleware[],\n step: StepInfo,\n executor: StepExecutor,\n): StepExecutor {\n return middlewares.reduceRight<StepExecutor>((next, mw) => mw(step, next), executor);\n}\n","import type { Step, StepContext, TypedStep } from './types.js';\n\n/**\n * A step with a conditional predicate attached.\n *\n * The pipeline engine checks for the `predicate` property to decide\n * whether to execute or skip the step. Use the {@link when} function\n * to create conditional steps — don't construct this type directly.\n */\nexport type ConditionalStep = Step & {\n /** Returns `true` to execute the step, `false` to skip it. */\n readonly predicate: (ctx: Readonly<StepContext>) => boolean;\n};\n\n/**\n * Wrap a step with a guard predicate.\n *\n * The step only executes when the predicate returns `true`. When\n * skipped:\n * - No context snapshot is taken.\n * - No rollback entry is created.\n * - The step name is recorded in `result.meta.stepsSkipped`.\n *\n * If the predicate throws, the pipeline treats it as a step failure\n * and triggers rollback for any previously completed steps.\n *\n * @example\n * ```ts\n * const steps = [\n * validateOrder,\n * when((ctx) => ctx.order.amount > 100, notifyManager),\n * sendConfirmation,\n * ];\n * ```\n *\n * @typeParam Requires - Inferred from the step's requires type.\n * @typeParam Provides - Inferred from the step's provides type.\n * @param predicate - Guard function. Receives the current accumulated\n * context (frozen). Return `true` to execute, `false` to skip.\n * @param step - The step to conditionally execute.\n * @returns A frozen {@link TypedStep} with the predicate attached.\n */\nexport function when<Requires extends StepContext, Provides extends StepContext>(\n predicate: (ctx: Readonly<Requires>) => boolean,\n step: TypedStep<Requires, Provides>,\n): TypedStep<Requires, Provides> {\n return Object.freeze({\n ...step,\n predicate: predicate as ConditionalStep['predicate'],\n }) as TypedStep<Requires, Provides>;\n}\n\n/** Type guard for conditional steps. */\nexport function isConditionalStep(step: Step): step is ConditionalStep {\n return 'predicate' in step && typeof (step as StepContext)['predicate'] === 'function';\n}\n","import type { ParserSchema, Result } from 'composable-functions';\nimport type {\n ExtractProvides,\n PipelineFailure,\n PipelineResult,\n PipelineSuccess,\n RollbackFailure,\n RollbackReport,\n Step,\n StepContext,\n StepOutput,\n UnionToIntersection,\n} from './types.js';\nimport type { StepMiddleware } from './middleware.js';\nimport type { RunsheetErrorCode } from './errors.js';\nimport { RunsheetError } from './errors.js';\nimport { applyMiddleware } from './middleware.js';\nimport { isConditionalStep } from './when.js';\n\n// ---------------------------------------------------------------------------\n// Pipeline configuration\n// ---------------------------------------------------------------------------\n\n/**\n * Internal configuration shape for the pipeline engine.\n *\n * Users typically don't construct this directly — use `buildPipeline()`\n * or `createPipeline()` instead.\n */\nexport type PipelineConfig = {\n /** Pipeline name, used in execution metadata and error messages. */\n readonly name: string;\n /** Steps to execute in order. */\n readonly steps: readonly Step[];\n /** Optional middleware applied to every step. First in array = outermost. */\n readonly middleware?: readonly StepMiddleware[];\n /** Optional schema that validates the pipeline's input arguments. */\n readonly argsSchema?: ParserSchema<StepContext>;\n};\n\n// ---------------------------------------------------------------------------\n// Pipeline\n// ---------------------------------------------------------------------------\n\n/**\n * A built pipeline, ready to execute.\n *\n * Call `run(args)` to execute the pipeline. The result is a\n * {@link PipelineResult} — either a success with the fully accumulated\n * context, or a failure with error details and a rollback report.\n *\n * Pipeline objects are frozen (immutable) and can be called repeatedly.\n *\n * @typeParam Args - The input type accepted by `run()`.\n * @typeParam Ctx - The accumulated output type on success.\n */\nexport type Pipeline<Args extends StepContext, Ctx> = {\n /** The pipeline's name, as provided at build time. */\n readonly name: string;\n /**\n * Execute the pipeline.\n *\n * @param args - The initial arguments. Merged into the context before\n * the first step runs. Validated against `argsSchema` if one was\n * provided.\n * @returns A {@link PipelineResult} — discriminate on `success` to\n * access `data` (on success) or `errors`/`rollback` (on failure).\n */\n readonly run: (args: Args) => Promise<PipelineResult<Ctx>>;\n};\n\n// ---------------------------------------------------------------------------\n// Schema validation\n// ---------------------------------------------------------------------------\n\nfunction validateSchema<T>(\n schema: ParserSchema<T> | undefined,\n data: unknown,\n label: string,\n code: RunsheetErrorCode,\n): { success: true; data: T } | { success: false; errors: RunsheetError[] } {\n if (!schema) return { success: true, data: data as T };\n\n const parsed = schema.safeParse(data);\n if (parsed.success) return { success: true, data: parsed.data };\n\n const errors = parsed.error.issues.map(\n (issue) => new RunsheetError(code, `${label}: ${issue.path.join('.')}: ${issue.message}`),\n );\n return { success: false, errors };\n}\n\n// ---------------------------------------------------------------------------\n// Rollback\n// ---------------------------------------------------------------------------\n\nasync function executeRollback(\n executedSteps: readonly Step[],\n snapshots: readonly StepContext[],\n outputs: readonly StepOutput[],\n): Promise<RollbackReport> {\n const completed: string[] = [];\n const failed: RollbackFailure[] = [];\n\n for (let i = executedSteps.length - 1; i >= 0; i--) {\n const step = executedSteps[i];\n if (!step.rollback) continue;\n\n try {\n await step.rollback(snapshots[i], outputs[i]);\n completed.push(step.name);\n } catch (err) {\n failed.push({\n step: step.name,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }\n\n return Object.freeze({ completed, failed });\n}\n\n// ---------------------------------------------------------------------------\n// Execution state — accumulated during pipeline run\n// ---------------------------------------------------------------------------\n\ntype ExecutionState = {\n context: StepContext;\n readonly snapshots: StepContext[];\n readonly outputs: StepOutput[];\n readonly executedSteps: Step[];\n readonly stepsExecuted: string[];\n readonly stepsSkipped: string[];\n};\n\nfunction createExecutionState(args: StepContext): ExecutionState {\n return {\n context: Object.freeze({ ...args }),\n snapshots: [],\n outputs: [],\n executedSteps: [],\n stepsExecuted: [],\n stepsSkipped: [],\n };\n}\n\n// ---------------------------------------------------------------------------\n// Result constructors\n// ---------------------------------------------------------------------------\n\nfunction pipelineFailure(\n pipelineName: string,\n args: StepContext,\n state: ExecutionState,\n failedStep: string,\n errors: Error[],\n rollback: RollbackReport,\n): PipelineFailure {\n return Object.freeze({\n success: false as const,\n errors,\n meta: Object.freeze({\n pipeline: pipelineName,\n args,\n stepsExecuted: state.stepsExecuted,\n stepsSkipped: state.stepsSkipped,\n }),\n failedStep,\n rollback,\n });\n}\n\nfunction pipelineSuccess(\n pipelineName: string,\n args: StepContext,\n state: ExecutionState,\n): PipelineSuccess<StepContext> {\n return Object.freeze({\n success: true as const,\n data: state.context,\n errors: [] as [],\n meta: Object.freeze({\n pipeline: pipelineName,\n args,\n stepsExecuted: state.stepsExecuted,\n stepsSkipped: state.stepsSkipped,\n }),\n });\n}\n\n// ---------------------------------------------------------------------------\n// Step executor — the full lifecycle (validate requires → run → validate provides)\n// ---------------------------------------------------------------------------\n\nfunction createStepExecutor(\n step: Step,\n): (ctx: Readonly<StepContext>) => Promise<Result<StepOutput>> {\n return async (ctx) => {\n // Validate requires\n const requiresCheck = validateSchema(\n step.requires,\n ctx,\n `${step.name} requires`,\n 'REQUIRES_VALIDATION',\n );\n if (!requiresCheck.success) {\n return { success: false as const, errors: requiresCheck.errors };\n }\n\n // Execute step run\n const result = await step.run(ctx);\n if (!result.success) return result;\n\n // Validate provides\n const providesCheck = validateSchema(\n step.provides,\n result.data,\n `${step.name} provides`,\n 'PROVIDES_VALIDATION',\n );\n if (!providesCheck.success) {\n return { success: false as const, errors: providesCheck.errors };\n }\n\n return {\n success: true as const,\n data: providesCheck.data as StepOutput,\n errors: [] as [],\n };\n };\n}\n\n// ---------------------------------------------------------------------------\n// Pipeline execution\n// ---------------------------------------------------------------------------\n\nasync function executePipeline(\n config: PipelineConfig,\n args: StepContext,\n): Promise<PipelineResult<StepContext>> {\n // Validate pipeline args if schema provided\n if (config.argsSchema) {\n const argsCheck = validateSchema(\n config.argsSchema,\n args,\n `${config.name} args`,\n 'ARGS_VALIDATION',\n );\n if (!argsCheck.success) {\n const state = createExecutionState(args);\n return pipelineFailure(\n config.name,\n args,\n state,\n config.name,\n argsCheck.errors,\n Object.freeze({ completed: [], failed: [] }),\n );\n }\n }\n\n const state = createExecutionState(args);\n const middlewares = config.middleware ?? [];\n\n for (const step of config.steps) {\n // Evaluate conditional predicate\n try {\n if (isConditionalStep(step) && !step.predicate(state.context)) {\n state.stepsSkipped.push(step.name);\n continue;\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const error = new RunsheetError('PREDICATE', `${step.name} predicate: ${message}`);\n if (err instanceof Error) error.cause = err;\n const rollback = await executeRollback(state.executedSteps, state.snapshots, state.outputs);\n return pipelineFailure(config.name, args, state, step.name, [error], rollback);\n }\n\n // Snapshot pre-step context\n state.snapshots.push(state.context);\n\n // Build executor with middleware wrapping the full lifecycle\n const baseExecutor = createStepExecutor(step);\n const executor = applyMiddleware(\n middlewares,\n { name: step.name, requires: step.requires, provides: step.provides },\n baseExecutor,\n );\n\n // Execute (try/catch handles middleware throws outside the Result boundary)\n let result: Result<StepOutput>;\n try {\n result = await executor(state.context);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n state.snapshots.pop();\n const rollback = await executeRollback(state.executedSteps, state.snapshots, state.outputs);\n return pipelineFailure(config.name, args, state, step.name, [error], rollback);\n }\n\n if (!result.success) {\n // Remove the snapshot we just pushed — the step didn't complete\n state.snapshots.pop();\n const rollback = await executeRollback(state.executedSteps, state.snapshots, state.outputs);\n return pipelineFailure(config.name, args, state, step.name, result.errors, rollback);\n }\n\n // Track step output and accumulate context\n const output = result.data;\n state.outputs.push(output);\n state.executedSteps.push(step);\n state.stepsExecuted.push(step.name);\n state.context = Object.freeze({ ...state.context, ...output });\n }\n\n return pipelineSuccess(config.name, args, state);\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Build a pipeline from an array of steps.\n *\n * The result type is inferred from the steps — `pipeline.run()` returns\n * a {@link PipelineResult} whose `data` is the intersection of the\n * initial `Args` and all step output types.\n *\n * @example\n * ```ts\n * const pipeline = buildPipeline({\n * name: 'placeOrder',\n * steps: [validateOrder, chargePayment, sendConfirmation],\n * middleware: [logging, timing],\n * argsSchema: z.object({ orderId: z.string() }),\n * });\n *\n * const result = await pipeline.run({ orderId: '123' });\n * if (result.success) {\n * result.data.chargeId; // string — fully typed\n * }\n * ```\n *\n * **Execution semantics:**\n * - Steps execute sequentially in array order.\n * - Context is frozen (`Object.freeze`) at every step boundary.\n * - Conditional steps (wrapped with `when()`) are skipped when their\n * predicate returns false — no snapshot, no rollback entry.\n * - On step failure, rollback handlers for all previously completed\n * steps execute in reverse order (best-effort).\n * - Middleware wraps the full step lifecycle including schema validation.\n *\n * **Invariants:**\n * - The returned pipeline object is frozen (immutable).\n * - Errors thrown by steps, predicates, or middleware are caught and\n * returned as `PipelineFailure` — `run()` never throws.\n *\n * @typeParam Args - The pipeline's input type. Inferred from `argsSchema`\n * if provided, otherwise defaults to `StepContext`.\n * @typeParam S - The step types in the array. Inferred automatically —\n * do not specify manually.\n * @param config - Pipeline configuration.\n * @param config.name - Pipeline name, used in metadata and error messages.\n * @param config.steps - Steps to execute in order.\n * @param config.middleware - Optional middleware applied to every step.\n * First in array = outermost wrapper.\n * @param config.argsSchema - Optional schema that validates `args` before\n * any steps run. Validation failure produces a `PipelineFailure` with\n * `failedStep` set to the pipeline name.\n * @returns A frozen {@link Pipeline} whose `run()` method executes the\n * steps and returns a {@link PipelineResult}.\n */\nexport function buildPipeline<\n Args extends StepContext = StepContext,\n S extends Step = Step,\n>(config: {\n readonly name: string;\n readonly steps: readonly S[];\n readonly middleware?: readonly StepMiddleware[];\n readonly argsSchema?: ParserSchema<Args>;\n}): Pipeline<Args, Args & UnionToIntersection<ExtractProvides<S>>> {\n return Object.freeze({\n name: config.name,\n run: (args: Args) => executePipeline(config as PipelineConfig, args),\n }) as Pipeline<Args, Args & UnionToIntersection<ExtractProvides<S>>>;\n}\n","import type { ParserSchema } from 'composable-functions';\nimport type { Step, StepContext, TypedStep } from './types.js';\nimport type { StepMiddleware } from './middleware.js';\nimport { buildPipeline } from './pipeline.js';\nimport type { Pipeline } from './pipeline.js';\n\n// ---------------------------------------------------------------------------\n// Builder types\n// ---------------------------------------------------------------------------\n\n/**\n * A fluent pipeline builder that progressively narrows the accumulated\n * context type as steps are added.\n *\n * Each method returns a new, frozen builder — builders are immutable.\n * This means you can safely fork a builder to create variants:\n *\n * ```ts\n * const base = createPipeline('order').step(validate);\n * const withCharge = base.step(charge).build();\n * const withoutCharge = base.build(); // unaffected by the fork\n * ```\n *\n * @typeParam Args - The pipeline's initial input type.\n * @typeParam Ctx - The accumulated context type so far (grows with each `.step()`).\n */\nexport type PipelineBuilder<Args extends StepContext, Ctx extends StepContext> = {\n /**\n * Add a step to the pipeline.\n *\n * The step's `Requires` type must be satisfied by the current `Ctx`.\n * The returned builder's `Ctx` expands to include the step's `Provides`.\n *\n * @typeParam Provides - The output type of the step being added.\n * @param step - A {@link TypedStep} (from `defineStep` or `when`).\n * @returns A new builder with the expanded context type.\n */\n readonly step: <Provides extends StepContext>(\n step: TypedStep<Ctx, Provides>,\n ) => PipelineBuilder<Args, Ctx & Provides>;\n\n /**\n * Add middleware to the pipeline.\n *\n * Middleware is applied to every step. Multiple `.use()` calls\n * accumulate — earlier middleware is outermost (executes first).\n *\n * @param middleware - One or more {@link StepMiddleware} functions.\n * @returns A new builder with the middleware added.\n */\n readonly use: (...middleware: StepMiddleware[]) => PipelineBuilder<Args, Ctx>;\n\n /**\n * Build the pipeline.\n *\n * @returns A frozen {@link Pipeline} ready to execute with `run()`.\n */\n readonly build: () => Pipeline<Args, Ctx>;\n};\n\n// ---------------------------------------------------------------------------\n// Internal builder state (immutable — each method returns a new builder)\n// ---------------------------------------------------------------------------\n\ntype BuilderState = {\n readonly name: string;\n readonly steps: readonly Step[];\n readonly middleware: readonly StepMiddleware[];\n readonly argsSchema: ParserSchema<StepContext> | undefined;\n};\n\nfunction makeBuilder<Args extends StepContext, Ctx extends StepContext>(\n state: BuilderState,\n): PipelineBuilder<Args, Ctx> {\n return Object.freeze({\n step: <Provides extends StepContext>(step: TypedStep<Ctx, Provides>) =>\n makeBuilder<Args, Ctx & Provides>({\n ...state,\n steps: [...state.steps, step],\n }),\n\n use: (...middleware: StepMiddleware[]) =>\n makeBuilder<Args, Ctx>({\n ...state,\n middleware: [...state.middleware, ...middleware],\n }),\n\n build: () =>\n buildPipeline({\n name: state.name,\n steps: state.steps,\n middleware: state.middleware.length > 0 ? state.middleware : undefined,\n argsSchema: state.argsSchema as ParserSchema<Args> | undefined,\n }) as Pipeline<Args, Ctx>,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Start building a pipeline with the fluent builder API.\n *\n * The builder gives progressive type narrowing — each `.step()` call\n * extends the known context type, so TypeScript catches mismatches\n * at compile time.\n *\n * **Type-only args** (no runtime validation):\n * ```ts\n * createPipeline<{ orderId: string }>('placeOrder')\n * .step(validateOrder)\n * .step(chargePayment)\n * .build();\n * ```\n *\n * **Schema args** (runtime validation + type inference):\n * ```ts\n * createPipeline('placeOrder', z.object({ orderId: z.string() }))\n * .step(validateOrder)\n * .step(chargePayment)\n * .build();\n * ```\n *\n * @typeParam Args - The pipeline's input type. Inferred from `argsSchema`\n * if provided, otherwise specify via generic parameter.\n * @param name - Pipeline name, used in metadata and error messages.\n * @param argsSchema - Optional schema that validates pipeline input\n * at runtime. When provided, `Args` is inferred from the schema.\n * @returns A frozen {@link PipelineBuilder} ready for `.step()`,\n * `.use()`, and `.build()`.\n */\nexport function createPipeline<Args extends StepContext>(\n name: string,\n argsSchema?: ParserSchema<Args>,\n): PipelineBuilder<Args, Args> {\n return makeBuilder<Args, Args>({\n name,\n steps: [],\n middleware: [],\n argsSchema,\n });\n}\n"],"mappings":"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","names":["state"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
import { ParserSchema, Result, Success, Failure } from 'composable-functions';
|
|
2
|
+
export { Failure, Result, Success } from 'composable-functions';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The type-erased context shape used at runtime by the pipeline engine.
|
|
6
|
+
*
|
|
7
|
+
* This is the base type for all step inputs. Concrete step types narrow
|
|
8
|
+
* this via their `Requires`/`Provides` type parameters, but the pipeline
|
|
9
|
+
* engine operates on `StepContext` internally since it handles
|
|
10
|
+
* heterogeneous step arrays.
|
|
11
|
+
*/
|
|
12
|
+
type StepContext = Record<string, unknown>;
|
|
13
|
+
/**
|
|
14
|
+
* The type-erased output shape produced by a step at runtime.
|
|
15
|
+
*
|
|
16
|
+
* Structurally identical to {@link StepContext}, but semantically distinct:
|
|
17
|
+
* context is what flows *in*, output is what a step *produces*. This
|
|
18
|
+
* separation makes the pipeline code easier to follow.
|
|
19
|
+
*/
|
|
20
|
+
type StepOutput = Record<string, unknown>;
|
|
21
|
+
/**
|
|
22
|
+
* Runtime step representation used by the pipeline engine.
|
|
23
|
+
*
|
|
24
|
+
* This type is non-generic — the pipeline engine operates on these without
|
|
25
|
+
* needing to know individual step type parameters. Schema validation at
|
|
26
|
+
* step boundaries ensures type correctness at runtime.
|
|
27
|
+
*
|
|
28
|
+
* All step objects are frozen (immutable). Use {@link TypedStep} when you
|
|
29
|
+
* need compile-time type information for a specific step.
|
|
30
|
+
*
|
|
31
|
+
* @see {@link TypedStep} for the compile-time typed variant
|
|
32
|
+
*/
|
|
33
|
+
type Step = {
|
|
34
|
+
/** Unique name identifying this step in metadata and rollback reports. */
|
|
35
|
+
readonly name: string;
|
|
36
|
+
/** Optional schema that validates the accumulated context before `run`. */
|
|
37
|
+
readonly requires: ParserSchema<StepContext> | undefined;
|
|
38
|
+
/** Optional schema that validates the step's output after `run`. */
|
|
39
|
+
readonly provides: ParserSchema<StepOutput> | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Execute the step. Receives the accumulated context and returns a
|
|
42
|
+
* `Result` — either `{ success: true, data }` or
|
|
43
|
+
* `{ success: false, errors }`.
|
|
44
|
+
*
|
|
45
|
+
* Step authors never call this directly; the pipeline engine calls it
|
|
46
|
+
* after validating `requires` and wrapping with middleware.
|
|
47
|
+
*/
|
|
48
|
+
readonly run: (ctx: Readonly<StepContext>) => Promise<Result<StepOutput>>;
|
|
49
|
+
/**
|
|
50
|
+
* Optional rollback handler, called when a later step fails.
|
|
51
|
+
*
|
|
52
|
+
* @param ctx - The frozen context snapshot from *before* this step ran.
|
|
53
|
+
* @param output - The frozen output this step produced.
|
|
54
|
+
*/
|
|
55
|
+
readonly rollback: ((ctx: Readonly<StepContext>, output: Readonly<StepOutput>) => Promise<void>) | undefined;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Phantom type brands for compile-time tracking of step I/O types.
|
|
59
|
+
* These symbols never exist at runtime — they only guide TypeScript's
|
|
60
|
+
* type checker through the builder's progressive type narrowing.
|
|
61
|
+
*/
|
|
62
|
+
declare const RequiresBrand: unique symbol;
|
|
63
|
+
declare const ProvidesBrand: unique symbol;
|
|
64
|
+
/**
|
|
65
|
+
* A step with compile-time type information.
|
|
66
|
+
*
|
|
67
|
+
* Extends the runtime {@link Step} with phantom brands and concrete typed
|
|
68
|
+
* signatures. This is the type returned by `defineStep()`.
|
|
69
|
+
*
|
|
70
|
+
* When held as a `TypedStep<R, P>`, the `run`, `rollback`, `requires`,
|
|
71
|
+
* and `provides` properties all carry concrete types matching the step's
|
|
72
|
+
* schemas or generics. When assigned to `Step` (e.g., in a pipeline's
|
|
73
|
+
* step array), the intersection collapses to the erased signatures.
|
|
74
|
+
*
|
|
75
|
+
* @typeParam Requires - The context shape this step reads from.
|
|
76
|
+
* @typeParam Provides - The output shape this step produces.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* // Hover over `step.run` to see:
|
|
81
|
+
* // (ctx: Readonly<{ amount: number }>) => Promise<Result<{ chargeId: string }>>
|
|
82
|
+
* const step = defineStep({
|
|
83
|
+
* name: 'charge',
|
|
84
|
+
* requires: z.object({ amount: z.number() }),
|
|
85
|
+
* provides: z.object({ chargeId: z.string() }),
|
|
86
|
+
* run: async (ctx) => ({ chargeId: `ch_${ctx.amount}` }),
|
|
87
|
+
* });
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
type TypedStep<Requires extends StepContext = StepContext, Provides extends StepContext = StepContext> = Step & {
|
|
91
|
+
readonly [RequiresBrand]: Requires;
|
|
92
|
+
readonly [ProvidesBrand]: Provides;
|
|
93
|
+
/** Optional schema that validates the accumulated context before `run`. */
|
|
94
|
+
readonly requires: ParserSchema<Requires> | undefined;
|
|
95
|
+
/** Optional schema that validates the step's output after `run`. */
|
|
96
|
+
readonly provides: ParserSchema<Provides> | undefined;
|
|
97
|
+
/** Execute the step with concrete input/output types. */
|
|
98
|
+
readonly run: (ctx: Readonly<Requires>) => Promise<Result<Provides>>;
|
|
99
|
+
/**
|
|
100
|
+
* Optional rollback handler, called when a later step fails.
|
|
101
|
+
*
|
|
102
|
+
* @param ctx - The frozen context snapshot from *before* this step ran.
|
|
103
|
+
* @param output - The frozen output this step produced.
|
|
104
|
+
*/
|
|
105
|
+
readonly rollback: ((ctx: Readonly<Requires>, output: Readonly<Provides>) => Promise<void>) | undefined;
|
|
106
|
+
};
|
|
107
|
+
/** Convert a union type to an intersection type. */
|
|
108
|
+
type UnionToIntersection<U> = [U] extends [never] ? unknown : (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
|
|
109
|
+
/** Extract the Provides type from a step. Returns `object` for untyped (erased) steps. */
|
|
110
|
+
type ExtractProvides<T extends Step> = T extends TypedStep<StepContext, infer P> ? P : object;
|
|
111
|
+
/**
|
|
112
|
+
* Configuration object passed to `defineStep()`.
|
|
113
|
+
*
|
|
114
|
+
* Schemas are optional — omit them for generics-only steps that rely on
|
|
115
|
+
* compile-time type safety without runtime validation.
|
|
116
|
+
*
|
|
117
|
+
* @typeParam Requires - The context shape this step reads from.
|
|
118
|
+
* @typeParam Provides - The output shape this step produces.
|
|
119
|
+
*/
|
|
120
|
+
type StepConfig<Requires extends StepContext, Provides extends StepContext> = {
|
|
121
|
+
/** Unique name identifying this step in metadata and rollback reports. */
|
|
122
|
+
name: string;
|
|
123
|
+
/**
|
|
124
|
+
* Optional Zod (or Standard Schema compatible) schema that validates
|
|
125
|
+
* the accumulated context before `run` is called. When provided, a
|
|
126
|
+
* schema validation failure produces a `Result` error — the step's
|
|
127
|
+
* `run` function is never invoked.
|
|
128
|
+
*/
|
|
129
|
+
requires?: ParserSchema<Requires>;
|
|
130
|
+
/**
|
|
131
|
+
* Optional Zod (or Standard Schema compatible) schema that validates
|
|
132
|
+
* the step's output after `run` returns. When provided, a schema
|
|
133
|
+
* validation failure produces a `Result` error even though `run`
|
|
134
|
+
* succeeded.
|
|
135
|
+
*/
|
|
136
|
+
provides?: ParserSchema<Provides>;
|
|
137
|
+
/**
|
|
138
|
+
* The step implementation. Receives the accumulated context (frozen)
|
|
139
|
+
* and returns the step's output. Can be sync or async.
|
|
140
|
+
*
|
|
141
|
+
* To signal failure, throw an error. The pipeline catches it and
|
|
142
|
+
* produces a `Result` failure — do not return failure objects.
|
|
143
|
+
*
|
|
144
|
+
* @param ctx - The frozen accumulated context up to this point.
|
|
145
|
+
* @returns The step's output, which is merged into the accumulated context.
|
|
146
|
+
*/
|
|
147
|
+
run: (ctx: Readonly<Requires>) => Provides | Promise<Provides>;
|
|
148
|
+
/**
|
|
149
|
+
* Optional rollback handler, called when a *later* step fails.
|
|
150
|
+
* Receives the pre-step context snapshot and this step's output.
|
|
151
|
+
* Can be sync or async.
|
|
152
|
+
*
|
|
153
|
+
* Rollback is best-effort: if this handler throws, remaining
|
|
154
|
+
* rollbacks still execute. The error is captured in the
|
|
155
|
+
* {@link RollbackReport}.
|
|
156
|
+
*
|
|
157
|
+
* @param ctx - The frozen context snapshot from *before* this step ran.
|
|
158
|
+
* @param output - The frozen output this step produced.
|
|
159
|
+
*/
|
|
160
|
+
rollback?: (ctx: Readonly<Requires>, output: Readonly<Provides>) => void | Promise<void>;
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Record of a single rollback handler that threw during rollback execution.
|
|
164
|
+
*
|
|
165
|
+
* Non-Error exceptions (e.g., thrown strings) are wrapped in an `Error`.
|
|
166
|
+
*/
|
|
167
|
+
type RollbackFailure = {
|
|
168
|
+
/** Name of the step whose rollback handler failed. */
|
|
169
|
+
readonly step: string;
|
|
170
|
+
/** The error thrown by the rollback handler. */
|
|
171
|
+
readonly error: Error;
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* Summary of rollback execution after a pipeline failure.
|
|
175
|
+
*
|
|
176
|
+
* Rollback is best-effort: every completed step's rollback handler is
|
|
177
|
+
* attempted in reverse order, regardless of whether earlier handlers
|
|
178
|
+
* threw. This report tells you exactly what succeeded and what didn't.
|
|
179
|
+
*/
|
|
180
|
+
type RollbackReport = {
|
|
181
|
+
/** Step names whose rollback handlers completed successfully, in execution order. */
|
|
182
|
+
readonly completed: readonly string[];
|
|
183
|
+
/** Steps whose rollback handlers threw, with the captured errors. */
|
|
184
|
+
readonly failed: readonly RollbackFailure[];
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Metadata about a pipeline execution, present on both success and failure
|
|
188
|
+
* results. Useful for logging, debugging, and observability.
|
|
189
|
+
*/
|
|
190
|
+
type PipelineExecutionMeta = {
|
|
191
|
+
/** The pipeline's name as passed to `buildPipeline` or `createPipeline`. */
|
|
192
|
+
readonly pipeline: string;
|
|
193
|
+
/** The original arguments passed to `pipeline.run()`. */
|
|
194
|
+
readonly args: Readonly<StepContext>;
|
|
195
|
+
/** Names of steps that executed successfully, in order. */
|
|
196
|
+
readonly stepsExecuted: readonly string[];
|
|
197
|
+
/** Names of conditional steps that were skipped (predicate returned false). */
|
|
198
|
+
readonly stepsSkipped: readonly string[];
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* A successful pipeline result.
|
|
202
|
+
*
|
|
203
|
+
* Extends composable-functions' `Success<T>` with pipeline execution
|
|
204
|
+
* metadata. The `data` property contains the fully accumulated context
|
|
205
|
+
* (initial args merged with all step outputs).
|
|
206
|
+
*
|
|
207
|
+
* @typeParam T - The accumulated context type.
|
|
208
|
+
*/
|
|
209
|
+
type PipelineSuccess<T> = Success<T> & {
|
|
210
|
+
/** Pipeline execution metadata. */
|
|
211
|
+
readonly meta: PipelineExecutionMeta;
|
|
212
|
+
};
|
|
213
|
+
/**
|
|
214
|
+
* A failed pipeline result.
|
|
215
|
+
*
|
|
216
|
+
* Extends composable-functions' `Failure` with the name of the step that
|
|
217
|
+
* failed, a rollback report, and pipeline execution metadata.
|
|
218
|
+
*
|
|
219
|
+
* On failure, rollback handlers for all previously completed steps are
|
|
220
|
+
* executed in reverse order before this result is returned.
|
|
221
|
+
*/
|
|
222
|
+
type PipelineFailure = Failure & {
|
|
223
|
+
/** Pipeline execution metadata. */
|
|
224
|
+
readonly meta: PipelineExecutionMeta;
|
|
225
|
+
/** Name of the step that failed. */
|
|
226
|
+
readonly failedStep: string;
|
|
227
|
+
/** Report of which rollback handlers succeeded and which threw. */
|
|
228
|
+
readonly rollback: RollbackReport;
|
|
229
|
+
};
|
|
230
|
+
/**
|
|
231
|
+
* The result of running a pipeline — either a success or a failure.
|
|
232
|
+
*
|
|
233
|
+
* Use the `success` discriminant to narrow:
|
|
234
|
+
*
|
|
235
|
+
* ```ts
|
|
236
|
+
* const result = await pipeline.run(args);
|
|
237
|
+
* if (result.success) {
|
|
238
|
+
* result.data; // fully typed accumulated context
|
|
239
|
+
* result.meta; // execution metadata
|
|
240
|
+
* } else {
|
|
241
|
+
* result.errors; // what went wrong
|
|
242
|
+
* result.failedStep; // which step failed
|
|
243
|
+
* result.rollback; // { completed: [...], failed: [...] }
|
|
244
|
+
* }
|
|
245
|
+
* ```
|
|
246
|
+
*
|
|
247
|
+
* @typeParam T - The accumulated context type on success.
|
|
248
|
+
*/
|
|
249
|
+
type PipelineResult<T> = PipelineSuccess<T> | PipelineFailure;
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Define a pipeline step.
|
|
253
|
+
*
|
|
254
|
+
* Returns a frozen {@link TypedStep} with concrete types for `run`,
|
|
255
|
+
* `rollback`, `requires`, and `provides`. The `run` function can be
|
|
256
|
+
* sync or async — both are supported.
|
|
257
|
+
*
|
|
258
|
+
* **With schemas** (runtime validation + type inference):
|
|
259
|
+
* ```ts
|
|
260
|
+
* const charge = defineStep({
|
|
261
|
+
* name: 'charge',
|
|
262
|
+
* requires: z.object({ amount: z.number() }),
|
|
263
|
+
* provides: z.object({ chargeId: z.string() }),
|
|
264
|
+
* run: async (ctx) => ({ chargeId: 'ch_123' }),
|
|
265
|
+
* });
|
|
266
|
+
* ```
|
|
267
|
+
*
|
|
268
|
+
* **With generics only** (no runtime validation):
|
|
269
|
+
* ```ts
|
|
270
|
+
* const log = defineStep<{ order: Order }, { loggedAt: Date }>({
|
|
271
|
+
* name: 'log',
|
|
272
|
+
* run: async (ctx) => ({ loggedAt: new Date() }),
|
|
273
|
+
* });
|
|
274
|
+
* ```
|
|
275
|
+
*
|
|
276
|
+
* **Invariants:**
|
|
277
|
+
* - The returned step object is always frozen (immutable).
|
|
278
|
+
* - The `run` function is wrapped with `composable()` from
|
|
279
|
+
* composable-functions, which catches thrown errors and produces
|
|
280
|
+
* `Result` values. Step authors should throw to signal failure.
|
|
281
|
+
* - This is the single type-erasure cast point in the library.
|
|
282
|
+
*
|
|
283
|
+
* @typeParam Requires - The context shape this step reads from.
|
|
284
|
+
* @typeParam Provides - The output shape this step produces.
|
|
285
|
+
* @param config - The step configuration. See {@link StepConfig}.
|
|
286
|
+
* @returns A frozen {@link TypedStep} ready for use in pipelines.
|
|
287
|
+
*/
|
|
288
|
+
declare function defineStep<Requires extends StepContext, Provides extends StepContext>(config: StepConfig<Requires, Provides>): TypedStep<Requires, Provides>;
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Error codes for errors produced by the runsheet library itself.
|
|
292
|
+
*
|
|
293
|
+
* Use these to distinguish library errors from application errors
|
|
294
|
+
* in a pipeline's `errors` array:
|
|
295
|
+
*
|
|
296
|
+
* ```ts
|
|
297
|
+
* if (!result.success) {
|
|
298
|
+
* for (const error of result.errors) {
|
|
299
|
+
* if (error instanceof RunsheetError) {
|
|
300
|
+
* console.log(error.code); // 'REQUIRES_VALIDATION', etc.
|
|
301
|
+
* }
|
|
302
|
+
* }
|
|
303
|
+
* }
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
type RunsheetErrorCode = 'REQUIRES_VALIDATION' | 'PROVIDES_VALIDATION' | 'ARGS_VALIDATION' | 'PREDICATE';
|
|
307
|
+
/**
|
|
308
|
+
* Base error class for all errors produced by the runsheet library.
|
|
309
|
+
*
|
|
310
|
+
* Application errors (thrown by step `run` or `rollback` functions)
|
|
311
|
+
* are never wrapped in `RunsheetError` — they pass through as-is.
|
|
312
|
+
* If you see a `RunsheetError` in a result's `errors` array, the
|
|
313
|
+
* library itself produced it.
|
|
314
|
+
*
|
|
315
|
+
* Use `instanceof RunsheetError` to distinguish library errors from
|
|
316
|
+
* application errors, and the `code` property to identify the
|
|
317
|
+
* specific failure.
|
|
318
|
+
*/
|
|
319
|
+
declare class RunsheetError extends Error {
|
|
320
|
+
/** Discriminant code identifying the type of library error. */
|
|
321
|
+
readonly code: RunsheetErrorCode;
|
|
322
|
+
/**
|
|
323
|
+
* @param code - The error code.
|
|
324
|
+
* @param message - A human-readable description of the failure.
|
|
325
|
+
*/
|
|
326
|
+
constructor(code: RunsheetErrorCode, message: string);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Metadata about the step being executed, passed to middleware.
|
|
331
|
+
*
|
|
332
|
+
* This is a read-only view of the step's public configuration.
|
|
333
|
+
* Middleware can use it for logging, metrics, or conditional behavior.
|
|
334
|
+
*/
|
|
335
|
+
type StepInfo = {
|
|
336
|
+
/** The step's name. */
|
|
337
|
+
readonly name: string;
|
|
338
|
+
/** The step's requires schema, or `undefined` if not provided. */
|
|
339
|
+
readonly requires: Step['requires'];
|
|
340
|
+
/** The step's provides schema, or `undefined` if not provided. */
|
|
341
|
+
readonly provides: Step['provides'];
|
|
342
|
+
};
|
|
343
|
+
/**
|
|
344
|
+
* A function that executes a step (or the next middleware in the chain).
|
|
345
|
+
*
|
|
346
|
+
* Receives the frozen accumulated context and returns a `Result` — either
|
|
347
|
+
* `{ success: true, data }` or `{ success: false, errors }`.
|
|
348
|
+
*/
|
|
349
|
+
type StepExecutor = (ctx: Readonly<StepContext>) => Promise<Result<StepOutput>>;
|
|
350
|
+
/**
|
|
351
|
+
* Middleware that wraps the entire step lifecycle, including schema
|
|
352
|
+
* validation.
|
|
353
|
+
*
|
|
354
|
+
* A middleware receives the step metadata and a `next` function, and
|
|
355
|
+
* returns a new executor. Call `next(ctx)` to proceed to the next
|
|
356
|
+
* middleware (or the actual step execution). You can:
|
|
357
|
+
*
|
|
358
|
+
* - **Observe**: read the context or result for logging/metrics.
|
|
359
|
+
* - **Transform**: modify the result before returning it.
|
|
360
|
+
* - **Short-circuit**: return a `Result` without calling `next`.
|
|
361
|
+
*
|
|
362
|
+
* If a middleware throws, the pipeline catches it and treats it as a
|
|
363
|
+
* step failure (triggering rollback for previously completed steps).
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* ```ts
|
|
367
|
+
* const timing: StepMiddleware = (step, next) => async (ctx) => {
|
|
368
|
+
* const start = performance.now();
|
|
369
|
+
* const result = await next(ctx);
|
|
370
|
+
* console.log(`${step.name}: ${performance.now() - start}ms`);
|
|
371
|
+
* return result;
|
|
372
|
+
* };
|
|
373
|
+
* ```
|
|
374
|
+
*
|
|
375
|
+
* @param step - Metadata about the step being wrapped.
|
|
376
|
+
* @param next - The next executor in the chain. Call it to continue.
|
|
377
|
+
* @returns A new executor that wraps `next`.
|
|
378
|
+
*/
|
|
379
|
+
type StepMiddleware = (step: StepInfo, next: StepExecutor) => StepExecutor;
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Internal configuration shape for the pipeline engine.
|
|
383
|
+
*
|
|
384
|
+
* Users typically don't construct this directly — use `buildPipeline()`
|
|
385
|
+
* or `createPipeline()` instead.
|
|
386
|
+
*/
|
|
387
|
+
type PipelineConfig = {
|
|
388
|
+
/** Pipeline name, used in execution metadata and error messages. */
|
|
389
|
+
readonly name: string;
|
|
390
|
+
/** Steps to execute in order. */
|
|
391
|
+
readonly steps: readonly Step[];
|
|
392
|
+
/** Optional middleware applied to every step. First in array = outermost. */
|
|
393
|
+
readonly middleware?: readonly StepMiddleware[];
|
|
394
|
+
/** Optional schema that validates the pipeline's input arguments. */
|
|
395
|
+
readonly argsSchema?: ParserSchema<StepContext>;
|
|
396
|
+
};
|
|
397
|
+
/**
|
|
398
|
+
* A built pipeline, ready to execute.
|
|
399
|
+
*
|
|
400
|
+
* Call `run(args)` to execute the pipeline. The result is a
|
|
401
|
+
* {@link PipelineResult} — either a success with the fully accumulated
|
|
402
|
+
* context, or a failure with error details and a rollback report.
|
|
403
|
+
*
|
|
404
|
+
* Pipeline objects are frozen (immutable) and can be called repeatedly.
|
|
405
|
+
*
|
|
406
|
+
* @typeParam Args - The input type accepted by `run()`.
|
|
407
|
+
* @typeParam Ctx - The accumulated output type on success.
|
|
408
|
+
*/
|
|
409
|
+
type Pipeline<Args extends StepContext, Ctx> = {
|
|
410
|
+
/** The pipeline's name, as provided at build time. */
|
|
411
|
+
readonly name: string;
|
|
412
|
+
/**
|
|
413
|
+
* Execute the pipeline.
|
|
414
|
+
*
|
|
415
|
+
* @param args - The initial arguments. Merged into the context before
|
|
416
|
+
* the first step runs. Validated against `argsSchema` if one was
|
|
417
|
+
* provided.
|
|
418
|
+
* @returns A {@link PipelineResult} — discriminate on `success` to
|
|
419
|
+
* access `data` (on success) or `errors`/`rollback` (on failure).
|
|
420
|
+
*/
|
|
421
|
+
readonly run: (args: Args) => Promise<PipelineResult<Ctx>>;
|
|
422
|
+
};
|
|
423
|
+
/**
|
|
424
|
+
* Build a pipeline from an array of steps.
|
|
425
|
+
*
|
|
426
|
+
* The result type is inferred from the steps — `pipeline.run()` returns
|
|
427
|
+
* a {@link PipelineResult} whose `data` is the intersection of the
|
|
428
|
+
* initial `Args` and all step output types.
|
|
429
|
+
*
|
|
430
|
+
* @example
|
|
431
|
+
* ```ts
|
|
432
|
+
* const pipeline = buildPipeline({
|
|
433
|
+
* name: 'placeOrder',
|
|
434
|
+
* steps: [validateOrder, chargePayment, sendConfirmation],
|
|
435
|
+
* middleware: [logging, timing],
|
|
436
|
+
* argsSchema: z.object({ orderId: z.string() }),
|
|
437
|
+
* });
|
|
438
|
+
*
|
|
439
|
+
* const result = await pipeline.run({ orderId: '123' });
|
|
440
|
+
* if (result.success) {
|
|
441
|
+
* result.data.chargeId; // string — fully typed
|
|
442
|
+
* }
|
|
443
|
+
* ```
|
|
444
|
+
*
|
|
445
|
+
* **Execution semantics:**
|
|
446
|
+
* - Steps execute sequentially in array order.
|
|
447
|
+
* - Context is frozen (`Object.freeze`) at every step boundary.
|
|
448
|
+
* - Conditional steps (wrapped with `when()`) are skipped when their
|
|
449
|
+
* predicate returns false — no snapshot, no rollback entry.
|
|
450
|
+
* - On step failure, rollback handlers for all previously completed
|
|
451
|
+
* steps execute in reverse order (best-effort).
|
|
452
|
+
* - Middleware wraps the full step lifecycle including schema validation.
|
|
453
|
+
*
|
|
454
|
+
* **Invariants:**
|
|
455
|
+
* - The returned pipeline object is frozen (immutable).
|
|
456
|
+
* - Errors thrown by steps, predicates, or middleware are caught and
|
|
457
|
+
* returned as `PipelineFailure` — `run()` never throws.
|
|
458
|
+
*
|
|
459
|
+
* @typeParam Args - The pipeline's input type. Inferred from `argsSchema`
|
|
460
|
+
* if provided, otherwise defaults to `StepContext`.
|
|
461
|
+
* @typeParam S - The step types in the array. Inferred automatically —
|
|
462
|
+
* do not specify manually.
|
|
463
|
+
* @param config - Pipeline configuration.
|
|
464
|
+
* @param config.name - Pipeline name, used in metadata and error messages.
|
|
465
|
+
* @param config.steps - Steps to execute in order.
|
|
466
|
+
* @param config.middleware - Optional middleware applied to every step.
|
|
467
|
+
* First in array = outermost wrapper.
|
|
468
|
+
* @param config.argsSchema - Optional schema that validates `args` before
|
|
469
|
+
* any steps run. Validation failure produces a `PipelineFailure` with
|
|
470
|
+
* `failedStep` set to the pipeline name.
|
|
471
|
+
* @returns A frozen {@link Pipeline} whose `run()` method executes the
|
|
472
|
+
* steps and returns a {@link PipelineResult}.
|
|
473
|
+
*/
|
|
474
|
+
declare function buildPipeline<Args extends StepContext = StepContext, S extends Step = Step>(config: {
|
|
475
|
+
readonly name: string;
|
|
476
|
+
readonly steps: readonly S[];
|
|
477
|
+
readonly middleware?: readonly StepMiddleware[];
|
|
478
|
+
readonly argsSchema?: ParserSchema<Args>;
|
|
479
|
+
}): Pipeline<Args, Args & UnionToIntersection<ExtractProvides<S>>>;
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* A step with a conditional predicate attached.
|
|
483
|
+
*
|
|
484
|
+
* The pipeline engine checks for the `predicate` property to decide
|
|
485
|
+
* whether to execute or skip the step. Use the {@link when} function
|
|
486
|
+
* to create conditional steps — don't construct this type directly.
|
|
487
|
+
*/
|
|
488
|
+
type ConditionalStep = Step & {
|
|
489
|
+
/** Returns `true` to execute the step, `false` to skip it. */
|
|
490
|
+
readonly predicate: (ctx: Readonly<StepContext>) => boolean;
|
|
491
|
+
};
|
|
492
|
+
/**
|
|
493
|
+
* Wrap a step with a guard predicate.
|
|
494
|
+
*
|
|
495
|
+
* The step only executes when the predicate returns `true`. When
|
|
496
|
+
* skipped:
|
|
497
|
+
* - No context snapshot is taken.
|
|
498
|
+
* - No rollback entry is created.
|
|
499
|
+
* - The step name is recorded in `result.meta.stepsSkipped`.
|
|
500
|
+
*
|
|
501
|
+
* If the predicate throws, the pipeline treats it as a step failure
|
|
502
|
+
* and triggers rollback for any previously completed steps.
|
|
503
|
+
*
|
|
504
|
+
* @example
|
|
505
|
+
* ```ts
|
|
506
|
+
* const steps = [
|
|
507
|
+
* validateOrder,
|
|
508
|
+
* when((ctx) => ctx.order.amount > 100, notifyManager),
|
|
509
|
+
* sendConfirmation,
|
|
510
|
+
* ];
|
|
511
|
+
* ```
|
|
512
|
+
*
|
|
513
|
+
* @typeParam Requires - Inferred from the step's requires type.
|
|
514
|
+
* @typeParam Provides - Inferred from the step's provides type.
|
|
515
|
+
* @param predicate - Guard function. Receives the current accumulated
|
|
516
|
+
* context (frozen). Return `true` to execute, `false` to skip.
|
|
517
|
+
* @param step - The step to conditionally execute.
|
|
518
|
+
* @returns A frozen {@link TypedStep} with the predicate attached.
|
|
519
|
+
*/
|
|
520
|
+
declare function when<Requires extends StepContext, Provides extends StepContext>(predicate: (ctx: Readonly<Requires>) => boolean, step: TypedStep<Requires, Provides>): TypedStep<Requires, Provides>;
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* A fluent pipeline builder that progressively narrows the accumulated
|
|
524
|
+
* context type as steps are added.
|
|
525
|
+
*
|
|
526
|
+
* Each method returns a new, frozen builder — builders are immutable.
|
|
527
|
+
* This means you can safely fork a builder to create variants:
|
|
528
|
+
*
|
|
529
|
+
* ```ts
|
|
530
|
+
* const base = createPipeline('order').step(validate);
|
|
531
|
+
* const withCharge = base.step(charge).build();
|
|
532
|
+
* const withoutCharge = base.build(); // unaffected by the fork
|
|
533
|
+
* ```
|
|
534
|
+
*
|
|
535
|
+
* @typeParam Args - The pipeline's initial input type.
|
|
536
|
+
* @typeParam Ctx - The accumulated context type so far (grows with each `.step()`).
|
|
537
|
+
*/
|
|
538
|
+
type PipelineBuilder<Args extends StepContext, Ctx extends StepContext> = {
|
|
539
|
+
/**
|
|
540
|
+
* Add a step to the pipeline.
|
|
541
|
+
*
|
|
542
|
+
* The step's `Requires` type must be satisfied by the current `Ctx`.
|
|
543
|
+
* The returned builder's `Ctx` expands to include the step's `Provides`.
|
|
544
|
+
*
|
|
545
|
+
* @typeParam Provides - The output type of the step being added.
|
|
546
|
+
* @param step - A {@link TypedStep} (from `defineStep` or `when`).
|
|
547
|
+
* @returns A new builder with the expanded context type.
|
|
548
|
+
*/
|
|
549
|
+
readonly step: <Provides extends StepContext>(step: TypedStep<Ctx, Provides>) => PipelineBuilder<Args, Ctx & Provides>;
|
|
550
|
+
/**
|
|
551
|
+
* Add middleware to the pipeline.
|
|
552
|
+
*
|
|
553
|
+
* Middleware is applied to every step. Multiple `.use()` calls
|
|
554
|
+
* accumulate — earlier middleware is outermost (executes first).
|
|
555
|
+
*
|
|
556
|
+
* @param middleware - One or more {@link StepMiddleware} functions.
|
|
557
|
+
* @returns A new builder with the middleware added.
|
|
558
|
+
*/
|
|
559
|
+
readonly use: (...middleware: StepMiddleware[]) => PipelineBuilder<Args, Ctx>;
|
|
560
|
+
/**
|
|
561
|
+
* Build the pipeline.
|
|
562
|
+
*
|
|
563
|
+
* @returns A frozen {@link Pipeline} ready to execute with `run()`.
|
|
564
|
+
*/
|
|
565
|
+
readonly build: () => Pipeline<Args, Ctx>;
|
|
566
|
+
};
|
|
567
|
+
/**
|
|
568
|
+
* Start building a pipeline with the fluent builder API.
|
|
569
|
+
*
|
|
570
|
+
* The builder gives progressive type narrowing — each `.step()` call
|
|
571
|
+
* extends the known context type, so TypeScript catches mismatches
|
|
572
|
+
* at compile time.
|
|
573
|
+
*
|
|
574
|
+
* **Type-only args** (no runtime validation):
|
|
575
|
+
* ```ts
|
|
576
|
+
* createPipeline<{ orderId: string }>('placeOrder')
|
|
577
|
+
* .step(validateOrder)
|
|
578
|
+
* .step(chargePayment)
|
|
579
|
+
* .build();
|
|
580
|
+
* ```
|
|
581
|
+
*
|
|
582
|
+
* **Schema args** (runtime validation + type inference):
|
|
583
|
+
* ```ts
|
|
584
|
+
* createPipeline('placeOrder', z.object({ orderId: z.string() }))
|
|
585
|
+
* .step(validateOrder)
|
|
586
|
+
* .step(chargePayment)
|
|
587
|
+
* .build();
|
|
588
|
+
* ```
|
|
589
|
+
*
|
|
590
|
+
* @typeParam Args - The pipeline's input type. Inferred from `argsSchema`
|
|
591
|
+
* if provided, otherwise specify via generic parameter.
|
|
592
|
+
* @param name - Pipeline name, used in metadata and error messages.
|
|
593
|
+
* @param argsSchema - Optional schema that validates pipeline input
|
|
594
|
+
* at runtime. When provided, `Args` is inferred from the schema.
|
|
595
|
+
* @returns A frozen {@link PipelineBuilder} ready for `.step()`,
|
|
596
|
+
* `.use()`, and `.build()`.
|
|
597
|
+
*/
|
|
598
|
+
declare function createPipeline<Args extends StepContext>(name: string, argsSchema?: ParserSchema<Args>): PipelineBuilder<Args, Args>;
|
|
599
|
+
|
|
600
|
+
export { type ConditionalStep, type Pipeline, type PipelineBuilder, type PipelineConfig, type PipelineExecutionMeta, type PipelineFailure, type PipelineResult, type PipelineSuccess, type RollbackFailure, type RollbackReport, RunsheetError, type RunsheetErrorCode, type Step, type StepConfig, type StepContext, type StepExecutor, type StepInfo, type StepMiddleware, type StepOutput, type TypedStep, buildPipeline, createPipeline, defineStep, when };
|