@telorun/analyzer 0.62.0 → 0.63.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 (146) hide show
  1. package/dist/analysis-registry.d.ts.map +1 -1
  2. package/dist/analysis-registry.js +6 -0
  3. package/dist/analyzer.d.ts +1 -1
  4. package/dist/analyzer.d.ts.map +1 -1
  5. package/dist/analyzer.js +343 -13
  6. package/dist/call-graph.d.ts.map +1 -1
  7. package/dist/call-graph.js +2 -7
  8. package/dist/flatten-for-analyzer.js +1 -1
  9. package/dist/import-resolution-diagnostics.d.ts +9 -2
  10. package/dist/import-resolution-diagnostics.d.ts.map +1 -1
  11. package/dist/import-resolution-diagnostics.js +26 -7
  12. package/dist/index.d.ts +15 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +13 -1
  15. package/dist/invocation-contract.d.ts +6 -1
  16. package/dist/invocation-contract.d.ts.map +1 -1
  17. package/dist/invocation-contract.js +27 -4
  18. package/dist/loaded-types.d.ts +12 -3
  19. package/dist/loaded-types.d.ts.map +1 -1
  20. package/dist/manifest-loader.d.ts +0 -1
  21. package/dist/manifest-loader.d.ts.map +1 -1
  22. package/dist/manifest-loader.js +62 -41
  23. package/dist/manifest-schemas.d.ts +699 -0
  24. package/dist/manifest-schemas.d.ts.map +1 -1
  25. package/dist/manifest-schemas.js +306 -14
  26. package/dist/module-compatibility.d.ts +40 -0
  27. package/dist/module-compatibility.d.ts.map +1 -0
  28. package/dist/module-compatibility.js +52 -0
  29. package/dist/ref-slot-reading.d.ts +30 -0
  30. package/dist/ref-slot-reading.d.ts.map +1 -0
  31. package/dist/ref-slot-reading.js +139 -0
  32. package/dist/referrer-rule.d.ts +67 -0
  33. package/dist/referrer-rule.d.ts.map +1 -0
  34. package/dist/referrer-rule.js +96 -0
  35. package/dist/release/index.d.ts +1 -1
  36. package/dist/release/index.d.ts.map +1 -1
  37. package/dist/release/index.js +1 -1
  38. package/dist/release/payload-digest.d.ts +7 -3
  39. package/dist/release/payload-digest.d.ts.map +1 -1
  40. package/dist/release/payload-digest.js +7 -3
  41. package/dist/release/version-stamp.d.ts +16 -0
  42. package/dist/release/version-stamp.d.ts.map +1 -1
  43. package/dist/release/version-stamp.js +52 -0
  44. package/dist/release/workspace-config.d.ts +10 -6
  45. package/dist/release/workspace-config.d.ts.map +1 -1
  46. package/dist/release/workspace-config.js +10 -6
  47. package/dist/resolve-schema-ref-kinds.d.ts +4 -3
  48. package/dist/resolve-schema-ref-kinds.d.ts.map +1 -1
  49. package/dist/resolve-schema-ref-kinds.js +16 -0
  50. package/dist/resolve-throws-union.d.ts.map +1 -1
  51. package/dist/resolve-throws-union.js +4 -3
  52. package/dist/resolve-zone-containment.d.ts +99 -0
  53. package/dist/resolve-zone-containment.d.ts.map +1 -0
  54. package/dist/resolve-zone-containment.js +212 -0
  55. package/dist/resolve-zone-requirements.d.ts +5 -0
  56. package/dist/resolve-zone-requirements.d.ts.map +1 -1
  57. package/dist/resolve-zone-requirements.js +48 -7
  58. package/dist/resource-rule.d.ts +106 -0
  59. package/dist/resource-rule.d.ts.map +1 -0
  60. package/dist/resource-rule.js +236 -0
  61. package/dist/rule-condition.d.ts +50 -0
  62. package/dist/rule-condition.d.ts.map +1 -0
  63. package/dist/rule-condition.js +108 -0
  64. package/dist/schema-keywords.d.ts.map +1 -1
  65. package/dist/schema-keywords.js +20 -0
  66. package/dist/schema-projection.d.ts +171 -0
  67. package/dist/schema-projection.d.ts.map +1 -0
  68. package/dist/schema-projection.js +317 -0
  69. package/dist/step-slot.d.ts +39 -0
  70. package/dist/step-slot.d.ts.map +1 -0
  71. package/dist/step-slot.js +49 -0
  72. package/dist/telo-version.d.ts +1 -1
  73. package/dist/telo-version.js +1 -1
  74. package/dist/validate-cel-context.d.ts.map +1 -1
  75. package/dist/validate-cel-context.js +17 -3
  76. package/dist/validate-durable-regions.d.ts +15 -0
  77. package/dist/validate-durable-regions.d.ts.map +1 -0
  78. package/dist/validate-durable-regions.js +336 -0
  79. package/dist/validate-references.d.ts.map +1 -1
  80. package/dist/validate-references.js +44 -2
  81. package/dist/validate-referrer-rules.d.ts +120 -0
  82. package/dist/validate-referrer-rules.d.ts.map +1 -0
  83. package/dist/validate-referrer-rules.js +255 -0
  84. package/dist/validate-resource-rules.d.ts +114 -0
  85. package/dist/validate-resource-rules.d.ts.map +1 -0
  86. package/dist/validate-resource-rules.js +283 -0
  87. package/dist/validate-schema-projection.d.ts +32 -0
  88. package/dist/validate-schema-projection.d.ts.map +1 -0
  89. package/dist/validate-schema-projection.js +110 -0
  90. package/dist/validate-step-inputs.d.ts +2 -1
  91. package/dist/validate-step-inputs.d.ts.map +1 -1
  92. package/dist/validate-step-inputs.js +5 -3
  93. package/dist/validate-throws-coverage.d.ts.map +1 -1
  94. package/dist/validate-throws-coverage.js +11 -5
  95. package/dist/validate-zone-slots.d.ts +2 -2
  96. package/dist/validate-zone-slots.d.ts.map +1 -1
  97. package/dist/validate-zone-slots.js +202 -6
  98. package/dist/validate-zone-violations.d.ts +12 -0
  99. package/dist/validate-zone-violations.d.ts.map +1 -0
  100. package/dist/validate-zone-violations.js +169 -0
  101. package/dist/value-type-keyword.d.ts +1 -1
  102. package/dist/value-type-keyword.d.ts.map +1 -1
  103. package/dist/value-type-keyword.js +4 -0
  104. package/dist/zone-slot.d.ts +61 -0
  105. package/dist/zone-slot.d.ts.map +1 -1
  106. package/dist/zone-slot.js +86 -5
  107. package/package.json +2 -2
  108. package/src/analysis-registry.ts +6 -0
  109. package/src/analyzer.ts +395 -14
  110. package/src/call-graph.ts +2 -8
  111. package/src/flatten-for-analyzer.ts +1 -1
  112. package/src/import-resolution-diagnostics.ts +25 -7
  113. package/src/index.ts +73 -0
  114. package/src/invocation-contract.ts +45 -2
  115. package/src/loaded-types.ts +12 -3
  116. package/src/manifest-loader.ts +87 -55
  117. package/src/manifest-schemas.ts +328 -14
  118. package/src/module-compatibility.ts +72 -0
  119. package/src/ref-slot-reading.ts +156 -0
  120. package/src/referrer-rule.ts +116 -0
  121. package/src/release/index.ts +1 -0
  122. package/src/release/payload-digest.ts +7 -3
  123. package/src/release/version-stamp.ts +58 -0
  124. package/src/release/workspace-config.ts +10 -6
  125. package/src/resolve-schema-ref-kinds.ts +28 -4
  126. package/src/resolve-throws-union.ts +4 -3
  127. package/src/resolve-zone-containment.ts +329 -0
  128. package/src/resolve-zone-requirements.ts +67 -7
  129. package/src/resource-rule.ts +252 -0
  130. package/src/rule-condition.ts +126 -0
  131. package/src/schema-keywords.ts +24 -0
  132. package/src/schema-projection.ts +403 -0
  133. package/src/step-slot.ts +64 -0
  134. package/src/telo-version.ts +1 -1
  135. package/src/validate-cel-context.ts +17 -3
  136. package/src/validate-durable-regions.ts +401 -0
  137. package/src/validate-references.ts +57 -2
  138. package/src/validate-referrer-rules.ts +373 -0
  139. package/src/validate-resource-rules.ts +401 -0
  140. package/src/validate-schema-projection.ts +184 -0
  141. package/src/validate-step-inputs.ts +5 -3
  142. package/src/validate-throws-coverage.ts +12 -5
  143. package/src/validate-zone-slots.ts +192 -8
  144. package/src/validate-zone-violations.ts +190 -0
  145. package/src/value-type-keyword.ts +4 -0
  146. package/src/zone-slot.ts +114 -5
@@ -0,0 +1,317 @@
1
+ /**
2
+ * The schema-projection annotations' single reader — the `ref-slot.ts` /
3
+ * `zone-slot.ts` precedent.
4
+ *
5
+ * A kind whose configuration is a COLLECTION OF TYPED ENTRIES can say what that
6
+ * collection means as a JSON Schema object, so a consumer can type the values
7
+ * it will read without the analyzer learning anything about the domain. A SQL
8
+ * table's columns are the first consumer; nothing in either annotation says
9
+ * SQL, column or table.
10
+ *
11
+ * Two halves, because the two facts have different owners:
12
+ *
13
+ * - `x-telo-schema-map`, on the field a projection keys on, gives the schema
14
+ * node each of its values means (`citext → {type: string}`). It sits with the
15
+ * field because that is where the value vocabulary is declared.
16
+ * - `x-telo-schema-projection`, on the KIND DOCUMENT (a sibling of `schema:`,
17
+ * not a keyword inside it), names the entry collection, the keying field, and
18
+ * the fields that MODIFY the mapped node. It sits on the document because it
19
+ * describes the kind's whole declaration rather than one field of it — but
20
+ * `schema:` is where every other `x-telo-*` keyword lives, so the reader
21
+ * accepts it in both positions and `validate-schema-projection.ts` reports the
22
+ * inner one. Silently ignoring a misplaced annotation is the exact failure the
23
+ * strict half exists to prevent: the projection stops typing its consumers and
24
+ * the diagnostic lands on the CONSUMER, blaming the wrong author.
25
+ *
26
+ * It is a declared LOOKUP, never a computed expression. The analyzer
27
+ * type-checks CEL and substitutes placeholders; it never evaluates, and a
28
+ * `base:`-style mapping is evaluated by the kernel at `create()` — too late for
29
+ * `telo check` to type the rows a consumer reads, which is the projection's
30
+ * whole purpose.
31
+ *
32
+ * Distinct from `x-telo-schema-from`, which derives a field's schema from a
33
+ * referenced KIND's definition schema. A projection is DECLARATION-derived: the
34
+ * row shape lives in one instance's own `columns:`, which no definition-level
35
+ * derivation can reach.
36
+ */
37
+ function isObject(value) {
38
+ return !!value && typeof value === "object" && !Array.isArray(value);
39
+ }
40
+ /** The projection a kind declares, or undefined. Invalid shapes read as absent;
41
+ * `validate-schema-projection.ts` is the half that reports them. */
42
+ export function readSchemaProjection(definition) {
43
+ if (!isObject(definition))
44
+ return undefined;
45
+ const raw = rawSchemaProjection(definition);
46
+ if (!isObject(raw))
47
+ return undefined;
48
+ const entries = raw.entries;
49
+ const key = raw.key;
50
+ if (typeof entries !== "string" || typeof key !== "string")
51
+ return undefined;
52
+ return {
53
+ entries,
54
+ key,
55
+ nameField: typeof raw.name === "string" ? raw.name : undefined,
56
+ nullable: typeof raw.nullable === "string" ? raw.nullable : undefined,
57
+ array: typeof raw.array === "string" ? raw.array : undefined,
58
+ };
59
+ }
60
+ /** The annotation as written, from either position — the document (canonical)
61
+ * or `schema:` (accepted, and reported by the strict half). The document wins:
62
+ * a kind spelling it in both places is describing its own document. */
63
+ export function rawSchemaProjection(definition) {
64
+ if (!isObject(definition))
65
+ return undefined;
66
+ const own = definition["x-telo-schema-projection"];
67
+ if (own !== undefined)
68
+ return own;
69
+ const schema = definition.schema;
70
+ return isObject(schema) ? schema["x-telo-schema-projection"] : undefined;
71
+ }
72
+ /** True when the annotation was found inside `schema:` rather than on the
73
+ * document — the misplacement the strict half reports. */
74
+ export function schemaProjectionIsMisplaced(definition) {
75
+ if (!isObject(definition))
76
+ return false;
77
+ if (definition["x-telo-schema-projection"] !== undefined)
78
+ return false;
79
+ const schema = definition.schema;
80
+ return isObject(schema) && schema["x-telo-schema-projection"] !== undefined;
81
+ }
82
+ export function readSchemaMap(node) {
83
+ if (!isObject(node))
84
+ return undefined;
85
+ const raw = node["x-telo-schema-map"];
86
+ if (!isObject(raw))
87
+ return undefined;
88
+ const entries = Object.entries(raw).filter(([, value]) => isObject(value));
89
+ if (entries.length === 0)
90
+ return undefined;
91
+ return Object.fromEntries(entries);
92
+ }
93
+ /** The consumer-side annotation: a JSON Pointer to this resource's ref slot
94
+ * whose target declares the projection. */
95
+ export function readProjectionFrom(node) {
96
+ if (!isObject(node))
97
+ return undefined;
98
+ const raw = node["x-telo-schema-projection-from"];
99
+ return typeof raw === "string" ? raw : undefined;
100
+ }
101
+ function navigate(root, pointer) {
102
+ let current = root;
103
+ for (const segment of pointer.split("/")) {
104
+ if (segment === "")
105
+ continue;
106
+ if (!isObject(current))
107
+ return undefined;
108
+ current = current[segment];
109
+ }
110
+ return current;
111
+ }
112
+ /**
113
+ * Find the `x-telo-schema-map` a projection keys on. The map sits on the entry
114
+ * field's schema, which is reached through the collection's own schema — a
115
+ * keyed map's `additionalProperties`, or an array's `items`.
116
+ */
117
+ export function projectionKeyMap(kindSchema, projection) {
118
+ let node = kindSchema;
119
+ for (const segment of projection.entries.split("/")) {
120
+ if (segment === "")
121
+ continue;
122
+ if (!isObject(node) || !isObject(node.properties))
123
+ return undefined;
124
+ node = node.properties[segment];
125
+ }
126
+ if (!isObject(node))
127
+ return undefined;
128
+ const entry = isObject(node.additionalProperties)
129
+ ? node.additionalProperties
130
+ : isObject(node.items)
131
+ ? node.items
132
+ : undefined;
133
+ if (!isObject(entry) || !isObject(entry.properties))
134
+ return undefined;
135
+ return readSchemaMap(entry.properties[projection.key]);
136
+ }
137
+ /**
138
+ * Project one declaration to an object schema.
139
+ *
140
+ * Modifiers are a CLOSED set applied in a FIXED order — `array` wraps, then
141
+ * `nullable` widens. Closed because each changes how the schema is assembled,
142
+ * so a third-party modifier would be a name nothing acts on; ordered because
143
+ * leaving it implicit is how two implementations come to disagree.
144
+ *
145
+ * The projection is deliberately LOSSY. Length, precision, collation and check
146
+ * constraints do not reach it: a consumer needs the type, its nullability and
147
+ * its repetition, and the database enforces the rest. A per-entry schema rich
148
+ * enough to double as a validator would move the domain's semantics into the
149
+ * type layer.
150
+ */
151
+ export function projectEntries(manifest, projection, map) {
152
+ const entries = navigate(manifest, projection.entries);
153
+ if (entries === undefined)
154
+ return undefined;
155
+ const pairs = [];
156
+ const consider = (name, entry) => {
157
+ if (!isObject(entry) || name === undefined)
158
+ return;
159
+ const key = entry[projection.key];
160
+ const mapped = typeof key === "string" ? map[key] : undefined;
161
+ // A value with no map entry projects to nothing rather than to `any`: the
162
+ // vocabulary is the kind's own enum, so an unmapped value is a gap in the
163
+ // kind's declaration, not a shape to guess at.
164
+ if (!mapped)
165
+ return;
166
+ let node = { ...mapped };
167
+ if (projection.array && entry[projection.array] === true) {
168
+ node = { type: "array", items: node };
169
+ }
170
+ if (projection.nullable && entry[projection.nullable] !== false) {
171
+ node = { anyOf: [node, { type: "null" }] };
172
+ }
173
+ pairs.push([name, node]);
174
+ };
175
+ if (Array.isArray(entries)) {
176
+ for (const entry of entries) {
177
+ const name = isObject(entry) && projection.nameField
178
+ ? entry[projection.nameField]
179
+ : undefined;
180
+ consider(name, entry);
181
+ }
182
+ }
183
+ else if (isObject(entries)) {
184
+ for (const [name, entry] of Object.entries(entries))
185
+ consider(name, entry);
186
+ }
187
+ else {
188
+ return undefined;
189
+ }
190
+ return {
191
+ type: "object",
192
+ properties: Object.fromEntries(pairs),
193
+ additionalProperties: false,
194
+ };
195
+ }
196
+ /** The `{kind, name, alias?}` reference a value holds, or undefined. Exported so
197
+ * a host whose slot may hold EITHER shape can fall back to this reading. */
198
+ export function readProjectionRef(value) {
199
+ if (!isObject(value))
200
+ return undefined;
201
+ const name = value.name;
202
+ if (typeof name !== "string")
203
+ return undefined;
204
+ return {
205
+ name,
206
+ kind: typeof value.kind === "string" ? value.kind : undefined,
207
+ alias: typeof value.alias === "string" ? value.alias : undefined,
208
+ };
209
+ }
210
+ /**
211
+ * The resolver for a FLATTENED manifest list — the analyzer's own shape.
212
+ *
213
+ * An alias narrows to the manifests forwarded from that import (stamped
214
+ * `metadata.alias` by flatten), so two libraries each exporting a `users` table
215
+ * stay distinguishable. Only when nothing carries the alias does it fall back to
216
+ * matching by name alone, which is the pre-flatten shape a standalone module
217
+ * analysis has.
218
+ */
219
+ export function manifestListScope(manifests, resolveDefinition) {
220
+ return {
221
+ resolveDefinition,
222
+ resolveManifest(value) {
223
+ const ref = readProjectionRef(value);
224
+ if (!ref)
225
+ return undefined;
226
+ const byName = manifests.filter((candidate) => candidate?.metadata?.name === ref.name &&
227
+ (typeof ref.kind !== "string" || candidate.kind === ref.kind));
228
+ const aliased = ref.alias && ref.alias !== "Self"
229
+ ? byName.filter((candidate) => candidate?.metadata?.alias === ref.alias)
230
+ : byName;
231
+ // A name that matches SEVERAL manifests is REFUSED rather than resolved to
232
+ // the first: picking one by flatten order would type the consumer's rows
233
+ // against the wrong declaration — a wrong answer, which is worse than no
234
+ // answer. Reported, so the author is told to disambiguate.
235
+ const matches = aliased.length > 0 ? aliased : byName;
236
+ if (matches.length === 0)
237
+ return undefined;
238
+ if (matches.length > 1)
239
+ return { ambiguous: true };
240
+ return { manifest: matches[0] };
241
+ },
242
+ };
243
+ }
244
+ function refTarget(value, scope, pointer) {
245
+ if (!isObject(value))
246
+ return { reason: "no-ref", pointer };
247
+ const name = typeof value.name === "string" ? value.name : "<unnamed>";
248
+ const found = scope.resolveManifest(value);
249
+ if (!found)
250
+ return { reason: "unresolved", pointer, name };
251
+ if ("ambiguous" in found)
252
+ return { reason: "ambiguous", pointer, name };
253
+ const manifest = found.manifest;
254
+ if (typeof manifest.kind !== "string")
255
+ return { reason: "unresolved", pointer, name };
256
+ const definition = scope.resolveDefinition(manifest.kind);
257
+ if (!definition)
258
+ return { reason: "no-projection", pointer, kind: manifest.kind };
259
+ return { manifest, definition };
260
+ }
261
+ export function describeProjectionFailure(failure) {
262
+ switch (failure.reason) {
263
+ case "no-ref":
264
+ return `'${failure.pointer}' does not hold a reference, so there is no declaration to project.`;
265
+ case "unresolved":
266
+ return `'${failure.pointer}' references '${failure.name}', which resolves to no resource.`;
267
+ case "ambiguous":
268
+ return (`'${failure.pointer}' references '${failure.name}', which matches more than one resource ` +
269
+ `in scope. Rename one of them so the reference names exactly one declaration.`);
270
+ case "no-projection":
271
+ return (`'${failure.pointer}' references a resource of kind '${failure.kind}', which declares no ` +
272
+ `'x-telo-schema-projection' — so there is nothing for this slot to be typed from.`);
273
+ }
274
+ }
275
+ /**
276
+ * Replace every `x-telo-schema-projection-from` node with the projection of the
277
+ * declaration it points at.
278
+ *
279
+ * Structural: returns a new schema and never mutates the one handed in. A node
280
+ * that cannot be projected is left exactly as it was — degrading to the slot's
281
+ * own schema rather than to a wrong one — and the reason is pushed to
282
+ * `failures`, because degrading SILENTLY is the failure this whole mechanism
283
+ * exists to move earlier: the consumer's contract quietly reopens and a
284
+ * misspelled field passes `telo check` exactly as it did before.
285
+ */
286
+ export function resolveSchemaProjections(schema, manifest, scope, failures) {
287
+ if (Array.isArray(schema)) {
288
+ return schema.map((item) => resolveSchemaProjections(item, manifest, scope, failures));
289
+ }
290
+ if (!isObject(schema))
291
+ return schema;
292
+ const pointer = readProjectionFrom(schema);
293
+ if (pointer && manifest) {
294
+ const target = refTarget(navigate(manifest, pointer), scope, pointer);
295
+ if ("reason" in target) {
296
+ failures?.push(target);
297
+ }
298
+ else {
299
+ const projection = readSchemaProjection(target.definition);
300
+ const map = projection && projectionKeyMap(target.definition.schema, projection);
301
+ const projected = projection && map ? projectEntries(target.manifest, projection, map) : undefined;
302
+ if (projected) {
303
+ const { ["x-telo-schema-projection-from"]: _dropped, ...rest } = schema;
304
+ return { ...rest, ...projected };
305
+ }
306
+ failures?.push({
307
+ reason: "no-projection",
308
+ pointer,
309
+ kind: String(target.manifest.kind ?? "<unknown>"),
310
+ });
311
+ }
312
+ }
313
+ return Object.fromEntries(Object.entries(schema).map(([key, value]) => [
314
+ key,
315
+ key.startsWith("x-telo-") ? value : resolveSchemaProjections(value, manifest, scope, failures),
316
+ ]));
317
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * "Does this array hold steps, and where does a step keep what the analyzer
3
+ * reads?" — one accessor, the `ref-slot.ts` / `zone-slot.ts` precedent.
4
+ *
5
+ * TWO SPELLINGS, one answer. A kind declares a step body by pointing its items
6
+ * at the shared grammar (`$ref: "telo://manifest#/$defs/Step"`), which fragment
7
+ * expansion stamps `x-telo-fragment: Step`; the field names are then constants
8
+ * of that grammar and nothing states them. Before the fragment existed the shape
9
+ * was each kind's own, so the kind had to say where its dispatch ref, output
10
+ * type and pure-value fields lived — `x-telo-step-context`. That annotation
11
+ * stays READ, permanently: published artifacts carry it and no migration entry
12
+ * can synthesize a `$ref` (the patch vocabulary writes scalars), so it has the
13
+ * standing of the legacy `x-telo-ref` string form.
14
+ *
15
+ * The annotation WINS where both are present. A kind that spells its own shape
16
+ * is describing its own manifest, and a stamp says only which grammar the items
17
+ * point at.
18
+ *
19
+ * Browser-safe: no Node built-ins.
20
+ */
21
+ /** The name a step-bearing array's items carry once expanded. */
22
+ export declare const STEP_FRAGMENT = "Step";
23
+ /** Where a step keeps what the analyzer reads. */
24
+ export interface StepSlot {
25
+ /** Field on a step naming the resource to dispatch. */
26
+ invoke: string;
27
+ /** Field on the INVOKED resource's manifest that narrows its result type.
28
+ * Absent for a composer that allows no per-instance narrowing. */
29
+ outputType?: string;
30
+ /** Field that produces a result without dispatching. Only a grammar with pure
31
+ * steps has one. */
32
+ value?: string;
33
+ }
34
+ /** The step slot an array property declares, or undefined when it holds no
35
+ * steps. `fieldSchema` is the ARRAY's schema — the stamp sits on its `items`. */
36
+ export declare function readStepSlot(fieldSchema: unknown): StepSlot | undefined;
37
+ /** True when the property holds a step body. */
38
+ export declare function isStepSlot(fieldSchema: unknown): boolean;
39
+ //# sourceMappingURL=step-slot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-slot.d.ts","sourceRoot":"","sources":["../src/step-slot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,iEAAiE;AACjE,eAAO,MAAM,aAAa,SAAS,CAAC;AAEpC,kDAAkD;AAClD,MAAM,WAAW,QAAQ;IACvB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf;uEACmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;yBACqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD;kFACkF;AAClF,wBAAgB,YAAY,CAAC,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CAcvE;AAED,gDAAgD;AAChD,wBAAgB,UAAU,CAAC,WAAW,EAAE,OAAO,GAAG,OAAO,CAExD"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * "Does this array hold steps, and where does a step keep what the analyzer
3
+ * reads?" — one accessor, the `ref-slot.ts` / `zone-slot.ts` precedent.
4
+ *
5
+ * TWO SPELLINGS, one answer. A kind declares a step body by pointing its items
6
+ * at the shared grammar (`$ref: "telo://manifest#/$defs/Step"`), which fragment
7
+ * expansion stamps `x-telo-fragment: Step`; the field names are then constants
8
+ * of that grammar and nothing states them. Before the fragment existed the shape
9
+ * was each kind's own, so the kind had to say where its dispatch ref, output
10
+ * type and pure-value fields lived — `x-telo-step-context`. That annotation
11
+ * stays READ, permanently: published artifacts carry it and no migration entry
12
+ * can synthesize a `$ref` (the patch vocabulary writes scalars), so it has the
13
+ * standing of the legacy `x-telo-ref` string form.
14
+ *
15
+ * The annotation WINS where both are present. A kind that spells its own shape
16
+ * is describing its own manifest, and a stamp says only which grammar the items
17
+ * point at.
18
+ *
19
+ * Browser-safe: no Node built-ins.
20
+ */
21
+ import { manifestFragmentOf } from "./manifest-schemas.js";
22
+ /** The name a step-bearing array's items carry once expanded. */
23
+ export const STEP_FRAGMENT = "Step";
24
+ /** The shared grammar's own field names — constants, since the shape is no
25
+ * longer the kind's to choose. */
26
+ const STEP_FRAGMENT_SLOT = { invoke: "invoke", outputType: "outputType", value: "value" };
27
+ /** The step slot an array property declares, or undefined when it holds no
28
+ * steps. `fieldSchema` is the ARRAY's schema — the stamp sits on its `items`. */
29
+ export function readStepSlot(fieldSchema) {
30
+ if (!fieldSchema || typeof fieldSchema !== "object")
31
+ return undefined;
32
+ const declared = fieldSchema["x-telo-step-context"];
33
+ if (declared && typeof declared === "object") {
34
+ const { invoke, outputType, value } = declared;
35
+ if (typeof invoke !== "string" || invoke.length === 0)
36
+ return undefined;
37
+ return {
38
+ invoke,
39
+ ...(typeof outputType === "string" ? { outputType } : {}),
40
+ ...(typeof value === "string" ? { value } : {}),
41
+ };
42
+ }
43
+ const items = fieldSchema.items;
44
+ return manifestFragmentOf(items) === STEP_FRAGMENT ? STEP_FRAGMENT_SLOT : undefined;
45
+ }
46
+ /** True when the property holds a step body. */
47
+ export function isStepSlot(fieldSchema) {
48
+ return readStepSlot(fieldSchema) !== undefined;
49
+ }
@@ -1,3 +1,3 @@
1
1
  /** The surface generation this analyzer implements. */
2
- export declare const TELO_SURFACE_VERSION = "0.77.0";
2
+ export declare const TELO_SURFACE_VERSION = "0.79.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.77.0";
8
+ export const TELO_SURFACE_VERSION = "0.79.0";
@@ -1 +1 @@
1
- {"version":3,"file":"validate-cel-context.d.ts","sourceRoot":"","sources":["../src/validate-cel-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAStF,MAAM,WAAW,kBAAkB;IACjC;mEAC+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC;;kDAE8C;IAC9C,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;KACxD,CAAC;IACF,OAAO,CAAC,EAAE;QACR,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;KAC/C,CAAC;IACF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;CACtC;AA4CD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EACnC,QAAQ,GAAE,WAAW,CAAC,MAAM,CAAa,GACxC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CA0EjC;AAyID;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAoBzE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACjC,IAAI,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAChD,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA+JrB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAQrB;AAWD;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,SAAM,GACT,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,CAAC,CAGvD;AAUD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,SAAM,GAAG,MAAM,EAAE,CAqBxF"}
1
+ {"version":3,"file":"validate-cel-context.d.ts","sourceRoot":"","sources":["../src/validate-cel-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAWtF,MAAM,WAAW,kBAAkB;IACjC;mEAC+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC;;kDAE8C;IAC9C,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;KACxD,CAAC;IACF,OAAO,CAAC,EAAE;QACR,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;KAC/C,CAAC;IACF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;CACtC;AA4CD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EACnC,QAAQ,GAAE,WAAW,CAAC,MAAM,CAAa,GACxC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CA0EjC;AAyID;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAoBzE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACjC,IAAI,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAChD,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAyKrB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAQrB;AAWD;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,SAAM,GACT,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,CAAC,CAGvD;AAYD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,SAAM,GAAG,MAAM,EAAE,CAqBxF"}
@@ -1,6 +1,8 @@
1
1
  export { extractAccessChains, validateChainAgainstSchema } from "@telorun/templating";
2
2
  import { elementSchemaOf, isLiveSlot, mergeTypeSchemas, parseCanonicalTypeSchemaId, } from "@telorun/sdk";
3
3
  import { KERNEL_BUILTINS } from "./builtins.js";
4
+ import { isStepSlot } from "./step-slot.js";
5
+ import { withRefSlotsAsReadings } from "./ref-slot-reading.js";
4
6
  /**
5
7
  * Resolve a type field value (string name, inline type, or raw schema) to a JSON Schema.
6
8
  * - String: look up the named type in allManifests (Type.JsonSchema resources)
@@ -367,7 +369,17 @@ export function resolveContextAnnotations(schema, manifestItem, opts) {
367
369
  // so the variable is typed by the CONTRACT rather than by the wrapper
368
370
  // around it. A raw JSON Schema resolves to itself, and a plain property
369
371
  // map (a transport scope) resolves to nothing and is used verbatim.
370
- return resolveTypeFieldToSchema(navigated, allManifests ?? []) ?? navigated;
372
+ const resolved = resolveTypeFieldToSchema(navigated, allManifests ?? []) ?? navigated;
373
+ // A ref slot inside it holds a live instance at runtime, which the
374
+ // kernel substitutes with that resource's published reading before
375
+ // evaluating (`celSelfView`). Type it the same way, or `self.<ref>` is
376
+ // the annotation node — a shape nothing can be read off.
377
+ return defs
378
+ ? withRefSlotsAsReadings(resolved, {
379
+ resolve: (kind) => defs.resolve(kind),
380
+ resolveKind: (kind) => aliases?.resolveKind(kind),
381
+ })
382
+ : resolved;
371
383
  }
372
384
  }
373
385
  if (defs) {
@@ -485,7 +497,9 @@ export function extractContextsFromSchema(schema, path = "$") {
485
497
  return all.sort((a, b) => b.scope.length - a.scope.length);
486
498
  }
487
499
  /** Schema keys that declare a CEL-bearing region: a field carrying any of these
488
- * is evaluated at runtime, so a `!cel` inside it (or a descendant) is live. */
500
+ * is evaluated at runtime, so a `!cel` inside it (or a descendant) is live. A
501
+ * STEP BODY is one too, and says so through the grammar its items point at
502
+ * rather than through a key — {@link isStepSlot} reads either spelling. */
489
503
  const CEL_REGION_KEYS = [
490
504
  "x-telo-context",
491
505
  "x-telo-step-context",
@@ -503,7 +517,7 @@ export function extractCelRegionScopes(schema, path = "$") {
503
517
  if (!schema || typeof schema !== "object")
504
518
  return [];
505
519
  const out = [];
506
- if (CEL_REGION_KEYS.some((k) => schema[k]))
520
+ if (CEL_REGION_KEYS.some((k) => schema[k]) || isStepSlot(schema))
507
521
  out.push(path);
508
522
  if (schema.properties) {
509
523
  for (const [key, value] of Object.entries(schema.properties)) {
@@ -0,0 +1,15 @@
1
+ import type { CallGraph } from "./call-graph.js";
2
+ import { type AnalysisDiagnostic } from "./types.js";
3
+ import { type DefinitionLookup, type ZoneRegion } from "./resolve-zone-containment.js";
4
+ export interface DurableRegionArgs {
5
+ graph: CallGraph;
6
+ resolveDef: DefinitionLookup;
7
+ /** Only report against modules the entry owns — a published dependency's body
8
+ * is not the consumer's to fix, the `X_TELO_REF_UNRESOLVED` precedent. */
9
+ reportModules: ReadonlySet<string>;
10
+ }
11
+ /** Every durable-region diagnostic, over one graph. */
12
+ export declare function validateDurableRegions(args: DurableRegionArgs): AnalysisDiagnostic[];
13
+ /** Re-exported so a consumer can name a region without importing two files. */
14
+ export type { ZoneRegion };
15
+ //# sourceMappingURL=validate-durable-regions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-durable-regions.d.ts","sourceRoot":"","sources":["../src/validate-durable-regions.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,SAAS,EAAgC,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAChB,MAAM,+BAA+B,CAAC;AAsVvC,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,EAAE,gBAAgB,CAAC;IAC7B;+EAC2E;IAC3E,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACpC;AAED,uDAAuD;AACvD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,iBAAiB,GAAG,kBAAkB,EAAE,CAkBpF;AAED,+EAA+E;AAC/E,YAAY,EAAE,UAAU,EAAE,CAAC"}