import pg from "pg"; import { PgBoss } from "pg-boss"; type WorkflowRun = { id: string; createdAt: Date; updatedAt: Date; resourceId: string | null; workflowId: string; status: "pending" | "running" | "paused" | "completed" | "failed" | "cancelled"; input: unknown; output: unknown | null; error: string | null; currentStepId: string; timeline: Record; pausedAt: Date | null; resumedAt: Date | null; completedAt: Date | null; timeoutAt: Date | null; retryCount: number; maxRetries: number; /** Resolved scheduling priority (pg-boss integer; higher runs first). */ priority: number; /** * When true, this run participates in the per-workflow-ID uniqueness * constraint: no other pending or running singleton run of the same * workflow ID may exist at the same time. Paused, completed, failed, and * cancelled runs release the slot. */ singleton: boolean; jobId: string | null; idempotencyKey: string | null; parentRunId: string | null; parentStepId: string | null; parentResourceId: string | null; /** Set when the run was started by a recurring schedule; the timestamp the schedule fired. */ scheduledAt: Date | null; }; import { StandardSchemaV1 } from "@standard-schema/spec"; type DurationObject = { weeks?: number; days?: number; hours?: number; minutes?: number; seconds?: number; }; type Duration = string | DurationObject; /** * Named priority levels mapped to pg-boss integer priorities. Higher numbers * are fetched first (pg-boss orders by `priority DESC`), and `normal = 0` * matches pg-boss's own default. The ±100 spacing leaves room for numeric * tuning between tiers via the escape hatch. */ declare const PRIORITY_LEVELS: { readonly high: 100; readonly normal: 0; readonly low: -100; }; type WorkflowPriority = keyof typeof PRIORITY_LEVELS | number; type Schedule = string | Exclude; declare enum WorkflowStatus { PENDING = "pending", RUNNING = "running", PAUSED = "paused", COMPLETED = "completed", FAILED = "failed", CANCELLED = "cancelled" } type InputParameters = StandardSchemaV1; type InferInputParameters

= StandardSchemaV1.InferOutput

; type StartWorkflowOptions = { resourceId?: string; timeout?: number; retries?: number; expireInSeconds?: number; idempotencyKey?: string; priority?: WorkflowPriority; /** * Client-side counterpart of `workflow(..., { singleton: true })`. * The engine reads this from the registered definition; pass it here when * starting from `WorkflowClient` so the uniqueness constraint applies. */ singleton?: boolean; }; type WorkflowOptions = { timeout?: number; retries?: number; inputSchema?: I; priority?: WorkflowPriority; /** * When true, at most one pending or running run of this workflow ID may exist. * A second `startWorkflow` throws `WorkflowRunInProgressError` until the * current run pauses, completes, fails, or is cancelled. */ singleton?: boolean; /** * Recurring schedule. Accepts a cron expression (`'0 9 * * 1-5'`), * a duration string (`'5m'`, `'1 hour'`), or a `DurationObject`. */ schedule?: Schedule; /** IANA timezone for cron expressions. Defaults to UTC. Ignored for duration-based schedules. */ timezone?: string; }; /** Metadata about a scheduled fire, exposed on `ctx.schedule` for runs triggered by a schedule. */ type ScheduleContext = { /** Time the schedule fired this run. */ timestamp: Date; }; type StepBaseContext = { run: (stepId: string, handler: () => Promise) => Promise; waitFor: { (stepId: string, options: { eventName: string; schema?: T; }): Promise>; (stepId: string, options: { eventName: string; timeout: number; schema?: T; }): Promise | undefined>; }; waitUntil: { (stepId: string, date: Date): Promise; (stepId: string, dateString: string): Promise; (stepId: string, options: { date: Date | string; }): Promise; }; /** Delay execution for a duration (sugar over waitUntil). Alias: sleep. */ delay: (stepId: string, duration: Duration) => Promise; /** Alias for delay. */ sleep: (stepId: string, duration: Duration) => Promise; pause: (stepId: string) => Promise; poll: (stepId: string, conditionFn: () => Promise, options?: { interval?: Duration; timeout?: Duration; }) => Promise<{ timedOut: false; data: T; } | { timedOut: true; }>; /** * Invoke a child workflow from inside the current workflow and pause until * the child run reaches a terminal state. */ invokeChildWorkflow: { < TInput extends InputParameters, TOutput = unknown >(stepId: string, ref: WorkflowRef, input: InferInputParameters, options?: StartWorkflowOptions): Promise; (stepId: string, params: { workflowId: string; input: unknown; resourceId?: string; idempotencyKey?: string; options?: StartWorkflowOptions; }): Promise; }; }; /** * Plugin that extends the workflow step API with extra methods. * @template TStepBase - The step type this plugin receives (base + previous plugins). * @template TStepExt - The extra methods this plugin adds to step. */ interface WorkflowPlugin< TStepBase = StepBaseContext, TStepExt = object > { name: string; methods: (step: TStepBase, context: WorkflowContext) => TStepExt; /** * Optional middleware around the workflow handler call. Composes in * registration order — the first plugin passed to `.use()` wraps everything * inside. Implementations MUST call `next()` exactly once. */ wrap?: (context: WorkflowContext, next: () => Promise) => Promise; } type WorkflowContext< TInput extends InputParameters = InputParameters, TStep extends StepBaseContext = StepBaseContext > = { input: InferInputParameters; step: TStep; workflowId: string; runId: string; /** Tenant/scope identifier set when the run was started, if any. */ resourceId?: string; /** Zero-based retry attempt number (= `run.retryCount`). */ attempt: number; timeline: Record; logger: WorkflowLogger; /** Set only for runs triggered by a recurring schedule. */ schedule?: ScheduleContext; }; type WorkflowDefinition = { id: string; /** Widest context avoids contravariance when collecting definitions; `workflow()` still types the handler narrowly. */ handler: (context: WorkflowContext) => Promise; inputSchema?: TInput; timeout?: number; retries?: number; priority?: WorkflowPriority; singleton?: boolean; schedule?: Schedule; timezone?: string; plugins?: WorkflowPlugin[]; }; /** * Lightweight workflow reference - carries the workflow ID and input type * but no handler code. Safe to import in API services without pulling in * heavy worker dependencies. * * Callable: pass a handler to create a full WorkflowDefinition. */ interface WorkflowRef< TInput extends InputParameters = InputParameters, TOutput = unknown > { (handler: (context: WorkflowContext) => Promise, options?: Omit, "inputSchema">): WorkflowDefinition; readonly id: string; readonly inputSchema?: TInput; readonly singleton?: boolean; } type WorkflowRunProgress = WorkflowRun & { completionPercentage: number; totalSteps: number; completedSteps: number; }; interface WorkflowLogger { log(message: string): void; error(message: string, ...args: unknown[]): void; } type WorkflowClientOptions = { logger?: WorkflowLogger; /** * Pre-configured pg-boss instance. Pass this when the engine side uses a * non-default pg-boss config (schema, retention, logger, etc.) so the * client enqueues jobs where the engine reads them. Mirrors the same * option on `WorkflowEngineOptions`. */ boss?: PgBoss; } & ({ pool: pg.Pool; connectionString?: never; } | { connectionString: string; pool?: never; }); declare class WorkflowClient { private boss; private db; private pool; private _ownsPool; private _started; private logger; constructor({ logger, boss,...connectionOptions }: WorkflowClientOptions); start(): Promise; stop(): Promise; startWorkflow(ref: WorkflowRef, input: InferInputParameters, options?: StartWorkflowOptions): Promise; startWorkflow(params: { workflowId: string; input: unknown; resourceId?: string; idempotencyKey?: string; options?: StartWorkflowOptions; }): Promise; triggerEvent({ runId, resourceId, eventName, data, options }: { runId: string; resourceId?: string; eventName: string; data?: Record; options?: { expireInSeconds?: number; }; }): Promise; pauseWorkflow({ runId, resourceId }: { runId: string; resourceId?: string; }): Promise; resumeWorkflow({ runId, resourceId, options }: { runId: string; resourceId?: string; options?: { expireInSeconds?: number; }; }): Promise; fastForwardWorkflow({ runId, resourceId, data }: { runId: string; resourceId?: string; data?: Record; }): Promise; cancelWorkflow({ runId, resourceId }: { runId: string; resourceId?: string; }): Promise; getRun({ runId, resourceId }: { runId: string; resourceId?: string; }): Promise; checkProgress({ runId, resourceId }: { runId: string; resourceId?: string; }): Promise; getRuns({ resourceId, startingAfter, endingBefore, limit, statuses, workflowId }: { resourceId?: string; startingAfter?: string | null; endingBefore?: string | null; limit?: number; statuses?: WorkflowStatus[]; workflowId?: string; }): Promise<{ items: WorkflowRun[]; nextCursor: string | null; prevCursor: string | null; hasMore: boolean; hasPrev: boolean; }>; private ensureStarted; } /** * Create a lightweight workflow reference. * Safe to import from `pg-workflows/client` - no engine or handler code. */ declare function createWorkflowRef< TOutput = unknown, TInput extends InputParameters = InputParameters >(id: string, options?: { inputSchema?: TInput; singleton?: boolean; }): WorkflowRef; import { StandardSchemaV1 as StandardSchemaV12 } from "@standard-schema/spec"; declare class WorkflowEngineError extends Error { readonly workflowId?: string | undefined; readonly runId?: string | undefined; readonly cause: Error | undefined; readonly issues?: StandardSchemaV12.FailureResult["issues"] | undefined; constructor(message: string, workflowId?: string | undefined, runId?: string | undefined, cause?: Error | undefined, issues?: StandardSchemaV12.FailureResult["issues"] | undefined); } declare class WorkflowRunNotFoundError extends WorkflowEngineError { constructor(runId?: string, workflowId?: string); } declare class WorkflowRunInProgressError extends WorkflowEngineError { constructor(workflowId: string, runId?: string); } export { createWorkflowRef, WorkflowStatus, WorkflowRunProgress, WorkflowRunNotFoundError, WorkflowRunInProgressError, WorkflowRun, WorkflowRef, WorkflowLogger, WorkflowEngineError, WorkflowClientOptions, WorkflowClient, StartWorkflowOptions, InputParameters, InferInputParameters };