First pipeline
Library imports need Node.js 22+. The CLI needs Bun 1.3.14+. Linux and macOS are supported. Windows is untested.
Install the library
Also pnpm add, yarn add, or bun add. ESM-only. Dependency-free at runtime.
Use the CLI
npx tubeless works if Bun is installed; otherwise it prints install instructions.
Define a pipeline
One createSteps factory per pipeline. The step object is the typed dependency token.
IDs stay stable because plans, reports, hooks, and CLI selection use them.
import { createSteps, definePipeline, requireOutputs } from "tubeless";
interface ImportOptions {
lines: readonly string[];
}
const step = createSteps<ImportOptions>();
const load = step("load", {
run: (_inputs, context) => context.options.lines,
});
const normalize = step("normalize", {
dependsOn: [load],
run: ({ load: rows }) =>
rows.map((row) => row.trim().toLowerCase()).filter(Boolean),
});
export const ImportPipeline = definePipeline({
id: "import",
steps: [load, normalize],
targets: [normalize],
finalize: requireOutputs([normalize], ({ normalize }) => normalize),
}); See the static graph
toMermaid() prints the static graph. Required edges are solid. Optional
inputs and failure gates are dotted. Same source from tubeless graph.
$ bunx tubeless graph ./examples/typed-import.ts --markdown --direction LR ```mermaidflowchart LR step0["load-rows"] step1["Normalize Rows"] step0 --> step1```
Pick an execution method
runOrThrow when failure should throw. run for the structured report.
plan when nothing may execute. Scripts should use definePipelineCommand
so --target, --step, and dry-run stay generated.
$ bunx tubeless run ./examples/cli-job.ts -- --source examples/rows.txt --limit 2 Pipeline import: starting (2 steps, dryRun=false) -> load-rows - Read raw input records from the caller. ok load-rows (1ms) -> normalize-rows - Trim, lowercase, drop blanks, and apply --limit. ok normalize-rows (0ms) -> finalize ok finalize (0ms)Pipeline import: done in 1ms (status=completed, steps=2, errors=0)Normalized 2 row(s).