@telorun/kernel 0.42.0 → 0.43.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 +25 -0
- package/dist/bundle/files-integrity.d.ts.map +1 -0
- package/dist/bundle/files-integrity.js +40 -0
- package/dist/bundle/files-integrity.js.map +1 -0
- package/dist/bundle/module-manifest.d.ts +22 -0
- package/dist/bundle/module-manifest.d.ts.map +1 -0
- package/dist/bundle/module-manifest.js +33 -0
- package/dist/bundle/module-manifest.js.map +1 -0
- package/dist/bundle/tar.d.ts +20 -0
- package/dist/bundle/tar.d.ts.map +1 -0
- package/dist/bundle/tar.js +63 -0
- package/dist/bundle/tar.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/kernel.d.ts.map +1 -1
- package/dist/kernel.js +8 -2
- 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 +14 -93
- package/dist/manifest-sources/local-manifest-cache-source.js.map +1 -1
- package/dist/transports/oci/docker-credentials.d.ts +10 -0
- package/dist/transports/oci/docker-credentials.d.ts.map +1 -0
- package/dist/transports/oci/docker-credentials.js +75 -0
- package/dist/transports/oci/docker-credentials.js.map +1 -0
- package/dist/transports/oci/oci-client.d.ts +51 -0
- package/dist/transports/oci/oci-client.d.ts.map +1 -0
- package/dist/transports/oci/oci-client.js +170 -0
- package/dist/transports/oci/oci-client.js.map +1 -0
- package/dist/transports/oci/oci-ref.d.ts +21 -0
- package/dist/transports/oci/oci-ref.d.ts.map +1 -0
- package/dist/transports/oci/oci-ref.js +36 -0
- package/dist/transports/oci/oci-ref.js.map +1 -0
- package/dist/transports/oci/oci-transport.d.ts +29 -0
- package/dist/transports/oci/oci-transport.d.ts.map +1 -0
- package/dist/transports/oci/oci-transport.js +142 -0
- package/dist/transports/oci/oci-transport.js.map +1 -0
- package/dist/transports/registry-transport.d.ts +23 -0
- package/dist/transports/registry-transport.d.ts.map +1 -0
- package/dist/transports/registry-transport.js +225 -0
- package/dist/transports/registry-transport.js.map +1 -0
- package/dist/transports/transport-registry.d.ts +40 -0
- package/dist/transports/transport-registry.d.ts.map +1 -0
- package/dist/transports/transport-registry.js +70 -0
- package/dist/transports/transport-registry.js.map +1 -0
- package/dist/transports/transport.d.ts +92 -0
- package/dist/transports/transport.d.ts.map +1 -0
- package/dist/transports/transport.js +2 -0
- package/dist/transports/transport.js.map +1 -0
- package/package.json +6 -3
- package/src/bundle/files-integrity.ts +46 -0
- package/src/bundle/module-manifest.ts +49 -0
- package/src/bundle/tar.ts +78 -0
- package/src/index.ts +22 -0
- package/src/kernel.ts +7 -2
- package/src/manifest-sources/local-manifest-cache-source.ts +14 -99
- package/src/transports/oci/docker-credentials.ts +85 -0
- package/src/transports/oci/oci-client.ts +237 -0
- package/src/transports/oci/oci-ref.ts +53 -0
- package/src/transports/oci/oci-transport.ts +192 -0
- package/src/transports/registry-transport.ts +281 -0
- package/src/transports/transport-registry.ts +91 -0
- package/src/transports/transport.ts +112 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { DEFAULT_MANIFEST_FILENAME, IntegrityError, verifyIntegrity, } from "@telorun/analyzer";
|
|
2
|
+
import { computeFilesIntegrity, injectFilesIntegrity } from "../../bundle/files-integrity.js";
|
|
3
|
+
import { readOwnerManifest } from "../../bundle/module-manifest.js";
|
|
4
|
+
import { makeTarGz, readTarGz, toPayloadFiles } from "../../bundle/tar.js";
|
|
5
|
+
import { OciClient, OCI_MANIFEST_MEDIA_TYPE, TELO_LAYER_MEDIA_TYPE, } from "./oci-client.js";
|
|
6
|
+
import { OCI_SCHEME, isOciRef, parseOciRef } from "./oci-ref.js";
|
|
7
|
+
/** Pull the module blob, returning its extracted entries and the `telo.yaml`
|
|
8
|
+
* bytes, verified against the ref's inline hash and its own `filesIntegrity`. */
|
|
9
|
+
async function pullVerified(ref) {
|
|
10
|
+
const { host, repo, reference, integrity } = parseOciRef(ref);
|
|
11
|
+
const client = new OciClient(host, repo);
|
|
12
|
+
const manifest = await client.pullManifest(reference);
|
|
13
|
+
const layer = manifest.layers.find((l) => l.mediaType === TELO_LAYER_MEDIA_TYPE) ?? manifest.layers[0];
|
|
14
|
+
if (!layer) {
|
|
15
|
+
throw new Error(`OCI artifact ${ref} has no layers`);
|
|
16
|
+
}
|
|
17
|
+
const tar = await client.pullBlob(layer.digest);
|
|
18
|
+
const entries = await readTarGz(tar);
|
|
19
|
+
const teloEntry = entries.find((e) => e.name === DEFAULT_MANIFEST_FILENAME);
|
|
20
|
+
if (!teloEntry) {
|
|
21
|
+
throw new Error(`OCI artifact ${ref} blob does not contain ${DEFAULT_MANIFEST_FILENAME}`);
|
|
22
|
+
}
|
|
23
|
+
const manifestText = typeof teloEntry.content === "string" ? teloEntry.content : teloEntry.content.toString("utf-8");
|
|
24
|
+
// Telo's inline hash is authoritative; the OCI content digest only corroborates.
|
|
25
|
+
if (integrity) {
|
|
26
|
+
await verifyIntegrity(new TextEncoder().encode(manifestText), integrity, ref);
|
|
27
|
+
}
|
|
28
|
+
const files = toPayloadFiles(entries);
|
|
29
|
+
const { filesIntegrity } = readOwnerManifest(manifestText);
|
|
30
|
+
if (filesIntegrity) {
|
|
31
|
+
const actual = await computeFilesIntegrity(files);
|
|
32
|
+
if (actual !== filesIntegrity) {
|
|
33
|
+
throw new IntegrityError(`Integrity check failed for ${ref}: filesIntegrity expected ${filesIntegrity}, ` +
|
|
34
|
+
`got ${actual}. The payload does not match the recorded hash.`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { manifest: manifestText, files };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* OCI transport: `oci://host/repo@reference` modules on any OCI distribution
|
|
41
|
+
* registry (GHCR / ECR / Docker Hub / Harbor), over a hand-rolled minimal
|
|
42
|
+
* client. A module is a single artifact — one tar blob carrying `telo.yaml`
|
|
43
|
+
* and the `files:` payload — pushed under a standard OCI artifact manifest.
|
|
44
|
+
*
|
|
45
|
+
* Not browser-reachable (token handshake, Docker credentials, tar extraction),
|
|
46
|
+
* so its resolution `source` is Node-only; the editor resolves `oci://` imports
|
|
47
|
+
* through the discovery hub instead.
|
|
48
|
+
*/
|
|
49
|
+
export class OciTransport {
|
|
50
|
+
constructor() {
|
|
51
|
+
this.source = {
|
|
52
|
+
supports: (url) => this.supports(url),
|
|
53
|
+
read: async (url) => {
|
|
54
|
+
const { manifest } = await pullVerified(url);
|
|
55
|
+
const { host, repo, reference } = parseOciRef(url);
|
|
56
|
+
return { text: manifest, source: `${OCI_SCHEME}${host}/${repo}@${reference}` };
|
|
57
|
+
},
|
|
58
|
+
resolveRelative: (base, relative) => this.resolveRelative(base, relative),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
supports(ref) {
|
|
62
|
+
return isOciRef(ref);
|
|
63
|
+
}
|
|
64
|
+
cacheLocation(ref) {
|
|
65
|
+
let parsed;
|
|
66
|
+
try {
|
|
67
|
+
parsed = parseOciRef(ref);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return ["__oci", parsed.host, ...parsed.repo.split("/"), parsed.reference];
|
|
73
|
+
}
|
|
74
|
+
/** Resolve a relative import against an `oci://` base, normalizing the repo to
|
|
75
|
+
* a directory base so `../lib` under `oci://ghcr.io/aws/my-app` →
|
|
76
|
+
* `oci://ghcr.io/aws/lib` (never `oci://ghcr.io/lib`). Non-relative refs pass
|
|
77
|
+
* through. The reference/tag is dropped — the caller re-pins from the
|
|
78
|
+
* sibling's own version. */
|
|
79
|
+
resolveRelative(base, relative) {
|
|
80
|
+
if (!relative.startsWith(".") && !relative.startsWith("/"))
|
|
81
|
+
return relative;
|
|
82
|
+
const { host, repo } = parseOciRef(base);
|
|
83
|
+
// Resolve the repo path with standard URL semantics against a directory base.
|
|
84
|
+
const resolved = new URL(relative, `https://${host}/${repo}/`);
|
|
85
|
+
const newRepo = resolved.pathname.replace(/^\/+/, "");
|
|
86
|
+
return `${OCI_SCHEME}${host}/${newRepo}`;
|
|
87
|
+
}
|
|
88
|
+
async listVersions(ref) {
|
|
89
|
+
const { host, repo } = parseOciRef(ref);
|
|
90
|
+
const tags = await new OciClient(host, repo).listTags();
|
|
91
|
+
return tags;
|
|
92
|
+
}
|
|
93
|
+
async fetchArtifact(ref) {
|
|
94
|
+
return pullVerified(ref);
|
|
95
|
+
}
|
|
96
|
+
async publish(destination, bundle, _opts = {}) {
|
|
97
|
+
const identity = readOwnerManifest(bundle.manifest);
|
|
98
|
+
if (!identity.version) {
|
|
99
|
+
throw new Error("OCI publish requires metadata.version (used as the tag).");
|
|
100
|
+
}
|
|
101
|
+
// Destination is a full repo (`oci://host/repo`) or host-only
|
|
102
|
+
// (`oci://host`), which defaults the repo to `<namespace>/<name>`.
|
|
103
|
+
const afterScheme = destination.replace(/^oci:\/\//, "").replace(/\/+$/, "");
|
|
104
|
+
const slash = afterScheme.indexOf("/");
|
|
105
|
+
const host = slash > 0 ? afterScheme.slice(0, slash) : afterScheme;
|
|
106
|
+
let repo = slash > 0 ? afterScheme.slice(slash + 1) : "";
|
|
107
|
+
if (!repo) {
|
|
108
|
+
if (!identity.namespace || !identity.name) {
|
|
109
|
+
throw new Error(`OCI publish to host-only '${destination}' needs metadata.namespace and metadata.name to default the repo.`);
|
|
110
|
+
}
|
|
111
|
+
repo = `${identity.namespace}/${identity.name}`;
|
|
112
|
+
}
|
|
113
|
+
const tag = identity.version;
|
|
114
|
+
// Pin the payload, then pack telo.yaml + files into the single module blob.
|
|
115
|
+
let manifestText = bundle.manifest;
|
|
116
|
+
if (bundle.files.length > 0) {
|
|
117
|
+
manifestText = injectFilesIntegrity(manifestText, await computeFilesIntegrity(bundle.files));
|
|
118
|
+
}
|
|
119
|
+
const tar = await makeTarGz([
|
|
120
|
+
{ name: DEFAULT_MANIFEST_FILENAME, content: manifestText },
|
|
121
|
+
...bundle.files.map((f) => ({ name: f.name, content: Buffer.from(f.content) })),
|
|
122
|
+
]);
|
|
123
|
+
const client = new OciClient(host, repo);
|
|
124
|
+
const layerDigest = await client.pushBlob(tar);
|
|
125
|
+
const config = await client.pushEmptyConfig();
|
|
126
|
+
const manifest = {
|
|
127
|
+
schemaVersion: 2,
|
|
128
|
+
mediaType: OCI_MANIFEST_MEDIA_TYPE,
|
|
129
|
+
artifactType: TELO_LAYER_MEDIA_TYPE,
|
|
130
|
+
config,
|
|
131
|
+
layers: [{ mediaType: TELO_LAYER_MEDIA_TYPE, digest: layerDigest, size: tar.length }],
|
|
132
|
+
};
|
|
133
|
+
await client.pushManifest(tag, manifest);
|
|
134
|
+
return { label: `${repo}@${tag}`, url: `${OCI_SCHEME}${host}/${repo}@${tag}` };
|
|
135
|
+
}
|
|
136
|
+
canonicalizeSiblingRef(destination, relativeSource, sibling) {
|
|
137
|
+
// The sibling's repo is the destination repo with the relative applied; the
|
|
138
|
+
// version is its own (identity is the ref, not metadata).
|
|
139
|
+
return `${this.resolveRelative(destination, relativeSource)}@${sibling.version}`;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=oci-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oci-transport.js","sourceRoot":"","sources":["../../../src/transports/oci/oci-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,cAAc,EACd,eAAe,GAEhB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC9F,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAS3E,OAAO,EACL,SAAS,EACT,uBAAuB,EACvB,qBAAqB,GAEtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEjE;kFACkF;AAClF,KAAK,UAAU,YAAY,CAAC,GAAW;IACrC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IACtD,MAAM,KAAK,GACT,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,qBAAqB,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC3F,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,gBAAgB,GAAG,gBAAgB,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;IAErC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,yBAAyB,CAAC,CAAC;IAC5E,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,gBAAgB,GAAG,0BAA0B,yBAAyB,EAAE,CAAC,CAAC;IAC5F,CAAC;IACD,MAAM,YAAY,GAChB,OAAO,SAAS,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAElG,iFAAiF;IACjF,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,eAAe,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;IAChF,CAAC;IAED,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAEtC,MAAM,EAAE,cAAc,EAAE,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC3D,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;YAC9B,MAAM,IAAI,cAAc,CACtB,8BAA8B,GAAG,6BAA6B,cAAc,IAAI;gBAC9E,OAAO,MAAM,iDAAiD,CACjE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AAC3C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,OAAO,YAAY;IAGvB;QACE,IAAI,CAAC,MAAM,GAAG;YACZ,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YACrC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;gBAClB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;gBAC7C,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;gBACnD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,UAAU,GAAG,IAAI,IAAI,IAAI,IAAI,SAAS,EAAE,EAAE,CAAC;YACjF,CAAC;YACD,eAAe,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC;SAC1E,CAAC;IACJ,CAAC;IAED,QAAQ,CAAC,GAAW;QAClB,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAED,aAAa,CAAC,GAAW;QACvB,IAAI,MAAsC,CAAC;QAC3C,IAAI,CAAC;YACH,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IAC7E,CAAC;IAED;;;;iCAI6B;IAC7B,eAAe,CAAC,IAAY,EAAE,QAAgB;QAC5C,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,QAAQ,CAAC;QAC5E,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACzC,8EAA8E;QAC9E,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,WAAW,IAAI,IAAI,IAAI,GAAG,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACtD,OAAO,GAAG,UAAU,GAAG,IAAI,IAAI,OAAO,EAAE,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,GAAW;QAC5B,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,MAAM,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QACxD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,GAAW;QAC7B,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,OAAO,CACX,WAAmB,EACnB,MAAqB,EACrB,QAAwB,EAAE;QAE1B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAC9E,CAAC;QAED,8DAA8D;QAC9D,mEAAmE;QACnE,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC7E,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QACnE,IAAI,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAC1C,MAAM,IAAI,KAAK,CACb,6BAA6B,WAAW,mEAAmE,CAC5G,CAAC;YACJ,CAAC;YACD,IAAI,GAAG,GAAG,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QAClD,CAAC;QACD,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC;QAE7B,4EAA4E;QAC5E,IAAI,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC;QACnC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,YAAY,GAAG,oBAAoB,CAAC,YAAY,EAAE,MAAM,qBAAqB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/F,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC;YAC1B,EAAE,IAAI,EAAE,yBAAyB,EAAE,OAAO,EAAE,YAAY,EAAE;YAC1D,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;SAChF,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACzC,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,eAAe,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAgB;YAC5B,aAAa,EAAE,CAAC;YAChB,SAAS,EAAE,uBAAuB;YAClC,YAAY,EAAE,qBAAqB;YACnC,MAAM;YACN,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC;SACtF,CAAC;QACF,MAAM,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAEzC,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,IAAI,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE,EAAE,CAAC;IACjF,CAAC;IAED,sBAAsB,CACpB,WAAmB,EACnB,cAAsB,EACtB,OAAwB;QAExB,4EAA4E;QAC5E,0DAA0D;QAC1D,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,cAAc,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IACnF,CAAC;CACF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ManifestSource } from "@telorun/analyzer";
|
|
2
|
+
import type { FetchedArtifact, PublishBundle, PublishOptions, PublishResult, SiblingIdentity, Transport } from "./transport.js";
|
|
3
|
+
/** The default HTTP transport: bare `namespace/name@version` registry refs and
|
|
4
|
+
* direct `https://…` URLs, resolving against `registry.telo.run` (or a
|
|
5
|
+
* configured registry). Its resolution `source` composes the browser-safe
|
|
6
|
+
* `RegistrySource` / `HttpSource` from `analyzer`; the Node-only management
|
|
7
|
+
* methods live here. This is the fallback transport for any ref that carries
|
|
8
|
+
* no owning scheme, so `oci://` (or a future `s3://`) never falls through to
|
|
9
|
+
* it — those refs are claimed by their own transport's `supports()`. */
|
|
10
|
+
export declare class RegistryTransport implements Transport {
|
|
11
|
+
private readonly registryUrl;
|
|
12
|
+
private readonly registrySource;
|
|
13
|
+
private readonly httpSource;
|
|
14
|
+
readonly source: ManifestSource;
|
|
15
|
+
constructor(registryUrl?: string);
|
|
16
|
+
supports(ref: string): boolean;
|
|
17
|
+
cacheLocation(ref: string): string[] | null;
|
|
18
|
+
listVersions(ref: string): Promise<string[] | null>;
|
|
19
|
+
fetchArtifact(ref: string): Promise<FetchedArtifact>;
|
|
20
|
+
publish(destination: string, bundle: PublishBundle, opts?: PublishOptions): Promise<PublishResult>;
|
|
21
|
+
canonicalizeSiblingRef(_destination: string, _relativeSource: string, sibling: SiblingIdentity): string;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=registry-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-transport.d.ts","sourceRoot":"","sources":["../../src/transports/registry-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,cAAc,EACd,aAAa,EACb,eAAe,EACf,SAAS,EACV,MAAM,gBAAgB,CAAC;AAiDxB;;;;;;yEAMyE;AACzE,qBAAa,iBAAkB,YAAW,SAAS;IAKrC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAJxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;gBAEH,WAAW,GAAE,MAA6B;IAYvE,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAK9B,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI;IA+CrC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;IAenD,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IA+BpD,OAAO,CACX,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,aAAa,EACrB,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,aAAa,CAAC;IAsEzB,sBAAsB,CACpB,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,eAAe,GACvB,MAAM;CASV"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { DEFAULT_MANIFEST_FILENAME, HttpSource, IntegrityError, RegistrySource, isRegistryRef, parseModuleRef, splitIntegrity, } from "@telorun/analyzer";
|
|
2
|
+
import { createHash } from "crypto";
|
|
3
|
+
import { computeFilesIntegrity, injectFilesIntegrity } from "../bundle/files-integrity.js";
|
|
4
|
+
import { readOwnerManifest } from "../bundle/module-manifest.js";
|
|
5
|
+
import { makeTarGz, readTarGz, toPayloadFiles } from "../bundle/tar.js";
|
|
6
|
+
const DEFAULT_REGISTRY_URL = "https://registry.telo.run";
|
|
7
|
+
const HTTP_NAMESPACE = "__http";
|
|
8
|
+
const QUERY_HASH_LENGTH = 12;
|
|
9
|
+
const MAX_PUSH_ATTEMPTS = 4;
|
|
10
|
+
const PUSH_BASE_DELAY_MS = 1000;
|
|
11
|
+
/** Registry / object-storage backends treat 408/425/429/5xx as transient. */
|
|
12
|
+
function isRetryableStatus(status) {
|
|
13
|
+
return status === 408 || status === 425 || status === 429 || status >= 500;
|
|
14
|
+
}
|
|
15
|
+
function sleep(ms) {
|
|
16
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
17
|
+
}
|
|
18
|
+
/** Mirror `HttpSource.read`'s `fetchUrl` derivation: when the URL does not
|
|
19
|
+
* already point at a YAML file, append `/telo.yaml`, so a raw import URL and
|
|
20
|
+
* the canonical source it resolves to map to the same cache path. */
|
|
21
|
+
function normalizePathname(rawUrl, parsed) {
|
|
22
|
+
let pathname = parsed.pathname;
|
|
23
|
+
if (!rawUrl.includes(".yaml")) {
|
|
24
|
+
pathname = pathname.endsWith("/")
|
|
25
|
+
? `${pathname}${DEFAULT_MANIFEST_FILENAME}`
|
|
26
|
+
: `${pathname}/${DEFAULT_MANIFEST_FILENAME}`;
|
|
27
|
+
}
|
|
28
|
+
return pathname;
|
|
29
|
+
}
|
|
30
|
+
/** Short hash of `search + hash` so two URLs that differ only in query /
|
|
31
|
+
* fragment do not collide at the same cache path. */
|
|
32
|
+
function disambiguatePath(pathname, search, hash) {
|
|
33
|
+
if (!search && !hash)
|
|
34
|
+
return pathname;
|
|
35
|
+
const digest = createHash("sha256")
|
|
36
|
+
.update(search + hash)
|
|
37
|
+
.digest("hex")
|
|
38
|
+
.slice(0, QUERY_HASH_LENGTH);
|
|
39
|
+
const dotIdx = pathname.lastIndexOf(".");
|
|
40
|
+
const slashIdx = pathname.lastIndexOf("/");
|
|
41
|
+
const ext = dotIdx > slashIdx ? pathname.slice(dotIdx) : "";
|
|
42
|
+
const base = pathname.slice(0, pathname.length - ext.length);
|
|
43
|
+
return `${base}.${digest}${ext}`;
|
|
44
|
+
}
|
|
45
|
+
/** The default HTTP transport: bare `namespace/name@version` registry refs and
|
|
46
|
+
* direct `https://…` URLs, resolving against `registry.telo.run` (or a
|
|
47
|
+
* configured registry). Its resolution `source` composes the browser-safe
|
|
48
|
+
* `RegistrySource` / `HttpSource` from `analyzer`; the Node-only management
|
|
49
|
+
* methods live here. This is the fallback transport for any ref that carries
|
|
50
|
+
* no owning scheme, so `oci://` (or a future `s3://`) never falls through to
|
|
51
|
+
* it — those refs are claimed by their own transport's `supports()`. */
|
|
52
|
+
export class RegistryTransport {
|
|
53
|
+
constructor(registryUrl = DEFAULT_REGISTRY_URL) {
|
|
54
|
+
this.registryUrl = registryUrl;
|
|
55
|
+
this.registrySource = new RegistrySource(registryUrl);
|
|
56
|
+
this.httpSource = new HttpSource();
|
|
57
|
+
const pick = (ref) => this.httpSource.supports(ref) ? this.httpSource : this.registrySource;
|
|
58
|
+
this.source = {
|
|
59
|
+
supports: (url) => this.supports(url),
|
|
60
|
+
read: (url) => pick(url).read(url),
|
|
61
|
+
resolveRelative: (base, relative) => pick(base).resolveRelative(base, relative),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
supports(ref) {
|
|
65
|
+
const { base } = splitIntegrity(ref);
|
|
66
|
+
return base.startsWith("http://") || base.startsWith("https://") || isRegistryRef(ref);
|
|
67
|
+
}
|
|
68
|
+
cacheLocation(ref) {
|
|
69
|
+
const url = splitIntegrity(ref).base;
|
|
70
|
+
const trimmedRegistry = this.registryUrl.replace(/\/+$/, "");
|
|
71
|
+
// 1. Registry ref form: namespace/name@version
|
|
72
|
+
if (isRegistryRef(url)) {
|
|
73
|
+
let parsed;
|
|
74
|
+
try {
|
|
75
|
+
parsed = parseModuleRef(url);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return [parsed.modulePath, parsed.version, DEFAULT_MANIFEST_FILENAME];
|
|
81
|
+
}
|
|
82
|
+
// 2. HTTP(S) URL — a direct registry URL or arbitrary external.
|
|
83
|
+
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
84
|
+
let parsed;
|
|
85
|
+
try {
|
|
86
|
+
parsed = new URL(url);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const pathname = normalizePathname(url, parsed);
|
|
92
|
+
// 2a. On the configured registry, no query/fragment: fold into the
|
|
93
|
+
// registry layout so a ref and a direct URL land on the same file.
|
|
94
|
+
const normalizedUrl = `${parsed.protocol}//${parsed.host}${pathname}`;
|
|
95
|
+
if (!parsed.search &&
|
|
96
|
+
!parsed.hash &&
|
|
97
|
+
(normalizedUrl === trimmedRegistry || normalizedUrl.startsWith(`${trimmedRegistry}/`))) {
|
|
98
|
+
const rel = normalizedUrl.slice(trimmedRegistry.length + 1);
|
|
99
|
+
if (!rel)
|
|
100
|
+
return null;
|
|
101
|
+
return rel.split("/");
|
|
102
|
+
}
|
|
103
|
+
// 2b. Arbitrary HTTP(S) → __http subtree, query-hash suffix on collision.
|
|
104
|
+
const cleanPath = pathname.startsWith("/") ? pathname.slice(1) : pathname;
|
|
105
|
+
const disambiguated = disambiguatePath(cleanPath, parsed.search, parsed.hash);
|
|
106
|
+
return [HTTP_NAMESPACE, parsed.host, ...disambiguated.split("/")];
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
async listVersions(ref) {
|
|
111
|
+
// Only bare registry refs are version-enumerable — a direct `https://` URL
|
|
112
|
+
// has no version-list endpoint.
|
|
113
|
+
if (!isRegistryRef(ref))
|
|
114
|
+
return null;
|
|
115
|
+
const { modulePath } = parseModuleRef(ref);
|
|
116
|
+
const url = `${this.registryUrl.replace(/\/+$/, "")}/${modulePath}`;
|
|
117
|
+
const res = await fetch(url, { headers: { accept: "application/json" } });
|
|
118
|
+
if (res.status === 404)
|
|
119
|
+
return null;
|
|
120
|
+
if (!res.ok) {
|
|
121
|
+
throw new Error(`Registry returned ${res.status} ${res.statusText} for ${modulePath}`);
|
|
122
|
+
}
|
|
123
|
+
const body = (await res.json());
|
|
124
|
+
return Array.isArray(body.versions) ? body.versions : [];
|
|
125
|
+
}
|
|
126
|
+
async fetchArtifact(ref) {
|
|
127
|
+
// `read` verifies the manifest bytes against the inline `#sha256-...` hash.
|
|
128
|
+
const { text: manifest, source } = await this.source.read(ref);
|
|
129
|
+
const meta = readOwnerManifest(manifest);
|
|
130
|
+
if (!meta.declaresFiles)
|
|
131
|
+
return { manifest, files: [] };
|
|
132
|
+
// The payload rides beside the manifest as `module.tar.gz`.
|
|
133
|
+
const tarUrl = source.replace(/\/telo\.yaml$/, "/module.tar.gz");
|
|
134
|
+
const res = await fetch(tarUrl);
|
|
135
|
+
if (!res.ok) {
|
|
136
|
+
throw new Error(`could not fetch bundle ${tarUrl}: ${res.status} ${res.statusText}`);
|
|
137
|
+
}
|
|
138
|
+
const files = toPayloadFiles(await readTarGz(Buffer.from(await res.arrayBuffer())));
|
|
139
|
+
// Verify the payload against the manifest's `filesIntegrity` before handing
|
|
140
|
+
// it back — a mismatch is terminal (a tampered bundle must never be used).
|
|
141
|
+
// The manifest that carries the hash is itself pinned by the inline hash.
|
|
142
|
+
if (meta.filesIntegrity) {
|
|
143
|
+
const actual = await computeFilesIntegrity(files);
|
|
144
|
+
if (actual !== meta.filesIntegrity) {
|
|
145
|
+
throw new IntegrityError(`Integrity check failed for bundle ${tarUrl}: filesIntegrity expected ` +
|
|
146
|
+
`${meta.filesIntegrity}, got ${actual}. The payload does not match the recorded ` +
|
|
147
|
+
`hash — the module may have been tampered with or republished.`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return { manifest, files };
|
|
151
|
+
}
|
|
152
|
+
async publish(destination, bundle, opts = {}) {
|
|
153
|
+
// Pin the payload in the manifest before it enters the tarball, then choose
|
|
154
|
+
// the artifact body: a `module.tar.gz` when there are files, else raw YAML.
|
|
155
|
+
let manifest = bundle.manifest;
|
|
156
|
+
let body = manifest;
|
|
157
|
+
let contentType = "text/yaml";
|
|
158
|
+
let urlSuffix = "";
|
|
159
|
+
if (bundle.files.length > 0) {
|
|
160
|
+
manifest = injectFilesIntegrity(manifest, await computeFilesIntegrity(bundle.files));
|
|
161
|
+
const entries = [
|
|
162
|
+
{ name: DEFAULT_MANIFEST_FILENAME, content: manifest },
|
|
163
|
+
...bundle.files.map((f) => ({ name: f.name, content: Buffer.from(f.content) })),
|
|
164
|
+
];
|
|
165
|
+
body = await makeTarGz(entries);
|
|
166
|
+
contentType = "application/gzip";
|
|
167
|
+
urlSuffix = "/module.tar.gz";
|
|
168
|
+
}
|
|
169
|
+
const { namespace, name, version } = readOwnerManifest(manifest);
|
|
170
|
+
if (!namespace || !name || !version) {
|
|
171
|
+
throw new Error("metadata must include namespace, name, and version.");
|
|
172
|
+
}
|
|
173
|
+
const identity = { namespace, name, version };
|
|
174
|
+
const base = `${destination.replace(/\/+$/, "")}/${identity.namespace}/${identity.name}/${identity.version}`;
|
|
175
|
+
const url = `${base}${urlSuffix}`;
|
|
176
|
+
const label = `${identity.namespace}/${identity.name}@${identity.version}`;
|
|
177
|
+
const headers = { "content-type": contentType };
|
|
178
|
+
if (opts.token)
|
|
179
|
+
headers.authorization = `Bearer ${opts.token}`;
|
|
180
|
+
let res = null;
|
|
181
|
+
let networkErr = null;
|
|
182
|
+
for (let attempt = 1; attempt <= MAX_PUSH_ATTEMPTS; attempt++) {
|
|
183
|
+
networkErr = null;
|
|
184
|
+
try {
|
|
185
|
+
res = await fetch(url, { method: "PUT", headers, body });
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
networkErr = err;
|
|
189
|
+
res = null;
|
|
190
|
+
}
|
|
191
|
+
const transient = networkErr != null || (res != null && isRetryableStatus(res.status));
|
|
192
|
+
if (!transient)
|
|
193
|
+
break;
|
|
194
|
+
if (attempt === MAX_PUSH_ATTEMPTS)
|
|
195
|
+
break;
|
|
196
|
+
const reason = networkErr
|
|
197
|
+
? `network error: ${networkErr instanceof Error ? networkErr.message : String(networkErr)}`
|
|
198
|
+
: `HTTP ${res.status}`;
|
|
199
|
+
// Drain the body so the underlying connection can be reused for the retry.
|
|
200
|
+
if (res)
|
|
201
|
+
await res.text().catch(() => { });
|
|
202
|
+
const delayMs = PUSH_BASE_DELAY_MS * 2 ** (attempt - 1) + Math.floor(Math.random() * 250);
|
|
203
|
+
opts.onRetry?.({ reason, attempt, maxAttempts: MAX_PUSH_ATTEMPTS, delayMs });
|
|
204
|
+
await sleep(delayMs);
|
|
205
|
+
}
|
|
206
|
+
if (networkErr) {
|
|
207
|
+
throw new Error(`Network error: ${networkErr instanceof Error ? networkErr.message : String(networkErr)} ` +
|
|
208
|
+
`(after ${MAX_PUSH_ATTEMPTS} attempts)`);
|
|
209
|
+
}
|
|
210
|
+
if (!res.ok) {
|
|
211
|
+
const ct = res.headers.get("content-type") ?? "";
|
|
212
|
+
const errBody = ct.includes("application/json") ? await res.json() : await res.text();
|
|
213
|
+
throw new Error(`Push failed (${res.status}): ${JSON.stringify(errBody)}`);
|
|
214
|
+
}
|
|
215
|
+
return { label, url };
|
|
216
|
+
}
|
|
217
|
+
canonicalizeSiblingRef(_destination, _relativeSource, sibling) {
|
|
218
|
+
// An HTTP registry path defaults to the sibling's own `<namespace>/<name>`.
|
|
219
|
+
if (!sibling.namespace || !sibling.name) {
|
|
220
|
+
throw new Error("a relative import canonicalized to an HTTP registry needs the sibling's metadata.namespace and metadata.name.");
|
|
221
|
+
}
|
|
222
|
+
return `${sibling.namespace}/${sibling.name}@${sibling.version}`;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=registry-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-transport.js","sourceRoot":"","sources":["../../src/transports/registry-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ManifestSource } from "@telorun/analyzer";
|
|
2
|
+
import type { FetchedArtifact, PublishBundle, PublishOptions, PublishResult, Transport } from "./transport.js";
|
|
3
|
+
/** Dispatches ref-scheme-specific operations to the transport that owns a ref.
|
|
4
|
+
* The loader, cache source, `upgrade`, and `publish` consult this instead of
|
|
5
|
+
* branching on ref shape. `RegistryTransport` is always last so it is the
|
|
6
|
+
* fallback for bare / `https` refs, and a scheme-owning transport (OCI, later
|
|
7
|
+
* S3) claims its refs via `supports()` before the fallback is reached. */
|
|
8
|
+
export declare class TransportRegistry {
|
|
9
|
+
private readonly transports;
|
|
10
|
+
constructor(transports: Transport[]);
|
|
11
|
+
/** The transport that owns `ref`, or `undefined` if none does. */
|
|
12
|
+
forRef(ref: string): Transport | undefined;
|
|
13
|
+
/** The resolution `ManifestSource`s of every registered transport, in order —
|
|
14
|
+
* the browser-safe subset the loader appends to its source chain. */
|
|
15
|
+
sources(): ManifestSource[];
|
|
16
|
+
/** Cache-path segments for `ref`, from its owning transport; `null` when no
|
|
17
|
+
* transport owns it or the ref is not cacheable. */
|
|
18
|
+
cacheLocation(ref: string): string[] | null;
|
|
19
|
+
/** Published versions for `ref` via its owning transport; `null` when the
|
|
20
|
+
* module is unpublished. Throws when no transport owns the ref. */
|
|
21
|
+
listVersions(ref: string): Promise<string[] | null>;
|
|
22
|
+
/** Full artifact for `ref` via its owning transport. Throws when no transport
|
|
23
|
+
* owns the ref. */
|
|
24
|
+
fetchArtifact(ref: string): Promise<FetchedArtifact>;
|
|
25
|
+
/** Publish `bundle` to `destination` via the transport its scheme selects.
|
|
26
|
+
* Throws when no transport owns the destination. */
|
|
27
|
+
publish(destination: string, bundle: PublishBundle, opts?: PublishOptions): Promise<PublishResult>;
|
|
28
|
+
private require;
|
|
29
|
+
}
|
|
30
|
+
/** The default transport set. Scheme-owning transports come first; the
|
|
31
|
+
* `RegistryTransport` is last, the fallback for bare / `https` refs. OCI (and
|
|
32
|
+
* later S3) claim their `oci://` / `s3://` refs before the fallback is reached. */
|
|
33
|
+
export declare function defaultTransports(registryUrl?: string): Transport[];
|
|
34
|
+
/** A `TransportRegistry` seeded with {@link defaultTransports}, memoized per
|
|
35
|
+
* `registryUrl`. The default transports are stateless config (a fresh
|
|
36
|
+
* `OciClient` with its own token cache is created per OCI operation), so one
|
|
37
|
+
* shared instance per registry URL is safe — and avoids re-instantiating the
|
|
38
|
+
* whole set on hot paths like `cachePathForCanonical`. */
|
|
39
|
+
export declare function defaultTransportRegistry(registryUrl?: string): TransportRegistry;
|
|
40
|
+
//# sourceMappingURL=transport-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-registry.d.ts","sourceRoot":"","sources":["../../src/transports/transport-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIxD,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,cAAc,EACd,aAAa,EACb,SAAS,EACV,MAAM,gBAAgB,CAAC;AAExB;;;;2EAI2E;AAC3E,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,SAAS,EAAE;IAEpD,kEAAkE;IAClE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI1C;0EACsE;IACtE,OAAO,IAAI,cAAc,EAAE;IAI3B;yDACqD;IACrD,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI;IAI3C;wEACoE;IACpE,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;IAInD;wBACoB;IACpB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAIpD;yDACqD;IACrD,OAAO,CACL,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,aAAa,EACrB,IAAI,CAAC,EAAE,cAAc,GACpB,OAAO,CAAC,aAAa,CAAC;IAIzB,OAAO,CAAC,OAAO;CAOhB;AAED;;oFAEoF;AACpF,wBAAgB,iBAAiB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CAEnE;AAID;;;;2DAI2D;AAC3D,wBAAgB,wBAAwB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAQhF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { OciTransport } from "./oci/oci-transport.js";
|
|
2
|
+
import { RegistryTransport } from "./registry-transport.js";
|
|
3
|
+
/** Dispatches ref-scheme-specific operations to the transport that owns a ref.
|
|
4
|
+
* The loader, cache source, `upgrade`, and `publish` consult this instead of
|
|
5
|
+
* branching on ref shape. `RegistryTransport` is always last so it is the
|
|
6
|
+
* fallback for bare / `https` refs, and a scheme-owning transport (OCI, later
|
|
7
|
+
* S3) claims its refs via `supports()` before the fallback is reached. */
|
|
8
|
+
export class TransportRegistry {
|
|
9
|
+
constructor(transports) {
|
|
10
|
+
this.transports = transports;
|
|
11
|
+
}
|
|
12
|
+
/** The transport that owns `ref`, or `undefined` if none does. */
|
|
13
|
+
forRef(ref) {
|
|
14
|
+
return this.transports.find((t) => t.supports(ref));
|
|
15
|
+
}
|
|
16
|
+
/** The resolution `ManifestSource`s of every registered transport, in order —
|
|
17
|
+
* the browser-safe subset the loader appends to its source chain. */
|
|
18
|
+
sources() {
|
|
19
|
+
return this.transports.map((t) => t.source);
|
|
20
|
+
}
|
|
21
|
+
/** Cache-path segments for `ref`, from its owning transport; `null` when no
|
|
22
|
+
* transport owns it or the ref is not cacheable. */
|
|
23
|
+
cacheLocation(ref) {
|
|
24
|
+
return this.forRef(ref)?.cacheLocation(ref) ?? null;
|
|
25
|
+
}
|
|
26
|
+
/** Published versions for `ref` via its owning transport; `null` when the
|
|
27
|
+
* module is unpublished. Throws when no transport owns the ref. */
|
|
28
|
+
listVersions(ref) {
|
|
29
|
+
return this.require(ref).listVersions(ref);
|
|
30
|
+
}
|
|
31
|
+
/** Full artifact for `ref` via its owning transport. Throws when no transport
|
|
32
|
+
* owns the ref. */
|
|
33
|
+
fetchArtifact(ref) {
|
|
34
|
+
return this.require(ref).fetchArtifact(ref);
|
|
35
|
+
}
|
|
36
|
+
/** Publish `bundle` to `destination` via the transport its scheme selects.
|
|
37
|
+
* Throws when no transport owns the destination. */
|
|
38
|
+
publish(destination, bundle, opts) {
|
|
39
|
+
return this.require(destination).publish(destination, bundle, opts);
|
|
40
|
+
}
|
|
41
|
+
require(ref) {
|
|
42
|
+
const transport = this.forRef(ref);
|
|
43
|
+
if (!transport) {
|
|
44
|
+
throw new Error(`no transport owns ref '${ref}'`);
|
|
45
|
+
}
|
|
46
|
+
return transport;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** The default transport set. Scheme-owning transports come first; the
|
|
50
|
+
* `RegistryTransport` is last, the fallback for bare / `https` refs. OCI (and
|
|
51
|
+
* later S3) claim their `oci://` / `s3://` refs before the fallback is reached. */
|
|
52
|
+
export function defaultTransports(registryUrl) {
|
|
53
|
+
return [new OciTransport(), new RegistryTransport(registryUrl)];
|
|
54
|
+
}
|
|
55
|
+
const defaultRegistryCache = new Map();
|
|
56
|
+
/** A `TransportRegistry` seeded with {@link defaultTransports}, memoized per
|
|
57
|
+
* `registryUrl`. The default transports are stateless config (a fresh
|
|
58
|
+
* `OciClient` with its own token cache is created per OCI operation), so one
|
|
59
|
+
* shared instance per registry URL is safe — and avoids re-instantiating the
|
|
60
|
+
* whole set on hot paths like `cachePathForCanonical`. */
|
|
61
|
+
export function defaultTransportRegistry(registryUrl) {
|
|
62
|
+
const key = registryUrl ?? "";
|
|
63
|
+
let cached = defaultRegistryCache.get(key);
|
|
64
|
+
if (!cached) {
|
|
65
|
+
cached = new TransportRegistry(defaultTransports(registryUrl));
|
|
66
|
+
defaultRegistryCache.set(key, cached);
|
|
67
|
+
}
|
|
68
|
+
return cached;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=transport-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-registry.js","sourceRoot":"","sources":["../../src/transports/transport-registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAS5D;;;;2EAI2E;AAC3E,MAAM,OAAO,iBAAiB;IAC5B,YAA6B,UAAuB;QAAvB,eAAU,GAAV,UAAU,CAAa;IAAG,CAAC;IAExD,kEAAkE;IAClE,MAAM,CAAC,GAAW;QAChB,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IACtD,CAAC;IAED;0EACsE;IACtE,OAAO;QACL,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC;IAED;yDACqD;IACrD,aAAa,CAAC,GAAW;QACvB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IACtD,CAAC;IAED;wEACoE;IACpE,YAAY,CAAC,GAAW;QACtB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC;IAED;wBACoB;IACpB,aAAa,CAAC,GAAW;QACvB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED;yDACqD;IACrD,OAAO,CACL,WAAmB,EACnB,MAAqB,EACrB,IAAqB;QAErB,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACtE,CAAC;IAEO,OAAO,CAAC,GAAW;QACzB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,GAAG,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;CACF;AAED;;oFAEoF;AACpF,MAAM,UAAU,iBAAiB,CAAC,WAAoB;IACpD,OAAO,CAAC,IAAI,YAAY,EAAE,EAAE,IAAI,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAA6B,CAAC;AAElE;;;;2DAI2D;AAC3D,MAAM,UAAU,wBAAwB,CAAC,WAAoB;IAC3D,MAAM,GAAG,GAAG,WAAW,IAAI,EAAE,CAAC;IAC9B,IAAI,MAAM,GAAG,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,IAAI,iBAAiB,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAC;QAC/D,oBAAoB,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { ManifestSource } from "@telorun/analyzer";
|
|
2
|
+
import type { PayloadFile } from "../bundle/files-integrity.js";
|
|
3
|
+
/** The full module artifact a transport delivers: the `telo.yaml` bytes plus
|
|
4
|
+
* the decompressed `files:` payload (empty for a manifest-only module). The
|
|
5
|
+
* manifest is already verified against the import's inline hash; the payload
|
|
6
|
+
* against the manifest-embedded `filesIntegrity`. */
|
|
7
|
+
export interface FetchedArtifact {
|
|
8
|
+
manifest: string;
|
|
9
|
+
files: PayloadFile[];
|
|
10
|
+
}
|
|
11
|
+
/** The module bundle handed to a transport for publishing: the final,
|
|
12
|
+
* already-analyzed / pinned / canonicalized `telo.yaml` bytes plus the `files:`
|
|
13
|
+
* payload (empty for a manifest-only module). The transport is responsible for
|
|
14
|
+
* pinning the payload (`filesIntegrity`) and for the artifact shape it writes
|
|
15
|
+
* (HTTP: `telo.yaml` + `module.tar.gz`; OCI: a single blob). */
|
|
16
|
+
export interface PublishBundle {
|
|
17
|
+
manifest: string;
|
|
18
|
+
files: PayloadFile[];
|
|
19
|
+
}
|
|
20
|
+
export interface PublishResult {
|
|
21
|
+
/** Human-readable `<ns>/<name>@<version>` label of what was pushed. */
|
|
22
|
+
label: string;
|
|
23
|
+
/** The location the artifact was written to. */
|
|
24
|
+
url: string;
|
|
25
|
+
}
|
|
26
|
+
/** Identity of a sibling library, read from its own manifest, that a relative
|
|
27
|
+
* import canonicalizes to. `version` is always required; `namespace`/`name` are
|
|
28
|
+
* used only by transports whose location is metadata-derived (HTTP registry). */
|
|
29
|
+
export interface SiblingIdentity {
|
|
30
|
+
namespace?: string;
|
|
31
|
+
name?: string;
|
|
32
|
+
version: string;
|
|
33
|
+
}
|
|
34
|
+
export interface PublishOptions {
|
|
35
|
+
/** Bearer token for registries that require auth. */
|
|
36
|
+
token?: string;
|
|
37
|
+
/** Notified before each backoff sleep on a transient push failure, so the
|
|
38
|
+
* caller can surface retry progress. */
|
|
39
|
+
onRetry?: (info: {
|
|
40
|
+
reason: string;
|
|
41
|
+
attempt: number;
|
|
42
|
+
maxAttempts: number;
|
|
43
|
+
delayMs: number;
|
|
44
|
+
}) => void;
|
|
45
|
+
}
|
|
46
|
+
/** A Transport owns everything ref-scheme-specific about a module's lifecycle:
|
|
47
|
+
* resolution (through its `ManifestSource`), cache placement, version
|
|
48
|
+
* enumeration, full-artifact fetch, and publish. Registering a transport is
|
|
49
|
+
* the only thing needed to add a backend — the loader, cache, `upgrade`, and
|
|
50
|
+
* `publish` never branch on scheme again; they ask the {@link TransportRegistry}
|
|
51
|
+
* which transport owns a ref and delegate.
|
|
52
|
+
*
|
|
53
|
+
* A Transport *composes* a resolution `ManifestSource`, it does not extend it:
|
|
54
|
+
* `ManifestSource` is the browser-safe resolution primitive (also implemented
|
|
55
|
+
* by the cache / local / memory sources, which have no versions and nothing to
|
|
56
|
+
* publish), so it stays in `analyzer`, while the Node-only management methods
|
|
57
|
+
* (`cacheLocation` and, in later phases, `listVersions` / `fetchArtifact` /
|
|
58
|
+
* `publish`) live on the Transport here in `kernel`. */
|
|
59
|
+
export interface Transport {
|
|
60
|
+
/** True when this transport owns the given ref (or publish destination). */
|
|
61
|
+
supports(ref: string): boolean;
|
|
62
|
+
/** The resolution primitive: fetch + verify `telo.yaml`, resolve relatives.
|
|
63
|
+
* Browser-safe for a browser-reachable transport (HTTP/registry), so it can
|
|
64
|
+
* live in `analyzer`; a Node-only transport has no browser-safe source. */
|
|
65
|
+
readonly source: ManifestSource;
|
|
66
|
+
/** Deterministic cache-path segments for a ref, joined under the cache root by
|
|
67
|
+
* the cache source. Returns `null` when the ref is not cacheable here
|
|
68
|
+
* (unsupported scheme, malformed ref, or path-traversal in the ref). */
|
|
69
|
+
cacheLocation(ref: string): string[] | null;
|
|
70
|
+
/** The versions published for the module `ref` names, newest-first order not
|
|
71
|
+
* guaranteed (the caller sorts). Returns `null` when the module is not
|
|
72
|
+
* published (e.g. a 404), distinct from `[]` (published, no versions). Used
|
|
73
|
+
* by `telo upgrade`. */
|
|
74
|
+
listVersions(ref: string): Promise<string[] | null>;
|
|
75
|
+
/** Retrieve the full artifact for `ref` — the `telo.yaml` and its `files:`
|
|
76
|
+
* payload — verifying the manifest against the inline hash and the payload
|
|
77
|
+
* against the manifest's `filesIntegrity`. Used by `telo install`; subsumes
|
|
78
|
+
* the out-of-band bundle fetch that used to sit outside the source chain. */
|
|
79
|
+
fetchArtifact(ref: string): Promise<FetchedArtifact>;
|
|
80
|
+
/** Push `bundle` to `destination` (a base ref / repo whose scheme this
|
|
81
|
+
* transport owns), pinning the payload and writing the transport-native
|
|
82
|
+
* artifact shape. Throws on failure. Used by `telo publish`. */
|
|
83
|
+
publish(destination: string, bundle: PublishBundle, opts?: PublishOptions): Promise<PublishResult>;
|
|
84
|
+
/** Canonicalize a relative sibling import (`../lib`) declared in a module
|
|
85
|
+
* being published to `destination` into the absolute ref it will resolve to
|
|
86
|
+
* once published. Owns the scheme-specific "where does a sibling land" rule —
|
|
87
|
+
* OCI derives the repo from the destination, HTTP from the sibling's
|
|
88
|
+
* `<namespace>/<name>` — so `telo publish` delegates instead of branching on
|
|
89
|
+
* transport shape. */
|
|
90
|
+
canonicalizeSiblingRef(destination: string, relativeSource: string, sibling: SiblingIdentity): string;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=transport.d.ts.map
|