@telorun/analyzer 0.48.0 → 0.49.1

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 (50) hide show
  1. package/dist/analysis-registry.d.ts +22 -11
  2. package/dist/analysis-registry.d.ts.map +1 -1
  3. package/dist/analysis-registry.js +36 -39
  4. package/dist/analyzer.d.ts +38 -1
  5. package/dist/analyzer.d.ts.map +1 -1
  6. package/dist/analyzer.js +115 -83
  7. package/dist/builtins.d.ts.map +1 -1
  8. package/dist/builtins.js +72 -1
  9. package/dist/extends-resolution.d.ts +41 -0
  10. package/dist/extends-resolution.d.ts.map +1 -1
  11. package/dist/extends-resolution.js +68 -0
  12. package/dist/index.d.ts +4 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +2 -1
  15. package/dist/invocation-contract.d.ts +100 -0
  16. package/dist/invocation-contract.d.ts.map +1 -0
  17. package/dist/invocation-contract.js +208 -0
  18. package/dist/manifest-loader.d.ts +11 -0
  19. package/dist/manifest-loader.d.ts.map +1 -1
  20. package/dist/manifest-loader.js +20 -0
  21. package/dist/schema-compat.d.ts +12 -4
  22. package/dist/schema-compat.d.ts.map +1 -1
  23. package/dist/schema-compat.js +185 -9
  24. package/dist/validate-base-mapping.js +11 -1
  25. package/dist/validate-cel-context.d.ts +0 -6
  26. package/dist/validate-cel-context.d.ts.map +1 -1
  27. package/dist/validate-cel-context.js +51 -4
  28. package/dist/validate-invocation-contract.d.ts +30 -0
  29. package/dist/validate-invocation-contract.d.ts.map +1 -0
  30. package/dist/validate-invocation-contract.js +394 -0
  31. package/dist/validate-step-inputs.d.ts +24 -0
  32. package/dist/validate-step-inputs.d.ts.map +1 -0
  33. package/dist/validate-step-inputs.js +87 -0
  34. package/dist/validate-throws-coverage.d.ts +1 -1
  35. package/dist/validate-throws-coverage.d.ts.map +1 -1
  36. package/dist/validate-throws-coverage.js +9 -1
  37. package/package.json +3 -3
  38. package/src/analysis-registry.ts +44 -34
  39. package/src/analyzer.ts +171 -100
  40. package/src/builtins.ts +74 -1
  41. package/src/extends-resolution.ts +86 -0
  42. package/src/index.ts +13 -1
  43. package/src/invocation-contract.ts +275 -0
  44. package/src/manifest-loader.ts +20 -0
  45. package/src/schema-compat.ts +191 -8
  46. package/src/validate-base-mapping.ts +14 -1
  47. package/src/validate-cel-context.ts +49 -4
  48. package/src/validate-invocation-contract.ts +450 -0
  49. package/src/validate-step-inputs.ts +117 -0
  50. package/src/validate-throws-coverage.ts +12 -2
package/dist/builtins.js CHANGED
@@ -206,6 +206,64 @@ export const KERNEL_BUILTINS = [
206
206
  additionalProperties: false,
207
207
  },
208
208
  },
209
+ {
210
+ // Telo.JsonSchema — the concrete data-shape kind, in the kernel rather than
211
+ // in an installable module for the same reason the mandatory sinks are:
212
+ // declaring a shape is not optional. Every kind with an invocation contract
213
+ // needs one, so requiring an import to write `inputType:` would put a tax on
214
+ // the one thing the contract wants authors to do more of — and a library
215
+ // declaring a contract would have to import a module purely to describe
216
+ // itself. `type.JsonSchema` remains as a deprecated alias of this kind.
217
+ kind: "Telo.Definition",
218
+ metadata: { name: "JsonSchema", module: "Telo" },
219
+ capability: "Telo.Type",
220
+ // Declared so the kind reads as controller-BEARING, which is what lets
221
+ // another definition inherit it by delegation (`extends: Telo.JsonSchema`
222
+ // with no controller of its own). The entry is never loaded from — the
223
+ // kernel registers this controller directly at boot, before any lazy
224
+ // resolution — it states truthfully who provides it.
225
+ controllers: [{ runtime: "kernel", entry: "Telo.JsonSchema" }],
226
+ schema: {
227
+ type: "object",
228
+ properties: {
229
+ schema: {
230
+ title: "Schema",
231
+ description: "JSON Schema definition for the declared data type.",
232
+ type: "object",
233
+ },
234
+ extends: {
235
+ title: "Extends",
236
+ description: "Parent type name or list of parent type names to inherit from.",
237
+ oneOf: [{ type: "string" }, { type: "array", items: { type: "string" } }],
238
+ },
239
+ rules: {
240
+ title: "Rules",
241
+ description: "CEL-based business invariant rules. Each rule's condition must return true for valid data.",
242
+ type: "array",
243
+ items: {
244
+ type: "object",
245
+ properties: {
246
+ condition: {
247
+ type: "string",
248
+ description: "CEL expression evaluated with 'this' bound to the data. Must return true for valid data.",
249
+ },
250
+ code: {
251
+ type: "string",
252
+ description: "Machine-readable error code surfaced on validation failure.",
253
+ },
254
+ message: {
255
+ type: "string",
256
+ description: "Optional human-readable hint for the validation failure.",
257
+ },
258
+ },
259
+ required: ["condition", "code"],
260
+ },
261
+ },
262
+ },
263
+ required: ["schema"],
264
+ additionalProperties: false,
265
+ },
266
+ },
209
267
  {
210
268
  kind: "Telo.Definition",
211
269
  metadata: { name: "Abstract", module: "Telo" },
@@ -479,6 +537,11 @@ export const KERNEL_BUILTINS = [
479
537
  default: "shared",
480
538
  },
481
539
  targets: {
540
+ // Boot targets form a step list: a later target reads an earlier one's
541
+ // result as `steps.<name>.result`, exactly as a sequence step does, so
542
+ // the same annotation types that context and drives the call-site
543
+ // contract check.
544
+ "x-telo-step-context": { invoke: "invoke", outputType: "outputType" },
482
545
  type: "array",
483
546
  items: {
484
547
  anyOf: [
@@ -552,7 +615,15 @@ export const KERNEL_BUILTINS = [
552
615
  { "x-telo-ref": "Telo.Runnable" },
553
616
  ],
554
617
  },
555
- inputs: { type: "object", additionalProperties: true },
618
+ inputs: {
619
+ // Same annotation Run.Sequence steps carry: it is what makes
620
+ // a boot target's inputs visible to the call-site contract
621
+ // check and to the wiring rule. Without it the kernel would
622
+ // validate these at dispatch and nothing before it.
623
+ "x-telo-topology-role": "inputs",
624
+ type: "object",
625
+ additionalProperties: true,
626
+ },
556
627
  when: { type: "string" },
557
628
  },
558
629
  additionalProperties: false,
@@ -36,6 +36,47 @@ export declare function inheritedCapability(def: ResourceDefinition | undefined,
36
36
  * `mergeTypeSchemas` that `Type.JsonSchema.extends` uses.
37
37
  * - no `extends` → the own schema unchanged. */
38
38
  export declare function effectiveAuthorSchema(def: ResourceDefinition | undefined, resolve: DefResolver): Record<string, any>;
39
+ /** The two directions of a kind's invocation contract. `inputType` is what a
40
+ * caller sends to `invoke()`; `outputType` is what `invoke()` / `provide()`
41
+ * returns. */
42
+ export type ContractDirection = "inputType" | "outputType";
43
+ /**
44
+ * The **nearest declaration** of an invocation contract along the `extends`
45
+ * chain, self first — the raw type-field value, still to be resolved to a schema
46
+ * by the caller (which is what keeps this module free of manifest lookup).
47
+ *
48
+ * Contracts RESOLVE, they never merge. A definition that declares one fully
49
+ * replaces its ancestor's; one that declares none inherits its ancestor's
50
+ * verbatim, at any depth. This is deliberately unlike {@link
51
+ * effectiveAuthorSchema} and {@link effectiveStatusSchema}: construction config
52
+ * and observed state are additive, a call signature is not. Folding a child's
53
+ * required fields into its parent's yields a union no caller can satisfy, and it
54
+ * would reject the very remapping `base:` + `inputs:` exists for — the point of
55
+ * a child declaring a signature is that it accepts something *different*.
56
+ *
57
+ * Substitutability is not weakened by that, because `extends` never carried the
58
+ * dispatch contract: it decides which slots accept a resource. Whether a
59
+ * particular slot may hold a resource whose contract differs from the slot's
60
+ * declared kind is a wiring question, answered per slot by
61
+ * `validate-invocation-contract`'s wiring rule.
62
+ */
63
+ export declare function effectiveContractField(def: ResourceDefinition | undefined, resolve: DefResolver, direction: ContractDirection): unknown;
64
+ /** The definition in the `extends` chain (self first) that actually DECLARES the
65
+ * contract for `direction` — the one whose scope its `telo#Type` references
66
+ * resolve in, and the one a diagnostic should name. Undefined when nothing in
67
+ * the chain declares it. */
68
+ export declare function contractDeclarer(def: ResourceDefinition | undefined, resolve: DefResolver, direction: ContractDirection): ResourceDefinition | undefined;
69
+ /** True when this definition declares its own contract for `direction` while
70
+ * inheriting the controller that will execute it — the case that REQUIRES a
71
+ * bridging mapping (`inputs:` for inputs, `result:` for outputs), because the
72
+ * inherited controller only understands the ancestor's shape. A definition with
73
+ * its own controller or template body is exempt: its controller *is* the
74
+ * implementation of whatever it declares. */
75
+ export declare function needsContractMapping(def: ResourceDefinition | undefined, resolve: DefResolver, direction: ContractDirection): boolean;
76
+ /** The mapping field that bridges a replaced contract back to the inherited
77
+ * controller: `inputs:` maps the child's signature onto the parent's call,
78
+ * `result:` maps the parent's result back to the child's declared output. */
79
+ export declare function mappingFieldFor(direction: ContractDirection): "inputs" | "result";
39
80
  /** The observed state a kind reports (`status:`), folded through `extends`:
40
81
  * - with `base:` present → the **parent's** effective status unchanged; the
41
82
  * child delegates to the parent's controller and *is* a parent instance, so
@@ -1 +1 @@
1
- {"version":3,"file":"extends-resolution.d.ts","sourceRoot":"","sources":["../src/extends-resolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGvD;;;;;;;2DAO2D;AAC3D,MAAM,MAAM,WAAW,GAAG,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,kBAAkB,KACtB,kBAAkB,GAAG,SAAS,CAAC;AAsBpC;sDACsD;AACtD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAIhC;AAED;6EAC6E;AAC7E,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,EAAE,CAUtB;AAED;iFACiF;AACjF,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAUvF;AAED;;mFAEmF;AACnF,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAMhC;AAED;;sCAEsC;AACtC,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,OAAO,CAGT;AAED;2EAC2E;AAC3E,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;;iDAMiD;AACjD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAOrB;AAED;;;;;;;;;gDASgD;AAChD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CASjC"}
1
+ {"version":3,"file":"extends-resolution.d.ts","sourceRoot":"","sources":["../src/extends-resolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGvD;;;;;;;2DAO2D;AAC3D,MAAM,MAAM,WAAW,GAAG,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,kBAAkB,KACtB,kBAAkB,GAAG,SAAS,CAAC;AA0BpC;sDACsD;AACtD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAIhC;AAED;6EAC6E;AAC7E,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,EAAE,CAUtB;AAED;iFACiF;AACjF,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAUvF;AAED;;mFAEmF;AACnF,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAMhC;AAED;;sCAEsC;AACtC,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,OAAO,CAGT;AAED;2EAC2E;AAC3E,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;;iDAMiD;AACjD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAOrB;AAED;;eAEe;AACf,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,YAAY,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,iBAAiB,GAC3B,OAAO,CAQT;AAED;;;6BAG6B;AAC7B,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,iBAAiB,GAC3B,kBAAkB,GAAG,SAAS,CAShC;AAED;;;;;8CAK8C;AAC9C,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,iBAAiB,GAC3B,OAAO,CAKT;AAED;;8EAE8E;AAC9E,wBAAgB,eAAe,CAAC,SAAS,EAAE,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,CAEjF;AAED;;;;;;;;;gDASgD;AAChD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CASjC"}
@@ -80,6 +80,74 @@ export function effectiveAuthorSchema(def, resolve) {
80
80
  const parentSchema = effectiveAuthorSchema(parent, resolve);
81
81
  return mergeTypeSchemas([parentSchema, own]);
82
82
  }
83
+ /**
84
+ * The **nearest declaration** of an invocation contract along the `extends`
85
+ * chain, self first — the raw type-field value, still to be resolved to a schema
86
+ * by the caller (which is what keeps this module free of manifest lookup).
87
+ *
88
+ * Contracts RESOLVE, they never merge. A definition that declares one fully
89
+ * replaces its ancestor's; one that declares none inherits its ancestor's
90
+ * verbatim, at any depth. This is deliberately unlike {@link
91
+ * effectiveAuthorSchema} and {@link effectiveStatusSchema}: construction config
92
+ * and observed state are additive, a call signature is not. Folding a child's
93
+ * required fields into its parent's yields a union no caller can satisfy, and it
94
+ * would reject the very remapping `base:` + `inputs:` exists for — the point of
95
+ * a child declaring a signature is that it accepts something *different*.
96
+ *
97
+ * Substitutability is not weakened by that, because `extends` never carried the
98
+ * dispatch contract: it decides which slots accept a resource. Whether a
99
+ * particular slot may hold a resource whose contract differs from the slot's
100
+ * declared kind is a wiring question, answered per slot by
101
+ * `validate-invocation-contract`'s wiring rule.
102
+ */
103
+ export function effectiveContractField(def, resolve, direction) {
104
+ const own = body(def)[direction];
105
+ if (own !== undefined && own !== null)
106
+ return own;
107
+ for (const a of ancestorChain(def, resolve)) {
108
+ const inherited = body(a)[direction];
109
+ if (inherited !== undefined && inherited !== null)
110
+ return inherited;
111
+ }
112
+ return undefined;
113
+ }
114
+ /** The definition in the `extends` chain (self first) that actually DECLARES the
115
+ * contract for `direction` — the one whose scope its `telo#Type` references
116
+ * resolve in, and the one a diagnostic should name. Undefined when nothing in
117
+ * the chain declares it. */
118
+ export function contractDeclarer(def, resolve, direction) {
119
+ if (!def)
120
+ return undefined;
121
+ const own = body(def)[direction];
122
+ if (own !== undefined && own !== null)
123
+ return def;
124
+ for (const a of ancestorChain(def, resolve)) {
125
+ const inherited = body(a)[direction];
126
+ if (inherited !== undefined && inherited !== null)
127
+ return a;
128
+ }
129
+ return undefined;
130
+ }
131
+ /** True when this definition declares its own contract for `direction` while
132
+ * inheriting the controller that will execute it — the case that REQUIRES a
133
+ * bridging mapping (`inputs:` for inputs, `result:` for outputs), because the
134
+ * inherited controller only understands the ancestor's shape. A definition with
135
+ * its own controller or template body is exempt: its controller *is* the
136
+ * implementation of whatever it declares. */
137
+ export function needsContractMapping(def, resolve, direction) {
138
+ const own = body(def)[direction];
139
+ if (own === undefined || own === null)
140
+ return false;
141
+ if (hasOwnControllerOrTemplate(def))
142
+ return false;
143
+ return controllerBearingAncestor(def, resolve) !== undefined;
144
+ }
145
+ /** The mapping field that bridges a replaced contract back to the inherited
146
+ * controller: `inputs:` maps the child's signature onto the parent's call,
147
+ * `result:` maps the parent's result back to the child's declared output. */
148
+ export function mappingFieldFor(direction) {
149
+ return direction === "inputType" ? "inputs" : "result";
150
+ }
83
151
  /** The observed state a kind reports (`status:`), folded through `extends`:
84
152
  * - with `base:` present → the **parent's** effective status unchanged; the
85
153
  * child delegates to the parent's controller and *is* a parent instance, so
package/dist/index.d.ts CHANGED
@@ -9,8 +9,10 @@ export { applyObservedStateNode, buildObservedStateIndex, buildObservedStateReso
9
9
  export type { AnalyzedResource, ObservedStateRead } from "./validate-observed-state.js";
10
10
  export { moduleScopedDefResolver, scopeResolverForModule } from "./alias-resolver.js";
11
11
  export type { ModuleScopes } from "./alias-resolver.js";
12
- export { ancestorChain, controllerBearingAncestor, effectiveAuthorSchema, effectiveStatusSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, resolveParent, } from "./extends-resolution.js";
13
- export type { DefResolver } from "./extends-resolution.js";
12
+ export { ancestorChain, contractDeclarer, controllerBearingAncestor, effectiveAuthorSchema, effectiveContractField, effectiveStatusSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, mappingFieldFor, needsContractMapping, resolveParent, } from "./extends-resolution.js";
13
+ export type { ContractDirection, DefResolver } from "./extends-resolution.js";
14
+ export { defaultBearingPaths, PERMISSIVE_CONTRACT, resolveContract, resolveContractSchema, withStreamPropertiesSkipped, } from "./invocation-contract.js";
15
+ export type { ContractOrigin, ContractScope, ResolvedContract } from "./invocation-contract.js";
14
16
  export { hasIntermediateWildcard, parseRedactionPath, RedactionPathError, } from "./redaction-path.js";
15
17
  export type { RedactionSegment } from "./redaction-path.js";
16
18
  export { buildReferenceFieldMap, isRefEntry, isScopeEntry } from "./reference-field-map.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -5,7 +5,8 @@ export { flattenForAnalyzer, flattenLoadedModule, forwardReExportManifests, pars
5
5
  export { buildEvalPaths, evalPathCovers } from "./eval-paths.js";
6
6
  export { applyObservedStateNode, buildObservedStateIndex, buildObservedStateResourcesSchema, collectRunReachableNames, observedStateRead, validateObservedStateDeclarations, OBSERVED_STATE_SCHEMA, } from "./validate-observed-state.js";
7
7
  export { moduleScopedDefResolver, scopeResolverForModule } from "./alias-resolver.js";
8
- export { ancestorChain, controllerBearingAncestor, effectiveAuthorSchema, effectiveStatusSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, resolveParent, } from "./extends-resolution.js";
8
+ export { ancestorChain, contractDeclarer, controllerBearingAncestor, effectiveAuthorSchema, effectiveContractField, effectiveStatusSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, mappingFieldFor, needsContractMapping, resolveParent, } from "./extends-resolution.js";
9
+ export { defaultBearingPaths, PERMISSIVE_CONTRACT, resolveContract, resolveContractSchema, withStreamPropertiesSkipped, } from "./invocation-contract.js";
9
10
  export { hasIntermediateWildcard, parseRedactionPath, RedactionPathError, } from "./redaction-path.js";
10
11
  export { buildReferenceFieldMap, isRefEntry, isScopeEntry } from "./reference-field-map.js";
11
12
  export { visitManifest } from "./manifest-visitor.js";
@@ -0,0 +1,100 @@
1
+ import type { ResourceDefinition } from "@telorun/sdk";
2
+ import { type ContractDirection, type DefResolver } from "./extends-resolution.js";
3
+ export type { ContractDirection };
4
+ /**
5
+ * The one answer to "what is this target's input / output schema".
6
+ *
7
+ * Both halves of Telo consume it: `telo check` validates call sites against it,
8
+ * and the kernel binds it to the instance at creation. It lives here rather than
9
+ * in the kernel because it must be browser-safe and because a second
10
+ * implementation would drift — the same split already used for
11
+ * `buildEvalPaths` / `evalPathCovers` and the redaction path parser. Before this
12
+ * there were three one-hop lookups (the analysis registry's editor helpers, the
13
+ * template-body `inputs` typing, the step-context definition fallback) and a
14
+ * runtime that consulted only an explicitly-passed type ref, so static analysis
15
+ * and dispatch could disagree about the very contract they were both checking.
16
+ */
17
+ /** Where a resolved contract was declared. Instance-level declarations let one
18
+ * call site narrow a kind's contract (`JS.Script` does this); kind-level ones
19
+ * are the kind's own signature. */
20
+ export type ContractOrigin = "instance" | "kind";
21
+ export interface ResolvedContract {
22
+ /** The JSON Schema a value is validated against. */
23
+ schema: Record<string, any>;
24
+ origin: ContractOrigin;
25
+ /** The definition that declared it, when `origin` is `"kind"` — the scope its
26
+ * named type references resolved in, and what a diagnostic should name. */
27
+ declaredBy?: ResourceDefinition;
28
+ }
29
+ export interface ContractScope {
30
+ /** Resolves a kind to its definition. Must be scoped to the module that
31
+ * DECLARED the definition being walked — `extends` aliases are lexical, so a
32
+ * chain crossing module boundaries re-scopes at each hop. */
33
+ resolveDefinition: DefResolver;
34
+ /**
35
+ * Manifests a named `telo#Type` reference resolves against, given the
36
+ * definition that DECLARED the type field.
37
+ *
38
+ * The parameter exists for a caller that keeps types per module. The analyzer
39
+ * does not: it works from one flattened list where names are already unique
40
+ * per module, so it ignores the argument and returns that list. A caller
41
+ * holding several scopes uses it to avoid resolving a bare name against the
42
+ * wrong module's type of the same name.
43
+ */
44
+ typeManifestsFor(def: ResourceDefinition | undefined): Record<string, any>[];
45
+ }
46
+ /** The fallback for a target that declares no contract: anything goes. Not
47
+ * `additionalProperties: false` — an undeclared contract is an absence of a
48
+ * claim, not a claim of emptiness. */
49
+ export declare const PERMISSIVE_CONTRACT: Record<string, any>;
50
+ /**
51
+ * Resolve a dispatch target's contract, layering:
52
+ * 1. the **instance manifest's** own `inputType:` / `outputType:` — per-call-site
53
+ * narrowing, opted into simply by the kind declaring the property;
54
+ * 2. the **kind's** contract, resolved to the nearest declaration along
55
+ * `extends` (see {@link effectiveContractField} — nearest wins, no merge);
56
+ * 3. undefined — the caller decides whether that means permissive.
57
+ *
58
+ * Returns undefined rather than {@link PERMISSIVE_CONTRACT} so a caller can tell
59
+ * "declared nothing" from "declared anything", which the wiring rule and the
60
+ * `run()` guard both need.
61
+ */
62
+ export declare function resolveContract(direction: ContractDirection, manifest: Record<string, any> | undefined, definition: ResourceDefinition | undefined, scope: ContractScope): ResolvedContract | undefined;
63
+ /** {@link resolveContract}, falling back to {@link PERMISSIVE_CONTRACT}. For
64
+ * callers that need a schema unconditionally (CEL context typing), as opposed
65
+ * to needing to know whether one was declared. */
66
+ export declare function resolveContractSchema(direction: ContractDirection, manifest: Record<string, any> | undefined, definition: ResourceDefinition | undefined, scope: ContractScope): Record<string, any>;
67
+ /**
68
+ * A copy of `schema` with every `x-telo-stream`-marked property removed from
69
+ * `properties` and `required`, for validating a runtime value against.
70
+ *
71
+ * Streams travel in BOTH directions — `Codec.Encoder` marks `input` on its
72
+ * `inputType` and lists it in `required`, and `Record.Stream`, `Ai`, `Tar` and
73
+ * `Console` do the same — so a one-directional skip would walk a live `Stream`
74
+ * with AJV on the hottest path in the runtime. That is the same defect as
75
+ * `stripCompiledValues` walking a live `ResourceInstance` in a ref slot: a live
76
+ * object in a declared slot is not data to be traversed. The annotation already
77
+ * marks exactly the properties to leave alone.
78
+ *
79
+ * Structural (returns a new object, never mutates), and shared so the analyzer
80
+ * and the kernel exempt the same set.
81
+ */
82
+ export declare function withStreamPropertiesSkipped(schema: Record<string, any>,
83
+ /** Resolves a `$ref` to the schema it names. Required to see through the
84
+ * reference form the runtime deliberately KEEPS intact for its validator: a
85
+ * contract written as `{ $ref: "telo:mod/Type" }` has none of its own
86
+ * properties, so a walk that cannot follow the reference exempts nothing and
87
+ * the stream is traversed after all. */
88
+ resolveRef?: (ref: string) => Record<string, any> | undefined): Record<string, any>;
89
+ /** Every property path in `schema` that can receive a `default:` — the paths a
90
+ * defaults pass may write to, and therefore exactly how far the caller's inputs
91
+ * must be copied before AJV's `useDefaults` runs. A flat shallow copy would not
92
+ * do: `useDefaults` writes at every level it finds a default, so a nested
93
+ * default would mutate the structure the caller still holds. Bounded by the
94
+ * schema's defaults rather than by the size of the payload. */
95
+ export declare function defaultBearingPaths(schema: Record<string, any>,
96
+ /** See {@link withStreamPropertiesSkipped} — a contract kept in `$ref` form
97
+ * declares its defaults behind the reference, and a walk that cannot follow
98
+ * it would report none, leaving the caller's data shared where a fill lands. */
99
+ resolveRef?: (ref: string) => Record<string, any> | undefined): string[][];
100
+ //# sourceMappingURL=invocation-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invocation-contract.d.ts","sourceRoot":"","sources":["../src/invocation-contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,WAAW,EAEjB,MAAM,yBAAyB,CAAC;AAGjC,YAAY,EAAE,iBAAiB,EAAE,CAAC;AAElC;;;;;;;;;;;;GAYG;AAEH;;oCAEoC;AACpC,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,MAAM,EAAE,cAAc,CAAC;IACvB;gFAC4E;IAC5E,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B;;kEAE8D;IAC9D,iBAAiB,EAAE,WAAW,CAAC;IAC/B;;;;;;;;;OASG;IACH,gBAAgB,CAAC,GAAG,EAAE,kBAAkB,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;CAC9E;AAED;;uCAEuC;AACvC,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAGnD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EACzC,UAAU,EAAE,kBAAkB,GAAG,SAAS,EAC1C,KAAK,EAAE,aAAa,GACnB,gBAAgB,GAAG,SAAS,CAa9B;AAED;;mDAEmD;AACnD,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EACzC,UAAU,EAAE,kBAAkB,GAAG,SAAS,EAC1C,KAAK,EAAE,aAAa,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAErB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;AAC3B;;;;yCAIyC;AACzC,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAC5D,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAErB;AAiGD;;;;;gEAKgE;AAChE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;AAC3B;;iFAEiF;AACjF,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAC5D,MAAM,EAAE,EAAE,CA+BZ"}
@@ -0,0 +1,208 @@
1
+ import { contractDeclarer, effectiveContractField, } from "./extends-resolution.js";
2
+ import { resolveTypeFieldToSchema } from "./validate-cel-context.js";
3
+ /** The fallback for a target that declares no contract: anything goes. Not
4
+ * `additionalProperties: false` — an undeclared contract is an absence of a
5
+ * claim, not a claim of emptiness. */
6
+ export const PERMISSIVE_CONTRACT = {
7
+ type: "object",
8
+ additionalProperties: true,
9
+ };
10
+ /**
11
+ * Resolve a dispatch target's contract, layering:
12
+ * 1. the **instance manifest's** own `inputType:` / `outputType:` — per-call-site
13
+ * narrowing, opted into simply by the kind declaring the property;
14
+ * 2. the **kind's** contract, resolved to the nearest declaration along
15
+ * `extends` (see {@link effectiveContractField} — nearest wins, no merge);
16
+ * 3. undefined — the caller decides whether that means permissive.
17
+ *
18
+ * Returns undefined rather than {@link PERMISSIVE_CONTRACT} so a caller can tell
19
+ * "declared nothing" from "declared anything", which the wiring rule and the
20
+ * `run()` guard both need.
21
+ */
22
+ export function resolveContract(direction, manifest, definition, scope) {
23
+ const own = manifest?.[direction];
24
+ if (own !== undefined && own !== null) {
25
+ const schema = resolveTypeFieldToSchema(own, scope.typeManifestsFor(definition));
26
+ if (schema)
27
+ return { schema, origin: "instance" };
28
+ }
29
+ const declared = effectiveContractField(definition, scope.resolveDefinition, direction);
30
+ if (declared === undefined || declared === null)
31
+ return undefined;
32
+ const declarer = contractDeclarer(definition, scope.resolveDefinition, direction);
33
+ const schema = resolveTypeFieldToSchema(declared, scope.typeManifestsFor(declarer));
34
+ if (!schema)
35
+ return undefined;
36
+ return { schema, origin: "kind", declaredBy: declarer };
37
+ }
38
+ /** {@link resolveContract}, falling back to {@link PERMISSIVE_CONTRACT}. For
39
+ * callers that need a schema unconditionally (CEL context typing), as opposed
40
+ * to needing to know whether one was declared. */
41
+ export function resolveContractSchema(direction, manifest, definition, scope) {
42
+ return resolveContract(direction, manifest, definition, scope)?.schema ?? PERMISSIVE_CONTRACT;
43
+ }
44
+ /**
45
+ * A copy of `schema` with every `x-telo-stream`-marked property removed from
46
+ * `properties` and `required`, for validating a runtime value against.
47
+ *
48
+ * Streams travel in BOTH directions — `Codec.Encoder` marks `input` on its
49
+ * `inputType` and lists it in `required`, and `Record.Stream`, `Ai`, `Tar` and
50
+ * `Console` do the same — so a one-directional skip would walk a live `Stream`
51
+ * with AJV on the hottest path in the runtime. That is the same defect as
52
+ * `stripCompiledValues` walking a live `ResourceInstance` in a ref slot: a live
53
+ * object in a declared slot is not data to be traversed. The annotation already
54
+ * marks exactly the properties to leave alone.
55
+ *
56
+ * Structural (returns a new object, never mutates), and shared so the analyzer
57
+ * and the kernel exempt the same set.
58
+ */
59
+ export function withStreamPropertiesSkipped(schema,
60
+ /** Resolves a `$ref` to the schema it names. Required to see through the
61
+ * reference form the runtime deliberately KEEPS intact for its validator: a
62
+ * contract written as `{ $ref: "telo:mod/Type" }` has none of its own
63
+ * properties, so a walk that cannot follow the reference exempts nothing and
64
+ * the stream is traversed after all. */
65
+ resolveRef) {
66
+ return stripStreams(schema, [], resolveRef);
67
+ }
68
+ function stripStreams(node,
69
+ // A PATH-scoped guard, not a global memo: a schema object reached twice from
70
+ // different parents must be stripped twice (a global `seen` would hand the
71
+ // second parent the unstripped original), while a cycle must still terminate.
72
+ path, resolveRef) {
73
+ if (Array.isArray(node)) {
74
+ let changed = false;
75
+ const items = node.map((item) => {
76
+ const next = stripStreams(item, path, resolveRef);
77
+ if (next !== item)
78
+ changed = true;
79
+ return next;
80
+ });
81
+ return changed ? items : node;
82
+ }
83
+ if (!node || typeof node !== "object")
84
+ return node;
85
+ let schema = node;
86
+ if (path.includes(schema))
87
+ return schema;
88
+ // Follow a whole-document reference to SEE the annotations behind it, but
89
+ // return the original node when nothing behind it was stripped. Substituting
90
+ // the resolved target unconditionally would break schema identity — the
91
+ // compiled-validator cache is keyed on it — and would move the target out of
92
+ // the document whose `$defs` its own internal `$ref`s resolve against.
93
+ if (resolveRef && typeof schema.$ref === "string") {
94
+ const target = resolveRef(schema.$ref);
95
+ if (target && !path.includes(target)) {
96
+ const stripped = stripStreams(target, [...path, schema], resolveRef);
97
+ if (stripped === target)
98
+ return node;
99
+ const { $ref: _ref, ...siblings } = schema;
100
+ return Object.keys(siblings).length > 0 ? { ...stripped, ...siblings } : stripped;
101
+ }
102
+ }
103
+ const here = [...path, schema];
104
+ let out = schema;
105
+ const properties = schema.properties;
106
+ if (properties) {
107
+ // A stream can be contributed by an `allOf` branch too (how type inheritance
108
+ // is expressed before the branches are merged), so the marked set is read
109
+ // from the folded view while the removal is applied here.
110
+ const streamed = Object.keys(properties).filter((key) => properties[key]?.["x-telo-stream"]);
111
+ if (streamed.length > 0) {
112
+ const kept = {};
113
+ for (const [key, value] of Object.entries(properties)) {
114
+ if (!streamed.includes(key))
115
+ kept[key] = value;
116
+ }
117
+ // The key stays DECLARED but unconstrained, rather than being deleted.
118
+ // Deleting it would force `additionalProperties: false` open, and a closed
119
+ // contract would stop rejecting unknown keys the moment it grew a stream —
120
+ // trading one exemption for a hole across the whole shape.
121
+ for (const key of streamed)
122
+ kept[key] = {};
123
+ out = { ...schema, properties: kept };
124
+ }
125
+ }
126
+ // Recurse: a stream one level down (an item, a branch, a nested object) is as
127
+ // live as one at the root, and walking it with AJV is the same defect.
128
+ //
129
+ // `properties` and `$defs` are MAPS of schemas, not schemas — descending into
130
+ // them as if they were would visit nothing, since a map has none of the
131
+ // keywords this walk looks for.
132
+ let changed = out !== schema;
133
+ const result = { ...out };
134
+ for (const key of ["properties", "$defs"]) {
135
+ const map = out[key];
136
+ if (!map || typeof map !== "object")
137
+ continue;
138
+ let mapChanged = false;
139
+ const next = {};
140
+ for (const [name, child] of Object.entries(map)) {
141
+ const stripped = stripStreams(child, here, resolveRef);
142
+ if (stripped !== child)
143
+ mapChanged = true;
144
+ next[name] = stripped;
145
+ }
146
+ if (mapChanged) {
147
+ result[key] = next;
148
+ changed = true;
149
+ }
150
+ }
151
+ for (const key of ["items", "allOf", "anyOf", "oneOf"]) {
152
+ const child = out[key];
153
+ if (child === undefined)
154
+ continue;
155
+ const next = stripStreams(child, here, resolveRef);
156
+ if (next !== child) {
157
+ result[key] = next;
158
+ changed = true;
159
+ }
160
+ }
161
+ return changed ? result : schema;
162
+ }
163
+ /** Every property path in `schema` that can receive a `default:` — the paths a
164
+ * defaults pass may write to, and therefore exactly how far the caller's inputs
165
+ * must be copied before AJV's `useDefaults` runs. A flat shallow copy would not
166
+ * do: `useDefaults` writes at every level it finds a default, so a nested
167
+ * default would mutate the structure the caller still holds. Bounded by the
168
+ * schema's defaults rather than by the size of the payload. */
169
+ export function defaultBearingPaths(schema,
170
+ /** See {@link withStreamPropertiesSkipped} — a contract kept in `$ref` form
171
+ * declares its defaults behind the reference, and a walk that cannot follow
172
+ * it would report none, leaving the caller's data shared where a fill lands. */
173
+ resolveRef) {
174
+ const out = [];
175
+ // Path-scoped, for the same reason as the stream walk: a shared subschema
176
+ // reached from two parents contributes a path under each.
177
+ const walk = (node, path, chain) => {
178
+ if (!node || typeof node !== "object")
179
+ return;
180
+ let s = node;
181
+ if (chain.includes(s))
182
+ return;
183
+ if (resolveRef && typeof s.$ref === "string") {
184
+ const target = resolveRef(s.$ref);
185
+ if (!target || chain.includes(target))
186
+ return;
187
+ s = { ...target, ...s, $ref: undefined };
188
+ }
189
+ const here = [...chain, node];
190
+ if ("default" in s && path.length > 0)
191
+ out.push(path);
192
+ const properties = s.properties;
193
+ if (properties) {
194
+ for (const [key, child] of Object.entries(properties))
195
+ walk(child, [...path, key], here);
196
+ }
197
+ for (const branch of ["allOf", "anyOf", "oneOf"]) {
198
+ const list = s[branch];
199
+ if (Array.isArray(list))
200
+ for (const child of list)
201
+ walk(child, path, here);
202
+ }
203
+ if (s.items)
204
+ walk(s.items, [...path, "[]"], here);
205
+ };
206
+ walk(schema, [], []);
207
+ return out;
208
+ }
@@ -30,6 +30,17 @@ export declare class Loader {
30
30
  * set-membership against a previous graph walk's modules without
31
31
  * triggering an extra source read. */
32
32
  canonicalize(url: string): string | undefined;
33
+ /** Drop every memo for `url` so the next `loadFile` reads it from the source
34
+ * chain again — the parsed file in each variant, plus every request URL that
35
+ * canonicalised to it (a module reached under several refs must not stay
36
+ * reachable through one of them).
37
+ *
38
+ * `loadFile`'s fast path assumes a file's contents do not change under a
39
+ * single Loader, which holds until something invalidates one deliberately:
40
+ * `telo check` dropping a manifest whose upstream tag has moved, and watch
41
+ * mode when it returns. Without this the only way to un-cache one file is to
42
+ * discard the whole Loader, taking every unrelated file's memo with it. */
43
+ forget(url: string): void;
33
44
  /** Read one file via the source chain and parse it into a LoadedFile.
34
45
  * The result is shared with `Loader.fileCache`. Callers that want a
35
46
  * private mutable copy must call `parseLoadedFile` directly with the
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-loader.d.ts","sourceRoot":"","sources":["../src/manifest-loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAGV,UAAU,EACV,WAAW,EACX,YAAY,EACb,MAAM,mBAAmB,CAAC;AAK3B,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AAwCpB,qBAAa,MAAM;IACjB;;;yEAGqE;IACrE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiC;IAE3D;;;;;8BAK0B;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IAEzD,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IAErC;;;;mBAIe;gBACH,OAAO,GAAE,cAAc,EAAO,EAAE,OAAO,GAAE,iBAAsB;IAK3E,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAKtC,OAAO,CAAC,IAAI;IAMN,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUrD;;;;2CAIuC;IACvC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAM7C;;;+BAG2B;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAyCvE;;;;gEAI4D;IAC5D,OAAO,CAAC,oBAAoB;IAa5B;gFAC4E;IAC5E,OAAO,CAAC,cAAc;IAQtB;;wEAEoE;IAC9D,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAsB3E;;;qCAGiC;IAC3B,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAiI9E;;;;;;;;sBAQkB;IAClB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAOlE,OAAO,CAAC,6BAA6B;IAarC,OAAO,CAAC,mCAAmC;IAc3C,OAAO,CAAC,2BAA2B;YAkCrB,eAAe;IAmB7B;;;0CAGsC;IAChC,gBAAgB,CACpB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CA0B5D"}
1
+ {"version":3,"file":"manifest-loader.d.ts","sourceRoot":"","sources":["../src/manifest-loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAGV,UAAU,EACV,WAAW,EACX,YAAY,EACb,MAAM,mBAAmB,CAAC;AAK3B,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AAwCpB,qBAAa,MAAM;IACjB;;;yEAGqE;IACrE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiC;IAE3D;;;;;8BAK0B;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IAEzD,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IAErC;;;;mBAIe;gBACH,OAAO,GAAE,cAAc,EAAO,EAAE,OAAO,GAAE,iBAAsB;IAK3E,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAKtC,OAAO,CAAC,IAAI;IAMN,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUrD;;;;2CAIuC;IACvC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI7C;;;;;;;;;gFAS4E;IAC5E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAYzB;;;+BAG2B;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAyCvE;;;;gEAI4D;IAC5D,OAAO,CAAC,oBAAoB;IAa5B;gFAC4E;IAC5E,OAAO,CAAC,cAAc;IAQtB;;wEAEoE;IAC9D,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAsB3E;;;qCAGiC;IAC3B,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAiI9E;;;;;;;;sBAQkB;IAClB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAOlE,OAAO,CAAC,6BAA6B;IAarC,OAAO,CAAC,mCAAmC;IAc3C,OAAO,CAAC,2BAA2B;YAkCrB,eAAe;IAmB7B;;;0CAGsC;IAChC,gBAAgB,CACpB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CA0B5D"}
@@ -88,6 +88,26 @@ export class Loader {
88
88
  canonicalize(url) {
89
89
  return this.urlToSource.get(url);
90
90
  }
91
+ /** Drop every memo for `url` so the next `loadFile` reads it from the source
92
+ * chain again — the parsed file in each variant, plus every request URL that
93
+ * canonicalised to it (a module reached under several refs must not stay
94
+ * reachable through one of them).
95
+ *
96
+ * `loadFile`'s fast path assumes a file's contents do not change under a
97
+ * single Loader, which holds until something invalidates one deliberately:
98
+ * `telo check` dropping a manifest whose upstream tag has moved, and watch
99
+ * mode when it returns. Without this the only way to un-cache one file is to
100
+ * discard the whole Loader, taking every unrelated file's memo with it. */
101
+ forget(url) {
102
+ const source = this.urlToSource.get(url) ?? url;
103
+ for (const [requestUrl, canonical] of this.urlToSource) {
104
+ if (canonical === source)
105
+ this.urlToSource.delete(requestUrl);
106
+ }
107
+ for (const variant of CACHE_VARIANTS) {
108
+ this.fileCache.delete(`${variant}:${source}`);
109
+ }
110
+ }
91
111
  // --- New API: returns LoadedFile / LoadedModule / LoadedGraph ----------
92
112
  /** Read one file via the source chain and parse it into a LoadedFile.
93
113
  * The result is shared with `Loader.fileCache`. Callers that want a