@pipelex/mthds-form 0.3.0 → 0.4.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 (80) hide show
  1. package/README.md +7 -2
  2. package/dist/chunk-6XD6UZSU.js +28 -0
  3. package/dist/chunk-6XD6UZSU.js.map +1 -0
  4. package/dist/chunk-7BMOPXDY.js +205 -0
  5. package/dist/chunk-7BMOPXDY.js.map +1 -0
  6. package/dist/chunk-GKV77RAS.js +46 -0
  7. package/dist/chunk-GKV77RAS.js.map +1 -0
  8. package/dist/chunk-HARYEWNG.js +31 -0
  9. package/dist/chunk-HARYEWNG.js.map +1 -0
  10. package/dist/chunk-KFZ5MZOM.js +44 -0
  11. package/dist/chunk-KFZ5MZOM.js.map +1 -0
  12. package/dist/chunk-NMT7BRLO.js +40 -0
  13. package/dist/chunk-NMT7BRLO.js.map +1 -0
  14. package/dist/chunk-O4O3QNVC.js +146 -0
  15. package/dist/chunk-O4O3QNVC.js.map +1 -0
  16. package/dist/chunk-PM55AHRO.js +52 -0
  17. package/dist/chunk-PM55AHRO.js.map +1 -0
  18. package/dist/chunk-RPA7DNSK.js +41 -0
  19. package/dist/chunk-RPA7DNSK.js.map +1 -0
  20. package/dist/chunk-V3OV2XQT.js +12 -0
  21. package/dist/chunk-V3OV2XQT.js.map +1 -0
  22. package/dist/chunk-VMLXO5JS.js +132 -0
  23. package/dist/chunk-VMLXO5JS.js.map +1 -0
  24. package/dist/chunk-VTPUDBSJ.js +61 -0
  25. package/dist/chunk-VTPUDBSJ.js.map +1 -0
  26. package/dist/chunk-WXBSM2CE.js +201 -0
  27. package/dist/chunk-WXBSM2CE.js.map +1 -0
  28. package/dist/chunk-XEPD5VJQ.js +99 -0
  29. package/dist/chunk-XEPD5VJQ.js.map +1 -0
  30. package/dist/core/contracts.d.ts +143 -0
  31. package/dist/core/contracts.js +4 -0
  32. package/dist/core/contracts.js.map +1 -0
  33. package/dist/core/date-format.d.ts +87 -0
  34. package/dist/core/date-format.js +3 -0
  35. package/dist/core/date-format.js.map +1 -0
  36. package/dist/core/derive.d.ts +20 -0
  37. package/dist/core/derive.js +7 -0
  38. package/dist/core/derive.js.map +1 -0
  39. package/dist/{descriptor-DPrrfAjL.d.ts → core/descriptor.d.ts} +28 -1
  40. package/dist/core/descriptor.js +3 -0
  41. package/dist/core/descriptor.js.map +1 -0
  42. package/dist/core/gate-validator.d.ts +27 -0
  43. package/dist/core/gate-validator.js +4 -0
  44. package/dist/core/gate-validator.js.map +1 -0
  45. package/dist/core/gate.d.ts +144 -0
  46. package/dist/core/gate.js +13 -0
  47. package/dist/core/gate.js.map +1 -0
  48. package/dist/core/index.d.ts +12 -623
  49. package/dist/core/index.js +14 -1
  50. package/dist/core/native-concepts.d.ts +78 -0
  51. package/dist/core/native-concepts.js +3 -0
  52. package/dist/core/native-concepts.js.map +1 -0
  53. package/dist/core/normalize-schema.d.ts +30 -0
  54. package/dist/core/normalize-schema.js +4 -0
  55. package/dist/core/normalize-schema.js.map +1 -0
  56. package/dist/core/own-property.d.ts +46 -0
  57. package/dist/core/own-property.js +3 -0
  58. package/dist/core/own-property.js.map +1 -0
  59. package/dist/core/readiness.d.ts +89 -0
  60. package/dist/core/readiness.js +4 -0
  61. package/dist/core/readiness.js.map +1 -0
  62. package/dist/core/schema-utils.d.ts +74 -0
  63. package/dist/core/schema-utils.js +3 -0
  64. package/dist/core/schema-utils.js.map +1 -0
  65. package/dist/core/validation-message.d.ts +39 -0
  66. package/dist/core/validation-message.js +4 -0
  67. package/dist/core/validation-message.js.map +1 -0
  68. package/dist/core/values.d.ts +91 -0
  69. package/dist/core/values.js +11 -0
  70. package/dist/core/values.js.map +1 -0
  71. package/dist/core/wire-format.d.ts +95 -0
  72. package/dist/core/wire-format.js +7 -0
  73. package/dist/core/wire-format.js.map +1 -0
  74. package/dist/react/index.d.ts +22 -1
  75. package/dist/react/index.js +128 -48
  76. package/dist/react/index.js.map +1 -1
  77. package/dist/styles.css +1 -1
  78. package/package.json +5 -1
  79. package/dist/chunk-S6KOTTGD.js +0 -990
  80. package/dist/chunk-S6KOTTGD.js.map +0 -1
@@ -0,0 +1,146 @@
1
+ // src/core/schema-utils.ts
2
+ function collapseNullable(schema) {
3
+ const anyOf = schema.anyOf;
4
+ if (!Array.isArray(anyOf)) return schema;
5
+ const branches = anyOf;
6
+ const nonNull = branches.filter((b) => b?.type !== "null");
7
+ if (nonNull.length === 1) return { ...stripAnyOf(schema), ...nonNull[0] };
8
+ return schema;
9
+ }
10
+ var PRIMITIVE_TYPES = /* @__PURE__ */ new Set(["string", "number", "integer", "boolean", "null"]);
11
+ function isSimplePrimitive(schema) {
12
+ const type = schema.type;
13
+ if (typeof type !== "string" || !PRIMITIVE_TYPES.has(type)) return false;
14
+ const allowedKeys = /* @__PURE__ */ new Set(["type", "default", "description", "title"]);
15
+ return Object.keys(schema).every((key) => allowedKeys.has(key));
16
+ }
17
+ function flattenAnyOf(schema) {
18
+ const anyOf = schema.anyOf;
19
+ if (!Array.isArray(anyOf)) return schema;
20
+ const branches = anyOf;
21
+ if (branches.every(
22
+ (branch) => typeof branch === "object" && branch !== null && isSimplePrimitive(branch)
23
+ )) {
24
+ const types = [];
25
+ let mergedDefault = void 0;
26
+ for (const branch of branches) {
27
+ types.push(branch.type);
28
+ if (branch.default !== void 0) mergedDefault = branch.default;
29
+ }
30
+ const { anyOf: _, ...rest } = schema;
31
+ const result = { ...rest, type: types };
32
+ if (mergedDefault !== void 0 && result.default === void 0) {
33
+ result.default = mergedDefault;
34
+ }
35
+ return result;
36
+ }
37
+ if (branches.length === 2) {
38
+ const nullBranch = branches.find(
39
+ (b) => typeof b === "object" && b !== null && b.type === "null"
40
+ );
41
+ const otherBranch = branches.find((b) => b !== nullBranch);
42
+ if (nullBranch && otherBranch && typeof otherBranch === "object") {
43
+ const { anyOf: _, ...rest } = schema;
44
+ return { ...rest, ...otherBranch };
45
+ }
46
+ }
47
+ return schema;
48
+ }
49
+ function stripAnyOf(schema) {
50
+ const { anyOf: _drop, ...rest } = schema;
51
+ return rest;
52
+ }
53
+ function schemaTypeOf(schema) {
54
+ const t = schema.type;
55
+ if (typeof t === "string") return t;
56
+ if (Array.isArray(t)) return t.find((x) => x !== "null");
57
+ return void 0;
58
+ }
59
+ function derefSchema(schema, defs) {
60
+ const ref = schema.$ref;
61
+ if (typeof ref === "string" && ref.startsWith("#/$defs/")) {
62
+ const resolved = defs[ref.slice("#/$defs/".length)];
63
+ if (resolved) return { ...resolved, ...stripRef(schema) };
64
+ }
65
+ return schema;
66
+ }
67
+ function stripRef(schema) {
68
+ const { $ref: _drop, ...rest } = schema;
69
+ return rest;
70
+ }
71
+ function resolveSchemaIndirection(schema, defs) {
72
+ let current = schema;
73
+ for (; ; ) {
74
+ const ref = current.$ref;
75
+ if (typeof ref === "string" && ref.startsWith("#/$defs/")) {
76
+ const resolved = defs[ref.slice("#/$defs/".length)];
77
+ if (resolved) {
78
+ current = resolved;
79
+ continue;
80
+ }
81
+ }
82
+ if (Array.isArray(current.anyOf)) {
83
+ const nonNull = current.anyOf.filter((b) => b?.type !== "null");
84
+ if (nonNull.length === 1) {
85
+ current = nonNull[0];
86
+ continue;
87
+ }
88
+ }
89
+ return current;
90
+ }
91
+ }
92
+ function collectSchemaDefs(schema, into, options) {
93
+ for (const [key, value] of Object.entries(schema)) {
94
+ if (key === "$defs" && value && typeof value === "object" && !Array.isArray(value)) {
95
+ for (const [name, def] of Object.entries(value)) {
96
+ if (!(name in into) && def && typeof def === "object") {
97
+ into[name] = def;
98
+ collectSchemaDefs(def, into, options);
99
+ }
100
+ }
101
+ } else if (value && typeof value === "object" && !Array.isArray(value)) {
102
+ collectSchemaDefs(value, into, options);
103
+ } else if (options.traverseArrays && Array.isArray(value)) {
104
+ for (const item of value) {
105
+ if (item && typeof item === "object") {
106
+ collectSchemaDefs(item, into, options);
107
+ }
108
+ }
109
+ }
110
+ }
111
+ return into;
112
+ }
113
+ function walkAndCollectDefs(schema, collected) {
114
+ const out = {};
115
+ for (const [key, value] of Object.entries(schema)) {
116
+ if (key === "$defs" && value && typeof value === "object" && !Array.isArray(value)) {
117
+ for (const [defName, defValue] of Object.entries(value)) {
118
+ if (!(defName in collected) && defValue && typeof defValue === "object") {
119
+ collected[defName] = {};
120
+ collected[defName] = walkAndCollectDefs(defValue, collected);
121
+ }
122
+ }
123
+ } else if (value && typeof value === "object" && !Array.isArray(value)) {
124
+ out[key] = walkAndCollectDefs(value, collected);
125
+ } else if (Array.isArray(value)) {
126
+ out[key] = value.map(
127
+ (item) => item && typeof item === "object" && !Array.isArray(item) ? walkAndCollectDefs(item, collected) : item
128
+ );
129
+ } else {
130
+ out[key] = value;
131
+ }
132
+ }
133
+ return out;
134
+ }
135
+ function hoistDefsToRoot(schema) {
136
+ const collected = {};
137
+ const stripped = walkAndCollectDefs(schema, collected);
138
+ if (Object.keys(collected).length > 0) {
139
+ stripped.$defs = collected;
140
+ }
141
+ return stripped;
142
+ }
143
+
144
+ export { collapseNullable, collectSchemaDefs, derefSchema, flattenAnyOf, hoistDefsToRoot, resolveSchemaIndirection, schemaTypeOf };
145
+ //# sourceMappingURL=chunk-O4O3QNVC.js.map
146
+ //# sourceMappingURL=chunk-O4O3QNVC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/schema-utils.ts"],"names":[],"mappings":"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","file":"chunk-O4O3QNVC.js","sourcesContent":["/**\n * The ONE place JSON-Schema plumbing lives for the run form kernel: nullable\n * `anyOf` collapsing, `$defs` collection/hoisting, `$ref` resolution, and type\n * extraction. Consolidated from three drifted private copies (`field-model.ts`,\n * `normalize-schema.ts`, `input-format.ts`) during the form-kernel extraction.\n *\n * Two collapse engines are exported ON PURPOSE - their semantics genuinely\n * differ, and each caller's observable behavior is characterized and preserved\n * (see `schema-utils-characterization.test.ts`):\n *\n * - `collapseNullable` (the field mapper's rule): collapse ONLY when exactly one\n * non-null branch remains, dropping the null. A multi-branch union stays an\n * `anyOf` and maps to the raw-JSON escape hatch.\n * - `flattenAnyOf` (the RJSF/ajv rule): a union of simple primitives becomes a\n * `type` ARRAY (null preserved as a type entry - ajv validates `type:\n * [\"number\",\"null\"]` natively); a 2-branch nullable non-primitive drops the\n * null branch.\n *\n * Whether these converge (and which semantics win) is an M1 question, decided\n * when the descriptor derivation moves server-side - not silently here.\n */\n\nexport type JsonSchema = Record<string, unknown>;\n\n// ─── anyOf collapsing ────────────────────────────────────────────────────────\n\n/** Pydantic emits `anyOf: [T, {type:'null'}]` for Optional[T]; collapse to T.\n * Collapses ONLY when exactly one non-null branch remains; the branch merges\n * OVER the outer schema (its constraints win). */\nexport function collapseNullable(schema: JsonSchema): JsonSchema {\n const anyOf = schema.anyOf;\n if (!Array.isArray(anyOf)) return schema;\n const branches = anyOf as JsonSchema[];\n const nonNull = branches.filter((b) => b?.type !== 'null');\n if (nonNull.length === 1) return { ...stripAnyOf(schema), ...nonNull[0] };\n return schema;\n}\n\nconst PRIMITIVE_TYPES = new Set(['string', 'number', 'integer', 'boolean', 'null']);\n\n/**\n * An `anyOf` entry that is a simple primitive with no constraints:\n * `{type: \"string\"}` is simple, `{type: \"string\", maxLength: 10}` is not.\n */\nfunction isSimplePrimitive(schema: JsonSchema): boolean {\n const type = schema.type;\n if (typeof type !== 'string' || !PRIMITIVE_TYPES.has(type)) return false;\n const allowedKeys = new Set(['type', 'default', 'description', 'title']);\n return Object.keys(schema).every((key) => allowedKeys.has(key));\n}\n\n/**\n * The RJSF/ajv collapse: a union of simple primitives flattens to a `type`\n * array (`anyOf: [{string},{null}]` → `type: [\"string\",\"null\"]`, which RJSF\n * renders as a plain input instead of a sub-schema picker); an exactly-two\n * `[T, {null}]` union of anything else drops the null branch and merges T over\n * the outer schema. Anything else passes through unchanged.\n */\nexport function flattenAnyOf(schema: JsonSchema): JsonSchema {\n const anyOf = schema.anyOf;\n if (!Array.isArray(anyOf)) return schema;\n\n const branches = anyOf as JsonSchema[];\n\n // Case 1: all branches are simple primitives → type array.\n if (\n branches.every(\n (branch) => typeof branch === 'object' && branch !== null && isSimplePrimitive(branch),\n )\n ) {\n const types: string[] = [];\n let mergedDefault: unknown = undefined;\n for (const branch of branches) {\n types.push(branch.type as string);\n if (branch.default !== undefined) mergedDefault = branch.default;\n }\n const { anyOf: _, ...rest } = schema;\n const result: JsonSchema = { ...rest, type: types };\n if (mergedDefault !== undefined && result.default === undefined) {\n result.default = mergedDefault;\n }\n return result;\n }\n\n // Case 2: exactly [T, {type: \"null\"}] - nullable non-primitive → drop null.\n if (branches.length === 2) {\n const nullBranch = branches.find(\n (b) => typeof b === 'object' && b !== null && b.type === 'null',\n );\n const otherBranch = branches.find((b) => b !== nullBranch);\n if (nullBranch && otherBranch && typeof otherBranch === 'object') {\n const { anyOf: _, ...rest } = schema;\n return { ...rest, ...otherBranch };\n }\n }\n\n return schema;\n}\n\nfunction stripAnyOf(schema: JsonSchema): JsonSchema {\n const { anyOf: _drop, ...rest } = schema;\n return rest;\n}\n\n// ─── Type & $ref helpers ─────────────────────────────────────────────────────\n\n/** The schema's non-null type: a bare `type` string, or the first non-null\n * entry of a `type` array (`[\"number\",\"null\"]` → `\"number\"`). */\nexport function schemaTypeOf(schema: JsonSchema): string | undefined {\n const t = schema.type;\n if (typeof t === 'string') return t;\n if (Array.isArray(t)) return t.find((x) => x !== 'null') as string | undefined;\n return undefined;\n}\n\n/** Resolve `{ $ref: \"#/$defs/Foo\" }` against a collected `$defs` map. Sibling\n * keys on the referencing schema override the definition's. */\nexport function derefSchema(schema: JsonSchema, defs: Record<string, JsonSchema>): JsonSchema {\n const ref = schema.$ref;\n if (typeof ref === 'string' && ref.startsWith('#/$defs/')) {\n const resolved = defs[ref.slice('#/$defs/'.length)];\n if (resolved) return { ...resolved, ...stripRef(schema) };\n }\n return schema;\n}\n\nfunction stripRef(schema: JsonSchema): JsonSchema {\n const { $ref: _drop, ...rest } = schema;\n return rest;\n}\n\n/**\n * Resolve the indirection layers pydantic puts in front of a value schema - a\n * `#/$defs/...` ref, a nullable `anyOf: [T, {null}]` wrapper, or a stack of\n * both - until a plain schema remains. This is the resolver `healStringWrappers`\n * and `pruneEmptyOptionals` apply before reading `type`. Unlike `derefSchema`\n * it REPLACES the schema with the definition (no sibling merge) - exactly what\n * the callers did inline.\n */\nexport function resolveSchemaIndirection(\n schema: JsonSchema,\n defs: Record<string, JsonSchema>,\n): JsonSchema {\n let current = schema;\n for (;;) {\n const ref = current.$ref;\n if (typeof ref === 'string' && ref.startsWith('#/$defs/')) {\n const resolved = defs[ref.slice('#/$defs/'.length)];\n if (resolved) {\n current = resolved;\n continue;\n }\n }\n if (Array.isArray(current.anyOf)) {\n const nonNull = (current.anyOf as JsonSchema[]).filter((b) => b?.type !== 'null');\n if (nonNull.length === 1) {\n current = nonNull[0]!;\n continue;\n }\n }\n return current;\n }\n}\n\n// ─── $defs collection ────────────────────────────────────────────────────────\n\nexport interface CollectDefsOptions {\n /**\n * Whether the walk descends into JSON arrays (`anyOf`/`allOf` branches,\n * tuple `items`). The field mapper always has (so a def declared inside an\n * `anyOf` branch resolves); the wire-format heal path historically has NOT -\n * both behaviors are characterized, and each caller states its mode\n * explicitly until M1 retires the difference.\n */\n traverseArrays: boolean;\n}\n\n/**\n * Collect every nested `$defs` entry into one flat map so `#/$defs/...` refs\n * resolve from anywhere. First definition of a name wins. The input schema is\n * NOT modified (see `hoistDefsToRoot` for the stripping variant).\n */\nexport function collectSchemaDefs(\n schema: JsonSchema,\n into: Record<string, JsonSchema>,\n options: CollectDefsOptions,\n): Record<string, JsonSchema> {\n for (const [key, value] of Object.entries(schema)) {\n if (key === '$defs' && value && typeof value === 'object' && !Array.isArray(value)) {\n for (const [name, def] of Object.entries(value as Record<string, JsonSchema>)) {\n if (!(name in into) && def && typeof def === 'object') {\n into[name] = def;\n collectSchemaDefs(def, into, options);\n }\n }\n } else if (value && typeof value === 'object' && !Array.isArray(value)) {\n collectSchemaDefs(value as JsonSchema, into, options);\n } else if (options.traverseArrays && Array.isArray(value)) {\n // Any object item recurses - including a nested array, whose indices then\n // walk as keys (matches the historical field-model walker exactly).\n for (const item of value) {\n if (item && typeof item === 'object') {\n collectSchemaDefs(item as JsonSchema, into, options);\n }\n }\n }\n }\n return into;\n}\n\n// ─── $defs hoisting (the RJSF wrapper-schema case) ──────────────────────────\n\n/**\n * Walk a schema, collect every `$defs` entry into `collected`, and return the\n * schema with those nested `$defs` STRIPPED. Cycle-safe: a def name is claimed\n * (placeholder) before its body is walked.\n */\nfunction walkAndCollectDefs(schema: JsonSchema, collected: JsonSchema): JsonSchema {\n const out: JsonSchema = {};\n for (const [key, value] of Object.entries(schema)) {\n if (key === '$defs' && value && typeof value === 'object' && !Array.isArray(value)) {\n for (const [defName, defValue] of Object.entries(value as JsonSchema)) {\n if (!(defName in collected) && defValue && typeof defValue === 'object') {\n collected[defName] = {};\n collected[defName] = walkAndCollectDefs(defValue as JsonSchema, collected);\n }\n }\n // Don't copy `$defs` into out - it's hoisted to the root.\n } else if (value && typeof value === 'object' && !Array.isArray(value)) {\n out[key] = walkAndCollectDefs(value as JsonSchema, collected);\n } else if (Array.isArray(value)) {\n out[key] = value.map((item) =>\n item && typeof item === 'object' && !Array.isArray(item)\n ? walkAndCollectDefs(item as JsonSchema, collected)\n : item,\n );\n } else {\n out[key] = value;\n }\n }\n return out;\n}\n\n/**\n * Hoist every nested `$defs` to the schema root, so a wrapper schema composed\n * from several pydantic sub-schemas keeps its `#/$defs/...` refs resolvable.\n * (Pydantic emits one `$defs` per model; composing models as properties of a\n * wrapper object leaves those maps below the root the refs point to.)\n */\nexport function hoistDefsToRoot(schema: JsonSchema): JsonSchema {\n const collected: JsonSchema = {};\n const stripped = walkAndCollectDefs(schema, collected);\n if (Object.keys(collected).length > 0) {\n stripped.$defs = collected;\n }\n return stripped;\n}\n"]}
@@ -0,0 +1,52 @@
1
+ import { hasOwnProp, ownProp } from './chunk-V3OV2XQT.js';
2
+
3
+ // src/core/readiness.ts
4
+ var MAX_FILLED_DEPTH = 64;
5
+ function isFilled(value) {
6
+ return walkFilled(value, 0, void 0);
7
+ }
8
+ function walkFilled(value, depth, seen) {
9
+ if (value == null) return false;
10
+ if (typeof value === "string") return value.trim() !== "";
11
+ if (typeof value === "function") return false;
12
+ if (typeof value !== "object") return true;
13
+ if (depth >= MAX_FILLED_DEPTH) return false;
14
+ const visited = seen ?? /* @__PURE__ */ new Map();
15
+ const judgedAt = visited.get(value);
16
+ if (judgedAt !== void 0 && judgedAt <= depth) return false;
17
+ visited.set(value, depth);
18
+ if (Array.isArray(value)) return value.some((item) => walkFilled(item, depth + 1, visited));
19
+ const obj = value;
20
+ if (hasOwnProp(obj, "url")) return walkFilled(obj.url, depth + 1, visited);
21
+ return Object.values(obj).some((child) => walkFilled(child, depth + 1, visited));
22
+ }
23
+ function fieldFilled(field, value) {
24
+ if (field.kind === "object") {
25
+ if (!isFilled(value)) return false;
26
+ const obj = value ?? {};
27
+ return field.fields.every((f) => !f.required || fieldFilled(f, ownProp(obj, f.name)));
28
+ }
29
+ if (field.kind === "list") {
30
+ if (field.maxItemCount !== void 0 && Array.isArray(value) && value.length > field.maxItemCount)
31
+ return false;
32
+ if (field.itemCount !== void 0) {
33
+ if (!Array.isArray(value) || value.length < field.itemCount) return false;
34
+ return value.every((item) => fieldFilled(field.item, item));
35
+ }
36
+ if (Array.isArray(value))
37
+ return value.every((item) => !isFilled(item) || fieldFilled(field.item, item)) && isFilled(value);
38
+ }
39
+ return isFilled(value);
40
+ }
41
+ function mustBeFilled(field) {
42
+ return field.gating ?? (field.required && field.kind !== "list");
43
+ }
44
+ function computeReadiness(fields, values) {
45
+ const gating = fields.filter((f) => mustBeFilled(f) || isFilled(ownProp(values, f.name)));
46
+ const missing = gating.filter((f) => !fieldFilled(f, ownProp(values, f.name))).map((f) => f.title ?? f.name);
47
+ return { total: gating.length, ready: gating.length - missing.length, missing };
48
+ }
49
+
50
+ export { computeReadiness, fieldFilled, isFilled, mustBeFilled };
51
+ //# sourceMappingURL=chunk-PM55AHRO.js.map
52
+ //# sourceMappingURL=chunk-PM55AHRO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/readiness.ts"],"names":[],"mappings":"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","file":"chunk-PM55AHRO.js","sourcesContent":["/**\n * Value readiness - the helpers the runner uses to decide whether the Run\n * button may fire and which inputs are still missing.\n */\n\nimport type { RunField } from './descriptor';\nimport { hasOwnProp, ownProp } from './own-property';\n\n/**\n * How deep `isFilled` walks a value before it stops looking, and the answer it\n * gives when it does.\n *\n * The walk is over CALLER-SUPPLIED data - a request body on a public run\n * endpoint, or a form's state - so its depth is whatever the caller sent, and\n * the schema is no bound on it: `pruneEmptyOptionals` copies a property the\n * schema does not declare straight through, so a key ajv never walks reaches\n * this function unwalked. Unbounded, a value a few thousand levels deep threw\n * `RangeError` out of the middle of a host's server gate - a gate whose whole\n * contract is that it returns a verdict instead of throwing.\n *\n * **The cap answers `false`, and that direction is the deliberate half.** Past\n * the cap this function cannot tell whether there is anything down there, and\n * the kernel's rule throughout is that an unanswerable absence fails closed.\n * The cost of the other choice is a run the method cannot use, started (and\n * billed) on a payload no schema validated. The cost of this one is nearly\n * nothing: `isFilled` combines branches with `some`, so a refused over-deep\n * branch only loses its own vote - a real value anywhere beside it still reads\n * filled - and no concept structure declares nesting anywhere near this deep,\n * so a value that reaches the cap is not one the method had a slot for.\n */\nconst MAX_FILLED_DEPTH = 64;\n\n/** True when a value is meaningfully filled (not empty / blank / empty container). */\nexport function isFilled(value: unknown): boolean {\n return walkFilled(value, 0, undefined);\n}\n\n/**\n * `isFilled`'s walk, carrying the depth and the objects already judged.\n *\n * `seen` is a cycle guard first - a value that references itself would\n * otherwise recurse to the cap on every branch - and a memo second. Both uses\n * rest on the same fact: an object reached twice within ONE call answered\n * `false` the first time, because a `true` short-circuits every `some` above it\n * and the walk never gets back down here. So the map can only ever hold empty\n * subtrees, which is what makes it safe to keep entries after unwinding -\n * without that, a value shaped like a diamond chain costs exponential time.\n *\n * **It records the DEPTH each object was judged at, and that is not a detail.**\n * A `false` here has two causes - nothing was down there, or the cap stopped\n * the walk - and only the first travels. An object whose children sit one level\n * past the cap answers `false` at depth 63 and is perfectly filled at depth 5;\n * memoizing identity alone then reported a genuinely filled input as missing\n * the moment a shallower path reached the same object second. So a recorded\n * answer is reused only for a revisit at the SAME depth or deeper, where the\n * walk could see no more than the first one did, and a strictly shallower\n * arrival walks again. That keeps the cycle guard exact (depth rises along\n * every path, so a cycle always revisits deeper) and keeps the memo bounded:\n * an object's recorded depth strictly falls each time it is re-walked, over a\n * range the cap fixes, so the diamond stays linear in all but a constant.\n */\nfunction walkFilled(value: unknown, depth: number, seen: Map<object, number> | undefined): boolean {\n if (value == null) return false;\n // Whitespace is not a value. The Run button lit up over a required text input\n // holding three spaces, ajv passed it (a content model carries no\n // `minLength`), and the run reached the runtime with nothing in it. The same\n // test is what makes a blank OPTIONAL input a real absence on the wire rather\n // than a supplied empty string - see `apiInputsFromSchemaData`.\n if (typeof value === 'string') return value.trim() !== '';\n // No concept in the taxonomy holds a function, so one here arrived by a route\n // that is already wrong - most plausibly an inherited `Object.prototype`\n // member read off a plain object by a colliding input name. `ownProp` closes\n // that route at every lookup; this branch is the backstop for the ones that\n // arrive by another.\n if (typeof value === 'function') return false;\n if (typeof value !== 'object') return true;\n\n if (depth >= MAX_FILLED_DEPTH) return false;\n const visited = seen ?? new Map<object, number>();\n const judgedAt = visited.get(value);\n if (judgedAt !== undefined && judgedAt <= depth) return false;\n visited.set(value, depth);\n\n if (Array.isArray(value)) return value.some((item) => walkFilled(item, depth + 1, visited));\n const obj = value as Record<string, unknown>;\n // A file value is { url } - filled when the url is set.\n if (hasOwnProp(obj, 'url')) return walkFilled(obj.url, depth + 1, visited);\n return Object.values(obj).some((child) => walkFilled(child, depth + 1, visited));\n}\n\n/**\n * True when a slot holds something AND every required field inside it has a\n * value.\n *\n * The two halves are both load-bearing, and the first one is the one that is\n * easy to leave out. A structure is satisfied only if there is something in it:\n * a struct whose concept declares no required child used to be *vacuously*\n * satisfied by an absent value - every child passed the `!f.required` test, so\n * `every` returned true over a value that was not there. Readiness reported\n * nothing missing and the Run button lit up, while the value bridge omitted the\n * untouched structure and the gate then rejected the run on the combined\n * schema's `required` list, naming an input the form had just declared ready.\n *\n * `isFilled` is the SAME predicate `toRjsf` uses to decide whether a structure\n * collapses to an absence (`values.ts`), which is what makes the two halves\n * agree by construction rather than by parallel edits: readiness calls an input\n * present exactly when the bridge keeps it. Absence is what a singular slot\n * expresses, so a required one has to be touched - the button stays dark until\n * the user puts a value somewhere inside, and then the whole shell travels,\n * empty children and all, so a required child left blank still fails loudly.\n *\n * Its own recursion follows the DESCRIPTOR, not the value, so it needs no depth\n * cap of its own: a `RunField` tree only exists because `buildRunFields`\n * finished walking a contract's schema, which bounds it. `isFilled` is where\n * the caller's data is walked, and where the cap lives.\n */\nexport function fieldFilled(field: RunField, value: unknown): boolean {\n if (field.kind === 'object') {\n if (!isFilled(value)) return false;\n const obj = (value ?? {}) as Record<string, unknown>;\n return field.fields.every((f) => !f.required || fieldFilled(f, ownProp(obj, f.name)));\n }\n if (field.kind === 'list') {\n // Too many items is not filled, and this is asked of EVERY list, not only\n // one carrying a lower bound. `ListField` will not add past the bound, so\n // it answers the list that arrived from somewhere else - a restored draft,\n // a host seeding values, a bespoke surface calling these predicates over\n // data it did not render. Asking it only inside the `itemCount` branch\n // meant a model stating `maxItems` alone published its ceiling on the\n // descriptor and enforced it nowhere: the button stayed live on a list ajv\n // was about to refuse. Naming it in `missing` is a small stretch of that\n // word, and the alternative is the disagreement.\n if (\n field.maxItemCount !== undefined &&\n Array.isArray(value) &&\n value.length > field.maxItemCount\n )\n return false;\n // A list the method gave a count to (`Concept[N]`) is satisfied only by that\n // many items, each of them filled. Answering it by `isFilled` alone - \"is\n // there anything in the array?\" - left the button live on a `[3]` slot\n // holding two, and the gate then refused it on the very count the method\n // declared. `itemCount` comes off the same `minItems` ajv reads, so the two\n // halves phrase one rule.\n if (field.itemCount !== undefined) {\n if (!Array.isArray(value) || value.length < field.itemCount) return false;\n return value.every((item) => fieldFilled(field.item, item));\n }\n // A VARIABLE list never gates on being empty (see `mustBeFilled`) - a plural\n // slot's empty form IS the empty list. But a row the user STARTED owes its\n // concept every field the concept declares, which is the same rule a touched\n // optional input follows one level up, and `isFilled` alone does not say it:\n // a row holding `{name: 'x', other: ''}` reads filled by `some`, satisfies\n // ajv's `required` (a present empty string is present), and went out as an\n // item the runtime cannot use. An untouched row stays an absence and still\n // blocks nothing.\n if (Array.isArray(value))\n return (\n value.every((item) => !isFilled(item) || fieldFilled(field.item, item)) && isFilled(value)\n );\n }\n return isFilled(value);\n}\n\nexport interface Readiness {\n total: number;\n ready: number;\n missing: string[];\n}\n\n/**\n * True when the user must put a value in this field before the run can start.\n *\n * Distinct from `required`, which also drives layout (a required field always\n * shows; an optional one may collapse). A **variable-plural** field stays\n * required - it is a first-class input and keeps its place in the form - but it\n * never gates: a plural slot is never \"absent\" in MTHDS, its empty form IS the\n * empty list, and no method can declare \"at least one item\". A **fixed-count**\n * list (`[N]`) is the exception the wire now states, and it gates like any other\n * slot - there the method HAS ruled the empty form out.\n *\n * **For a field this package built, the answer comes from `inputMustBeFilled`**\n * (`contracts.ts`) - the SAME predicate the method viewer's Run button, its ajv\n * `required` list and its missing-inputs toast all read. `buildRunFields`\n * stamps it onto `gating`. This used to be re-derived here as\n * `required && kind !== 'list'`: the same rule expressed against the MAPPED\n * field instead of the contract, and the two could disagree - `kind` is `'list'`\n * for a `conceptRef` ending in `[]` OR an array schema, while the contract's\n * plural test is the array schema alone, so a plural input carrying a non-array\n * schema gated on one surface and not the other.\n *\n * The shape heuristic survives only as the fallback for a **hand-authored**\n * `RunField` - story fixtures and unit tests, which have no contract to consult\n * and therefore nothing to disagree with. Every field a host renders comes from\n * `buildRunFields` and carries `gating`, so a host is on the contract's answer\n * alone. (The fallback cannot see a fixed count either - one more thing only the\n * contract knows.)\n */\nexport function mustBeFilled(field: RunField): boolean {\n return field.gating ?? (field.required && field.kind !== 'list');\n}\n\n/**\n * How many top-level inputs stand between the current values and a run.\n *\n * Two kinds count, and the second is easy to miss. An input the method DEMANDS\n * counts always (`mustBeFilled`). An input the method left optional counts once\n * the user has put something in it - because a structure that has been touched\n * owes its concept every field the concept declares, and the gate enforces\n * exactly that. Left out, an optional struct opened and half-filled was ignored\n * here and refused there: the button stayed live and the run came back rejected\n * on a required child, which is the same disagreement the demanded case had.\n *\n * So an optional input moves INTO the denominator the moment it is touched, and\n * out of `missing` as soon as it is complete: 3 of 3 while it is untouched, 3\n * of 4 once it is started, 4 of 4 once it is done. `total` answers \"how many\n * things stand between me and Run\", which is the number a host is displaying.\n */\nexport function computeReadiness(fields: RunField[], values: Record<string, unknown>): Readiness {\n const gating = fields.filter((f) => mustBeFilled(f) || isFilled(ownProp(values, f.name)));\n const missing = gating\n .filter((f) => !fieldFilled(f, ownProp(values, f.name)))\n .map((f) => f.title ?? f.name);\n return { total: gating.length, ready: gating.length - missing.length, missing };\n}\n"]}
@@ -0,0 +1,41 @@
1
+ import { dayWithinDateTime } from './chunk-GKV77RAS.js';
2
+
3
+ // src/core/validation-message.ts
4
+ var MAX_SHOWN_VALUE_CHARS = 120;
5
+ function valueAtProperty(data, property) {
6
+ if (!property) return void 0;
7
+ let current = data;
8
+ for (const segment of property.split(".").filter(Boolean)) {
9
+ if (typeof current !== "object" || current === null) return void 0;
10
+ current = current[segment];
11
+ }
12
+ return current;
13
+ }
14
+ function displayValue(value) {
15
+ if (value === void 0 || value === null) return null;
16
+ if (typeof value === "string" && value.trim() === "") return null;
17
+ const text = typeof value === "string" ? value : JSON.stringify(value);
18
+ if (text === void 0) return null;
19
+ return text.length > MAX_SHOWN_VALUE_CHARS ? `${text.slice(0, MAX_SHOWN_VALUE_CHARS)}\u2026` : text;
20
+ }
21
+ function labelOf(error, t) {
22
+ return error.stack?.match(/'([^']+)'/)?.[1] ?? t("inputPanel.aDateField");
23
+ }
24
+ function describeValidationError(error, t, formData) {
25
+ const format = error.params?.format;
26
+ const value = valueAtProperty(formData, error.property);
27
+ const shown = displayValue(value);
28
+ if (error.name === "format" && (format === "date" || format === "date-time")) {
29
+ const label = labelOf(error, t);
30
+ if (shown === null) return t("inputPanel.pickValidDateEmpty", { label });
31
+ const day = format === "date" && typeof value === "string" ? dayWithinDateTime(value) : null;
32
+ if (day !== null) return t("inputPanel.dateCarriesTime", { label, value: shown, day });
33
+ return t("inputPanel.pickValidDate", { label, value: shown });
34
+ }
35
+ const stack = error.stack ?? error.message ?? t("inputPanel.invalidValue");
36
+ return shown === null ? stack : t("inputPanel.invalidValueWithData", { stack, value: shown });
37
+ }
38
+
39
+ export { describeValidationError, displayValue, valueAtProperty };
40
+ //# sourceMappingURL=chunk-RPA7DNSK.js.map
41
+ //# sourceMappingURL=chunk-RPA7DNSK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/validation-message.ts"],"names":[],"mappings":";;;AA4BA,IAAM,qBAAA,GAAwB,GAAA;AA6BvB,SAAS,eAAA,CAAgB,MAAe,QAAA,EAAuC;AACpF,EAAA,IAAI,CAAC,UAAU,OAAO,MAAA;AACtB,EAAA,IAAI,OAAA,GAAmB,IAAA;AACvB,EAAA,KAAA,MAAW,WAAW,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,EAAG;AACzD,IAAA,IAAI,OAAO,OAAA,KAAY,QAAA,IAAY,OAAA,KAAY,MAAM,OAAO,MAAA;AAC5D,IAAA,OAAA,GAAW,QAAoC,OAAO,CAAA;AAAA,EACxD;AACA,EAAA,OAAO,OAAA;AACT;AAOO,SAAS,aAAa,KAAA,EAA+B;AAC1D,EAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM,OAAO,IAAA;AAClD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,MAAM,IAAA,EAAK,KAAM,IAAI,OAAO,IAAA;AAC7D,EAAA,MAAM,OAAO,OAAO,KAAA,KAAU,WAAW,KAAA,GAAQ,IAAA,CAAK,UAAU,KAAK,CAAA;AACrE,EAAA,IAAI,IAAA,KAAS,QAAW,OAAO,IAAA;AAC/B,EAAA,OAAO,IAAA,CAAK,SAAS,qBAAA,GAAwB,CAAA,EAAG,KAAK,KAAA,CAAM,CAAA,EAAG,qBAAqB,CAAC,CAAA,MAAA,CAAA,GAAM,IAAA;AAC5F;AAGA,SAAS,OAAA,CAAQ,OAAsB,CAAA,EAAsB;AAC3D,EAAA,OAAO,KAAA,CAAM,OAAO,KAAA,CAAM,WAAW,IAAI,CAAC,CAAA,IAAK,EAAE,uBAAuB,CAAA;AAC1E;AAUO,SAAS,uBAAA,CACd,KAAA,EACA,CAAA,EACA,QAAA,EACQ;AACR,EAAA,MAAM,MAAA,GAAU,MAAM,MAAA,EAA4C,MAAA;AAClE,EAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,QAAA,EAAU,KAAA,CAAM,QAAQ,CAAA;AACtD,EAAA,MAAM,KAAA,GAAQ,aAAa,KAAK,CAAA;AAEhC,EAAA,IAAI,MAAM,IAAA,KAAS,QAAA,KAAa,MAAA,KAAW,MAAA,IAAU,WAAW,WAAA,CAAA,EAAc;AAC5E,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,EAAO,CAAC,CAAA;AAC9B,IAAA,IAAI,UAAU,IAAA,EAAM,OAAO,EAAE,+BAAA,EAAiC,EAAE,OAAO,CAAA;AAEvE,IAAA,MAAM,GAAA,GAAM,WAAW,MAAA,IAAU,OAAO,UAAU,QAAA,GAAW,iBAAA,CAAkB,KAAK,CAAA,GAAI,IAAA;AACxF,IAAA,IAAI,GAAA,KAAQ,IAAA,EAAM,OAAO,CAAA,CAAE,4BAAA,EAA8B,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,GAAA,EAAK,CAAA;AACrF,IAAA,OAAO,EAAE,0BAAA,EAA4B,EAAE,KAAA,EAAO,KAAA,EAAO,OAAO,CAAA;AAAA,EAC9D;AAEA,EAAA,MAAM,QAAQ,KAAA,CAAM,KAAA,IAAS,KAAA,CAAM,OAAA,IAAW,EAAE,yBAAyB,CAAA;AACzE,EAAA,OAAO,KAAA,KAAU,OAAO,KAAA,GAAQ,CAAA,CAAE,mCAAmC,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,CAAA;AAC9F","file":"chunk-RPA7DNSK.js","sourcesContent":["/**\n * Turning one ajv/RJSF validation error into a line a human can act on.\n *\n * ## Why this isn't just `error.stack`\n *\n * A blocked run used to say \"Date: pick a valid date\" while the date picker\n * showed a perfectly good 06/07/2026. Both were telling the truth about\n * different values: the stored value was `2026-07-06T14:30:00+02:00` (a real\n * time - correctly rejected for a `format: date` field), but\n * `toDateInputValue` renders `.slice(0, 10)` of it, so the FIELD showed the day\n * while the VALIDATOR judged the timestamp. The user cannot reconcile that from\n * the message, because the message named neither value.\n *\n * So: every line here quotes what is ACTUALLY in the data. An error the user\n * can see the input of is one they can fix; an instruction to \"pick a valid\n * date\" for a date that looks valid is not.\n *\n * Kept React-free (the caller passes its `t`) so the wording is unit-testable\n * without mounting the panel.\n */\nimport { dayWithinDateTime } from './date-format';\nimport type { RunInputError } from './gate-validator';\n\n/**\n * A rejected value can be an entire base64 document, and this lands in a toast.\n * Past this many characters the tail is elided - a date never comes close, and\n * a megabyte of base64 in a toast helps nobody understand anything.\n */\nconst MAX_SHOWN_VALUE_CHARS = 120;\n\n/** The message keys this module renders, relative to the caller's namespace\n * (a host passes its own translator for that namespace). */\nexport type ValidationMessageKey =\n | 'inputPanel.aDateField'\n | 'inputPanel.pickValidDate'\n | 'inputPanel.pickValidDateEmpty'\n | 'inputPanel.dateCarriesTime'\n | 'inputPanel.invalidValue'\n | 'inputPanel.invalidValueWithData';\n\n/**\n * The translate function the caller injects. Typed on the EXACT keys this\n * module uses - not a loose `(key: string) => string` - for two reasons: a\n * typo'd key still fails the build here, and next-intl's translator (whose\n * `key` parameter is the namespace's real key union, a SUPERSET of these)\n * remains assignable by parameter contravariance. Kernel-owned: this module\n * must not import next-intl's types.\n */\nexport type Translate = (key: ValidationMessageKey, values?: Record<string, string>) => string;\n\n/**\n * The value the validator actually rejected, read back out of the submitted data.\n *\n * RJSF builds `property` from ajv's `instancePath` by swapping `/` for `.`\n * (`.quote_date.date`), so the segments index straight into the form data.\n * Array indices arrive as digit strings and index arrays natively.\n */\nexport function valueAtProperty(data: unknown, property: string | undefined): unknown {\n if (!property) return undefined;\n let current: unknown = data;\n for (const segment of property.split('.').filter(Boolean)) {\n if (typeof current !== 'object' || current === null) return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n return current;\n}\n\n/**\n * The rejected value rendered for a toast, or `null` when there is nothing\n * worth showing (an absent or blank value - \"you left it empty\" is what the\n * message says on its own, and `“”` adds noise).\n */\nexport function displayValue(value: unknown): string | null {\n if (value === undefined || value === null) return null;\n if (typeof value === 'string' && value.trim() === '') return null;\n const text = typeof value === 'string' ? value : JSON.stringify(value);\n if (text === undefined) return null;\n return text.length > MAX_SHOWN_VALUE_CHARS ? `${text.slice(0, MAX_SHOWN_VALUE_CHARS)}…` : text;\n}\n\n/** The field name ajv quoted in its stack, or a generic stand-in. */\nfunction labelOf(error: RunInputError, t: Translate): string {\n return error.stack?.match(/'([^']+)'/)?.[1] ?? t('inputPanel.aDateField');\n}\n\n/**\n * One validation error as a human line naming the offending value.\n *\n * The date branch is special-cased because ajv's own complaint (`'Date' must\n * match format \"date-time\"`) is opaque, and because the carries-a-time case has\n * a specific fix the user cannot guess: move the time into the sibling `time`\n * field, which is exactly what the runtime's own error says.\n */\nexport function describeValidationError(\n error: RunInputError,\n t: Translate,\n formData: unknown,\n): string {\n const format = (error.params as { format?: string } | undefined)?.format;\n const value = valueAtProperty(formData, error.property);\n const shown = displayValue(value);\n\n if (error.name === 'format' && (format === 'date' || format === 'date-time')) {\n const label = labelOf(error, t);\n if (shown === null) return t('inputPanel.pickValidDateEmpty', { label });\n // Only a `format: date` field rejects a real time; date-time takes it.\n const day = format === 'date' && typeof value === 'string' ? dayWithinDateTime(value) : null;\n if (day !== null) return t('inputPanel.dateCarriesTime', { label, value: shown, day });\n return t('inputPanel.pickValidDate', { label, value: shown });\n }\n\n const stack = error.stack ?? error.message ?? t('inputPanel.invalidValue');\n return shown === null ? stack : t('inputPanel.invalidValueWithData', { stack, value: shown });\n}\n"]}
@@ -0,0 +1,12 @@
1
+ // src/core/own-property.ts
2
+ function ownProp(record, key) {
3
+ if (record == null) return void 0;
4
+ return Object.prototype.hasOwnProperty.call(record, key) ? record[key] : void 0;
5
+ }
6
+ function hasOwnProp(record, key) {
7
+ return record != null && Object.prototype.hasOwnProperty.call(record, key);
8
+ }
9
+
10
+ export { hasOwnProp, ownProp };
11
+ //# sourceMappingURL=chunk-V3OV2XQT.js.map
12
+ //# sourceMappingURL=chunk-V3OV2XQT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/own-property.ts"],"names":[],"mappings":";AAyCO,SAAS,OAAA,CACd,QACA,GAAA,EACe;AACf,EAAA,IAAI,MAAA,IAAU,MAAM,OAAO,MAAA;AAC3B,EAAA,OAAO,MAAA,CAAO,UAAU,cAAA,CAAe,IAAA,CAAK,QAAQ,GAAG,CAAA,GAAI,MAAA,CAAO,GAAG,CAAA,GAAI,MAAA;AAC3E;AAGO,SAAS,UAAA,CAAW,QAAmC,GAAA,EAAsB;AAClF,EAAA,OAAO,UAAU,IAAA,IAAQ,MAAA,CAAO,UAAU,cAAA,CAAe,IAAA,CAAK,QAAQ,GAAG,CAAA;AAC3E","file":"chunk-V3OV2XQT.js","sourcesContent":["/**\n * Read a property a record OWNS, never one it merely inherits.\n *\n * Every name this package indexes a record by - an input variable name, a\n * structure's property name, a pipe code, a concept's content key - is chosen\n * by the METHOD AUTHOR, and the records they index are plain objects the host\n * built (`{}` from a form's state, `JSON.parse` of a request body, a map keyed\n * by pipe ref). A plain object inherits `Object.prototype`, so a name that\n * collides with a prototype member - `constructor`, `toString`, `valueOf`,\n * `hasOwnProperty`, … - does NOT read as `undefined`: it reads as the inherited\n * function, which is truthy.\n *\n * That is a verdict bug wherever a bare read decides one. An input named\n * `constructor` with nothing entered used to resolve to `Object`, which\n * `isFilled` had no branch for and therefore called filled - a live Run button\n * over an empty required input. `getPipeIOContract` returned the same function\n * for a prototype-named pipe code, which sailed past the `if (!contract)` guard\n * hosts are shown writing.\n *\n * What it does NOT close, stated so nobody reads a fixed read as a fixed class:\n * the WRITE twin. `out[name] = value` on a plain object invokes the inherited\n * `__proto__` setter for that one name, so an input actually called `__proto__`\n * is dropped from a payload rather than added to it. That is fail-loud (the\n * runtime rejects a run whose input is missing) where the read bug was\n * fail-open, and `__proto__` is not a name an author writes, so the writes are\n * left plain and legible.\n *\n * Spelled with `Object.prototype.hasOwnProperty.call` rather than `Object.hasOwn`\n * deliberately. `hasOwn` is an ES2022 runtime API and `tsconfig.json` compiles\n * to **ES2020**, so a browser inside the declared target has no such function\n * and every read here would throw before a form could render a single field -\n * a whole-package failure in service of a shorter spelling. TypeScript cannot\n * catch that: `lib` is what types a runtime API, `target` is what states the\n * baseline, and the two are allowed to disagree.\n *\n * Deliberately module-private: this is a spelling of `record[key]`, not a\n * concept a consumer needs. Reachability is low - only a method author picks\n * these names - but the cost of being wrong is a form that says a field is\n * filled when it is empty, so the package spells the read one way everywhere\n * rather than guarding the sites someone happened to notice.\n */\nexport function ownProp<T>(\n record: Record<string, T> | null | undefined,\n key: string,\n): T | undefined {\n if (record == null) return undefined;\n return Object.prototype.hasOwnProperty.call(record, key) ? record[key] : undefined;\n}\n\n/** `key in record` with the prototype chain left out. */\nexport function hasOwnProp(record: object | null | undefined, key: string): boolean {\n return record != null && Object.prototype.hasOwnProperty.call(record, key);\n}\n"]}
@@ -0,0 +1,132 @@
1
+ import { collectSchemaDefs, collapseNullable, derefSchema, schemaTypeOf } from './chunk-O4O3QNVC.js';
2
+ import { isOptionalInput, inputMustBeFilled } from './chunk-HARYEWNG.js';
3
+ import { splitListConcept, FIELD_DOCUMENT_CONCEPTS, IMAGE_CONCEPTS, FIELD_TEXT_CONCEPTS, HTML_CONCEPTS, TEXT_WRAPPER_CONCEPTS, NUMBER_CONCEPTS, YES_NO_CONCEPTS } from './chunk-NMT7BRLO.js';
4
+
5
+ // src/core/derive.ts
6
+ function isDocumentObject(schema) {
7
+ const props = schema.properties;
8
+ return Boolean(props?.url);
9
+ }
10
+ function scalarWrapper(schema, ctx) {
11
+ const props = schema.properties;
12
+ const entries = props ? Object.entries(props) : [];
13
+ const only = entries.length === 1 ? entries[0] : void 0;
14
+ if (!only) return void 0;
15
+ const [key, propSchema] = only;
16
+ return { key, schema: collapseNullable(derefSchema(propSchema ?? {}, ctx.defs)) };
17
+ }
18
+ function mapSchema(name, conceptRef, rawSchema, required, ctx) {
19
+ const schema = collapseNullable(derefSchema(rawSchema, ctx.defs));
20
+ const common = {
21
+ name,
22
+ conceptRef,
23
+ description: typeof schema.description === "string" ? schema.description : void 0,
24
+ required
25
+ };
26
+ const { base, isList } = splitListConcept(conceptRef);
27
+ if (isList || schemaTypeOf(schema) === "array") {
28
+ const itemsSchema = schema.items ?? {};
29
+ const item = mapSchema(name, base, itemsSchema, true, { ...ctx, depth: ctx.depth + 1 });
30
+ const itemCount = numOrUndef(schema.minItems);
31
+ const maxItemCount = numOrUndef(schema.maxItems);
32
+ return {
33
+ ...common,
34
+ kind: "list",
35
+ item,
36
+ ...itemCount === void 0 ? {} : { itemCount },
37
+ ...maxItemCount === void 0 ? {} : { maxItemCount }
38
+ };
39
+ }
40
+ if (Array.isArray(schema.enum)) {
41
+ return { ...common, kind: "enum", options: schema.enum.map(String) };
42
+ }
43
+ if (base) {
44
+ if (FIELD_DOCUMENT_CONCEPTS.has(base))
45
+ return { ...common, kind: "document", accept: "PDF, DOCX, TXT" };
46
+ if (IMAGE_CONCEPTS.has(base)) return { ...common, kind: "image", accept: "PNG, JPG, WEBP" };
47
+ const wrapper = scalarWrapper(schema, ctx);
48
+ if (FIELD_TEXT_CONCEPTS.has(base) || HTML_CONCEPTS.has(base)) {
49
+ const contentKey = wrapper?.key ?? (TEXT_WRAPPER_CONCEPTS.has(base) ? "text" : void 0);
50
+ return ctx.depth === 0 ? { ...common, contentKey, kind: "prose" } : { ...common, contentKey, kind: "text" };
51
+ }
52
+ if (NUMBER_CONCEPTS.has(base))
53
+ return {
54
+ ...common,
55
+ contentKey: wrapper?.key,
56
+ kind: "number",
57
+ // `NumberContent.number` is `int | float`, an unresolvable union, so the
58
+ // control stays a float input. Constraints are read off the WRAPPED
59
+ // property - the wrapper object never carries them, which is why the
60
+ // outer schema always answered `undefined`.
61
+ integer: false,
62
+ min: numOrUndef(wrapper?.schema.minimum ?? schema.minimum),
63
+ max: numOrUndef(wrapper?.schema.maximum ?? schema.maximum)
64
+ };
65
+ if (YES_NO_CONCEPTS.has(base)) return { ...common, contentKey: wrapper?.key, kind: "boolean" };
66
+ }
67
+ if (isDocumentObject(schema)) {
68
+ return { ...common, kind: "document", accept: "PDF, DOCX, TXT" };
69
+ }
70
+ const type = schemaTypeOf(schema);
71
+ switch (type) {
72
+ case "string": {
73
+ if (base && (FIELD_DOCUMENT_CONCEPTS.has(base) || base === "native.Document"))
74
+ return { ...common, kind: "document", accept: "PDF, DOCX, TXT" };
75
+ if (schema.format === "date" || schema.format === "date-time")
76
+ return { ...common, kind: "date", datetime: schema.format === "date-time" };
77
+ const long = base && FIELD_TEXT_CONCEPTS.has(base) ? ctx.depth === 0 : typeof schema.maxLength === "number" ? schema.maxLength > 120 : false;
78
+ return long ? { ...common, kind: "prose" } : { ...common, kind: "text", placeholder: void 0 };
79
+ }
80
+ case "integer":
81
+ return {
82
+ ...common,
83
+ kind: "number",
84
+ integer: true,
85
+ min: numOrUndef(schema.minimum),
86
+ max: numOrUndef(schema.maximum)
87
+ };
88
+ case "number":
89
+ return {
90
+ ...common,
91
+ kind: "number",
92
+ integer: false,
93
+ min: numOrUndef(schema.minimum),
94
+ max: numOrUndef(schema.maximum)
95
+ };
96
+ case "boolean":
97
+ return { ...common, kind: "boolean" };
98
+ case "object": {
99
+ const props = schema.properties ?? {};
100
+ const req = new Set(Array.isArray(schema.required) ? schema.required : []);
101
+ const fields = Object.entries(props).map(
102
+ ([fieldName, fieldSchema]) => mapSchema(fieldName, void 0, fieldSchema, req.has(fieldName), {
103
+ ...ctx,
104
+ depth: ctx.depth + 1
105
+ })
106
+ );
107
+ return { ...common, kind: "object", fields };
108
+ }
109
+ default:
110
+ if (base && FIELD_TEXT_CONCEPTS.has(base))
111
+ return ctx.depth === 0 ? { ...common, kind: "prose" } : { ...common, kind: "text" };
112
+ return { ...common, kind: "unknown" };
113
+ }
114
+ }
115
+ function numOrUndef(v) {
116
+ return typeof v === "number" ? v : void 0;
117
+ }
118
+ function buildRunFields(inputs) {
119
+ return Object.entries(inputs).map(([name, input]) => {
120
+ const defs = {};
121
+ collectSchemaDefs(input.json_schema, defs, { traverseArrays: true });
122
+ const field = mapSchema(name, input.concept_ref, input.json_schema, !isOptionalInput(input), {
123
+ defs,
124
+ depth: 0
125
+ });
126
+ return { ...field, gating: inputMustBeFilled(input) };
127
+ });
128
+ }
129
+
130
+ export { buildRunFields };
131
+ //# sourceMappingURL=chunk-VMLXO5JS.js.map
132
+ //# sourceMappingURL=chunk-VMLXO5JS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/derive.ts"],"names":[],"mappings":"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","file":"chunk-VMLXO5JS.js","sourcesContent":["/**\n * The ONE derivation function: `PipeInputContract` map → `RunField[]`.\n *\n * Everything heuristic stays module-private behind `buildRunFields`: the\n * native-concept taxonomy, `isDocumentObject`, the depth-based prose/label\n * rule, the `accept` strings, list splitting. Nothing here is exported except\n * the function itself - so the M1 milestone can swap the source of the\n * descriptor (server-derived) without touching consumers.\n */\n\nimport { inputMustBeFilled, isOptionalInput, type PipeInputContract } from './contracts';\nimport type { RunField, RunFieldCommon } from './descriptor';\nimport {\n FIELD_DOCUMENT_CONCEPTS,\n FIELD_TEXT_CONCEPTS,\n HTML_CONCEPTS,\n IMAGE_CONCEPTS,\n NUMBER_CONCEPTS,\n splitListConcept,\n TEXT_WRAPPER_CONCEPTS,\n YES_NO_CONCEPTS,\n} from './native-concepts';\nimport {\n collapseNullable,\n collectSchemaDefs,\n derefSchema,\n schemaTypeOf,\n type JsonSchema,\n} from './schema-utils';\n\n// Native concepts arrive as their pydantic wrapper schema (e.g. native.Text is\n// `TextContent {text}`, native.Document is `DocumentContent {url,…}`), NOT a bare\n// primitive - so we map them by concept_ref, before the generic schema-type\n// dispatch, or they'd all render as nested objects. The taxonomy lives in\n// `native-concepts.ts`, which also records where this mapper's view drifts from\n// the wire format's.\n\n/**\n * A url-bearing object renders as a document field. This is `Boolean(\n * schema.properties?.url)` and nothing more: the historical description check\n * (\"storage url\" / \"document url\") was followed by `|| 'url' in props`, which\n * made it unreachable. Stated honestly as the heuristic it is - M1 replaces it\n * with the server-derived descriptor; narrowing it to the description match is\n * a recorded M1 option, not a K1 change.\n */\nfunction isDocumentObject(schema: JsonSchema): boolean {\n const props = schema.properties as Record<string, JsonSchema> | undefined;\n return Boolean(props?.url);\n}\n\ninterface MapCtx {\n defs: Record<string, JsonSchema>;\n depth: number;\n}\n\n/**\n * The single property a pydantic scalar content model holds its value in -\n * `TextContent {text}`, `NumberContent {number}`, `YesNoContent {yes_no}`.\n *\n * A native scalar's value does NOT sit at the top of its declared schema, and\n * this is where that is discovered: from the CONTRACT, not from a hand-kept\n * list of which concepts wrap. Keeping such a list is what broke `native.Number`\n * - the render taxonomy knew the concept, the wrapper taxonomy did not, so a\n * number reached the gate bare and failed against `NumberContent`. Reading the\n * declared shape covers a concept nobody remembered to add.\n *\n * A wrapper is a schema declaring EXACTLY ONE property. A multi-property content\n * model (`DateContent {date, time}`, `HtmlContent {inner_html, css_class}`) is\n * not one and deliberately answers `undefined`; so does a contract that declares\n * no properties at all. The returned `schema` is the WRAPPED property's, which\n * is where its constraints live.\n */\nfunction scalarWrapper(\n schema: JsonSchema,\n ctx: MapCtx,\n): { key: string; schema: JsonSchema } | undefined {\n const props = schema.properties as Record<string, JsonSchema> | undefined;\n const entries = props ? Object.entries(props) : [];\n const only = entries.length === 1 ? entries[0] : undefined;\n if (!only) return undefined;\n const [key, propSchema] = only;\n return { key, schema: collapseNullable(derefSchema(propSchema ?? {}, ctx.defs)) };\n}\n\n/** Build the recursive RunField for a single resolved schema node. */\nfunction mapSchema(\n name: string,\n conceptRef: string | undefined,\n rawSchema: JsonSchema,\n required: boolean,\n ctx: MapCtx,\n): RunField {\n const schema = collapseNullable(derefSchema(rawSchema, ctx.defs));\n // The LABEL is always the stuff name (the variable key) - that's what\n // identifies the input in the method. We deliberately do NOT use\n // `schema.title`, which is the pydantic model name (TextContent, ImageContent,\n // DocumentContent…) and would mask the stuff name. The concept pill carries\n // the type instead. `title` stays undefined here so FieldShell falls back to\n // `name`; list items still pass `title: ''` to suppress the per-row label.\n const common: RunFieldCommon = {\n name,\n conceptRef,\n description: typeof schema.description === 'string' ? schema.description : undefined,\n required,\n };\n\n const { base, isList } = splitListConcept(conceptRef);\n\n // List concepts (native.Text[], demo.Invoice[]) and array schemas.\n if (isList || schemaTypeOf(schema) === 'array') {\n const itemsSchema = (schema.items as JsonSchema) ?? {};\n const item = mapSchema(name, base, itemsSchema, true, { ...ctx, depth: ctx.depth + 1 });\n // A declared count (`Concept[N]`) reaches the descriptor from the schema\n // keywords ajv itself reads - see `ListRunField.itemCount`. BOTH bounds\n // travel, because they are two facts: a `[N]` slot states them equal, but\n // this mapper also walks nested arrays, whose model may have stated only\n // one. Carrying a single number forced readiness and the control to read it\n // as a minimum and a maximum respectively.\n const itemCount = numOrUndef(schema.minItems);\n const maxItemCount = numOrUndef(schema.maxItems);\n return {\n ...common,\n kind: 'list',\n item,\n ...(itemCount === undefined ? {} : { itemCount }),\n ...(maxItemCount === undefined ? {} : { maxItemCount }),\n };\n }\n\n // Enum (a custom concept may refine a native with a fixed value set).\n if (Array.isArray(schema.enum)) {\n return { ...common, kind: 'enum', options: schema.enum.map(String) };\n }\n\n // Native concepts: map by concept_ref regardless of the wrapper schema shape.\n if (base) {\n if (FIELD_DOCUMENT_CONCEPTS.has(base))\n return { ...common, kind: 'document', accept: 'PDF, DOCX, TXT' };\n if (IMAGE_CONCEPTS.has(base)) return { ...common, kind: 'image', accept: 'PNG, JPG, WEBP' };\n\n // The three native scalars render as a bare control but travel inside the\n // content model their concept declares. `contentKey` carries that property\n // name to the value bridge, which is how the control can hold `2` while the\n // wire carries `{number: 2}`.\n const wrapper = scalarWrapper(schema, ctx);\n\n if (FIELD_TEXT_CONCEPTS.has(base) || HTML_CONCEPTS.has(base)) {\n // `Date` declares two properties, so no wrapper is found for it and the\n // `{text}` fallback answers instead - the recorded drift, kept until the\n // derivation swap (see `native-concepts.ts`).\n const contentKey = wrapper?.key ?? (TEXT_WRAPPER_CONCEPTS.has(base) ? 'text' : undefined);\n return ctx.depth === 0\n ? { ...common, contentKey, kind: 'prose' }\n : { ...common, contentKey, kind: 'text' };\n }\n if (NUMBER_CONCEPTS.has(base))\n return {\n ...common,\n contentKey: wrapper?.key,\n kind: 'number',\n // `NumberContent.number` is `int | float`, an unresolvable union, so the\n // control stays a float input. Constraints are read off the WRAPPED\n // property - the wrapper object never carries them, which is why the\n // outer schema always answered `undefined`.\n integer: false,\n min: numOrUndef(wrapper?.schema.minimum ?? schema.minimum),\n max: numOrUndef(wrapper?.schema.maximum ?? schema.maximum),\n };\n if (YES_NO_CONCEPTS.has(base)) return { ...common, contentKey: wrapper?.key, kind: 'boolean' };\n }\n\n // A custom concept whose schema looks like DocumentContent (refines Document).\n if (isDocumentObject(schema)) {\n return { ...common, kind: 'document', accept: 'PDF, DOCX, TXT' };\n }\n\n const type = schemaTypeOf(schema);\n switch (type) {\n case 'string': {\n if (base && (FIELD_DOCUMENT_CONCEPTS.has(base) || base === 'native.Document'))\n return { ...common, kind: 'document', accept: 'PDF, DOCX, TXT' };\n // A `date` structure field compiles to a `format: date`/`date-time`\n // string. Render it as a real date picker so the user picks a day - no\n // hand-typed timestamps - and stores a value the API accepts.\n if (schema.format === 'date' || schema.format === 'date-time')\n return { ...common, kind: 'date', datetime: schema.format === 'date-time' };\n // A top-level Text input is usually the main prompt (roomy textarea); the\n // same concept nested in a concept/list is usually a short attribute\n // (name, label) and reads better as a single line.\n const long =\n base && FIELD_TEXT_CONCEPTS.has(base)\n ? ctx.depth === 0\n : typeof schema.maxLength === 'number'\n ? schema.maxLength > 120\n : false;\n return long\n ? { ...common, kind: 'prose' }\n : { ...common, kind: 'text', placeholder: undefined };\n }\n case 'integer':\n return {\n ...common,\n kind: 'number',\n integer: true,\n min: numOrUndef(schema.minimum),\n max: numOrUndef(schema.maximum),\n };\n case 'number':\n return {\n ...common,\n kind: 'number',\n integer: false,\n min: numOrUndef(schema.minimum),\n max: numOrUndef(schema.maximum),\n };\n case 'boolean':\n return { ...common, kind: 'boolean' };\n case 'object': {\n const props = (schema.properties as Record<string, JsonSchema>) ?? {};\n const req = new Set(Array.isArray(schema.required) ? (schema.required as string[]) : []);\n const fields = Object.entries(props).map(([fieldName, fieldSchema]) =>\n mapSchema(fieldName, undefined, fieldSchema, req.has(fieldName), {\n ...ctx,\n depth: ctx.depth + 1,\n }),\n );\n return { ...common, kind: 'object', fields };\n }\n default:\n // A bare `native.Text` concept may arrive as `{type:'string'}` (handled\n // above) but a custom concept with no resolvable shape lands here.\n if (base && FIELD_TEXT_CONCEPTS.has(base))\n return ctx.depth === 0 ? { ...common, kind: 'prose' } : { ...common, kind: 'text' };\n return { ...common, kind: 'unknown' };\n }\n}\n\nfunction numOrUndef(v: unknown): number | undefined {\n return typeof v === 'number' ? v : undefined;\n}\n\n/**\n * Convert the API's per-input contracts into the runner's field descriptors.\n * The map's insertion order is preserved (required-first is the caller's job).\n */\nexport function buildRunFields(inputs: Record<string, PipeInputContract>): RunField[] {\n return Object.entries(inputs).map(([name, input]) => {\n const defs: Record<string, JsonSchema> = {};\n collectSchemaDefs(input.json_schema, defs, { traverseArrays: true });\n // A top-level input is required unless the method declared it optional (`?`).\n const field = mapSchema(name, input.concept_ref, input.json_schema, !isOptionalInput(input), {\n defs,\n depth: 0,\n });\n // Whether Run gates on it is a SEPARATE question, and it is answered by the\n // contract, not by the shape we mapped it to - see `mustBeFilled`.\n return { ...field, gating: inputMustBeFilled(input) };\n });\n}\n"]}
@@ -0,0 +1,61 @@
1
+ import { isAcceptableDate, isAcceptableDateTime } from './chunk-GKV77RAS.js';
2
+ import Ajv from 'ajv';
3
+ import addFormats from 'ajv-formats';
4
+
5
+ var ajv = new Ajv({
6
+ allErrors: true,
7
+ multipleOfPrecision: 8,
8
+ strict: false,
9
+ verbose: true,
10
+ discriminator: false,
11
+ coerceTypes: true
12
+ });
13
+ addFormats(ajv);
14
+ ajv.addFormat("data-url", /^data:([a-z]+\/[a-z0-9-+.]+)?;(?:name=(.*);)?base64,(.*)$/);
15
+ ajv.addFormat(
16
+ "color",
17
+ /^(#?([0-9A-Fa-f]{3}){1,2}\b|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow|(rgb\(\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*\))|(rgb\(\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*\)))$/
18
+ );
19
+ ajv.addFormat("date", isAcceptableDate);
20
+ ajv.addFormat("date-time", isAcceptableDateTime);
21
+ function validateRunInputsSchema(data, schema) {
22
+ let validate;
23
+ try {
24
+ validate = ajv.compile(schema);
25
+ } catch (err) {
26
+ return [{ stack: err instanceof Error ? err.message : String(err) }];
27
+ }
28
+ validate(data);
29
+ const errors = (validate.errors ?? []).map(toRunInputError);
30
+ validate.errors = null;
31
+ return errors;
32
+ }
33
+ function toRunInputError(e) {
34
+ const { instancePath, keyword, schemaPath, parentSchema } = e;
35
+ const params = e.params;
36
+ const message = e.message ?? "";
37
+ let property = instancePath.replace(/\//g, ".");
38
+ let stack = `${property} ${message}`.trim();
39
+ const namesAProperty = [
40
+ ...typeof params.deps === "string" ? params.deps.split(", ") : [],
41
+ params.missingProperty,
42
+ params.property
43
+ ].some((item) => typeof item === "string" && item.length > 0);
44
+ if (namesAProperty) {
45
+ stack = message;
46
+ } else {
47
+ const parentTitle = parentSchema?.title;
48
+ if (typeof parentTitle === "string" && parentTitle) {
49
+ stack = `'${parentTitle}' ${message}`.trim();
50
+ }
51
+ }
52
+ if ("missingProperty" in params) {
53
+ const missing = String(params.missingProperty);
54
+ property = property ? `${property}.${missing}` : missing;
55
+ }
56
+ return { name: keyword, property, message, params, stack, schemaPath };
57
+ }
58
+
59
+ export { validateRunInputsSchema };
60
+ //# sourceMappingURL=chunk-VTPUDBSJ.js.map
61
+ //# sourceMappingURL=chunk-VTPUDBSJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/gate-validator.ts"],"names":[],"mappings":";;;;AAoDA,IAAM,GAAA,GAAM,IAAI,GAAA,CAAI;AAAA,EAClB,SAAA,EAAW,IAAA;AAAA,EACX,mBAAA,EAAqB,CAAA;AAAA,EACrB,MAAA,EAAQ,KAAA;AAAA,EACR,OAAA,EAAS,IAAA;AAAA,EACT,aAAA,EAAe,KAAA;AAAA,EACf,WAAA,EAAa;AACf,CAAC,CAAA;AACD,UAAA,CAAW,GAAG,CAAA;AACd,GAAA,CAAI,SAAA,CAAU,YAAY,2DAA2D,CAAA;AACrF,GAAA,CAAI,SAAA;AAAA,EACF,OAAA;AAAA,EACA;AACF,CAAA;AAKA,GAAA,CAAI,SAAA,CAAU,QAAQ,gBAAgB,CAAA;AACtC,GAAA,CAAI,SAAA,CAAU,aAAa,oBAAoB,CAAA;AAOxC,SAAS,uBAAA,CAAwB,MAAe,MAAA,EAAiC;AACtF,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI;AACF,IAAA,QAAA,GAAW,GAAA,CAAI,QAAQ,MAAM,CAAA;AAAA,EAC/B,SAAS,GAAA,EAAK;AAGZ,IAAA,OAAO,CAAC,EAAE,KAAA,EAAO,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAA,EAAG,CAAA;AAAA,EACrE;AACA,EAAA,QAAA,CAAS,IAAI,CAAA;AACb,EAAA,MAAM,UAAU,QAAA,CAAS,MAAA,IAAU,EAAC,EAAG,IAAI,eAAe,CAAA;AAC1D,EAAA,QAAA,CAAS,MAAA,GAAS,IAAA;AAClB,EAAA,OAAO,MAAA;AACT;AAIA,SAAS,gBAAgB,CAAA,EAA+B;AACtD,EAAA,MAAM,EAAE,YAAA,EAAc,OAAA,EAAS,UAAA,EAAY,cAAa,GAAI,CAAA;AAC5D,EAAA,MAAM,SAAS,CAAA,CAAE,MAAA;AACjB,EAAA,MAAM,OAAA,GAAU,EAAE,OAAA,IAAW,EAAA;AAC7B,EAAA,IAAI,QAAA,GAAW,YAAA,CAAa,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAC9C,EAAA,IAAI,QAAQ,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,OAAO,GAAG,IAAA,EAAK;AAE1C,EAAA,MAAM,cAAA,GAAiB;AAAA,IACrB,GAAI,OAAO,MAAA,CAAO,IAAA,KAAS,QAAA,GAAW,OAAO,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,GAAI,EAAC;AAAA,IACjE,MAAA,CAAO,eAAA;AAAA,IACP,MAAA,CAAO;AAAA,GACT,CAAE,KAAK,CAAC,IAAA,KAAS,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA;AAE5D,EAAA,IAAI,cAAA,EAAgB;AASlB,IAAA,KAAA,GAAQ,OAAA;AAAA,EACV,CAAA,MAAO;AACL,IAAA,MAAM,cAAe,YAAA,EAAkD,KAAA;AACvE,IAAA,IAAI,OAAO,WAAA,KAAgB,QAAA,IAAY,WAAA,EAAa;AAClD,MAAA,KAAA,GAAQ,CAAA,CAAA,EAAI,WAAW,CAAA,EAAA,EAAK,OAAO,GAAG,IAAA,EAAK;AAAA,IAC7C;AAAA,EACF;AAEA,EAAA,IAAI,qBAAqB,MAAA,EAAQ;AAC/B,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,MAAA,CAAO,eAAe,CAAA;AAC7C,IAAA,QAAA,GAAW,QAAA,GAAW,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA,GAAK,OAAA;AAAA,EACnD;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,UAAU,OAAA,EAAS,MAAA,EAAQ,OAAO,UAAA,EAAW;AACvE","file":"chunk-VTPUDBSJ.js","sourcesContent":["/**\n * The run gate's OWN validator - ajv direct, no RJSF.\n *\n * Until the form-kernel extraction the gate validated through\n * `@rjsf/validator-ajv8` (`rjsf-validator.ts`), which is an RJSF `ValidatorType`\n * wrapper around exactly this: an ajv instance plus an error-shape transform.\n * The kernel must not depend on RJSF, so this module owns both halves directly,\n * configured to reproduce its output but for one deliberate divergence:\n *\n * - the ajv OPTIONS are `@rjsf/validator-ajv8`'s `AJV_CONFIG` plus the same\n * `coerceTypes: true` override this gate has always run with (pydantic runs in\n * lax mode - `\"20\"` is a number, `\"5\"` an int - and rejecting client-side what\n * the runner accepts blocks valid work; see `rjsf-validator.ts`);\n * - the `date` / `date-time` formats are the pydantic-parity predicates from\n * `date-format.ts`, same as before;\n * - `toRunInputError` reproduces RJSF's `transformRJSFValidationErrors` for the\n * no-uiSchema case the gate is: `property` is the dotted instance path (plus\n * the missing property name for `required` errors), and `stack` quotes the\n * parent schema's `title` when the error does not itself name a property.\n *\n * It diverges from RJSF in exactly one place, and deliberately: an error that\n * NAMES a property keeps the property's own name rather than swapping in that\n * property's schema `title`. RJSF substitutes because the title is the label its\n * forms render; this package labels a field by its identifier instead, so the\n * substitution named something the user could not find. See `toRunInputError`.\n */\nimport Ajv, { type ErrorObject } from 'ajv';\nimport addFormats from 'ajv-formats';\nimport { isAcceptableDate, isAcceptableDateTime } from './date-format';\n\n/**\n * One validation error, in the shape hosts read (`property`, `message`,\n * `name`, `stack`, `params.format`). Structurally a superset-compatible twin of\n * RJSF's `RJSFValidationError`, so a host surface still holding RJSF form errors\n * (an RJSF-based inputs panel) can hand them to the same message renderer.\n */\nexport interface RunInputError {\n /** The ajv keyword that failed (`required`, `format`, `type`, …). */\n name?: string;\n /** Dotted path into the form data (`.quote_date.date`); for a `required`\n * error the missing property name is appended (top-level: no leading dot). */\n property?: string;\n message?: string;\n params?: Record<string, unknown>;\n /** The human line: `property message`, or `'title' message` when the parent\n * schema titles the field. */\n stack: string;\n schemaPath?: string;\n}\n\n// The exact instance `@rjsf/validator-ajv8` builds (its AJV_CONFIG + the\n// standard ajv-formats + its two custom formats), plus our two overrides.\nconst ajv = new Ajv({\n allErrors: true,\n multipleOfPrecision: 8,\n strict: false,\n verbose: true,\n discriminator: false,\n coerceTypes: true,\n});\naddFormats(ajv);\najv.addFormat('data-url', /^data:([a-z]+\\/[a-z0-9-+.]+)?;(?:name=(.*);)?base64,(.*)$/);\najv.addFormat(\n 'color',\n /^(#?([0-9A-Fa-f]{3}){1,2}\\b|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow|(rgb\\(\\s*\\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\b\\s*,\\s*\\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\b\\s*,\\s*\\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\b\\s*\\))|(rgb\\(\\s*(\\d?\\d%|100%)+\\s*,\\s*(\\d?\\d%|100%)+\\s*,\\s*(\\d?\\d%|100%)+\\s*\\)))$/,\n);\n// Pydantic-parity leniency, replacing ajv-formats' spec-strict versions: a\n// midnight-padded timestamp IS a date, a bare day IS a date-time. Measured\n// against pydantic in `date-format.ts` - keep in step with the runtime, not\n// with the JSON Schema spec.\najv.addFormat('date', isAcceptableDate);\najv.addFormat('date-time', isAcceptableDateTime);\n\n/**\n * Validate `data` against `schema`, returning mapped errors (empty = valid).\n * MUTATES `data` where ajv coerces (`\"20\"` → `20`) - deliberate and relied on:\n * the string the user typed is stored as a number going forward.\n */\nexport function validateRunInputsSchema(data: unknown, schema: object): RunInputError[] {\n let validate;\n try {\n validate = ajv.compile(schema);\n } catch (err) {\n // A malformed schema produces a verdict-less failure, same as RJSF's\n // `validationError` path: one bare-stack error, nothing to pin on a field.\n return [{ stack: err instanceof Error ? err.message : String(err) }];\n }\n validate(data);\n const errors = (validate.errors ?? []).map(toRunInputError);\n validate.errors = null;\n return errors;\n}\n\n/** RJSF's `transformRJSFValidationErrors`, minus the uiSchema lookups the gate\n * never had (it passes no uiSchema). */\nfunction toRunInputError(e: ErrorObject): RunInputError {\n const { instancePath, keyword, schemaPath, parentSchema } = e;\n const params = e.params as Record<string, unknown>;\n const message = e.message ?? '';\n let property = instancePath.replace(/\\//g, '.');\n let stack = `${property} ${message}`.trim();\n\n const namesAProperty = [\n ...(typeof params.deps === 'string' ? params.deps.split(', ') : []),\n params.missingProperty,\n params.property,\n ].some((item) => typeof item === 'string' && item.length > 0);\n\n if (namesAProperty) {\n // ajv already quotes the property NAME, and that is the name kept - the ONE\n // deliberate divergence from RJSF, which substitutes the parent schema's\n // `properties[name].title` here. That substitution is right in an RJSF form,\n // where the title IS the rendered label; it is wrong for this package, whose\n // controls label a field by its identifier on purpose (see `mapSchema`). A\n // pydantic contract titles `audience` as `Audience`, so the blocked run read\n // `must have required property 'Audience'` and sent the user hunting for a\n // field their bundle does not contain.\n stack = message;\n } else {\n const parentTitle = (parentSchema as { title?: unknown } | undefined)?.title;\n if (typeof parentTitle === 'string' && parentTitle) {\n stack = `'${parentTitle}' ${message}`.trim();\n }\n }\n\n if ('missingProperty' in params) {\n const missing = String(params.missingProperty);\n property = property ? `${property}.${missing}` : missing;\n }\n\n return { name: keyword, property, message, params, stack, schemaPath };\n}\n"]}