@telorun/cli 0.61.0 → 0.63.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/README.md +19 -4
- package/dist/bundle/partition-layers.d.ts +4 -2
- package/dist/bundle/partition-layers.d.ts.map +1 -1
- package/dist/bundle/partition-layers.js +13 -14
- package/dist/bundle/partition-layers.js.map +1 -1
- package/dist/bundle/payload-drift.d.ts +46 -0
- package/dist/bundle/payload-drift.d.ts.map +1 -0
- package/dist/bundle/payload-drift.js +109 -0
- package/dist/bundle/payload-drift.js.map +1 -0
- package/dist/bundle/select-files.d.ts +13 -0
- package/dist/bundle/select-files.d.ts.map +1 -1
- package/dist/bundle/select-files.js +27 -4
- package/dist/bundle/select-files.js.map +1 -1
- package/dist/commands/check.d.ts +1 -0
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +136 -10
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/manifest-imports.d.ts.map +1 -1
- package/dist/commands/manifest-imports.js +2 -2
- package/dist/commands/manifest-imports.js.map +1 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +51 -7
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +149 -30
- package/dist/commands/run.js.map +1 -1
- package/dist/logger.d.ts +5 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +55 -26
- package/dist/logger.js.map +1 -1
- package/dist/manifest-freshness.d.ts +120 -0
- package/dist/manifest-freshness.d.ts.map +1 -0
- package/dist/manifest-freshness.js +261 -0
- package/dist/manifest-freshness.js.map +1 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -122,6 +122,15 @@ telo check https://example.com/manifest.yaml
|
|
|
122
122
|
|
|
123
123
|
Accepts local paths, directories containing a `telo.yaml`, or HTTP(S) URLs.
|
|
124
124
|
|
|
125
|
+
Imports resolve through the same `.telo/manifests/` cache `telo run` reads, and `check` writes through to it after a successful load (disable with `--no-cache-write`). Freshness depends on how the import addresses its target:
|
|
126
|
+
|
|
127
|
+
- **Pinned** (`…@1.2.3#sha256-…`, or an `@sha256:` reference) — verified against the hash on read, so a repeat check of a fully pinned manifest needs no network at all.
|
|
128
|
+
- **Mutable OCI tag** — revalidated with one `HEAD` per reference against the digest recorded in `.telo/manifests/.origins.json`. If the tag has moved, that entry is dropped and refetched.
|
|
129
|
+
- **Registry ref** (`<namespace>/<name>@<version>`) — served from cache without revalidation; a published version is immutable by convention.
|
|
130
|
+
- **HTTP(S) URL** — never read from the cache by `check`, since its key carries no version segment and a hit would be served indefinitely. Always re-fetched (one request, the same cost revalidating would have).
|
|
131
|
+
|
|
132
|
+
One loader serves every path in a single invocation, so `telo check a b c` resolves a module shared between them once.
|
|
133
|
+
|
|
125
134
|
**Example output:**
|
|
126
135
|
|
|
127
136
|
```
|
|
@@ -161,12 +170,14 @@ telo install ./apps/a/telo.yaml ./apps/b/telo.yaml
|
|
|
161
170
|
|
|
162
171
|
The cache lives next to the manifest at `<entry-manifest-dir>/.telo/`:
|
|
163
172
|
|
|
164
|
-
- `.telo/npm/` — controller node_modules tree (one realm per manifest).
|
|
173
|
+
- `.telo/npm/` — controller node_modules tree (one realm per manifest), for the modules that still deliver their controller from npm.
|
|
174
|
+
- `.telo/controller-src/` — bundles built from a **local** module's controller sources. Only ever written for a module that is a working copy on disk: a published module ships a prebuilt bundle in its artifact and never reaches this path. Each entry is named by a digest of every input the build read, so an edit anywhere in the source graph yields a new entry rather than invalidating one.
|
|
165
175
|
- `.telo/manifests/registry/<host>/<path…>/<version>/telo.yaml` — registry-served manifests.
|
|
166
176
|
- `.telo/manifests/oci/<host>/<repo…>/<tag>/telo.yaml` — manifests imported from an OCI registry.
|
|
167
177
|
- `.telo/manifests/url/<host>/<pathname>` — manifests imported via raw HTTP URLs.
|
|
178
|
+
- `.telo/manifests/.origins.json` — for each cached import named by a **mutable tag**, the OCI manifest digest that produced the copy. `telo check` revalidates against it with one `HEAD` per reference; a pinned import needs no entry, since its bytes are verified against the ref's own hash.
|
|
168
179
|
|
|
169
|
-
Every entry is keyed `<transport>/<host>/<path…>/<version>/<file>`, the same grammar the
|
|
180
|
+
Every manifest entry is keyed `<transport>/<host>/<path…>/<version>/<file>`, the same grammar the
|
|
170
181
|
discovery hub uses for its cached manifests.
|
|
171
182
|
|
|
172
183
|
Per-manifest scope means the whole `.telo/` tree is naturally portable: `COPY` the manifest dir into your image and both caches travel with it; no environment variable is required.
|
|
@@ -175,13 +186,17 @@ Per-manifest scope means the whole `.telo/` tree is naturally portable: `COPY` t
|
|
|
175
186
|
|
|
176
187
|
```
|
|
177
188
|
Installing 20 controllers for apps/my-app/telo.yaml
|
|
178
|
-
✓ pkg:
|
|
179
|
-
✓ pkg:
|
|
189
|
+
✓ pkg:telo/local/js?path=./nodejs/server.mjs
|
|
190
|
+
✓ pkg:telo/local/js?path=./nodejs/request.mjs
|
|
180
191
|
...
|
|
181
192
|
|
|
182
193
|
✓ 20 installed in 3.2s
|
|
183
194
|
```
|
|
184
195
|
|
|
196
|
+
A bundled controller (`pkg:telo/local/js`) ships inside its module's own artifact, so
|
|
197
|
+
"installing" it is materializing that artifact's controller layer — nothing is fetched
|
|
198
|
+
from npm. A `pkg:npm` candidate still resolves through the npm cache above.
|
|
199
|
+
|
|
185
200
|
**Typical Dockerfile usage:**
|
|
186
201
|
|
|
187
202
|
```dockerfile
|
|
@@ -54,8 +54,10 @@ export declare function readControllerClaims(manifestText: string): ControllerCl
|
|
|
54
54
|
* are optional and only ever buy laziness.
|
|
55
55
|
*
|
|
56
56
|
* `files` are the manifest-relative paths `selectFiles` produced; `assetPatterns`
|
|
57
|
-
* is the author's `assets:` list.
|
|
58
|
-
*
|
|
57
|
+
* is the author's `assets:` list. Every bundled controller's `path=` entry joins
|
|
58
|
+
* the payload whether or not `files:` selected it — the manifest already names
|
|
59
|
+
* it, so restating it would be pure duplication. Layers with no files are
|
|
60
|
+
* dropped, so a controller-only module publishes exactly one payload layer.
|
|
59
61
|
*/
|
|
60
62
|
export declare function partitionLayers(manifestText: string, files: string[], assetPatterns: string[]): Partition;
|
|
61
63
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"partition-layers.d.ts","sourceRoot":"","sources":["../../src/bundle/partition-layers.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKpD;;uDAEuD;AACvD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;uEAEuE;AACvE,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB;yDACqD;IACrD,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B;oBACgB;IAChB,iBAAiB,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC7D;AAgBD,UAAU,eAAe;IACvB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;CACd;AAQD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,eAAe,EAAE,CAmC5E;AAED
|
|
1
|
+
{"version":3,"file":"partition-layers.d.ts","sourceRoot":"","sources":["../../src/bundle/partition-layers.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKpD;;uDAEuD;AACvD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;uEAEuE;AACvE,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB;yDACqD;IACrD,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B;oBACgB;IAChB,iBAAiB,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC7D;AAgBD,UAAU,eAAe;IACvB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;CACd;AAQD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,eAAe,EAAE,CAmC5E;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EAAE,EACf,aAAa,EAAE,MAAM,EAAE,GACtB,SAAS,CAgEX;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,EAAE,CAYhE"}
|
|
@@ -77,24 +77,23 @@ export function readControllerClaims(manifestText) {
|
|
|
77
77
|
* are optional and only ever buy laziness.
|
|
78
78
|
*
|
|
79
79
|
* `files` are the manifest-relative paths `selectFiles` produced; `assetPatterns`
|
|
80
|
-
* is the author's `assets:` list.
|
|
81
|
-
*
|
|
80
|
+
* is the author's `assets:` list. Every bundled controller's `path=` entry joins
|
|
81
|
+
* the payload whether or not `files:` selected it — the manifest already names
|
|
82
|
+
* it, so restating it would be pure duplication. Layers with no files are
|
|
83
|
+
* dropped, so a controller-only module publishes exactly one payload layer.
|
|
82
84
|
*/
|
|
83
85
|
export function partitionLayers(manifestText, files, assetPatterns) {
|
|
84
86
|
const claims = readControllerClaims(manifestText);
|
|
85
|
-
|
|
87
|
+
// A controller entry point is part of the payload because `controllers:` names
|
|
88
|
+
// it, not because `files:` restates it. `files:` keeps its role for everything
|
|
89
|
+
// the manifest cannot otherwise see — assets, static files, sidecars — and a
|
|
90
|
+
// module whose only payload is its controller declares no `files:` at all.
|
|
91
|
+
//
|
|
92
|
+
// Sibling patterns are still matched against `files:` alone: a sibling is a
|
|
93
|
+
// glob over the payload, so a pattern that selects nothing there means the
|
|
94
|
+
// author forgot to include the file, which `unmatchedSiblings` reports.
|
|
95
|
+
const selected = new Set([...files, ...claims.map((claim) => claim.entry)]);
|
|
86
96
|
const unclaimed = new Set(files);
|
|
87
|
-
// A controller entry point the `files:` list does not select is a broken
|
|
88
|
-
// artifact, and it is decidable right here: its layer would ship without it (or
|
|
89
|
-
// be dropped entirely as empty), and the consumer would only find out at load
|
|
90
|
-
// time as "ships no layer for <selector>". Fail at publish, naming both the PURL
|
|
91
|
-
// and the path that has to be added.
|
|
92
|
-
const missing = claims.filter((c) => !selected.has(c.entry));
|
|
93
|
-
if (missing.length > 0) {
|
|
94
|
-
throw new Error(`controller entry point${missing.length === 1 ? "" : "s"} not selected by 'files:':\n` +
|
|
95
|
-
missing.map((c) => ` ${c.entry} (from ${c.purl})`).join("\n") +
|
|
96
|
-
`\nAdd the path to 'files:' — a bundled controller must ship in the module's artifact.`);
|
|
97
|
-
}
|
|
98
97
|
// Controller layers first: a file an entry point or sibling claims belongs to
|
|
99
98
|
// that selector, never to assets or common, so the layer a kernel skips is
|
|
100
99
|
// genuinely skippable. A file several candidates claim is copied into each of
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"partition-layers.js","sourceRoot":"","sources":["../../src/bundle/partition-layers.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,WAAW,GAEZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAwBzC;;4BAE4B;AAC5B,MAAM,YAAY,GAAG,MAAM,CAAC;AAC5B,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAElC;;;;;4EAK4E;AAC5E,MAAM,kBAAkB,GAAG,UAAU,CAAC;AAYtC;mEACmE;AACnE,SAAS,iBAAiB,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,YAAoB;IACvD,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,KAAK,MAAM,GAAG,IAAI,iBAAiB,CAAC,YAAY,EAAE,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,CAAC,EAAE,CAAC;QACvF,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,EAAsC,CAAC;QAC9D,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5E,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,IAAI,OAAO,SAAS,KAAK,QAAQ;gBAAE,SAAS;YAC5C,IAAI,MAAkB,CAAC;YACvB,IAAI,CAAC;gBACH,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YAC5C,CAAC;YAAC,MAAM,CAAC;gBACP,oEAAoE;gBACpE,yEAAyE;gBACzE,SAAS;YACX,CAAC;YACD,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,SAAS,KAAK,iBAAiB;gBAAE,SAAS;YACrF,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC;YACtC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE;gBAAE,SAAS;YACxD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC;iBACnE,KAAK,CAAC,GAAG,CAAC;iBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,sBAAsB,CAC9B,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,UAAU,EACjB,eAAe,SAAS,GAAG,CAC5B;gBACD,KAAK,EAAE,iBAAiB,CAAC,KAAK,CAAC;gBAC/B,QAAQ;gBACR,IAAI,EAAE,SAAS;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"partition-layers.js","sourceRoot":"","sources":["../../src/bundle/partition-layers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type ArtifactSelector } from "@telorun/analyzer";
|
|
2
|
+
import { type PayloadFile } from "@telorun/kernel";
|
|
3
|
+
/**
|
|
4
|
+
* Does the payload we are about to publish differ from what is already published
|
|
5
|
+
* at this `metadata.version`?
|
|
6
|
+
*
|
|
7
|
+
* Bundling moves a module's dependency coupling from load time to build time. It
|
|
8
|
+
* does not remove it: once `codec` — or `fastify`, or a transitive dependency the
|
|
9
|
+
* lockfile alone moved — is copied into a module's bundle, that module's bytes
|
|
10
|
+
* have changed while nothing under its own directory has. No path-scoped rule and
|
|
11
|
+
* no version ledger can see that, so a fix silently ships to nobody.
|
|
12
|
+
*
|
|
13
|
+
* The artifact already carries the exact answer. Each layer's `integrity` is a
|
|
14
|
+
* framing-independent digest of its contents, so comparing the layer we just
|
|
15
|
+
* built against the one published under the same version decides the question
|
|
16
|
+
* from the bytes themselves — it fires for a shared-library fix, a lockfile bump
|
|
17
|
+
* and a sibling source edit alike, and it cannot fire spuriously, because
|
|
18
|
+
* identical bytes hash identically.
|
|
19
|
+
*/
|
|
20
|
+
export interface LayerDrift {
|
|
21
|
+
role: string;
|
|
22
|
+
selector?: string;
|
|
23
|
+
/** `integrity` recorded in the published `layers:` index, or `undefined` when
|
|
24
|
+
* the published artifact ships no layer for this role/selector at all. */
|
|
25
|
+
published?: string;
|
|
26
|
+
/** `integrity` of the layer built from the working copy, or `undefined` when
|
|
27
|
+
* the build no longer produces this layer. */
|
|
28
|
+
built?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface BuiltLayer {
|
|
31
|
+
role: string;
|
|
32
|
+
selector?: ArtifactSelector;
|
|
33
|
+
files: PayloadFile[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Compare the built payload against the published one at the same version.
|
|
37
|
+
*
|
|
38
|
+
* Returns `null` when nothing is published at that ref — a new version, so there
|
|
39
|
+
* is nothing to disagree with. Returns an empty array when the payloads match.
|
|
40
|
+
*/
|
|
41
|
+
export declare function findPayloadDrift(destination: string, version: string, built: BuiltLayer[], registry: string): Promise<LayerDrift[] | null>;
|
|
42
|
+
/** The message shown when the gate fires. It names the version to bump, because
|
|
43
|
+
* that — not a re-push — is the fix: overwriting a published tag would change
|
|
44
|
+
* what an existing pinned import resolves to. */
|
|
45
|
+
export declare function describeDrift(moduleRef: string, version: string, drift: LayerDrift[]): string;
|
|
46
|
+
//# sourceMappingURL=payload-drift.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payload-drift.d.ts","sourceRoot":"","sources":["../../src/bundle/payload-drift.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,gBAAgB,EACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAmD,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGpG;;;;;;;;;;;;;;;;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;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AA2DD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,UAAU,EAAE,EACnB,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,CAc7F"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { describeSelector, parseLayerIndex, selectorKey, } from "@telorun/analyzer";
|
|
2
|
+
import { computeFilesIntegrity, defaultTransportRegistry } from "@telorun/kernel";
|
|
3
|
+
import { parseAllDocuments } from "yaml";
|
|
4
|
+
/** Identity of a layer within an artifact: its role, plus its selector for the
|
|
5
|
+
* controller layers, of which there is one per selector. */
|
|
6
|
+
function layerKey(role, selector) {
|
|
7
|
+
return selector ? `${role}\0${selectorKey(selector)}` : role;
|
|
8
|
+
}
|
|
9
|
+
function describeKey(role, selector) {
|
|
10
|
+
return selector ? `${role} (${describeSelector(selector)})` : role;
|
|
11
|
+
}
|
|
12
|
+
/** A published version genuinely absent from the registry — the normal case on
|
|
13
|
+
* every release, and the ONLY reason this gate is allowed to pass without
|
|
14
|
+
* comparing anything. */
|
|
15
|
+
const NOT_FOUND = /\b404\b|not found|MANIFEST_UNKNOWN|NAME_UNKNOWN/i;
|
|
16
|
+
/**
|
|
17
|
+
* Read the `layers:` index off an already-published manifest, or `null` when
|
|
18
|
+
* nothing is published at that ref.
|
|
19
|
+
*
|
|
20
|
+
* A ref that does not resolve is not an error: a new version has no predecessor.
|
|
21
|
+
* **Anything else is.** A 401, a 5xx or a DNS failure says nothing about whether
|
|
22
|
+
* the payload changed, and answering "no drift" to a question the registry
|
|
23
|
+
* refused to answer would turn a byte-equality gate into a no-op during exactly
|
|
24
|
+
* the kind of incident where a release is most likely to ship something wrong.
|
|
25
|
+
* Those propagate and fail the publish.
|
|
26
|
+
*/
|
|
27
|
+
async function readPublishedLayers(ref, registry) {
|
|
28
|
+
const transport = defaultTransportRegistry(registry).forRef(ref);
|
|
29
|
+
if (!transport) {
|
|
30
|
+
throw new Error(`Cannot verify the published payload of '${ref}': no transport owns that ref.`);
|
|
31
|
+
}
|
|
32
|
+
let text;
|
|
33
|
+
try {
|
|
34
|
+
({ text } = await transport.source.read(ref));
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
38
|
+
if (NOT_FOUND.test(message))
|
|
39
|
+
return null;
|
|
40
|
+
throw new Error(`Cannot verify whether '${ref}' is already published with a different payload: ${message}. ` +
|
|
41
|
+
`Publishing without that answer could ship changed bytes at an unchanged version — ` +
|
|
42
|
+
`resolve the registry error and retry.`);
|
|
43
|
+
}
|
|
44
|
+
for (const doc of parseAllDocuments(text)) {
|
|
45
|
+
const json = doc.toJSON();
|
|
46
|
+
if (json?.kind !== "Telo.Application" && json?.kind !== "Telo.Library")
|
|
47
|
+
continue;
|
|
48
|
+
if (json.layers === undefined)
|
|
49
|
+
return [];
|
|
50
|
+
return parseLayerIndex(json.layers, `${ref} layers`);
|
|
51
|
+
}
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Compare the built payload against the published one at the same version.
|
|
56
|
+
*
|
|
57
|
+
* Returns `null` when nothing is published at that ref — a new version, so there
|
|
58
|
+
* is nothing to disagree with. Returns an empty array when the payloads match.
|
|
59
|
+
*/
|
|
60
|
+
export async function findPayloadDrift(destination, version, built, registry) {
|
|
61
|
+
const published = await readPublishedLayers(`${destination}@${version}`, registry);
|
|
62
|
+
if (published === null)
|
|
63
|
+
return null;
|
|
64
|
+
const publishedByKey = new Map();
|
|
65
|
+
for (const layer of published)
|
|
66
|
+
publishedByKey.set(layerKey(layer.role, layer.selector), layer);
|
|
67
|
+
const drift = [];
|
|
68
|
+
const seen = new Set();
|
|
69
|
+
for (const layer of built) {
|
|
70
|
+
const key = layerKey(layer.role, layer.selector);
|
|
71
|
+
seen.add(key);
|
|
72
|
+
const integrity = await computeFilesIntegrity(layer.files);
|
|
73
|
+
const before = publishedByKey.get(key);
|
|
74
|
+
if (before?.integrity !== integrity) {
|
|
75
|
+
drift.push({
|
|
76
|
+
role: describeKey(layer.role, layer.selector),
|
|
77
|
+
published: before?.integrity,
|
|
78
|
+
built: integrity,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// A layer that was published and is no longer built is drift too — the payload
|
|
83
|
+
// shrank, which changes what a consumer receives just as much as a byte edit.
|
|
84
|
+
for (const [key, layer] of publishedByKey) {
|
|
85
|
+
if (seen.has(key))
|
|
86
|
+
continue;
|
|
87
|
+
drift.push({ role: describeKey(layer.role, layer.selector), published: layer.integrity });
|
|
88
|
+
}
|
|
89
|
+
return drift;
|
|
90
|
+
}
|
|
91
|
+
/** The message shown when the gate fires. It names the version to bump, because
|
|
92
|
+
* that — not a re-push — is the fix: overwriting a published tag would change
|
|
93
|
+
* what an existing pinned import resolves to. */
|
|
94
|
+
export function describeDrift(moduleRef, version, drift) {
|
|
95
|
+
const lines = drift.map((entry) => {
|
|
96
|
+
if (!entry.built)
|
|
97
|
+
return ` ${entry.role}: published, no longer built`;
|
|
98
|
+
if (!entry.published)
|
|
99
|
+
return ` ${entry.role}: newly built, not in the published artifact`;
|
|
100
|
+
return ` ${entry.role}: ${entry.published} → ${entry.built}`;
|
|
101
|
+
});
|
|
102
|
+
return (`${moduleRef} is already published at ${version}, but its payload has changed:\n` +
|
|
103
|
+
lines.join("\n") +
|
|
104
|
+
`\nA bundle inlines its dependencies, so a change in a shared library or the ` +
|
|
105
|
+
`lockfile alters these bytes without touching this module's own files. ` +
|
|
106
|
+
`Add a changie fragment for this module so metadata.version moves — republishing ` +
|
|
107
|
+
`over the existing tag would change what an already-pinned import resolves to.`);
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=payload-drift.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payload-drift.js","sourceRoot":"","sources":["../../src/bundle/payload-drift.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,4 +14,17 @@
|
|
|
14
14
|
export declare function selectFiles(manifestDir: string, patterns: string[], opts?: {
|
|
15
15
|
applyDefaultIgnore?: boolean;
|
|
16
16
|
}): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Reject any path that resolves — via a symlink — outside `manifestDir`.
|
|
19
|
+
*
|
|
20
|
+
* Separate from {@link selectFiles} because a `files:` pattern is no longer the
|
|
21
|
+
* only route into the payload: a bundled controller's `path=` entry joins it
|
|
22
|
+
* from `controllers:`, and the guard has to cover what actually ships rather
|
|
23
|
+
* than what a pattern happened to match. Applied to the whole partition, so
|
|
24
|
+
* every file in every layer passes it.
|
|
25
|
+
*
|
|
26
|
+
* A missing file is reported here too — publish is about to read it, and
|
|
27
|
+
* "declared but absent" is the same class of mistake as "declared but outside".
|
|
28
|
+
*/
|
|
29
|
+
export declare function assertWithinModule(manifestDir: string, rels: Iterable<string>): void;
|
|
17
30
|
//# sourceMappingURL=select-files.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select-files.d.ts","sourceRoot":"","sources":["../../src/bundle/select-files.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,GAAE;IAAE,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC1C,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"select-files.d.ts","sourceRoot":"","sources":["../../src/bundle/select-files.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,GAAE;IAAE,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC1C,MAAM,EAAE,CAoBV;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAoBpF"}
|
|
@@ -31,14 +31,37 @@ export function selectFiles(manifestDir, patterns, opts = {}) {
|
|
|
31
31
|
const selected = selectByPatterns(rels, patterns, {
|
|
32
32
|
applyDefaultIgnore: opts.applyDefaultIgnore,
|
|
33
33
|
});
|
|
34
|
+
assertWithinModule(manifestDir, selected);
|
|
35
|
+
return selected;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Reject any path that resolves — via a symlink — outside `manifestDir`.
|
|
39
|
+
*
|
|
40
|
+
* Separate from {@link selectFiles} because a `files:` pattern is no longer the
|
|
41
|
+
* only route into the payload: a bundled controller's `path=` entry joins it
|
|
42
|
+
* from `controllers:`, and the guard has to cover what actually ships rather
|
|
43
|
+
* than what a pattern happened to match. Applied to the whole partition, so
|
|
44
|
+
* every file in every layer passes it.
|
|
45
|
+
*
|
|
46
|
+
* A missing file is reported here too — publish is about to read it, and
|
|
47
|
+
* "declared but absent" is the same class of mistake as "declared but outside".
|
|
48
|
+
*/
|
|
49
|
+
export function assertWithinModule(manifestDir, rels) {
|
|
34
50
|
const realManifestDir = fs.realpathSync(manifestDir) + path.sep;
|
|
35
|
-
for (const rel of
|
|
36
|
-
|
|
51
|
+
for (const rel of rels) {
|
|
52
|
+
let real;
|
|
53
|
+
try {
|
|
54
|
+
real = fs.realpathSync(path.resolve(manifestDir, rel));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
throw new Error(`'${rel}' is declared as part of this module's payload but does not exist. ` +
|
|
58
|
+
`A bundled controller's entry point is built from its source — run the module's ` +
|
|
59
|
+
`build before publishing.`);
|
|
60
|
+
}
|
|
37
61
|
if (!real.startsWith(realManifestDir)) {
|
|
38
|
-
throw new Error(`
|
|
62
|
+
throw new Error(`'${rel}' resolves outside the module directory. ` +
|
|
39
63
|
`Bundling files from outside the module root is not allowed.`);
|
|
40
64
|
}
|
|
41
65
|
}
|
|
42
|
-
return selected;
|
|
43
66
|
}
|
|
44
67
|
//# sourceMappingURL=select-files.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select-files.js","sourceRoot":"","sources":["../../src/bundle/select-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CACzB,WAAmB,EACnB,QAAkB,EAClB,OAAyC,EAAE;IAE3C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,8EAA8E;IAC9E,2EAA2E;IAC3E,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACtF,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,yEAAyE;QACzE,mDAAmD;QACnD,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,SAAS;QAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3G,CAAC;IAED,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE;QAChD,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;KAC5C,CAAC,CAAC;IAEH,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC;IAChE,KAAK,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"select-files.js","sourceRoot":"","sources":["../../src/bundle/select-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CACzB,WAAmB,EACnB,QAAkB,EAClB,OAAyC,EAAE;IAE3C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,8EAA8E;IAC9E,2EAA2E;IAC3E,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACtF,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,yEAAyE;QACzE,mDAAmD;QACnD,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,SAAS;QAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3G,CAAC;IAED,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE;QAChD,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;KAC5C,CAAC,CAAC;IAEH,kBAAkB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC1C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAmB,EAAE,IAAsB;IAC5E,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC;IAChE,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC;YACH,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CACb,IAAI,GAAG,qEAAqE;gBAC1E,iFAAiF;gBACjF,0BAA0B,CAC7B,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CACb,IAAI,GAAG,2CAA2C;gBAChD,6DAA6D,CAChE,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/commands/check.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAkOlC,wBAAsB,KAAK,CAAC,IAAI,EAAE;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DhB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,CAoB9C"}
|
package/dist/commands/check.js
CHANGED
|
@@ -1,13 +1,42 @@
|
|
|
1
1
|
import { Loader, StaticAnalyzer, flattenForAnalyzer } from "@telorun/analyzer";
|
|
2
2
|
import { assembleGraphDiagnostics } from "@telorun/ide-support";
|
|
3
|
+
import { LocalManifestCacheSource, resolveCacheRoot, resolveEntryDir, writeManifestCache, } from "@telorun/kernel";
|
|
3
4
|
import { LocalFileSource } from "@telorun/kernel/manifest-sources/local-file-source";
|
|
4
5
|
import { defaultTransportRegistry } from "@telorun/kernel/transports";
|
|
6
|
+
import * as fs from "fs/promises";
|
|
5
7
|
import * as path from "path";
|
|
8
|
+
import { pathToFileURL } from "url";
|
|
6
9
|
import { createLogger, formatAnalysisDiagnostics, formatDiagnostics } from "../logger.js";
|
|
10
|
+
import { RecordingCacheSource, readOriginDigests, revalidateMutableOciRefs, writeOriginDigests, } from "../manifest-freshness.js";
|
|
7
11
|
const DEFAULT_REGISTRY_URL = "https://registry.telo.run";
|
|
8
|
-
|
|
12
|
+
function cacheTargetFor(entryPath) {
|
|
13
|
+
const cacheRoot = resolveCacheRoot(entryPath);
|
|
14
|
+
const entryDir = resolveEntryDir(entryPath);
|
|
15
|
+
if (!cacheRoot || entryDir === null)
|
|
16
|
+
return null;
|
|
17
|
+
return { entryDir, manifestsDir: path.join(cacheRoot, "manifests") };
|
|
18
|
+
}
|
|
19
|
+
function resolveEntryPath(inputPath) {
|
|
9
20
|
const isUrl = inputPath.startsWith("http://") || inputPath.startsWith("https://");
|
|
10
|
-
|
|
21
|
+
return isUrl ? inputPath : path.resolve(process.cwd(), inputPath);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* One loader for the whole invocation, ahead of the transports:
|
|
25
|
+
*
|
|
26
|
+
* - `LocalManifestCacheSource` makes a repeat check hermetic. Without it every
|
|
27
|
+
* `oci://` / registry import was re-pulled on every run even when fully
|
|
28
|
+
* pinned, which is the bulk of `check`'s wall time.
|
|
29
|
+
* - The loader is shared across *all* input paths, so `telo check a b c` reads
|
|
30
|
+
* a module common to several of them once. Its `urlToSource` / `fileCache`
|
|
31
|
+
* dedupe by canonical URL, so this is purely a cache-hit question — the
|
|
32
|
+
* resolution result for a given URL does not depend on which entry asked.
|
|
33
|
+
*
|
|
34
|
+
* A cache source is registered for every input path's cache root: the entries
|
|
35
|
+
* are content-addressed, so a hit under any root is as good as a hit under the
|
|
36
|
+
* one this path would write to, and a miss falls through unchanged.
|
|
37
|
+
*/
|
|
38
|
+
function openSession(cacheTargets, registryUrl) {
|
|
39
|
+
const recorders = cacheTargets.map((t) => new RecordingCacheSource(new LocalManifestCacheSource(t.entryDir, registryUrl, t.manifestsDir), registryUrl));
|
|
11
40
|
// The kernel's transport sources — the same set `install` / `run` use — so
|
|
12
41
|
// `check` resolves every scheme they do, `oci://` included, direct-to-origin.
|
|
13
42
|
// The browser-only `manifests.telo.sh` cache path stays the editor's; a CLI
|
|
@@ -15,14 +44,78 @@ async function checkOne(inputPath, registryUrl, log) {
|
|
|
15
44
|
// plan: resolution never routes through the hub).
|
|
16
45
|
const loader = new Loader([
|
|
17
46
|
new LocalFileSource(),
|
|
47
|
+
...recorders,
|
|
18
48
|
...defaultTransportRegistry(registryUrl).sources(),
|
|
19
49
|
]);
|
|
50
|
+
return {
|
|
51
|
+
loader,
|
|
52
|
+
recorders,
|
|
53
|
+
manifestsDirs: cacheTargets.map((t) => t.manifestsDir),
|
|
54
|
+
verified: new Map(),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Drop a stale cache entry: the file, the loader's memo of it, and the record
|
|
59
|
+
* that it was ever served. The next load re-resolves that one manifest through
|
|
60
|
+
* the transports and leaves every other file's memo intact.
|
|
61
|
+
*
|
|
62
|
+
* Removal failures are warned, not thrown. This is cache maintenance, and the
|
|
63
|
+
* rest of the command already treats caching as an optimization — a read-only
|
|
64
|
+
* or root-owned `.telo` must not change the exit code of a static check. An
|
|
65
|
+
* entry that could not be removed is still forgotten by the loader, so the
|
|
66
|
+
* reload re-fetches it rather than trusting bytes it just judged stale.
|
|
67
|
+
*/
|
|
68
|
+
async function dropStaleEntry(file, session, log) {
|
|
69
|
+
try {
|
|
70
|
+
await fs.rm(file, { force: true });
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
process.stderr.write(`${log.warn(`[manifest-cache] could not remove stale entry ${file}: ${err instanceof Error ? err.message : String(err)}`)}\n`);
|
|
74
|
+
}
|
|
75
|
+
session.loader.forget(pathToFileURL(file).href);
|
|
76
|
+
for (const recorder of session.recorders) {
|
|
77
|
+
for (const [url, served] of recorder.served) {
|
|
78
|
+
if (served === file)
|
|
79
|
+
recorder.served.delete(url);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function checkOne(inputPath, registryUrl, session, cacheTarget, cacheWrite,
|
|
84
|
+
/** Digests already verified by a prior pass. Present only on the retry after
|
|
85
|
+
* a stale entry was dropped: revalidating again would re-`HEAD` the same
|
|
86
|
+
* tags, and the freshly fetched bytes are current by construction. */
|
|
87
|
+
knownDigests, log) {
|
|
88
|
+
const entryPath = resolveEntryPath(inputPath);
|
|
89
|
+
const isUrl = entryPath.startsWith("http://") || entryPath.startsWith("https://");
|
|
20
90
|
try {
|
|
21
91
|
// `desugarImports` so inline `imports:` maps expand into synthetic
|
|
22
92
|
// Telo.Import manifests before analysis — `telo check` is a static
|
|
23
93
|
// resolution consumer and must see inline imports exactly as the kernel does.
|
|
24
|
-
const graph = await loader.loadGraph(entryPath, { desugarImports: true });
|
|
25
|
-
|
|
94
|
+
const graph = await session.loader.loadGraph(entryPath, { desugarImports: true });
|
|
95
|
+
// Freshness before analysis: a verdict computed from a moved tag would be
|
|
96
|
+
// reported as authoritative. Pinned imports make this a no-op.
|
|
97
|
+
let digests = knownDigests ?? new Map();
|
|
98
|
+
if (!knownDigests && session.recorders.length > 0) {
|
|
99
|
+
const served = new Map();
|
|
100
|
+
for (const recorder of session.recorders) {
|
|
101
|
+
for (const [url, file] of recorder.served)
|
|
102
|
+
served.set(url, file);
|
|
103
|
+
}
|
|
104
|
+
const originsByRoot = new Map();
|
|
105
|
+
for (const dir of session.manifestsDirs) {
|
|
106
|
+
originsByRoot.set(dir, await readOriginDigests(dir));
|
|
107
|
+
}
|
|
108
|
+
const freshness = await revalidateMutableOciRefs(graph, served, originsByRoot, registryUrl, session.verified);
|
|
109
|
+
if (freshness.staleFiles.length > 0) {
|
|
110
|
+
return {
|
|
111
|
+
errorCount: 0,
|
|
112
|
+
warnCount: 0,
|
|
113
|
+
staleFiles: freshness.staleFiles,
|
|
114
|
+
digests: freshness.digests,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
digests = freshness.digests;
|
|
118
|
+
}
|
|
26
119
|
// `assembleGraphDiagnostics` is the shared assembler every host uses: it
|
|
27
120
|
// folds parse, version-reconciliation, import-resolution, and static
|
|
28
121
|
// analysis diagnostics into one list, holding back the cascade for files
|
|
@@ -30,28 +123,61 @@ async function checkOne(inputPath, registryUrl, log) {
|
|
|
30
123
|
// `imports:` source thus surfaces here as a coded diagnostic — identical to
|
|
31
124
|
// the editor — instead of a bare re-thrown load error. The CLI drops the
|
|
32
125
|
// suppressed cascade; the editor / VS Code keep it available to render.
|
|
33
|
-
const analysis = new StaticAnalyzer().analyze(
|
|
126
|
+
const analysis = new StaticAnalyzer().analyze(flattenForAnalyzer(graph));
|
|
34
127
|
const { diagnostics } = assembleGraphDiagnostics(graph, analysis);
|
|
35
|
-
|
|
128
|
+
const counts = formatAnalysisDiagnostics(diagnostics, graph, log, entryPath);
|
|
129
|
+
if (cacheWrite && cacheTarget) {
|
|
130
|
+
// Write-through so the next check — and the next `telo run` from this
|
|
131
|
+
// directory, which reads the same cache — is hermetic. Caching is an
|
|
132
|
+
// optimization: a read-only filesystem warns rather than fails the check.
|
|
133
|
+
try {
|
|
134
|
+
await writeManifestCache(graph, cacheTarget.entryDir, registryUrl, cacheTarget.manifestsDir);
|
|
135
|
+
await writeOriginDigests(cacheTarget.manifestsDir, digests);
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
process.stderr.write(`${log.warn(`[manifest-cache] write failed: ${err instanceof Error ? err.message : String(err)}`)}\n`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return { ...counts, staleFiles: [], digests };
|
|
36
142
|
}
|
|
37
143
|
catch (err) {
|
|
38
144
|
const sourceLine = err.sourceLine;
|
|
39
145
|
const displayPath = isUrl ? entryPath : path.relative(process.cwd(), entryPath);
|
|
40
146
|
const loc = sourceLine !== undefined ? `:${sourceLine + 1}` : "";
|
|
41
147
|
formatDiagnostics([{ message: err instanceof Error ? err.message : String(err) }], log, `${displayPath}${loc}`);
|
|
42
|
-
return { errorCount: 1, warnCount: 0 };
|
|
148
|
+
return { errorCount: 1, warnCount: 0, staleFiles: [], digests: new Map() };
|
|
43
149
|
}
|
|
44
150
|
}
|
|
45
151
|
export async function check(argv) {
|
|
46
152
|
const log = createLogger(false);
|
|
47
153
|
// Same fallback chain as `run` / `install`.
|
|
48
154
|
const registryUrl = argv.registryUrl ?? process.env.TELO_REGISTRY_URL ?? DEFAULT_REGISTRY_URL;
|
|
155
|
+
const cacheWrite = argv.cacheWrite !== false;
|
|
156
|
+
const cacheTargets = new Map();
|
|
157
|
+
for (const p of argv.paths) {
|
|
158
|
+
const target = cacheTargetFor(resolveEntryPath(p));
|
|
159
|
+
if (target)
|
|
160
|
+
cacheTargets.set(target.manifestsDir, target);
|
|
161
|
+
}
|
|
162
|
+
const session = openSession([...cacheTargets.values()], registryUrl);
|
|
49
163
|
let totalErrors = 0;
|
|
50
164
|
let totalWarns = 0;
|
|
51
165
|
for (const p of argv.paths) {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
166
|
+
const cacheTarget = cacheTargetFor(resolveEntryPath(p));
|
|
167
|
+
let outcome = await checkOne(p, registryUrl, session, cacheTarget, cacheWrite, null, log);
|
|
168
|
+
if (outcome.staleFiles.length > 0) {
|
|
169
|
+
// A mutable tag moved under the cache. Drop just those entries — file,
|
|
170
|
+
// loader memo, and served record — so every other path's resolution
|
|
171
|
+
// survives, then re-check. Revalidation is off on the retry: the digests
|
|
172
|
+
// were established a moment ago, and the reload cannot be stale because
|
|
173
|
+
// the entries it would have used are gone.
|
|
174
|
+
for (const file of outcome.staleFiles) {
|
|
175
|
+
await dropStaleEntry(file, session, log);
|
|
176
|
+
}
|
|
177
|
+
outcome = await checkOne(p, registryUrl, session, cacheTarget, cacheWrite, outcome.digests, log);
|
|
178
|
+
}
|
|
179
|
+
totalErrors += outcome.errorCount;
|
|
180
|
+
totalWarns += outcome.warnCount;
|
|
55
181
|
}
|
|
56
182
|
if (totalErrors === 0 && totalWarns === 0) {
|
|
57
183
|
console.log(log.ok("✓") + " No issues found");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,oDAAoD,CAAC;AACrF,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"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"}
|