@telorun/cli 0.73.0 → 0.75.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/dist/bundle/manifest-text.d.ts +28 -0
- package/dist/bundle/manifest-text.d.ts.map +1 -0
- package/dist/bundle/manifest-text.js +92 -0
- package/dist/bundle/manifest-text.js.map +1 -0
- package/dist/bundle/module-payload.d.ts +157 -0
- package/dist/bundle/module-payload.d.ts.map +1 -0
- package/dist/bundle/module-payload.js +273 -0
- package/dist/bundle/module-payload.js.map +1 -0
- package/dist/bundle/payload-drift.d.ts +14 -8
- package/dist/bundle/payload-drift.d.ts.map +1 -1
- package/dist/bundle/payload-drift.js +23 -3
- package/dist/bundle/payload-drift.js.map +1 -1
- package/dist/bundle/select-files.d.ts +16 -4
- package/dist/bundle/select-files.d.ts.map +1 -1
- package/dist/bundle/select-files.js +25 -7
- package/dist/bundle/select-files.js.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/publish.d.ts +7 -18
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +60 -250
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/release.d.ts +16 -0
- package/dist/commands/release.d.ts.map +1 -0
- package/dist/commands/release.js +376 -0
- package/dist/commands/release.js.map +1 -0
- package/dist/output.d.ts +40 -0
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +86 -2
- package/dist/output.js.map +1 -1
- package/dist/release/apply-plan.d.ts +38 -0
- package/dist/release/apply-plan.d.ts.map +1 -0
- package/dist/release/apply-plan.js +103 -0
- package/dist/release/apply-plan.js.map +1 -0
- package/dist/release/evidence.d.ts +56 -0
- package/dist/release/evidence.d.ts.map +1 -0
- package/dist/release/evidence.js +245 -0
- package/dist/release/evidence.js.map +1 -0
- package/dist/release/ledger-store.d.ts +27 -0
- package/dist/release/ledger-store.d.ts.map +1 -0
- package/dist/release/ledger-store.js +62 -0
- package/dist/release/ledger-store.js.map +1 -0
- package/dist/release/render.d.ts +17 -0
- package/dist/release/render.d.ts.map +1 -0
- package/dist/release/render.js +71 -0
- package/dist/release/render.js.map +1 -0
- package/dist/release/workspace.d.ts +58 -0
- package/dist/release/workspace.d.ts.map +1 -0
- package/dist/release/workspace.js +138 -0
- package/dist/release/workspace.js.map +1 -0
- package/package.json +6 -6
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading and rewriting a module's `telo.yaml` on the way to the artifact.
|
|
3
|
+
*
|
|
4
|
+
* These three transforms sit between the author's manifest and the published
|
|
5
|
+
* one, and both gates that care about the published bytes — `telo publish` and
|
|
6
|
+
* `telo release` — go through them. They were inside the publish command, which
|
|
7
|
+
* is where a second copy would have appeared the moment anything else needed to
|
|
8
|
+
* know what a module ships.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Resolve `include:` globs and inline each partial as an extra document, then
|
|
12
|
+
* drop the `include:` key.
|
|
13
|
+
*
|
|
14
|
+
* The declaring file does not exist in the artifact, which is why every
|
|
15
|
+
* module-relative path in a manifest is module-ROOT-relative rather than
|
|
16
|
+
* relative to the file it was written in.
|
|
17
|
+
*/
|
|
18
|
+
export declare function expandAndInlineIncludes(content: string, manifestDir: string): string;
|
|
19
|
+
/** The owner doc's `files:` globs — the payload set the manifest cannot
|
|
20
|
+
* otherwise name. Empty when none are declared. */
|
|
21
|
+
export declare function readFilesPatterns(content: string): string[];
|
|
22
|
+
/** The owner doc's `assets:` globs — the author-claimed subset of `files:` that
|
|
23
|
+
* ships in the lazily materialized asset layer. */
|
|
24
|
+
export declare function readAssetPatterns(content: string): string[];
|
|
25
|
+
/** The owner doc's `metadata.version` — the tag this artifact publishes under,
|
|
26
|
+
* and so the version every drift check compares against. */
|
|
27
|
+
export declare function readOwnerVersion(content: string): string | undefined;
|
|
28
|
+
//# sourceMappingURL=manifest-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-text.d.ts","sourceRoot":"","sources":["../../src/bundle/manifest-text.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAoDpF;AAED;oDACoD;AACpD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAE3D;AAED;oDACoD;AACpD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAE3D;AAED;6DAC6D;AAC7D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKpE"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading and rewriting a module's `telo.yaml` on the way to the artifact.
|
|
3
|
+
*
|
|
4
|
+
* These three transforms sit between the author's manifest and the published
|
|
5
|
+
* one, and both gates that care about the published bytes — `telo publish` and
|
|
6
|
+
* `telo release` — go through them. They were inside the publish command, which
|
|
7
|
+
* is where a second copy would have appeared the moment anything else needed to
|
|
8
|
+
* know what a module ships.
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from "node:fs";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
import { defaultCustomTags } from "@telorun/templating";
|
|
13
|
+
import { parseAllDocuments } from "yaml";
|
|
14
|
+
import { selectFiles } from "./select-files.js";
|
|
15
|
+
/**
|
|
16
|
+
* Resolve `include:` globs and inline each partial as an extra document, then
|
|
17
|
+
* drop the `include:` key.
|
|
18
|
+
*
|
|
19
|
+
* The declaring file does not exist in the artifact, which is why every
|
|
20
|
+
* module-relative path in a manifest is module-ROOT-relative rather than
|
|
21
|
+
* relative to the file it was written in.
|
|
22
|
+
*/
|
|
23
|
+
export function expandAndInlineIncludes(content, manifestDir) {
|
|
24
|
+
const docs = parseAllDocuments(content, { customTags: defaultCustomTags() });
|
|
25
|
+
const firstParsed = docs[0]?.toJSON();
|
|
26
|
+
if (!firstParsed || !Array.isArray(firstParsed.include) || firstParsed.include.length === 0) {
|
|
27
|
+
return content;
|
|
28
|
+
}
|
|
29
|
+
const patterns = firstParsed.include.filter((p) => typeof p === "string");
|
|
30
|
+
if (patterns.length === 0)
|
|
31
|
+
return content;
|
|
32
|
+
// A glob entry is matched with the shared `ignore` engine (gitignore
|
|
33
|
+
// semantics); a plain path is taken verbatim and validated to exist — an
|
|
34
|
+
// explicit `include:` of a missing file is an error, unlike a glob that
|
|
35
|
+
// simply matches nothing.
|
|
36
|
+
const hasGlobs = patterns.some((p) => /[*?{}\[\]!]/.test(p));
|
|
37
|
+
let resolvedFiles;
|
|
38
|
+
if (hasGlobs) {
|
|
39
|
+
resolvedFiles = selectFiles(manifestDir, patterns, { applyDefaultIgnore: false }).map((rel) => path.resolve(manifestDir, rel));
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
resolvedFiles = [...new Set(patterns.map((p) => path.resolve(manifestDir, p)))];
|
|
43
|
+
const realManifestDir = fs.realpathSync(manifestDir) + path.sep;
|
|
44
|
+
for (const filePath of resolvedFiles) {
|
|
45
|
+
if (!fs.existsSync(filePath)) {
|
|
46
|
+
throw new Error(`Included file not found: ${filePath}`);
|
|
47
|
+
}
|
|
48
|
+
const realPath = fs.realpathSync(filePath);
|
|
49
|
+
if (!realPath.startsWith(realManifestDir)) {
|
|
50
|
+
throw new Error(`Include path '${filePath}' resolves outside the module directory. ` +
|
|
51
|
+
`Publishing files from outside the module root is not allowed.`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
docs[0].deleteIn(["include"]);
|
|
56
|
+
let inlined = "";
|
|
57
|
+
for (const filePath of resolvedFiles) {
|
|
58
|
+
const partialContent = fs.readFileSync(filePath, "utf-8").trim();
|
|
59
|
+
if (!partialContent)
|
|
60
|
+
continue;
|
|
61
|
+
inlined += "\n---\n" + partialContent + "\n";
|
|
62
|
+
}
|
|
63
|
+
const serialized = docs.map((d) => d.toString()).join("---\n");
|
|
64
|
+
return serialized + inlined;
|
|
65
|
+
}
|
|
66
|
+
/** The owner doc's `files:` globs — the payload set the manifest cannot
|
|
67
|
+
* otherwise name. Empty when none are declared. */
|
|
68
|
+
export function readFilesPatterns(content) {
|
|
69
|
+
return readPatternField(content, "files");
|
|
70
|
+
}
|
|
71
|
+
/** The owner doc's `assets:` globs — the author-claimed subset of `files:` that
|
|
72
|
+
* ships in the lazily materialized asset layer. */
|
|
73
|
+
export function readAssetPatterns(content) {
|
|
74
|
+
return readPatternField(content, "assets");
|
|
75
|
+
}
|
|
76
|
+
/** The owner doc's `metadata.version` — the tag this artifact publishes under,
|
|
77
|
+
* and so the version every drift check compares against. */
|
|
78
|
+
export function readOwnerVersion(content) {
|
|
79
|
+
const docs = parseAllDocuments(content, { customTags: defaultCustomTags() });
|
|
80
|
+
const first = docs[0]?.toJSON();
|
|
81
|
+
const version = first?.metadata?.version;
|
|
82
|
+
return typeof version === "string" ? version : undefined;
|
|
83
|
+
}
|
|
84
|
+
function readPatternField(content, field) {
|
|
85
|
+
const docs = parseAllDocuments(content, { customTags: defaultCustomTags() });
|
|
86
|
+
const first = docs[0]?.toJSON();
|
|
87
|
+
const value = first?.[field];
|
|
88
|
+
if (!Array.isArray(value))
|
|
89
|
+
return [];
|
|
90
|
+
return value.filter((p) => typeof p === "string");
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=manifest-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-text.js","sourceRoot":"","sources":["../../src/bundle/manifest-text.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Building a module's published payload — the one computation both gates run.
|
|
3
|
+
*
|
|
4
|
+
* `telo publish` pushes it and `telo release` digests it, and they have to be
|
|
5
|
+
* the same bytes or the ledger's number and the registry's number are answers to
|
|
6
|
+
* different questions. So there is one builder, and the publish command consumes
|
|
7
|
+
* it rather than carrying its own copy of the transform.
|
|
8
|
+
*
|
|
9
|
+
* ## What makes the bytes a pure function of the commit
|
|
10
|
+
*
|
|
11
|
+
* Three inputs used to leak in, and each is closed here:
|
|
12
|
+
*
|
|
13
|
+
* 1. **Pins were discovered, not authored.** Publish fetched each remote
|
|
14
|
+
* dependency's published `telo.yaml` to derive its hash, best-effort — so one
|
|
15
|
+
* commit produced different manifest bytes depending on network reachability.
|
|
16
|
+
* An author's pin is now the input: `telo install` / `telo upgrade` write it,
|
|
17
|
+
* and an unpinned remote import is refused here rather than resolved.
|
|
18
|
+
* 2. **Re-serialization was conditional** on at least one pin having been
|
|
19
|
+
* written, so the same manifest serialized two ways depending on its own
|
|
20
|
+
* content. It is unconditional now.
|
|
21
|
+
* 3. **A sibling's pin came from the registry.** An in-repo sibling is on disk,
|
|
22
|
+
* so its published manifest is *derived* — recursively, through this same
|
|
23
|
+
* builder — which is what lets a whole release batch be planned offline, with
|
|
24
|
+
* post-bump versions the registry has never seen.
|
|
25
|
+
*
|
|
26
|
+
* The publish destination stays an input, because canonicalization writes it
|
|
27
|
+
* into the manifest. It is not derivable, so the ledger records which base its
|
|
28
|
+
* digests were taken against.
|
|
29
|
+
*/
|
|
30
|
+
import { type ArtifactSelector, type LayerRole } from "@telorun/analyzer";
|
|
31
|
+
import { type PayloadFile } from "@telorun/kernel";
|
|
32
|
+
import { type Partition } from "./partition-layers.js";
|
|
33
|
+
/** A layer built from a working copy: what publish pushes and what the release
|
|
34
|
+
* ledger digests. Mutable-shaped because the transport's own `PayloadLayer` is,
|
|
35
|
+
* and the two are handed straight across. */
|
|
36
|
+
export interface BuiltLayer {
|
|
37
|
+
role: LayerRole;
|
|
38
|
+
selector?: ArtifactSelector;
|
|
39
|
+
files: PayloadFile[];
|
|
40
|
+
}
|
|
41
|
+
export interface ModulePayload {
|
|
42
|
+
/** The `telo.yaml` that ships: canonicalized, pinned, includes inlined. */
|
|
43
|
+
readonly manifest: string;
|
|
44
|
+
readonly layers: BuiltLayer[];
|
|
45
|
+
readonly partition: Partition;
|
|
46
|
+
/**
|
|
47
|
+
* Absolute paths of every file the controller builds read — the module's own
|
|
48
|
+
* sources, the shared libraries they inline, their dependency tree. The
|
|
49
|
+
* release edge graph is built from these; nothing else can see what a bundle
|
|
50
|
+
* actually contains.
|
|
51
|
+
*/
|
|
52
|
+
readonly buildInputs: readonly string[];
|
|
53
|
+
/**
|
|
54
|
+
* In-repo siblings this module imports relatively: the sibling's absolute
|
|
55
|
+
* manifest path (the release edge) and the ref the import canonicalized to
|
|
56
|
+
* (which publish checks resolves at its published location before pushing).
|
|
57
|
+
*/
|
|
58
|
+
readonly relativeImports: readonly {
|
|
59
|
+
readonly manifestPath: string;
|
|
60
|
+
readonly ref: string;
|
|
61
|
+
}[];
|
|
62
|
+
/**
|
|
63
|
+
* Remote imports carrying an author-written pin, already split into the ref
|
|
64
|
+
* and the hash it claims.
|
|
65
|
+
*
|
|
66
|
+
* Split HERE because this is the only place both spellings are in hand: a
|
|
67
|
+
* scalar-form pin carries its hash as a `#sha256-…` fragment on the source,
|
|
68
|
+
* and the object form carries it as an `integrity:` sibling. A consumer handed
|
|
69
|
+
* only the ref can recover the first by re-splitting and the second not at all
|
|
70
|
+
* — which is exactly how the verification below came to be a silent no-op for
|
|
71
|
+
* every pin in this repo.
|
|
72
|
+
*
|
|
73
|
+
* Publish verifies these against the registry — fetch, compare, hard-fail on
|
|
74
|
+
* mismatch. A sibling-derived pin is deliberately not here: it was computed
|
|
75
|
+
* from local bytes the registry has not seen yet, and the batch pushes
|
|
76
|
+
* dependencies first precisely so it does not have to have.
|
|
77
|
+
*/
|
|
78
|
+
readonly authoredPins: readonly {
|
|
79
|
+
readonly alias: string;
|
|
80
|
+
/** The ref with no integrity fragment — what the registry is asked for. */
|
|
81
|
+
readonly ref: string;
|
|
82
|
+
/** The hash the author committed. */
|
|
83
|
+
readonly integrity: string;
|
|
84
|
+
}[];
|
|
85
|
+
}
|
|
86
|
+
export interface PayloadBuilderOptions {
|
|
87
|
+
/** The read-only registry origin `registry://` refs resolve against. Not the
|
|
88
|
+
* publish destination, which is per module and passed to `payload()`. */
|
|
89
|
+
readonly registryOrigin?: string;
|
|
90
|
+
/** Where the controller build cache lives. */
|
|
91
|
+
readonly cacheRoot: string;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* One module's payload, memoized across a batch.
|
|
95
|
+
*
|
|
96
|
+
* Memoized because a release digests every module in a workspace and the
|
|
97
|
+
* standard library's import graph is dense — `modules/sql`'s published manifest
|
|
98
|
+
* is needed by five dependents to derive their pins, and re-deriving it per
|
|
99
|
+
* dependent would rebuild its controller each time.
|
|
100
|
+
*/
|
|
101
|
+
export declare class ModulePayloadBuilder {
|
|
102
|
+
private readonly options;
|
|
103
|
+
private readonly manifests;
|
|
104
|
+
private readonly payloads;
|
|
105
|
+
/** Manifest paths currently being derived, so an import cycle is reported
|
|
106
|
+
* rather than overflowing the stack. */
|
|
107
|
+
private readonly deriving;
|
|
108
|
+
/**
|
|
109
|
+
* Where each manifest publishes.
|
|
110
|
+
*
|
|
111
|
+
* A ROOT's destination is an input — which repo a module publishes to is a
|
|
112
|
+
* policy no graph can answer, so the caller states it (the release derives it
|
|
113
|
+
* as `<base>/<directory name>`, the rule the OCI mirror has always used).
|
|
114
|
+
*
|
|
115
|
+
* A SIBLING's is *derived*: the parent's destination with the relative path
|
|
116
|
+
* applied, which is the transport's own rule and exactly what canonicalization
|
|
117
|
+
* writes into the manifest. That one is not a free choice — deriving it
|
|
118
|
+
* independently, from the directory name say, would work for this repo's
|
|
119
|
+
* layout and quietly disagree with the ref the artifact actually carries the
|
|
120
|
+
* moment a layout differs.
|
|
121
|
+
*
|
|
122
|
+
* When a module is reached both ways and the two answers differ,
|
|
123
|
+
* `claimDestination` refuses rather than picking one, because the manifest can
|
|
124
|
+
* only carry a single ref.
|
|
125
|
+
*/
|
|
126
|
+
private readonly destinations;
|
|
127
|
+
constructor(options: PayloadBuilderOptions);
|
|
128
|
+
payload(manifestPath: string, destination: string): Promise<ModulePayload>;
|
|
129
|
+
/**
|
|
130
|
+
* The in-repo siblings this module imports relatively, without building a
|
|
131
|
+
* single controller.
|
|
132
|
+
*
|
|
133
|
+
* Publish ORDER needs only this — a dependency must be pushed before its
|
|
134
|
+
* dependents, because canonicalization writes the sibling's ref into the
|
|
135
|
+
* manifest and publish then hard-fails when it does not resolve — and running
|
|
136
|
+
* esbuild across the whole standard library to answer it would be minutes of
|
|
137
|
+
* work for a question the manifests already contain.
|
|
138
|
+
*/
|
|
139
|
+
relativeImportsOf(manifestPath: string, destination: string): Promise<readonly {
|
|
140
|
+
manifestPath: string;
|
|
141
|
+
ref: string;
|
|
142
|
+
}[]>;
|
|
143
|
+
/** The published `telo.yaml` text alone — what a dependent needs to derive its
|
|
144
|
+
* pin, without building the dependency's controller layers. */
|
|
145
|
+
publishedManifest(manifestPath: string): Promise<string>;
|
|
146
|
+
private claimDestination;
|
|
147
|
+
private destinationOf;
|
|
148
|
+
private deriveManifest;
|
|
149
|
+
/**
|
|
150
|
+
* Canonicalize, pin and inline — every rewrite that stands between the
|
|
151
|
+
* author's `telo.yaml` and the published one.
|
|
152
|
+
*/
|
|
153
|
+
private transformManifest;
|
|
154
|
+
private siblingHash;
|
|
155
|
+
private buildPayload;
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=module-payload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-payload.d.ts","sourceRoot":"","sources":["../../src/bundle/module-payload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAKL,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAmD,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAOpG,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGxE;;8CAE8C;AAC9C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,eAAe,EAAE,SAAS;QACjC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;KACtB,EAAE,CAAC;IACJ;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,YAAY,EAAE,SAAS;QAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,2EAA2E;QAC3E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,qCAAqC;QACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;KAC5B,EAAE,CAAC;CACL;AAED,MAAM,WAAW,qBAAqB;IACpC;8EAC0E;IAC1E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,qBAAa,oBAAoB;IA2BnB,OAAO,CAAC,QAAQ,CAAC,OAAO;IA1BpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsC;IAChE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6C;IACtE;6CACyC;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAE9C;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;gBAE7B,OAAO,EAAE,qBAAqB;IAErD,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAUhF;;;;;;;;;OASG;IACG,iBAAiB,CACrB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,SAAS;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAM5D;oEACgE;IAC1D,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgB9D,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,aAAa;YAQP,cAAc;IAK5B;;;OAGG;YACW,iBAAiB;YAqEjB,WAAW;YAKX,YAAY;CA6D3B"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Building a module's published payload — the one computation both gates run.
|
|
3
|
+
*
|
|
4
|
+
* `telo publish` pushes it and `telo release` digests it, and they have to be
|
|
5
|
+
* the same bytes or the ledger's number and the registry's number are answers to
|
|
6
|
+
* different questions. So there is one builder, and the publish command consumes
|
|
7
|
+
* it rather than carrying its own copy of the transform.
|
|
8
|
+
*
|
|
9
|
+
* ## What makes the bytes a pure function of the commit
|
|
10
|
+
*
|
|
11
|
+
* Three inputs used to leak in, and each is closed here:
|
|
12
|
+
*
|
|
13
|
+
* 1. **Pins were discovered, not authored.** Publish fetched each remote
|
|
14
|
+
* dependency's published `telo.yaml` to derive its hash, best-effort — so one
|
|
15
|
+
* commit produced different manifest bytes depending on network reachability.
|
|
16
|
+
* An author's pin is now the input: `telo install` / `telo upgrade` write it,
|
|
17
|
+
* and an unpinned remote import is refused here rather than resolved.
|
|
18
|
+
* 2. **Re-serialization was conditional** on at least one pin having been
|
|
19
|
+
* written, so the same manifest serialized two ways depending on its own
|
|
20
|
+
* content. It is unconditional now.
|
|
21
|
+
* 3. **A sibling's pin came from the registry.** An in-repo sibling is on disk,
|
|
22
|
+
* so its published manifest is *derived* — recursively, through this same
|
|
23
|
+
* builder — which is what lets a whole release batch be planned offline, with
|
|
24
|
+
* post-bump versions the registry has never seen.
|
|
25
|
+
*
|
|
26
|
+
* The publish destination stays an input, because canonicalization writes it
|
|
27
|
+
* into the manifest. It is not derivable, so the ledger records which base its
|
|
28
|
+
* digests were taken against.
|
|
29
|
+
*/
|
|
30
|
+
import { collectModuleFileClaims, DEFAULT_MANIFEST_FILENAME, sha256Base64Url, splitIntegrity, } from "@telorun/analyzer";
|
|
31
|
+
import { buildControllerBundle, defaultTransportRegistry } from "@telorun/kernel";
|
|
32
|
+
import { defaultCustomTags } from "@telorun/templating";
|
|
33
|
+
import * as fs from "node:fs";
|
|
34
|
+
import * as path from "node:path";
|
|
35
|
+
import { parseAllDocuments } from "yaml";
|
|
36
|
+
import { findModuleDoc, importSourceRefs } from "../commands/manifest-imports.js";
|
|
37
|
+
import { expandAndInlineIncludes, readAssetPatterns, readFilesPatterns } from "./manifest-text.js";
|
|
38
|
+
import { partitionLayers } from "./partition-layers.js";
|
|
39
|
+
import { assertWithinModule, selectFiles } from "./select-files.js";
|
|
40
|
+
/**
|
|
41
|
+
* One module's payload, memoized across a batch.
|
|
42
|
+
*
|
|
43
|
+
* Memoized because a release digests every module in a workspace and the
|
|
44
|
+
* standard library's import graph is dense — `modules/sql`'s published manifest
|
|
45
|
+
* is needed by five dependents to derive their pins, and re-deriving it per
|
|
46
|
+
* dependent would rebuild its controller each time.
|
|
47
|
+
*/
|
|
48
|
+
export class ModulePayloadBuilder {
|
|
49
|
+
options;
|
|
50
|
+
manifests = new Map();
|
|
51
|
+
payloads = new Map();
|
|
52
|
+
/** Manifest paths currently being derived, so an import cycle is reported
|
|
53
|
+
* rather than overflowing the stack. */
|
|
54
|
+
deriving = new Set();
|
|
55
|
+
/**
|
|
56
|
+
* Where each manifest publishes.
|
|
57
|
+
*
|
|
58
|
+
* A ROOT's destination is an input — which repo a module publishes to is a
|
|
59
|
+
* policy no graph can answer, so the caller states it (the release derives it
|
|
60
|
+
* as `<base>/<directory name>`, the rule the OCI mirror has always used).
|
|
61
|
+
*
|
|
62
|
+
* A SIBLING's is *derived*: the parent's destination with the relative path
|
|
63
|
+
* applied, which is the transport's own rule and exactly what canonicalization
|
|
64
|
+
* writes into the manifest. That one is not a free choice — deriving it
|
|
65
|
+
* independently, from the directory name say, would work for this repo's
|
|
66
|
+
* layout and quietly disagree with the ref the artifact actually carries the
|
|
67
|
+
* moment a layout differs.
|
|
68
|
+
*
|
|
69
|
+
* When a module is reached both ways and the two answers differ,
|
|
70
|
+
* `claimDestination` refuses rather than picking one, because the manifest can
|
|
71
|
+
* only carry a single ref.
|
|
72
|
+
*/
|
|
73
|
+
destinations = new Map();
|
|
74
|
+
constructor(options) {
|
|
75
|
+
this.options = options;
|
|
76
|
+
}
|
|
77
|
+
async payload(manifestPath, destination) {
|
|
78
|
+
const key = path.resolve(manifestPath);
|
|
79
|
+
this.claimDestination(key, destination);
|
|
80
|
+
const existing = this.payloads.get(key);
|
|
81
|
+
if (existing)
|
|
82
|
+
return existing;
|
|
83
|
+
const work = this.buildPayload(key);
|
|
84
|
+
this.payloads.set(key, work);
|
|
85
|
+
return work;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The in-repo siblings this module imports relatively, without building a
|
|
89
|
+
* single controller.
|
|
90
|
+
*
|
|
91
|
+
* Publish ORDER needs only this — a dependency must be pushed before its
|
|
92
|
+
* dependents, because canonicalization writes the sibling's ref into the
|
|
93
|
+
* manifest and publish then hard-fails when it does not resolve — and running
|
|
94
|
+
* esbuild across the whole standard library to answer it would be minutes of
|
|
95
|
+
* work for a question the manifests already contain.
|
|
96
|
+
*/
|
|
97
|
+
async relativeImportsOf(manifestPath, destination) {
|
|
98
|
+
const key = path.resolve(manifestPath);
|
|
99
|
+
this.claimDestination(key, destination);
|
|
100
|
+
return (await this.transformManifest(key)).relativeImports;
|
|
101
|
+
}
|
|
102
|
+
/** The published `telo.yaml` text alone — what a dependent needs to derive its
|
|
103
|
+
* pin, without building the dependency's controller layers. */
|
|
104
|
+
async publishedManifest(manifestPath) {
|
|
105
|
+
const key = path.resolve(manifestPath);
|
|
106
|
+
const existing = this.manifests.get(key);
|
|
107
|
+
if (existing)
|
|
108
|
+
return existing;
|
|
109
|
+
if (this.deriving.has(key)) {
|
|
110
|
+
throw new Error(`Import cycle through '${key}': a module's published manifest embeds a hash of its ` +
|
|
111
|
+
`dependency's, so a cycle has no fixed point.`);
|
|
112
|
+
}
|
|
113
|
+
this.deriving.add(key);
|
|
114
|
+
const work = this.deriveManifest(key).finally(() => this.deriving.delete(key));
|
|
115
|
+
this.manifests.set(key, work);
|
|
116
|
+
return work;
|
|
117
|
+
}
|
|
118
|
+
claimDestination(manifestPath, destination) {
|
|
119
|
+
const existing = this.destinations.get(manifestPath);
|
|
120
|
+
if (existing && existing !== destination) {
|
|
121
|
+
throw new Error(`'${manifestPath}' is being published to both '${existing}' and '${destination}'. ` +
|
|
122
|
+
`A module's destination is part of its published bytes — canonicalization writes it ` +
|
|
123
|
+
`into every relative import — so it cannot be two things in one batch.`);
|
|
124
|
+
}
|
|
125
|
+
this.destinations.set(manifestPath, destination);
|
|
126
|
+
}
|
|
127
|
+
destinationOf(manifestPath) {
|
|
128
|
+
const destination = this.destinations.get(manifestPath);
|
|
129
|
+
if (!destination) {
|
|
130
|
+
throw new Error(`no publish destination is known for '${manifestPath}'.`);
|
|
131
|
+
}
|
|
132
|
+
return destination;
|
|
133
|
+
}
|
|
134
|
+
async deriveManifest(manifestPath) {
|
|
135
|
+
const { text } = await this.transformManifest(manifestPath);
|
|
136
|
+
return text;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Canonicalize, pin and inline — every rewrite that stands between the
|
|
140
|
+
* author's `telo.yaml` and the published one.
|
|
141
|
+
*/
|
|
142
|
+
async transformManifest(manifestPath) {
|
|
143
|
+
const manifestDir = path.dirname(manifestPath);
|
|
144
|
+
const original = fs.readFileSync(manifestPath, "utf8");
|
|
145
|
+
const docs = parseAllDocuments(original, { customTags: defaultCustomTags() });
|
|
146
|
+
const moduleDoc = findModuleDoc(docs);
|
|
147
|
+
const relativeImports = [];
|
|
148
|
+
const authoredPins = [];
|
|
149
|
+
if (moduleDoc) {
|
|
150
|
+
const destination = this.destinationOf(manifestPath);
|
|
151
|
+
const transport = defaultTransportRegistry(this.options.registryOrigin).forRef(destination);
|
|
152
|
+
if (!transport) {
|
|
153
|
+
throw new Error(`no transport owns publish destination '${destination}'`);
|
|
154
|
+
}
|
|
155
|
+
for (const entry of importSourceRefs(moduleDoc)) {
|
|
156
|
+
const source = entry.source;
|
|
157
|
+
if (!source.startsWith(".") && !source.startsWith("/")) {
|
|
158
|
+
// A remote import. Its pin is authored state — the deliberate
|
|
159
|
+
// statement "I am not affected until I choose to be" — so publishing
|
|
160
|
+
// reads it and never invents one. Refusing an unpinned ref is what
|
|
161
|
+
// keeps the bytes a function of the commit; it used to be resolved
|
|
162
|
+
// over the network, or silently shipped unpinned when that failed.
|
|
163
|
+
const { base, integrity } = splitIntegrity(source);
|
|
164
|
+
const declared = integrity ?? entry.integrity;
|
|
165
|
+
if (declared) {
|
|
166
|
+
authoredPins.push({ alias: entry.alias, ref: base, integrity: declared });
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
throw new Error(`import '${entry.alias}' points at '${source}' with no integrity pin. ` +
|
|
170
|
+
`A pin is written when the dependency is added or moved — run ` +
|
|
171
|
+
`\`telo install\` or \`telo upgrade\` in ${path.basename(manifestDir)} — so that ` +
|
|
172
|
+
`what this artifact embeds is decided by its author rather than by whatever the ` +
|
|
173
|
+
`registry happened to serve at publish time.`);
|
|
174
|
+
}
|
|
175
|
+
const siblingManifest = resolveSiblingManifest(manifestDir, source);
|
|
176
|
+
const version = readSiblingVersion(siblingManifest, source);
|
|
177
|
+
const ref = transport.canonicalizeSiblingRef(destination, source, version);
|
|
178
|
+
relativeImports.push({ manifestPath: siblingManifest, ref });
|
|
179
|
+
this.claimDestination(siblingManifest, transport.source.resolveRelative(destination, source));
|
|
180
|
+
// The sibling's pin comes from the sibling's own published bytes, in
|
|
181
|
+
// topological order — never from the registry, which has not seen the
|
|
182
|
+
// post-bump version this batch is planning.
|
|
183
|
+
const hash = await this.siblingHash(siblingManifest);
|
|
184
|
+
moduleDoc.setIn(entry.path, `${ref}#${hash}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Unconditional. Whether a manifest was rewritten is a property of its own
|
|
188
|
+
// content, and letting it decide the serializer meant one commit produced two
|
|
189
|
+
// different byte sequences for the same document.
|
|
190
|
+
const canonical = docs.map((doc) => doc.toString()).join("---\n");
|
|
191
|
+
return {
|
|
192
|
+
text: expandAndInlineIncludes(canonical, manifestDir),
|
|
193
|
+
relativeImports,
|
|
194
|
+
authoredPins,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async siblingHash(siblingManifest) {
|
|
198
|
+
const published = await this.publishedManifest(siblingManifest);
|
|
199
|
+
return `sha256-${await sha256Base64Url(new TextEncoder().encode(published))}`;
|
|
200
|
+
}
|
|
201
|
+
async buildPayload(manifestPath) {
|
|
202
|
+
const manifestDir = path.dirname(manifestPath);
|
|
203
|
+
const { text: manifest, relativeImports, authoredPins } = await this.transformManifest(manifestPath);
|
|
204
|
+
const claims = collectModuleFileClaims(manifest);
|
|
205
|
+
const partition = partitionLayers(claims, selectFiles(manifestDir, readFilesPatterns(manifest)), readAssetPatterns(manifest));
|
|
206
|
+
// Controller entry points are BUILT, not read: `path=` names a gitignored
|
|
207
|
+
// artifact that may not exist at all on a fresh clone, and reading a stale
|
|
208
|
+
// one would digest and ship bytes other than the source the manifest says
|
|
209
|
+
// they came from.
|
|
210
|
+
//
|
|
211
|
+
// This runs BEFORE the payload guard, because the guard's job is to reject a
|
|
212
|
+
// file that will not be there when the artifact is read — and an entry point
|
|
213
|
+
// this loop just produced WILL be there. Checking first was a latent break:
|
|
214
|
+
// on a checkout with no `.mjs` files, publish refused before the builder ran
|
|
215
|
+
// and told the author to run a build step this design removed.
|
|
216
|
+
const built = new Map();
|
|
217
|
+
const buildInputs = new Set();
|
|
218
|
+
for (const claim of claims) {
|
|
219
|
+
if (claim.role !== "controller" || !claim.localPath)
|
|
220
|
+
continue;
|
|
221
|
+
const entry = path.resolve(manifestDir, claim.localPath);
|
|
222
|
+
if (!fs.existsSync(entry)) {
|
|
223
|
+
throw new Error(`controller source '${claim.localPath}' does not exist (from ${claim.origin}).`);
|
|
224
|
+
}
|
|
225
|
+
const bundle = await buildControllerBundle(entry, this.options.cacheRoot);
|
|
226
|
+
built.set(claim.path, fs.readFileSync(bundle.path));
|
|
227
|
+
for (const input of bundle.inputs)
|
|
228
|
+
buildInputs.add(input);
|
|
229
|
+
}
|
|
230
|
+
assertWithinModule(manifestDir, partition.layers.flatMap((layer) => layer.files), new Set(built.keys()));
|
|
231
|
+
const layers = partition.layers.map((layer) => ({
|
|
232
|
+
role: layer.role,
|
|
233
|
+
...(layer.selector ? { selector: layer.selector } : {}),
|
|
234
|
+
files: layer.files.map((rel) => ({
|
|
235
|
+
name: rel,
|
|
236
|
+
content: built.get(rel) ?? fs.readFileSync(path.resolve(manifestDir, rel)),
|
|
237
|
+
})),
|
|
238
|
+
}));
|
|
239
|
+
return {
|
|
240
|
+
manifest,
|
|
241
|
+
layers,
|
|
242
|
+
partition,
|
|
243
|
+
buildInputs: [...buildInputs],
|
|
244
|
+
relativeImports,
|
|
245
|
+
authoredPins,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/** A relative `imports:` source resolved to the sibling's `telo.yaml`. */
|
|
250
|
+
function resolveSiblingManifest(manifestDir, source) {
|
|
251
|
+
const resolved = path.resolve(manifestDir, source);
|
|
252
|
+
try {
|
|
253
|
+
if (fs.statSync(resolved).isDirectory()) {
|
|
254
|
+
return path.join(resolved, DEFAULT_MANIFEST_FILENAME);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
throw new Error(`import source '${source}' does not resolve to a file or directory on disk.`);
|
|
259
|
+
}
|
|
260
|
+
return resolved;
|
|
261
|
+
}
|
|
262
|
+
function readSiblingVersion(siblingManifest, source) {
|
|
263
|
+
const first = parseAllDocuments(fs.readFileSync(siblingManifest, "utf8"), {
|
|
264
|
+
customTags: defaultCustomTags(),
|
|
265
|
+
})[0]?.toJSON();
|
|
266
|
+
const version = first?.metadata?.version;
|
|
267
|
+
if (typeof version !== "string") {
|
|
268
|
+
throw new Error(`import source '${source}' (resolved: '${siblingManifest}') has no metadata.version, ` +
|
|
269
|
+
`which is what a canonicalized ref names it by.`);
|
|
270
|
+
}
|
|
271
|
+
return version;
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=module-payload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-payload.js","sourceRoot":"","sources":["../../src/bundle/module-payload.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type PayloadFile } from "@telorun/kernel";
|
|
1
|
+
import { type LayerDigests } from "@telorun/analyzer";
|
|
3
2
|
/**
|
|
4
3
|
* Does the payload we are about to publish differ from what is already published
|
|
5
4
|
* at this `metadata.version`?
|
|
@@ -27,18 +26,25 @@ export interface LayerDrift {
|
|
|
27
26
|
* the build no longer produces this layer. */
|
|
28
27
|
built?: string;
|
|
29
28
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
import type { BuiltLayer } from "./module-payload.js";
|
|
30
|
+
export type { BuiltLayer };
|
|
31
|
+
/**
|
|
32
|
+
* The per-layer integrity the registry serves at `<destination>@<version>`, or
|
|
33
|
+
* `null` when nothing is published there.
|
|
34
|
+
*
|
|
35
|
+
* The **registry's own numbers**, read off the published `layers:` index rather
|
|
36
|
+
* than recomputed from anything local. That is what makes it the authority half
|
|
37
|
+
* of the ledger's cache: `telo release verify` compares the committed digests
|
|
38
|
+
* against these, and `--write` records these.
|
|
39
|
+
*/
|
|
40
|
+
export declare function readPublishedDigests(destination: string, version: string, registry: string): Promise<LayerDigests | null>;
|
|
35
41
|
/**
|
|
36
42
|
* Compare the built payload against the published one at the same version.
|
|
37
43
|
*
|
|
38
44
|
* Returns `null` when nothing is published at that ref — a new version, so there
|
|
39
45
|
* is nothing to disagree with. Returns an empty array when the payloads match.
|
|
40
46
|
*/
|
|
41
|
-
export declare function findPayloadDrift(destination: string, version: string, built: BuiltLayer[], registry: string): Promise<LayerDrift[] | null>;
|
|
47
|
+
export declare function findPayloadDrift(destination: string, version: string, built: readonly BuiltLayer[], registry: string): Promise<LayerDrift[] | null>;
|
|
42
48
|
/** The message shown when the gate fires. It names the version to bump, because
|
|
43
49
|
* that — not a re-push — is the fix: overwriting a published tag would change
|
|
44
50
|
* what an existing pinned import resolves to. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payload-drift.d.ts","sourceRoot":"","sources":["../../src/bundle/payload-drift.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"payload-drift.d.ts","sourceRoot":"","sources":["../../src/bundle/payload-drift.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAI3B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;+EAC2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;mDAC+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,UAAU,EAAE,CAAC;AA2D3B;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAQ9B;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,CA6B9B;AAED;;kDAEkD;AAClD,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAe7F"}
|