@pipelex/mthds-form 0.3.0 → 0.5.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.
- package/README.md +21 -7
- package/dist/chunk-25I6JDIK.js +28 -0
- package/dist/chunk-25I6JDIK.js.map +1 -0
- package/dist/chunk-5Q2W6HBA.js +201 -0
- package/dist/chunk-5Q2W6HBA.js.map +1 -0
- package/dist/chunk-GCXV76WU.js +213 -0
- package/dist/chunk-GCXV76WU.js.map +1 -0
- package/dist/chunk-GKV77RAS.js +46 -0
- package/dist/chunk-GKV77RAS.js.map +1 -0
- package/dist/chunk-IIJRJGZQ.js +128 -0
- package/dist/chunk-IIJRJGZQ.js.map +1 -0
- package/dist/chunk-IM2AHWBR.js +99 -0
- package/dist/chunk-IM2AHWBR.js.map +1 -0
- package/dist/chunk-LBFZXYCY.js +44 -0
- package/dist/chunk-LBFZXYCY.js.map +1 -0
- package/dist/chunk-OD3VYXUY.js +156 -0
- package/dist/chunk-OD3VYXUY.js.map +1 -0
- package/dist/chunk-PM55AHRO.js +52 -0
- package/dist/chunk-PM55AHRO.js.map +1 -0
- package/dist/chunk-RPA7DNSK.js +41 -0
- package/dist/chunk-RPA7DNSK.js.map +1 -0
- package/dist/chunk-V3OV2XQT.js +12 -0
- package/dist/chunk-V3OV2XQT.js.map +1 -0
- package/dist/chunk-VTPUDBSJ.js +61 -0
- package/dist/chunk-VTPUDBSJ.js.map +1 -0
- package/dist/chunk-XYQ7NXQZ.js +31 -0
- package/dist/chunk-XYQ7NXQZ.js.map +1 -0
- package/dist/chunk-YEVVR6FE.js +66 -0
- package/dist/chunk-YEVVR6FE.js.map +1 -0
- package/dist/core/contracts.d.ts +114 -0
- package/dist/core/contracts.js +4 -0
- package/dist/core/contracts.js.map +1 -0
- package/dist/core/date-format.d.ts +87 -0
- package/dist/core/date-format.js +3 -0
- package/dist/core/date-format.js.map +1 -0
- package/dist/core/derive.d.ts +55 -0
- package/dist/core/derive.js +6 -0
- package/dist/core/derive.js.map +1 -0
- package/dist/core/descriptor.d.ts +172 -0
- package/dist/core/descriptor.js +3 -0
- package/dist/core/descriptor.js.map +1 -0
- package/dist/core/gate-validator.d.ts +27 -0
- package/dist/core/gate-validator.js +4 -0
- package/dist/core/gate-validator.js.map +1 -0
- package/dist/core/gate.d.ts +144 -0
- package/dist/core/gate.js +12 -0
- package/dist/core/gate.js.map +1 -0
- package/dist/core/gating-fields.d.ts +38 -0
- package/dist/core/gating-fields.js +6 -0
- package/dist/core/gating-fields.js.map +1 -0
- package/dist/core/index.d.ts +13 -623
- package/dist/core/index.js +14 -1
- package/dist/core/normalize-schema.d.ts +30 -0
- package/dist/core/normalize-schema.js +4 -0
- package/dist/core/normalize-schema.js.map +1 -0
- package/dist/core/own-property.d.ts +46 -0
- package/dist/core/own-property.js +3 -0
- package/dist/core/own-property.js.map +1 -0
- package/dist/core/readiness.d.ts +91 -0
- package/dist/core/readiness.js +4 -0
- package/dist/core/readiness.js.map +1 -0
- package/dist/core/schema-utils.d.ts +86 -0
- package/dist/core/schema-utils.js +3 -0
- package/dist/core/schema-utils.js.map +1 -0
- package/dist/core/validation-message.d.ts +39 -0
- package/dist/core/validation-message.js +4 -0
- package/dist/core/validation-message.js.map +1 -0
- package/dist/core/values.d.ts +98 -0
- package/dist/core/values.js +10 -0
- package/dist/core/values.js.map +1 -0
- package/dist/core/wire-format.d.ts +95 -0
- package/dist/core/wire-format.js +6 -0
- package/dist/core/wire-format.js.map +1 -0
- package/dist/react/index.d.ts +43 -2
- package/dist/react/index.js +166 -64
- package/dist/react/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +7 -1
- package/dist/chunk-S6KOTTGD.js +0 -990
- package/dist/chunk-S6KOTTGD.js.map +0 -1
- package/dist/descriptor-DPrrfAjL.d.ts +0 -101
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/wire-format.ts"],"names":[],"mappings":"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","file":"chunk-GCXV76WU.js","sourcesContent":["/**\n * Converts between the simplified inputs.json format and the full RJSF form format.\n *\n * The inputs.json file uses a SIMPLIFIED format for users:\n * - Text: \"my text\" (instead of { text: \"my text\" })\n * - Document: \"file.pdf\" or { url: \"...\" } (instead of { url: \"...\", ... })\n * - Image: same as Document\n * - Text[]: [\"t1\", \"t2\"]\n * - Document[]: [\"f1.pdf\"] or [{ url: \"...\" }]\n * - Custom: { concept, content } (no simplification)\n *\n * The RJSF form uses the FULL concept structure from the json_schema.\n *\n * Two directions:\n * - deflate: form (full) → inputs.json (simplified) - for writing inputs.json / API calls\n * - inflate: inputs.json (simplified) → form (full) - for populating the form from inputs.json\n */\n\nimport { asCalendarDate } from './date-format';\nimport { hasOwnProp, ownProp } from './own-property';\nimport { collectSchemaDefs, resolveSchemaIndirection, schemaTypeOf } from './schema-utils';\n\n// ─── The wire taxonomy ──────────────────────────────────────────────────────\n//\n// Which native concepts use a SIMPLIFIED wire form is a fact about the\n// runtime's input parser, not about rendering - so this module states it for\n// itself, and it is the one native-concept knowledge left in the package now\n// that the render taxonomy is gone (the field mapper reads the wire descriptor;\n// see docs/derivation-swap.md). `native.Date` and `native.Html` are absent on\n// purpose: both travel through the structured `{ concept, content }` branch,\n// which since the derivation swap carries their REAL content models\n// (`DateContent {date, time}`, `HtmlContent {inner_html, css_class}`) rather\n// than the historical `{text}` drift.\n\n/** Both spellings a concept ref uses: bare (`Text`) and namespaced (`native.Text`). */\nfunction nativeSet(...names: string[]): ReadonlySet<string> {\n return new Set(names.flatMap((n) => [n, `native.${n}`]));\n}\n\n/** Concepts whose simplified wire form is a bare string (`{text} ↔ \"...\"`). */\nconst WIRE_TEXT_CONCEPTS = nativeSet('Text');\n\n/** Concepts whose simplified wire form is a bare URL string. */\nconst WIRE_DOCUMENT_LIKE_CONCEPTS = nativeSet('Document', 'Image', 'Page');\n\nfunction isTextConcept(concept: string): boolean {\n return WIRE_TEXT_CONCEPTS.has(concept);\n}\n\nfunction isDocumentLikeConcept(concept: string): boolean {\n return WIRE_DOCUMENT_LIKE_CONCEPTS.has(concept);\n}\n\n/** A concept ref like `native.Document[]` → base `native.Document`, isList true. */\nfunction isListConcept(conceptCode: string): { isList: boolean; baseConcept: string } {\n if (conceptCode.endsWith('[]')) return { isList: true, baseConcept: conceptCode.slice(0, -2) };\n return { isList: false, baseConcept: conceptCode };\n}\n\n// ─── Deflate: form (full) → inputs.json (simplified) ──────────────────────\n\n/**\n * Convert a single form value to the simplified inputs.json format.\n * Used when writing inputs.json and when calling the run API.\n *\n * Rules:\n * - Text { text: \"hello\" } → \"hello\"\n * - Document { url: \"file.pdf\", ... } → \"file.pdf\" (if only url) or { url, ... }\n * - Image: same as Document\n * - Page: same as Document\n * - List types → array of deflated items\n * - Custom → { concept, content }\n */\nexport function deflateInput(value: unknown, conceptCode: string): unknown {\n const { isList, baseConcept } = isListConcept(conceptCode);\n\n if (isList) {\n const items = Array.isArray(value) ? value : [];\n // pipelex accepts Sequence[str] for list inputs, not list of dicts.\n // Always simplify list items to their scalar form (URL string for docs, plain string for text).\n return items.map((item) => deflateListItem(item, baseConcept));\n }\n\n return deflateSingleValue(value, baseConcept);\n}\n\n/** Deflate a single item within a list - always reduces to the simplest scalar form. */\nfunction deflateListItem(value: unknown, concept: string): unknown {\n if (isTextConcept(concept)) {\n if (value && typeof value === 'object' && 'text' in value) {\n return (value as { text: string }).text;\n }\n return typeof value === 'string' ? value : String(value ?? '');\n }\n\n if (isDocumentLikeConcept(concept)) {\n // Always extract just the URL for list items - pipelex resolves metadata at runtime\n if (value && typeof value === 'object' && 'url' in value) {\n return (value as { url: string }).url;\n }\n if (typeof value === 'string') return value;\n return '';\n }\n\n // Custom structured concept → { concept, content }.\n //\n // IDEMPOTENT ON PURPOSE - see `unwrapAllWrappers`. Wrapping unconditionally\n // corrupted persisted inputs: a host panel seeds the form with the RAW\n // stored value when the input schemas aren't loaded yet (no dry run yet),\n // so the form could hold an ALREADY-wrapped value; the next change deflated\n // it again and saved `{ concept, content: { concept, content: {...} } }`.\n // Wrapping exactly once, whatever we're handed, makes that unreachable.\n return { concept, content: unwrapAllWrappers(value) };\n}\n\nfunction deflateSingleValue(value: unknown, concept: string): unknown {\n if (isTextConcept(concept)) {\n // { text: \"hello\" } → \"hello\"\n if (value && typeof value === 'object' && 'text' in value) {\n return (value as { text: string }).text;\n }\n // Already a string (passthrough)\n return typeof value === 'string' ? value : String(value ?? '');\n }\n\n if (isDocumentLikeConcept(concept)) {\n // Always extract just the URL - pipelex resolves metadata at runtime.\n // A bare dict without a 'concept' key is rejected by StuffFactory.\n if (value && typeof value === 'object' && 'url' in value) {\n return (value as { url: string }).url;\n }\n // Already a string URL (passthrough)\n if (typeof value === 'string') return value;\n return '';\n }\n\n // Custom structured concept → { concept, content }.\n //\n // IDEMPOTENT ON PURPOSE - see `unwrapAllWrappers`. Wrapping unconditionally\n // corrupted persisted inputs: a host panel seeds the form with the RAW\n // stored value when the input schemas aren't loaded yet (no dry run yet),\n // so the form could hold an ALREADY-wrapped value; the next change deflated\n // it again and saved `{ concept, content: { concept, content: {...} } }`.\n // Wrapping exactly once, whatever we're handed, makes that unreachable.\n return { concept, content: unwrapAllWrappers(value) };\n}\n\n// ─── Inflate: inputs.json (simplified) → form (full) ──────────────────────\n\n/**\n * Convert a simplified inputs.json value to the full form structure.\n * Used when populating the RJSF form from inputs.json.\n *\n * Rules:\n * - \"hello\" → { text: \"hello\" } (for Text concepts)\n * - \"file.pdf\" → { url: \"file.pdf\" } (for Document/Image/Page concepts)\n * - { url: \"...\" } → passthrough (already full)\n * - [\"t1\", \"t2\"] → inflated array of items\n * - { concept, content } → content (for custom concepts)\n */\nexport function inflateInput(value: unknown, conceptCode: string): unknown {\n const { isList, baseConcept } = isListConcept(conceptCode);\n\n if (isList) {\n // The sandbox may write the wrapped form at the LIST level:\n // { concept: \"native.Document\", content: [item, item] } - pipelex accepts it.\n // Unwrap before the array check, otherwise the wrapper itself gets treated\n // as a single list item and inflates to one empty entry.\n const unwrapped = isWrappedForm(value) ? value.content : value;\n // Handle: array (correct), single object (legacy/form default), or null/undefined\n let items: unknown[];\n if (Array.isArray(unwrapped)) {\n items = unwrapped;\n } else if (unwrapped != null && typeof unwrapped === 'object') {\n // Single object instead of array (e.g., {\"url\": \"\"} from form default) - wrap it\n items = [unwrapped];\n } else {\n items = [];\n }\n return items.map((item) => inflateSingleValue(item, baseConcept));\n }\n\n return inflateSingleValue(value, baseConcept);\n}\n\n/** Known optional fields on DocumentContent (from pipelex Pydantic model). */\nconst DOCUMENT_FIELDS = new Set(['url', 'public_url', 'mime_type', 'filename', 'title', 'snippet']);\n\n/** Returns true if the object looks like a DocumentContent (has any known doc field). */\nfunction looksLikeDocument(obj: Record<string, unknown>): boolean {\n return Object.keys(obj).some((k) => DOCUMENT_FIELDS.has(k));\n}\n\n/**\n * Detect the fully-qualified wrapper form `{ concept: \"...\", content: ... }`.\n * pipelex accepts this for any concept (native or custom), and the mthds-inputs\n * agent skill writes it by default for disambiguation. We unwrap before applying\n * concept-specific inflation so the form populates correctly.\n */\nfunction isWrappedForm(value: unknown): value is { concept: string; content: unknown } {\n return (\n !!value &&\n typeof value === 'object' &&\n 'concept' in value &&\n 'content' in value &&\n typeof (value as { concept: unknown }).concept === 'string'\n );\n}\n\nfunction inflateSingleValue(value: unknown, concept: string): unknown {\n // Unwrap { concept, content } for native concepts - the content IS the value.\n // For custom concepts we unwrap below (historical behaviour) but after concept-specific checks.\n if (isWrappedForm(value) && (isTextConcept(concept) || isDocumentLikeConcept(concept))) {\n return inflateSingleValue(value.content, concept);\n }\n\n if (isTextConcept(concept)) {\n // \"hello\" → { text: \"hello\" }\n if (typeof value === 'string') {\n return { text: value };\n }\n // Already full structure { text: \"...\" }\n if (value && typeof value === 'object' && 'text' in value) {\n return value;\n }\n return { text: '' };\n }\n\n if (isDocumentLikeConcept(concept)) {\n // \"file.pdf\" → { url: \"file.pdf\" }\n if (typeof value === 'string') {\n return { url: value };\n }\n // Already full structure { url: \"...\" }\n if (value && typeof value === 'object' && 'url' in value) {\n return value;\n }\n // Object without url key but with other document fields (e.g. from RJSF defaults)\n // Ensure the required url field is present\n if (value && typeof value === 'object' && looksLikeDocument(value as Record<string, unknown>)) {\n return { ...(value as Record<string, unknown>), url: '' };\n }\n return { url: '' };\n }\n\n // Custom structured: unwrap { concept, content } → content.\n //\n // Unwrap REPEATEDLY. `deflateSingleValue` used to wrap unconditionally, so a\n // form change made while the input schemas weren't loaded yet re-wrapped an\n // already-wrapped value and persisted `{ concept, content: { concept,\n // content: {...} } }` to DynamoDB. Unwrapping a single level left the FORM\n // holding `{ concept, content }` - properties no schema declares, so RJSF\n // matched nothing and rendered every field empty, with the real values\n // sitting one level deeper. Deflate is idempotent now, but the corrupted\n // shape survives in persisted inputData, so this heals it on read.\n return unwrapAllWrappers(value);\n}\n\n/** Strip every `{ concept, content }` layer - one, or the double wrap a\n * non-idempotent deflate persisted. */\nfunction unwrapAllWrappers(value: unknown): unknown {\n let current = value;\n while (isWrappedForm(current)) {\n current = current.content;\n }\n // A `{ content }` with no `concept` is the historical half-wrapper.\n if (current && typeof current === 'object' && !Array.isArray(current) && 'content' in current) {\n return (current as { content: unknown }).content;\n }\n return current;\n}\n\n// ─── Schema helpers ─────────────────────────────────────────────────────\n\ninterface InputSchema {\n concept_ref: string;\n json_schema?: Record<string, unknown>;\n}\n\n/**\n * The validation API returns concept_ref WITHOUT the [] suffix for list inputs.\n * The array-ness is only encoded in json_schema.type === \"array\".\n * This helper resolves the correct concept ref by checking the schema.\n */\nexport function resolveConceptCode(schema: InputSchema): string {\n const code = schema.concept_ref;\n // Defensive: a malformed/partial contract entry (missing concept) must\n // degrade, never throw and blank the whole input panel.\n if (!code) return '';\n if (!code.endsWith('[]') && (schema.json_schema as Record<string, unknown>)?.type === 'array') {\n return code + '[]';\n }\n return code;\n}\n\n// ─── Batch helpers for full inputData objects ────────────────────────────\n\n/**\n * Deflate all inputs from form format to simplified inputs.json format.\n * Used by InputConfigPanel when preparing data for the run API.\n */\nexport function deflateAllInputs(\n formData: Record<string, unknown>,\n inputSchemas: Record<string, InputSchema>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [stuffName, schema] of Object.entries(inputSchemas)) {\n result[stuffName] = deflateInput(ownProp(formData, stuffName), resolveConceptCode(schema));\n }\n return result;\n}\n\n/**\n * Heal values against their json_schema: the run-form bridge used to\n * double-wrap plain string properties as `{ text: \"...\" }` (fixed in\n * run-values.ts, but the corrupted shape survives in persisted inputData -\n * store and server copies). Wherever the schema expects a string but the\n * value is a lone `{ text: string }` wrapper, unwrap it. Walks nested\n * objects and arrays, resolving `#/$defs/...` refs against the root schema;\n * anything already valid passes through untouched.\n */\nexport function healStringWrappers(\n value: unknown,\n rawSchema: Record<string, unknown> | undefined,\n defs?: Record<string, Record<string, unknown>>,\n): unknown {\n if (!rawSchema || value == null) return value;\n\n // Resolve $ref / nullable-anyOf indirection (Pydantic emits `{$ref}` for\n // nested models and `anyOf: [T, {type:'null'}]` for optionals). The `$defs`\n // walk deliberately keeps its historical no-array-traversal mode - see\n // `CollectDefsOptions` in schema-utils.\n const allDefs = defs ?? collectSchemaDefs(rawSchema, {}, { traverseArrays: false });\n const schema = resolveSchemaIndirection(rawSchema, allDefs);\n const type = schemaTypeOf(schema);\n\n // A `format: date` field takes a calendar date ALONE. `DateContent` in pipelex\n // enforces that with a `mode=\"before\"` validator (`_reject_lax_temporal`) that\n // deliberately closes pydantic's lax coercion - a datetime string on `date`\n // would silently drop its time and offset (DT3, \"no silent midnight\"), so the\n // runner answers a 500, not a coercion.\n //\n // An agent-written or hand-written inputs.json says `\"2026-07-06T00:00:00Z\"`\n // anyway - that is how every system exports a date. So NORMALIZE it here to\n // the day it denotes rather than forwarding it to fail at the runner: the\n // padding is noise, and dropping noise is not the fidelity loss DT3 forbids.\n // A value carrying a REAL time (15:40) returns null and is left untouched -\n // it must fail, because silently discarding it is precisely the corruption\n // the rule exists to prevent.\n if (type === 'string' && schema.format === 'date' && typeof value === 'string') {\n return asCalendarDate(value) ?? value;\n }\n\n if (type === 'string') {\n if (\n typeof value === 'object' &&\n !Array.isArray(value) &&\n Object.keys(value).length === 1 &&\n typeof (value as { text?: unknown }).text === 'string'\n ) {\n return (value as { text: string }).text;\n }\n return value;\n }\n if (type === 'object' && typeof value === 'object' && !Array.isArray(value)) {\n const props = schema.properties as Record<string, Record<string, unknown>> | undefined;\n if (!props) return value;\n const out = { ...(value as Record<string, unknown>) };\n for (const [key, propSchema] of Object.entries(props)) {\n if (hasOwnProp(out, key)) out[key] = healStringWrappers(out[key], propSchema, allDefs);\n }\n return out;\n }\n if (type === 'array' && Array.isArray(value)) {\n const items = schema.items as Record<string, unknown> | undefined;\n return value.map((item) => healStringWrappers(item, items, allDefs));\n }\n return value;\n}\n\n/** Nothing left worth sending, once this value has itself been pruned. */\nfunction isEmptyAfterPruning(value: unknown): boolean {\n if (value === '' || value === null || value === undefined) return true;\n // An object whose every property was itself pruned away carries nothing, and\n // that is what an untouched OPTIONAL STRUCTURED input looks like by the time\n // it reaches here - a shell of empty children, emptied out. Keeping the `{}`\n // handed it to ajv against the concept's full schema, which rejected the run\n // for a required child of an input the method said may be omitted. Dropping\n // it is the same judgement the wire payload already makes one step later\n // (`apiInputsFromSchemaData` omits it as unfilled); making the prune agree is\n // what stops the gate from failing a run it was about to omit anyway.\n //\n // An empty ARRAY is deliberately NOT empty: a plural slot is never absent in\n // MTHDS - its empty form IS the empty list - so dropping it would invent an\n // absence the method cannot express.\n return typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0;\n}\n\n/**\n * Drop optional properties the user never filled, so an untouched field cannot\n * fail validation or reach the API as an empty string.\n *\n * RJSF fills EVERY unset string property with `\"\"` on mount. That is harmless\n * for a plain string, but `prepareSchemaForRjsf` collapses pydantic's\n * `anyOf: [T, null]` by dropping the null branch, so an optional *constrained*\n * field - `DateContent.time`, declared `datetime.time | None` and rendered\n * `{ type: \"string\", format: \"time\" }` - is left demanding a well-formed time.\n * `\"\"` is not one, and the run was blocked on a field the user never opened.\n *\n * Pruning is the semantically correct repair, not a validation dodge: for\n * pipelex an absent optional field IS `None`, and `\"\"` would fail pydantic at\n * the runner just as it fails ajv here. Only properties absent from their\n * parent's `required` are dropped - an empty REQUIRED field must still fail, so\n * the user is told about it.\n *\n * What counts as empty is `isEmptyAfterPruning`, and it includes an optional\n * STRUCTURE the user never opened, on exactly the same grounds.\n */\nexport function pruneEmptyOptionals(\n value: unknown,\n rawSchema: Record<string, unknown> | undefined,\n defs?: Record<string, Record<string, unknown>>,\n): unknown {\n if (!rawSchema || value == null) return value;\n\n const allDefs = defs ?? collectSchemaDefs(rawSchema, {}, { traverseArrays: false });\n const schema = resolveSchemaIndirection(rawSchema, allDefs);\n const type = schemaTypeOf(schema);\n\n if (type === 'array' && Array.isArray(value)) {\n const items = schema.items as Record<string, unknown> | undefined;\n return value.map((item) => pruneEmptyOptionals(item, items, allDefs));\n }\n if (type !== 'object' || typeof value !== 'object' || Array.isArray(value)) return value;\n\n const props = schema.properties as Record<string, Record<string, unknown>> | undefined;\n if (!props) return value;\n const required = new Set(Array.isArray(schema.required) ? (schema.required as string[]) : []);\n const out: Record<string, unknown> = {};\n for (const [key, raw] of Object.entries(value as Record<string, unknown>)) {\n const propSchema = ownProp(props, key);\n if (!propSchema) {\n out[key] = raw;\n continue;\n }\n const pruned = pruneEmptyOptionals(raw, propSchema, allDefs);\n if (isEmptyAfterPruning(pruned) && !required.has(key)) continue;\n out[key] = pruned;\n }\n return out;\n}\n\n/**\n * Inflate all inputs from simplified inputs.json format to form format.\n * Used by onInputUpdate when receiving inputs.json changes from the sandbox.\n */\nexport function inflateAllInputs(\n simplifiedData: Record<string, unknown>,\n inputSchemas: Record<string, InputSchema>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [stuffName, value] of Object.entries(simplifiedData)) {\n const schema = ownProp(inputSchemas, stuffName);\n if (schema) {\n result[stuffName] = healStringWrappers(\n inflateInput(value, resolveConceptCode(schema)),\n schema.json_schema,\n );\n } else {\n // Unknown input - pass through unchanged\n result[stuffName] = value;\n }\n }\n return result;\n}\n"]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// src/core/date-format.ts
|
|
2
|
+
var FULL_DATE_RE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
3
|
+
var ZERO_TIME_DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})[T ]00:00(?::00(?:\.0+)?)?(?:Z|z|[+-]\d{2}:?\d{2})?$/;
|
|
4
|
+
var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?(?:Z|z|[+-]\d{2}:?\d{2})?$/;
|
|
5
|
+
function isRealCalendarDate(value) {
|
|
6
|
+
const match = FULL_DATE_RE.exec(value);
|
|
7
|
+
if (!match) return false;
|
|
8
|
+
const [year, month, day] = [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
9
|
+
if (month < 1 || month > 12) return false;
|
|
10
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
11
|
+
return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
|
|
12
|
+
}
|
|
13
|
+
function asCalendarDate(value) {
|
|
14
|
+
if (isRealCalendarDate(value)) return value;
|
|
15
|
+
const zeroTime = ZERO_TIME_DATE_TIME_RE.exec(value);
|
|
16
|
+
if (zeroTime && isRealCalendarDate(zeroTime[1])) return zeroTime[1];
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
function dayWithinDateTime(value) {
|
|
20
|
+
if (asCalendarDate(value) !== null) return null;
|
|
21
|
+
const match = DATE_TIME_RE.exec(value);
|
|
22
|
+
if (!match || !isRealCalendarDate(match[1])) return null;
|
|
23
|
+
return match[1];
|
|
24
|
+
}
|
|
25
|
+
function isAcceptableDate(value) {
|
|
26
|
+
return isRealCalendarDate(value);
|
|
27
|
+
}
|
|
28
|
+
function isAcceptableDateTime(value) {
|
|
29
|
+
if (isRealCalendarDate(value)) return true;
|
|
30
|
+
const match = DATE_TIME_RE.exec(value);
|
|
31
|
+
if (!match || !isRealCalendarDate(match[1])) return false;
|
|
32
|
+
const [hours, minutes, seconds] = [Number(match[2]), Number(match[3]), Number(match[4] ?? 0)];
|
|
33
|
+
return hours <= 23 && minutes <= 59 && seconds <= 59;
|
|
34
|
+
}
|
|
35
|
+
function toDateInputValue(value) {
|
|
36
|
+
if (typeof value !== "string") return "";
|
|
37
|
+
return asCalendarDate(value) ?? value.slice(0, 10);
|
|
38
|
+
}
|
|
39
|
+
function toStoredDateValue(day, datetime) {
|
|
40
|
+
if (!day) return void 0;
|
|
41
|
+
return datetime ? `${day}T00:00:00Z` : day;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { asCalendarDate, dayWithinDateTime, isAcceptableDate, isAcceptableDateTime, toDateInputValue, toStoredDateValue };
|
|
45
|
+
//# sourceMappingURL=chunk-GKV77RAS.js.map
|
|
46
|
+
//# sourceMappingURL=chunk-GKV77RAS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/date-format.ts"],"names":[],"mappings":";AAqCA,IAAM,YAAA,GAAe,2BAAA;AAOrB,IAAM,sBAAA,GACJ,0EAAA;AAGF,IAAM,YAAA,GACJ,0FAAA;AAGF,SAAS,mBAAmB,KAAA,EAAwB;AAClD,EAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,IAAA,CAAK,KAAK,CAAA;AACrC,EAAA,IAAI,CAAC,OAAO,OAAO,KAAA;AACnB,EAAA,MAAM,CAAC,MAAM,KAAA,EAAO,GAAG,IAAI,CAAC,MAAA,CAAO,MAAM,CAAC,CAAC,GAAG,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA,EAAG,OAAO,KAAA,CAAM,CAAC,CAAC,CAAC,CAAA;AAChF,EAAA,IAAI,KAAA,GAAQ,CAAA,IAAK,KAAA,GAAQ,EAAA,EAAI,OAAO,KAAA;AACpC,EAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,IAAA,CAAK,IAAI,IAAA,EAAM,KAAA,GAAQ,CAAA,EAAG,GAAG,CAAC,CAAA;AACpD,EAAA,OACE,IAAA,CAAK,cAAA,EAAe,KAAM,IAAA,IAAQ,IAAA,CAAK,WAAA,EAAY,KAAM,KAAA,GAAQ,CAAA,IAAK,IAAA,CAAK,UAAA,EAAW,KAAM,GAAA;AAEhG;AAQO,SAAS,eAAe,KAAA,EAA8B;AAC3D,EAAA,IAAI,kBAAA,CAAmB,KAAK,CAAA,EAAG,OAAO,KAAA;AACtC,EAAA,MAAM,QAAA,GAAW,sBAAA,CAAuB,IAAA,CAAK,KAAK,CAAA;AAClD,EAAA,IAAI,QAAA,IAAY,mBAAmB,QAAA,CAAS,CAAC,CAAE,CAAA,EAAG,OAAO,SAAS,CAAC,CAAA;AACnE,EAAA,OAAO,IAAA;AACT;AAeO,SAAS,kBAAkB,KAAA,EAA8B;AAC9D,EAAA,IAAI,cAAA,CAAe,KAAK,CAAA,KAAM,IAAA,EAAM,OAAO,IAAA;AAC3C,EAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,IAAA,CAAK,KAAK,CAAA;AACrC,EAAA,IAAI,CAAC,SAAS,CAAC,kBAAA,CAAmB,MAAM,CAAC,CAAE,GAAG,OAAO,IAAA;AACrD,EAAA,OAAO,MAAM,CAAC,CAAA;AAChB;AAoBO,SAAS,iBAAiB,KAAA,EAAwB;AACvD,EAAA,OAAO,mBAAmB,KAAK,CAAA;AACjC;AAGO,SAAS,qBAAqB,KAAA,EAAwB;AAC3D,EAAA,IAAI,kBAAA,CAAmB,KAAK,CAAA,EAAG,OAAO,IAAA;AACtC,EAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,IAAA,CAAK,KAAK,CAAA;AACrC,EAAA,IAAI,CAAC,SAAS,CAAC,kBAAA,CAAmB,MAAM,CAAC,CAAE,GAAG,OAAO,KAAA;AACrD,EAAA,MAAM,CAAC,OAAO,OAAA,EAAS,OAAO,IAAI,CAAC,MAAA,CAAO,MAAM,CAAC,CAAC,GAAG,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA,EAAG,OAAO,KAAA,CAAM,CAAC,CAAA,IAAK,CAAC,CAAC,CAAA;AAC5F,EAAA,OAAO,KAAA,IAAS,EAAA,IAAM,OAAA,IAAW,EAAA,IAAM,OAAA,IAAW,EAAA;AACpD;AAGO,SAAS,iBAAiB,KAAA,EAAmC;AAClE,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,EAAA;AACtC,EAAA,OAAO,eAAe,KAAK,CAAA,IAAK,KAAA,CAAM,KAAA,CAAM,GAAG,EAAE,CAAA;AACnD;AAOO,SAAS,iBAAA,CAAkB,KAAa,QAAA,EAAuC;AACpF,EAAA,IAAI,CAAC,KAAK,OAAO,MAAA;AACjB,EAAA,OAAO,QAAA,GAAW,CAAA,EAAG,GAAG,CAAA,UAAA,CAAA,GAAe,GAAA;AACzC","file":"chunk-GKV77RAS.js","sourcesContent":["/**\n * Pure conversions between a stored date value and what a native `<input\n * type=\"date\">` shows, plus the leniency rules our schema validation uses.\n * Kept React-free so both the runner's `DateField` and the RJSF `DateWidget`\n * share one source of truth (and it's trivially unit-tested).\n *\n * Two schema shapes reach us, and they are NOT interchangeable:\n * - an MTHDS `type = \"date\"` structure field compiles to `format: date-time`,\n * so its value round-trips as a full RFC 3339 timestamp;\n * - `native.Date`'s own `date` field is a python `datetime.date`, i.e.\n * `format: date` - a bare `YYYY-MM-DD`.\n *\n * ## Why these rules exist\n *\n * The runtime (pydantic) is LENIENT in both directions, and our client used to\n * be stricter than the contract it was enforcing: `ajv`'s stock `format: \"date\"`\n * accepts a bare `YYYY-MM-DD` and nothing else, so a hand-written\n * `\"2026-07-06T00:00:00Z\"` in an `inputs.json` was rejected here even though\n * pydantic accepts it happily and coerces it to `date(2026, 7, 6)`. The run\n * never even reached the runner. These predicates mirror pydantic exactly\n * (measured, not assumed):\n *\n * format: date \"2026-07-06\" -> date(2026, 7, 6)\n * \"2026-07-06T00:00:00Z\" -> date(2026, 7, 6)\n * \"2026-07-06T00:00:00+02:00\" -> date(2026, 7, 6) (literal date, no UTC shift)\n * \"2026-07-06T15:40:00Z\" -> REJECTED \"should have zero time\"\n * format: date-time \"2026-07-06\" -> datetime(2026, 7, 6, 0, 0)\n * \"2026-07-06T00:00:00Z\" -> datetime(2026, 7, 6, 0, 0, tz)\n *\n * A midnight-padded timestamp is unambiguously \"just a day\", so take it. A real\n * time is data - refusing it is the point (`DateContentError`: \"no silent\n * midnight\"), because silently dropping 15:40 corrupts the value. And an\n * ambiguous `06/07/2026` is never accepted by anyone: 6 July or June 7 depends\n * on who's reading, and guessing wrong fails silently.\n */\n\n/** `YYYY-MM-DD`, no time. */\nconst FULL_DATE_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/**\n * A datetime whose clock reads exactly zero - optional seconds, optional\n * all-zero fraction, optional `Z`/offset. `00:00:01` and `00:00:00.001` do NOT\n * match: they carry a real time.\n */\nconst ZERO_TIME_DATE_TIME_RE =\n /^(\\d{4}-\\d{2}-\\d{2})[T ]00:00(?::00(?:\\.0+)?)?(?:Z|z|[+-]\\d{2}:?\\d{2})?$/;\n\n/** Any RFC 3339-ish datetime we can hand to the runtime as a date-time. */\nconst DATE_TIME_RE =\n /^(\\d{4}-\\d{2}-\\d{2})[T ](\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d+)?)?(?:Z|z|[+-]\\d{2}:?\\d{2})?$/;\n\n/** Guards against `2026-02-30` - a well-formed string that isn't a real day. */\nfunction isRealCalendarDate(value: string): boolean {\n const match = FULL_DATE_RE.exec(value);\n if (!match) return false;\n const [year, month, day] = [Number(match[1]), Number(match[2]), Number(match[3])];\n if (month < 1 || month > 12) return false;\n const date = new Date(Date.UTC(year, month - 1, day));\n return (\n date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day\n );\n}\n\n/**\n * The calendar day a value denotes, or `null` when it doesn't denote one.\n * Accepts a bare date or a midnight-padded timestamp; the day is taken\n * LITERALLY from the string (never shifted through a timezone), matching\n * pydantic - `2026-07-06T00:00:00+02:00` is 2026-07-06, not the 5th.\n */\nexport function asCalendarDate(value: string): string | null {\n if (isRealCalendarDate(value)) return value;\n const zeroTime = ZERO_TIME_DATE_TIME_RE.exec(value);\n if (zeroTime && isRealCalendarDate(zeroTime[1]!)) return zeroTime[1]!;\n return null;\n}\n\n/**\n * The calendar day inside a value that carries a REAL time - precisely the case\n * `asCalendarDate` refuses. `null` when the value isn't a timestamp at all, or\n * when it IS already an acceptable day (nothing to report).\n *\n * This exists to EXPLAIN, never to coerce. `2026-07-06T14:30:00+02:00` is\n * rejected for a `format: date` field, and the rejection is right (DT3, \"no\n * silent midnight\" - dropping 14:30 corrupts the value). But telling the user\n * \"pick a valid date\" while the picker shows them a perfectly good 06/07/2026\n * reads as a lie: `toDateInputValue` renders the day, the stored value carries\n * the time, and only one of those is what gets validated. Naming both the value\n * we hold and the day it would have to become is what makes the error legible.\n */\nexport function dayWithinDateTime(value: string): string | null {\n if (asCalendarDate(value) !== null) return null;\n const match = DATE_TIME_RE.exec(value);\n if (!match || !isRealCalendarDate(match[1]!)) return null;\n return match[1]!;\n}\n\n/**\n * What `format: \"date\"` accepts: a bare `YYYY-MM-DD`, and nothing else.\n *\n * DO NOT relax this to take a midnight-padded timestamp. `DateContent` in\n * pipelex carries a `mode=\"before\"` field validator (`_reject_lax_temporal`)\n * that deliberately CLOSES pydantic's lax coercion for exactly this case:\n *\n * \"A Date's `date` field takes a calendar date alone; a string carrying a\n * time (e.g. '2026-07-07T00:00:00') would drop it - put the time and offset\n * in `time` instead.\"\n *\n * That rule (DT3, \"no silent midnight\") is the concept's whole point, so a\n * lenient client here does not help anyone: it just forwards the value and the\n * runner answers with a 500 instead of the field saying so up front.\n *\n * The leniency belongs in `asCalendarDate` - normalize the pasted timestamp to\n * the day it denotes, then this passes. Accept-and-fix, not accept-and-forward.\n */\nexport function isAcceptableDate(value: string): boolean {\n return isRealCalendarDate(value);\n}\n\n/** What `format: \"date-time\"` should accept - a bare day is midnight. */\nexport function isAcceptableDateTime(value: string): boolean {\n if (isRealCalendarDate(value)) return true;\n const match = DATE_TIME_RE.exec(value);\n if (!match || !isRealCalendarDate(match[1]!)) return false;\n const [hours, minutes, seconds] = [Number(match[2]), Number(match[3]), Number(match[4] ?? 0)];\n return hours <= 23 && minutes <= 59 && seconds <= 59;\n}\n\n/** The `YYYY-MM-DD` a native date input shows, from any stored date/date-time. */\nexport function toDateInputValue(value: string | undefined): string {\n if (typeof value !== 'string') return '';\n return asCalendarDate(value) ?? value.slice(0, 10);\n}\n\n/**\n * The value to store for a picked day. A `date-time` field becomes midnight-UTC\n * (`2026-07-06T00:00:00Z`); a plain `date` field keeps the bare `YYYY-MM-DD`.\n * An empty day clears the value.\n */\nexport function toStoredDateValue(day: string, datetime: boolean): string | undefined {\n if (!day) return undefined;\n return datetime ? `${day}T00:00:00Z` : day;\n}\n"]}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { collectSchemaDefs, resolveSchemaNode } from './chunk-OD3VYXUY.js';
|
|
2
|
+
import { buildPipeRef } from './chunk-XYQ7NXQZ.js';
|
|
3
|
+
import { ownProp } from './chunk-V3OV2XQT.js';
|
|
4
|
+
|
|
5
|
+
// src/core/derive.ts
|
|
6
|
+
function getPipeInputForm(inputForm, domain, pipeCode) {
|
|
7
|
+
if (!inputForm || !pipeCode) return void 0;
|
|
8
|
+
if (domain) {
|
|
9
|
+
const byRef = ownProp(inputForm, buildPipeRef(domain, pipeCode));
|
|
10
|
+
if (byRef) return byRef;
|
|
11
|
+
}
|
|
12
|
+
return ownProp(inputForm, pipeCode);
|
|
13
|
+
}
|
|
14
|
+
function scalarWrapperKey(schema) {
|
|
15
|
+
const props = schema?.properties;
|
|
16
|
+
const keys = props ? Object.keys(props) : [];
|
|
17
|
+
return keys.length === 1 ? keys[0] : void 0;
|
|
18
|
+
}
|
|
19
|
+
function numOrUndef(v) {
|
|
20
|
+
return typeof v === "number" ? v : void 0;
|
|
21
|
+
}
|
|
22
|
+
function inclusiveFrom(bound, integer, toNearest) {
|
|
23
|
+
return typeof bound === "number" && integer === true ? toNearest(bound) : void 0;
|
|
24
|
+
}
|
|
25
|
+
function resolveSchema(schema, defs) {
|
|
26
|
+
return schema ? resolveSchemaNode(schema, defs) : void 0;
|
|
27
|
+
}
|
|
28
|
+
function commonOf(node, name) {
|
|
29
|
+
return {
|
|
30
|
+
name,
|
|
31
|
+
title: node.title,
|
|
32
|
+
conceptRef: node.concept_ref,
|
|
33
|
+
refines: node.refines,
|
|
34
|
+
description: node.description,
|
|
35
|
+
required: node.required,
|
|
36
|
+
defaultValue: node.default_value,
|
|
37
|
+
examples: node.examples,
|
|
38
|
+
hints: node.hints
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function mapNode(node, name, rawSchema, defs) {
|
|
42
|
+
const schema = resolveSchema(rawSchema, defs);
|
|
43
|
+
const common = commonOf(node, name);
|
|
44
|
+
switch (node.kind) {
|
|
45
|
+
case "text":
|
|
46
|
+
case "prose":
|
|
47
|
+
return {
|
|
48
|
+
...common,
|
|
49
|
+
contentKey: scalarWrapperKey(schema),
|
|
50
|
+
kind: node.kind,
|
|
51
|
+
minLength: node.min_length,
|
|
52
|
+
maxLength: node.max_length,
|
|
53
|
+
pattern: node.pattern,
|
|
54
|
+
format: node.format
|
|
55
|
+
};
|
|
56
|
+
case "date":
|
|
57
|
+
return { ...common, kind: "date", datetime: node.datetime };
|
|
58
|
+
case "number":
|
|
59
|
+
return {
|
|
60
|
+
...common,
|
|
61
|
+
contentKey: scalarWrapperKey(schema),
|
|
62
|
+
kind: "number",
|
|
63
|
+
integer: node.integer,
|
|
64
|
+
// A number control clamps; it does not express open intervals. So an
|
|
65
|
+
// exclusive bound becomes the nearest inclusive one where that is
|
|
66
|
+
// exact (integers) and is dropped where it is not (floats) - never
|
|
67
|
+
// the excluded endpoint itself, which the control would clamp onto
|
|
68
|
+
// and the gate would then refuse. ajv enforces the exact keyword off
|
|
69
|
+
// the schema either way, so the bound is a hint, never the rule.
|
|
70
|
+
min: node.minimum ?? inclusiveFrom(
|
|
71
|
+
node.exclusive_minimum,
|
|
72
|
+
node.integer,
|
|
73
|
+
(endpoint) => Math.floor(endpoint) + 1
|
|
74
|
+
),
|
|
75
|
+
max: node.maximum ?? inclusiveFrom(
|
|
76
|
+
node.exclusive_maximum,
|
|
77
|
+
node.integer,
|
|
78
|
+
(endpoint) => Math.ceil(endpoint) - 1
|
|
79
|
+
)
|
|
80
|
+
};
|
|
81
|
+
case "boolean":
|
|
82
|
+
return { ...common, contentKey: scalarWrapperKey(schema), kind: "boolean" };
|
|
83
|
+
case "enum":
|
|
84
|
+
return { ...common, kind: "enum", options: node.choices.map(String) };
|
|
85
|
+
case "document":
|
|
86
|
+
return { ...common, kind: "document", accept: "PDF, DOCX, TXT" };
|
|
87
|
+
case "image":
|
|
88
|
+
return { ...common, kind: "image", accept: "PNG, JPG, WEBP" };
|
|
89
|
+
case "object": {
|
|
90
|
+
const props = schema?.properties;
|
|
91
|
+
return {
|
|
92
|
+
...common,
|
|
93
|
+
kind: "object",
|
|
94
|
+
fields: node.fields.map(
|
|
95
|
+
(child) => mapNode(child, child.name, props ? ownProp(props, child.name) : void 0, defs)
|
|
96
|
+
)
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
case "list": {
|
|
100
|
+
const item = mapNode(node.item, name, schema?.items, defs);
|
|
101
|
+
const itemCount = node.item_count ?? numOrUndef(schema?.minItems);
|
|
102
|
+
const maxItemCount = numOrUndef(schema?.maxItems) ?? node.item_count;
|
|
103
|
+
return {
|
|
104
|
+
...common,
|
|
105
|
+
kind: "list",
|
|
106
|
+
item,
|
|
107
|
+
...itemCount === void 0 ? {} : { itemCount },
|
|
108
|
+
...maxItemCount === void 0 ? {} : { maxItemCount }
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
case "unknown":
|
|
112
|
+
return { ...common, kind: "unknown" };
|
|
113
|
+
}
|
|
114
|
+
return { ...common, kind: "unknown" };
|
|
115
|
+
}
|
|
116
|
+
function buildRunFields(descriptor, inputs) {
|
|
117
|
+
return descriptor.fields.map((node) => {
|
|
118
|
+
const input = ownProp(inputs, node.name);
|
|
119
|
+
const defs = {};
|
|
120
|
+
if (input) collectSchemaDefs(input.json_schema, defs, { traverseArrays: true });
|
|
121
|
+
const field = mapNode(node, node.name, input?.json_schema, defs);
|
|
122
|
+
return { ...field, presence: node.presence, gating: node.gating };
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export { buildRunFields, getPipeInputForm };
|
|
127
|
+
//# sourceMappingURL=chunk-IIJRJGZQ.js.map
|
|
128
|
+
//# sourceMappingURL=chunk-IIJRJGZQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/derive.ts"],"names":[],"mappings":";;;;;AA6CO,SAAS,gBAAA,CACd,SAAA,EACA,MAAA,EACA,QAAA,EACqC;AACrC,EAAA,IAAI,CAAC,SAAA,IAAa,CAAC,QAAA,EAAU,OAAO,MAAA;AACpC,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAM,QAAQ,OAAA,CAAQ,SAAA,EAAW,YAAA,CAAa,MAAA,EAAQ,QAAQ,CAAC,CAAA;AAC/D,IAAA,IAAI,OAAO,OAAO,KAAA;AAAA,EACpB;AACA,EAAA,OAAO,OAAA,CAAQ,WAAW,QAAQ,CAAA;AACpC;AAaA,SAAS,iBAAiB,MAAA,EAAoD;AAC5E,EAAA,MAAM,QAAQ,MAAA,EAAQ,UAAA;AACtB,EAAA,MAAM,OAAO,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,KAAK,IAAI,EAAC;AAC3C,EAAA,OAAO,IAAA,CAAK,MAAA,KAAW,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA,GAAI,MAAA;AACvC;AAEA,SAAS,WAAW,CAAA,EAAgC;AAClD,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,GAAW,CAAA,GAAI,MAAA;AACrC;AAWA,SAAS,aAAA,CACP,KAAA,EACA,OAAA,EACA,SAAA,EACoB;AACpB,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,YAAY,IAAA,GAAO,SAAA,CAAU,KAAK,CAAA,GAAI,MAAA;AAC5E;AAKA,SAAS,aAAA,CACP,QACA,IAAA,EACwB;AACxB,EAAA,OAAO,MAAA,GAAS,iBAAA,CAAkB,MAAA,EAAQ,IAAI,CAAA,GAAI,MAAA;AACpD;AAGA,SAAS,QAAA,CAAS,MAAqB,IAAA,EAA8B;AACnE,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,OAAO,IAAA,CAAK,KAAA;AAAA,IACZ,YAAY,IAAA,CAAK,WAAA;AAAA,IACjB,SAAS,IAAA,CAAK,OAAA;AAAA,IACd,aAAa,IAAA,CAAK,WAAA;AAAA,IAClB,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,cAAc,IAAA,CAAK,aAAA;AAAA,IACnB,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,OAAO,IAAA,CAAK;AAAA,GACd;AACF;AAQA,SAAS,OAAA,CACP,IAAA,EACA,IAAA,EACA,SAAA,EACA,IAAA,EACU;AACV,EAAA,MAAM,MAAA,GAAS,aAAA,CAAc,SAAA,EAAW,IAAI,CAAA;AAC5C,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,IAAA,EAAM,IAAI,CAAA;AAElC,EAAA,QAAQ,KAAK,IAAA;AAAM,IACjB,KAAK,MAAA;AAAA,IACL,KAAK,OAAA;AACH,MAAA,OAAO;AAAA,QACL,GAAG,MAAA;AAAA,QACH,UAAA,EAAY,iBAAiB,MAAM,CAAA;AAAA,QACnC,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,WAAW,IAAA,CAAK,UAAA;AAAA,QAChB,WAAW,IAAA,CAAK,UAAA;AAAA,QAChB,SAAS,IAAA,CAAK,OAAA;AAAA,QACd,QAAQ,IAAA,CAAK;AAAA,OACf;AAAA,IACF,KAAK,MAAA;AACH,MAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,MAAM,MAAA,EAAQ,QAAA,EAAU,KAAK,QAAA,EAAS;AAAA,IAC5D,KAAK,QAAA;AACH,MAAA,OAAO;AAAA,QACL,GAAG,MAAA;AAAA,QACH,UAAA,EAAY,iBAAiB,MAAM,CAAA;AAAA,QACnC,IAAA,EAAM,QAAA;AAAA,QACN,SAAS,IAAA,CAAK,OAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOd,GAAA,EACE,KAAK,OAAA,IACL,aAAA;AAAA,UACE,IAAA,CAAK,iBAAA;AAAA,UACL,IAAA,CAAK,OAAA;AAAA,UACL,CAAC,QAAA,KAAa,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA,GAAI;AAAA,SACvC;AAAA,QACF,GAAA,EACE,KAAK,OAAA,IACL,aAAA;AAAA,UACE,IAAA,CAAK,iBAAA;AAAA,UACL,IAAA,CAAK,OAAA;AAAA,UACL,CAAC,QAAA,KAAa,IAAA,CAAK,IAAA,CAAK,QAAQ,CAAA,GAAI;AAAA;AACtC,OACJ;AAAA,IACF,KAAK,SAAA;AACH,MAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,UAAA,EAAY,iBAAiB,MAAM,CAAA,EAAG,MAAM,SAAA,EAAU;AAAA,IAC5E,KAAK,MAAA;AAGH,MAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,IAAA,EAAM,MAAA,EAAQ,SAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,EAAE;AAAA,IACtE,KAAK,UAAA;AAGH,MAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,IAAA,EAAM,UAAA,EAAY,QAAQ,gBAAA,EAAiB;AAAA,IACjE,KAAK,OAAA;AACH,MAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,IAAA,EAAM,OAAA,EAAS,QAAQ,gBAAA,EAAiB;AAAA,IAC9D,KAAK,QAAA,EAAU;AACb,MAAA,MAAM,QAAQ,MAAA,EAAQ,UAAA;AACtB,MAAA,OAAO;AAAA,QACL,GAAG,MAAA;AAAA,QACH,IAAA,EAAM,QAAA;AAAA,QACN,MAAA,EAAQ,KAAK,MAAA,CAAO,GAAA;AAAA,UAAI,CAAC,KAAA,KACvB,OAAA,CAAQ,KAAA,EAAO,KAAA,CAAM,IAAA,EAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,EAAO,KAAA,CAAM,IAAI,CAAA,GAAI,QAAW,IAAI;AAAA;AACjF,OACF;AAAA,IACF;AAAA,IACA,KAAK,MAAA,EAAQ;AAGX,MAAA,MAAM,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,IAAA,EAAM,MAAA,EAAQ,OAAiC,IAAI,CAAA;AACnF,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,UAAA,IAAc,UAAA,CAAW,QAAQ,QAAQ,CAAA;AAChE,MAAA,MAAM,YAAA,GAAe,UAAA,CAAW,MAAA,EAAQ,QAAQ,KAAK,IAAA,CAAK,UAAA;AAC1D,MAAA,OAAO;AAAA,QACL,GAAG,MAAA;AAAA,QACH,IAAA,EAAM,MAAA;AAAA,QACN,IAAA;AAAA,QACA,GAAI,SAAA,KAAc,MAAA,GAAY,EAAC,GAAI,EAAE,SAAA,EAAU;AAAA,QAC/C,GAAI,YAAA,KAAiB,MAAA,GAAY,EAAC,GAAI,EAAE,YAAA;AAAa,OACvD;AAAA,IACF;AAAA,IACA,KAAK,SAAA;AACH,MAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAU;AAAA;AAYxC,EAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAU;AACtC;AAYO,SAAS,cAAA,CACd,YACA,MAAA,EACY;AACZ,EAAA,OAAO,UAAA,CAAW,MAAA,CAAO,GAAA,CAAI,CAAC,IAAA,KAAS;AACrC,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,MAAA,EAAQ,IAAA,CAAK,IAAI,CAAA;AACvC,IAAA,MAAM,OAAmC,EAAC;AAC1C,IAAA,IAAI,KAAA,oBAAyB,KAAA,CAAM,WAAA,EAAa,MAAM,EAAE,cAAA,EAAgB,MAAM,CAAA;AAC9E,IAAA,MAAM,QAAQ,OAAA,CAAQ,IAAA,EAAM,KAAK,IAAA,EAAM,KAAA,EAAO,aAAuC,IAAI,CAAA;AACzF,IAAA,OAAO,EAAE,GAAG,KAAA,EAAO,QAAA,EAAU,KAAK,QAAA,EAAU,MAAA,EAAQ,KAAK,MAAA,EAAO;AAAA,EAClE,CAAC,CAAA;AACH","file":"chunk-IIJRJGZQ.js","sourcesContent":["/**\n * The ONE derivation function: wire input-form descriptor → `RunField[]`.\n *\n * `buildRunFields` maps the standard's per-pipe descriptor STRUCTURALLY onto\n * the kernel's `RunField` shape. It decides nothing: what a field IS - its\n * kind, its constraints, its refinement chain, whether Run gates on it - is\n * stated by the wire, derived by the engine from the resolved library. The\n * heuristics that used to live here (native-concept sets, the url-bearing\n * object test, the depth-based prose/label rule) are deleted, not bypassed;\n * docs/derivation-swap.md is the record of that swap and of every behaviour\n * that moved with it.\n *\n * The contract is still consulted, for exactly two facts the wire deliberately\n * does not carry:\n *\n * - **`contentKey`** - the single property a native scalar's value sits inside\n * on the wire (`TextContent {text}`, `NumberContent {number}`). A renderer\n * holds the bare scalar; the value bridge wraps by this name. It is read off\n * the contract's `json_schema` because it is a fact about the PAYLOAD shape,\n * which is the schema's job - the descriptor describes the form, never the\n * payload.\n * - **Nested list bounds** - the wire puts `item_count` only on a top-level\n * fixed `[N]` slot, but the model behind a structured concept may state\n * `minItems`/`maxItems` on an array property of its own, and ajv enforces\n * them. Reading them off the schema is what keeps readiness from being more\n * permissive than the gate.\n *\n * Both are structural reads (a property count, two keywords ajv itself\n * enforces), not judgements - the mapper stays honest about owning no taxonomy.\n */\n\nimport type { PipeInputFormDescriptor } from 'mthds/protocol';\nimport type { InputForm, InputFormField, InputFormItem } from 'mthds/protocol';\n\nimport { buildPipeRef, type PipeInputContract } from './contracts';\nimport type { RunField, RunFieldCommon } from './descriptor';\nimport { ownProp } from './own-property';\nimport { collectSchemaDefs, resolveSchemaNode, type JsonSchema } from './schema-utils';\n\n/**\n * Look up a pipe's input-form descriptor by pipe code, tolerant of both key\n * conventions - the exact mirror of `getPipeIOContract`, because the standard\n * keys `input_form` by the same `pipe_ref` set as `pipe_io_contracts` and a\n * host tracks the same bare codes either way.\n */\nexport function getPipeInputForm(\n inputForm: InputForm | null | undefined,\n domain: string | null | undefined,\n pipeCode: string | null | undefined,\n): PipeInputFormDescriptor | undefined {\n if (!inputForm || !pipeCode) return undefined;\n if (domain) {\n const byRef = ownProp(inputForm, buildPipeRef(domain, pipeCode));\n if (byRef) return byRef;\n }\n return ownProp(inputForm, pipeCode);\n}\n\n/**\n * The single property a scalar content model holds its value in - `TextContent\n * {text}`, `NumberContent {number}`, `YesNoContent {yes_no}`.\n *\n * A wrapper is a schema declaring EXACTLY ONE property. A multi-property\n * content model (`DateContent {date, time}`, `HtmlContent {inner_html,\n * css_class}`) is not one and deliberately answers `undefined` - those travel\n * as the structures they are, which the wire now also says by giving them\n * `kind: \"object\"`. Reading the declared shape rather than keeping a list of\n * wrapping concepts is what covers a concept nobody remembered to add.\n */\nfunction scalarWrapperKey(schema: JsonSchema | undefined): string | undefined {\n const props = schema?.properties as Record<string, JsonSchema> | undefined;\n const keys = props ? Object.keys(props) : [];\n return keys.length === 1 ? keys[0] : undefined;\n}\n\nfunction numOrUndef(v: unknown): number | undefined {\n return typeof v === 'number' ? v : undefined;\n}\n\n/** The inclusive bound a control can express for a wire-stated exclusive one.\n * On an integer the open interval has a nearest neighbour and the conversion\n * is exact (`> 0` IS `>= 1`), so `toNearest` steps off the endpoint onto it.\n * It rounds rather than adding one, because the endpoint need not be integral\n * - JSON Schema allows `> 0.5` on an integer node, whose nearest neighbour is\n * `1`, not `1.5`. On a float the interval has no nearest neighbour, and the\n * answer is to publish no bound at all: a control that only clamps cannot\n * express an open interval, and naming the excluded endpoint would advertise\n * the one value the gate is about to refuse. */\nfunction inclusiveFrom(\n bound: number | undefined,\n integer: boolean | undefined,\n toNearest: (endpoint: number) => number,\n): number | undefined {\n return typeof bound === 'number' && integer === true ? toNearest(bound) : undefined;\n}\n\n/** Resolve one schema node the same way the gate's validator will see it -\n * to the FIXPOINT, so a nullable `$ref` (pydantic's Optional concept-typed\n * field) yields its definition rather than an unresolved reference. */\nfunction resolveSchema(\n schema: JsonSchema | undefined,\n defs: Record<string, JsonSchema>,\n): JsonSchema | undefined {\n return schema ? resolveSchemaNode(schema, defs) : undefined;\n}\n\n/** The slots every wire node carries, mapped onto the descriptor's names. */\nfunction commonOf(node: InputFormItem, name: string): RunFieldCommon {\n return {\n name,\n title: node.title,\n conceptRef: node.concept_ref,\n refines: node.refines,\n description: node.description,\n required: node.required,\n defaultValue: node.default_value,\n examples: node.examples,\n hints: node.hints,\n };\n}\n\n/**\n * Map one wire node onto a `RunField`, walking the aligned `json_schema` node\n * beside it. The schema walk supplies only `contentKey` and list bounds (see\n * the module header); a missing or misaligned schema degrades to their absence,\n * never to a different field.\n */\nfunction mapNode(\n node: InputFormItem,\n name: string,\n rawSchema: JsonSchema | undefined,\n defs: Record<string, JsonSchema>,\n): RunField {\n const schema = resolveSchema(rawSchema, defs);\n const common = commonOf(node, name);\n\n switch (node.kind) {\n case 'text':\n case 'prose':\n return {\n ...common,\n contentKey: scalarWrapperKey(schema),\n kind: node.kind,\n minLength: node.min_length,\n maxLength: node.max_length,\n pattern: node.pattern,\n format: node.format,\n };\n case 'date':\n return { ...common, kind: 'date', datetime: node.datetime };\n case 'number':\n return {\n ...common,\n contentKey: scalarWrapperKey(schema),\n kind: 'number',\n integer: node.integer,\n // A number control clamps; it does not express open intervals. So an\n // exclusive bound becomes the nearest inclusive one where that is\n // exact (integers) and is dropped where it is not (floats) - never\n // the excluded endpoint itself, which the control would clamp onto\n // and the gate would then refuse. ajv enforces the exact keyword off\n // the schema either way, so the bound is a hint, never the rule.\n min:\n node.minimum ??\n inclusiveFrom(\n node.exclusive_minimum,\n node.integer,\n (endpoint) => Math.floor(endpoint) + 1,\n ),\n max:\n node.maximum ??\n inclusiveFrom(\n node.exclusive_maximum,\n node.integer,\n (endpoint) => Math.ceil(endpoint) - 1,\n ),\n };\n case 'boolean':\n return { ...common, contentKey: scalarWrapperKey(schema), kind: 'boolean' };\n case 'enum':\n // The wire carries the authored `choices` verbatim (`unknown[]`); the\n // control set renders and stores strings, as it always has.\n return { ...common, kind: 'enum', options: node.choices.map(String) };\n case 'document':\n // `accept` is a renderer-side affordance the wire deliberately does not\n // state - a presentation default keyed on the WIRE's kind, not a guess.\n return { ...common, kind: 'document', accept: 'PDF, DOCX, TXT' };\n case 'image':\n return { ...common, kind: 'image', accept: 'PNG, JPG, WEBP' };\n case 'object': {\n const props = schema?.properties as Record<string, JsonSchema> | undefined;\n return {\n ...common,\n kind: 'object',\n fields: node.fields.map((child: InputFormField) =>\n mapNode(child, child.name, props ? ownProp(props, child.name) : undefined, defs),\n ),\n };\n }\n case 'list': {\n // The item keeps the parent's name (unused for labels - the index labels\n // items), exactly as the wire's `item` carries no `name` of its own.\n const item = mapNode(node.item, name, schema?.items as JsonSchema | undefined, defs);\n const itemCount = node.item_count ?? numOrUndef(schema?.minItems);\n const maxItemCount = numOrUndef(schema?.maxItems) ?? node.item_count;\n return {\n ...common,\n kind: 'list',\n item,\n ...(itemCount === undefined ? {} : { itemCount }),\n ...(maxItemCount === undefined ? {} : { maxItemCount }),\n };\n }\n case 'unknown':\n return { ...common, kind: 'unknown' };\n }\n // Version drift: the wire states a kind this build's pinned peer does not\n // define. The switch above is exhaustive over `InputFormItem`, so\n // `satisfies never` keeps the build LOUD when the PEER grows a kind - and\n // this return keeps the mapper TOTAL when a SERVER is ahead of the peer,\n // which no type can rule out. The standard's own escape hatch is the honest\n // answer (`unknown` exists so a derivation can be total truthfully): the\n // field keeps its name and falls back to raw entry against the contract's\n // `json_schema`. Returning nothing produced a field with no `name` at all -\n // unaddressable by the value bridge and unnameable by readiness.\n node satisfies never;\n return { ...common, kind: 'unknown' };\n}\n\n/**\n * Map a pipe's wire input-form descriptor onto the kernel's field descriptors,\n * with the pipe's input contracts beside it for the two schema-derived facts.\n *\n * The order is the DESCRIPTOR's - authored input order, the fact the contract's\n * `inputs` map deliberately does not carry. `required`, `presence` and `gating`\n * are taken from the wire verbatim: the standard's top-level type ties\n * `required` to the presence marker, and `gating` is the producer-derived\n * answer `mustBeFilled` reads - the kernel re-derives none of them.\n */\nexport function buildRunFields(\n descriptor: PipeInputFormDescriptor,\n inputs: Record<string, PipeInputContract>,\n): RunField[] {\n return descriptor.fields.map((node) => {\n const input = ownProp(inputs, node.name);\n const defs: Record<string, JsonSchema> = {};\n if (input) collectSchemaDefs(input.json_schema, defs, { traverseArrays: true });\n const field = mapNode(node, node.name, input?.json_schema as JsonSchema | undefined, defs);\n return { ...field, presence: node.presence, gating: node.gating };\n });\n}\n"]}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { prepareSchemaForRjsf } from './chunk-LBFZXYCY.js';
|
|
2
|
+
import { pruneEmptyOptionals, healStringWrappers } from './chunk-GCXV76WU.js';
|
|
3
|
+
import { isFilled, mustBeFilled, fieldFilled } from './chunk-PM55AHRO.js';
|
|
4
|
+
import { validateRunInputsSchema } from './chunk-VTPUDBSJ.js';
|
|
5
|
+
import { gatingFieldsFromInputs } from './chunk-YEVVR6FE.js';
|
|
6
|
+
import { inputMustBeFilled, isOptionalInput, isPluralInput } from './chunk-XYQ7NXQZ.js';
|
|
7
|
+
import { ownProp } from './chunk-V3OV2XQT.js';
|
|
8
|
+
|
|
9
|
+
// src/core/gate.ts
|
|
10
|
+
function buildRunInputsSchema(inputs) {
|
|
11
|
+
const properties = {};
|
|
12
|
+
const required = [];
|
|
13
|
+
for (const [varName, input] of Object.entries(inputs)) {
|
|
14
|
+
const inputSchema = { ...input.json_schema };
|
|
15
|
+
inputSchema.title = varName;
|
|
16
|
+
if (input.concept_ref && input.concept_ref !== varName) {
|
|
17
|
+
inputSchema.description = input.concept_ref;
|
|
18
|
+
}
|
|
19
|
+
properties[varName] = inputSchema;
|
|
20
|
+
if (inputMustBeFilled(input)) required.push(varName);
|
|
21
|
+
}
|
|
22
|
+
return prepareSchemaForRjsf({ type: "object", properties, required });
|
|
23
|
+
}
|
|
24
|
+
function prepareRunInputs(data, schema) {
|
|
25
|
+
return pruneEmptyOptionals(healStringWrappers(data, schema), schema);
|
|
26
|
+
}
|
|
27
|
+
function validateRunInputs(preparedData, inputs, schema) {
|
|
28
|
+
const errors = validateRunInputsSchema(preparedData, schema);
|
|
29
|
+
if (errors.length === 0) return { isValid: true, missingInputs: [], errors: [] };
|
|
30
|
+
const record0 = typeof preparedData === "object" && preparedData !== null && !Array.isArray(preparedData) ? preparedData : void 0;
|
|
31
|
+
const missingInputs = [];
|
|
32
|
+
for (const [varName, input] of Object.entries(inputs)) {
|
|
33
|
+
if (!inputMustBeFilled(input)) continue;
|
|
34
|
+
const varData = ownProp(record0, varName);
|
|
35
|
+
if (varData == null) {
|
|
36
|
+
missingInputs.push(varName);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const inputSchema = input.json_schema;
|
|
40
|
+
const requiredFields = inputSchema.required || [];
|
|
41
|
+
if (requiredFields.length === 0) continue;
|
|
42
|
+
if (typeof varData !== "object") {
|
|
43
|
+
missingInputs.push(varName);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const record = varData;
|
|
47
|
+
if (requiredFields.some((f) => {
|
|
48
|
+
const child = ownProp(record, f);
|
|
49
|
+
return child === void 0 || child === "";
|
|
50
|
+
})) {
|
|
51
|
+
missingInputs.push(varName);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { isValid: false, missingInputs, errors };
|
|
55
|
+
}
|
|
56
|
+
function apiInputsFromSchemaData(preparedData, inputs) {
|
|
57
|
+
const out = {};
|
|
58
|
+
for (const [varName, input] of Object.entries(inputs)) {
|
|
59
|
+
const raw = ownProp(preparedData, varName);
|
|
60
|
+
if (isOptionalInput(input) && !isFilled(raw)) continue;
|
|
61
|
+
if (isPluralInput(input) && !isFilled(raw)) {
|
|
62
|
+
out[varName] = [];
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const content = isPluralInput(input) && !Array.isArray(raw) ? [] : raw;
|
|
66
|
+
out[varName] = { concept: input.concept_ref, content };
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
var SCHEMA_CACHE = /* @__PURE__ */ new WeakMap();
|
|
71
|
+
function schemaForContract(contract) {
|
|
72
|
+
const cached = SCHEMA_CACHE.get(contract);
|
|
73
|
+
if (cached) return cached;
|
|
74
|
+
const schema = buildRunInputsSchema(contract.inputs);
|
|
75
|
+
SCHEMA_CACHE.set(contract, schema);
|
|
76
|
+
return schema;
|
|
77
|
+
}
|
|
78
|
+
function gateRunInputs(contract, data) {
|
|
79
|
+
const isRecord = typeof data === "object" && data !== null && !Array.isArray(data);
|
|
80
|
+
const payload = isRecord ? data : {};
|
|
81
|
+
const schema = schemaForContract(contract);
|
|
82
|
+
const preparedData = prepareRunInputs(payload, schema);
|
|
83
|
+
const verdict = validateRunInputs(isRecord ? preparedData : data, contract.inputs, schema);
|
|
84
|
+
if (!verdict.isValid) {
|
|
85
|
+
return {
|
|
86
|
+
ok: false,
|
|
87
|
+
missingInputs: verdict.missingInputs,
|
|
88
|
+
errors: verdict.errors,
|
|
89
|
+
preparedData
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const missingInputs = gatingFieldsFromInputs(contract.inputs).filter((field) => mustBeFilled(field) || isFilled(ownProp(preparedData, field.name))).filter((field) => !fieldFilled(field, ownProp(preparedData, field.name))).map((field) => field.name);
|
|
93
|
+
if (missingInputs.length) return { ok: false, missingInputs, errors: [], preparedData };
|
|
94
|
+
return { ok: true, inputs: apiInputsFromSchemaData(preparedData, contract.inputs) };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export { apiInputsFromSchemaData, buildRunInputsSchema, gateRunInputs, prepareRunInputs, validateRunInputs };
|
|
98
|
+
//# sourceMappingURL=chunk-IM2AHWBR.js.map
|
|
99
|
+
//# sourceMappingURL=chunk-IM2AHWBR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/gate.ts"],"names":[],"mappings":"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","file":"chunk-IM2AHWBR.js","sourcesContent":["/**\n * The gate every run passes through, whichever surface starts it.\n *\n * A host may offer more than one place to run a method - a schema-driven\n * inputs panel (an RJSF form) and a standalone run page (a bespoke field\n * renderer), say. **Only the rendering of inputs differs.** Everything between\n * \"the user pressed Run\" and \"the payload goes on the wire\" lives here, so\n * those surfaces cannot drift:\n *\n * 1. `buildRunInputsSchema` - the combined JSON Schema, whose `required` list\n * is `inputMustBeFilled` (optional `?` and variable-plural `[]` never\n * block; a fixed-count `[N]` list does).\n * 2. `prepareRunInputs` - heal legacy wrappers, then prune empty optionals.\n * 3. `validateRunInputs` - ajv, plus the missing-input scan that names the\n * VARIABLE at fault.\n * 4. `apiInputsFromSchemaData` - the `{concept, content}` payload, built from\n * the PREPARED data so the pruning reaches the wire too.\n *\n * **`gateRunInputs` is that whole chain as one call**, and it is what a server\n * should use. The four steps stay exported because a host that renders its own\n * panel needs the schema and the verdict separately, but assembling them is not\n * a host's job: the step between validation and the payload is an emptiness\n * check with four look-alike predicates to choose from, only two of which are\n * the ones the Run button reads, and choosing the near-miss pair produces a\n * server that is more permissive than the button in front of it.\n *\n * This module is pure: no React, no toasts, no i18n. Each caller renders the\n * verdict in its own idiom.\n */\nimport { inputMustBeFilled, isOptionalInput, isPluralInput } from './contracts';\nimport { gatingFieldsFromInputs } from './gating-fields';\nimport { fieldFilled, isFilled, mustBeFilled } from './readiness';\nimport { validateRunInputsSchema, type RunInputError } from './gate-validator';\nimport { healStringWrappers, pruneEmptyOptionals } from './wire-format';\nimport { prepareSchemaForRjsf } from './normalize-schema';\nimport { ownProp } from './own-property';\nimport type { PipeIOContract, PipeInputContract } from './contracts';\n\ntype Dict = Record<string, unknown>;\n\n/**\n * Combine the per-input schemas into one object schema.\n *\n * Each input variable becomes a property, titled with the variable name and\n * described with the concept code. Only the inputs the method actually demands\n * land in `required` - an optional (`?`) or variable-plural (`[]`) input must\n * not block the form (see `inputMustBeFilled`).\n *\n * The per-input schema travels verbatim, which is how a fixed-count (`[N]`)\n * list's declared count reaches ajv: pipelex states it as `minItems`/`maxItems`\n * on the array wrapper, so the count is enforced here without the kernel\n * restating it.\n */\nexport function buildRunInputsSchema(inputs: Record<string, PipeInputContract>): Dict {\n const properties: Dict = {};\n const required: string[] = [];\n\n for (const [varName, input] of Object.entries(inputs)) {\n const inputSchema = { ...input.json_schema } as Dict;\n inputSchema.title = varName;\n if (input.concept_ref && input.concept_ref !== varName) {\n inputSchema.description = input.concept_ref;\n }\n properties[varName] = inputSchema;\n if (inputMustBeFilled(input)) required.push(varName);\n }\n\n return prepareSchemaForRjsf({ type: 'object', properties, required });\n}\n\n/**\n * Last-gate repair, in two passes against the exact schema ajv validates.\n *\n * 1. **HEAL** - persisted `inputData` may still carry the legacy double-wrapped\n * `{ text: { text } }` shape (or a form's state may lag a store fix).\n * 2. **PRUNE** - RJSF fills every unset string with `\"\"` on mount, which an\n * optional CONSTRAINED field rejects (`DateContent.time` is `format: \"time\"`)\n * - blocking a run on a field the user never opened. An absent optional field\n * is what pipelex means by `None` anyway, so dropping it is the semantically\n * correct repair, not a validation dodge.\n */\nexport function prepareRunInputs(data: Dict, schema: Dict): Dict {\n return pruneEmptyOptionals(healStringWrappers(data, schema), schema) as Dict;\n}\n\nexport interface RunInputsVerdict {\n isValid: boolean;\n /** Variable names the scan could pin a missing required field on. */\n missingInputs: string[];\n /** Raw ajv errors, for when the scan cannot name anything. */\n errors: RunInputError[];\n}\n\n/**\n * Validate PREPARED data against the combined schema.\n *\n * `missingInputs` is reported by VARIABLE NAME - the name on the node the user\n * clicks - never by `concept_ref`, which used to produce \"Missing required\n * fields in: native.Text\" and named neither the input at fault nor, when several\n * inputs share a concept, which of them. Inputs the method declared omittable\n * are skipped: an empty `?` input is not a missing one.\n *\n * The scan can come up empty even on an invalid form (a wrong value shape, a\n * nested mismatch); `errors` is what the caller falls back to then, so a failure\n * is never undiagnosable.\n *\n * `preparedData` is `unknown` for the same reason `gateRunInputs`' `data` is: on\n * a public endpoint the body is whatever was sent, and ajv must be shown that\n * rather than a repair of it, or `must be object` is a verdict no caller can\n * ever receive. The name-the-variable scan below needs something indexable, so\n * a body that is not a record scans against nothing and names every input the\n * method demands - which is the honest answer for a body that carried none.\n */\nexport function validateRunInputs(\n preparedData: unknown,\n inputs: Record<string, PipeInputContract>,\n schema: Dict,\n): RunInputsVerdict {\n const errors = validateRunInputsSchema(preparedData, schema);\n if (errors.length === 0) return { isValid: true, missingInputs: [], errors: [] };\n\n const record0 =\n typeof preparedData === 'object' && preparedData !== null && !Array.isArray(preparedData)\n ? (preparedData as Dict)\n : undefined;\n const missingInputs: string[] = [];\n for (const [varName, input] of Object.entries(inputs)) {\n if (!inputMustBeFilled(input)) continue;\n const varData = ownProp(record0, varName);\n // A demanded input that is not there at all is missing whatever its concept\n // declares inside. The check has to come BEFORE the required-children one:\n // a struct whose concept demands no child used to fall out of the scan\n // here, so the run was refused by the combined schema's `required` list\n // while the scan named nothing and the caller could only quote ajv.\n if (varData == null) {\n missingInputs.push(varName);\n continue;\n }\n const inputSchema = input.json_schema as Dict;\n const requiredFields = (inputSchema.required as string[]) || [];\n if (requiredFields.length === 0) continue;\n if (typeof varData !== 'object') {\n missingInputs.push(varName);\n continue;\n }\n const record = varData as Dict;\n if (\n requiredFields.some((f) => {\n const child = ownProp(record, f);\n return child === undefined || child === '';\n })\n ) {\n missingInputs.push(varName);\n }\n }\n\n return { isValid: false, missingInputs, errors };\n}\n\n/**\n * Build the `{ concept, content }` map a run expects, from PREPARED data.\n *\n * The two ways a method says \"this may be nothing\" land differently on the wire:\n * - an **optional (`?`)** input left blank is OMITTED, so the runtime records a\n * real absence the method can branch on - sending `{ text: \"\" }` would look\n * like the caller supplied an empty string;\n * - a **plural (`[]`)** input keeps its key, because a plural slot is never\n * absent - its empty form IS the empty list, and the runtime requires the key.\n * When that list is EMPTY it is sent BARE, without the envelope: the envelope\n * is the runtime's \"explicit form\", which bypasses the top-down shaper and\n * hands the value to the bottom-up factory, and that factory types a list from\n * its first item - so an empty list there raises \"Cannot create Stuff from\n * empty list in content\". The bare form keeps the shaper, which reads the\n * DECLARED concept and builds the empty list correctly. (pipelex/#1096 makes\n * the envelope agree; the bare form runs today and stays correct after.)\n *\n * A fixed-count (`[N]`) list takes that same empty-list path, and an empty one\n * is not a payload the method can accept. It is unreachable through the gate,\n * which demands the input and rejects a short list on `minItems`; building the\n * payload straight from unvalidated data is what would reach it, and inventing\n * a different absence here would only hide that.\n */\nexport function apiInputsFromSchemaData(\n preparedData: Dict,\n inputs: Record<string, PipeInputContract>,\n): Dict {\n const out: Dict = {};\n for (const [varName, input] of Object.entries(inputs)) {\n const raw = ownProp(preparedData, varName);\n if (isOptionalInput(input) && !isFilled(raw)) continue;\n if (isPluralInput(input) && !isFilled(raw)) {\n out[varName] = [];\n continue;\n }\n const content = isPluralInput(input) && !Array.isArray(raw) ? [] : raw;\n out[varName] = { concept: input.concept_ref, content };\n }\n return out;\n}\n\n// ─── The whole chain, as one call ────────────────────────────────────────────\n\n/** The gate's verdict: the payload to send, or why the run may not start. */\nexport type RunInputsGateResult =\n | { ok: true; inputs: Dict }\n | {\n ok: false;\n /** Variable names the caller left empty or short. */\n missingInputs: string[];\n /** Raw ajv errors, for when the scan cannot name anything. */\n errors: RunInputError[];\n /** The repaired data the verdict was reached on - what\n * `describeValidationError` needs to quote the value it received. */\n preparedData: Dict;\n };\n\n/**\n * One schema object per contract, for the lifetime of the process.\n *\n * `buildRunInputsSchema` is a pure function of the contract, so rebuilding it is\n * *semantically* free - but validation runs through a module-level ajv whose\n * compiled-schema cache is keyed on **schema object identity** and is never\n * evicted. A fresh object per call therefore misses every time and retains\n * another compiled validator. On a publicly callable server endpoint that is\n * unbounded growth driven by the cheapest request there is: an empty body,\n * rejected in a fraction of a millisecond, costing nothing to send.\n *\n * Weakly keyed so the map never pins a contract that goes out of scope. The\n * schema a run has been gated against is pinned for the process lifetime anyway\n * by ajv's own cache; the point is that the NUMBER of them is bounded by the\n * number of distinct contracts rather than by traffic.\n */\nconst SCHEMA_CACHE = new WeakMap<PipeIOContract, Dict>();\n\nfunction schemaForContract(contract: PipeIOContract): Dict {\n const cached = SCHEMA_CACHE.get(contract);\n if (cached) return cached;\n const schema = buildRunInputsSchema(contract.inputs);\n SCHEMA_CACHE.set(contract, schema);\n return schema;\n}\n\n/**\n * Gate a run: repair the caller's data, validate it against the contract,\n * refuse anything the Run button would have refused, and build the payload.\n *\n * Returns a verdict rather than throwing. A server endpoint must not throw\n * across the boundary to its client - frameworks routinely strip the message to\n * an opaque digest in a production build - and a rejection here is an ordinary\n * outcome, not an exceptional one.\n *\n * **`data` is `unknown` because that is what it is.** A run endpoint is public\n * and no framework enforces a declared parameter type, so the argument is\n * whatever the caller put in the body. The chain indexes the payload by\n * variable name without first checking it is indexable, so a `null` body would\n * throw *after* ajv had already reported `must be object` and before any\n * verdict came back.\n *\n * So the two uses are separated rather than collapsed into one repair. **ajv\n * judges the value the caller actually sent**, which is what makes `must be\n * object` the verdict for a body that is not one; the indexing that follows\n * uses a safe `{}` stand-in, which is what keeps the gate from throwing. Repair\n * FIRST - coercing a non-object to `{}` before validating - is the shape that\n * looks equivalent and is not: a contract whose inputs are all optional has an\n * empty `required` list, so `{}` validates, and `gateRunInputs(\"garbage\", …)`\n * came back `ok: true` on a body the caller never meant as a run. Fail-closed\n * costs a malformed caller an error it earned; the other direction bills a run.\n *\n * **The schema alone is not the rule.** ajv's `required` asserts only that a\n * key is PRESENT, and a content model carries no `minLength` - so a required\n * input that arrived empty (`{document: {url: \"\"}}`, `{text: {text: \"\"}}`)\n * satisfies the schema. That is the natural payload, not a contrived one:\n * `rjsfDataFromRunValues({}, fields)` emits exactly that when nothing is\n * selected. So the gate re-applies the emptiness rule using\n * `computeReadiness`'s OWN two functions over the same derived fields, which is\n * the only way to be sure the two sides cannot disagree.\n *\n * Picking a pair that merely looks equivalent is not enough, and this is the\n * whole reason the assembly lives here rather than in each host: the obvious\n * choice, `inputMustBeFilled` + `isFilled`, agrees on every leaf kind and\n * diverges on a structured concept in BOTH directions - `isFilled` on an object\n * is `some(child filled)` where `fieldFilled` is `every(required child\n * filled)`. That accepts a half-filled struct the browser refuses (a paid run\n * past a disabled button) and rejects a filled all-optional struct the browser\n * accepts. A host whose methods happen to use only native concepts has no test\n * that can catch either.\n */\nexport function gateRunInputs(contract: PipeIOContract, data: unknown): RunInputsGateResult {\n const isRecord = typeof data === 'object' && data !== null && !Array.isArray(data);\n const payload = isRecord ? (data as Dict) : {};\n const schema = schemaForContract(contract);\n const preparedData = prepareRunInputs(payload, schema);\n\n // The value ajv is shown is the caller's, not the stand-in - see above.\n const verdict = validateRunInputs(isRecord ? preparedData : data, contract.inputs, schema);\n if (!verdict.isValid) {\n return {\n ok: false,\n missingInputs: verdict.missingInputs,\n errors: verdict.errors,\n preparedData,\n };\n }\n\n // The SELECTION is half the rule, and leaving it out is what made the two\n // halves disagree. `computeReadiness` reckons with an input the method\n // demands AND one it left optional that the user has touched - because a\n // structure with something in it owes its concept every field the concept\n // declares. Filtering on `mustBeFilled` alone dropped the second kind, so a\n // half-filled optional struct was refused by the button and accepted here.\n //\n // ajv cannot cover for it: a required child that is a plain string arrives as\n // `''`, which satisfies `required`. And the payload builder below then SENDS\n // that input, because `isFilled` is exactly what it tests. Which is the rule\n // stated properly: the gate holds to its concept precisely the inputs it is\n // about to put on the wire, and nothing it will omit.\n //\n // The tree the predicates run over is the gate's own, walked structurally\n // from the same `json_schema` ajv just validated - NOT the render tree, which\n // is built from the input-form descriptor. A server validating a payload must\n // never need that presentation artifact; see `gating-fields.ts`.\n const missingInputs = gatingFieldsFromInputs(contract.inputs)\n .filter((field) => mustBeFilled(field) || isFilled(ownProp(preparedData, field.name)))\n .filter((field) => !fieldFilled(field, ownProp(preparedData, field.name)))\n .map((field) => field.name);\n if (missingInputs.length) return { ok: false, missingInputs, errors: [], preparedData };\n\n return { ok: true, inputs: apiInputsFromSchemaData(preparedData, contract.inputs) };\n}\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { flattenAnyOf, hoistDefsToRoot } from './chunk-OD3VYXUY.js';
|
|
2
|
+
|
|
3
|
+
// src/core/normalize-schema.ts
|
|
4
|
+
function normalizeSchemaForRjsf(schema) {
|
|
5
|
+
let normalized = flattenAnyOf(schema);
|
|
6
|
+
if (normalized.properties && typeof normalized.properties === "object") {
|
|
7
|
+
const props = normalized.properties;
|
|
8
|
+
const normalizedProps = {};
|
|
9
|
+
for (const [key, value] of Object.entries(props)) {
|
|
10
|
+
normalizedProps[key] = value && typeof value === "object" ? normalizeSchemaForRjsf(value) : value;
|
|
11
|
+
}
|
|
12
|
+
normalized = { ...normalized, properties: normalizedProps };
|
|
13
|
+
}
|
|
14
|
+
if (normalized.items && typeof normalized.items === "object" && !Array.isArray(normalized.items)) {
|
|
15
|
+
normalized = {
|
|
16
|
+
...normalized,
|
|
17
|
+
items: normalizeSchemaForRjsf(normalized.items)
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(normalized.anyOf)) {
|
|
21
|
+
normalized = {
|
|
22
|
+
...normalized,
|
|
23
|
+
anyOf: normalized.anyOf.map(
|
|
24
|
+
(branch) => typeof branch === "object" && branch !== null ? normalizeSchemaForRjsf(branch) : branch
|
|
25
|
+
)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (normalized.$defs && typeof normalized.$defs === "object" && !Array.isArray(normalized.$defs)) {
|
|
29
|
+
const defs = normalized.$defs;
|
|
30
|
+
const normalizedDefs = {};
|
|
31
|
+
for (const [key, value] of Object.entries(defs)) {
|
|
32
|
+
normalizedDefs[key] = value && typeof value === "object" ? normalizeSchemaForRjsf(value) : value;
|
|
33
|
+
}
|
|
34
|
+
normalized = { ...normalized, $defs: normalizedDefs };
|
|
35
|
+
}
|
|
36
|
+
return normalized;
|
|
37
|
+
}
|
|
38
|
+
function prepareSchemaForRjsf(schema) {
|
|
39
|
+
return normalizeSchemaForRjsf(hoistDefsToRoot(schema));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { normalizeSchemaForRjsf, prepareSchemaForRjsf };
|
|
43
|
+
//# sourceMappingURL=chunk-LBFZXYCY.js.map
|
|
44
|
+
//# sourceMappingURL=chunk-LBFZXYCY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/normalize-schema.ts"],"names":[],"mappings":";;;AAsBO,SAAS,uBAAuB,MAAA,EAA0D;AAE/F,EAAA,IAAI,UAAA,GAAa,aAAa,MAAM,CAAA;AAGpC,EAAA,IAAI,UAAA,CAAW,UAAA,IAAc,OAAO,UAAA,CAAW,eAAe,QAAA,EAAU;AACtE,IAAA,MAAM,QAAQ,UAAA,CAAW,UAAA;AACzB,IAAA,MAAM,kBAA2C,EAAC;AAClD,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAChD,MAAA,eAAA,CAAgB,GAAG,IACjB,KAAA,IAAS,OAAO,UAAU,QAAA,GACtB,sBAAA,CAAuB,KAAgC,CAAA,GACvD,KAAA;AAAA,IACR;AACA,IAAA,UAAA,GAAa,EAAE,GAAG,UAAA,EAAY,UAAA,EAAY,eAAA,EAAgB;AAAA,EAC5D;AAGA,EAAA,IACE,UAAA,CAAW,KAAA,IACX,OAAO,UAAA,CAAW,KAAA,KAAU,QAAA,IAC5B,CAAC,KAAA,CAAM,OAAA,CAAQ,UAAA,CAAW,KAAK,CAAA,EAC/B;AACA,IAAA,UAAA,GAAa;AAAA,MACX,GAAG,UAAA;AAAA,MACH,KAAA,EAAO,sBAAA,CAAuB,UAAA,CAAW,KAAgC;AAAA,KAC3E;AAAA,EACF;AAGA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,UAAA,CAAW,KAAK,CAAA,EAAG;AACnC,IAAA,UAAA,GAAa;AAAA,MACX,GAAG,UAAA;AAAA,MACH,KAAA,EAAQ,WAAW,KAAA,CAAoC,GAAA;AAAA,QAAI,CAAC,WAC1D,OAAO,MAAA,KAAW,YAAY,MAAA,KAAW,IAAA,GACrC,sBAAA,CAAuB,MAAiC,CAAA,GACxD;AAAA;AACN,KACF;AAAA,EACF;AAGA,EAAA,IACE,UAAA,CAAW,KAAA,IACX,OAAO,UAAA,CAAW,KAAA,KAAU,QAAA,IAC5B,CAAC,KAAA,CAAM,OAAA,CAAQ,UAAA,CAAW,KAAK,CAAA,EAC/B;AACA,IAAA,MAAM,OAAO,UAAA,CAAW,KAAA;AACxB,IAAA,MAAM,iBAA0C,EAAC;AACjD,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAA,EAAG;AAC/C,MAAA,cAAA,CAAe,GAAG,IAChB,KAAA,IAAS,OAAO,UAAU,QAAA,GACtB,sBAAA,CAAuB,KAAgC,CAAA,GACvD,KAAA;AAAA,IACR;AACA,IAAA,UAAA,GAAa,EAAE,GAAG,UAAA,EAAY,KAAA,EAAO,cAAA,EAAe;AAAA,EACtD;AAEA,EAAA,OAAO,UAAA;AACT;AAOO,SAAS,qBAAqB,MAAA,EAA0D;AAC7F,EAAA,OAAO,sBAAA,CAAuB,eAAA,CAAgB,MAAM,CAAC,CAAA;AACvD","file":"chunk-LBFZXYCY.js","sourcesContent":["/**\n * Normalizes a JSON Schema for RJSF compatibility.\n *\n * Pydantic v2 generates `anyOf: [{type: \"string\"}, {type: \"null\"}]` for optional\n * fields (`str | None`). RJSF renders this as a dropdown selector asking the user\n * to pick a sub-schema, which is terrible UX. The normalizer flattens those\n * patterns on every node (see `flattenAnyOf` in `schema-utils.ts` for the exact\n * rules) and hoists nested `$defs` to the root so composed sub-schemas keep\n * their refs resolvable.\n *\n * The collapse and hoist engines live in `schema-utils.ts` - the\n * consolidated home for the kernel's JSON-Schema plumbing; this module owns the\n * recursive application over a whole schema tree.\n */\nimport { flattenAnyOf, hoistDefsToRoot } from './schema-utils';\n\nexport { hoistDefsToRoot };\n\n/**\n * Recursively normalize a JSON Schema for RJSF.\n * Walks the entire schema tree and flattens anyOf patterns on every node.\n */\nexport function normalizeSchemaForRjsf(schema: Record<string, unknown>): Record<string, unknown> {\n // Flatten anyOf at this level\n let normalized = flattenAnyOf(schema);\n\n // Recurse into properties\n if (normalized.properties && typeof normalized.properties === 'object') {\n const props = normalized.properties as Record<string, unknown>;\n const normalizedProps: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(props)) {\n normalizedProps[key] =\n value && typeof value === 'object'\n ? normalizeSchemaForRjsf(value as Record<string, unknown>)\n : value;\n }\n normalized = { ...normalized, properties: normalizedProps };\n }\n\n // Recurse into items (array schemas)\n if (\n normalized.items &&\n typeof normalized.items === 'object' &&\n !Array.isArray(normalized.items)\n ) {\n normalized = {\n ...normalized,\n items: normalizeSchemaForRjsf(normalized.items as Record<string, unknown>),\n };\n }\n\n // Recurse into anyOf branches that weren't flattened (complex unions)\n if (Array.isArray(normalized.anyOf)) {\n normalized = {\n ...normalized,\n anyOf: (normalized.anyOf as Record<string, unknown>[]).map((branch) =>\n typeof branch === 'object' && branch !== null\n ? normalizeSchemaForRjsf(branch as Record<string, unknown>)\n : branch,\n ),\n };\n }\n\n // Recurse into $defs so nested definitions (e.g. ImageSize) also get anyOf normalized\n if (\n normalized.$defs &&\n typeof normalized.$defs === 'object' &&\n !Array.isArray(normalized.$defs)\n ) {\n const defs = normalized.$defs as Record<string, unknown>;\n const normalizedDefs: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(defs)) {\n normalizedDefs[key] =\n value && typeof value === 'object'\n ? normalizeSchemaForRjsf(value as Record<string, unknown>)\n : value;\n }\n normalized = { ...normalized, $defs: normalizedDefs };\n }\n\n return normalized;\n}\n\n/**\n * Prepare a schema for RJSF: hoist all nested `$defs` to the root, then normalize\n * anyOf patterns. Call this on any schema that composes multiple sub-schemas\n * (each of which may ship its own `$defs`).\n */\nexport function prepareSchemaForRjsf(schema: Record<string, unknown>): Record<string, unknown> {\n return normalizeSchemaForRjsf(hoistDefsToRoot(schema));\n}\n"]}
|