@telorun/analyzer 0.73.0 → 0.74.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/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +26 -7
- package/dist/artifact-axes.d.ts +14 -0
- package/dist/artifact-axes.d.ts.map +1 -0
- package/dist/artifact-axes.js +12 -0
- package/dist/artifact-layer-index.d.ts +2 -2
- package/dist/artifact-layer-index.d.ts.map +1 -1
- package/dist/artifact-layer-index.js +9 -4
- package/dist/artifact-selector.d.ts +47 -21
- package/dist/artifact-selector.d.ts.map +1 -1
- package/dist/artifact-selector.js +85 -16
- package/dist/builtins.d.ts.map +1 -1
- package/dist/builtins.js +73 -16
- package/dist/call-graph.d.ts +12 -1
- package/dist/call-graph.d.ts.map +1 -1
- package/dist/call-graph.js +22 -0
- package/dist/catch-scope.js +1 -1
- package/dist/forwarded-declaration.d.ts +26 -0
- package/dist/forwarded-declaration.d.ts.map +1 -0
- package/dist/forwarded-declaration.js +31 -0
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/kernel-globals.d.ts.map +1 -1
- package/dist/kernel-globals.js +21 -5
- package/dist/module-alias-scope.d.ts +11 -0
- package/dist/module-alias-scope.d.ts.map +1 -1
- package/dist/module-alias-scope.js +10 -0
- package/dist/module-file-claims.d.ts +17 -1
- package/dist/module-file-claims.d.ts.map +1 -1
- package/dist/module-file-claims.js +38 -3
- package/dist/module-named-files.d.ts +72 -0
- package/dist/module-named-files.d.ts.map +1 -0
- package/dist/module-named-files.js +115 -0
- package/dist/native-entries.d.ts +83 -0
- package/dist/native-entries.d.ts.map +1 -0
- package/dist/native-entries.js +169 -0
- package/dist/normalize-inline-resources.d.ts +41 -13
- package/dist/normalize-inline-resources.d.ts.map +1 -1
- package/dist/normalize-inline-resources.js +236 -54
- package/dist/reference-field-map.d.ts +59 -1
- package/dist/reference-field-map.d.ts.map +1 -1
- package/dist/reference-field-map.js +200 -34
- package/dist/release/payload-digest.d.ts +2 -1
- package/dist/release/payload-digest.d.ts.map +1 -1
- package/dist/release/payload-digest.js +2 -1
- package/dist/resolve-ref-sentinels.d.ts.map +1 -1
- package/dist/resolve-ref-sentinels.js +8 -5
- package/dist/resolve-throws-union.d.ts +25 -4
- package/dist/resolve-throws-union.d.ts.map +1 -1
- package/dist/resolve-throws-union.js +62 -32
- package/dist/resolve-zone-requirements.d.ts.map +1 -1
- package/dist/resolve-zone-requirements.js +2 -1
- package/dist/rewrite-synthetic-origins.d.ts +6 -1
- package/dist/rewrite-synthetic-origins.d.ts.map +1 -1
- package/dist/rewrite-synthetic-origins.js +107 -13
- package/dist/schema-compat.d.ts.map +1 -1
- package/dist/schema-compat.js +18 -5
- package/dist/schema-walk.d.ts +47 -13
- package/dist/schema-walk.d.ts.map +1 -1
- package/dist/schema-walk.js +150 -30
- package/dist/scope-declarations.d.ts +59 -0
- package/dist/scope-declarations.d.ts.map +1 -0
- package/dist/scope-declarations.js +45 -0
- package/dist/source-entries.d.ts +119 -0
- package/dist/source-entries.d.ts.map +1 -0
- package/dist/source-entries.js +349 -0
- package/dist/step-bodies.d.ts +24 -0
- package/dist/step-bodies.d.ts.map +1 -0
- package/dist/step-bodies.js +28 -0
- package/dist/telo-version.d.ts +1 -1
- package/dist/telo-version.js +1 -1
- package/dist/validate-cel-context.d.ts.map +1 -1
- package/dist/validate-cel-context.js +3 -2
- package/dist/validate-module-artifact.d.ts +4 -2
- package/dist/validate-module-artifact.d.ts.map +1 -1
- package/dist/validate-module-artifact.js +43 -4
- package/dist/validate-native-entries.d.ts +15 -0
- package/dist/validate-native-entries.d.ts.map +1 -0
- package/dist/validate-native-entries.js +103 -0
- package/dist/validate-observed-state.d.ts +7 -1
- package/dist/validate-observed-state.d.ts.map +1 -1
- package/dist/validate-observed-state.js +24 -6
- package/dist/validate-reference-forms.d.ts.map +1 -1
- package/dist/validate-reference-forms.js +2 -2
- package/dist/validate-references.d.ts.map +1 -1
- package/dist/validate-references.js +11 -5
- package/dist/validate-scope-reach.d.ts +31 -0
- package/dist/validate-scope-reach.d.ts.map +1 -0
- package/dist/validate-scope-reach.js +180 -0
- package/dist/validate-source-entries.d.ts +16 -0
- package/dist/validate-source-entries.d.ts.map +1 -0
- package/dist/validate-source-entries.js +90 -0
- package/dist/validate-throws-coverage.d.ts.map +1 -1
- package/dist/validate-throws-coverage.js +21 -39
- package/dist/value-type-keyword.d.ts +22 -5
- package/dist/value-type-keyword.d.ts.map +1 -1
- package/dist/value-type-keyword.js +16 -7
- package/package.json +3 -3
- package/src/analyzer.ts +33 -9
- package/src/artifact-axes.ts +24 -0
- package/src/artifact-layer-index.ts +9 -6
- package/src/artifact-selector.ts +110 -35
- package/src/builtins.ts +75 -16
- package/src/call-graph.ts +30 -0
- package/src/catch-scope.ts +1 -1
- package/src/forwarded-declaration.ts +32 -0
- package/src/index.ts +36 -1
- package/src/kernel-globals.ts +28 -5
- package/src/migrations/CLAUDE.md +35 -0
- package/src/module-alias-scope.ts +17 -0
- package/src/module-file-claims.ts +63 -4
- package/src/module-named-files.ts +162 -0
- package/src/native-entries.ts +227 -0
- package/src/normalize-inline-resources.ts +326 -70
- package/src/reference-field-map.ts +257 -52
- package/src/release/CLAUDE.md +32 -0
- package/src/release/payload-digest.ts +2 -1
- package/src/resolve-ref-sentinels.ts +7 -6
- package/src/resolve-throws-union.ts +87 -32
- package/src/resolve-zone-requirements.ts +2 -1
- package/src/rewrite-synthetic-origins.ts +107 -16
- package/src/schema-compat.ts +18 -4
- package/src/schema-walk.ts +162 -34
- package/src/scope-declarations.ts +98 -0
- package/src/source-entries.ts +502 -0
- package/src/step-bodies.ts +55 -0
- package/src/telo-version.ts +1 -1
- package/src/validate-cel-context.ts +3 -2
- package/src/validate-module-artifact.ts +46 -3
- package/src/validate-native-entries.ts +147 -0
- package/src/validate-observed-state.ts +36 -7
- package/src/validate-reference-forms.ts +2 -3
- package/src/validate-references.ts +10 -6
- package/src/validate-scope-reach.ts +213 -0
- package/src/validate-source-entries.ts +120 -0
- package/src/validate-throws-coverage.ts +24 -31
- package/src/value-type-keyword.ts +35 -9
package/dist/analyzer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAiBzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAiBzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAuC9B,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAWvF,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AA4DjE,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AAwGpB;0CAC0C;AAC1C,eAAO,MAAM,eAAe,GAAI,OAAO;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,KAAG,OACT,CAAC;AAErD;8EAC8E;AAC9E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhD;AAqUD,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACtC;AA6DD,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAkFD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;gBAEzB,OAAO,GAAE,qBAA0B;IAI/C;;;;;;;;;;;;;;OAcG;IACH,OAAO,CACL,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,EAC3B,eAAe,CAAC,EAAE,eAAe,GAChC,kBAAkB,EAAE;IAsmEvB,aAAa,CACX,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,EAC3B,eAAe,CAAC,EAAE,eAAe,GAChC,kBAAkB,EAAE;IAMvB,SAAS,CACP,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,gBAAgB,EAI1B,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,GACtC,gBAAgB,EAAE;IAyBrB,OAAO,CACL,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,gBAAgB,GACzB;QAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;CAsB5F"}
|
package/dist/analyzer.js
CHANGED
|
@@ -9,7 +9,7 @@ import { analyzerContractScope, resolveContract, } from "./invocation-contract.j
|
|
|
9
9
|
import { buildCallGraph } from "./call-graph.js";
|
|
10
10
|
import { buildDependencyGraph, formatCycle } from "./dependency-graph.js";
|
|
11
11
|
import { buildKernelGlobalsIndex, KERNEL_GLOBAL_NAMES, } from "./kernel-globals.js";
|
|
12
|
-
import { buildObservedStateIndex, buildObservedStateResourcesSchema, collectRunReachableNames, observedStateRead, validateObservedStateDeclarations, } from "./validate-observed-state.js";
|
|
12
|
+
import { buildObservedStateIndex, buildObservedStateResourcesSchema, collectRunReachableNames, forwardedResourceKey, observedStateRead, validateObservedStateDeclarations, } from "./validate-observed-state.js";
|
|
13
13
|
import { computeSuggestKind } from "./kind-suggest.js";
|
|
14
14
|
import { visitManifest } from "./manifest-visitor.js";
|
|
15
15
|
import { declaringModuleScope, moduleAliasScope } from "./module-alias-scope.js";
|
|
@@ -54,6 +54,8 @@ import { validateIdentifierNames } from "./validate-identifier-names.js";
|
|
|
54
54
|
import { validateExtends } from "./validate-extends.js";
|
|
55
55
|
import { validateLogging } from "./validate-logging.js";
|
|
56
56
|
import { validateModuleArtifact } from "./validate-module-artifact.js";
|
|
57
|
+
import { validateNativeEntries } from "./validate-native-entries.js";
|
|
58
|
+
import { validateSourceEntries } from "./validate-source-entries.js";
|
|
57
59
|
import { validateIncludePlacement } from "./validate-include-placement.js";
|
|
58
60
|
import { validateModuleMetadata } from "./validate-module-metadata.js";
|
|
59
61
|
import { validateRequires } from "./validate-requires.js";
|
|
@@ -69,6 +71,8 @@ import { validateResourceInputs } from "./validate-resource-inputs.js";
|
|
|
69
71
|
import { validateExports } from "./validate-exports.js";
|
|
70
72
|
import { validateTemplateBody } from "./validate-template-body.js";
|
|
71
73
|
import { validateUnusedDeclarations } from "./validate-unused-declarations.js";
|
|
74
|
+
import { validateScopedNameReach } from "./validate-scope-reach.js";
|
|
75
|
+
import { isForwardedDeclaration } from "./forwarded-declaration.js";
|
|
72
76
|
import { validateThrowsCoverage } from "./validate-throws-coverage.js";
|
|
73
77
|
import { readStepSlot } from "./step-slot.js";
|
|
74
78
|
const SELF_PREFIX = "Self.";
|
|
@@ -277,7 +281,7 @@ function validateStepInvokeReferences(allManifests, defs, aliases) {
|
|
|
277
281
|
const meta = r.metadata;
|
|
278
282
|
if (typeof meta?.name !== "string" || REF_VALIDATION_SKIP_KINDS.has(r.kind))
|
|
279
283
|
continue;
|
|
280
|
-
if (
|
|
284
|
+
if (isForwardedDeclaration(r)) {
|
|
281
285
|
if (typeof meta.module === "string")
|
|
282
286
|
loadedModules.add(meta.module);
|
|
283
287
|
continue;
|
|
@@ -343,7 +347,7 @@ function validateStepInvokeReferences(allManifests, defs, aliases) {
|
|
|
343
347
|
const meta = m.metadata;
|
|
344
348
|
if (typeof meta?.name !== "string" ||
|
|
345
349
|
REF_VALIDATION_SKIP_KINDS.has(m.kind) ||
|
|
346
|
-
|
|
350
|
+
isForwardedDeclaration(m))
|
|
347
351
|
continue;
|
|
348
352
|
const def = defs.resolve(aliases.resolveKind(m.kind) ?? m.kind);
|
|
349
353
|
const defSchema = def?.schema;
|
|
@@ -1302,6 +1306,11 @@ export class StaticAnalyzer {
|
|
|
1302
1306
|
// would otherwise fail on a consumer's machine — or, for a mistyped platform
|
|
1303
1307
|
// axis, silently offer one platform's binary to every host.
|
|
1304
1308
|
diagnostics.push(...validateModuleArtifact(allManifests));
|
|
1309
|
+
// The module doc's `native:` block: each rule decides whether a platform's
|
|
1310
|
+
// file can ever match a host, or whether two layers would write one path.
|
|
1311
|
+
diagnostics.push(...validateNativeEntries(allManifests, rootModules));
|
|
1312
|
+
// The module doc's `sources:` block: where each staged file comes from.
|
|
1313
|
+
diagnostics.push(...validateSourceEntries(allManifests, rootModules));
|
|
1305
1314
|
// The descriptive `metadata:` surface. Nothing in the kernel branches on
|
|
1306
1315
|
// these fields, which is precisely why they need a check: a mistyped one
|
|
1307
1316
|
// has no runtime failure mode that would ever surface it.
|
|
@@ -1552,9 +1561,8 @@ export class StaticAnalyzer {
|
|
|
1552
1561
|
// `kind`/CEL are authored in that module's scope (e.g. `Self.X` → that module, not the
|
|
1553
1562
|
// consumer). Re-validating against the consumer's scope yields false UNDEFINED_KIND /
|
|
1554
1563
|
// scope-mismatch errors, so skip — they participate here only as resolution targets.
|
|
1555
|
-
if (m
|
|
1564
|
+
if (isForwardedDeclaration(m))
|
|
1556
1565
|
continue;
|
|
1557
|
-
}
|
|
1558
1566
|
// A kind-only stand-in for a `resources:` entry is a DECLARATION, not an
|
|
1559
1567
|
// instantiation: its kind is routinely an abstract and its configuration
|
|
1560
1568
|
// is the importer's to supply, so validating it here would report a
|
|
@@ -2209,8 +2217,16 @@ export class StaticAnalyzer {
|
|
|
2209
2217
|
continue;
|
|
2210
2218
|
// An import's exported instance is indexed under `<Alias>.<name>`,
|
|
2211
2219
|
// the two-level shape it publishes under, so a cross-module read
|
|
2212
|
-
// is checked exactly like a local one.
|
|
2213
|
-
|
|
2220
|
+
// is checked exactly like a local one. A bare name read inside a
|
|
2221
|
+
// dependency's own manifest names that dependency's resource.
|
|
2222
|
+
const readerModule = isForwardedDeclaration(m)
|
|
2223
|
+
? m.metadata?.module
|
|
2224
|
+
: undefined;
|
|
2225
|
+
const reported = observedState.get(read.alias
|
|
2226
|
+
? `${read.alias}.${read.name}`
|
|
2227
|
+
: readerModule !== undefined
|
|
2228
|
+
? forwardedResourceKey(readerModule, read.name)
|
|
2229
|
+
: read.name);
|
|
2214
2230
|
if (celRuleApplies && celEvalModeAt(celSites, path) === "compile") {
|
|
2215
2231
|
diagnostics.push({
|
|
2216
2232
|
severity: DiagnosticSeverity.Error,
|
|
@@ -2446,6 +2462,9 @@ export class StaticAnalyzer {
|
|
|
2446
2462
|
diagnostics.push(...validateExports(allManifests, defs, aliases, rootModules));
|
|
2447
2463
|
// A library's declared resource inputs, and every import that supplies them.
|
|
2448
2464
|
diagnostics.push(...validateResourceInputs(allManifests, defs, aliases, rootModules, (supplied, required, isDeclaration) => kindSatisfies(supplied, required, defs, isDeclaration)));
|
|
2465
|
+
// An inline declaration referencing a name declared by a scope it was
|
|
2466
|
+
// written inside but is created outside of.
|
|
2467
|
+
diagnostics.push(...validateScopedNameReach(allManifests, defs, aliases, aliasesByModule, rootModules, (expr) => celAccessChains(this.celEnv, expr)));
|
|
2449
2468
|
// Reroute diagnostics on synthetic (inline-extracted) resources back to
|
|
2450
2469
|
// the chain root so position-index lookups land on the parent doc.
|
|
2451
2470
|
return rewriteSyntheticOrigins(suppressUnreadableModuleDiagnostics(diagnostics, unreadableFiles), allManifests);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** The selector platform axes, in canonical order. Closed as a set of axis
|
|
2
|
+
* names; the set of values stays open. */
|
|
3
|
+
export declare const PLATFORM_AXES: readonly ["os", "arch", "libc", "abi"];
|
|
4
|
+
export type PlatformAxis = (typeof PLATFORM_AXES)[number];
|
|
5
|
+
/** A form an axis value must take beyond the shared token grammar. */
|
|
6
|
+
export interface AxisValueForm {
|
|
7
|
+
readonly pattern: RegExp;
|
|
8
|
+
/** The form as a reader writes it, e.g. `<family>-<version>`. */
|
|
9
|
+
readonly form: string;
|
|
10
|
+
readonly examples: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
/** The axes whose values carry a form of their own. */
|
|
13
|
+
export declare const AXIS_VALUE_FORMS: Readonly<Partial<Record<PlatformAxis, AxisValueForm>>>;
|
|
14
|
+
//# sourceMappingURL=artifact-axes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-axes.d.ts","sourceRoot":"","sources":["../src/artifact-axes.ts"],"names":[],"mappings":"AAEA;2CAC2C;AAC3C,eAAO,MAAM,aAAa,wCAAyC,CAAC;AAEpE,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,uDAAuD;AACvD,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC,CAMnF,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// GENERATED by scripts/generate-artifact-axes.mjs from analyzer/artifact-axes/axes.json — do not edit.
|
|
2
|
+
/** The selector platform axes, in canonical order. Closed as a set of axis
|
|
3
|
+
* names; the set of values stays open. */
|
|
4
|
+
export const PLATFORM_AXES = ["os", "arch", "libc", "abi"];
|
|
5
|
+
/** The axes whose values carry a form of their own. */
|
|
6
|
+
export const AXIS_VALUE_FORMS = {
|
|
7
|
+
abi: {
|
|
8
|
+
pattern: new RegExp("^[a-z][a-z0-9_]*-[0-9]+(\\.[0-9]+)*$"),
|
|
9
|
+
form: "<family>-<version>",
|
|
10
|
+
examples: ["node-137", "telo-2"],
|
|
11
|
+
},
|
|
12
|
+
};
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
import { type ArtifactSelector, type LayerRole, type PlatformTarget } from "./artifact-selector.js";
|
|
31
31
|
export interface ArtifactLayer {
|
|
32
32
|
role: LayerRole;
|
|
33
|
-
/** Present on the
|
|
33
|
+
/** Present on the selector-keyed roles (`controller`, `library`, `native`) only. */
|
|
34
34
|
selector?: ArtifactSelector;
|
|
35
35
|
/** OCI blob digest — addresses the layer and verifies the transfer. */
|
|
36
36
|
blob: string;
|
|
@@ -48,7 +48,7 @@ export declare class LayerIndexError extends Error {
|
|
|
48
48
|
*/
|
|
49
49
|
export declare function parseLayerIndex(value: unknown, describe?: string): ArtifactLayer[];
|
|
50
50
|
/** The singleton layer for a role, or undefined when the artifact has none. */
|
|
51
|
-
export declare function singletonLayer(layers: readonly ArtifactLayer[], role: Exclude<LayerRole, "controller" | "library">): ArtifactLayer | undefined;
|
|
51
|
+
export declare function singletonLayer(layers: readonly ArtifactLayer[], role: Exclude<LayerRole, "controller" | "library" | "native">): ArtifactLayer | undefined;
|
|
52
52
|
/** The layer of one code role carrying exactly `selector`, or undefined.
|
|
53
53
|
*
|
|
54
54
|
* By exact key rather than by re-matching a host: the candidate being resolved
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-layer-index.d.ts","sourceRoot":"","sources":["../src/artifact-layer-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"artifact-layer-index.d.ts","sourceRoot":"","sources":["../src/artifact-layer-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAML,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,cAAc,EACpB,MAAM,wBAAwB,CAAC;AAQhC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,SAAS,CAAC;IAChB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,yBAAyB;gBAE1B,MAAM,EAAE,MAAM;CAI3B;AAiBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,SAAW,GAAG,aAAa,EAAE,CAuEpF;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE,YAAY,GAAG,SAAS,GAAG,QAAQ,CAAC,GAC5D,aAAa,GAAG,SAAS,CAE3B;AAED;;;;uBAIuB;AACvB,wBAAgB,YAAY,CAC1B,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE,YAAY,GAAG,SAAS,CAAC,EAClD,QAAQ,EAAE,gBAAgB,GACzB,aAAa,GAAG,SAAS,CAK3B;AAED;;;6BAG6B;AAC7B,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,MAAM,EAAE,cAAc,GACrB,aAAa,EAAE,CAOjB"}
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* Browser-safe: `telo check`, the editor and the hub validate an index through
|
|
28
28
|
* this module; only the kernel fetches and extracts.
|
|
29
29
|
*/
|
|
30
|
-
import {
|
|
30
|
+
import { isLayerRole, normalizeSelector, roleCarriesSelector, selectorKey, selectorMatches, } from "./artifact-selector.js";
|
|
31
31
|
/** OCI content digest: `sha256:` + 64 lowercase hex. */
|
|
32
32
|
const BLOB_DIGEST = /^sha256:[0-9a-f]{64}$/;
|
|
33
33
|
/** Telo content digest: `sha256-` + unpadded base64url of 32 bytes. */
|
|
@@ -70,9 +70,11 @@ export function parseLayerIndex(value, describe = "layers") {
|
|
|
70
70
|
}
|
|
71
71
|
const entry = raw;
|
|
72
72
|
if (typeof entry.role !== "string" || entry.role === "") {
|
|
73
|
-
throw new LayerIndexError(`${where}: role is required and must be
|
|
73
|
+
throw new LayerIndexError(`${where}: role is required and must be a non-empty string; ` +
|
|
74
74
|
`got ${entry.role === undefined ? "nothing" : `'${String(entry.role)}'`}.`);
|
|
75
75
|
}
|
|
76
|
+
const blob = digest("blob", entry.blob, where);
|
|
77
|
+
const integrity = digest("integrity", entry.integrity, where);
|
|
76
78
|
// A role this runtime does not know is SKIPPED, never rejected. Roles are
|
|
77
79
|
// added over time, and a runtime that cannot name one cannot need it — while
|
|
78
80
|
// throwing would make the whole manifest unreadable, so a module gaining a
|
|
@@ -88,6 +90,9 @@ export function parseLayerIndex(value, describe = "layers") {
|
|
|
88
90
|
throw new LayerIndexError(`${where}: a ${role} layer must declare a selector.`);
|
|
89
91
|
}
|
|
90
92
|
selector = normalizeSelector(entry.selector, where);
|
|
93
|
+
// An unknown axis skips the entry as an unknown role does (spec §3.1).
|
|
94
|
+
if (selector === undefined)
|
|
95
|
+
return;
|
|
91
96
|
// Scoped by role: a module's `js` controller layer and its `js` library
|
|
92
97
|
// layer are different layers with the same selector, and only a collision
|
|
93
98
|
// *within* one role means two layers claim one address.
|
|
@@ -110,8 +115,8 @@ export function parseLayerIndex(value, describe = "layers") {
|
|
|
110
115
|
layers.push({
|
|
111
116
|
role,
|
|
112
117
|
...(selector ? { selector } : {}),
|
|
113
|
-
blob
|
|
114
|
-
integrity
|
|
118
|
+
blob,
|
|
119
|
+
integrity,
|
|
115
120
|
});
|
|
116
121
|
});
|
|
117
122
|
return layers;
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* controller candidate is chosen by, and the key a controller layer of a module
|
|
4
4
|
* artifact is stored under.
|
|
5
5
|
*
|
|
6
|
-
* A selector is `format` plus the optional platform axes
|
|
6
|
+
* A selector is `format` plus the optional platform axes, whose vocabulary is
|
|
7
|
+
* data (`analyzer/artifact-axes/axes.json`, generated into `PLATFORM_AXES`).
|
|
7
8
|
* Matching is one rule, applied per axis: an axis the selector omits accepts
|
|
8
9
|
* anything, an axis it states must be equal. That is what lets a `js` controller
|
|
9
10
|
* be platform-neutral and a `napi` controller be pinned to one triple, with no
|
|
@@ -24,9 +25,11 @@
|
|
|
24
25
|
* canonical OCI/GOOS names at the kernel boundary, since these values are
|
|
25
26
|
* published into OCI descriptors.
|
|
26
27
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
import { PLATFORM_AXES, type PlatformAxis } from "./artifact-axes.js";
|
|
29
|
+
/** The role a layer plays in a module artifact. `controller`, `library` and
|
|
30
|
+
* `native` layers carry a selector; `assets` and `common` are singletons and
|
|
31
|
+
* carry none. */
|
|
32
|
+
export type LayerRole = "controller" | "library" | "native" | "assets" | "common";
|
|
30
33
|
export declare const LAYER_ROLES: readonly LayerRole[];
|
|
31
34
|
export declare function isLayerRole(value: unknown): value is LayerRole;
|
|
32
35
|
/** The roles that hold executable code, and are therefore per format rather than
|
|
@@ -36,39 +39,41 @@ export declare function isLayerRole(value: unknown): value is LayerRole;
|
|
|
36
39
|
* A singleton would be wrong the moment a second runtime ships. */
|
|
37
40
|
export declare const CODE_LAYER_ROLES: readonly LayerRole[];
|
|
38
41
|
export declare function roleCarriesSelector(role: LayerRole): boolean;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
export declare const PLATFORM_AXES: readonly ["os", "arch", "libc"];
|
|
42
|
-
export type PlatformAxis = (typeof PLATFORM_AXES)[number];
|
|
43
|
-
export interface ArtifactSelector {
|
|
42
|
+
export { PLATFORM_AXES, type PlatformAxis };
|
|
43
|
+
export interface ArtifactSelector extends Partial<Record<PlatformAxis, string>> {
|
|
44
44
|
/** Bundled controller format: the PURL name segment (`js`, `napi`, `wasm`, …). */
|
|
45
45
|
format: string;
|
|
46
|
-
os?: string;
|
|
47
|
-
arch?: string;
|
|
48
|
-
libc?: string;
|
|
49
46
|
}
|
|
50
47
|
/** What a selector is matched against: the host the kernel runs on, or the
|
|
51
|
-
* target `telo install
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
export interface PlatformTarget {
|
|
48
|
+
* target `telo install` is warming a cache for. An axis left undetermined (a
|
|
49
|
+
* host whose libc cannot be detected) matches no selector that constrains it —
|
|
50
|
+
* refusing to load is the safe direction for a native binary. */
|
|
51
|
+
export interface PlatformTarget extends Partial<Record<PlatformAxis, string>> {
|
|
55
52
|
format?: string;
|
|
56
|
-
os?: string;
|
|
57
|
-
arch?: string;
|
|
58
|
-
libc?: string;
|
|
59
53
|
}
|
|
60
54
|
export declare class ArtifactSelectorError extends Error {
|
|
61
55
|
readonly code = "INVALID_ARTIFACT_SELECTOR";
|
|
62
56
|
constructor(detail: string);
|
|
63
57
|
}
|
|
58
|
+
/** Validate and normalize one selector value: the shared token grammar, plus the
|
|
59
|
+
* axis's own value form where the vocabulary declares one. */
|
|
60
|
+
export declare function normalizeAxisValue(axis: string, raw: unknown, describe: string): string;
|
|
64
61
|
/**
|
|
65
62
|
* Build a selector from a controller candidate's format and qualifier map.
|
|
66
63
|
* Qualifier keys other than the platform axes are ignored — `path` and the
|
|
67
64
|
* sibling list live in the same map and are not part of the selector.
|
|
68
65
|
*/
|
|
69
66
|
export declare function selectorFromQualifiers(format: unknown, qualifiers: Readonly<Record<string, unknown>> | undefined, describe?: string): ArtifactSelector;
|
|
70
|
-
/**
|
|
71
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Validate and normalize a selector read off a published layer index.
|
|
69
|
+
*
|
|
70
|
+
* Returns undefined when the selector carries an axis this runtime does not
|
|
71
|
+
* know: the layer is for a newer runtime, and the caller skips it whole. The
|
|
72
|
+
* unknown axis is never dropped — two layers differing only in it would then
|
|
73
|
+
* claim one address. The known axes are still validated, since their grammar
|
|
74
|
+
* does not change with the axis set.
|
|
75
|
+
*/
|
|
76
|
+
export declare function normalizeSelector(value: unknown, describe?: string): ArtifactSelector | undefined;
|
|
72
77
|
/**
|
|
73
78
|
* The canonical stable key for a selector: sorted `axis=value` pairs joined by
|
|
74
79
|
* `;`. Used to group entry points into layers at publish time and to detect two
|
|
@@ -85,4 +90,25 @@ export declare function describeSelector(selector: ArtifactSelector): string;
|
|
|
85
90
|
* not be handed a `libc=gnu` binary on the assumption it will run.
|
|
86
91
|
*/
|
|
87
92
|
export declare function selectorMatches(selector: ArtifactSelector, target: PlatformTarget): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* The axes `selector` constrains and `target` leaves undetermined, when those
|
|
95
|
+
* alone keep the two from matching — what a warm skips for want of a value rather
|
|
96
|
+
* than because the selector is for another platform. `undefined` when the
|
|
97
|
+
* selector matches, or differs on a determined axis.
|
|
98
|
+
*/
|
|
99
|
+
export declare function undeterminedAxesBlockingMatch(selector: ArtifactSelector, target: PlatformTarget): PlatformAxis[] | undefined;
|
|
100
|
+
/** A selector that no host can match as its author meant it. */
|
|
101
|
+
export interface SelectorContradiction {
|
|
102
|
+
/** Suffix of the diagnostic code; each surface prefixes its own. */
|
|
103
|
+
readonly rule: "NAPI_ABI_FORBIDDEN" | "LIBC_OFF_LINUX";
|
|
104
|
+
readonly axis: PlatformAxis;
|
|
105
|
+
readonly detail: string;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The combinations of axes the grammar accepts and no host can mean: an N-API
|
|
109
|
+
* addon stating a runtime ABI, and a libc on an os that has none. Shared by every
|
|
110
|
+
* surface that authors a selector — `native:` entries, controller candidates and
|
|
111
|
+
* `exports.code:` entries — so each reports the same rule under its own prefix.
|
|
112
|
+
*/
|
|
113
|
+
export declare function selectorContradictions(selector: ArtifactSelector): SelectorContradiction[];
|
|
88
114
|
//# sourceMappingURL=artifact-selector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-selector.d.ts","sourceRoot":"","sources":["../src/artifact-selector.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"artifact-selector.d.ts","sourceRoot":"","sources":["../src/artifact-selector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAoB,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAExF;;kBAEkB;AAClB,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAElF,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAM3C,CAAC;AAEF,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAE9D;AAED;;;;oEAIoE;AACpE,eAAO,MAAM,gBAAgB,EAAE,SAAS,SAAS,EAA8B,CAAC;AAOhF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAE5D;AAED,OAAO,EAAE,aAAa,EAAE,KAAK,YAAY,EAAE,CAAC;AAE5C,MAAM,WAAW,gBAAiB,SAAQ,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAC7E,kFAAkF;IAClF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;kEAGkE;AAClE,MAAM,WAAW,cAAe,SAAQ,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,+BAA+B;gBAEhC,MAAM,EAAE,MAAM;CAI3B;AAMD;+DAC+D;AAC/D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAqBvF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,EACzD,QAAQ,SAAwB,GAC/B,gBAAgB,CAUlB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,QAAQ,SAAmB,GAC1B,gBAAgB,GAAG,SAAS,CAU9B;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAO9D;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAKnE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAQ3F;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,cAAc,GACrB,YAAY,EAAE,GAAG,SAAS,CAU5B;AAED,gEAAgE;AAChE,MAAM,WAAW,qBAAqB;IACpC,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,oBAAoB,GAAG,gBAAgB,CAAC;IACvD,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,qBAAqB,EAAE,CAqB1F"}
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* controller candidate is chosen by, and the key a controller layer of a module
|
|
4
4
|
* artifact is stored under.
|
|
5
5
|
*
|
|
6
|
-
* A selector is `format` plus the optional platform axes
|
|
6
|
+
* A selector is `format` plus the optional platform axes, whose vocabulary is
|
|
7
|
+
* data (`analyzer/artifact-axes/axes.json`, generated into `PLATFORM_AXES`).
|
|
7
8
|
* Matching is one rule, applied per axis: an axis the selector omits accepts
|
|
8
9
|
* anything, an axis it states must be equal. That is what lets a `js` controller
|
|
9
10
|
* be platform-neutral and a `napi` controller be pinned to one triple, with no
|
|
@@ -24,7 +25,14 @@
|
|
|
24
25
|
* canonical OCI/GOOS names at the kernel boundary, since these values are
|
|
25
26
|
* published into OCI descriptors.
|
|
26
27
|
*/
|
|
27
|
-
|
|
28
|
+
import { AXIS_VALUE_FORMS, PLATFORM_AXES } from "./artifact-axes.js";
|
|
29
|
+
export const LAYER_ROLES = [
|
|
30
|
+
"controller",
|
|
31
|
+
"library",
|
|
32
|
+
"native",
|
|
33
|
+
"assets",
|
|
34
|
+
"common",
|
|
35
|
+
];
|
|
28
36
|
export function isLayerRole(value) {
|
|
29
37
|
return typeof value === "string" && LAYER_ROLES.includes(value);
|
|
30
38
|
}
|
|
@@ -34,12 +42,14 @@ export function isLayerRole(value) {
|
|
|
34
42
|
* different files, and a consumer resolves the one its own runtime can import.
|
|
35
43
|
* A singleton would be wrong the moment a second runtime ships. */
|
|
36
44
|
export const CODE_LAYER_ROLES = ["controller", "library"];
|
|
45
|
+
/** Every role keyed by a selector, one layer per selector: the code roles, plus
|
|
46
|
+
* `native` — a platform-specific file the runtime does not import as code,
|
|
47
|
+
* declared in the module doc's `native:` block. */
|
|
48
|
+
const SELECTOR_LAYER_ROLES = [...CODE_LAYER_ROLES, "native"];
|
|
37
49
|
export function roleCarriesSelector(role) {
|
|
38
|
-
return
|
|
50
|
+
return SELECTOR_LAYER_ROLES.includes(role);
|
|
39
51
|
}
|
|
40
|
-
|
|
41
|
-
* new architectures appear without a Telo release — only of axis names. */
|
|
42
|
-
export const PLATFORM_AXES = ["os", "arch", "libc"];
|
|
52
|
+
export { PLATFORM_AXES };
|
|
43
53
|
export class ArtifactSelectorError extends Error {
|
|
44
54
|
code = "INVALID_ARTIFACT_SELECTOR";
|
|
45
55
|
constructor(detail) {
|
|
@@ -50,7 +60,9 @@ export class ArtifactSelectorError extends Error {
|
|
|
50
60
|
/** Canonical token shape for every selector value. Lowercase, so the same
|
|
51
61
|
* platform written two ways is one layer rather than two. */
|
|
52
62
|
const TOKEN = /^[a-z0-9][a-z0-9_.-]*$/;
|
|
53
|
-
|
|
63
|
+
/** Validate and normalize one selector value: the shared token grammar, plus the
|
|
64
|
+
* axis's own value form where the vocabulary declares one. */
|
|
65
|
+
export function normalizeAxisValue(axis, raw, describe) {
|
|
54
66
|
if (typeof raw !== "string") {
|
|
55
67
|
throw new ArtifactSelectorError(`${describe}: ${axis} must be a string, got ${raw === null ? "null" : typeof raw}.`);
|
|
56
68
|
}
|
|
@@ -59,6 +71,11 @@ function normalizeToken(axis, raw, describe) {
|
|
|
59
71
|
throw new ArtifactSelectorError(`${describe}: ${axis} value '${raw}' is not a canonical token. ` +
|
|
60
72
|
`Use lowercase letters, digits, '.', '-' or '_', starting with a letter or digit.`);
|
|
61
73
|
}
|
|
74
|
+
const valueForm = AXIS_VALUE_FORMS[axis];
|
|
75
|
+
if (valueForm && !valueForm.pattern.test(value)) {
|
|
76
|
+
throw new ArtifactSelectorError(`${describe}: ${axis} value '${raw}' must have the form ${valueForm.form}, ` +
|
|
77
|
+
`e.g. ${valueForm.examples.map((e) => `'${e}'`).join(" or ")}.`);
|
|
78
|
+
}
|
|
62
79
|
return value;
|
|
63
80
|
}
|
|
64
81
|
/**
|
|
@@ -68,28 +85,33 @@ function normalizeToken(axis, raw, describe) {
|
|
|
68
85
|
*/
|
|
69
86
|
export function selectorFromQualifiers(format, qualifiers, describe = "controller selector") {
|
|
70
87
|
const selector = {
|
|
71
|
-
format:
|
|
88
|
+
format: normalizeAxisValue("format", format, describe),
|
|
72
89
|
};
|
|
73
90
|
for (const axis of PLATFORM_AXES) {
|
|
74
91
|
const raw = qualifiers?.[axis];
|
|
75
92
|
if (raw === undefined || raw === "")
|
|
76
93
|
continue;
|
|
77
|
-
selector[axis] =
|
|
94
|
+
selector[axis] = normalizeAxisValue(axis, raw, describe);
|
|
78
95
|
}
|
|
79
96
|
return selector;
|
|
80
97
|
}
|
|
81
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* Validate and normalize a selector read off a published layer index.
|
|
100
|
+
*
|
|
101
|
+
* Returns undefined when the selector carries an axis this runtime does not
|
|
102
|
+
* know: the layer is for a newer runtime, and the caller skips it whole. The
|
|
103
|
+
* unknown axis is never dropped — two layers differing only in it would then
|
|
104
|
+
* claim one address. The known axes are still validated, since their grammar
|
|
105
|
+
* does not change with the axis set.
|
|
106
|
+
*/
|
|
82
107
|
export function normalizeSelector(value, describe = "layer selector") {
|
|
83
108
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
84
109
|
throw new ArtifactSelectorError(`${describe}: expected an object of selector axes.`);
|
|
85
110
|
}
|
|
86
111
|
const record = value;
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
`${unknown.map((k) => `'${k}'`).join(", ")}. Known axes: format, ${PLATFORM_AXES.join(", ")}.`);
|
|
91
|
-
}
|
|
92
|
-
return selectorFromQualifiers(record.format, record, describe);
|
|
112
|
+
const selector = selectorFromQualifiers(record.format, record, describe);
|
|
113
|
+
const carriesUnknownAxis = Object.keys(record).some((k) => k !== "format" && !PLATFORM_AXES.includes(k));
|
|
114
|
+
return carriesUnknownAxis ? undefined : selector;
|
|
93
115
|
}
|
|
94
116
|
/**
|
|
95
117
|
* The canonical stable key for a selector: sorted `axis=value` pairs joined by
|
|
@@ -129,3 +151,50 @@ export function selectorMatches(selector, target) {
|
|
|
129
151
|
}
|
|
130
152
|
return true;
|
|
131
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* The axes `selector` constrains and `target` leaves undetermined, when those
|
|
156
|
+
* alone keep the two from matching — what a warm skips for want of a value rather
|
|
157
|
+
* than because the selector is for another platform. `undefined` when the
|
|
158
|
+
* selector matches, or differs on a determined axis.
|
|
159
|
+
*/
|
|
160
|
+
export function undeterminedAxesBlockingMatch(selector, target) {
|
|
161
|
+
if (target.format !== undefined && selector.format !== target.format)
|
|
162
|
+
return undefined;
|
|
163
|
+
const axes = [];
|
|
164
|
+
for (const axis of PLATFORM_AXES) {
|
|
165
|
+
const constraint = selector[axis];
|
|
166
|
+
if (constraint === undefined)
|
|
167
|
+
continue;
|
|
168
|
+
if (target[axis] === undefined)
|
|
169
|
+
axes.push(axis);
|
|
170
|
+
else if (target[axis] !== constraint)
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
return axes.length > 0 ? axes : undefined;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* The combinations of axes the grammar accepts and no host can mean: an N-API
|
|
177
|
+
* addon stating a runtime ABI, and a libc on an os that has none. Shared by every
|
|
178
|
+
* surface that authors a selector — `native:` entries, controller candidates and
|
|
179
|
+
* `exports.code:` entries — so each reports the same rule under its own prefix.
|
|
180
|
+
*/
|
|
181
|
+
export function selectorContradictions(selector) {
|
|
182
|
+
const out = [];
|
|
183
|
+
if (selector.format === "napi" && selector.abi !== undefined) {
|
|
184
|
+
out.push({
|
|
185
|
+
rule: "NAPI_ABI_FORBIDDEN",
|
|
186
|
+
axis: "abi",
|
|
187
|
+
detail: `an N-API addon is ABI-stable across runtime releases and states no abi — remove ` +
|
|
188
|
+
`abi ${selector.abi}, which would keep it from loading anywhere else.`,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
if (selector.libc !== undefined && selector.os !== undefined && selector.os !== "linux") {
|
|
192
|
+
out.push({
|
|
193
|
+
rule: "LIBC_OFF_LINUX",
|
|
194
|
+
axis: "libc",
|
|
195
|
+
detail: `libc is only determined on linux, so a selector for os '${selector.os}' that states ` +
|
|
196
|
+
`libc ${selector.libc} could never match a host. Remove libc.`,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
return out;
|
|
200
|
+
}
|
package/dist/builtins.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AAkFA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAoSvD,eAAO,MAAM,eAAe,EAAE,kBAAkB,EA+pB/C,CAAC"}
|
package/dist/builtins.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PLATFORM_AXES } from "./artifact-axes.js";
|
|
1
2
|
import { manifestFragment, manifestFragmentRef, withSchemaFragments } from "./manifest-schemas.js";
|
|
2
3
|
/** A slot holding author-written JSON Schema. Localized and hoisted by
|
|
3
4
|
* {@link withSchemaFragments} on the enclosing schema, which is what makes the
|
|
@@ -147,9 +148,68 @@ const LIBRARY_CANDIDATES_SCHEMA = {
|
|
|
147
148
|
format: { type: "string" },
|
|
148
149
|
path: { type: "string" },
|
|
149
150
|
source: { type: "string" },
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
...Object.fromEntries(PLATFORM_AXES.map((axis) => [axis, { type: "string" }])),
|
|
152
|
+
},
|
|
153
|
+
additionalProperties: false,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
/** `native:` — the module's platform-specific files, one entry per logical name
|
|
157
|
+
* per platform tuple. Closed, so a mistyped axis is a schema violation rather
|
|
158
|
+
* than a platform-neutral entry. Grammar and rules live in
|
|
159
|
+
* `analyzer/nodejs/src/native-entries.ts` and `validate-native-entries.ts`. */
|
|
160
|
+
const NATIVE_ENTRIES_SCHEMA = {
|
|
161
|
+
type: "array",
|
|
162
|
+
items: {
|
|
163
|
+
type: "object",
|
|
164
|
+
required: ["name", "format", "os", "arch", "path"],
|
|
165
|
+
properties: {
|
|
166
|
+
name: { type: "string" },
|
|
167
|
+
format: { type: "string" },
|
|
168
|
+
path: { type: "string" },
|
|
169
|
+
...Object.fromEntries(PLATFORM_AXES.map((axis) => [axis, { type: "string" }])),
|
|
170
|
+
},
|
|
171
|
+
additionalProperties: false,
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
/** `sources:` — where every staged file comes from, keyed by source name, each
|
|
175
|
+
* entry keyed by the module-relative path it produces. Closed at every level.
|
|
176
|
+
* An entry is a file (`upstream` + `member`, pinned with `sha256` +
|
|
177
|
+
* `executable`) or a link (`target`); a mix of the two, and every other rule,
|
|
178
|
+
* is reported by `analyzer/nodejs/src/validate-source-entries.ts`. `archive`
|
|
179
|
+
* names the upstream's format. A source built in the repo names its build under
|
|
180
|
+
* `build`, keyed by build system (`cargo: <crate dir>`), with the digest of its
|
|
181
|
+
* build inputs (`inputs`). */
|
|
182
|
+
const SOURCES_SCHEMA = {
|
|
183
|
+
type: "object",
|
|
184
|
+
additionalProperties: {
|
|
185
|
+
type: "object",
|
|
186
|
+
required: ["version", "url", "archive", "notices", "entries"],
|
|
187
|
+
properties: {
|
|
188
|
+
version: { type: "string" },
|
|
189
|
+
url: { type: "string" },
|
|
190
|
+
archive: { enum: ["tar.gz"] },
|
|
191
|
+
notices: { type: "array", minItems: 1, items: { type: "string" } },
|
|
192
|
+
build: {
|
|
193
|
+
type: "object",
|
|
194
|
+
required: ["cargo"],
|
|
195
|
+
properties: { cargo: { type: "string" }, inputs: { type: "string" } },
|
|
196
|
+
additionalProperties: false,
|
|
197
|
+
},
|
|
198
|
+
entries: {
|
|
199
|
+
type: "object",
|
|
200
|
+
additionalProperties: {
|
|
201
|
+
type: "object",
|
|
202
|
+
anyOf: [{ required: ["upstream", "member"] }, { required: ["target"] }],
|
|
203
|
+
properties: {
|
|
204
|
+
upstream: { type: "string" },
|
|
205
|
+
member: { type: "string" },
|
|
206
|
+
sha256: { type: "string" },
|
|
207
|
+
executable: { type: "boolean" },
|
|
208
|
+
target: { type: "string" },
|
|
209
|
+
},
|
|
210
|
+
additionalProperties: false,
|
|
211
|
+
},
|
|
212
|
+
},
|
|
153
213
|
},
|
|
154
214
|
additionalProperties: false,
|
|
155
215
|
},
|
|
@@ -158,25 +218,18 @@ const LIBRARY_CANDIDATES_SCHEMA = {
|
|
|
158
218
|
* One entry per layer except the manifest layer, which cannot list its own hash
|
|
159
219
|
* inside itself and is pinned by the importer's `#sha256-...` instead. Shape and
|
|
160
220
|
* matching rules are normative in kernel/specs/module-artifact.md; the parser
|
|
161
|
-
* that enforces them is `artifact-layer-index.ts`.
|
|
221
|
+
* that enforces them is `artifact-layer-index.ts`. `role` stays open and
|
|
222
|
+
* `selector` unconstrained: an entry for a newer runtime is skipped, not
|
|
223
|
+
* rejected, and its selector is not examined (spec §3.1). A known role's
|
|
224
|
+
* selector is validated by the parser, which `telo check` runs. */
|
|
162
225
|
const LAYER_INDEX_SCHEMA = {
|
|
163
226
|
type: "array",
|
|
164
227
|
items: {
|
|
165
228
|
type: "object",
|
|
166
229
|
required: ["role", "blob", "integrity"],
|
|
167
230
|
properties: {
|
|
168
|
-
role: { type: "string",
|
|
169
|
-
selector: {
|
|
170
|
-
type: "object",
|
|
171
|
-
required: ["format"],
|
|
172
|
-
properties: {
|
|
173
|
-
format: { type: "string" },
|
|
174
|
-
os: { type: "string" },
|
|
175
|
-
arch: { type: "string" },
|
|
176
|
-
libc: { type: "string" },
|
|
177
|
-
},
|
|
178
|
-
additionalProperties: false,
|
|
179
|
-
},
|
|
231
|
+
role: { type: "string", minLength: 1 },
|
|
232
|
+
selector: {},
|
|
180
233
|
blob: { type: "string", pattern: "^sha256:[0-9a-f]{64}$" },
|
|
181
234
|
integrity: { type: "string", pattern: "^sha256-[A-Za-z0-9_-]{43}$" },
|
|
182
235
|
},
|
|
@@ -716,6 +769,8 @@ export const KERNEL_BUILTINS = [
|
|
|
716
769
|
items: { type: "string" },
|
|
717
770
|
},
|
|
718
771
|
assets: ASSETS_FILES_SCHEMA,
|
|
772
|
+
native: NATIVE_ENTRIES_SCHEMA,
|
|
773
|
+
sources: SOURCES_SCHEMA,
|
|
719
774
|
layers: LAYER_INDEX_SCHEMA,
|
|
720
775
|
filesIntegrity: LEGACY_FILES_INTEGRITY_SCHEMA,
|
|
721
776
|
// Inline imports — name-keyed map sugar for separate `Telo.Import`
|
|
@@ -889,6 +944,8 @@ export const KERNEL_BUILTINS = [
|
|
|
889
944
|
items: { type: "string" },
|
|
890
945
|
},
|
|
891
946
|
assets: ASSETS_FILES_SCHEMA,
|
|
947
|
+
native: NATIVE_ENTRIES_SCHEMA,
|
|
948
|
+
sources: SOURCES_SCHEMA,
|
|
892
949
|
layers: LAYER_INDEX_SCHEMA,
|
|
893
950
|
filesIntegrity: LEGACY_FILES_INTEGRITY_SCHEMA,
|
|
894
951
|
// Inline imports — same name-keyed map sugar as Telo.Application; the
|