@telorun/kernel 0.60.0 → 0.61.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 (53) hide show
  1. package/dist/controllers/resource-definition/resource-inherited-controller.d.ts.map +1 -1
  2. package/dist/controllers/resource-definition/resource-inherited-controller.js +57 -10
  3. package/dist/controllers/resource-definition/resource-inherited-controller.js.map +1 -1
  4. package/dist/controllers/type/json-schema-controller.d.ts +8 -0
  5. package/dist/controllers/type/json-schema-controller.d.ts.map +1 -0
  6. package/dist/controllers/type/json-schema-controller.js +91 -0
  7. package/dist/controllers/type/json-schema-controller.js.map +1 -0
  8. package/dist/evaluation-context.d.ts +5 -0
  9. package/dist/evaluation-context.d.ts.map +1 -1
  10. package/dist/evaluation-context.js +63 -33
  11. package/dist/evaluation-context.js.map +1 -1
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/init-failure-diagnostics.d.ts +61 -0
  17. package/dist/init-failure-diagnostics.d.ts.map +1 -0
  18. package/dist/init-failure-diagnostics.js +141 -0
  19. package/dist/init-failure-diagnostics.js.map +1 -0
  20. package/dist/invocation-contract-binding.d.ts +105 -0
  21. package/dist/invocation-contract-binding.d.ts.map +1 -0
  22. package/dist/invocation-contract-binding.js +296 -0
  23. package/dist/invocation-contract-binding.js.map +1 -0
  24. package/dist/kernel.d.ts +17 -0
  25. package/dist/kernel.d.ts.map +1 -1
  26. package/dist/kernel.js +62 -5
  27. package/dist/kernel.js.map +1 -1
  28. package/dist/module-context.d.ts.map +1 -1
  29. package/dist/module-context.js +21 -0
  30. package/dist/module-context.js.map +1 -1
  31. package/dist/resource-context.d.ts +45 -0
  32. package/dist/resource-context.d.ts.map +1 -1
  33. package/dist/resource-context.js +79 -0
  34. package/dist/resource-context.js.map +1 -1
  35. package/dist/schema-compiled-values.d.ts +9 -1
  36. package/dist/schema-compiled-values.d.ts.map +1 -1
  37. package/dist/schema-compiled-values.js +55 -16
  38. package/dist/schema-compiled-values.js.map +1 -1
  39. package/dist/schema-validator.d.ts.map +1 -1
  40. package/dist/schema-validator.js +15 -1
  41. package/dist/schema-validator.js.map +1 -1
  42. package/package.json +3 -3
  43. package/src/controllers/resource-definition/resource-inherited-controller.ts +69 -10
  44. package/src/controllers/type/json-schema-controller.ts +114 -0
  45. package/src/evaluation-context.ts +81 -32
  46. package/src/index.ts +1 -0
  47. package/src/init-failure-diagnostics.ts +169 -0
  48. package/src/invocation-contract-binding.ts +392 -0
  49. package/src/kernel.ts +83 -6
  50. package/src/module-context.ts +27 -0
  51. package/src/resource-context.ts +81 -0
  52. package/src/schema-compiled-values.ts +55 -15
  53. package/src/schema-validator.ts +15 -1
@@ -65,27 +65,67 @@ function collectSchemaProperties(
65
65
  * Template strings were compiled from YAML at load time; this restores a shape
66
66
  * that AJV can validate without evaluating expressions. When no schema is
67
67
  * supplied every compiled value collapses to `""` (the `default` branch of
68
- * `placeholderForSchema`), matching the schema-unaware strip. */
68
+ * `placeholderForSchema`), matching the schema-unaware strip.
69
+ *
70
+ * The walk stops short of anything that is not plain config, mirroring
71
+ * `buildResolvedProperties`: by the time a resource reaches validation its ref
72
+ * slots may already hold LIVE resource instances (a template passing the
73
+ * caller's client down with `client: !cel "self.client"` hands the child the
74
+ * injected instance, not a ref), and a controller's object graph is
75
+ * arbitrarily deep and routinely cyclic — walking one overflows the stack
76
+ * instead of producing a diagnostic, and there is nothing inside it to strip. */
69
77
  export function stripCompiledValues(
70
78
  v: unknown,
71
79
  schema: Record<string, unknown> = {},
72
80
  rootSchema?: Record<string, unknown>,
73
81
  ): unknown {
74
82
  const root = rootSchema ?? schema;
75
- const resolved = resolveSchemaRef(schema, root);
83
+ // Ancestors on the current path, so a genuine cycle stops while a sub-object
84
+ // that merely appears twice is still stripped both times.
85
+ const ancestors = new Set<object>();
76
86
 
77
- if (isCompiledValue(v)) return placeholderForSchema(resolved);
78
- if (Array.isArray(v)) {
79
- const itemSchema = resolveSchemaRef((resolved.items ?? {}) as Record<string, unknown>, root);
80
- return v.map((item) => stripCompiledValues(item, itemSchema, root));
81
- }
82
- if (v !== null && typeof v === "object") {
83
- const props = collectSchemaProperties(resolved);
84
- const out: Record<string, unknown> = {};
85
- for (const [k, val] of Object.entries(v as Record<string, unknown>)) {
86
- out[k] = stripCompiledValues(val, props[k] ?? {}, root);
87
+ const walk = (value: unknown, nodeSchema: Record<string, unknown>): unknown => {
88
+ const resolved = resolveSchemaRef(nodeSchema, root);
89
+
90
+ if (isCompiledValue(value)) return placeholderForSchema(resolved);
91
+ // A slot the schema declares as a reference is never config: it holds a
92
+ // `{kind, name}` ref or the live instance Phase 5 replaced it with, and the
93
+ // schema declares no shape to validate against either way.
94
+ if (resolved["x-telo-ref"] !== undefined) return value;
95
+
96
+ if (Array.isArray(value)) {
97
+ const itemSchema = resolveSchemaRef((resolved.items ?? {}) as Record<string, unknown>, root);
98
+ return walkGuarded(value, () => value.map((item) => walk(item, itemSchema)));
87
99
  }
88
- return out;
89
- }
90
- return v;
100
+ if (value !== null && typeof value === "object") {
101
+ // A class instance (a client, a pool, a stream) carries no CompiledValues
102
+ // and is not described by the schema — copying it is pure risk.
103
+ const proto = Object.getPrototypeOf(value);
104
+ if (proto !== Object.prototype && proto !== null) return value;
105
+
106
+ const props = collectSchemaProperties(resolved);
107
+ return walkGuarded(value, () => {
108
+ const out: Record<string, unknown> = {};
109
+ for (const [k, val] of Object.entries(value as Record<string, unknown>)) {
110
+ out[k] = walk(val, props[k] ?? {});
111
+ }
112
+ return out;
113
+ });
114
+ }
115
+ return value;
116
+ };
117
+
118
+ /** Runs `fn` with `node` marked as an ancestor; a node already on the path is
119
+ * a cycle and is returned as-is rather than recursed into. */
120
+ const walkGuarded = (node: object, fn: () => unknown): unknown => {
121
+ if (ancestors.has(node)) return node;
122
+ ancestors.add(node);
123
+ try {
124
+ return fn();
125
+ } finally {
126
+ ancestors.delete(node);
127
+ }
128
+ };
129
+
130
+ return walk(v, schema);
91
131
  }
@@ -8,6 +8,20 @@ import * as fs from "node:fs";
8
8
  import { createRequire } from "node:module";
9
9
  import * as path from "node:path";
10
10
  import { formatAjvErrors } from "./manifest-schemas.js";
11
+
12
+ /** Render a value for an error message without ever throwing.
13
+ *
14
+ * `JSON.stringify` refuses BigInt, and CEL evaluates an integer literal to one —
15
+ * so serializing the offending data threw from inside the message template and
16
+ * the thrown stringify error REPLACED the validation failure. The author was
17
+ * told "cannot serialize BigInt" instead of which field was wrong. */
18
+ function describeValue(data: unknown): string {
19
+ try {
20
+ return JSON.stringify(data, (_k, v) => (typeof v === "bigint" ? `${v}` : v)) ?? String(data);
21
+ } catch {
22
+ return String(data);
23
+ }
24
+ }
11
25
  import {
12
26
  EXACT_TEMPLATE_REGEX,
13
27
  isTaggedSentinel,
@@ -297,7 +311,7 @@ export class SchemaValidator {
297
311
  if (!isValid) {
298
312
  throw new RuntimeError(
299
313
  "ERR_RESOURCE_SCHEMA_VALIDATION_FAILED",
300
- `Invalid value passed: ${JSON.stringify(data)}. Error: ${formatAjvErrors(validate.errors)}`,
314
+ `Invalid value passed: ${describeValue(data)}. Error: ${formatAjvErrors(validate.errors)}`,
301
315
  );
302
316
  }
303
317
  },