tubeless 0.1.0
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 +106 -0
- package/dist/abort.d.ts +12 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/abort.js +49 -0
- package/dist/abort.js.map +1 -0
- package/dist/batch.d.ts +22 -0
- package/dist/batch.d.ts.map +1 -0
- package/dist/batch.js +73 -0
- package/dist/batch.js.map +1 -0
- package/dist/checkpoint.d.ts +33 -0
- package/dist/checkpoint.d.ts.map +1 -0
- package/dist/checkpoint.js +71 -0
- package/dist/checkpoint.js.map +1 -0
- package/dist/child-execution.d.ts +30 -0
- package/dist/child-execution.d.ts.map +1 -0
- package/dist/child-execution.js +270 -0
- package/dist/child-execution.js.map +1 -0
- package/dist/cli-command.d.ts +29 -0
- package/dist/cli-command.d.ts.map +1 -0
- package/dist/cli-command.js +314 -0
- package/dist/cli-command.js.map +1 -0
- package/dist/cli-parser.d.ts +28 -0
- package/dist/cli-parser.d.ts.map +1 -0
- package/dist/cli-parser.js +557 -0
- package/dist/cli-parser.js.map +1 -0
- package/dist/cli-pipeline-command.d.ts +84 -0
- package/dist/cli-pipeline-command.d.ts.map +1 -0
- package/dist/cli-pipeline-command.js +185 -0
- package/dist/cli-pipeline-command.js.map +1 -0
- package/dist/cli-types.d.ts +220 -0
- package/dist/cli-types.d.ts.map +1 -0
- package/dist/cli-types.js +19 -0
- package/dist/cli-types.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -0
- package/dist/env.d.ts +2 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +8 -0
- package/dist/env.js.map +1 -0
- package/dist/file-utils.d.ts +4 -0
- package/dist/file-utils.d.ts.map +1 -0
- package/dist/file-utils.js +35 -0
- package/dist/file-utils.js.map +1 -0
- package/dist/interactive-reporter.d.ts +38 -0
- package/dist/interactive-reporter.d.ts.map +1 -0
- package/dist/interactive-reporter.js +308 -0
- package/dist/interactive-reporter.js.map +1 -0
- package/dist/lifecycle.d.ts +17 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +77 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/live-ticker.d.ts +21 -0
- package/dist/live-ticker.d.ts.map +1 -0
- package/dist/live-ticker.js +377 -0
- package/dist/live-ticker.js.map +1 -0
- package/dist/mapped-child-progress.d.ts +109 -0
- package/dist/mapped-child-progress.d.ts.map +1 -0
- package/dist/mapped-child-progress.js +133 -0
- package/dist/mapped-child-progress.js.map +1 -0
- package/dist/node.d.ts +5 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +5 -0
- package/dist/node.js.map +1 -0
- package/dist/paths.d.ts +9 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +19 -0
- package/dist/paths.js.map +1 -0
- package/dist/pipeline-command-marker.d.ts +5 -0
- package/dist/pipeline-command-marker.d.ts.map +1 -0
- package/dist/pipeline-command-marker.js +21 -0
- package/dist/pipeline-command-marker.js.map +1 -0
- package/dist/pipeline-diagnostics.d.ts +4 -0
- package/dist/pipeline-diagnostics.d.ts.map +1 -0
- package/dist/pipeline-diagnostics.js +17 -0
- package/dist/pipeline-diagnostics.js.map +1 -0
- package/dist/pipeline-module.d.ts +62 -0
- package/dist/pipeline-module.d.ts.map +1 -0
- package/dist/pipeline-module.js +157 -0
- package/dist/pipeline-module.js.map +1 -0
- package/dist/pipeline.d.ts +606 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +1444 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/progress.d.ts +4 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +8 -0
- package/dist/progress.js.map +1 -0
- package/dist/prompt-select.d.ts +81 -0
- package/dist/prompt-select.d.ts.map +1 -0
- package/dist/prompt-select.js +197 -0
- package/dist/prompt-select.js.map +1 -0
- package/dist/rate-limit.d.ts +7 -0
- package/dist/rate-limit.d.ts.map +1 -0
- package/dist/rate-limit.js +23 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/render.d.ts +21 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +60 -0
- package/dist/render.js.map +1 -0
- package/dist/reporter-entry.d.ts +3 -0
- package/dist/reporter-entry.d.ts.map +1 -0
- package/dist/reporter-entry.js +3 -0
- package/dist/reporter-entry.js.map +1 -0
- package/dist/reporter.d.ts +50 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +167 -0
- package/dist/reporter.js.map +1 -0
- package/dist/retry.d.ts +28 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +59 -0
- package/dist/retry.js.map +1 -0
- package/dist/run-store-sqlite.d.ts +12 -0
- package/dist/run-store-sqlite.d.ts.map +1 -0
- package/dist/run-store-sqlite.js +187 -0
- package/dist/run-store-sqlite.js.map +1 -0
- package/dist/run-store-ui-http.d.ts +5 -0
- package/dist/run-store-ui-http.d.ts.map +1 -0
- package/dist/run-store-ui-http.js +19 -0
- package/dist/run-store-ui-http.js.map +1 -0
- package/dist/run-store-ui-page.d.ts +2 -0
- package/dist/run-store-ui-page.d.ts.map +1 -0
- package/dist/run-store-ui-page.js +759 -0
- package/dist/run-store-ui-page.js.map +1 -0
- package/dist/run-store-ui-protocol.d.ts +28 -0
- package/dist/run-store-ui-protocol.d.ts.map +1 -0
- package/dist/run-store-ui-protocol.js +84 -0
- package/dist/run-store-ui-protocol.js.map +1 -0
- package/dist/run-store-ui-state.d.ts +21 -0
- package/dist/run-store-ui-state.d.ts.map +1 -0
- package/dist/run-store-ui-state.js +65 -0
- package/dist/run-store-ui-state.js.map +1 -0
- package/dist/run-store-ui.d.ts +25 -0
- package/dist/run-store-ui.d.ts.map +1 -0
- package/dist/run-store-ui.js +217 -0
- package/dist/run-store-ui.js.map +1 -0
- package/dist/run-store.d.ts +109 -0
- package/dist/run-store.d.ts.map +1 -0
- package/dist/run-store.js +345 -0
- package/dist/run-store.js.map +1 -0
- package/dist/testing.d.ts +40 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +83 -0
- package/dist/testing.js.map +1 -0
- package/dist/tracing-internal.d.ts +21 -0
- package/dist/tracing-internal.d.ts.map +1 -0
- package/dist/tracing-internal.js +206 -0
- package/dist/tracing-internal.js.map +1 -0
- package/dist/tracing-json.d.ts +12 -0
- package/dist/tracing-json.d.ts.map +1 -0
- package/dist/tracing-json.js +8 -0
- package/dist/tracing-json.js.map +1 -0
- package/dist/tracing-otel.d.ts +36 -0
- package/dist/tracing-otel.d.ts.map +1 -0
- package/dist/tracing-otel.js +60 -0
- package/dist/tracing-otel.js.map +1 -0
- package/dist/tracing.d.ts +48 -0
- package/dist/tracing.d.ts.map +1 -0
- package/dist/tracing.js +2 -0
- package/dist/tracing.js.map +1 -0
- package/dist/workbench-bin.d.ts +3 -0
- package/dist/workbench-bin.d.ts.map +1 -0
- package/dist/workbench-bin.js +8 -0
- package/dist/workbench-bin.js.map +1 -0
- package/dist/workbench-graph.d.ts +3 -0
- package/dist/workbench-graph.d.ts.map +1 -0
- package/dist/workbench-graph.js +64 -0
- package/dist/workbench-graph.js.map +1 -0
- package/dist/workbench-inspect.d.ts +3 -0
- package/dist/workbench-inspect.d.ts.map +1 -0
- package/dist/workbench-inspect.js +65 -0
- package/dist/workbench-inspect.js.map +1 -0
- package/dist/workbench-plan.d.ts +3 -0
- package/dist/workbench-plan.d.ts.map +1 -0
- package/dist/workbench-plan.js +72 -0
- package/dist/workbench-plan.js.map +1 -0
- package/dist/workbench-run.d.ts +13 -0
- package/dist/workbench-run.d.ts.map +1 -0
- package/dist/workbench-run.js +115 -0
- package/dist/workbench-run.js.map +1 -0
- package/dist/workbench-shared.d.ts +67 -0
- package/dist/workbench-shared.d.ts.map +1 -0
- package/dist/workbench-shared.js +163 -0
- package/dist/workbench-shared.js.map +1 -0
- package/dist/workbench-studio.d.ts +26 -0
- package/dist/workbench-studio.d.ts.map +1 -0
- package/dist/workbench-studio.js +57 -0
- package/dist/workbench-studio.js.map +1 -0
- package/dist/workbench-ui.d.ts +3 -0
- package/dist/workbench-ui.d.ts.map +1 -0
- package/dist/workbench-ui.js +262 -0
- package/dist/workbench-ui.js.map +1 -0
- package/dist/workbench.d.ts +5 -0
- package/dist/workbench.d.ts.map +1 -0
- package/dist/workbench.js +43 -0
- package/dist/workbench.js.map +1 -0
- package/docs/README.md +31 -0
- package/docs/agent-guide.md +168 -0
- package/docs/api-reference.md +269 -0
- package/docs/api-report.json +298 -0
- package/docs/child-pipeline-composition.md +185 -0
- package/docs/cli.md +118 -0
- package/docs/concepts.md +502 -0
- package/docs/getting-started.md +162 -0
- package/docs/llms.txt +62 -0
- package/docs/recipes.md +51 -0
- package/docs/studio.md +86 -0
- package/examples/best-effort.ts +42 -0
- package/examples/cancellation-and-testing.ts +45 -0
- package/examples/child-pipeline.ts +51 -0
- package/examples/cli-job.ts +86 -0
- package/examples/conditional-step.ts +41 -0
- package/examples/fan-out-progress.ts +53 -0
- package/examples/local-observability.ts +80 -0
- package/examples/publish-with-gates.ts +56 -0
- package/examples/rendering.ts +34 -0
- package/examples/resumable-enrichment.ts +75 -0
- package/examples/tracing.ts +35 -0
- package/examples/tsconfig.json +15 -0
- package/examples/typed-import.ts +54 -0
- package/examples/validated-boundaries.ts +75 -0
- package/package.json +156 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createSteps, definePipeline, type PipelineError } from "tubeless";
|
|
2
|
+
import { renderPipelineError, renderPipelinePlan } from "tubeless/render";
|
|
3
|
+
|
|
4
|
+
const step = createSteps();
|
|
5
|
+
|
|
6
|
+
const load = step("load", {
|
|
7
|
+
description: "Load the release inputs.",
|
|
8
|
+
run: () => "artifact",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const publish = step("publish", {
|
|
12
|
+
dependsOn: [load],
|
|
13
|
+
description: "Publish the built artifact.",
|
|
14
|
+
run: () => "published",
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export const ReleasePipeline = definePipeline({
|
|
18
|
+
id: "release",
|
|
19
|
+
steps: [load, publish],
|
|
20
|
+
targets: [publish],
|
|
21
|
+
finalize: (outputs) => outputs.publish,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const plan = ReleasePipeline.plan({ targets: ["publish"] });
|
|
25
|
+
|
|
26
|
+
// The same structured plan backs terminal output and machine-readable tooling.
|
|
27
|
+
export const humanPlan = renderPipelinePlan(plan);
|
|
28
|
+
export const jsonPlan = renderPipelinePlan(plan, { format: "json", pretty: true });
|
|
29
|
+
|
|
30
|
+
export function renderDiagnostic(error: PipelineError, format: "human" | "json"): string {
|
|
31
|
+
return format === "json"
|
|
32
|
+
? renderPipelineError(error, { format: "json" })
|
|
33
|
+
: renderPipelineError(error);
|
|
34
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { createSteps, definePipeline } from "tubeless";
|
|
3
|
+
import { runBatched } from "tubeless/batch";
|
|
4
|
+
import { openCheckpoint, withCheckpointedBatch } from "tubeless/node";
|
|
5
|
+
import { RateLimiter } from "tubeless/rate-limit";
|
|
6
|
+
import { withRetry } from "tubeless/retry";
|
|
7
|
+
|
|
8
|
+
interface EnrichmentOptions {
|
|
9
|
+
checkpointPath: string;
|
|
10
|
+
items: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface EnrichedItem {
|
|
14
|
+
id: string;
|
|
15
|
+
summary: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const step = createSteps<EnrichmentOptions>();
|
|
19
|
+
|
|
20
|
+
const loadPendingItems = step("load-pending-items", {
|
|
21
|
+
description: "Skip work that was already checkpointed by a previous run.",
|
|
22
|
+
run: (_inputs, context) => {
|
|
23
|
+
const checkpoint = openCheckpoint(resolve(context.cwd, context.options.checkpointPath));
|
|
24
|
+
return context.options.items.filter((item) => !checkpoint.has(item));
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const enrichItems = step("enrich-items", {
|
|
29
|
+
dependsOn: [loadPendingItems],
|
|
30
|
+
description: "Process API work in small batches with retry and rate limiting.",
|
|
31
|
+
dryRun: "skip",
|
|
32
|
+
run: async ({ "load-pending-items": items }, context) => {
|
|
33
|
+
const checkpoint = openCheckpoint(resolve(context.cwd, context.options.checkpointPath));
|
|
34
|
+
const limiter = new RateLimiter(100);
|
|
35
|
+
|
|
36
|
+
return runBatched(items, { size: 5, concurrency: 2, signal: context.signal }, async (batch) => {
|
|
37
|
+
const enriched = await Promise.all(
|
|
38
|
+
batch.map((id) =>
|
|
39
|
+
withRetry(
|
|
40
|
+
async (): Promise<EnrichedItem> => {
|
|
41
|
+
await limiter.wait(context.signal);
|
|
42
|
+
return { id, summary: `summary for ${id}` };
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
baseDelayMs: 250,
|
|
46
|
+
maxAttempts: 3,
|
|
47
|
+
signal: context.signal,
|
|
48
|
+
sleep: context.sleep,
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
await withCheckpointedBatch(
|
|
55
|
+
checkpoint,
|
|
56
|
+
batch,
|
|
57
|
+
(id) => id,
|
|
58
|
+
async () => {
|
|
59
|
+
// Persist `enriched` here before recording the checkpoint.
|
|
60
|
+
void enriched;
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return enriched;
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
export const EnrichmentPipeline = definePipeline({
|
|
70
|
+
id: "enrichment",
|
|
71
|
+
steps: [loadPendingItems, enrichItems],
|
|
72
|
+
finalize: (outputs) => ({
|
|
73
|
+
enrichedCount: outputs["enrich-items"]?.flat().length ?? 0,
|
|
74
|
+
}),
|
|
75
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createSteps, defaultPipelineContext, definePipeline } from "tubeless";
|
|
2
|
+
import { withRetry } from "tubeless/retry";
|
|
3
|
+
import { createJsonTraceExporter } from "tubeless/tracing/json";
|
|
4
|
+
|
|
5
|
+
interface TracingExampleOptions {
|
|
6
|
+
rows: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const step = createSteps<TracingExampleOptions>();
|
|
10
|
+
const normalize = step("normalize", {
|
|
11
|
+
run: async (_inputs, context) =>
|
|
12
|
+
withRetry(
|
|
13
|
+
async ({ attempt }) => {
|
|
14
|
+
context.reportAttempt(attempt, { operation: "normalize" });
|
|
15
|
+
return context.options.rows.map((row) => row.trim().toLowerCase());
|
|
16
|
+
},
|
|
17
|
+
{ baseDelayMs: 0, maxAttempts: 1 }
|
|
18
|
+
),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const TracingExamplePipeline = definePipeline({
|
|
22
|
+
id: "tracing-example",
|
|
23
|
+
steps: [normalize],
|
|
24
|
+
finalize: (outputs) => outputs.normalize ?? [],
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export async function runTracingExample(rows: readonly string[]): Promise<readonly string[]> {
|
|
28
|
+
return TracingExamplePipeline.runOrThrow(
|
|
29
|
+
{ rows },
|
|
30
|
+
{
|
|
31
|
+
...defaultPipelineContext(),
|
|
32
|
+
tracing: { exporter: createJsonTraceExporter({ log: console }) },
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"esModuleInterop": true,
|
|
4
|
+
"lib": ["ES2022", "DOM"],
|
|
5
|
+
"module": "NodeNext",
|
|
6
|
+
"moduleResolution": "NodeNext",
|
|
7
|
+
"noEmit": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"target": "ES2022",
|
|
11
|
+
"types": ["node"],
|
|
12
|
+
"verbatimModuleSyntax": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["*.ts"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { createSteps, definePipeline, requireOutputs } from "tubeless";
|
|
2
|
+
|
|
3
|
+
interface ImportOptions {
|
|
4
|
+
lines: readonly string[];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const step = createSteps<ImportOptions>();
|
|
8
|
+
|
|
9
|
+
const loadRows = step("load-rows", {
|
|
10
|
+
description: "Read raw input records from the caller.",
|
|
11
|
+
run: (_inputs, context) => context.options.lines,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const normalizeRows = step("normalize-rows", {
|
|
15
|
+
name: "Normalize Rows",
|
|
16
|
+
dependsOn: [loadRows],
|
|
17
|
+
description: "Normalize records after the raw rows are available.",
|
|
18
|
+
run: ({ "load-rows": rows }) =>
|
|
19
|
+
rows.map((row) => row.trim().toLowerCase()).filter((row) => row.length > 0),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const ImportPipeline = definePipeline({
|
|
23
|
+
id: "import",
|
|
24
|
+
steps: [loadRows, normalizeRows],
|
|
25
|
+
targets: [normalizeRows],
|
|
26
|
+
finalize: requireOutputs([normalizeRows], (outputs) => ({
|
|
27
|
+
count: outputs["normalize-rows"].length,
|
|
28
|
+
rows: outputs["normalize-rows"],
|
|
29
|
+
})),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export async function runImportExample() {
|
|
33
|
+
return ImportPipeline.runOrThrow({
|
|
34
|
+
lines: [" Alpha ", "", "Beta"],
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function renderImportDiagram() {
|
|
39
|
+
return ImportPipeline.toMermaid({ direction: "LR" });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function planNormalizeTarget(lines: readonly string[]) {
|
|
43
|
+
void lines;
|
|
44
|
+
return ImportPipeline.plan({ targets: ["normalize-rows"] });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (false) {
|
|
48
|
+
// @ts-expect-error Pipeline step IDs stay literal, so typos fail typecheck.
|
|
49
|
+
ImportPipeline.plan({ stepIds: ["normalise-rows"] });
|
|
50
|
+
// @ts-expect-error Pipeline targets use only declared literal target IDs.
|
|
51
|
+
ImportPipeline.plan({ targets: ["normalise-rows"] });
|
|
52
|
+
// @ts-expect-error Existing internal step IDs are not automatically public targets.
|
|
53
|
+
ImportPipeline.plan({ targets: ["load-rows"] });
|
|
54
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createSteps, definePipeline, requireOutputs, type StandardSchemaV1 } from "tubeless";
|
|
2
|
+
|
|
3
|
+
function standardSchema<TInput, TOutput>(
|
|
4
|
+
validate: StandardSchemaV1<TInput, TOutput>["~standard"]["validate"]
|
|
5
|
+
): StandardSchemaV1<TInput, TOutput> {
|
|
6
|
+
return {
|
|
7
|
+
"~standard": {
|
|
8
|
+
validate,
|
|
9
|
+
vendor: "example",
|
|
10
|
+
version: 1,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const optionsSchema = standardSchema<{ source: string }, { limit: number; source: string }>(
|
|
16
|
+
(value) => {
|
|
17
|
+
// SAFETY: value is unvalidated external input; the optional `source` field is only
|
|
18
|
+
// read so the typeof check below can validate it before any use.
|
|
19
|
+
const source = (value as { source?: unknown }).source;
|
|
20
|
+
return typeof source === "string"
|
|
21
|
+
? { value: { limit: 100, source } }
|
|
22
|
+
: { issues: [{ message: "Expected a source path", path: ["source"] }] };
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const rowsSchema = standardSchema<readonly string[], { readonly rows: readonly string[] }>(
|
|
27
|
+
(value) =>
|
|
28
|
+
Array.isArray(value)
|
|
29
|
+
? // SAFETY: Array.isArray proved an array; this minimal example trusts element
|
|
30
|
+
// types instead of checking every item.
|
|
31
|
+
{ value: { rows: value as readonly string[] } }
|
|
32
|
+
: { issues: [{ message: "Expected rows" }] }
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const resultSchema = standardSchema<
|
|
36
|
+
{ count: number; source: string },
|
|
37
|
+
{ count: number; source: string; validated: true }
|
|
38
|
+
>((value) => {
|
|
39
|
+
// SAFETY: the result schema validates this pipeline's own finalize output, which is
|
|
40
|
+
// constructed as { count, source } by the finalize below — internal data, not external input.
|
|
41
|
+
const result = value as { count: number; source: string };
|
|
42
|
+
return { value: { ...result, validated: true } };
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const step = createSteps(optionsSchema);
|
|
46
|
+
|
|
47
|
+
const load = step("load", {
|
|
48
|
+
outputSchema: rowsSchema,
|
|
49
|
+
run: (_inputs, context) => [context.options.source].slice(0, context.options.limit),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export const ValidatedPipeline = definePipeline({
|
|
53
|
+
id: "validated-import",
|
|
54
|
+
steps: [load],
|
|
55
|
+
resultSchema,
|
|
56
|
+
finalize: requireOutputs([load], ({ load }, context) => ({
|
|
57
|
+
count: load.rows.length,
|
|
58
|
+
source: context.options.source,
|
|
59
|
+
})),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export async function runValidatedExample() {
|
|
63
|
+
const result = await ValidatedPipeline.runOrThrow({ source: "rows.txt" });
|
|
64
|
+
return result.validated;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (false) {
|
|
68
|
+
// @ts-expect-error Options are inferred from the schema input.
|
|
69
|
+
ValidatedPipeline.runOrThrow({});
|
|
70
|
+
|
|
71
|
+
// SAFETY: an empty array literal has no elements that could violate readonly string[].
|
|
72
|
+
const duplicate = step("load", { run: () => [] as readonly string[] });
|
|
73
|
+
// @ts-expect-error Literal duplicate step IDs are rejected at definition time.
|
|
74
|
+
definePipeline({ id: "duplicate", steps: [load, duplicate], finalize: () => undefined });
|
|
75
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tubeless",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Typed pipeline primitives for composable data-processing workflows.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Chet Mancini",
|
|
7
|
+
"url": "https://github.com/chetmancini"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/chetmancini/tubeless.git"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/chetmancini/tubeless#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/chetmancini/tubeless/issues"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"pipeline",
|
|
20
|
+
"workflow",
|
|
21
|
+
"typescript",
|
|
22
|
+
"cli",
|
|
23
|
+
"esm"
|
|
24
|
+
],
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"packageManager": "bun@1.3.14",
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22",
|
|
31
|
+
"bun": ">=1.3.14"
|
|
32
|
+
},
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"type": "module",
|
|
35
|
+
"bin": {
|
|
36
|
+
"tubeless": "./dist/workbench-bin.js"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"docs",
|
|
41
|
+
"examples",
|
|
42
|
+
"LICENSE",
|
|
43
|
+
"README.md"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc -p tsconfig.json",
|
|
47
|
+
"api:check": "node scripts/generate-api-reference.mjs --check",
|
|
48
|
+
"api:generate": "bun run build && node scripts/generate-api-reference.mjs",
|
|
49
|
+
"check": "bun run build && bun run lint:run && bun run format:check && bun run typecheck:run && bun run docs:check && bun run api:check && bun run test:run && bun run eval:verify && bun run pack:verify",
|
|
50
|
+
"docs:check": "node scripts/validate-learning-surface.mjs",
|
|
51
|
+
"eval:agent": "node scripts/evaluate-agent-submission.mjs",
|
|
52
|
+
"eval:verify": "node scripts/verify-agent-evaluation-runner.mjs",
|
|
53
|
+
"format": "oxfmt --write .",
|
|
54
|
+
"format:check": "oxfmt --check .",
|
|
55
|
+
"lint": "bun run build && bun run lint:run",
|
|
56
|
+
"lint:run": "oxlint .",
|
|
57
|
+
"pack:dry-run": "bun pm pack --dry-run --ignore-scripts",
|
|
58
|
+
"tubeless": "bun run --silent build && bun dist/workbench-bin.js",
|
|
59
|
+
"prepack": "bun run build",
|
|
60
|
+
"test": "bun run build && bun run test:run",
|
|
61
|
+
"test:run": "vitest run --config vitest.config.ts",
|
|
62
|
+
"typecheck": "bun run build && bun run typecheck:run",
|
|
63
|
+
"typecheck:run": "tsc -p tsconfig.json --noEmit && tsc -p examples/tsconfig.json --noEmit",
|
|
64
|
+
"pack:verify": "node scripts/verify-packed-artifact.mjs"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@oxlint/plugins": "1.80.0",
|
|
68
|
+
"@types/node": "26.4.0",
|
|
69
|
+
"oxfmt": "0.65.0",
|
|
70
|
+
"oxlint": "1.80.0",
|
|
71
|
+
"typescript": "7.0.2",
|
|
72
|
+
"vitest": "4.1.11"
|
|
73
|
+
},
|
|
74
|
+
"exports": {
|
|
75
|
+
".": {
|
|
76
|
+
"types": "./dist/pipeline.d.ts",
|
|
77
|
+
"import": "./dist/pipeline.js",
|
|
78
|
+
"default": "./dist/pipeline.js"
|
|
79
|
+
},
|
|
80
|
+
"./batch": {
|
|
81
|
+
"types": "./dist/batch.d.ts",
|
|
82
|
+
"import": "./dist/batch.js",
|
|
83
|
+
"default": "./dist/batch.js"
|
|
84
|
+
},
|
|
85
|
+
"./cli": {
|
|
86
|
+
"types": "./dist/cli.d.ts",
|
|
87
|
+
"import": "./dist/cli.js",
|
|
88
|
+
"default": "./dist/cli.js"
|
|
89
|
+
},
|
|
90
|
+
"./node": {
|
|
91
|
+
"types": "./dist/node.d.ts",
|
|
92
|
+
"import": "./dist/node.js",
|
|
93
|
+
"default": "./dist/node.js"
|
|
94
|
+
},
|
|
95
|
+
"./rate-limit": {
|
|
96
|
+
"types": "./dist/rate-limit.d.ts",
|
|
97
|
+
"import": "./dist/rate-limit.js",
|
|
98
|
+
"default": "./dist/rate-limit.js"
|
|
99
|
+
},
|
|
100
|
+
"./render": {
|
|
101
|
+
"types": "./dist/render.d.ts",
|
|
102
|
+
"import": "./dist/render.js",
|
|
103
|
+
"default": "./dist/render.js"
|
|
104
|
+
},
|
|
105
|
+
"./reporter": {
|
|
106
|
+
"types": "./dist/reporter-entry.d.ts",
|
|
107
|
+
"import": "./dist/reporter-entry.js",
|
|
108
|
+
"default": "./dist/reporter-entry.js"
|
|
109
|
+
},
|
|
110
|
+
"./retry": {
|
|
111
|
+
"types": "./dist/retry.d.ts",
|
|
112
|
+
"import": "./dist/retry.js",
|
|
113
|
+
"default": "./dist/retry.js"
|
|
114
|
+
},
|
|
115
|
+
"./run-store": {
|
|
116
|
+
"types": "./dist/run-store.d.ts",
|
|
117
|
+
"import": "./dist/run-store.js",
|
|
118
|
+
"default": "./dist/run-store.js"
|
|
119
|
+
},
|
|
120
|
+
"./run-store/sqlite": {
|
|
121
|
+
"types": "./dist/run-store-sqlite.d.ts",
|
|
122
|
+
"import": "./dist/run-store-sqlite.js",
|
|
123
|
+
"default": "./dist/run-store-sqlite.js"
|
|
124
|
+
},
|
|
125
|
+
"./workbench/studio": {
|
|
126
|
+
"types": "./dist/workbench-studio.d.ts",
|
|
127
|
+
"import": "./dist/workbench-studio.js",
|
|
128
|
+
"default": "./dist/workbench-studio.js"
|
|
129
|
+
},
|
|
130
|
+
"./run-store/ui": {
|
|
131
|
+
"types": "./dist/run-store-ui.d.ts",
|
|
132
|
+
"import": "./dist/run-store-ui.js",
|
|
133
|
+
"default": "./dist/run-store-ui.js"
|
|
134
|
+
},
|
|
135
|
+
"./testing": {
|
|
136
|
+
"types": "./dist/testing.d.ts",
|
|
137
|
+
"import": "./dist/testing.js",
|
|
138
|
+
"default": "./dist/testing.js"
|
|
139
|
+
},
|
|
140
|
+
"./tracing": {
|
|
141
|
+
"types": "./dist/tracing.d.ts",
|
|
142
|
+
"import": "./dist/tracing.js",
|
|
143
|
+
"default": "./dist/tracing.js"
|
|
144
|
+
},
|
|
145
|
+
"./tracing/json": {
|
|
146
|
+
"types": "./dist/tracing-json.d.ts",
|
|
147
|
+
"import": "./dist/tracing-json.js",
|
|
148
|
+
"default": "./dist/tracing-json.js"
|
|
149
|
+
},
|
|
150
|
+
"./tracing/otel": {
|
|
151
|
+
"types": "./dist/tracing-otel.d.ts",
|
|
152
|
+
"import": "./dist/tracing-otel.js",
|
|
153
|
+
"default": "./dist/tracing-otel.js"
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|