@telorun/analyzer 0.60.0 → 0.62.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.
Files changed (88) hide show
  1. package/dist/analyzer.d.ts.map +1 -1
  2. package/dist/analyzer.js +130 -9
  3. package/dist/artifact-layer-index.d.ts +13 -5
  4. package/dist/artifact-layer-index.d.ts.map +1 -1
  5. package/dist/artifact-layer-index.js +37 -13
  6. package/dist/artifact-selector.d.ts +10 -3
  7. package/dist/artifact-selector.d.ts.map +1 -1
  8. package/dist/artifact-selector.js +10 -1
  9. package/dist/builtins.d.ts.map +1 -1
  10. package/dist/builtins.js +97 -13
  11. package/dist/cel-bindings.d.ts +0 -6
  12. package/dist/cel-bindings.d.ts.map +1 -1
  13. package/dist/cel-bindings.js +3 -28
  14. package/dist/definition-registry.d.ts +17 -0
  15. package/dist/definition-registry.d.ts.map +1 -1
  16. package/dist/definition-registry.js +31 -2
  17. package/dist/identifier-name.d.ts +114 -0
  18. package/dist/identifier-name.d.ts.map +1 -0
  19. package/dist/identifier-name.js +183 -0
  20. package/dist/index.d.ts +14 -2
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +11 -2
  23. package/dist/manifest-schemas.d.ts +81 -0
  24. package/dist/manifest-schemas.d.ts.map +1 -1
  25. package/dist/manifest-schemas.js +208 -6
  26. package/dist/module-file-claims.d.ts +7 -0
  27. package/dist/module-file-claims.d.ts.map +1 -1
  28. package/dist/module-file-claims.js +22 -2
  29. package/dist/module-library.d.ts +97 -0
  30. package/dist/module-library.d.ts.map +1 -0
  31. package/dist/module-library.js +162 -0
  32. package/dist/requires-block.d.ts +125 -0
  33. package/dist/requires-block.d.ts.map +1 -0
  34. package/dist/requires-block.js +182 -0
  35. package/dist/schema-keywords.d.ts +68 -0
  36. package/dist/schema-keywords.d.ts.map +1 -0
  37. package/dist/schema-keywords.js +324 -0
  38. package/dist/schema-region.d.ts +12 -1
  39. package/dist/schema-region.d.ts.map +1 -1
  40. package/dist/schema-region.js +12 -1
  41. package/dist/telo-version.d.ts +3 -0
  42. package/dist/telo-version.d.ts.map +1 -0
  43. package/dist/telo-version.js +8 -0
  44. package/dist/types.d.ts +31 -0
  45. package/dist/types.d.ts.map +1 -1
  46. package/dist/validate-identifier-names.d.ts +31 -0
  47. package/dist/validate-identifier-names.d.ts.map +1 -0
  48. package/dist/validate-identifier-names.js +144 -0
  49. package/dist/validate-module-artifact.d.ts.map +1 -1
  50. package/dist/validate-module-artifact.js +53 -1
  51. package/dist/validate-observed-state.d.ts +9 -2
  52. package/dist/validate-observed-state.d.ts.map +1 -1
  53. package/dist/validate-observed-state.js +9 -2
  54. package/dist/validate-references.d.ts.map +1 -1
  55. package/dist/validate-references.js +5 -26
  56. package/dist/validate-requires.d.ts +49 -0
  57. package/dist/validate-requires.d.ts.map +1 -0
  58. package/dist/validate-requires.js +99 -0
  59. package/dist/value-type-keyword.d.ts +1 -1
  60. package/dist/value-type-keyword.d.ts.map +1 -1
  61. package/dist/value-type-keyword.js +1 -0
  62. package/dist/version-range.d.ts +88 -0
  63. package/dist/version-range.d.ts.map +1 -0
  64. package/dist/version-range.js +173 -0
  65. package/package.json +2 -2
  66. package/src/analyzer.ts +146 -10
  67. package/src/artifact-layer-index.ts +47 -14
  68. package/src/artifact-selector.ts +15 -4
  69. package/src/builtins.ts +102 -13
  70. package/src/cel-bindings.ts +3 -28
  71. package/src/definition-registry.ts +30 -2
  72. package/src/identifier-name.ts +228 -0
  73. package/src/index.ts +44 -1
  74. package/src/manifest-schemas.ts +223 -4
  75. package/src/module-file-claims.ts +32 -2
  76. package/src/module-library.ts +208 -0
  77. package/src/requires-block.ts +253 -0
  78. package/src/schema-keywords.ts +359 -0
  79. package/src/schema-region.ts +12 -1
  80. package/src/telo-version.ts +9 -0
  81. package/src/types.ts +32 -0
  82. package/src/validate-identifier-names.ts +173 -0
  83. package/src/validate-module-artifact.ts +56 -0
  84. package/src/validate-observed-state.ts +9 -2
  85. package/src/validate-references.ts +5 -26
  86. package/src/validate-requires.ts +129 -0
  87. package/src/value-type-keyword.ts +1 -0
  88. package/src/version-range.ts +238 -0
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"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"}
package/dist/analyzer.js CHANGED
@@ -29,12 +29,15 @@ import { collectValueSchemaIssues } from "./validate-value-schema.js";
29
29
  import { DiagnosticSeverity } from "./types.js";
30
30
  import { extractAccessChains, extractCelRegionScopes, getManifestItem, pathMatchesScope, resolveContextAnnotations, resolveTypeFieldToSchema, } from "./validate-cel-context.js";
31
31
  import { buildEvalPaths, evalPathsCover } from "./eval-paths.js";
32
- import { BINDINGS_ANNOTATION, bindingContextProperties, bindingPathChain, CEL_RESERVED_WORDS, findBindingSites, resolveBindingOrder, schemaAtChain, } from "./cel-bindings.js";
32
+ import { BINDINGS_ANNOTATION, bindingContextProperties, bindingPathChain, findBindingSites, resolveBindingOrder, schemaAtChain, } from "./cel-bindings.js";
33
+ import { CEL_RESERVED_WORDS, checkName } from "./identifier-name.js";
34
+ import { validateIdentifierNames } from "./validate-identifier-names.js";
33
35
  import { validateExtends } from "./validate-extends.js";
34
36
  import { validateLogging } from "./validate-logging.js";
35
37
  import { validateModuleArtifact } from "./validate-module-artifact.js";
36
38
  import { validateIncludePlacement } from "./validate-include-placement.js";
37
39
  import { validateModuleMetadata } from "./validate-module-metadata.js";
40
+ import { validateRequires } from "./validate-requires.js";
38
41
  import { validateBaseMapping } from "./validate-base-mapping.js";
39
42
  import { validateInvocationContract } from "./validate-invocation-contract.js";
40
43
  import { collectStepInputIssues } from "./validate-step-inputs.js";
@@ -819,6 +822,85 @@ function collectCelValueSlots(data, schema, path) {
819
822
  }
820
823
  return slots;
821
824
  }
825
+ /**
826
+ * Files belonging to a module this runtime declared itself unable to read.
827
+ *
828
+ * Attribution is by FILE rather than by resource identity, the same choice
829
+ * `remapMigratedPaths` makes and for the same reason: a diagnostic carries at
830
+ * most two routing facts and routinely only one, so indexing by resource would
831
+ * leave every diagnostic without `data.resource` unreachable.
832
+ *
833
+ * **A module NAME is not a graph-unique key.** Names are module-scoped, so two
834
+ * libraries may both be called `Store` — CLAUDE.md names this exact hazard for
835
+ * migration provenance ("two libraries declaring a Store would share one
836
+ * bucket"), where the answer is to narrow or not remap at all. Same answer here:
837
+ * the gated doc's own `metadata.source` is always suppressed, and a name is used
838
+ * to reach its `include:` partials only when that name identifies exactly ONE
839
+ * module doc in the set. Where it does not, the partials keep their diagnostics
840
+ * rather than risk silencing an unrelated library's — a stray extra diagnostic is
841
+ * a far cheaper failure than a hidden one.
842
+ *
843
+ * A module doc with no `source` contributes nothing — suppressing on a guess
844
+ * would hide diagnostics belonging to files nobody named.
845
+ */
846
+ function filesOfUnreadableModules(manifests, requiresDiagnostics) {
847
+ const files = new Set();
848
+ const gatedNames = new Set();
849
+ for (const d of requiresDiagnostics) {
850
+ if (d.code !== "MODULE_REQUIRES_NEWER_RUNTIME")
851
+ continue;
852
+ const data = d.data;
853
+ // The gated document itself, addressed by the file it was declared in.
854
+ if (typeof data?.filePath === "string" && data.filePath)
855
+ files.add(data.filePath);
856
+ const name = data?.resource?.name;
857
+ if (typeof name === "string")
858
+ gatedNames.add(name);
859
+ }
860
+ if (files.size === 0 && gatedNames.size === 0)
861
+ return files;
862
+ // How many module docs answer to each gated name — the ambiguity test.
863
+ const docsPerName = new Map();
864
+ for (const m of manifests) {
865
+ if (m.kind !== "Telo.Application" && m.kind !== "Telo.Library")
866
+ continue;
867
+ const name = m.metadata?.name;
868
+ if (typeof name === "string" && gatedNames.has(name)) {
869
+ docsPerName.set(name, (docsPerName.get(name) ?? 0) + 1);
870
+ }
871
+ }
872
+ for (const m of manifests) {
873
+ const metadata = (m.metadata ?? {});
874
+ const owner = metadata.module;
875
+ if (typeof owner !== "string" || !gatedNames.has(owner))
876
+ continue;
877
+ if (docsPerName.get(owner) !== 1)
878
+ continue; // ambiguous — do not guess
879
+ if (typeof metadata.source === "string" && metadata.source)
880
+ files.add(metadata.source);
881
+ }
882
+ return files;
883
+ }
884
+ /**
885
+ * Drop every diagnostic anchored in a file whose module this runtime cannot
886
+ * read, except the gate diagnostic itself.
887
+ *
888
+ * A filter rather than a guard on each validator: threading "skip this module"
889
+ * through thirty validators would make each one responsible for a rule none of
890
+ * them owns, and a validator added later would silently opt out of it. A
891
+ * diagnostic with no `filePath` is KEPT — suppression must never be the default
892
+ * for something it cannot attribute.
893
+ */
894
+ function suppressUnreadableModuleDiagnostics(diagnostics, unreadableFiles) {
895
+ if (unreadableFiles.size === 0)
896
+ return diagnostics;
897
+ return diagnostics.filter((d) => {
898
+ if (d.code === "MODULE_REQUIRES_NEWER_RUNTIME")
899
+ return true;
900
+ const filePath = d.data?.filePath;
901
+ return typeof filePath !== "string" || !unreadableFiles.has(filePath);
902
+ });
903
+ }
822
904
  export class StaticAnalyzer {
823
905
  celEnv;
824
906
  constructor(options = {}) {
@@ -1278,6 +1360,21 @@ export class StaticAnalyzer {
1278
1360
  });
1279
1361
  }
1280
1362
  }
1363
+ // Declared runtime requirements, FIRST among the validators and suppressing
1364
+ // the rest for any module this runtime cannot read. A module that adopted
1365
+ // newer syntax also produces the vocabulary errors that syntax causes here —
1366
+ // an unknown `use` token, an object where a zone annotation expects a
1367
+ // pointer, an `additionalProperties` violation against a kernel-owned
1368
+ // schema — every one of which is true and blames the module's author for a
1369
+ // version skew. Reporting them beside the gate would bury the one message
1370
+ // that names the actual cause and the actual fix.
1371
+ const requiresDiagnostics = validateRequires(allManifests, {
1372
+ teloVersion: options?.teloVersion,
1373
+ hostVersions: options?.hostVersions,
1374
+ entryModules: rootModules,
1375
+ });
1376
+ const unreadableFiles = filesOfUnreadableModules(allManifests, requiresDiagnostics);
1377
+ diagnostics.push(...requiresDiagnostics);
1281
1378
  if (!options?.skipValidation) {
1282
1379
  diagnostics.push(...validateSchemaTypeRefs(allManifests, defs, aliases, aliasesByModule, rootModules));
1283
1380
  // §14.1 / §10.3: redaction paths and `on_full: block` are statically
@@ -1292,6 +1389,11 @@ export class StaticAnalyzer {
1292
1389
  // these fields, which is precisely why they need a check: a mistyped one
1293
1390
  // has no runtime failure mode that would ever surface it.
1294
1391
  diagnostics.push(...validateModuleMetadata(allManifests, defs, aliases));
1392
+ // Every author-written name. Telo has no lexer, so a name's shape is
1393
+ // unchecked where it is declared and its consequences land at whichever
1394
+ // CEL site reads it — for a hyphen, sometimes as silent arithmetic. Takes
1395
+ // the call graph for step names rather than re-walking the step arrays.
1396
+ diagnostics.push(...validateIdentifierNames(allManifests, defs, aliases, rootModules, getCallGraph()));
1295
1397
  // A file embed resolves at resource creation, so one written on a doc that
1296
1398
  // is never instantiated is read by nothing and would ship silently.
1297
1399
  diagnostics.push(...validateIncludePlacement(allManifests));
@@ -1304,7 +1406,7 @@ export class StaticAnalyzer {
1304
1406
  // normalisation have already run above; that's all downstream
1305
1407
  // consumers (prepare, init loop) require.
1306
1408
  if (options?.skipValidation) {
1307
- return diagnostics;
1409
+ return suppressUnreadableModuleDiagnostics(diagnostics, unreadableFiles);
1308
1410
  }
1309
1411
  // Build a name→manifest map for looking up referenced resources
1310
1412
  const byName = new Map();
@@ -1769,15 +1871,34 @@ export class StaticAnalyzer {
1769
1871
  const keywords = new Set(CEL_RESERVED_WORDS);
1770
1872
  for (const name of Object.keys(declared)) {
1771
1873
  const shadows = inScope.has(name);
1772
- if (!shadows && !keywords.has(name))
1874
+ if (shadows || keywords.has(name)) {
1875
+ diagnostics.push({
1876
+ severity: DiagnosticSeverity.Error,
1877
+ code: "BINDING_NAME_RESERVED",
1878
+ source: SOURCE,
1879
+ message: shadows
1880
+ ? `${m.kind}/${bindingsName}: binding '${name}' shadows a variable already in scope here (${[...inScope].sort().join(", ")}). Rename the binding — a scope variable always wins, so this one would never be read.`
1881
+ : `${m.kind}/${bindingsName}: binding '${name}' is a CEL keyword, so no expression can read it as a reference. Rename the binding.`,
1882
+ data: {
1883
+ resource: resourceRef,
1884
+ filePath: bindingsFile,
1885
+ path: `${celBindingSites.field}.${name}`,
1886
+ },
1887
+ });
1888
+ continue;
1889
+ }
1890
+ // A binding is read by bare name, so it lives in the same
1891
+ // identifier space as a resource or step name and breaks the
1892
+ // same way. The keyword tier is unreachable here — the check
1893
+ // above owns it, and can also say what is being shadowed.
1894
+ const violation = checkName(name, "value", "binding name");
1895
+ if (!violation)
1773
1896
  continue;
1774
1897
  diagnostics.push({
1775
- severity: DiagnosticSeverity.Error,
1776
- code: "BINDING_NAME_RESERVED",
1898
+ severity: violation.severity,
1899
+ code: violation.code,
1777
1900
  source: SOURCE,
1778
- message: shadows
1779
- ? `${m.kind}/${bindingsName}: binding '${name}' shadows a variable already in scope here (${[...inScope].sort().join(", ")}). Rename the binding — a scope variable always wins, so this one would never be read.`
1780
- : `${m.kind}/${bindingsName}: binding '${name}' is a CEL keyword, so no expression can read it as a reference. Rename the binding.`,
1901
+ message: `${m.kind}/${bindingsName}: ${violation.message}`,
1781
1902
  data: {
1782
1903
  resource: resourceRef,
1783
1904
  filePath: bindingsFile,
@@ -2120,7 +2241,7 @@ export class StaticAnalyzer {
2120
2241
  diagnostics.push(...validateUnusedDeclarations(allManifests, this.celEnv));
2121
2242
  // Reroute diagnostics on synthetic (inline-extracted) resources back to
2122
2243
  // the chain root so position-index lookups land on the parent doc.
2123
- return rewriteSyntheticOrigins(diagnostics, allManifests);
2244
+ return rewriteSyntheticOrigins(suppressUnreadableModuleDiagnostics(diagnostics, unreadableFiles), allManifests);
2124
2245
  }
2125
2246
  analyzeErrors(manifests, options, registry, zoneExportCache) {
2126
2247
  return this.analyze(manifests, options, registry, zoneExportCache).filter((d) => d.severity === DiagnosticSeverity.Error);
@@ -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 `controller` layers only. */
33
+ /** Present on the code-bearing roles (`controller`, `library`) only. */
34
34
  selector?: ArtifactSelector;
35
35
  /** OCI blob digest — addresses the layer and verifies the transfer. */
36
36
  blob: string;
@@ -48,8 +48,16 @@ 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">): ArtifactLayer | undefined;
52
- /** Every controller layer matching `target`, in declaration order. Used by
53
- * `telo install` to warm a cache for one platform. */
54
- export declare function matchControllerLayers(layers: readonly ArtifactLayer[], target: PlatformTarget): ArtifactLayer[];
51
+ export declare function singletonLayer(layers: readonly ArtifactLayer[], role: Exclude<LayerRole, "controller" | "library">): ArtifactLayer | undefined;
52
+ /** The layer of one code role carrying exactly `selector`, or undefined.
53
+ *
54
+ * By exact key rather than by re-matching a host: the candidate being resolved
55
+ * already *is* one selector, and it is by construction the key of the layer
56
+ * that carries it. */
57
+ export declare function codeLayerFor(layers: readonly ArtifactLayer[], role: Extract<LayerRole, "controller" | "library">, selector: ArtifactSelector): ArtifactLayer | undefined;
58
+ /** Every code layer — controller and library alike — matching `target`, in
59
+ * declaration order. Used by `telo install` to warm a cache for one platform:
60
+ * a library layer is as much a prerequisite of an offline run as the controller
61
+ * layer that imports it. */
62
+ export declare function matchCodeLayers(layers: readonly ArtifactLayer[], target: PlatformTarget): ArtifactLayer[];
55
63
  //# sourceMappingURL=artifact-layer-index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-layer-index.d.ts","sourceRoot":"","sources":["../src/artifact-layer-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAKL,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,cAAc,EACpB,MAAM,wBAAwB,CAAC;AAQhC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,SAAS,CAAC;IAChB,2CAA2C;IAC3C,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,CAyDpF;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE,YAAY,CAAC,GACrC,aAAa,GAAG,SAAS,CAE3B;AAED;uDACuD;AACvD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,MAAM,EAAE,cAAc,GACrB,aAAa,EAAE,CAIjB"}
1
+ {"version":3,"file":"artifact-layer-index.d.ts","sourceRoot":"","sources":["../src/artifact-layer-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAOL,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,cAAc,EACpB,MAAM,wBAAwB,CAAC;AAQhC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,SAAS,CAAC;IAChB,wEAAwE;IACxE,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,CAmEpF;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE,YAAY,GAAG,SAAS,CAAC,GACjD,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 { isLayerRole, normalizeSelector, selectorKey, selectorMatches, } from "./artifact-selector.js";
30
+ import { LAYER_ROLES, 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. */
@@ -69,21 +69,32 @@ export function parseLayerIndex(value, describe = "layers") {
69
69
  throw new LayerIndexError(`${where}: expected an object.`);
70
70
  }
71
71
  const entry = raw;
72
- if (!isLayerRole(entry.role)) {
73
- throw new LayerIndexError(`${where}: role must be one of 'controller', 'assets', 'common'; got ` +
74
- `${entry.role === undefined ? "nothing" : `'${String(entry.role)}'`}.`);
72
+ if (typeof entry.role !== "string" || entry.role === "") {
73
+ throw new LayerIndexError(`${where}: role is required and must be one of ${LAYER_ROLES.map((r) => `'${r}'`).join(", ")}; ` +
74
+ `got ${entry.role === undefined ? "nothing" : `'${String(entry.role)}'`}.`);
75
75
  }
76
+ // A role this runtime does not know is SKIPPED, never rejected. Roles are
77
+ // added over time, and a runtime that cannot name one cannot need it — while
78
+ // throwing would make the whole manifest unreadable, so a module gaining a
79
+ // layer for a newer runtime would stop loading on an older one entirely
80
+ // rather than merely lacking that layer. The error stays for a structurally
81
+ // invalid entry, which is a malformed index rather than a newer one.
82
+ if (!isLayerRole(entry.role))
83
+ return;
76
84
  const role = entry.role;
77
85
  let selector;
78
- if (role === "controller") {
86
+ if (roleCarriesSelector(role)) {
79
87
  if (entry.selector === undefined) {
80
- throw new LayerIndexError(`${where}: a controller layer must declare a selector.`);
88
+ throw new LayerIndexError(`${where}: a ${role} layer must declare a selector.`);
81
89
  }
82
90
  selector = normalizeSelector(entry.selector, where);
83
- const key = selectorKey(selector);
91
+ // Scoped by role: a module's `js` controller layer and its `js` library
92
+ // layer are different layers with the same selector, and only a collision
93
+ // *within* one role means two layers claim one address.
94
+ const key = `${role}\0${selectorKey(selector)}`;
84
95
  if (seenSelectors.has(key)) {
85
- throw new LayerIndexError(`${where}: a second controller layer claims the selector ${key}. ` +
86
- `Each selector addresses exactly one layer.`);
96
+ throw new LayerIndexError(`${where}: a second ${role} layer claims the selector ${selectorKey(selector)}. ` +
97
+ `Each selector addresses exactly one layer of a role.`);
87
98
  }
88
99
  seenSelectors.add(key);
89
100
  }
@@ -109,8 +120,21 @@ export function parseLayerIndex(value, describe = "layers") {
109
120
  export function singletonLayer(layers, role) {
110
121
  return layers.find((l) => l.role === role);
111
122
  }
112
- /** Every controller layer matching `target`, in declaration order. Used by
113
- * `telo install` to warm a cache for one platform. */
114
- export function matchControllerLayers(layers, target) {
115
- return layers.filter((l) => l.role === "controller" && l.selector !== undefined && selectorMatches(l.selector, target));
123
+ /** The layer of one code role carrying exactly `selector`, or undefined.
124
+ *
125
+ * By exact key rather than by re-matching a host: the candidate being resolved
126
+ * already *is* one selector, and it is by construction the key of the layer
127
+ * that carries it. */
128
+ export function codeLayerFor(layers, role, selector) {
129
+ const key = selectorKey(selector);
130
+ return layers.find((l) => l.role === role && l.selector !== undefined && selectorKey(l.selector) === key);
131
+ }
132
+ /** Every code layer — controller and library alike — matching `target`, in
133
+ * declaration order. Used by `telo install` to warm a cache for one platform:
134
+ * a library layer is as much a prerequisite of an offline run as the controller
135
+ * layer that imports it. */
136
+ export function matchCodeLayers(layers, target) {
137
+ return layers.filter((l) => (l.role === "controller" || l.role === "library") &&
138
+ l.selector !== undefined &&
139
+ selectorMatches(l.selector, target));
116
140
  }
@@ -24,11 +24,18 @@
24
24
  * canonical OCI/GOOS names at the kernel boundary, since these values are
25
25
  * published into OCI descriptors.
26
26
  */
27
- /** The role a layer plays in a module artifact. `controller` layers carry a
28
- * selector; `assets` and `common` are singletons and carry none. */
29
- export type LayerRole = "controller" | "assets" | "common";
27
+ /** The role a layer plays in a module artifact. `controller` and `library` layers
28
+ * carry a selector; `assets` and `common` are singletons and carry none. */
29
+ export type LayerRole = "controller" | "library" | "assets" | "common";
30
30
  export declare const LAYER_ROLES: readonly LayerRole[];
31
31
  export declare function isLayerRole(value: unknown): value is LayerRole;
32
+ /** The roles that hold executable code, and are therefore per format rather than
33
+ * singletons. A `library` layer is per selector for the same reason a
34
+ * `controller` layer is: a module's JS entry point and its future Rust one are
35
+ * different files, and a consumer resolves the one its own runtime can import.
36
+ * A singleton would be wrong the moment a second runtime ships. */
37
+ export declare const CODE_LAYER_ROLES: readonly LayerRole[];
38
+ export declare function roleCarriesSelector(role: LayerRole): boolean;
32
39
  /** The platform axes, in canonical order. Not a closed vocabulary of *values* —
33
40
  * new architectures appear without a Telo release — only of axis names. */
34
41
  export declare const PLATFORM_AXES: readonly ["os", "arch", "libc"];
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-selector.d.ts","sourceRoot":"","sources":["../src/artifact-selector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;qEACqE;AACrE,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE3D,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAAuC,CAAC;AAEpF,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAE9D;AAED;4EAC4E;AAC5E,eAAO,MAAM,aAAa,iCAAkC,CAAC;AAE7D,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,MAAM,WAAW,gBAAgB;IAC/B,kFAAkF;IAClF,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;kFAGkF;AAClF,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,+BAA+B;gBAEhC,MAAM,EAAE,MAAM;CAI3B;AAsBD;;;;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,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,QAAQ,SAAmB,GAC1B,gBAAgB,CAelB;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"}
1
+ {"version":3,"file":"artifact-selector.d.ts","sourceRoot":"","sources":["../src/artifact-selector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;6EAC6E;AAC7E,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEvE,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAAkD,CAAC;AAE/F,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAE9D;AAED;;;;oEAIoE;AACpE,eAAO,MAAM,gBAAgB,EAAE,SAAS,SAAS,EAA8B,CAAC;AAEhF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAE5D;AAED;4EAC4E;AAC5E,eAAO,MAAM,aAAa,iCAAkC,CAAC;AAE7D,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,MAAM,WAAW,gBAAgB;IAC/B,kFAAkF;IAClF,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;kFAGkF;AAClF,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,+BAA+B;gBAEhC,MAAM,EAAE,MAAM;CAI3B;AAsBD;;;;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,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,QAAQ,SAAmB,GAC1B,gBAAgB,CAelB;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"}
@@ -24,10 +24,19 @@
24
24
  * canonical OCI/GOOS names at the kernel boundary, since these values are
25
25
  * published into OCI descriptors.
26
26
  */
27
- export const LAYER_ROLES = ["controller", "assets", "common"];
27
+ export const LAYER_ROLES = ["controller", "library", "assets", "common"];
28
28
  export function isLayerRole(value) {
29
29
  return typeof value === "string" && LAYER_ROLES.includes(value);
30
30
  }
31
+ /** The roles that hold executable code, and are therefore per format rather than
32
+ * singletons. A `library` layer is per selector for the same reason a
33
+ * `controller` layer is: a module's JS entry point and its future Rust one are
34
+ * different files, and a consumer resolves the one its own runtime can import.
35
+ * A singleton would be wrong the moment a second runtime ships. */
36
+ export const CODE_LAYER_ROLES = ["controller", "library"];
37
+ export function roleCarriesSelector(role) {
38
+ return CODE_LAYER_ROLES.includes(role);
39
+ }
31
40
  /** The platform axes, in canonical order. Not a closed vocabulary of *values* —
32
41
  * new architectures appear without a Telo release — only of axis names. */
33
42
  export const PLATFORM_AXES = ["os", "arch", "libc"];
@@ -1 +1 @@
1
- {"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AA6JvD,eAAO,MAAM,eAAe,EAAE,kBAAkB,EA0rB/C,CAAC"}
1
+ {"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAiNvD,eAAO,MAAM,eAAe,EAAE,kBAAkB,EAusB/C,CAAC"}
package/dist/builtins.js CHANGED
@@ -1,5 +1,25 @@
1
- import { manifestFragment } from "./manifest-schemas.js";
2
- import { OBSERVED_STATE_SCHEMA } from "./validate-observed-state.js";
1
+ import { manifestFragment, manifestFragmentRef, withSchemaFragments } from "./manifest-schemas.js";
2
+ /** A slot holding author-written JSON Schema. Localized and hoisted by
3
+ * {@link withSchemaFragments} on the enclosing schema, which is what makes the
4
+ * `#/$defs` pointer resolve inside whatever AJV compiles.
5
+ *
6
+ * `KindSchema` and `JsonSchema7` share a body; the name is the discriminator
7
+ * the IDE reads off the `x-telo-fragment` stamp to decide whether the
8
+ * `x-telo-*` vocabulary belongs here. A kind's own `schema:` is where it does;
9
+ * a `status:` block or an `inputType:` describes plain data, where it does not. */
10
+ const kindSchemaSlot = {
11
+ title: "Schema",
12
+ description: "Configuration this kind accepts, as JSON Schema plus `x-telo-*` annotations.",
13
+ $ref: manifestFragmentRef("KindSchema"),
14
+ };
15
+ /** Observed state a kind reports while running, as a data schema. `required:` is
16
+ * rejected separately by `validateObservedStateDeclarations`, which can say why
17
+ * and what to write instead. */
18
+ const observedStateSlot = {
19
+ title: "Observed state",
20
+ description: "What a resource of this kind reports while running, published at `resources.<name>.status.<field>`.",
21
+ $ref: manifestFragmentRef("JsonSchema7"),
22
+ };
3
23
  /** Descriptive provenance a module declares about itself, shared by
4
24
  * `Telo.Application` and `Telo.Library`.
5
25
  *
@@ -21,6 +41,31 @@ const PROVENANCE_METADATA = {
21
41
  license: { type: "string" },
22
42
  documentation: { type: "string" },
23
43
  };
44
+ /** The declared runtime requirements block, shared by `Telo.Application` and
45
+ * `Telo.Library` — the two module kinds, whose schemas are otherwise
46
+ * independent and would drift.
47
+ *
48
+ * **Deliberately says only "these are objects", and nothing about the values.**
49
+ * The grammar belongs to `requires-block.ts`, which is the single reader, and
50
+ * every rule that matters — `^` and `~` refused, a bare version refused, bounds
51
+ * that must not exclude each other, an upper bound that must name a version that
52
+ * exists — needs a parse and a comparison, not a schema. Adding `type: "string"`
53
+ * here bought nothing and cost a duplicate: `telo: 80` then produced BOTH a
54
+ * `SCHEMA_VIOLATION` and a `REQUIRES_INVALID` for one node, one of them phrased
55
+ * by a layer that does not know what the value is for.
56
+ *
57
+ * Left open at both tiers for the same reason. An unrecognized axis is reported
58
+ * by the reader with the vocabulary it knows — a far better message than AJV's —
59
+ * and, critically, is SUPPRESSED while the `telo` requirement is itself unmet,
60
+ * since an older runtime not knowing a newer axis is a consequence of the
61
+ * version skew rather than a second defect. AJV cannot express that ordering. */
62
+ const REQUIRES_SCHEMA = {
63
+ type: "object",
64
+ properties: {
65
+ host: { type: "object" },
66
+ },
67
+ additionalProperties: true,
68
+ };
24
69
  /** Author-declared subset of `files:` that ships in the artifact's lazily
25
70
  * materialized `assets` layer. Optional: an unclaimed file joins the `common`
26
71
  * layer, which is pulled alongside any controller layer, so omitting this costs
@@ -29,6 +74,32 @@ const ASSETS_FILES_SCHEMA = {
29
74
  type: "array",
30
75
  items: { type: "string" },
31
76
  };
77
+ /** `exports.code` — the entry point a sibling module's controller bundle resolves
78
+ * this library's bare specifier to, one per format.
79
+ *
80
+ * Data rather than a package URL: `controllers:` needs a PURL because it can name
81
+ * an ecosystem fetch (`pkg:npm`, `pkg:cargo`), while this always names a file the
82
+ * module already ships, so the type/namespace segments would be constant noise —
83
+ * and a query string is one opaque box to the visual editor. `format` plus the
84
+ * platform axes build the same `ArtifactSelector` a controller candidate does.
85
+ * Semantics and diagnostics live in `analyzer/nodejs/src/module-library.ts`. */
86
+ const LIBRARY_CANDIDATES_SCHEMA = {
87
+ type: "array",
88
+ items: {
89
+ type: "object",
90
+ required: ["specifier", "format", "path"],
91
+ properties: {
92
+ specifier: { type: "string" },
93
+ format: { type: "string" },
94
+ path: { type: "string" },
95
+ source: { type: "string" },
96
+ os: { type: "string" },
97
+ arch: { type: "string" },
98
+ libc: { type: "string" },
99
+ },
100
+ additionalProperties: false,
101
+ },
102
+ };
32
103
  /** The published layer index, written by `telo publish` (never hand-authored).
33
104
  * One entry per layer except the manifest layer, which cannot list its own hash
34
105
  * inside itself and is pinned by the importer's `#sha256-...` instead. Shape and
@@ -40,7 +111,7 @@ const LAYER_INDEX_SCHEMA = {
40
111
  type: "object",
41
112
  required: ["role", "blob", "integrity"],
42
113
  properties: {
43
- role: { type: "string", enum: ["controller", "assets", "common"] },
114
+ role: { type: "string", enum: ["controller", "library", "assets", "common"] },
44
115
  selector: {
45
116
  type: "object",
46
117
  required: ["format"],
@@ -239,13 +310,13 @@ export const KERNEL_BUILTINS = [
239
310
  // kernel registers this controller directly at boot, before any lazy
240
311
  // resolution — it states truthfully who provides it.
241
312
  controllers: [{ runtime: "kernel", entry: "Telo.JsonSchema" }],
242
- schema: {
313
+ schema: withSchemaFragments({
243
314
  type: "object",
244
315
  properties: {
245
316
  schema: {
246
317
  title: "Schema",
247
318
  description: "JSON Schema definition for the declared data type.",
248
- type: "object",
319
+ $ref: manifestFragmentRef("JsonSchema7"),
249
320
  },
250
321
  extends: {
251
322
  title: "Extends",
@@ -278,13 +349,13 @@ export const KERNEL_BUILTINS = [
278
349
  },
279
350
  required: ["schema"],
280
351
  additionalProperties: false,
281
- },
352
+ }),
282
353
  },
283
354
  {
284
355
  kind: "Telo.Definition",
285
356
  metadata: { name: "Abstract", module: "Telo" },
286
357
  capability: "Telo.Template",
287
- schema: {
358
+ schema: withSchemaFragments({
288
359
  type: "object",
289
360
  properties: {
290
361
  kind: { type: "string" },
@@ -295,15 +366,15 @@ export const KERNEL_BUILTINS = [
295
366
  additionalProperties: true,
296
367
  },
297
368
  capability: { type: "string" },
298
- schema: { type: "object", additionalProperties: true },
299
- status: OBSERVED_STATE_SCHEMA,
369
+ schema: kindSchemaSlot,
370
+ status: observedStateSlot,
300
371
  },
301
372
  required: ["metadata"],
302
373
  // Telo.Abstract is an extension point by design — it must accept forward-compatible
303
374
  // fields (e.g. inputType/outputType from the typed-abstracts plan) without requiring
304
375
  // the analyzer to enumerate them here.
305
376
  additionalProperties: true,
306
- },
377
+ }),
307
378
  },
308
379
  {
309
380
  kind: "Telo.Definition",
@@ -321,11 +392,17 @@ export const KERNEL_BUILTINS = [
321
392
  // matching how Run.Sequence steps factor dispatch from data. The dispatch
322
393
  // entry-point (`invoke` / `provide` / `run`) determines how `inputs`/`result`
323
394
  // are interpreted at runtime. See analyzer/nodejs/plans/template-internal-cel-validation.md.
324
- schema: {
395
+ schema: withSchemaFragments({
325
396
  type: "object",
326
397
  additionalProperties: true,
327
398
  properties: {
328
- status: OBSERVED_STATE_SCHEMA,
399
+ // The kind's own configuration contract. Declared as a slot for the
400
+ // first time here: it was reachable only as an unnamed extra property,
401
+ // so nothing could say what belonged in it — no completion inside a
402
+ // `schema:` block, and a misspelled keyword surviving to a runtime
403
+ // failure that named a different field.
404
+ schema: kindSchemaSlot,
405
+ status: observedStateSlot,
329
406
  resources: {
330
407
  type: "array",
331
408
  items: {
@@ -495,7 +572,7 @@ export const KERNEL_BUILTINS = [
495
572
  },
496
573
  },
497
574
  },
498
- },
575
+ }),
499
576
  },
500
577
  {
501
578
  kind: "Telo.Definition",
@@ -746,6 +823,9 @@ export const KERNEL_BUILTINS = [
746
823
  // CLI flag — so a level derived from the host environment goes through a
747
824
  // `variables:` entry read with `!cel`. See kernel/specs/logging.md §12.
748
825
  logging: ROOT_LOGGING_SCHEMA,
826
+ // The runtime range this module is verified against. See
827
+ // `analyzer/nodejs/src/requires-block.ts`.
828
+ requires: REQUIRES_SCHEMA,
749
829
  },
750
830
  required: ["metadata"],
751
831
  additionalProperties: false,
@@ -832,9 +912,13 @@ export const KERNEL_BUILTINS = [
832
912
  type: "array",
833
913
  items: { type: "string", not: { enum: ["variables", "secrets"] } },
834
914
  },
915
+ code: LIBRARY_CANDIDATES_SCHEMA,
835
916
  },
836
917
  additionalProperties: true,
837
918
  },
919
+ // The runtime range this module is verified against. See
920
+ // `analyzer/nodejs/src/requires-block.ts`.
921
+ requires: REQUIRES_SCHEMA,
838
922
  },
839
923
  required: ["metadata"],
840
924
  additionalProperties: false,
@@ -14,12 +14,6 @@ export interface BindingSites {
14
14
  /** Variable names the annotated contexts declare — a binding may not shadow one. */
15
15
  scopeNames: Set<string>;
16
16
  }
17
- /**
18
- * CEL keywords. A binding named after one is unreachable — `true` lexes as a
19
- * literal, `in` as an operator — so it is reserved alongside the scope names,
20
- * which turns silence into a diagnostic.
21
- */
22
- export declare const CEL_RESERVED_WORDS: readonly string[];
23
17
  /** Locate a kind's bindings field and the scope names its annotated contexts
24
18
  * declare. Returns undefined for a kind that declares no bindings region. */
25
19
  export declare function findBindingSites(definitionSchema: Record<string, any> | undefined): BindingSites | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"cel-bindings.d.ts","sourceRoot":"","sources":["../src/cel-bindings.ts"],"names":[],"mappings":"AAIA;;;;gCAIgC;AAChC,eAAO,MAAM,mBAAmB,yBAAyB,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd;;gCAE4B;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,oFAAoF;IACpF,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzB;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAsB/C,CAAC;AAEF;8EAC8E;AAC9E,wBAAgB,gBAAgB,CAC9B,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAChD,YAAY,GAAG,SAAS,CAW1B;AAuDD;uEACuE;AACvE,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAW1B;AAED;;mFAEmF;AACnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,IAAI,CAQhE;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACjC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAMrB;AAED;oEACoE;AACpE,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACxB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CASjC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACtE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;CACpB,CAwBA"}
1
+ {"version":3,"file":"cel-bindings.d.ts","sourceRoot":"","sources":["../src/cel-bindings.ts"],"names":[],"mappings":"AAIA;;;;gCAIgC;AAChC,eAAO,MAAM,mBAAmB,yBAAyB,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd;;gCAE4B;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,oFAAoF;IACpF,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzB;AAMD;8EAC8E;AAC9E,wBAAgB,gBAAgB,CAC9B,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAChD,YAAY,GAAG,SAAS,CAW1B;AAuDD;uEACuE;AACvE,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAW1B;AAED;;mFAEmF;AACnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,IAAI,CAQhE;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACjC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAMrB;AAED;oEACoE;AACpE,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACxB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CASjC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACtE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;CACpB,CAwBA"}