@telorun/kernel 0.58.0 → 0.60.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/files-integrity.d.ts +21 -12
- package/dist/bundle/files-integrity.d.ts.map +1 -1
- package/dist/bundle/files-integrity.js +27 -14
- package/dist/bundle/files-integrity.js.map +1 -1
- package/dist/bundle/module-artifact.d.ts +134 -0
- package/dist/bundle/module-artifact.d.ts.map +1 -0
- package/dist/bundle/module-artifact.js +300 -0
- package/dist/bundle/module-artifact.js.map +1 -0
- package/dist/bundle/module-manifest.d.ts +12 -4
- package/dist/bundle/module-manifest.d.ts.map +1 -1
- package/dist/bundle/module-manifest.js +8 -4
- package/dist/bundle/module-manifest.js.map +1 -1
- package/dist/controller-loader.d.ts +3 -2
- package/dist/controller-loader.d.ts.map +1 -1
- package/dist/controller-loader.js +8 -8
- package/dist/controller-loader.js.map +1 -1
- package/dist/controller-loaders/bundle-loader.d.ts +8 -6
- package/dist/controller-loaders/bundle-loader.d.ts.map +1 -1
- package/dist/controller-loaders/bundle-loader.js +52 -13
- package/dist/controller-loaders/bundle-loader.js.map +1 -1
- package/dist/controller-loaders/npm-loader.d.ts +0 -18
- package/dist/controller-loaders/npm-loader.d.ts.map +1 -1
- package/dist/controller-loaders/npm-loader.js +3 -190
- package/dist/controller-loaders/npm-loader.js.map +1 -1
- package/dist/controllers/resource-definition/resource-definition-controller.d.ts.map +1 -1
- package/dist/controllers/resource-definition/resource-definition-controller.js +6 -1
- package/dist/controllers/resource-definition/resource-definition-controller.js.map +1 -1
- package/dist/directory-lock.d.ts +27 -0
- package/dist/directory-lock.d.ts.map +1 -0
- package/dist/directory-lock.js +205 -0
- package/dist/directory-lock.js.map +1 -0
- package/dist/evaluation-context.d.ts.map +1 -1
- package/dist/evaluation-context.js +20 -6
- package/dist/evaluation-context.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/kernel.d.ts +32 -0
- package/dist/kernel.d.ts.map +1 -1
- package/dist/kernel.js +55 -1
- package/dist/kernel.js.map +1 -1
- package/dist/manifest-sources/local-manifest-cache-source.d.ts +1 -1
- package/dist/manifest-sources/local-manifest-cache-source.d.ts.map +1 -1
- package/dist/manifest-sources/local-manifest-cache-source.js +1 -1
- package/dist/manifest-sources/local-manifest-cache-source.js.map +1 -1
- package/dist/resource-context.d.ts +18 -0
- package/dist/resource-context.d.ts.map +1 -1
- package/dist/resource-context.js +72 -1
- package/dist/resource-context.js.map +1 -1
- package/dist/transports/oci/oci-client.d.ts +28 -1
- package/dist/transports/oci/oci-client.d.ts.map +1 -1
- package/dist/transports/oci/oci-client.js +24 -1
- package/dist/transports/oci/oci-client.js.map +1 -1
- package/dist/transports/oci/oci-transport.d.ts +20 -14
- package/dist/transports/oci/oci-transport.d.ts.map +1 -1
- package/dist/transports/oci/oci-transport.js +105 -46
- package/dist/transports/oci/oci-transport.js.map +1 -1
- package/dist/transports/registry-transport.d.ts +7 -2
- package/dist/transports/registry-transport.d.ts.map +1 -1
- package/dist/transports/registry-transport.js +8 -33
- package/dist/transports/registry-transport.js.map +1 -1
- package/dist/transports/transport-registry.d.ts +5 -4
- package/dist/transports/transport-registry.d.ts.map +1 -1
- package/dist/transports/transport-registry.js +4 -4
- package/dist/transports/transport-registry.js.map +1 -1
- package/dist/transports/transport.d.ts +27 -19
- package/dist/transports/transport.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/bundle/files-integrity.ts +34 -14
- package/src/bundle/module-artifact.ts +375 -0
- package/src/bundle/module-manifest.ts +22 -6
- package/src/controller-loader.ts +9 -4
- package/src/controller-loaders/bundle-loader.ts +57 -11
- package/src/controller-loaders/npm-loader.ts +3 -209
- package/src/controllers/resource-definition/resource-definition-controller.ts +19 -0
- package/src/directory-lock.ts +225 -0
- package/src/evaluation-context.ts +17 -7
- package/src/index.ts +10 -2
- package/src/kernel.ts +66 -0
- package/src/manifest-sources/local-manifest-cache-source.ts +1 -1
- package/src/resource-context.ts +78 -1
- package/src/transports/oci/oci-client.ts +32 -1
- package/src/transports/oci/oci-transport.ts +122 -51
- package/src/transports/registry-transport.ts +10 -38
- package/src/transports/transport-registry.ts +5 -5
- package/src/transports/transport.ts +32 -19
|
@@ -1,25 +1,34 @@
|
|
|
1
|
+
import { type ArtifactLayer } from "@telorun/analyzer";
|
|
1
2
|
export interface PayloadFile {
|
|
2
3
|
/** POSIX-relative path inside the bundle. */
|
|
3
4
|
name: string;
|
|
4
5
|
content: Buffer | Uint8Array;
|
|
5
6
|
}
|
|
6
7
|
/**
|
|
7
|
-
* Canonical per-file content digest of
|
|
8
|
-
* of
|
|
9
|
-
* `<path>\0<sha256(content)>` lines of every
|
|
10
|
-
* excluded (the
|
|
11
|
-
*
|
|
8
|
+
* Canonical per-file content digest of one **layer**'s files — the `integrity`
|
|
9
|
+
* value of that layer's entry in the published `layers:` index. SHA-256 over the
|
|
10
|
+
* sorted `<path>\0<sha256(content)>` lines of every file in the layer,
|
|
11
|
+
* `telo.yaml` excluded (it is the manifest layer, which carries the index and so
|
|
12
|
+
* cannot hash itself; the importer's `#sha256-...` pin covers it instead).
|
|
12
13
|
*
|
|
13
14
|
* Hashing file *contents* rather than the tar/gzip bytes makes the digest
|
|
14
15
|
* independent of archive framing, so publisher and client compute the same
|
|
15
16
|
* value from the same file set, and it can be re-derived from the extracted
|
|
16
|
-
* files on disk
|
|
17
|
+
* files on disk — which is what makes a per-layer cache marker checkable without
|
|
18
|
+
* re-tarring. Distinct from the layer's `blob` digest, which covers the pushed
|
|
19
|
+
* bytes and addresses the layer. Returns `sha256-<base64url>`.
|
|
17
20
|
*/
|
|
18
21
|
export declare function computeFilesIntegrity(files: PayloadFile[]): Promise<string>;
|
|
19
|
-
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Write the `layers:` index onto the manifest's owner doc so the published
|
|
24
|
+
* `telo.yaml` pins and addresses every payload layer — transitively covered by
|
|
25
|
+
* importers' `#sha256-...` hash over this manifest.
|
|
26
|
+
*
|
|
27
|
+
* Called after the payload blobs are pushed and before the manifest blob is,
|
|
28
|
+
* which is what keeps the index non-circular: it names only layers other than
|
|
29
|
+
* the one carrying it. Each layer's own digest excludes `telo.yaml`, so
|
|
30
|
+
* injecting the index does not invalidate any of them. Returns the manifest
|
|
31
|
+
* unchanged when it has no owner doc.
|
|
32
|
+
*/
|
|
33
|
+
export declare function injectLayerIndex(manifest: string, layers: readonly ArtifactLayer[]): string;
|
|
25
34
|
//# sourceMappingURL=files-integrity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files-integrity.d.ts","sourceRoot":"","sources":["../../src/bundle/files-integrity.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"files-integrity.d.ts","sourceRoot":"","sources":["../../src/bundle/files-integrity.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAC;AAI3B,MAAM,WAAW,WAAW;IAC1B,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;CAC9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAUjF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,MAAM,CAc3F"}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import { DEFAULT_MANIFEST_FILENAME, sha256Base64Url } from "@telorun/analyzer";
|
|
1
|
+
import { DEFAULT_MANIFEST_FILENAME, sha256Base64Url, } from "@telorun/analyzer";
|
|
2
2
|
import { findOwnerDoc, parseManifestDocs } from "./module-manifest.js";
|
|
3
3
|
/**
|
|
4
|
-
* Canonical per-file content digest of
|
|
5
|
-
* of
|
|
6
|
-
* `<path>\0<sha256(content)>` lines of every
|
|
7
|
-
* excluded (the
|
|
8
|
-
*
|
|
4
|
+
* Canonical per-file content digest of one **layer**'s files — the `integrity`
|
|
5
|
+
* value of that layer's entry in the published `layers:` index. SHA-256 over the
|
|
6
|
+
* sorted `<path>\0<sha256(content)>` lines of every file in the layer,
|
|
7
|
+
* `telo.yaml` excluded (it is the manifest layer, which carries the index and so
|
|
8
|
+
* cannot hash itself; the importer's `#sha256-...` pin covers it instead).
|
|
9
9
|
*
|
|
10
10
|
* Hashing file *contents* rather than the tar/gzip bytes makes the digest
|
|
11
11
|
* independent of archive framing, so publisher and client compute the same
|
|
12
12
|
* value from the same file set, and it can be re-derived from the extracted
|
|
13
|
-
* files on disk
|
|
13
|
+
* files on disk — which is what makes a per-layer cache marker checkable without
|
|
14
|
+
* re-tarring. Distinct from the layer's `blob` digest, which covers the pushed
|
|
15
|
+
* bytes and addresses the layer. Returns `sha256-<base64url>`.
|
|
14
16
|
*/
|
|
15
17
|
export async function computeFilesIntegrity(files) {
|
|
16
18
|
const lines = [];
|
|
@@ -24,17 +26,28 @@ export async function computeFilesIntegrity(files) {
|
|
|
24
26
|
const canonical = new TextEncoder().encode(lines.join("\n"));
|
|
25
27
|
return `sha256-${await sha256Base64Url(canonical)}`;
|
|
26
28
|
}
|
|
27
|
-
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Write the `layers:` index onto the manifest's owner doc so the published
|
|
31
|
+
* `telo.yaml` pins and addresses every payload layer — transitively covered by
|
|
32
|
+
* importers' `#sha256-...` hash over this manifest.
|
|
33
|
+
*
|
|
34
|
+
* Called after the payload blobs are pushed and before the manifest blob is,
|
|
35
|
+
* which is what keeps the index non-circular: it names only layers other than
|
|
36
|
+
* the one carrying it. Each layer's own digest excludes `telo.yaml`, so
|
|
37
|
+
* injecting the index does not invalidate any of them. Returns the manifest
|
|
38
|
+
* unchanged when it has no owner doc.
|
|
39
|
+
*/
|
|
40
|
+
export function injectLayerIndex(manifest, layers) {
|
|
33
41
|
const docs = parseManifestDocs(manifest);
|
|
34
42
|
const owner = findOwnerDoc(docs);
|
|
35
43
|
if (!owner)
|
|
36
44
|
return manifest;
|
|
37
|
-
owner.set("
|
|
45
|
+
owner.set("layers", layers.map((layer) => ({
|
|
46
|
+
role: layer.role,
|
|
47
|
+
...(layer.selector ? { selector: { ...layer.selector } } : {}),
|
|
48
|
+
blob: layer.blob,
|
|
49
|
+
integrity: layer.integrity,
|
|
50
|
+
})));
|
|
38
51
|
return docs.map((d) => d.toString()).join("---\n");
|
|
39
52
|
}
|
|
40
53
|
//# sourceMappingURL=files-integrity.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files-integrity.js","sourceRoot":"","sources":["../../src/bundle/files-integrity.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"files-integrity.js","sourceRoot":"","sources":["../../src/bundle/files-integrity.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,eAAe,GAEhB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAQvE;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAoB;IAC9D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,yBAAyB;YAAE,SAAS;QACtD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,YAAY,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/F,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,KAAK,MAAM,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,KAAK,CAAC,IAAI,EAAE,CAAC;IACb,MAAM,SAAS,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7D,OAAO,UAAU,MAAM,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC;AACtD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,MAAgC;IACjF,MAAM,IAAI,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,CAAC,KAAK;QAAE,OAAO,QAAQ,CAAC;IAC5B,KAAK,CAAC,GAAG,CACP,QAAQ,EACR,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACrB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,SAAS,EAAE,KAAK,CAAC,SAAS;KAC3B,CAAC,CAAC,CACJ,CAAC;IACF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { type ArtifactLayer, type ArtifactSelector, type PlatformTarget } from "@telorun/analyzer";
|
|
2
|
+
import { type Logger } from "@telorun/sdk";
|
|
3
|
+
import type { TransportRegistry } from "../transports/transport-registry.js";
|
|
4
|
+
/** A materialized layer: the directory its files were extracted into (the
|
|
5
|
+
* module's cache directory) and the manifest-relative paths it wrote. */
|
|
6
|
+
export interface MaterializedLayer {
|
|
7
|
+
dir: string;
|
|
8
|
+
files: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare function hostPlatformTarget(): PlatformTarget;
|
|
11
|
+
/**
|
|
12
|
+
* A module's artifact, scoped to one loaded module.
|
|
13
|
+
*
|
|
14
|
+
* Built during module load, where the **pinned** import ref and the
|
|
15
|
+
* already-verified manifest are both in hand — which is the whole reason this
|
|
16
|
+
* exists as its own object rather than as logic inside a controller loader. A
|
|
17
|
+
* loader is handed only the canonical base URI, which carries no `#sha256-`, so
|
|
18
|
+
* a loader that fetched for itself would have to re-read the layer index off the
|
|
19
|
+
* cache directory: verification silently downgraded from "anchored at the
|
|
20
|
+
* importer's pin" to "trust whatever is already on disk".
|
|
21
|
+
*
|
|
22
|
+
* Materialization is per layer, memoized in-process, and guarded by the shared
|
|
23
|
+
* cross-process directory lock — oauth-client alone has seventeen definitions
|
|
24
|
+
* resolving concurrently against one controller layer, and several kernels may
|
|
25
|
+
* populate one cache directory at once.
|
|
26
|
+
*
|
|
27
|
+
* Verification runs before extraction: the transport checks the transfer against
|
|
28
|
+
* the layer's `blob` digest, and the extracted file set is checked against its
|
|
29
|
+
* `integrity` content digest here. A per-layer marker keyed by the blob digest
|
|
30
|
+
* records success, so a republish to different bytes re-extracts rather than
|
|
31
|
+
* being mistaken for an already-populated layer.
|
|
32
|
+
*/
|
|
33
|
+
export declare class ModuleArtifact {
|
|
34
|
+
/** The importer's pinned ref — what the transport verifies the manifest layer
|
|
35
|
+
* against, and what keeps the Merkle chain anchored. */
|
|
36
|
+
private readonly pinnedRef;
|
|
37
|
+
private readonly layers;
|
|
38
|
+
private readonly dir;
|
|
39
|
+
private readonly transports;
|
|
40
|
+
private readonly log;
|
|
41
|
+
/** In-flight / completed materializations, keyed by blob digest. Rejections
|
|
42
|
+
* are dropped so a transient fetch failure retries on the next ask. */
|
|
43
|
+
private readonly inFlight;
|
|
44
|
+
constructor(opts: {
|
|
45
|
+
pinnedRef: string;
|
|
46
|
+
layers: readonly ArtifactLayer[];
|
|
47
|
+
dir: string;
|
|
48
|
+
transports: TransportRegistry;
|
|
49
|
+
log?: Logger;
|
|
50
|
+
});
|
|
51
|
+
/** The module's local directory — where every materialized layer lands, and
|
|
52
|
+
* what a module-relative path resolves against. */
|
|
53
|
+
get directory(): string;
|
|
54
|
+
/**
|
|
55
|
+
* Materialize the layer carrying `selector` exactly, plus the `common` layer.
|
|
56
|
+
*
|
|
57
|
+
* Looked up by exact selector key rather than by re-matching the host: the
|
|
58
|
+
* candidate being resolved already *is* one selector, and it is by construction
|
|
59
|
+
* the key of the layer that carries it. Re-matching would take the first layer
|
|
60
|
+
* in declaration order that the host satisfies, so a module shipping both a
|
|
61
|
+
* platform-neutral and a platform-constrained layer of one format would fetch
|
|
62
|
+
* whichever came first regardless of which candidate asked — materializing the
|
|
63
|
+
* wrong layer and then reporting "bundle not found".
|
|
64
|
+
*
|
|
65
|
+
* The `common` layer rides along because it is the sink for files no candidate
|
|
66
|
+
* claimed — an undeclared sidecar an entry point loads at runtime. Pulling it
|
|
67
|
+
* with any controller layer is what makes a forgotten declaration cost bytes
|
|
68
|
+
* instead of a module-not-found at import.
|
|
69
|
+
*
|
|
70
|
+
* Returns `undefined` when the artifact ships no layer for this selector, which
|
|
71
|
+
* is how a loader learns to fall through to the next candidate.
|
|
72
|
+
*/
|
|
73
|
+
materializeController(selector: ArtifactSelector): Promise<MaterializedLayer | undefined>;
|
|
74
|
+
/**
|
|
75
|
+
* Materialize everything a module-relative file read could need: the `assets`
|
|
76
|
+
* layer **and** the `common` layer.
|
|
77
|
+
*
|
|
78
|
+
* Both, because `common` is where the sink rule puts a file the author did not
|
|
79
|
+
* claim via `assets:` — and a module that ships static files but has no bundled
|
|
80
|
+
* controller has no other path to its own payload. Assets alone would leave such
|
|
81
|
+
* a module's `Http.Static` root resolving into an empty directory, which is the
|
|
82
|
+
* exact silent failure this design promises not to have.
|
|
83
|
+
*/
|
|
84
|
+
materializeModuleFiles(): Promise<void>;
|
|
85
|
+
/** Materialize the lazily-fetched `assets` layer, if the module ships one. */
|
|
86
|
+
materializeAssets(): Promise<MaterializedLayer | undefined>;
|
|
87
|
+
/** Materialize the `common` layer, if the module ships one. */
|
|
88
|
+
materializeCommon(): Promise<MaterializedLayer | undefined>;
|
|
89
|
+
/**
|
|
90
|
+
* Materialize every layer a `target` platform could need — both singletons and
|
|
91
|
+
* each controller layer matching it. `telo install`'s make-this-offline pass,
|
|
92
|
+
* where being exhaustive for one platform is the point.
|
|
93
|
+
*/
|
|
94
|
+
materializeAll(target: PlatformTarget): Promise<MaterializedLayer[]>;
|
|
95
|
+
/** Human-facing description of what this artifact ships, for diagnostics that
|
|
96
|
+
* have to explain why no layer matched. */
|
|
97
|
+
describeLayers(): string;
|
|
98
|
+
private materialize;
|
|
99
|
+
private markerPath;
|
|
100
|
+
private materializeUncached;
|
|
101
|
+
private extract;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The directory a module's layers live in.
|
|
105
|
+
*
|
|
106
|
+
* Derived from the **pinned** `requestedUrl`, not the canonical `source`, because
|
|
107
|
+
* those diverge exactly when the manifest cache is warm: a cache hit is served as
|
|
108
|
+
* a `file://` URL into `.telo/manifests/`, which no transport claims, so a
|
|
109
|
+
* `source`-derived path is `null` on every run after the first. The pinned ref is
|
|
110
|
+
* what the importer wrote and survives the hit, so it places the module
|
|
111
|
+
* identically cold and warm. A genuinely local `source` (development, or a module
|
|
112
|
+
* loaded straight off disk) resolves to its own directory.
|
|
113
|
+
*
|
|
114
|
+
* Returns `null` when neither route yields a directory — a `memory://` module, or
|
|
115
|
+
* a ref this cache has no coordinates for.
|
|
116
|
+
*/
|
|
117
|
+
export declare function moduleDirectoryFor(requestedUrl: string, source: string, entryDir: string, registryUrl: string | undefined, manifestsDir: string | undefined): string | null;
|
|
118
|
+
/**
|
|
119
|
+
* Build the artifact handle for a loaded module, or `undefined` when the module
|
|
120
|
+
* has no payload to materialize.
|
|
121
|
+
*
|
|
122
|
+
* The trigger is the presence of a `layers:` index — a module that ships nothing
|
|
123
|
+
* needs no handle. `pinnedRef` is the ref **as the importer wrote it**, integrity
|
|
124
|
+
* fragment included, which is what keeps verification anchored to the importer's
|
|
125
|
+
* pin; `moduleDir` is where its layers extract to (see {@link moduleDirectoryFor}).
|
|
126
|
+
*/
|
|
127
|
+
export declare function moduleArtifactFor(opts: {
|
|
128
|
+
pinnedRef: string;
|
|
129
|
+
layers: readonly ArtifactLayer[] | undefined;
|
|
130
|
+
moduleDir: string | null;
|
|
131
|
+
transports: TransportRegistry;
|
|
132
|
+
log?: Logger;
|
|
133
|
+
}): ModuleArtifact | undefined;
|
|
134
|
+
//# sourceMappingURL=module-artifact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-artifact.d.ts","sourceRoot":"","sources":["../../src/bundle/module-artifact.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAA6B,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAQtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAG7E;0EAC0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AA2DD,wBAAgB,kBAAkB,IAAI,cAAc,CAOnD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,cAAc;IACzB;6DACyD;IACzD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAClD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B;4EACwE;IACxE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiD;gBAE9D,IAAI,EAAE;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;QACjC,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,EAAE,iBAAiB,CAAC;QAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;KACd;IAQD;wDACoD;IACpD,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACG,qBAAqB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAU/F;;;;;;;;;OASG;IACG,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7C,8EAA8E;IACxE,iBAAiB,IAAI,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAKjE,+DAA+D;IACzD,iBAAiB,IAAI,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAKjE;;;;OAIG;IACG,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAW1E;gDAC4C;IAC5C,cAAc,IAAI,MAAM;IAOxB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,UAAU;YAQJ,mBAAmB;YA0CnB,OAAO;CAkBtB;AAOD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,MAAM,GAAG,IAAI,CAWf;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,SAAS,CAAC;IAC7C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,cAAc,GAAG,SAAS,CAU7B"}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { matchControllerLayers, selectorKey, singletonLayer, splitIntegrity, describeSelector, } from "@telorun/analyzer";
|
|
2
|
+
import { NOOP_LOGGER, RuntimeError } from "@telorun/sdk";
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
import * as fs from "fs/promises";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
import { withDirectoryLock } from "../directory-lock.js";
|
|
8
|
+
import { cachePathForCanonical } from "../manifest-sources/local-manifest-cache-source.js";
|
|
9
|
+
import { computeFilesIntegrity } from "./files-integrity.js";
|
|
10
|
+
/**
|
|
11
|
+
* Map Node's platform vocabulary onto the canonical OCI/GOOS names selectors are
|
|
12
|
+
* published with. Node says `win32`/`x64`; OCI descriptors say
|
|
13
|
+
* `windows`/`amd64`, and the published artifact is what has to be matched.
|
|
14
|
+
*/
|
|
15
|
+
const NODE_OS_TO_OCI = {
|
|
16
|
+
win32: "windows",
|
|
17
|
+
darwin: "darwin",
|
|
18
|
+
linux: "linux",
|
|
19
|
+
freebsd: "freebsd",
|
|
20
|
+
openbsd: "openbsd",
|
|
21
|
+
sunos: "solaris",
|
|
22
|
+
aix: "aix",
|
|
23
|
+
};
|
|
24
|
+
const NODE_ARCH_TO_OCI = {
|
|
25
|
+
x64: "amd64",
|
|
26
|
+
ia32: "386",
|
|
27
|
+
arm64: "arm64",
|
|
28
|
+
arm: "arm",
|
|
29
|
+
ppc64: "ppc64le",
|
|
30
|
+
s390x: "s390x",
|
|
31
|
+
riscv64: "riscv64",
|
|
32
|
+
loong64: "loong64",
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Which libc this process is linked against, or `undefined` when it cannot be
|
|
36
|
+
* determined. Undetermined is deliberately *not* guessed: a selector that
|
|
37
|
+
* constrains `libc` then matches nothing, so a glibc binary is never handed to
|
|
38
|
+
* an Alpine host on the assumption it will run. Node reports
|
|
39
|
+
* `glibcVersionRuntime` in its process report only on a glibc build, which makes
|
|
40
|
+
* its absence on Linux the musl signal.
|
|
41
|
+
*/
|
|
42
|
+
function detectLibc() {
|
|
43
|
+
if (process.platform !== "linux")
|
|
44
|
+
return undefined;
|
|
45
|
+
try {
|
|
46
|
+
const report = process.report?.getReport();
|
|
47
|
+
return report?.header?.glibcVersionRuntime ? "gnu" : "musl";
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The platform this kernel is running on, in the published vocabulary. An axis
|
|
55
|
+
* Node cannot name is left absent rather than guessed.
|
|
56
|
+
*
|
|
57
|
+
* Computed once: the host cannot change mid-process, and `detectLibc` generates a
|
|
58
|
+
* full Node diagnostic report (a heap and stack walk costing tens of milliseconds).
|
|
59
|
+
* The controller loader asks per candidate per definition — oauth-client alone has
|
|
60
|
+
* seventeen — so recomputing would put that squarely inside the init loop.
|
|
61
|
+
*/
|
|
62
|
+
let cachedHostTarget;
|
|
63
|
+
export function hostPlatformTarget() {
|
|
64
|
+
cachedHostTarget ?? (cachedHostTarget = {
|
|
65
|
+
os: NODE_OS_TO_OCI[process.platform],
|
|
66
|
+
arch: NODE_ARCH_TO_OCI[process.arch],
|
|
67
|
+
libc: detectLibc(),
|
|
68
|
+
});
|
|
69
|
+
return cachedHostTarget;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* A module's artifact, scoped to one loaded module.
|
|
73
|
+
*
|
|
74
|
+
* Built during module load, where the **pinned** import ref and the
|
|
75
|
+
* already-verified manifest are both in hand — which is the whole reason this
|
|
76
|
+
* exists as its own object rather than as logic inside a controller loader. A
|
|
77
|
+
* loader is handed only the canonical base URI, which carries no `#sha256-`, so
|
|
78
|
+
* a loader that fetched for itself would have to re-read the layer index off the
|
|
79
|
+
* cache directory: verification silently downgraded from "anchored at the
|
|
80
|
+
* importer's pin" to "trust whatever is already on disk".
|
|
81
|
+
*
|
|
82
|
+
* Materialization is per layer, memoized in-process, and guarded by the shared
|
|
83
|
+
* cross-process directory lock — oauth-client alone has seventeen definitions
|
|
84
|
+
* resolving concurrently against one controller layer, and several kernels may
|
|
85
|
+
* populate one cache directory at once.
|
|
86
|
+
*
|
|
87
|
+
* Verification runs before extraction: the transport checks the transfer against
|
|
88
|
+
* the layer's `blob` digest, and the extracted file set is checked against its
|
|
89
|
+
* `integrity` content digest here. A per-layer marker keyed by the blob digest
|
|
90
|
+
* records success, so a republish to different bytes re-extracts rather than
|
|
91
|
+
* being mistaken for an already-populated layer.
|
|
92
|
+
*/
|
|
93
|
+
export class ModuleArtifact {
|
|
94
|
+
constructor(opts) {
|
|
95
|
+
/** In-flight / completed materializations, keyed by blob digest. Rejections
|
|
96
|
+
* are dropped so a transient fetch failure retries on the next ask. */
|
|
97
|
+
this.inFlight = new Map();
|
|
98
|
+
this.pinnedRef = opts.pinnedRef;
|
|
99
|
+
this.layers = opts.layers;
|
|
100
|
+
this.dir = opts.dir;
|
|
101
|
+
this.transports = opts.transports;
|
|
102
|
+
this.log = opts.log ?? NOOP_LOGGER;
|
|
103
|
+
}
|
|
104
|
+
/** The module's local directory — where every materialized layer lands, and
|
|
105
|
+
* what a module-relative path resolves against. */
|
|
106
|
+
get directory() {
|
|
107
|
+
return this.dir;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Materialize the layer carrying `selector` exactly, plus the `common` layer.
|
|
111
|
+
*
|
|
112
|
+
* Looked up by exact selector key rather than by re-matching the host: the
|
|
113
|
+
* candidate being resolved already *is* one selector, and it is by construction
|
|
114
|
+
* the key of the layer that carries it. Re-matching would take the first layer
|
|
115
|
+
* in declaration order that the host satisfies, so a module shipping both a
|
|
116
|
+
* platform-neutral and a platform-constrained layer of one format would fetch
|
|
117
|
+
* whichever came first regardless of which candidate asked — materializing the
|
|
118
|
+
* wrong layer and then reporting "bundle not found".
|
|
119
|
+
*
|
|
120
|
+
* The `common` layer rides along because it is the sink for files no candidate
|
|
121
|
+
* claimed — an undeclared sidecar an entry point loads at runtime. Pulling it
|
|
122
|
+
* with any controller layer is what makes a forgotten declaration cost bytes
|
|
123
|
+
* instead of a module-not-found at import.
|
|
124
|
+
*
|
|
125
|
+
* Returns `undefined` when the artifact ships no layer for this selector, which
|
|
126
|
+
* is how a loader learns to fall through to the next candidate.
|
|
127
|
+
*/
|
|
128
|
+
async materializeController(selector) {
|
|
129
|
+
const key = selectorKey(selector);
|
|
130
|
+
const layer = this.layers.find((l) => l.role === "controller" && l.selector !== undefined && selectorKey(l.selector) === key);
|
|
131
|
+
if (!layer)
|
|
132
|
+
return undefined;
|
|
133
|
+
await this.materializeCommon();
|
|
134
|
+
return this.materialize(layer);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Materialize everything a module-relative file read could need: the `assets`
|
|
138
|
+
* layer **and** the `common` layer.
|
|
139
|
+
*
|
|
140
|
+
* Both, because `common` is where the sink rule puts a file the author did not
|
|
141
|
+
* claim via `assets:` — and a module that ships static files but has no bundled
|
|
142
|
+
* controller has no other path to its own payload. Assets alone would leave such
|
|
143
|
+
* a module's `Http.Static` root resolving into an empty directory, which is the
|
|
144
|
+
* exact silent failure this design promises not to have.
|
|
145
|
+
*/
|
|
146
|
+
async materializeModuleFiles() {
|
|
147
|
+
await Promise.all([this.materializeAssets(), this.materializeCommon()]);
|
|
148
|
+
}
|
|
149
|
+
/** Materialize the lazily-fetched `assets` layer, if the module ships one. */
|
|
150
|
+
async materializeAssets() {
|
|
151
|
+
const layer = singletonLayer(this.layers, "assets");
|
|
152
|
+
return layer ? this.materialize(layer) : undefined;
|
|
153
|
+
}
|
|
154
|
+
/** Materialize the `common` layer, if the module ships one. */
|
|
155
|
+
async materializeCommon() {
|
|
156
|
+
const layer = singletonLayer(this.layers, "common");
|
|
157
|
+
return layer ? this.materialize(layer) : undefined;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Materialize every layer a `target` platform could need — both singletons and
|
|
161
|
+
* each controller layer matching it. `telo install`'s make-this-offline pass,
|
|
162
|
+
* where being exhaustive for one platform is the point.
|
|
163
|
+
*/
|
|
164
|
+
async materializeAll(target) {
|
|
165
|
+
const wanted = [
|
|
166
|
+
...matchControllerLayers(this.layers, target),
|
|
167
|
+
singletonLayer(this.layers, "assets"),
|
|
168
|
+
singletonLayer(this.layers, "common"),
|
|
169
|
+
].filter((l) => l !== undefined);
|
|
170
|
+
const out = [];
|
|
171
|
+
for (const layer of wanted)
|
|
172
|
+
out.push(await this.materialize(layer));
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
/** Human-facing description of what this artifact ships, for diagnostics that
|
|
176
|
+
* have to explain why no layer matched. */
|
|
177
|
+
describeLayers() {
|
|
178
|
+
if (this.layers.length === 0)
|
|
179
|
+
return "(no payload layers)";
|
|
180
|
+
return this.layers
|
|
181
|
+
.map((l) => (l.selector ? `${l.role} ${describeSelector(l.selector)}` : l.role))
|
|
182
|
+
.join(", ");
|
|
183
|
+
}
|
|
184
|
+
materialize(layer) {
|
|
185
|
+
const pending = this.inFlight.get(layer.blob);
|
|
186
|
+
if (pending)
|
|
187
|
+
return pending;
|
|
188
|
+
const work = this.materializeUncached(layer).catch((err) => {
|
|
189
|
+
// Drop the rejection so a transient fetch failure is retried rather than
|
|
190
|
+
// cached for the lifetime of the module.
|
|
191
|
+
this.inFlight.delete(layer.blob);
|
|
192
|
+
throw err;
|
|
193
|
+
});
|
|
194
|
+
this.inFlight.set(layer.blob, work);
|
|
195
|
+
return work;
|
|
196
|
+
}
|
|
197
|
+
markerPath(layer) {
|
|
198
|
+
// Keyed by the blob digest, so a republish to different bytes gets a new
|
|
199
|
+
// marker and re-extracts instead of being read as already-populated. The
|
|
200
|
+
// role is in the name purely so a human can tell the markers apart.
|
|
201
|
+
const short = layer.blob.replace(/^sha256:/, "").slice(0, 16);
|
|
202
|
+
return path.join(this.dir, `.telo-layer-${layer.role}-${short}`);
|
|
203
|
+
}
|
|
204
|
+
async materializeUncached(layer) {
|
|
205
|
+
const marker = this.markerPath(layer);
|
|
206
|
+
if (existsSync(marker)) {
|
|
207
|
+
return { dir: this.dir, files: await readMarker(marker) };
|
|
208
|
+
}
|
|
209
|
+
return withDirectoryLock(this.dir, "module layer", async () => {
|
|
210
|
+
// Re-check inside the lock: a peer may have extracted this layer between
|
|
211
|
+
// the fast-path miss and our acquisition.
|
|
212
|
+
if (existsSync(marker)) {
|
|
213
|
+
return { dir: this.dir, files: await readMarker(marker) };
|
|
214
|
+
}
|
|
215
|
+
const files = await this.transports.fetchLayer(this.pinnedRef, layer.blob);
|
|
216
|
+
const actual = await computeFilesIntegrity(files);
|
|
217
|
+
if (actual !== layer.integrity) {
|
|
218
|
+
throw new RuntimeError("ERR_MODULE_LAYER_INTEGRITY", `Integrity check failed for the ${layer.role} layer of ${this.pinnedRef}: ` +
|
|
219
|
+
`expected ${layer.integrity}, got ${actual}. The layer's contents do not match ` +
|
|
220
|
+
`the digest recorded in the module's pinned telo.yaml — it may have been ` +
|
|
221
|
+
`tampered with or republished.`);
|
|
222
|
+
}
|
|
223
|
+
const written = await this.extract(files, layer);
|
|
224
|
+
// Marker last, so a partial extraction leaves none and re-runs.
|
|
225
|
+
await fs.writeFile(marker, `${written.join("\n")}\n`, "utf-8");
|
|
226
|
+
this.log.debug("materialized module layer", {
|
|
227
|
+
"telo.module.ref": this.pinnedRef,
|
|
228
|
+
"telo.layer.role": layer.role,
|
|
229
|
+
"telo.layer.files": written.length,
|
|
230
|
+
});
|
|
231
|
+
return { dir: this.dir, files: written };
|
|
232
|
+
}, this.log);
|
|
233
|
+
}
|
|
234
|
+
async extract(files, layer) {
|
|
235
|
+
const root = path.resolve(this.dir) + path.sep;
|
|
236
|
+
const written = [];
|
|
237
|
+
for (const entry of files) {
|
|
238
|
+
const dest = path.resolve(this.dir, entry.name);
|
|
239
|
+
if (!dest.startsWith(root)) {
|
|
240
|
+
throw new RuntimeError("ERR_MODULE_LAYER_INVALID", `The ${layer.role} layer of ${this.pinnedRef} contains entry '${entry.name}', which ` +
|
|
241
|
+
`resolves outside the module's cache directory.`);
|
|
242
|
+
}
|
|
243
|
+
await fs.mkdir(path.dirname(dest), { recursive: true });
|
|
244
|
+
await fs.writeFile(dest, entry.content);
|
|
245
|
+
written.push(entry.name);
|
|
246
|
+
}
|
|
247
|
+
return written.sort();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
async function readMarker(marker) {
|
|
251
|
+
const text = await fs.readFile(marker, "utf-8");
|
|
252
|
+
return text.split("\n").filter((line) => line !== "");
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* The directory a module's layers live in.
|
|
256
|
+
*
|
|
257
|
+
* Derived from the **pinned** `requestedUrl`, not the canonical `source`, because
|
|
258
|
+
* those diverge exactly when the manifest cache is warm: a cache hit is served as
|
|
259
|
+
* a `file://` URL into `.telo/manifests/`, which no transport claims, so a
|
|
260
|
+
* `source`-derived path is `null` on every run after the first. The pinned ref is
|
|
261
|
+
* what the importer wrote and survives the hit, so it places the module
|
|
262
|
+
* identically cold and warm. A genuinely local `source` (development, or a module
|
|
263
|
+
* loaded straight off disk) resolves to its own directory.
|
|
264
|
+
*
|
|
265
|
+
* Returns `null` when neither route yields a directory — a `memory://` module, or
|
|
266
|
+
* a ref this cache has no coordinates for.
|
|
267
|
+
*/
|
|
268
|
+
export function moduleDirectoryFor(requestedUrl, source, entryDir, registryUrl, manifestsDir) {
|
|
269
|
+
const cacheFile = cachePathForCanonical(splitIntegrity(requestedUrl).base, entryDir, registryUrl, manifestsDir);
|
|
270
|
+
if (cacheFile)
|
|
271
|
+
return path.dirname(cacheFile);
|
|
272
|
+
if (source.startsWith("file://"))
|
|
273
|
+
return path.dirname(fileURLToPath(source));
|
|
274
|
+
if (path.isAbsolute(source))
|
|
275
|
+
return path.dirname(source);
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Build the artifact handle for a loaded module, or `undefined` when the module
|
|
280
|
+
* has no payload to materialize.
|
|
281
|
+
*
|
|
282
|
+
* The trigger is the presence of a `layers:` index — a module that ships nothing
|
|
283
|
+
* needs no handle. `pinnedRef` is the ref **as the importer wrote it**, integrity
|
|
284
|
+
* fragment included, which is what keeps verification anchored to the importer's
|
|
285
|
+
* pin; `moduleDir` is where its layers extract to (see {@link moduleDirectoryFor}).
|
|
286
|
+
*/
|
|
287
|
+
export function moduleArtifactFor(opts) {
|
|
288
|
+
if (!opts.layers || opts.layers.length === 0)
|
|
289
|
+
return undefined;
|
|
290
|
+
if (!opts.moduleDir)
|
|
291
|
+
return undefined;
|
|
292
|
+
return new ModuleArtifact({
|
|
293
|
+
pinnedRef: opts.pinnedRef,
|
|
294
|
+
layers: opts.layers,
|
|
295
|
+
dir: opts.moduleDir,
|
|
296
|
+
transports: opts.transports,
|
|
297
|
+
log: opts.log,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=module-artifact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-artifact.js","sourceRoot":"","sources":["../../src/bundle/module-artifact.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,16 +1,24 @@
|
|
|
1
|
+
import { type ArtifactLayer } from "@telorun/analyzer";
|
|
1
2
|
import { type Document } from "yaml";
|
|
2
3
|
/** Parse a manifest's YAML documents, tolerating its `!cel` / `!ref` tags. */
|
|
3
4
|
export declare function parseManifestDocs(text: string): Document[];
|
|
4
5
|
/** The owner document of a manifest — the single `Telo.Application` /
|
|
5
|
-
* `Telo.Library` doc that carries its identity, `files:`, and
|
|
6
|
-
* The one place that selects it, shared by every
|
|
6
|
+
* `Telo.Library` doc that carries its identity, `files:` / `assets:`, and the
|
|
7
|
+
* published `layers:` index. The one place that selects it, shared by every
|
|
8
|
+
* reader/writer. */
|
|
7
9
|
export declare function findOwnerDoc(docs: Document[]): Document | undefined;
|
|
8
10
|
/** The owner-doc fields the transports read: identity for the publish location,
|
|
9
11
|
* and payload markers for artifact fetch. */
|
|
10
12
|
export interface OwnerManifest {
|
|
11
13
|
name?: string;
|
|
12
14
|
version?: string;
|
|
13
|
-
|
|
15
|
+
/** The published layer index, absent on an unpublished manifest. Parsed and
|
|
16
|
+
* validated through the analyzer's shared model, so a malformed index is a
|
|
17
|
+
* hard `LayerIndexError` rather than a silently ignored field. */
|
|
18
|
+
layers?: ArtifactLayer[];
|
|
19
|
+
/** Ordered `.gitignore`-style patterns the author claimed as the lazily
|
|
20
|
+
* materialized `assets` layer. */
|
|
21
|
+
assetPatterns: string[];
|
|
14
22
|
/** True when the owner doc declares a non-empty `files:` list. */
|
|
15
23
|
declaresFiles: boolean;
|
|
16
24
|
/** Descriptive provenance a transport projects into its backend's metadata
|
|
@@ -22,6 +30,6 @@ export interface OwnerManifest {
|
|
|
22
30
|
}
|
|
23
31
|
/** Read the owner doc's identity + payload fields from a manifest, parsing once
|
|
24
32
|
* (never regex-scraping). The single source both transports call for the
|
|
25
|
-
* module's name and version,
|
|
33
|
+
* module's name and version, its layer index, and payload detection. */
|
|
26
34
|
export declare function readOwnerManifest(text: string): OwnerManifest;
|
|
27
35
|
//# sourceMappingURL=module-manifest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-manifest.d.ts","sourceRoot":"","sources":["../../src/bundle/module-manifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"module-manifest.d.ts","sourceRoot":"","sources":["../../src/bundle/module-manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAExE,OAAO,EAAqB,KAAK,QAAQ,EAAE,MAAM,MAAM,CAAC;AAIxD,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAE1D;AAED;;;qBAGqB;AACrB,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,QAAQ,GAAG,SAAS,CAKnE;AAED;8CAC8C;AAC9C,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;uEAEmE;IACnE,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB;uCACmC;IACnC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,kEAAkE;IAClE,aAAa,EAAE,OAAO,CAAC;IACvB;iEAC6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;yEAEyE;AACzE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAyB7D"}
|