import { StandardSchemaV1 } from '@standard-schema/spec'; /** A value that may be returned directly or as a promise. */ type MaybePromise = Promise | T; /** * A human-friendly duration. Either a raw millisecond count, a structured * `{ amount, unit }` pair, or a `{ cron }` expression resolved against "now". */ type Duration = number | { amount: number; unit: DurationUnit; } | { cron: string; tz?: string; }; /** Units accepted by the structured {@link Duration} form. */ type DurationUnit = "days" | "hours" | "milliseconds" | "minutes" | "ms" | "seconds" | "weeks"; /** * The context handed to a workflow body. Every durable operation goes through * `ctx` so the engine can record, skip and resume it deterministically. * * IMPORTANT: any side effect that must run *exactly once* has to be wrapped in * {@link RunContext.step}. Code outside `step`/`sleep`/`waitForEvent` re-executes * on every replay. */ interface RunContext { /** The validated trigger payload. */ readonly payload: PayloadT; /** The id of the current run. */ readonly runId: string; /** * Durably pause the run for a duration, then resume. * @param id A stable, unique id for this sleep. * @param duration How long to pause. */ sleep: (id: string, duration: Duration) => Promise; /** * Run a side effect exactly once. The result is recorded; on replay the * recorded value is returned without re-executing the function. * @param id A stable, unique id for this step within the workflow. * @param function_ The side effect to run. */ step: (id: string, function_: () => MaybePromise) => Promise; /** * Durably suspend until an external event is delivered via * `runtime.signal(runId, name, payload)`, or the optional timeout elapses. * @param id A stable, unique id for this wait. * @param name The event name to wait for. * @param options Optional settings for the wait. * @param options.timeout How long to wait before resolving to `undefined`. * @returns The signalled payload, or `undefined` on timeout. */ waitForEvent: (id: string, name: string, options?: { timeout?: Duration; }) => Promise; } /** The body of a workflow: an async function driven by {@link RunContext}. */ type WorkflowRun = (context: RunContext) => MaybePromise; /** Options accepted by `defineWorkflow`. */ interface WorkflowConfig { /** Unique id of the workflow, used as the namespace for run ids and storage. */ id: string; /** Optional Standard Schema validating (and typing) the trigger payload. */ payload?: StandardSchemaV1; /** The workflow body. */ run: WorkflowRun; /** Optional free-form tags for routing/observability. */ tags?: string[]; } /** A defined workflow: the config plus the validated payload-schema accessor. */ interface WorkflowDefinition extends WorkflowConfig { /** Validate (and parse) an unknown input against the payload schema. */ parsePayload: (input: unknown) => Promise; /** Brand marking this object as a defined workflow. */ readonly [WORKFLOW_BRAND]: true; } export { Duration as D, MaybePromise as M, WorkflowConfig as W, WorkflowDefinition as a };