cl-pipelines pipeline. Each phase is a plain TypeScript object with a name and a run function — no classes, no decorators, no inheritance. Because phases are stateless objects, you can define them at module scope, pass them around, and test them in isolation without any special setup.
Phase shape
name field is how the library looks up a phase from the checkpoint. It must be unique within the array you pass to runPipeline or advancePhase — if two phases share a name, the first match wins.
PhaseContext
Yourrun function receives a PhaseContext<TState> with everything it needs to read state, write logs, and persist mid-phase progress:
string
The ID of the currently running job. Useful if your phase needs to look up related records by the same ID.
Checkpoint<TState>
The checkpoint as it existed when this phase started. Read
checkpoint.state to access state passed from the previous phase (or initialState on the first run).(message: string, level?: string) => Promise<void>
Appends a
LogEntry to the job’s log via StorageAdapter.appendLog. Default level is "info". Log entries are visible through the UI components and storage._inspect() in tests.(state: TState) => Promise<void>
Writes a new checkpoint mid-phase. The stored checkpoint will have
nextPhase set to the current phase name, so a crash and re-run re-enters this phase from the saved position. Use this inside loops over large datasets.PhaseResult
Everyrun function must return one of three variants:
- kind: next
- kind: done
- kind: error
Return
{ kind: "next", nextPhase, state } to advance to another phase. The nextPhase string must match a phase name in your array. The state value becomes ctx.checkpoint.state in the next phase.Throwing an exception from
run has the same effect as returning { kind: "error" } — status is set to "error" and the checkpoint is preserved. You don’t need to wrap every async call in try/catch unless you want to produce a richer error message.Mid-phase checkpointing with ctx.saveState
For phases that process large datasets in a loop, you can callctx.saveState() after each item (or batch). If the process crashes, the next run re-enters the same phase from the last saved position rather than starting the whole phase over.
saveState is called, the stored checkpoint has nextPhase set to "processItems" — so a crash and re-run enters the same phase with the saved chunkIndex, skipping already-processed items.
Testing a phase in isolation
Because phases are plain objects, you can callrun directly in a test with a fake context: