@telorun/analyzer 0.67.0 → 0.69.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 (96) hide show
  1. package/dist/analysis-registry.d.ts +12 -0
  2. package/dist/analysis-registry.d.ts.map +1 -1
  3. package/dist/analysis-registry.js +26 -0
  4. package/dist/analyzer.d.ts.map +1 -1
  5. package/dist/analyzer.js +23 -0
  6. package/dist/call-graph.d.ts +80 -1
  7. package/dist/call-graph.d.ts.map +1 -1
  8. package/dist/call-graph.js +145 -12
  9. package/dist/extends-resolution.d.ts +20 -0
  10. package/dist/extends-resolution.d.ts.map +1 -1
  11. package/dist/extends-resolution.js +29 -0
  12. package/dist/import-resolution-diagnostics.d.ts.map +1 -1
  13. package/dist/import-resolution-diagnostics.js +22 -8
  14. package/dist/index.d.ts +8 -7
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +6 -6
  17. package/dist/invocation-contract.d.ts +20 -0
  18. package/dist/invocation-contract.d.ts.map +1 -1
  19. package/dist/invocation-contract.js +74 -0
  20. package/dist/loaded-types.d.ts +4 -4
  21. package/dist/loaded-types.d.ts.map +1 -1
  22. package/dist/manifest-analysis.d.ts +19 -0
  23. package/dist/manifest-analysis.d.ts.map +1 -1
  24. package/dist/manifest-analysis.js +27 -0
  25. package/dist/manifest-loader.d.ts +3 -4
  26. package/dist/manifest-loader.d.ts.map +1 -1
  27. package/dist/manifest-loader.js +4 -5
  28. package/dist/manifest-schemas.d.ts +2 -0
  29. package/dist/manifest-schemas.d.ts.map +1 -1
  30. package/dist/manifest-schemas.js +4 -0
  31. package/dist/module-graph.d.ts +500 -0
  32. package/dist/module-graph.d.ts.map +1 -0
  33. package/dist/module-graph.js +1411 -0
  34. package/dist/reconcile-module-versions.d.ts.map +1 -1
  35. package/dist/reconcile-module-versions.js +10 -11
  36. package/dist/release/release-plan.d.ts +1 -1
  37. package/dist/resolve-zone-containment.d.ts +9 -1
  38. package/dist/resolve-zone-containment.d.ts.map +1 -1
  39. package/dist/resolve-zone-containment.js +34 -6
  40. package/dist/resolve-zone-requirements.d.ts.map +1 -1
  41. package/dist/resolve-zone-requirements.js +4 -2
  42. package/dist/schema-keywords.d.ts +16 -1
  43. package/dist/schema-keywords.d.ts.map +1 -1
  44. package/dist/schema-keywords.js +20 -0
  45. package/dist/sources/default-sources.d.ts +6 -6
  46. package/dist/sources/default-sources.d.ts.map +1 -1
  47. package/dist/sources/default-sources.js +7 -8
  48. package/dist/sources/integrity.d.ts +3 -2
  49. package/dist/sources/integrity.d.ts.map +1 -1
  50. package/dist/sources/integrity.js +26 -3
  51. package/dist/sources/versioned-ref.d.ts +17 -12
  52. package/dist/sources/versioned-ref.d.ts.map +1 -1
  53. package/dist/sources/versioned-ref.js +22 -24
  54. package/dist/telo-version.d.ts +1 -1
  55. package/dist/telo-version.js +1 -1
  56. package/dist/validate-extends.d.ts.map +1 -1
  57. package/dist/validate-extends.js +42 -1
  58. package/dist/validate-sensitive-slots.d.ts +28 -0
  59. package/dist/validate-sensitive-slots.d.ts.map +1 -0
  60. package/dist/validate-sensitive-slots.js +75 -0
  61. package/dist/value-type-keyword.d.ts +1 -1
  62. package/dist/value-type-keyword.d.ts.map +1 -1
  63. package/dist/value-type-keyword.js +1 -0
  64. package/package.json +1 -1
  65. package/src/analysis-registry.ts +37 -0
  66. package/src/analyzer.ts +26 -0
  67. package/src/call-graph.ts +207 -14
  68. package/src/extends-resolution.ts +33 -0
  69. package/src/import-resolution-diagnostics.ts +24 -7
  70. package/src/index.ts +42 -5
  71. package/src/invocation-contract.ts +71 -0
  72. package/src/loaded-types.ts +4 -4
  73. package/src/manifest-analysis.ts +39 -0
  74. package/src/manifest-loader.ts +4 -5
  75. package/src/manifest-schemas.ts +4 -0
  76. package/src/module-graph.ts +2005 -0
  77. package/src/reconcile-module-versions.ts +10 -11
  78. package/src/release/release-plan.ts +1 -1
  79. package/src/resolve-zone-containment.ts +49 -9
  80. package/src/resolve-zone-requirements.ts +7 -2
  81. package/src/schema-keywords.ts +33 -1
  82. package/src/sources/default-sources.ts +7 -8
  83. package/src/sources/integrity.ts +28 -3
  84. package/src/sources/versioned-ref.ts +26 -28
  85. package/src/telo-version.ts +1 -1
  86. package/src/validate-extends.ts +51 -1
  87. package/src/validate-sensitive-slots.ts +109 -0
  88. package/src/value-type-keyword.ts +1 -0
  89. package/dist/sources/module-ref.d.ts +0 -21
  90. package/dist/sources/module-ref.d.ts.map +0 -1
  91. package/dist/sources/module-ref.js +0 -36
  92. package/dist/sources/registry-source.d.ts +0 -14
  93. package/dist/sources/registry-source.d.ts.map +0 -1
  94. package/dist/sources/registry-source.js +0 -45
  95. package/src/sources/module-ref.ts +0 -49
  96. package/src/sources/registry-source.ts +0 -52
@@ -1 +1 @@
1
- {"version":3,"file":"reconcile-module-versions.d.ts","sourceRoot":"","sources":["../src/reconcile-module-versions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAOlE,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAIzE;;;;0CAI0C;AAC1C,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B;2EACuE;IACvE,WAAW,EAAE,kBAAkB,EAAE,CAAC;CACnC;AAgJD;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EAClC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,GAChD,qBAAqB,CAsEvB"}
1
+ {"version":3,"file":"reconcile-module-versions.d.ts","sourceRoot":"","sources":["../src/reconcile-module-versions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAOlE,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAIzE;;;;0CAI0C;AAC1C,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B;2EACuE;IACvE,WAAW,EAAE,kBAAkB,EAAE,CAAC;CACnC;AA+ID;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EAClC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,GAChD,qBAAqB,CAsEvB"}
@@ -19,15 +19,14 @@ const SOURCE = "telo-analyzer";
19
19
  * **What this key cannot relate.** It compares ref *spellings*, so it groups by
20
20
  * origin exactly and nothing else. Two consequences, both accepted:
21
21
  *
22
- * - A module imported once by a registry ref and once by a relative path is two
23
- * groups, so a version skew between them is not hoisted. Keying on what the
24
- * module declares about itself would catch that case, but only by trusting a
25
- * self-declared identity — which is what this change removes, and which
26
- * cannot tell two same-named modules from different origins apart.
27
- * - A bare `std/kv-store@0.4.0` and the equivalent direct
28
- * `https://<registry>/std/kv-store/0.4.0/telo.yaml` are two groups. Relating
29
- * them needs the configured registry base, which this pure, browser-safe
30
- * function does not have. */
22
+ * - A module imported once by an `oci://` ref and once by a relative path is
23
+ * two groups, so a version skew between them is not hoisted. Keying on what
24
+ * the module declares about itself would catch that case, but only by
25
+ * trusting a self-declared identity — which is what this change removes, and
26
+ * which cannot tell two same-named modules from different origins apart.
27
+ * - An `oci://` ref and a direct `https://…/telo.yaml` URL serving the same
28
+ * module are two groups. Relating them needs knowledge of the origin's
29
+ * layout, which this pure, browser-safe function does not have. */
31
30
  function refIdentity(ref) {
32
31
  const base = ref.split("#")[0];
33
32
  if (!base || base.startsWith(".") || base.startsWith("/") || base.startsWith("file:")) {
@@ -137,8 +136,8 @@ export function reconcileModuleVersions(modules, importEdges) {
137
136
  // source normally maps to exactly one identity; the entry module has no
138
137
  // inbound edge and needs none (it is never reconciled against itself).
139
138
  //
140
- // One source CAN be reached by two spellings of the same location (a bare
141
- // registry ref and the direct URL it resolves to). Both name the same module
139
+ // One source CAN be reached by two spellings of the same location (a ref and
140
+ // the direct URL it resolves to). Both name the same module
142
141
  // at the same version, so either identity groups it correctly — but the choice
143
142
  // must not depend on edge iteration order, or the same graph could reconcile
144
143
  // differently across runs. First edge wins.
@@ -51,7 +51,7 @@ export interface ModuleEvidence {
51
51
  readonly inlines: ReadonlyMap<ModuleKey, readonly string[]>;
52
52
  /**
53
53
  * Modules reached by an in-repo **relative** `imports:` source. A pinned
54
- * registry ref is deliberately not an edge: pinning is the statement "I am not
54
+ * remote ref is deliberately not an edge: pinning is the statement "I am not
55
55
  * affected until I choose to be", and moving it is `telo upgrade`'s job.
56
56
  */
57
57
  readonly imports: readonly ModuleKey[];
@@ -81,8 +81,15 @@ export interface ZoneRegion {
81
81
  * DECLARED it — the same resolver the projection takes, passed in rather than
82
82
  * rebuilt so both walks agree about what a kind means. */
83
83
  export type DefinitionLookup = (kind: string, module?: string) => ResourceDefinition | undefined;
84
+ /** A region as the WALK finds it, before any attribute is asked for: the slot
85
+ * that opens it and everything it reaches. Every attribute query is a filter
86
+ * over these, so a consumer wanting regions regardless of what they declare —
87
+ * an editor drawing the enclosure, where a zone declaring no attribute is
88
+ * still a zone — reads them directly instead of enumerating the vocabulary and
89
+ * silently missing whatever is not in it. */
90
+ export type ZoneProvider = Omit<ZoneRegion, "attribute" | "reason">;
84
91
  /**
85
- * Every region in the graph opened by a slot declaring `attribute`.
92
+ * Every region in the graph, keyed by the slot that opens it.
86
93
  *
87
94
  * The provider itself is NOT in `contents` — a zone constrains what runs inside
88
95
  * its body, not the resource that establishes it. A transaction's own
@@ -90,6 +97,7 @@ export type DefinitionLookup = (kind: string, module?: string) => ResourceDefini
90
97
  * treated the provider as contained would report the provider against its own
91
98
  * constraint.
92
99
  */
100
+ export declare function findZoneProviders(graph: CallGraph, resolveDef: DefinitionLookup): ZoneProvider[];
93
101
  export declare function findZoneRegions(graph: CallGraph, resolveDef: DefinitionLookup, attribute: string): ZoneRegion[];
94
102
  /** Convenience for a consumer that only wants membership: every node id inside
95
103
  * any region opened by `attribute`, mapped to the region that contains it. */
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-zone-containment.d.ts","sourceRoot":"","sources":["../src/resolve-zone-containment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAKlG,+DAA+D;AAC/D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,aAAa,CAAC;IACpB;wDACoD;IACpD,GAAG,EAAE,MAAM,EAAE,CAAC;CACf;AAED;;;;;gFAKgF;AAChF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,aAAa,CAAC;IACpB,mDAAmD;IACnD,IAAI,EAAE,iBAAiB,CAAC;IACxB,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB;uEACmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb;4EACwE;IACxE,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C;8EAC0E;IAC1E,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC7C,0EAA0E;IAC1E,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;CACvC;AAED;;2DAE2D;AAC3D,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;AA4GjG;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS,EAChB,UAAU,EAAE,gBAAgB,EAC5B,SAAS,EAAE,MAAM,GAChB,UAAU,EAAE,CA6Dd;AAoCD;+EAC+E;AAC/E,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,SAAS,UAAU,EAAE,GAC7B,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAQjC;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,EAAE,CAMtE"}
1
+ {"version":3,"file":"resolve-zone-containment.d.ts","sourceRoot":"","sources":["../src/resolve-zone-containment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAKlG,+DAA+D;AAC/D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,aAAa,CAAC;IACpB;wDACoD;IACpD,GAAG,EAAE,MAAM,EAAE,CAAC;CACf;AAED;;;;;gFAKgF;AAChF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,aAAa,CAAC;IACpB,mDAAmD;IACnD,IAAI,EAAE,iBAAiB,CAAC;IACxB,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB;uEACmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb;4EACwE;IACxE,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C;8EAC0E;IAC1E,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC7C,0EAA0E;IAC1E,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;CACvC;AAED;;2DAE2D;AAC3D,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;AA4GjG;;;;;8CAK8C;AAC9C,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,GAAG,QAAQ,CAAC,CAAC;AAEpE;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,EAChB,UAAU,EAAE,gBAAgB,GAC3B,YAAY,EAAE,CA0DhB;AAmBD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS,EAChB,UAAU,EAAE,gBAAgB,EAC5B,SAAS,EAAE,MAAM,GAChB,UAAU,EAAE,CAad;AAoCD;+EAC+E;AAC/E,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,SAAS,UAAU,EAAE,GAC7B,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAQjC;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,EAAE,CAMtE"}
@@ -91,7 +91,7 @@ function collect(graph, entries, contents, boundaries) {
91
91
  }
92
92
  }
93
93
  /**
94
- * Every region in the graph opened by a slot declaring `attribute`.
94
+ * Every region in the graph, keyed by the slot that opens it.
95
95
  *
96
96
  * The provider itself is NOT in `contents` — a zone constrains what runs inside
97
97
  * its body, not the resource that establishes it. A transaction's own
@@ -99,7 +99,7 @@ function collect(graph, entries, contents, boundaries) {
99
99
  * treated the provider as contained would report the provider against its own
100
100
  * constraint.
101
101
  */
102
- export function findZoneRegions(graph, resolveDef, attribute) {
102
+ export function findZoneProviders(graph, resolveDef) {
103
103
  const regions = [];
104
104
  for (const node of graph.nodes.values()) {
105
105
  if (node.type !== "resource")
@@ -112,8 +112,7 @@ export function findZoneRegions(graph, resolveDef, attribute) {
112
112
  // properties rather than by knowing any kind's field names.
113
113
  for (const [slot, slotSchema] of providingSlots(rootSchema)) {
114
114
  const provides = readProvidesZone(slotSchema);
115
- const reason = provides?.attributes[attribute];
116
- if (!provides || typeof reason !== "string")
115
+ if (!provides)
117
116
  continue;
118
117
  const contents = new Map();
119
118
  const boundaries = [];
@@ -147,8 +146,6 @@ export function findZoneRegions(graph, resolveDef, attribute) {
147
146
  collect(graph, entries, contents, boundaries);
148
147
  }
149
148
  regions.push({
150
- attribute,
151
- reason,
152
149
  provider: node,
153
150
  slot,
154
151
  attributes: provides.attributes,
@@ -159,6 +156,37 @@ export function findZoneRegions(graph, resolveDef, attribute) {
159
156
  }
160
157
  return regions;
161
158
  }
159
+ /**
160
+ * Every region opened by a slot declaring `attribute`.
161
+ *
162
+ * A filter over {@link findZoneProviders}, so the walk is stated once: what an
163
+ * attribute query adds is which regions are in scope and the author's `reason`,
164
+ * which is the attribute's own value.
165
+ *
166
+ * **The provider list is memoized per graph**, because the filter made the walk
167
+ * unconditional: it used to skip the containment BFS for any provider not
168
+ * declaring the queried attribute, and six queries per analysis (four zone
169
+ * attributes plus two durable ones) became six full walks over every provider
170
+ * in the module. The cache is keyed on the CallGraph object, which is itself
171
+ * built once per analysis — so it lives exactly as long as the answer stays
172
+ * true, and a rebuilt graph gets a fresh one.
173
+ */
174
+ const providersByGraph = new WeakMap();
175
+ export function findZoneRegions(graph, resolveDef, attribute) {
176
+ let providers = providersByGraph.get(graph);
177
+ if (!providers) {
178
+ providers = findZoneProviders(graph, resolveDef);
179
+ providersByGraph.set(graph, providers);
180
+ }
181
+ const out = [];
182
+ for (const region of providers) {
183
+ const reason = region.attributes[attribute];
184
+ if (typeof reason !== "string")
185
+ continue;
186
+ out.push({ ...region, attribute, reason });
187
+ }
188
+ return out;
189
+ }
162
190
  /** Field-map paths of every slot in a kind's schema carrying a provides-zone
163
191
  * annotation, with the schema node at each. Walks properties, array items and
164
192
  * `additionalProperties`, resolving local `$ref`s — the paths the call graph's
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-zone-requirements.d.ts","sourceRoot":"","sources":["../src/resolve-zone-requirements.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolve-zone-requirements.d.ts","sourceRoot":"","sources":["../src/resolve-zone-requirements.ts"],"names":[],"mappings":"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"}
@@ -175,7 +175,9 @@ export function projectZoneRequirements(args) {
175
175
  if (local)
176
176
  return local;
177
177
  }
178
- return graph.resourceByName(name);
178
+ // In the scope that WROTE the name: a bare reference means the reader's own
179
+ // module, and two libraries may each declare one.
180
+ return graph.resourceByName(name, from.manifest.metadata?.module);
179
181
  };
180
182
  const acceptedFor = (zone) => {
181
183
  const out = new Set([zone]);
@@ -550,7 +552,7 @@ export function runZoneAnalysis(args) {
550
552
  for (const [exportName, specs] of openExports) {
551
553
  if (!lib.exportedNames.has(exportName))
552
554
  continue;
553
- const node = graph.resourceByName(exportName);
555
+ const node = graph.resourceByName(exportName, lib.module);
554
556
  if (!node || node.manifest.metadata?.module !== lib.module) {
555
557
  continue;
556
558
  }
@@ -26,6 +26,8 @@
26
26
  * Browser-safe: no Node built-ins.
27
27
  */
28
28
  import { X_TELO_TYPE } from "@telorun/sdk";
29
+ /** The one annotation read from a DATA schema rather than a kind schema. */
30
+ declare const X_TELO_SENSITIVE: "x-telo-sensitive";
29
31
  import { ANNOTATION_KEYWORDS } from "./value-type-keyword.js";
30
32
  /** A keyword entry: the JSON Schema its VALUE must satisfy, carrying the title
31
33
  * and description completion and hover show. */
@@ -64,5 +66,18 @@ export declare function jsonSchemaKeywords(self: string): SchemaKeywords;
64
66
  * neither validation nor completion. Closing it needs the walkers to distinguish
65
67
  * a schema describing an annotation from an annotation, which nothing does yet.
66
68
  */
67
- export declare const TELO_SCHEMA_ANNOTATIONS: Record<(typeof ANNOTATION_KEYWORDS)[number] | typeof X_TELO_TYPE, Record<string, unknown>>;
69
+ export declare const TELO_SCHEMA_ANNOTATIONS: Record<Exclude<(typeof ANNOTATION_KEYWORDS)[number], typeof X_TELO_SENSITIVE> | typeof X_TELO_TYPE, Record<string, unknown>>;
70
+ /**
71
+ * Annotations that belong on a DATA schema — an `inputType` / `outputType`
72
+ * contract — rather than on a kind's own `schema:`.
73
+ *
74
+ * Split out because {@link TELO_SCHEMA_ANNOTATIONS} is offered only where the
75
+ * fragment is `KindSchema`, which is a kind's CONFIGURATION. `x-telo-sensitive`
76
+ * is read from the opposite place: the kernel resolves it off a bound contract,
77
+ * which stamps `JsonSchema7`. Offering it from the kind vocabulary alone put it
78
+ * on the one schema where nothing reads it and withheld it from the two where it
79
+ * is the whole mechanism.
80
+ */
81
+ export declare const TELO_DATA_SCHEMA_ANNOTATIONS: Record<typeof X_TELO_SENSITIVE, Record<string, unknown>>;
82
+ export {};
68
83
  //# sourceMappingURL=schema-keywords.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema-keywords.d.ts","sourceRoot":"","sources":["../src/schema-keywords.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D;iDACiD;AACjD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AASrE;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAuJ/D;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAC1C,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,WAAW,EACzD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwJxB,CAAC"}
1
+ {"version":3,"file":"schema-keywords.d.ts","sourceRoot":"","sources":["../src/schema-keywords.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,4EAA4E;AAC5E,QAAA,MAAM,gBAAgB,EAAG,kBAA2B,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D;iDACiD;AACjD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AASrE;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAuJ/D;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAMxC,OAAO,CAAC,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,gBAAgB,CAAC,GACtE,OAAO,WAAW,EACpB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwJxB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,EAAE,MAAM,CAC/C,OAAO,gBAAgB,EACvB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQxB,CAAC"}
@@ -25,6 +25,8 @@
25
25
  *
26
26
  * Browser-safe: no Node built-ins.
27
27
  */
28
+ /** The one annotation read from a DATA schema rather than a kind schema. */
29
+ const X_TELO_SENSITIVE = "x-telo-sensitive";
28
30
  /** A JSON type name, as `type:` accepts it — one, or a list (`[string, "null"]`,
29
31
  * the spelling `CEL_NULLABLE_ACCESS` guards). */
30
32
  const TYPE_NAME = {
@@ -342,3 +344,21 @@ export const TELO_SCHEMA_ANNOTATIONS = {
342
344
  type: "string",
343
345
  },
344
346
  };
347
+ /**
348
+ * Annotations that belong on a DATA schema — an `inputType` / `outputType`
349
+ * contract — rather than on a kind's own `schema:`.
350
+ *
351
+ * Split out because {@link TELO_SCHEMA_ANNOTATIONS} is offered only where the
352
+ * fragment is `KindSchema`, which is a kind's CONFIGURATION. `x-telo-sensitive`
353
+ * is read from the opposite place: the kernel resolves it off a bound contract,
354
+ * which stamps `JsonSchema7`. Offering it from the kind vocabulary alone put it
355
+ * on the one schema where nothing reads it and withheld it from the two where it
356
+ * is the whole mechanism.
357
+ */
358
+ export const TELO_DATA_SCHEMA_ANNOTATIONS = {
359
+ [X_TELO_SENSITIVE]: {
360
+ title: "Sensitive",
361
+ description: "This value is auth material or equivalent: carry it as `[redacted]` in trace payloads and on the debug wire rather than verbatim. Read only from a resource's declared `inputType` / `outputType`.",
362
+ type: "boolean",
363
+ },
364
+ };
@@ -1,8 +1,8 @@
1
1
  import type { ManifestSource } from "../types.js";
2
- /** The browser-safe built-in sources, in resolution order: HTTP fetch then
3
- * registry. Node-specific sources (local filesystem) are supplied by the
4
- * consuming package and passed alongside these into the `Loader` constructor.
5
- * Callers that only want a subset (e.g. the editor, which brings its own
6
- * registry adapters) construct the individual sources directly. */
7
- export declare function defaultSources(registryUrl?: string): ManifestSource[];
2
+ /** The browser-safe built-in sources. Node-specific sources (local filesystem)
3
+ * are supplied by the consuming package and passed alongside these into the
4
+ * `Loader` constructor. Callers that only want a subset (e.g. the editor, which
5
+ * brings its own manifest-cache adapter) construct the individual sources
6
+ * directly. */
7
+ export declare function defaultSources(): ManifestSource[];
8
8
  //# sourceMappingURL=default-sources.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"default-sources.d.ts","sourceRoot":"","sources":["../../src/sources/default-sources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD;;;;oEAIoE;AACpE,wBAAgB,cAAc,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE,CAErE"}
1
+ {"version":3,"file":"default-sources.d.ts","sourceRoot":"","sources":["../../src/sources/default-sources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD;;;;gBAIgB;AAChB,wBAAgB,cAAc,IAAI,cAAc,EAAE,CAEjD"}
@@ -1,10 +1,9 @@
1
1
  import { HttpSource } from "./http-source.js";
2
- import { RegistrySource } from "./registry-source.js";
3
- /** The browser-safe built-in sources, in resolution order: HTTP fetch then
4
- * registry. Node-specific sources (local filesystem) are supplied by the
5
- * consuming package and passed alongside these into the `Loader` constructor.
6
- * Callers that only want a subset (e.g. the editor, which brings its own
7
- * registry adapters) construct the individual sources directly. */
8
- export function defaultSources(registryUrl) {
9
- return [new HttpSource(), new RegistrySource(registryUrl)];
2
+ /** The browser-safe built-in sources. Node-specific sources (local filesystem)
3
+ * are supplied by the consuming package and passed alongside these into the
4
+ * `Loader` constructor. Callers that only want a subset (e.g. the editor, which
5
+ * brings its own manifest-cache adapter) construct the individual sources
6
+ * directly. */
7
+ export function defaultSources() {
8
+ return [new HttpSource()];
10
9
  }
@@ -43,8 +43,9 @@ export declare function verifyIntegrity(bytes: Uint8Array, integrity: string, de
43
43
  /** The single verified network read for remote manifests: fetch `fetchUrl`,
44
44
  * verify the raw bytes against `integrity` (when pinned), and return both the
45
45
  * bytes and the decoded text. The one choke point every network `ManifestSource`
46
- * routes through, so verification cannot drift between them. `describe` names
47
- * the artifact in error messages. */
46
+ * routes through, so verification cannot drift between them which is also why
47
+ * the object-storage non-manifest check lives here rather than in each source.
48
+ * `describe` names the artifact in error messages. */
48
49
  export declare function verifiedFetch(fetchUrl: string, integrity: string | undefined, describe: string): Promise<{
49
50
  bytes: Uint8Array;
50
51
  text: string;
@@ -1 +1 @@
1
- {"version":3,"file":"integrity.d.ts","sourceRoot":"","sources":["../../src/sources/integrity.ts"],"names":[],"mappings":"AAAA;;;;;;6EAM6E;AAc7E;;;qDAGqD;AACrD,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED;;2EAE2E;AAC3E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAIhF;AAED;;;kFAGkF;AAClF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAIxE;AAED;;;;;;;;8DAQ8D;AAC9D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEpE;AAcD,iFAAiF;AACjF,wBAAsB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAOxE;AAED;;gFAEgF;AAChF,wBAAsB,eAAe,CACnC,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED;;;;sCAIsC;AACtC,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAU9C"}
1
+ {"version":3,"file":"integrity.d.ts","sourceRoot":"","sources":["../../src/sources/integrity.ts"],"names":[],"mappings":"AAAA;;;;;;6EAM6E;AAc7E;;;qDAGqD;AACrD,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED;;2EAE2E;AAC3E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAIhF;AAED;;;kFAGkF;AAClF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAIxE;AAED;;;;;;;;8DAQ8D;AAC9D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEpE;AAcD,iFAAiF;AACjF,wBAAsB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAOxE;AAED;;gFAEgF;AAChF,wBAAsB,eAAe,CACnC,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAkBf;AAgBD;;;;;uDAKuD;AACvD,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAoB9C"}
@@ -93,18 +93,41 @@ export async function verifyIntegrity(bytes, integrity, describe) {
93
93
  `the module may have been tampered with or republished.`);
94
94
  }
95
95
  }
96
+ /** Object-storage backends (Cloudflare R2, S3) surface auth and permission
97
+ * failures as a **200 with an XML error body**. Caught here rather than left to
98
+ * the loader, which would parse the XML as YAML and report a downstream
99
+ * `UNDEFINED_KIND` — naming the manifest's contents as the problem instead of
100
+ * the origin that refused to serve it. Returns the failure detail, or `null`
101
+ * when the body is not an XML error document. */
102
+ function objectStorageError(text) {
103
+ const head = text.trimStart();
104
+ if (!head.startsWith("<?xml") && !head.startsWith("<Error"))
105
+ return null;
106
+ const code = text.match(/<Code>([^<]+)<\/Code>/);
107
+ const message = text.match(/<Message>([^<]+)<\/Message>/);
108
+ return code && message ? `${code[1]}: ${message[1]}` : text.slice(0, 200);
109
+ }
96
110
  /** The single verified network read for remote manifests: fetch `fetchUrl`,
97
111
  * verify the raw bytes against `integrity` (when pinned), and return both the
98
112
  * bytes and the decoded text. The one choke point every network `ManifestSource`
99
- * routes through, so verification cannot drift between them. `describe` names
100
- * the artifact in error messages. */
113
+ * routes through, so verification cannot drift between them which is also why
114
+ * the object-storage non-manifest check lives here rather than in each source.
115
+ * `describe` names the artifact in error messages. */
101
116
  export async function verifiedFetch(fetchUrl, integrity, describe) {
102
117
  const response = await fetch(fetchUrl);
103
118
  if (!response.ok) {
104
119
  throw new Error(`Failed to fetch manifest ${describe}: ${response.status} ${response.statusText} (${fetchUrl})`);
105
120
  }
106
121
  const bytes = new Uint8Array(await response.arrayBuffer());
122
+ const text = new TextDecoder().decode(bytes);
123
+ // Before the integrity check: a bucket's error page hashes to something, and
124
+ // reporting a pin mismatch would name the wrong cause just as the loader does.
125
+ const storageError = objectStorageError(text);
126
+ if (storageError) {
127
+ throw new Error(`The origin returned a non-manifest response for ${describe} ` +
128
+ `(URL: ${fetchUrl}): ${storageError}`);
129
+ }
107
130
  if (integrity)
108
131
  await verifyIntegrity(bytes, integrity, describe);
109
- return { bytes, text: new TextDecoder().decode(bytes) };
132
+ return { bytes, text };
110
133
  }
@@ -2,11 +2,11 @@
2
2
  * ref, the version segment it currently names, and any inline pin. */
3
3
  export interface ParsedVersionedRef {
4
4
  /** The ref with its `@version` segment and integrity fragment removed —
5
- * `std/run`, `oci://ghcr.io/telorun/timer`. This is the identity a version
6
- * list is keyed by (the hub registers modules under exactly this form). */
5
+ * `oci://ghcr.io/telorun/timer`. This is the identity a version list is keyed
6
+ * by (the hub registers modules under exactly this form). */
7
7
  baseRef: string;
8
- /** The version segment, raw — a registry `@version`, an OCI tag, or an OCI
9
- * digest reference (`sha256:…`). The caller applies its own SemVer check. */
8
+ /** The version segment, raw — an OCI tag or an OCI digest reference
9
+ * (`sha256:…`). The caller applies its own SemVer check. */
10
10
  version: string;
11
11
  /** Telo's inline `sha256-<base64url>` pin, when the ref carried one. */
12
12
  integrity?: string;
@@ -15,12 +15,17 @@ export interface ParsedVersionedRef {
15
15
  * upgradeable version — a local path, a bare `https://` URL, or an OCI ref
16
16
  * with no explicit reference (an implicit `latest` is not a pin).
17
17
  *
18
- * Browser-safe and transport-neutral: this is the *grammar* half of an
19
- * upgrade, shared by the kernel transports (whose `refVersion` / `withVersion`
20
- * delegate here) and the editor, which cannot use a transport at all — the
21
- * *network* half (enumerating versions) is scheme-specific and stays behind
22
- * `Transport.listVersions` on Node and the hub's `/module/versions` in the
23
- * browser. */
18
+ * Browser-safe: this is the *grammar* half of an upgrade, shared by the kernel
19
+ * transports (whose `refVersion` / `withVersion` delegate here) and the editor,
20
+ * which cannot use a transport at all — the *network* half (enumerating
21
+ * versions) is scheme-specific and stays behind `Transport.listVersions` on
22
+ * Node and the hub's `/module/versions` in the browser.
23
+ *
24
+ * It is NOT transport-neutral: `oci://` is the only versionable grammar, named
25
+ * literally below. That was equally true when the registry ref was the second
26
+ * branch, and a third scheme still means editing this file — the versionable
27
+ * set would have to become data the transports contribute before that claim
28
+ * could be made honestly. */
24
29
  export declare function parseVersionedRef(ref: string): ParsedVersionedRef | null;
25
30
  /** `ref` rewritten to name `version`, dropping any integrity fragment (the
26
31
  * caller re-pins the result). Appends the version when the ref carries none —
@@ -28,7 +33,7 @@ export declare function parseVersionedRef(ref: string): ParsedVersionedRef | nul
28
33
  *
29
34
  * Throws when the ref's grammar has no version segment at all — a relative
30
35
  * path, a bare `https://` URL. Producing `../lib@0.4.0` for those would write
31
- * a ref nothing can resolve, so this fails where the transport-specific
32
- * parsers it replaced (`parseOciRef` / `parseModuleRef`) also failed. */
36
+ * a ref nothing can resolve, so this fails where the transport-specific parser
37
+ * it replaced (`parseOciRef`) also failed. */
33
38
  export declare function withRefVersion(ref: string, version: string): string;
34
39
  //# sourceMappingURL=versioned-ref.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"versioned-ref.d.ts","sourceRoot":"","sources":["../../src/sources/versioned-ref.ts"],"names":[],"mappings":"AAIA;uEACuE;AACvE,MAAM,WAAW,kBAAkB;IACjC;;gFAE4E;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB;kFAC8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;eASe;AACf,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAOxE;AAED;;;;;;;0EAO0E;AAC1E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAUnE"}
1
+ {"version":3,"file":"versioned-ref.d.ts","sourceRoot":"","sources":["../../src/sources/versioned-ref.ts"],"names":[],"mappings":"AAGA;uEACuE;AACvE,MAAM,WAAW,kBAAkB;IACjC;;kEAE8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB;iEAC6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;8BAc8B;AAC9B,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAOxE;AAED;;;;;;;+CAO+C;AAC/C,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CASnE"}
@@ -1,16 +1,20 @@
1
1
  import { splitIntegrity } from "./integrity.js";
2
- import { isRegistryRef } from "./module-ref.js";
3
2
  import { OCI_SCHEME } from "./oci-ref.js";
4
3
  /** Split a versioned module ref. Returns `null` when the ref names no
5
4
  * upgradeable version — a local path, a bare `https://` URL, or an OCI ref
6
5
  * with no explicit reference (an implicit `latest` is not a pin).
7
6
  *
8
- * Browser-safe and transport-neutral: this is the *grammar* half of an
9
- * upgrade, shared by the kernel transports (whose `refVersion` / `withVersion`
10
- * delegate here) and the editor, which cannot use a transport at all — the
11
- * *network* half (enumerating versions) is scheme-specific and stays behind
12
- * `Transport.listVersions` on Node and the hub's `/module/versions` in the
13
- * browser. */
7
+ * Browser-safe: this is the *grammar* half of an upgrade, shared by the kernel
8
+ * transports (whose `refVersion` / `withVersion` delegate here) and the editor,
9
+ * which cannot use a transport at all — the *network* half (enumerating
10
+ * versions) is scheme-specific and stays behind `Transport.listVersions` on
11
+ * Node and the hub's `/module/versions` in the browser.
12
+ *
13
+ * It is NOT transport-neutral: `oci://` is the only versionable grammar, named
14
+ * literally below. That was equally true when the registry ref was the second
15
+ * branch, and a third scheme still means editing this file — the versionable
16
+ * set would have to become data the transports contribute before that claim
17
+ * could be made honestly. */
14
18
  export function parseVersionedRef(ref) {
15
19
  const { base, integrity } = splitIntegrity(ref);
16
20
  const at = versionSeparator(base);
@@ -27,34 +31,28 @@ export function parseVersionedRef(ref) {
27
31
  *
28
32
  * Throws when the ref's grammar has no version segment at all — a relative
29
33
  * path, a bare `https://` URL. Producing `../lib@0.4.0` for those would write
30
- * a ref nothing can resolve, so this fails where the transport-specific
31
- * parsers it replaced (`parseOciRef` / `parseModuleRef`) also failed. */
34
+ * a ref nothing can resolve, so this fails where the transport-specific parser
35
+ * it replaced (`parseOciRef`) also failed. */
32
36
  export function withRefVersion(ref, version) {
33
37
  const { base } = splitIntegrity(ref);
34
- if (refGrammar(base) === null) {
35
- throw new Error(`Cannot set a version on '${ref}' — only registry (namespace/name@version) ` +
36
- `and oci:// refs carry a version segment.`);
38
+ if (!isVersionableRef(base)) {
39
+ throw new Error(`Cannot set a version on '${ref}' — only oci:// refs carry a version segment.`);
37
40
  }
38
41
  const at = versionSeparator(base);
39
42
  return `${at === null ? base : base.slice(0, at)}@${version}`;
40
43
  }
41
- /** Which versionable ref grammar `base` is written in, or `null` when it is
42
- * neither — a relative/absolute path, a `file:`/`https://` URL. */
43
- function refGrammar(base) {
44
- if (base.startsWith(OCI_SCHEME)) {
45
- // A host alone is not addressable; the repo path is what carries a version.
46
- return base.indexOf("/", OCI_SCHEME.length) > OCI_SCHEME.length ? "oci" : null;
47
- }
48
- // `isRegistryRef` requires the `@`, so a version-less `std/console` is not a
49
- // registry ref by this test — matching `parseModuleRef`, which throws on it.
50
- return isRegistryRef(base) ? "registry" : null;
44
+ /** True when `base` is written in a grammar that carries a version segment — a
45
+ * relative/absolute path and a `file:`/`https://` URL are not. */
46
+ function isVersionableRef(base) {
47
+ // A host alone is not addressable; the repo path is what carries a version.
48
+ return base.startsWith(OCI_SCHEME) && base.indexOf("/", OCI_SCHEME.length) > OCI_SCHEME.length;
51
49
  }
52
50
  /** Index of the `@` that separates the version, or `null` when the ref names
53
51
  * none. Split on the LAST `@` so a digest reference (`repo@sha256:…`) keeps
54
52
  * everything before it as the ref. */
55
53
  function versionSeparator(base) {
56
- if (refGrammar(base) === null)
54
+ if (!isVersionableRef(base))
57
55
  return null;
58
56
  const at = base.lastIndexOf("@");
59
- return at > (base.startsWith(OCI_SCHEME) ? OCI_SCHEME.length : 0) ? at : null;
57
+ return at > OCI_SCHEME.length ? at : null;
60
58
  }
@@ -1,3 +1,3 @@
1
1
  /** The surface generation this analyzer implements. */
2
- export declare const TELO_SURFACE_VERSION = "0.83.0";
2
+ export declare const TELO_SURFACE_VERSION = "0.85.0";
3
3
  //# sourceMappingURL=telo-version.d.ts.map
@@ -5,4 +5,4 @@
5
5
  // its release identity, this is the scale a module's `requires.telo` range is
6
6
  // written against, and every kernel in every language reports the same scale.
7
7
  /** The surface generation this analyzer implements. */
8
- export const TELO_SURFACE_VERSION = "0.83.0";
8
+ export const TELO_SURFACE_VERSION = "0.85.0";
@@ -1 +1 @@
1
- {"version":3,"file":"validate-extends.d.ts","sourceRoot":"","sources":["../src/validate-extends.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA8BzE,wBAAgB,eAAe,CAC7B,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE,aAAa,GACrB,kBAAkB,EAAE,CA4JtB"}
1
+ {"version":3,"file":"validate-extends.d.ts","sourceRoot":"","sources":["../src/validate-extends.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAQnE,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAiCzE,wBAAgB,eAAe,CAC7B,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE,aAAa,GACrB,kBAAkB,EAAE,CAqMtB"}
@@ -1,4 +1,4 @@
1
- import { inheritedCapability } from "./extends-resolution.js";
1
+ import { controllerBearingAncestor, effectiveAuthorSchema, inheritedCapability, isInheritedDelegation, } from "./extends-resolution.js";
2
2
  import { DiagnosticSeverity } from "./types.js";
3
3
  const SOURCE = "telo-analyzer";
4
4
  /** Alias-form pattern for `extends`: "<Alias>.<AbstractName>", two PascalCase segments. */
@@ -19,6 +19,9 @@ const EXTENDS_ALIAS_RE = /^[A-Z][A-Za-z0-9_]*\.[A-Z][A-Za-z0-9_]*$/;
19
19
  * - EXTENDS_UNKNOWN_TARGET: alias resolves to a module, but that module has no
20
20
  * registered definition with the target name.
21
21
  * - EXTENDS_NON_ABSTRACT: target resolves to a Telo.Definition, not a Telo.Abstract.
22
+ * - EXTENDS_CLOSED_PARENT_ADDS_FIELD: a child with no `base:` declares a property its
23
+ * controller-bearing ancestor's closed schema rejects — the runtime counterpart is a
24
+ * create-time failure phrased against the ancestor kind.
22
25
  * - CAPABILITY_SHADOWS_EXTENDS (warning): `capability` names a user-declared abstract
23
26
  * (metadata.module !== "Telo"). Builtin lifecycle capabilities (Telo.Invocable, etc.)
24
27
  * never trigger this — they're lifecycle roles by design.
@@ -140,6 +143,44 @@ export function validateExtends(manifests, registry, aliases) {
140
143
  data: { resource, filePath, path: "capability" },
141
144
  });
142
145
  }
146
+ // A merge-form child (no `base:`) forwards its WHOLE config to the
147
+ // inherited controller as the parent's config, so a field the
148
+ // parent's schema closes out is rejected at the parent's own
149
+ // create-time validation — phrased against the parent kind, at the
150
+ // instance's line, about a resource the author never wrote.
151
+ // Reported here instead, at the property that has to change.
152
+ if (m.base == null &&
153
+ isInheritedDelegation(m, resolveDef)) {
154
+ const ancestor = controllerBearingAncestor(m, resolveDef);
155
+ const ancestorSchema = ancestor
156
+ ? effectiveAuthorSchema(ancestor, resolveDef)
157
+ : undefined;
158
+ if (ancestorSchema?.additionalProperties === false) {
159
+ const inherited = new Set(Object.keys(ancestorSchema.properties ?? {}));
160
+ const ownProps = (m
161
+ .schema?.properties ?? {});
162
+ const ancestorKind = `${ancestor?.metadata.module}.${ancestor?.metadata.name}`;
163
+ for (const prop of Object.keys(ownProps)) {
164
+ if (inherited.has(prop))
165
+ continue;
166
+ diagnostics.push({
167
+ severity: DiagnosticSeverity.Error,
168
+ code: "EXTENDS_CLOSED_PARENT_ADDS_FIELD",
169
+ source: SOURCE,
170
+ message: `${label}: declares '${prop}', but '${ancestorKind}' closes its schema ` +
171
+ `(additionalProperties: false) and a child without 'base:' forwards its whole ` +
172
+ `config as that kind's config — so '${prop}' is rejected when the resource is ` +
173
+ `created. Add a 'base:' mapping, which makes this kind's fields construction ` +
174
+ `inputs and builds the parent's config explicitly.`,
175
+ data: {
176
+ resource,
177
+ filePath,
178
+ path: `schema.properties.${prop}`,
179
+ },
180
+ });
181
+ }
182
+ }
183
+ }
143
184
  }
144
185
  }
145
186
  }
@@ -0,0 +1,28 @@
1
+ import type { ResourceManifest } from "@telorun/sdk";
2
+ /**
3
+ * `x-telo-sensitive` where nothing reads it.
4
+ *
5
+ * The annotation has exactly one consumer: the kernel resolves it from a
6
+ * resource's bound CONTRACT — `inputType` / `outputType` — and carries the
7
+ * marked value as `[redacted]` in trace payloads. Written anywhere else it is an
8
+ * unknown keyword in an open schema, which is to say it validates, ships, and
9
+ * does nothing.
10
+ *
11
+ * For a security control that is the worst available failure: an author marks a
12
+ * token, sees no error, and puts it on the debug wire anyway. So a misplacement
13
+ * is reported rather than ignored — the same posture `X_TELO_REF_UNRESOLVED`
14
+ * takes toward a reference constraint that resolves to nothing, and for the same
15
+ * reason: silence reads as protection.
16
+ *
17
+ * Scoped by the caller to the entry's own modules, since a dependency's schema
18
+ * is not the consumer's to fix.
19
+ */
20
+ export interface SensitiveSlotIssue {
21
+ code: "SENSITIVE_ANNOTATION_MISPLACED" | "SENSITIVE_ANNOTATION_INVALID";
22
+ manifest: ResourceManifest;
23
+ /** Dotted path to the annotated schema node. */
24
+ path: string;
25
+ message: string;
26
+ }
27
+ export declare function validateSensitiveSlots(manifest: ResourceManifest): SensitiveSlotIssue[];
28
+ //# sourceMappingURL=validate-sensitive-slots.d.ts.map