@8lines/gauntlet-protocol 0.1.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 (91) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +265 -0
  3. package/dist/environment.d.ts +3 -0
  4. package/dist/environment.d.ts.map +1 -0
  5. package/dist/environment.js +32 -0
  6. package/dist/environment.js.map +1 -0
  7. package/dist/identifiers.d.ts +4 -0
  8. package/dist/identifiers.d.ts.map +1 -0
  9. package/dist/identifiers.js +5 -0
  10. package/dist/identifiers.js.map +1 -0
  11. package/dist/index.d.ts +8 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +8 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/placements.d.ts +5 -0
  16. package/dist/placements.d.ts.map +1 -0
  17. package/dist/placements.js +99 -0
  18. package/dist/placements.js.map +1 -0
  19. package/dist/portable-pattern.d.ts +2 -0
  20. package/dist/portable-pattern.d.ts.map +1 -0
  21. package/dist/portable-pattern.js +450 -0
  22. package/dist/portable-pattern.js.map +1 -0
  23. package/dist/preset-secrets.d.ts +7 -0
  24. package/dist/preset-secrets.d.ts.map +1 -0
  25. package/dist/preset-secrets.js +694 -0
  26. package/dist/preset-secrets.js.map +1 -0
  27. package/dist/revision.d.ts +11 -0
  28. package/dist/revision.d.ts.map +1 -0
  29. package/dist/revision.js +135 -0
  30. package/dist/revision.js.map +1 -0
  31. package/dist/schema-profile.d.ts +5 -0
  32. package/dist/schema-profile.d.ts.map +1 -0
  33. package/dist/schema-profile.js +295 -0
  34. package/dist/schema-profile.js.map +1 -0
  35. package/dist/semantic-validation.d.ts +24 -0
  36. package/dist/semantic-validation.d.ts.map +1 -0
  37. package/dist/semantic-validation.js +321 -0
  38. package/dist/semantic-validation.js.map +1 -0
  39. package/dist/types.d.ts +437 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +2 -0
  42. package/dist/types.js.map +1 -0
  43. package/fixtures/v1/adapter-semantic-vectors.json +3257 -0
  44. package/fixtures/v1/adapter-semantic-vectors.schema.json +519 -0
  45. package/fixtures/v1/create-run-request.valid.json +33 -0
  46. package/fixtures/v1/data-source-page.valid.json +18 -0
  47. package/fixtures/v1/data-source-query.valid.json +12 -0
  48. package/fixtures/v1/data-source-resolve-request.valid.json +10 -0
  49. package/fixtures/v1/data-source-resolve-response.valid.json +17 -0
  50. package/fixtures/v1/health.valid.json +4 -0
  51. package/fixtures/v1/jcs-revision-vectors.json +114 -0
  52. package/fixtures/v1/manifest.invalid-major-version.json +18 -0
  53. package/fixtures/v1/manifest.invalid-unknown-property.json +27 -0
  54. package/fixtures/v1/manifest.minor-forward.valid.json +142 -0
  55. package/fixtures/v1/manifest.valid.json +137 -0
  56. package/fixtures/v1/operation.invalid-remote-ref.json +28 -0
  57. package/fixtures/v1/operation.invalid-schema-profile.json +28 -0
  58. package/fixtures/v1/operation.invalid-unsafe-id.json +28 -0
  59. package/fixtures/v1/operation.valid.json +227 -0
  60. package/fixtures/v1/problem.unsupported-capability.valid.json +7 -0
  61. package/fixtures/v1/problem.valid.json +8 -0
  62. package/fixtures/v1/problem.validation.valid.json +16 -0
  63. package/fixtures/v1/run-event.valid.json +21 -0
  64. package/fixtures/v1/run.cancelled.valid.json +17 -0
  65. package/fixtures/v1/run.failed.valid.json +32 -0
  66. package/fixtures/v1/run.invalid-active-problem.json +16 -0
  67. package/fixtures/v1/run.invalid-cancelled-problem.json +17 -0
  68. package/fixtures/v1/run.invalid-terminal-without-problem.json +12 -0
  69. package/fixtures/v1/run.invalid-timed-out-status.json +18 -0
  70. package/fixtures/v1/run.queued.valid.json +15 -0
  71. package/fixtures/v1/run.succeeded.valid.json +68 -0
  72. package/fixtures/v1/run.timed-out.valid.json +18 -0
  73. package/fixtures/v1/session-launch.valid.json +5 -0
  74. package/fixtures/v1/tc-schema-core-pattern-vectors.json +450 -0
  75. package/fixtures/v1/upload-response.valid.json +11 -0
  76. package/openapi/adapter-v1.yaml +251 -0
  77. package/package.json +41 -0
  78. package/schemas/v1/common.schema.json +558 -0
  79. package/schemas/v1/create-run-request.schema.json +16 -0
  80. package/schemas/v1/data-source-page.schema.json +15 -0
  81. package/schemas/v1/data-source-query.schema.json +14 -0
  82. package/schemas/v1/data-source-resolve-request.schema.json +16 -0
  83. package/schemas/v1/data-source-resolve-response.schema.json +27 -0
  84. package/schemas/v1/health.schema.json +12 -0
  85. package/schemas/v1/manifest.schema.json +147 -0
  86. package/schemas/v1/operation-definition.schema.json +326 -0
  87. package/schemas/v1/problem.schema.json +5 -0
  88. package/schemas/v1/run-event.schema.json +15 -0
  89. package/schemas/v1/run.schema.json +95 -0
  90. package/schemas/v1/session-launch.schema.json +13 -0
  91. package/schemas/v1/upload.schema.json +11 -0
@@ -0,0 +1,694 @@
1
+ const DYNAMIC_INSTANCE_KEYWORDS = [
2
+ "contains",
3
+ "additionalProperties",
4
+ "propertyNames",
5
+ "unevaluatedItems",
6
+ "unevaluatedProperties",
7
+ "contentSchema",
8
+ ];
9
+ const SAME_INSTANCE_ARRAY_KEYWORDS = ["allOf", "anyOf", "oneOf"];
10
+ const SAME_INSTANCE_KEYWORDS = ["not", "if", "then", "else"];
11
+ const MAX_GRAPH_NODES = 250_000;
12
+ const MAX_GRAPH_EDGES = 500_000;
13
+ const MAX_PRESET_VISITS = 500_000;
14
+ function asRecord(value) {
15
+ return value !== null && typeof value === "object" && !Array.isArray(value)
16
+ ? value
17
+ : undefined;
18
+ }
19
+ function asSchemaNode(value) {
20
+ if (typeof value === "boolean")
21
+ return value;
22
+ return asRecord(value);
23
+ }
24
+ function decodePointer(pointer) {
25
+ if (pointer === "")
26
+ return [];
27
+ if (!pointer.startsWith("/"))
28
+ return undefined;
29
+ const segments = [];
30
+ for (const encoded of pointer.slice(1).split("/")) {
31
+ if (/~(?:[^01]|$)/.test(encoded))
32
+ return undefined;
33
+ segments.push(encoded.replaceAll("~1", "/").replaceAll("~0", "~"));
34
+ }
35
+ return segments;
36
+ }
37
+ function pointerFor(segments) {
38
+ return segments.length === 0
39
+ ? ""
40
+ : `/${segments.map((segment) => segment.replaceAll("~", "~0").replaceAll("/", "~1")).join("/")}`;
41
+ }
42
+ function childPointer(parent, segment) {
43
+ return `${parent}/${segment.replaceAll("~", "~0").replaceAll("/", "~1")}`;
44
+ }
45
+ function resolveSchemaPointer(rootSchema, pointer) {
46
+ const segments = decodePointer(pointer);
47
+ if (segments === undefined)
48
+ return undefined;
49
+ let current = rootSchema;
50
+ for (const segment of segments) {
51
+ if (current === null || typeof current !== "object" || !Object.hasOwn(current, segment)) {
52
+ return undefined;
53
+ }
54
+ current = current[segment];
55
+ }
56
+ const schema = asSchemaNode(current);
57
+ return schema === undefined ? undefined : { pointer: pointerFor(segments), schema };
58
+ }
59
+ function resolveLocalReference(rootSchema, reference) {
60
+ if (!reference.startsWith("#"))
61
+ return undefined;
62
+ let pointer;
63
+ try {
64
+ pointer = decodeURIComponent(reference.slice(1));
65
+ }
66
+ catch {
67
+ return undefined;
68
+ }
69
+ return resolveSchemaPointer(rootSchema, pointer);
70
+ }
71
+ function appendTransition(transitions, key, target) {
72
+ const targets = transitions.get(key);
73
+ if (targets === undefined) {
74
+ transitions.set(key, [target]);
75
+ }
76
+ else {
77
+ targets.push(target);
78
+ }
79
+ }
80
+ function appendIndexedTransition(transitions, key, target) {
81
+ const targets = transitions.get(key);
82
+ if (targets === undefined) {
83
+ transitions.set(key, [target]);
84
+ }
85
+ else {
86
+ targets.push(target);
87
+ }
88
+ }
89
+ function buildInstanceRouteGraph(rootSchema) {
90
+ const nodes = [];
91
+ const nodesByPointer = new Map();
92
+ let edgeCount = 0;
93
+ let valid = true;
94
+ const ensureNode = (resolved) => {
95
+ const existing = nodesByPointer.get(resolved.pointer);
96
+ if (existing !== undefined)
97
+ return existing;
98
+ const node = {
99
+ ...resolved,
100
+ id: nodes.length,
101
+ edges: [],
102
+ sameInstance: [],
103
+ properties: new Map(),
104
+ dependentSchemas: new Map(),
105
+ arrayIndices: new Map(),
106
+ arrayTails: new Map(),
107
+ };
108
+ nodes.push(node);
109
+ nodesByPointer.set(node.pointer, node);
110
+ if (nodes.length > MAX_GRAPH_NODES)
111
+ valid = false;
112
+ return node;
113
+ };
114
+ const addEdge = (source, resolved, dynamic) => {
115
+ const target = ensureNode(resolved);
116
+ source.edges.push({ target: target.id, dynamic });
117
+ edgeCount += 1;
118
+ if (edgeCount > MAX_GRAPH_EDGES)
119
+ valid = false;
120
+ return target;
121
+ };
122
+ ensureNode({ pointer: "", schema: rootSchema });
123
+ for (let cursor = 0; cursor < nodes.length && valid; cursor += 1) {
124
+ const node = nodes[cursor];
125
+ const { pointer: schemaPointer, schema } = node;
126
+ if (typeof schema === "boolean")
127
+ continue;
128
+ if (typeof schema.$ref === "string") {
129
+ const referenced = resolveLocalReference(rootSchema, schema.$ref);
130
+ if (referenced === undefined) {
131
+ valid = false;
132
+ }
133
+ else {
134
+ node.sameInstance.push(addEdge(node, referenced, false).id);
135
+ }
136
+ }
137
+ const properties = asRecord(schema.properties);
138
+ if (properties !== undefined) {
139
+ for (const [property, child] of Object.entries(properties)) {
140
+ const childSchema = asSchemaNode(child);
141
+ if (childSchema === undefined)
142
+ continue;
143
+ const resolved = {
144
+ pointer: childPointer(childPointer(schemaPointer, "properties"), property),
145
+ schema: childSchema,
146
+ };
147
+ appendTransition(node.properties, property, addEdge(node, resolved, false).id);
148
+ }
149
+ }
150
+ const dependentSchemas = asRecord(schema.dependentSchemas);
151
+ if (dependentSchemas !== undefined) {
152
+ for (const [property, child] of Object.entries(dependentSchemas)) {
153
+ const childSchema = asSchemaNode(child);
154
+ if (childSchema === undefined)
155
+ continue;
156
+ const resolved = {
157
+ pointer: childPointer(childPointer(schemaPointer, "dependentSchemas"), property),
158
+ schema: childSchema,
159
+ };
160
+ appendTransition(node.dependentSchemas, property, addEdge(node, resolved, false).id);
161
+ }
162
+ }
163
+ for (const keyword of SAME_INSTANCE_ARRAY_KEYWORDS) {
164
+ const children = schema[keyword];
165
+ if (!Array.isArray(children))
166
+ continue;
167
+ children.forEach((child, index) => {
168
+ const childSchema = asSchemaNode(child);
169
+ if (childSchema === undefined)
170
+ return;
171
+ const resolved = {
172
+ pointer: childPointer(childPointer(schemaPointer, keyword), String(index)),
173
+ schema: childSchema,
174
+ };
175
+ node.sameInstance.push(addEdge(node, resolved, false).id);
176
+ });
177
+ }
178
+ for (const keyword of SAME_INSTANCE_KEYWORDS) {
179
+ const childSchema = asSchemaNode(schema[keyword]);
180
+ if (childSchema === undefined)
181
+ continue;
182
+ const resolved = {
183
+ pointer: childPointer(schemaPointer, keyword),
184
+ schema: childSchema,
185
+ };
186
+ node.sameInstance.push(addEdge(node, resolved, false).id);
187
+ }
188
+ const prefixItems = Array.isArray(schema.prefixItems) ? schema.prefixItems : [];
189
+ prefixItems.forEach((child, index) => {
190
+ const childSchema = asSchemaNode(child);
191
+ if (childSchema === undefined)
192
+ return;
193
+ const resolved = {
194
+ pointer: childPointer(childPointer(schemaPointer, "prefixItems"), String(index)),
195
+ schema: childSchema,
196
+ };
197
+ appendIndexedTransition(node.arrayIndices, index, addEdge(node, resolved, false).id);
198
+ });
199
+ const items = asSchemaNode(schema.items);
200
+ if (items !== undefined) {
201
+ const resolved = { pointer: childPointer(schemaPointer, "items"), schema: items };
202
+ appendIndexedTransition(node.arrayTails, prefixItems.length, addEdge(node, resolved, false).id);
203
+ }
204
+ const patternProperties = asRecord(schema.patternProperties);
205
+ if (patternProperties !== undefined) {
206
+ for (const [pattern, child] of Object.entries(patternProperties)) {
207
+ const childSchema = asSchemaNode(child);
208
+ if (childSchema === undefined)
209
+ continue;
210
+ addEdge(node, {
211
+ pointer: childPointer(childPointer(schemaPointer, "patternProperties"), pattern),
212
+ schema: childSchema,
213
+ }, true);
214
+ }
215
+ }
216
+ for (const keyword of DYNAMIC_INSTANCE_KEYWORDS) {
217
+ const childSchema = asSchemaNode(schema[keyword]);
218
+ if (childSchema === undefined)
219
+ continue;
220
+ addEdge(node, {
221
+ pointer: childPointer(schemaPointer, keyword),
222
+ schema: childSchema,
223
+ }, true);
224
+ }
225
+ }
226
+ return valid ? { nodes, nodesByPointer, edgeCount } : undefined;
227
+ }
228
+ function graphComponents(edgesByNode) {
229
+ const seen = new Uint8Array(edgesByNode.length);
230
+ const finishOrder = [];
231
+ for (let start = 0; start < edgesByNode.length; start += 1) {
232
+ if (seen[start] === 1)
233
+ continue;
234
+ seen[start] = 1;
235
+ const stack = [{ node: start, nextEdge: 0 }];
236
+ while (stack.length > 0) {
237
+ const frame = stack[stack.length - 1];
238
+ const edges = edgesByNode[frame.node];
239
+ if (frame.nextEdge < edges.length) {
240
+ const target = edges[frame.nextEdge].target;
241
+ frame.nextEdge += 1;
242
+ if (seen[target] === 0) {
243
+ seen[target] = 1;
244
+ stack.push({ node: target, nextEdge: 0 });
245
+ }
246
+ }
247
+ else {
248
+ finishOrder.push(frame.node);
249
+ stack.pop();
250
+ }
251
+ }
252
+ }
253
+ const reverseEdges = Array.from({ length: edgesByNode.length }, () => []);
254
+ for (let source = 0; source < edgesByNode.length; source += 1) {
255
+ for (const edge of edgesByNode[source])
256
+ reverseEdges[edge.target].push(source);
257
+ }
258
+ const componentByNode = new Int32Array(edgesByNode.length);
259
+ componentByNode.fill(-1);
260
+ let componentCount = 0;
261
+ for (let index = finishOrder.length - 1; index >= 0; index -= 1) {
262
+ const start = finishOrder[index];
263
+ if (componentByNode[start] !== -1)
264
+ continue;
265
+ componentByNode[start] = componentCount;
266
+ const pending = [start];
267
+ while (pending.length > 0) {
268
+ const node = pending.pop();
269
+ for (const source of reverseEdges[node]) {
270
+ if (componentByNode[source] === -1) {
271
+ componentByNode[source] = componentCount;
272
+ pending.push(source);
273
+ }
274
+ }
275
+ }
276
+ componentCount += 1;
277
+ }
278
+ return { componentByNode, componentCount };
279
+ }
280
+ function compileDominance(graph) {
281
+ // Iterative Lengauer-Tarjan keeps dominance independent of DFS edge order
282
+ // while bounding work by the finite graph rather than recursive histories.
283
+ const nodeCount = graph.nodes.length;
284
+ const dfsNumberByNode = new Uint32Array(nodeCount);
285
+ const parent = new Uint32Array(nodeCount + 1);
286
+ let dfsCount = 1;
287
+ dfsNumberByNode[0] = dfsCount;
288
+ const dfsStack = [{ node: 0, nextEdge: 0 }];
289
+ while (dfsStack.length > 0) {
290
+ const frame = dfsStack[dfsStack.length - 1];
291
+ const edges = graph.nodes[frame.node].edges;
292
+ if (frame.nextEdge >= edges.length) {
293
+ dfsStack.pop();
294
+ continue;
295
+ }
296
+ const target = edges[frame.nextEdge].target;
297
+ frame.nextEdge += 1;
298
+ if (dfsNumberByNode[target] !== 0)
299
+ continue;
300
+ dfsCount += 1;
301
+ dfsNumberByNode[target] = dfsCount;
302
+ parent[dfsCount] = dfsNumberByNode[frame.node];
303
+ dfsStack.push({ node: target, nextEdge: 0 });
304
+ }
305
+ if (dfsCount !== nodeCount)
306
+ return undefined;
307
+ const predecessorCounts = new Uint32Array(nodeCount + 1);
308
+ for (const source of graph.nodes) {
309
+ for (const edge of source.edges) {
310
+ const target = dfsNumberByNode[edge.target];
311
+ predecessorCounts[target] = predecessorCounts[target] + 1;
312
+ }
313
+ }
314
+ const predecessorOffsets = new Uint32Array(nodeCount + 2);
315
+ for (let vertex = 1; vertex <= nodeCount; vertex += 1) {
316
+ predecessorOffsets[vertex + 1] = predecessorOffsets[vertex] + predecessorCounts[vertex];
317
+ }
318
+ const predecessorPositions = predecessorOffsets.slice();
319
+ const predecessors = new Uint32Array(graph.edgeCount);
320
+ for (const source of graph.nodes) {
321
+ const sourceVertex = dfsNumberByNode[source.id];
322
+ for (const edge of source.edges) {
323
+ const targetVertex = dfsNumberByNode[edge.target];
324
+ const position = predecessorPositions[targetVertex];
325
+ predecessors[position] = sourceVertex;
326
+ predecessorPositions[targetVertex] = position + 1;
327
+ }
328
+ }
329
+ const semi = new Uint32Array(nodeCount + 1);
330
+ const label = new Uint32Array(nodeCount + 1);
331
+ const ancestor = new Uint32Array(nodeCount + 1);
332
+ const immediateDominator = new Uint32Array(nodeCount + 1);
333
+ const bucketHead = new Uint32Array(nodeCount + 1);
334
+ const bucketNext = new Uint32Array(nodeCount + 1);
335
+ for (let vertex = 1; vertex <= nodeCount; vertex += 1) {
336
+ semi[vertex] = vertex;
337
+ label[vertex] = vertex;
338
+ }
339
+ const compressionPath = [];
340
+ const evaluate = (vertex) => {
341
+ if (ancestor[vertex] === 0)
342
+ return label[vertex];
343
+ compressionPath.length = 0;
344
+ let cursor = vertex;
345
+ while (ancestor[ancestor[cursor]] !== 0) {
346
+ compressionPath.push(cursor);
347
+ cursor = ancestor[cursor];
348
+ }
349
+ for (let index = compressionPath.length - 1; index >= 0; index -= 1) {
350
+ const child = compressionPath[index];
351
+ const ancestorVertex = ancestor[child];
352
+ if (semi[label[ancestorVertex]] < semi[label[child]]) {
353
+ label[child] = label[ancestorVertex];
354
+ }
355
+ ancestor[child] = ancestor[ancestorVertex];
356
+ }
357
+ return label[vertex];
358
+ };
359
+ for (let vertex = nodeCount; vertex >= 2; vertex -= 1) {
360
+ for (let position = predecessorOffsets[vertex]; position < predecessorOffsets[vertex + 1]; position += 1) {
361
+ const candidate = evaluate(predecessors[position]);
362
+ if (semi[candidate] < semi[vertex])
363
+ semi[vertex] = semi[candidate];
364
+ }
365
+ bucketNext[vertex] = bucketHead[semi[vertex]];
366
+ bucketHead[semi[vertex]] = vertex;
367
+ const parentVertex = parent[vertex];
368
+ ancestor[vertex] = parentVertex;
369
+ let deferred = bucketHead[parentVertex];
370
+ bucketHead[parentVertex] = 0;
371
+ while (deferred !== 0) {
372
+ const next = bucketNext[deferred];
373
+ const candidate = evaluate(deferred);
374
+ immediateDominator[deferred] = semi[candidate] < semi[deferred]
375
+ ? candidate
376
+ : parentVertex;
377
+ deferred = next;
378
+ }
379
+ }
380
+ for (let vertex = 2; vertex <= nodeCount; vertex += 1) {
381
+ if (immediateDominator[vertex] === 0)
382
+ return undefined;
383
+ if (immediateDominator[vertex] !== semi[vertex]) {
384
+ immediateDominator[vertex] = immediateDominator[immediateDominator[vertex]];
385
+ }
386
+ }
387
+ const childCounts = new Uint32Array(nodeCount + 1);
388
+ for (let vertex = 2; vertex <= nodeCount; vertex += 1) {
389
+ const dominator = immediateDominator[vertex];
390
+ childCounts[dominator] = childCounts[dominator] + 1;
391
+ }
392
+ const childOffsets = new Uint32Array(nodeCount + 2);
393
+ for (let vertex = 1; vertex <= nodeCount; vertex += 1) {
394
+ childOffsets[vertex + 1] = childOffsets[vertex] + childCounts[vertex];
395
+ }
396
+ const childPositions = childOffsets.slice();
397
+ const children = new Uint32Array(Math.max(0, nodeCount - 1));
398
+ for (let vertex = 2; vertex <= nodeCount; vertex += 1) {
399
+ const dominator = immediateDominator[vertex];
400
+ const position = childPositions[dominator];
401
+ children[position] = vertex;
402
+ childPositions[dominator] = position + 1;
403
+ }
404
+ const enteredAt = new Uint32Array(nodeCount + 1);
405
+ const exitedAt = new Uint32Array(nodeCount + 1);
406
+ let timestamp = 1;
407
+ enteredAt[1] = timestamp;
408
+ const dominatorStack = [{
409
+ vertex: 1,
410
+ nextChild: childOffsets[1],
411
+ }];
412
+ while (dominatorStack.length > 0) {
413
+ const frame = dominatorStack[dominatorStack.length - 1];
414
+ if (frame.nextChild < childOffsets[frame.vertex + 1]) {
415
+ const child = children[frame.nextChild];
416
+ frame.nextChild += 1;
417
+ timestamp += 1;
418
+ enteredAt[child] = timestamp;
419
+ dominatorStack.push({ vertex: child, nextChild: childOffsets[child] });
420
+ }
421
+ else {
422
+ exitedAt[frame.vertex] = timestamp;
423
+ dominatorStack.pop();
424
+ }
425
+ }
426
+ return (dominatorNode, node) => {
427
+ const dominator = dfsNumberByNode[dominatorNode];
428
+ const dominated = dfsNumberByNode[node];
429
+ return enteredAt[dominator] <= enteredAt[dominated]
430
+ && exitedAt[dominated] <= exitedAt[dominator];
431
+ };
432
+ }
433
+ function compileDynamicTaint(graph) {
434
+ const tainted = new Uint8Array(graph.nodes.length);
435
+ const pending = [];
436
+ for (const node of graph.nodes) {
437
+ for (const edge of node.edges) {
438
+ if (!edge.dynamic || tainted[edge.target] === 1)
439
+ continue;
440
+ tainted[edge.target] = 1;
441
+ pending.push(edge.target);
442
+ }
443
+ }
444
+ for (let cursor = 0; cursor < pending.length; cursor += 1) {
445
+ for (const edge of graph.nodes[pending[cursor]].edges) {
446
+ if (tainted[edge.target] === 1)
447
+ continue;
448
+ tainted[edge.target] = 1;
449
+ pending.push(edge.target);
450
+ }
451
+ }
452
+ return tainted;
453
+ }
454
+ function compileRouteProvenance(graph) {
455
+ const dominates = compileDominance(graph);
456
+ if (dominates === undefined)
457
+ return undefined;
458
+ // A transition back to a dominator is always a revisit: every route to its
459
+ // source has already crossed the target. All other transitions retain their
460
+ // provenance, including cross-entry references into a recursive component.
461
+ const residualEdges = graph.nodes.map((node) => node.edges.filter((edge) => !dominates(edge.target, node.id)));
462
+ const { componentByNode, componentCount } = graphComponents(residualEdges);
463
+ const componentEdges = Array.from({ length: componentCount }, () => []);
464
+ const indegree = new Uint32Array(componentCount);
465
+ const ambiguous = new Uint8Array(componentCount);
466
+ for (let source = 0; source < residualEdges.length; source += 1) {
467
+ const sourceComponent = componentByNode[source];
468
+ for (const edge of residualEdges[source]) {
469
+ const targetComponent = componentByNode[edge.target];
470
+ if (sourceComponent === targetComponent) {
471
+ // Cycles left after natural revisits are removed have independent
472
+ // entries, so their locations (and descendants) are ambiguous.
473
+ ambiguous[sourceComponent] = 1;
474
+ }
475
+ else {
476
+ componentEdges[sourceComponent].push({ target: targetComponent });
477
+ indegree[targetComponent] = indegree[targetComponent] + 1;
478
+ }
479
+ }
480
+ }
481
+ const routeCounts = new Uint8Array(componentCount);
482
+ routeCounts[componentByNode[0]] = 1;
483
+ const ready = [];
484
+ for (let component = 0; component < componentCount; component += 1) {
485
+ if (indegree[component] === 0)
486
+ ready.push(component);
487
+ }
488
+ for (let cursor = 0; cursor < ready.length; cursor += 1) {
489
+ const source = ready[cursor];
490
+ for (const edge of componentEdges[source]) {
491
+ if (routeCounts[source] > 0) {
492
+ routeCounts[edge.target] = Math.min(2, routeCounts[edge.target] + routeCounts[source]);
493
+ if (ambiguous[source] === 1)
494
+ ambiguous[edge.target] = 1;
495
+ }
496
+ indegree[edge.target] = indegree[edge.target] - 1;
497
+ if (indegree[edge.target] === 0)
498
+ ready.push(edge.target);
499
+ }
500
+ }
501
+ return ready.length === componentCount
502
+ ? { componentByNode, routeCounts, ambiguous }
503
+ : undefined;
504
+ }
505
+ function compileTargetRouteGraph(rootSchema, schemaPointers) {
506
+ const graph = buildInstanceRouteGraph(rootSchema);
507
+ if (graph === undefined)
508
+ return undefined;
509
+ const provenance = compileRouteProvenance(graph);
510
+ if (provenance === undefined)
511
+ return undefined;
512
+ const dynamicTaint = compileDynamicTaint(graph);
513
+ const targetNodeIds = new Set();
514
+ const targetPointers = new Set();
515
+ for (const schemaPointer of schemaPointers) {
516
+ const resolved = resolveSchemaPointer(rootSchema, schemaPointer);
517
+ if (resolved === undefined)
518
+ return undefined;
519
+ if (targetPointers.has(resolved.pointer))
520
+ continue;
521
+ targetPointers.add(resolved.pointer);
522
+ const target = graph.nodesByPointer.get(resolved.pointer);
523
+ if (target === undefined)
524
+ return undefined;
525
+ const component = provenance.componentByNode[target.id];
526
+ if (provenance.routeCounts[component] === 0
527
+ || dynamicTaint[target.id] === 1
528
+ || (target.schema !== false
529
+ && (provenance.routeCounts[component] > 1 || provenance.ambiguous[component] === 1))) {
530
+ return undefined;
531
+ }
532
+ if (target.schema !== false)
533
+ targetNodeIds.add(target.id);
534
+ }
535
+ return { ...graph, targetNodeIds };
536
+ }
537
+ function countJsonNodes(root) {
538
+ let count = 0;
539
+ const pending = [root];
540
+ while (pending.length > 0) {
541
+ const value = pending.pop();
542
+ count += 1;
543
+ if (Array.isArray(value)) {
544
+ for (const child of value)
545
+ pending.push(child);
546
+ }
547
+ else if (value !== null && typeof value === "object") {
548
+ for (const child of Object.values(value))
549
+ pending.push(child);
550
+ }
551
+ }
552
+ return count;
553
+ }
554
+ function graphTargetsAreValid(graph, values, targetIsValid) {
555
+ function* childVisits(node, value) {
556
+ for (const target of node.sameInstance) {
557
+ yield { nodeId: target, value };
558
+ }
559
+ if (Array.isArray(value)) {
560
+ for (let index = 0; index < value.length; index += 1) {
561
+ const childValue = value[index];
562
+ for (const target of node.arrayIndices.get(index) ?? []) {
563
+ yield { nodeId: target, value: childValue };
564
+ }
565
+ for (const [firstIndex, targets] of node.arrayTails) {
566
+ if (index < firstIndex)
567
+ continue;
568
+ for (const target of targets) {
569
+ yield { nodeId: target, value: childValue };
570
+ }
571
+ }
572
+ }
573
+ }
574
+ else if (value !== null && typeof value === "object") {
575
+ const objectValue = value;
576
+ for (const property in objectValue) {
577
+ if (!Object.hasOwn(objectValue, property))
578
+ continue;
579
+ const childValue = objectValue[property];
580
+ for (const target of node.properties.get(property) ?? []) {
581
+ yield { nodeId: target, value: childValue };
582
+ }
583
+ for (const target of node.dependentSchemas.get(property) ?? []) {
584
+ yield { nodeId: target, value };
585
+ }
586
+ }
587
+ }
588
+ }
589
+ const inputNodeCount = values.reduce((count, value) => count + countJsonNodes(value), 0);
590
+ const visitBudget = Math.min(MAX_PRESET_VISITS, Math.max(8_192, graph.nodes.length * 4 + graph.edgeCount * 2 + inputNodeCount * 64));
591
+ let visitCount = 0;
592
+ for (const input of values) {
593
+ const objectVisits = new Map();
594
+ const primitiveVisits = new Set();
595
+ const continuations = [];
596
+ let current = {
597
+ nodeId: 0,
598
+ value: input,
599
+ };
600
+ const resume = () => {
601
+ while (continuations.length > 0) {
602
+ const continuation = continuations[continuations.length - 1];
603
+ const next = continuation.next();
604
+ if (!next.done)
605
+ return next.value;
606
+ continuations.pop();
607
+ }
608
+ return undefined;
609
+ };
610
+ while (current !== undefined) {
611
+ const { nodeId, value } = current;
612
+ visitCount += 1;
613
+ if (visitCount > visitBudget
614
+ || (graph.targetNodeIds.has(nodeId) && !targetIsValid(nodeId, value)))
615
+ return false;
616
+ const node = graph.nodes[nodeId];
617
+ if (value !== null && typeof value === "object") {
618
+ const prior = objectVisits.get(nodeId) ?? new WeakSet();
619
+ if (prior.has(value)) {
620
+ current = resume();
621
+ continue;
622
+ }
623
+ prior.add(value);
624
+ objectVisits.set(nodeId, prior);
625
+ }
626
+ else {
627
+ if (primitiveVisits.has(nodeId)) {
628
+ current = resume();
629
+ continue;
630
+ }
631
+ primitiveVisits.add(nodeId);
632
+ }
633
+ const continuation = childVisits(node, value);
634
+ const next = continuation.next();
635
+ if (next.done) {
636
+ current = resume();
637
+ }
638
+ else {
639
+ continuations.push(continuation);
640
+ current = next.value;
641
+ }
642
+ }
643
+ }
644
+ return true;
645
+ }
646
+ export function operationPresetsOmitSecrets(operation) {
647
+ const schemaPointers = new Set(operation.inputHandling?.rules.flatMap((rule) => rule.kind === "secret" ? [rule.schemaPointer] : []) ?? []);
648
+ if (schemaPointers.size === 0)
649
+ return true;
650
+ const graph = compileTargetRouteGraph(operation.inputSchema, schemaPointers);
651
+ return graph !== undefined
652
+ && graphTargetsAreValid(graph, operation.presets.map(({ input }) => input), () => false);
653
+ }
654
+ export function operationInputHandlingValuesAreValid(operation, input, fileReferenceIsValid) {
655
+ const rules = operation.inputHandling?.rules ?? [];
656
+ if (rules.length === 0)
657
+ return true;
658
+ const schemaPointers = new Set(rules.map(({ schemaPointer }) => schemaPointer));
659
+ const graph = compileTargetRouteGraph(operation.inputSchema, schemaPointers);
660
+ if (graph === undefined)
661
+ return false;
662
+ const rulesByNode = new Map();
663
+ for (const rule of rules) {
664
+ const resolved = resolveSchemaPointer(operation.inputSchema, rule.schemaPointer);
665
+ if (resolved === undefined)
666
+ return false;
667
+ const target = graph.nodesByPointer.get(resolved.pointer);
668
+ if (target === undefined)
669
+ return false;
670
+ if (!graph.targetNodeIds.has(target.id))
671
+ continue;
672
+ const nodeRules = rulesByNode.get(target.id);
673
+ if (nodeRules === undefined)
674
+ rulesByNode.set(target.id, [rule]);
675
+ else
676
+ nodeRules.push(rule);
677
+ }
678
+ return graphTargetsAreValid(graph, [input], (nodeId, value) => {
679
+ for (const rule of rulesByNode.get(nodeId) ?? []) {
680
+ if (rule.kind === "secret")
681
+ return false;
682
+ if (rule.multiple) {
683
+ if (!Array.isArray(value)
684
+ || !value.every((candidate) => fileReferenceIsValid(candidate, rule)))
685
+ return false;
686
+ }
687
+ else if (!fileReferenceIsValid(value, rule)) {
688
+ return false;
689
+ }
690
+ }
691
+ return true;
692
+ });
693
+ }
694
+ //# sourceMappingURL=preset-secrets.js.map