@olivervea/pipelines 2.0.0-beta.2 → 2.0.0-beta.20

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.
Files changed (54) hide show
  1. package/README.md +125 -62
  2. package/manifest.schema.json +208 -11
  3. package/package.json +6 -4
  4. package/src/assets.d.ts +2 -2
  5. package/src/build/build.ts +121 -51
  6. package/src/build/cli.ts +29 -22
  7. package/src/build/elf.ts +8 -7
  8. package/src/build/hashes.ts +82 -20
  9. package/src/build/project.ts +95 -28
  10. package/src/builder/pipeline.ts +344 -88
  11. package/src/builder/refs.ts +15 -5
  12. package/src/core/brands.ts +7 -5
  13. package/src/core/config-refs.ts +103 -0
  14. package/src/core/config.ts +224 -0
  15. package/src/core/external.ts +86 -0
  16. package/src/core/handlers.ts +61 -15
  17. package/src/core/models.ts +32 -15
  18. package/src/core/origin.ts +23 -0
  19. package/src/core/secrets.ts +2 -2
  20. package/src/core/steps.ts +89 -38
  21. package/src/core/types.ts +5 -1
  22. package/src/core/webhooks.ts +21 -7
  23. package/src/ctx/files.ts +111 -40
  24. package/src/ctx/index.ts +84 -31
  25. package/src/ctx/sh.ts +105 -44
  26. package/src/ctx/types.ts +12 -4
  27. package/src/describe/describe.ts +701 -133
  28. package/src/describe/manifest-schema.ts +258 -61
  29. package/src/describe/mapper-source.ts +249 -104
  30. package/src/describe/record.ts +67 -37
  31. package/src/dev/cli.ts +72 -35
  32. package/src/harness/env.ts +45 -25
  33. package/src/harness/execute.ts +58 -29
  34. package/src/harness/index.ts +22 -9
  35. package/src/harness/main.ts +239 -78
  36. package/src/harness/result.ts +38 -22
  37. package/src/harness/validate.ts +77 -15
  38. package/src/index.ts +124 -11
  39. package/src/library/checks.ts +28 -0
  40. package/src/library/compose-deploy.ts +113 -0
  41. package/src/library/github-source.ts +100 -47
  42. package/src/library/helm-deploy-ssh.ts +452 -108
  43. package/src/library/helm-deploy.ts +449 -0
  44. package/src/library/http-health.ts +7 -5
  45. package/src/library/image-build.ts +499 -105
  46. package/src/library/index.ts +48 -12
  47. package/src/library/models.ts +33 -9
  48. package/src/library/ssh.ts +67 -0
  49. package/src/testing/index.ts +74 -36
  50. package/src/util/canonical.ts +7 -4
  51. package/src/util/handler-hash.ts +17 -7
  52. package/src/util/hash.ts +5 -5
  53. package/src/util/tar.ts +86 -36
  54. package/src/library/script.ts +0 -85
package/src/dev/cli.ts CHANGED
@@ -1,31 +1,52 @@
1
1
  #!/usr/bin/env bun
2
2
  // olve-dev — run a pipeline from source through the same harness path as the compiled binary.
3
3
  // olve-dev describe <dir> [--sentinels]
4
- // olve-dev run <dir> <step> [--input-file f] [--olve-dir d] [--secret NAME=value]...
4
+ // olve-dev run <dir> <step> [--input-file f] [--config-file f] [--olve-dir d] [--secret NAME=value]...
5
5
  // olve-dev map-trigger <dir> <trigger> --event-file f [--olve-dir d]
6
6
  // $OLVE_DIR defaults to <dir>/.olve; outputs land in <dir>/.olve/work/.
7
- import { copyFileSync, mkdirSync } from "node:fs";
8
- import { join, resolve } from "node:path";
9
- import { parseArgs } from "node:util";
10
- import { runHarness, type HarnessConfig } from "../harness/main.ts";
11
- import { EXIT } from "../harness/exit.ts";
12
- import { handlerHashes } from "../build/hashes.ts";
13
- import { harnessInfo, loadProject, ProjectError } from "../build/project.ts";
7
+ import {
8
+ copyFileSync,
9
+ existsSync,
10
+ mkdirSync,
11
+ readFileSync,
12
+ writeFileSync,
13
+ } from 'node:fs';
14
+ import { join, resolve } from 'node:path';
15
+ import { parseArgs } from 'node:util';
16
+ import { runHarness, type HarnessConfig } from '../harness/main.ts';
17
+ import { EXIT } from '../harness/exit.ts';
18
+ import { handlerHashes, kindHashes } from '../build/hashes.ts';
19
+ import {
20
+ harnessInfo,
21
+ loadPipeline,
22
+ loadProject,
23
+ ProjectError,
24
+ } from '../build/project.ts';
14
25
 
15
26
  const USAGE = `usage: olve-dev describe <dir> [--sentinels]
16
- olve-dev run <dir> <step> [--input-file f] [--olve-dir d] [--secret NAME=value]...
27
+ olve-dev run <dir> <step> [--input-file f] [--config-file f] [--olve-dir d] [--secret NAME=value]...
17
28
  olve-dev map-trigger <dir> <trigger> --event-file f [--olve-dir d]`;
18
29
 
19
- export async function devConfig(dir: string, withHashes: boolean): Promise<HarnessConfig> {
20
- const project = loadProject(dir);
21
- const mod = (await import(project.pipelineFile)) as { default?: unknown };
22
- if (!mod.default) throw new ProjectError(`${project.pipelineFile} has no default export (export default pipeline({...})...)`);
30
+ export async function devConfig(
31
+ dir: string,
32
+ withHashes: boolean,
33
+ ): Promise<HarnessConfig> {
34
+ const project = await loadProject(dir);
35
+ const pipeline = await loadPipeline(project);
23
36
  const harness = harnessInfo();
24
37
  const hashes = withHashes ? await handlerHashes(project, harness) : {};
25
38
  return {
26
- pipeline: mod.default,
27
- handlers: Object.fromEntries(project.handlers.map(([name, file]) => [name, () => import(file) as Promise<{ default: unknown }>])),
28
- handlerHashes: Object.fromEntries(Object.entries(hashes).map(([k, v]) => [k, v.handlerHash])),
39
+ pipeline,
40
+ handlers: Object.fromEntries(
41
+ project.handlers.map(([name, file]) => [
42
+ name,
43
+ () => import(file) as Promise<{ default: unknown }>,
44
+ ]),
45
+ ),
46
+ handlerHashes: Object.fromEntries(
47
+ Object.entries(hashes).map(([k, v]) => [k, v.handlerHash]),
48
+ ),
49
+ ...(withHashes ? { kindHashes: await kindHashes(project, pipeline) } : {}),
29
50
  harness,
30
51
  };
31
52
  }
@@ -37,12 +58,13 @@ export async function devMain(argv: string[]): Promise<number> {
37
58
  args: argv,
38
59
  allowPositionals: true,
39
60
  options: {
40
- "input-file": { type: "string" },
41
- "event-file": { type: "string" },
42
- "olve-dir": { type: "string" },
43
- secret: { type: "string", multiple: true },
44
- sentinels: { type: "boolean", default: false },
45
- help: { type: "boolean", short: "h", default: false },
61
+ 'input-file': { type: 'string' },
62
+ 'config-file': { type: 'string' },
63
+ 'event-file': { type: 'string' },
64
+ 'olve-dir': { type: 'string' },
65
+ secret: { type: 'string', multiple: true },
66
+ sentinels: { type: 'boolean', default: false },
67
+ help: { type: 'boolean', short: 'h', default: false },
46
68
  },
47
69
  });
48
70
  } catch (e) {
@@ -50,28 +72,43 @@ export async function devMain(argv: string[]): Promise<number> {
50
72
  return EXIT.usage;
51
73
  }
52
74
  const { values, positionals } = parsed;
53
- if (values.help) return console.log(USAGE), 0;
75
+ if (values.help) return (console.log(USAGE), 0);
54
76
  const [mode, dir, name] = positionals;
55
- if (!mode || !dir) return console.error(USAGE), EXIT.usage;
77
+ if (!mode || !dir) return (console.error(USAGE), EXIT.usage);
56
78
  try {
57
- if (mode === "describe") return await runHarness(await devConfig(dir, true), ["describe", ...(values.sentinels ? ["--sentinels"] : [])]);
58
- if (mode !== "run" && mode !== "map-trigger") return console.error(USAGE), EXIT.usage;
59
- if (!name) return console.error(USAGE), EXIT.usage;
60
- const olveDir = resolve(values["olve-dir"] ?? join(dir, ".olve"));
79
+ if (mode === 'describe')
80
+ return await runHarness(await devConfig(dir, true), [
81
+ 'describe',
82
+ ...(values.sentinels ? ['--sentinels'] : []),
83
+ ]);
84
+ if (mode !== 'run' && mode !== 'map-trigger')
85
+ return (console.error(USAGE), EXIT.usage);
86
+ if (!name) return (console.error(USAGE), EXIT.usage);
87
+ const file = mode === 'run' ? values['input-file'] : values['event-file'];
88
+ if (mode === 'map-trigger' && !file)
89
+ return (console.error('--event-file is required'), EXIT.usage);
90
+ const olveDir = resolve(values['olve-dir'] ?? join(dir, '.olve'));
61
91
  mkdirSync(olveDir, { recursive: true });
62
92
  process.env.OLVE_DIR = olveDir;
63
- process.env.TMPDIR ??= join(olveDir, "tmp");
93
+ process.env.TMPDIR ??= join(olveDir, 'tmp');
64
94
  for (const s of values.secret ?? []) {
65
- const i = s.indexOf("=");
66
- if (i <= 0) return console.error(`--secret expects NAME=value, got '${s}'`), EXIT.usage;
95
+ const i = s.indexOf('=');
96
+ if (i <= 0)
97
+ return (console.error(`--secret expects NAME=value, got '${s}'`), EXIT.usage);
67
98
  process.env[s.slice(0, i)] = s.slice(i + 1);
68
99
  }
69
- const file = mode === "run" ? values["input-file"] : values["event-file"];
70
- if (file) copyFileSync(resolve(file), join(olveDir, "input.json"));
71
- else if (mode === "map-trigger") return console.error("--event-file is required"), EXIT.usage;
100
+ if (file) copyFileSync(resolve(file), join(olveDir, 'input.json'));
101
+ if (mode === 'run' && values['config-file']) {
102
+ const inputFile = join(olveDir, 'input.json');
103
+ const input = (
104
+ existsSync(inputFile) ? JSON.parse(readFileSync(inputFile, 'utf8')) : {}
105
+ ) as Record<string, unknown>;
106
+ input.$config = JSON.parse(readFileSync(resolve(values['config-file']), 'utf8'));
107
+ writeFileSync(inputFile, JSON.stringify(input));
108
+ }
72
109
  return await runHarness(await devConfig(dir, false), [mode, name]);
73
110
  } catch (e) {
74
- if (e instanceof ProjectError) return console.error(e.message), EXIT.configInvalid;
111
+ if (e instanceof ProjectError) return (console.error(e.message), EXIT.configInvalid);
75
112
  console.error((e as Error)?.stack ?? String(e));
76
113
  return EXIT.configInvalid;
77
114
  }
@@ -1,58 +1,78 @@
1
1
  // The environment contract between the service and the harness. Documented in README.md.
2
- import { join } from "node:path";
2
+ import { join } from 'node:path';
3
3
 
4
4
  export const ENV = {
5
5
  /** Root of the harness IO directory (default /olve). */
6
- dir: "OLVE_DIR",
7
- pipeline: "OLVE_PIPELINE",
8
- runId: "OLVE_RUN_ID",
9
- run: "OLVE_RUN",
10
- attempt: "OLVE_ATTEMPT",
11
- versionStamp: "OLVE_VERSION_STAMP",
6
+ dir: 'OLVE_DIR',
7
+ pipeline: 'OLVE_PIPELINE',
8
+ runId: 'OLVE_RUN_ID',
9
+ run: 'OLVE_RUN',
10
+ attempt: 'OLVE_ATTEMPT',
11
+ versionStamp: 'OLVE_VERSION_STAMP',
12
12
  /** Pre-signed PUT for result.tar.gz (run / map-trigger). Optional. */
13
- resultUrl: "OLVE_RESULT_URL",
13
+ resultUrl: 'OLVE_RESULT_URL',
14
14
  /** JSON object: file key (`<run>/<step>/<attempt>/<path>`) → pre-signed GET URL. Optional. */
15
- fileUrls: "OLVE_FILE_URLS",
15
+ fileUrls: 'OLVE_FILE_URLS',
16
+ /** JSON object: `<step>/<input>` → callback URL of that external input in this run (`ctx.inputUrl`). Optional. */
17
+ callbackUrls: 'OLVE_CALLBACK_URLS',
16
18
  /** Base URL for file downloads: GET `<base>/<run>/<step>/<attempt>/<object path>`. Optional. */
17
- filesBaseUrl: "OLVE_FILES_BASE_URL",
19
+ filesBaseUrl: 'OLVE_FILES_BASE_URL',
18
20
  /** Bearer token sent with OLVE_FILES_BASE_URL requests. Optional. */
19
- filesToken: "OLVE_FILES_TOKEN",
21
+ filesToken: 'OLVE_FILES_TOKEN',
20
22
  /** Local directory laid out as `<run>/<step>/<attempt>/files/<object path>` (dev). Optional. */
21
- filesDir: "OLVE_FILES_DIR",
23
+ filesDir: 'OLVE_FILES_DIR',
22
24
  } as const;
23
25
 
24
26
  /** Env vars never passed to child processes (they carry credentials for the harness only). */
25
- export const PRIVATE_ENV: readonly string[] = [ENV.resultUrl, ENV.fileUrls, ENV.filesToken];
27
+ export const PRIVATE_ENV: readonly string[] = [
28
+ ENV.resultUrl,
29
+ ENV.fileUrls,
30
+ ENV.filesToken,
31
+ ENV.callbackUrls,
32
+ ];
26
33
 
27
- export const olveDir = () => process.env[ENV.dir] || "/olve";
34
+ /** `OLVE_CALLBACK_URLS`, parsed; empty when unset or malformed. */
35
+ export function callbackUrlsFromEnv(): Record<string, string> {
36
+ const raw = process.env[ENV.callbackUrls];
37
+ if (!raw) return {};
38
+ try {
39
+ const parsed: unknown = JSON.parse(raw);
40
+ return parsed && typeof parsed === 'object' ? (parsed as Record<string, string>) : {};
41
+ } catch {
42
+ return {};
43
+ }
44
+ }
45
+
46
+ export const olveDir = () => process.env[ENV.dir] || '/olve';
28
47
  export const paths = () => {
29
48
  const root = olveDir();
30
49
  return {
31
50
  root,
32
- input: join(root, "input.json"),
33
- work: join(root, "work"),
34
- output: join(root, "work", "output.json"),
35
- files: join(root, "work", "files"),
36
- tmp: join(root, "tmp"),
37
- fileUrls: join(root, "files.json"),
51
+ input: join(root, 'input.json'),
52
+ work: join(root, 'work'),
53
+ output: join(root, 'work', 'output.json'),
54
+ files: join(root, 'work', 'files'),
55
+ tmp: join(root, 'tmp'),
56
+ fileUrls: join(root, 'files.json'),
38
57
  };
39
58
  };
40
59
 
41
60
  function int(name: string, fallback: number): number {
42
61
  const v = process.env[name];
43
- if (v === undefined || v === "") return fallback;
62
+ if (v === undefined || v === '') return fallback;
44
63
  const n = Number(v);
45
- if (!Number.isInteger(n) || n < 0) throw new Error(`${name} must be a non-negative integer, got '${v}'`);
64
+ if (!Number.isInteger(n) || n < 0)
65
+ throw new Error(`${name} must be a non-negative integer, got '${v}'`);
46
66
  return n;
47
67
  }
48
68
 
49
69
  export function runInfoFromEnv(step: string) {
50
70
  return {
51
- pipeline: process.env[ENV.pipeline] ?? "local",
52
- id: process.env[ENV.runId] ?? "local",
71
+ pipeline: process.env[ENV.pipeline] ?? 'local',
72
+ id: process.env[ENV.runId] ?? 'local',
53
73
  number: int(ENV.run, 0),
54
74
  attempt: Math.max(1, int(ENV.attempt, 1)),
55
75
  step,
56
- version: process.env[ENV.versionStamp] ?? "0.0.0-local",
76
+ version: process.env[ENV.versionStamp] ?? '0.0.0-local',
57
77
  };
58
78
  }
@@ -1,20 +1,20 @@
1
1
  // The shared execution path: validate input → handler → validate output → envelope.
2
2
  // Used by the compiled harness (`run`), the dev runner and testHandler.
3
- import { existsSync } from "node:fs";
4
- import { join } from "node:path";
5
- import { isSkipped } from "../core/handlers.ts";
6
- import type { AnyStep } from "../core/steps.ts";
7
- import type { Ctx, RunInfo } from "../ctx/types.ts";
8
- import { objectPath } from "../ctx/files.ts";
9
- import { sha256File } from "../util/hash.ts";
10
- import { EXIT } from "./exit.ts";
11
- import { validateInput, validateOutput } from "./validate.ts";
3
+ import { existsSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { isSkipped } from '../core/handlers.ts';
6
+ import type { AnyStep } from '../core/steps.ts';
7
+ import type { Ctx, RunInfo } from '../ctx/types.ts';
8
+ import { objectPath } from '../ctx/files.ts';
9
+ import { sha256File } from '../util/hash.ts';
10
+ import { EXIT } from './exit.ts';
11
+ import { validateConfig, validateInput, validateOutput } from './validate.ts';
12
12
 
13
- export type FailureKind = "handler" | "input" | "output";
13
+ export type FailureKind = 'handler' | 'input' | 'output';
14
14
  export type Envelope =
15
- | { status: "succeeded"; output: unknown }
16
- | { status: "skipped"; reason: string }
17
- | { status: "failed"; error: { kind: FailureKind; message: string } };
15
+ | { status: 'succeeded'; output: unknown }
16
+ | { status: 'skipped'; reason: string }
17
+ | { status: 'failed'; error: { kind: FailureKind; message: string } };
18
18
 
19
19
  export interface Execution {
20
20
  envelope: Envelope;
@@ -26,7 +26,7 @@ export type StepFunction = (input: Record<string, unknown>, ctx: Ctx) => unknown
26
26
  /** Signal → exit code, when the handler failed after a cancellation. */
27
27
  export function cancelExitCode(signal: AbortSignal): number | undefined {
28
28
  if (!signal.aborted) return undefined;
29
- return signal.reason === "SIGINT" ? EXIT.sigint : EXIT.sigterm;
29
+ return signal.reason === 'SIGINT' ? EXIT.sigint : EXIT.sigterm;
30
30
  }
31
31
 
32
32
  const errorMessage = (e: unknown): string => (e instanceof Error ? e.message : String(e));
@@ -36,17 +36,29 @@ function checkOwnFileRefs(value: unknown, run: RunInfo, workFiles: string): stri
36
36
  const problems: string[] = [];
37
37
  const walk = (v: unknown, at: string) => {
38
38
  if (Array.isArray(v)) return v.forEach((x, i) => walk(x, `${at}[${i}]`));
39
- if (typeof v !== "object" || v === null) return;
39
+ if (typeof v !== 'object' || v === null) return;
40
40
  const o = v as Record<string, unknown>;
41
- if (typeof o.path === "string" && typeof o.sha256 === "string" && o.run === run.number && o.step === run.step && o.attempt === run.attempt) {
41
+ if (
42
+ typeof o.path === 'string' &&
43
+ typeof o.sha256 === 'string' &&
44
+ o.run === run.number &&
45
+ o.step === run.step &&
46
+ o.attempt === run.attempt
47
+ ) {
42
48
  const file = join(workFiles, objectPath(o.path));
43
- if (!existsSync(file)) problems.push(`${at}: file reference '${o.path}' points to this attempt but no such output file was produced`);
44
- else if (sha256File(file) !== o.sha256) problems.push(`${at}: file reference '${o.path}' has the wrong sha256 (the file changed after it was referenced)`);
49
+ if (!existsSync(file))
50
+ problems.push(
51
+ `${at}: file reference '${o.path}' points to this attempt but no such output file was produced`,
52
+ );
53
+ else if (sha256File(file) !== o.sha256)
54
+ problems.push(
55
+ `${at}: file reference '${o.path}' has the wrong sha256 (the file changed after it was referenced)`,
56
+ );
45
57
  return;
46
58
  }
47
59
  for (const [k, x] of Object.entries(o)) walk(x, `${at}.${k}`);
48
60
  };
49
- walk(value, "output");
61
+ walk(value, 'output');
50
62
  return problems;
51
63
  }
52
64
 
@@ -58,13 +70,22 @@ export async function executeStep(args: {
58
70
  workFiles: string;
59
71
  log: (line: string) => void;
60
72
  }): Promise<Execution> {
61
- const { step, ctx, log } = args;
73
+ const { step, log } = args;
62
74
  const input = validateInput(step, args.rawInput);
63
- if (!input.ok) {
64
- const message = `step '${step.name}': input does not match the step's inputs:\n ${input.issues.join("\n ")}`;
75
+ const config = validateConfig(step, args.rawInput);
76
+ if (!input.ok || !config.ok) {
77
+ const issues = [
78
+ ...(input.ok ? [] : input.issues),
79
+ ...(config.ok ? [] : config.issues),
80
+ ];
81
+ const message = `step '${step.name}': input does not match the step's inputs:\n ${issues.join('\n ')}`;
65
82
  log(message);
66
- return { envelope: { status: "failed", error: { kind: "input", message } }, exitCode: EXIT.inputInvalid };
83
+ return {
84
+ envelope: { status: 'failed', error: { kind: 'input', message } },
85
+ exitCode: EXIT.inputInvalid,
86
+ };
67
87
  }
88
+ const ctx: Ctx = { ...args.ctx, config: Object.freeze(config.value) as Ctx['config'] };
68
89
 
69
90
  let value: unknown;
70
91
  try {
@@ -76,19 +97,27 @@ export async function executeStep(args: {
76
97
  : `step '${step.name}' failed: ${errorMessage(e)}`;
77
98
  log(message);
78
99
  if (e instanceof Error && e.stack && !cancelled) log(e.stack);
79
- return { envelope: { status: "failed", error: { kind: "handler", message } }, exitCode: cancelled ?? EXIT.handlerFailed };
100
+ return {
101
+ envelope: { status: 'failed', error: { kind: 'handler', message } },
102
+ exitCode: cancelled ?? EXIT.handlerFailed,
103
+ };
80
104
  }
81
105
 
82
106
  if (isSkipped(value)) {
83
107
  log(`step '${step.name}' skipped: ${value.reason}`);
84
- return { envelope: { status: "skipped", reason: value.reason }, exitCode: EXIT.ok };
108
+ return { envelope: { status: 'skipped', reason: value.reason }, exitCode: EXIT.ok };
85
109
  }
86
110
  const out = validateOutput(step, value);
87
- const problems = out.ok ? checkOwnFileRefs(out.value, ctx.run, args.workFiles) : out.issues;
111
+ const problems = out.ok
112
+ ? checkOwnFileRefs(out.value, ctx.run, args.workFiles)
113
+ : out.issues;
88
114
  if (!out.ok || problems.length) {
89
- const message = `step '${step.name}': returned value does not match ${step.output?.name ?? "its (absent) output model"}:\n ${problems.join("\n ")}`;
115
+ const message = `step '${step.name}': returned value does not match ${step.output?.name ?? 'its (absent) output model'}:\n ${problems.join('\n ')}`;
90
116
  log(message);
91
- return { envelope: { status: "failed", error: { kind: "output", message } }, exitCode: EXIT.outputInvalid };
117
+ return {
118
+ envelope: { status: 'failed', error: { kind: 'output', message } },
119
+ exitCode: EXIT.outputInvalid,
120
+ };
92
121
  }
93
- return { envelope: { status: "succeeded", output: out.value }, exitCode: EXIT.ok };
122
+ return { envelope: { status: 'succeeded', output: out.value }, exitCode: EXIT.ok };
94
123
  }
@@ -1,9 +1,22 @@
1
- // @olve/pipelines/harness — the runtime the build tool compiles into the step binary.
2
- export { runHarness, defaultIO, allSteps, resolveStepFunction, type HarnessConfig, type HandlerRegistry, type HarnessIO } from "./main.ts";
3
- export { EXIT } from "./exit.ts";
4
- export { ENV, paths, runInfoFromEnv } from "./env.ts";
5
- export { executeStep, type Envelope, type Execution, type FailureKind } from "./execute.ts";
6
- export { RESULT_BEGIN, RESULT_END, MANIFEST_BEGIN, MANIFEST_END } from "./result.ts";
7
- export { describePipeline, DescribeError, manifestText } from "../describe/describe.ts";
8
- export type { ManifestT as Manifest } from "../describe/manifest-schema.ts";
9
- export type { HarnessInfo } from "../util/handler-hash.ts";
1
+ // @olivervea/pipelines/harness — the runtime the build tool compiles into the step binary.
2
+ export {
3
+ runHarness,
4
+ defaultIO,
5
+ allSteps,
6
+ resolveStepFunction,
7
+ type HarnessConfig,
8
+ type HandlerRegistry,
9
+ type HarnessIO,
10
+ } from './main.ts';
11
+ export { EXIT } from './exit.ts';
12
+ export { ENV, paths, runInfoFromEnv } from './env.ts';
13
+ export {
14
+ executeStep,
15
+ type Envelope,
16
+ type Execution,
17
+ type FailureKind,
18
+ } from './execute.ts';
19
+ export { RESULT_BEGIN, RESULT_END, MANIFEST_BEGIN, MANIFEST_END } from './result.ts';
20
+ export { describePipeline, DescribeError, manifestText } from '../describe/describe.ts';
21
+ export type { ManifestT as Manifest } from '../describe/manifest-schema.ts';
22
+ export type { HarnessInfo } from '../util/handler-hash.ts';