@olivervea/pipelines 2.0.0-beta.6 → 2.0.0-beta.7

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/README.md CHANGED
@@ -4,7 +4,7 @@ The [Olve.Pipelines](https://github.com/OliverVea/Olve.Pipelines) v2 SDK. It has
4
4
 
5
5
  - the **authoring API**: models, steps, handlers and the typed pipeline builder;
6
6
  - the **step harness**: the runtime compiled into each pipeline's single executable (`describe`, `run`, `map-trigger`);
7
- - the **build tool** (`olve-build`), which turns a pipeline directory into `step.tar.gz` and `manifest.json`;
7
+ - the **build tool** (`olve-build`), which turns a pipeline directory into `step.tar.zst` and `manifest.json`;
8
8
  - the **dev runner** (`olve-dev`), which runs the same harness path from source (used by `pl dev`).
9
9
 
10
10
  Design: [`docs/design/pipelines-v2.md`](https://github.com/OliverVea/Olve.Pipelines/blob/v2/docs/design/pipelines-v2.md). Spike findings: [`pipelines-v2-spikes.md`](https://github.com/OliverVea/Olve.Pipelines/blob/v2/docs/design/pipelines-v2-spikes.md).
@@ -418,8 +418,8 @@ olve-build <pipelineDir> --hash-only # print handler hashes (diagnostic
418
418
  3. Run `bun build --compile --target=bun-linux-x64 --no-compile-autoload-dotenv --no-compile-autoload-bunfig --bytecode --format=esm` → `<out>/step`. The output is never minified, because mapper source analysis needs real source.
419
419
  4. Check that `PT_INTERP` is `/lib64/ld-linux-x86-64.so.2`. On alpine, Bun silently produces a musl binary; the check fails it.
420
420
  5. Run `<out>/step describe` → `<out>/manifest.json`. A describe problem is a build failure with exit 78. **A custom step without a handler file is an error.**
421
- 6. Write `<out>/step.tar.gz` (deterministic, `step` at the root, mode 0755) and `<out>/build.json` (diagnostics).
422
- 7. With `--upload-url`, PUT `step.tar.gz`, using the same retry rules as the result upload. With `--sentinels`, print the manifest between the manifest sentinels.
421
+ 6. Write `<out>/step.tar.zst` (a deterministic tar, `step` at the root, mode 0755, zstd level 3: it unpacks in the step pod far faster than gzip; harness-base also still unpacks the gzip archives of older SDKs; from 2.0.0-beta.7 the SDK needs an instance whose harness-base unpacks zstd, i.e. one deployed on or after 2026-10-25) and `<out>/build.json` (diagnostics).
422
+ 7. With `--upload-url`, PUT `step.tar.zst`, using the same retry rules as the result upload. With `--sentinels`, print the manifest between the manifest sentinels.
423
423
 
424
424
  Exit codes: 0 ok, 1 build failure, 64 usage, 78 pipeline invalid.
425
425
 
@@ -435,7 +435,7 @@ From npm, nothing else is needed. A local `file:`/`link:` dependency (`"@oliverv
435
435
 
436
436
  The repo depends on the SDK as a normal package. It resolves through `exports` (`@olivervea/pipelines`, `@olivervea/pipelines/harness`, `@olivervea/pipelines/testing`), and the tests cover this with a `file:` install. `bun` must be on `PATH`, because the bins use `#!/usr/bin/env bun`. A consumer `tsconfig.json` has to include the dot-directory explicitly (`"include": [".pipelines/**/*.ts"]`), and should exclude `.pipelines/.olve`.
437
437
 
438
- How the service runs it (reconcile, `BuildJobBuilder`): one Job per (pipeline, config commit), named `olve-build-<pipeline12>-<sha12>`. The repo tarball comes from `codeload.github.com/<repo>/tar.gz/<sha>` anonymously (public repos), or from the GitHub API tarball endpoint with the binding's credentials key from the pipeline Secret. The binary is PUT to `versions/<pipeline>/builds/<sha>/step.tar.gz`, and a version added from that build keeps this key as its `BinaryKey`. The in-repo fixture `.pipelines-test/` (bound on v2 beta) uses exactly this layout.
438
+ How the service runs it (reconcile, `BuildJobBuilder`): one Job per (pipeline, config commit), named `olve-build-<pipeline12>-<sha12>`. The repo tarball comes from `codeload.github.com/<repo>/tar.gz/<sha>` anonymously (public repos), or from the GitHub API tarball endpoint with the binding's credentials key from the pipeline Secret. The archive is PUT to `versions/<pipeline>/builds/<sha>/step.tar.gz` (the key predates zstd; the init container tells the formats apart by content), and a version added from that build keeps this key as its `BinaryKey`. The in-repo fixture `.pipelines-test/` (bound on v2 beta) uses exactly this layout.
439
439
 
440
440
  The manifest is the text between the sentinels in the pod log. The manifest text is identical across checkouts. The binary and archive bytes are identical for the same checkout layout.
441
441
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olivervea/pipelines",
3
- "version": "2.0.0-beta.6",
3
+ "version": "2.0.0-beta.7",
4
4
  "description": "Olve.Pipelines v2 SDK: typed pipeline authoring, the step harness, and the build tool.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,10 +1,10 @@
1
- // olve-build: pipeline dir → single executable + step.tar.gz + manifest.json.
1
+ // olve-build: pipeline dir → single executable + step.tar.zst + manifest.json.
2
2
  import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { join, resolve } from "node:path";
4
4
  import { canonicalJson } from "../util/canonical.ts";
5
5
  import { sha256File } from "../util/hash.ts";
6
6
  import type { HarnessInfo } from "../util/handler-hash.ts";
7
- import { writeTarGz } from "../util/tar.ts";
7
+ import { writeTarZst } from "../util/tar.ts";
8
8
  import { MANIFEST_BEGIN, MANIFEST_END, uploadFile } from "../harness/result.ts";
9
9
  import { GLIBC_INTERP, MUSL_INTERP, readInterpreter } from "./elf.ts";
10
10
  import { handlerHashes, type HandlerHash } from "./hashes.ts";
@@ -23,7 +23,7 @@ export class BuildError extends Error {
23
23
  export interface BuildOptions {
24
24
  out: string;
25
25
  target?: Target;
26
- /** Pre-signed PUT for step.tar.gz. */
26
+ /** Pre-signed PUT for the step archive. */
27
27
  uploadUrl?: string;
28
28
  /** Print the manifest between sentinels on stdout (for the build Job's pod log). */
29
29
  sentinels?: boolean;
@@ -107,9 +107,9 @@ export async function build(dir: string, opts: BuildOptions): Promise<BuildResul
107
107
  const manifestFile = join(out, "manifest.json");
108
108
  writeFileSync(manifestFile, manifest);
109
109
 
110
- // 4. step.tar.gz (deterministic: `step` at the root, 0755, mtime 0)
111
- const archive = join(out, "step.tar.gz");
112
- await writeTarGz(archive, [{ path: "step", type: "file", mode: 0o755, source: binary }]);
110
+ // 4. step.tar.zst (deterministic: `step` at the root, 0755, mtime 0)
111
+ const archive = join(out, "step.tar.zst");
112
+ await writeTarZst(archive, [{ path: "step", type: "file", mode: 0o755, source: binary }]);
113
113
  writeFileSync(
114
114
  join(out, "build.json"),
115
115
  canonicalJson({ target, flags: BUILD_FLAGS, harness, handlers: hashes, binarySha256: sha256File(binary), archiveSha256: sha256File(archive) }),
@@ -118,7 +118,7 @@ export async function build(dir: string, opts: BuildOptions): Promise<BuildResul
118
118
 
119
119
  if (opts.uploadUrl) {
120
120
  await uploadFile(opts.uploadUrl, archive, log);
121
- log("olve-build: uploaded step.tar.gz");
121
+ log("olve-build: uploaded step.tar.zst");
122
122
  }
123
123
  if (opts.sentinels) await stdout(`${MANIFEST_BEGIN}\n${manifest}${MANIFEST_END}\n`);
124
124
  return { binary, archive, manifestFile, manifest, hashes, harness };
package/src/util/tar.ts CHANGED
@@ -147,6 +147,19 @@ export async function writeTarGz(out: string, entries: readonly TarEntry[], leve
147
147
  }
148
148
  }
149
149
 
150
+ /** Writes a deterministic zstd-compressed tar (level 3: fast to write, and unpacks far faster than gzip). */
151
+ export async function writeTarZst(out: string, entries: readonly TarEntry[], level = 3): Promise<void> {
152
+ const tar = `${out}.tar-tmp`;
153
+ const tmp = `${out}.partial`;
154
+ try {
155
+ writeTar(tar, entries);
156
+ await Bun.write(tmp, await Bun.zstdCompress(await Bun.file(tar).bytes(), { level }));
157
+ renameSync(tmp, out);
158
+ } finally {
159
+ rmSync(tar, { force: true });
160
+ }
161
+ }
162
+
150
163
  /** Extracts a tar or tar.gz file into `dir`. */
151
164
  export async function extractTar(archive: string, dir: string): Promise<void> {
152
165
  const a = new Bun.Archive(await Bun.file(archive).bytes());