@pipelex/mthds-form 0.9.0 → 0.10.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 (50) hide show
  1. package/README.md +3 -0
  2. package/dist/{chunk-S4CB423P.js → chunk-4JQAJT7C.js} +3 -3
  3. package/dist/{chunk-S4CB423P.js.map → chunk-4JQAJT7C.js.map} +1 -1
  4. package/dist/{chunk-YABRYTQ4.js → chunk-4KGQ65TQ.js} +3 -3
  5. package/dist/{chunk-YABRYTQ4.js.map → chunk-4KGQ65TQ.js.map} +1 -1
  6. package/dist/chunk-CAKQ5VFT.js +35 -0
  7. package/dist/chunk-CAKQ5VFT.js.map +1 -0
  8. package/dist/{chunk-25I6JDIK.js → chunk-FABY3DEY.js} +2 -2
  9. package/dist/chunk-FABY3DEY.js.map +1 -0
  10. package/dist/{chunk-KG4IYFWI.js → chunk-G6BWZUGV.js} +165 -46
  11. package/dist/chunk-G6BWZUGV.js.map +1 -0
  12. package/dist/{chunk-AZZAAGNX.js → chunk-TID7ZN63.js} +7 -3
  13. package/dist/chunk-TID7ZN63.js.map +1 -0
  14. package/dist/chunk-XCO6GTEC.js +38 -0
  15. package/dist/chunk-XCO6GTEC.js.map +1 -0
  16. package/dist/{chunk-KIEOLP2L.js → chunk-ZB4RYUKV.js} +4 -4
  17. package/dist/chunk-ZB4RYUKV.js.map +1 -0
  18. package/dist/core/derive.d.ts +1 -0
  19. package/dist/core/derive.js +2 -2
  20. package/dist/core/descriptor.d.ts +13 -2
  21. package/dist/core/descriptor.js +1 -1
  22. package/dist/core/file-formats.d.ts +34 -7
  23. package/dist/core/file-formats.js +1 -1
  24. package/dist/core/gating-fields.d.ts +1 -0
  25. package/dist/core/index.d.ts +2 -1
  26. package/dist/core/index.js +7 -6
  27. package/dist/core/narrow-file-formats.d.ts +50 -0
  28. package/dist/core/narrow-file-formats.js +4 -0
  29. package/dist/core/narrow-file-formats.js.map +1 -0
  30. package/dist/core/native-content.d.ts +20 -11
  31. package/dist/core/native-content.js +1 -1
  32. package/dist/core/readiness.d.ts +1 -0
  33. package/dist/core/stuff-files.d.ts +1 -0
  34. package/dist/core/stuff-files.js +2 -2
  35. package/dist/core/values.d.ts +1 -0
  36. package/dist/core/values.js +3 -3
  37. package/dist/generative/index.d.ts +105 -12
  38. package/dist/generative/index.js +79 -157
  39. package/dist/generative/index.js.map +1 -1
  40. package/dist/{ui-designer.mthds → layout-design.mthds} +177 -29
  41. package/dist/react/index.d.ts +66 -10
  42. package/dist/react/index.js +5 -5
  43. package/dist/styles.css +1 -1
  44. package/package.json +3 -3
  45. package/dist/chunk-25I6JDIK.js.map +0 -1
  46. package/dist/chunk-2JWRG53S.js +0 -33
  47. package/dist/chunk-2JWRG53S.js.map +0 -1
  48. package/dist/chunk-AZZAAGNX.js.map +0 -1
  49. package/dist/chunk-KG4IYFWI.js.map +0 -1
  50. package/dist/chunk-KIEOLP2L.js.map +0 -1
@@ -62,7 +62,11 @@ function isNativeDateNode(node) {
62
62
  function isNativeCompositeNode(node) {
63
63
  return refinesNative(node, NATIVE_COMPOSITE_CONCEPT_REF);
64
64
  }
65
+ function isNativeValueNode(node) {
66
+ return isNativeDateNode(node) || isNativeHtmlNode(node) || isNativeCompositeNode(node);
67
+ }
65
68
  function refinesNative(node, ref) {
69
+ if (node.kind === "list") return false;
66
70
  if (node.conceptRef === ref) return true;
67
71
  return node.refines?.includes(ref) ?? false;
68
72
  }
@@ -189,6 +193,6 @@ function hasTypedScalarMarkers(value) {
189
193
  return isRecord(value) && TYPED_SCALAR_MARKERS.every((marker) => hasOwnProp(value, marker));
190
194
  }
191
195
 
192
- export { NATIVE_COMPOSITE_CONCEPT_REF, NATIVE_DATE_CONCEPT_REF, NATIVE_HTML_CONCEPT_REF, TYPED_SCALAR_MARKERS, formatDateContent, hasTypedScalarMarkers, isNativeCompositeNode, isNativeDateNode, isNativeHtmlNode, isViewableUrl, readCompositeContent, readDataUrl, readDateContent, readDocumentContent, readHtmlContent, readImageContent, viewableUrl };
193
- //# sourceMappingURL=chunk-AZZAAGNX.js.map
194
- //# sourceMappingURL=chunk-AZZAAGNX.js.map
196
+ export { NATIVE_COMPOSITE_CONCEPT_REF, NATIVE_DATE_CONCEPT_REF, NATIVE_HTML_CONCEPT_REF, TYPED_SCALAR_MARKERS, formatDateContent, hasTypedScalarMarkers, isNativeCompositeNode, isNativeDateNode, isNativeHtmlNode, isNativeValueNode, isViewableUrl, readCompositeContent, readDataUrl, readDateContent, readDocumentContent, readHtmlContent, readImageContent, viewableUrl };
197
+ //# sourceMappingURL=chunk-TID7ZN63.js.map
198
+ //# sourceMappingURL=chunk-TID7ZN63.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/native-content.ts"],"names":["parsed"],"mappings":"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","file":"chunk-TID7ZN63.js","sourcesContent":["/**\n * How to READ the native content models — the result side's twin of\n * `./file-formats`.\n *\n * A renderer handed a result knows the field's `kind` from the descriptor, and\n * for the kinds whose value is a structured content model rather than a bare\n * scalar (`document`, `image`, `date`) it must then read that model's members.\n * **That is reading the standard, not sniffing at it.** The distinction is the\n * whole reason this module exists as data rather than as heuristics inside a\n * control: a reader keyed by a STATED kind consults a pinned definition, where\n * a reader that works out *which* kind it is holding by counting properties is\n * guessing — and guessing is exactly what [../../docs/derivation-swap.md]\n * records removing from the input side.\n *\n * ## Where each shape comes from\n *\n * `native.Image` and `native.Document` are pinned by the standard, in\n * `docs/spec/native-concepts.md` § \"The Pinned Set (MTHDS 1.0.0)\". Both carry a\n * required `url` — a storage URI, an HTTP(S) URL, or a base64 data URL — and\n * optional presentation members beside it. Nothing here adds a member the spec\n * does not state.\n *\n * `native.Date` is pinned the same way (`{date, time}`), but a `date` FIELD\n * inside a structured concept is not a `native.Date` value: it is a python\n * `datetime.date`, and the serialization layer stamps it with its class. So a\n * date arrives in one of three legal shapes, all three of which a run really\n * produces:\n *\n * \"2026-03-14\" a plain ISO string\n * { date: \"2026-03-14\", __class__: \"date\", … } a typed scalar\n * { date: \"2026-03-14\", time: \"15:40:00\" } native.Date\n *\n * The typed-scalar envelope is the one shape the standard does NOT pin — it is\n * a serialization fact, measured off a real run rather than read off a spec —\n * and it is called out as such here so nobody mistakes it for normative.\n *\n * This module lives in core, not beside the control that renders it, for the\n * reason `file-formats.ts` established: a host that shows a result its own way\n * needs the same answer the control uses, and two copies of an answer is two\n * places for it to drift. Pure data and pure functions — no React.\n */\n\nimport { hasOwnProp, ownProp } from './own-property';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** A member the content models declare as `type = \"text\"`, when it is one. */\nfunction readText(record: Record<string, unknown>, key: string): string | undefined {\n const value = ownProp(record, key);\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction readNumber(record: Record<string, unknown>, key: string): number | undefined {\n const value = ownProp(record, key);\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\n/**\n * `native.Document`, read.\n *\n * `url` is the only required member; everything else is a producer's courtesy,\n * so a reader that demands any of them describes a value the standard permits\n * as malformed.\n */\nexport interface DocumentContentView {\n url: string;\n publicUrl?: string;\n mimeType?: string;\n filename?: string;\n title?: string;\n snippet?: string;\n}\n\n/** `native.Image`, read. `width`/`height` are optional but PAIRED by the spec. */\nexport interface ImageContentView {\n url: string;\n publicUrl?: string;\n caption?: string;\n mimeType?: string;\n filename?: string;\n width?: number;\n height?: number;\n sourcePrompt?: string;\n}\n\n/** `native.Date` (and the typed-scalar envelope a nested `date` field arrives in). */\nexport interface DateContentView {\n /** ISO 8601 calendar date, `YYYY-MM-DD`. */\n date: string;\n /** ISO 8601 time of day, present only when the source stated one. */\n time?: string;\n}\n\n/**\n * Read a `document`-kind value. `undefined` when the value carries no `url`,\n * which is the one member the standard requires — a caller renders its own\n * absence rather than being handed a half-value to test.\n */\nexport function readDocumentContent(value: unknown): DocumentContentView | undefined {\n if (!isRecord(value)) return undefined;\n const url = readText(value, 'url');\n if (url === undefined) return undefined;\n return {\n url,\n publicUrl: readText(value, 'public_url'),\n mimeType: readText(value, 'mime_type'),\n filename: readText(value, 'filename'),\n title: readText(value, 'title'),\n snippet: readText(value, 'snippet'),\n };\n}\n\n/** Read an `image`-kind value. Same contract as `readDocumentContent`. */\nexport function readImageContent(value: unknown): ImageContentView | undefined {\n if (!isRecord(value)) return undefined;\n const url = readText(value, 'url');\n if (url === undefined) return undefined;\n return {\n url,\n publicUrl: readText(value, 'public_url'),\n caption: readText(value, 'caption'),\n mimeType: readText(value, 'mime_type'),\n filename: readText(value, 'filename'),\n width: readNumber(value, 'width'),\n height: readNumber(value, 'height'),\n sourcePrompt: readText(value, 'source_prompt'),\n };\n}\n\n/**\n * `native.Html`, read.\n *\n * The only content model here that is NOT reached by a field kind, and the\n * reason is a deliberate decision of the standard: the kind vocabulary has no\n * `html` member, so a `native.Html` value is an `object` node over its two\n * declared fields. That is right for the descriptor — the kinds name how a value\n * is ENTERED, and markup is entered as text — and wrong for a result view, which\n * would otherwise print a page's source at a reader.\n *\n * So this one is keyed by CONCEPT rather than by kind, through\n * `isNativeHtmlNode` below. That is a membership test on facts the descriptor\n * states (`concept_ref`, `refines`), which the standard's own page calls out as\n * the supported way to ask \"does this refine `native.X`?\" — the opposite of\n * inspecting a value to guess what it is.\n */\nexport interface HtmlContentView {\n /** The markup itself. The one required member. */\n innerHtml: string;\n /** A class name for a wrapper a consumer may put around it, when stated. */\n cssClass?: string;\n}\n\n/** Read an `native.Html` value. `undefined` when it carries no markup. */\nexport function readHtmlContent(value: unknown): HtmlContentView | undefined {\n if (!isRecord(value)) return undefined;\n const innerHtml = readText(value, 'inner_html');\n if (innerHtml === undefined) return undefined;\n return { innerHtml, cssClass: readText(value, 'css_class') };\n}\n\n/** The concept refs whose content model is multi-property, spelled once each. */\nexport const NATIVE_HTML_CONCEPT_REF = 'native.Html';\nexport const NATIVE_DATE_CONCEPT_REF = 'native.Date';\nexport const NATIVE_COMPOSITE_CONCEPT_REF = 'native.Composite';\n\n/** One member of a composite: the name it was composed under, and its content. */\nexport interface CompositeMember {\n name: string;\n value: unknown;\n}\n\n/**\n * Read a `native.Composite` — a named composition of contents.\n *\n * The members are returned in the order the payload states them, which is the\n * order the method composed them in and the only order there is: a composite\n * declares no fields, so there is no authored order to prefer over it.\n *\n * `undefined` for anything that is not a record, so the caller falls back.\n */\nexport function readCompositeContent(value: unknown): CompositeMember[] | undefined {\n if (!isRecord(value)) return undefined;\n return Object.entries(value).map(([name, member]) => ({ name, value: member }));\n}\n\n/**\n * Whether a descriptor node carries markup — its concept IS `native.Html`, or\n * refines it.\n *\n * The refinement chain is checked, not just the leaf, because a method may\n * declare `legal.ClauseMarkup` refining `native.Html` and a reader of that result\n * wants the markup rendered just the same. `refines` is on the wire for exactly\n * this question.\n */\nexport function isNativeHtmlNode(node: NativeNode): boolean {\n return refinesNative(node, NATIVE_HTML_CONCEPT_REF);\n}\n\n/**\n * Whether a node IS a `native.Date` — the other content model the kind\n * vocabulary cannot name.\n *\n * `native.Date` is `{date, time}`, two properties, so nothing unwraps it and its\n * node is an `object`. Correct for the descriptor and wrong for a reader: a date\n * result rendered structurally is a two-field card whose second field says \"not\n * provided\", where the answer is a date. The `date` ARM already reads exactly\n * this model — `readDateContent` takes `{date, time}` — it just never fires,\n * because the kind says `object`.\n *\n * A `date` FIELD inside a structure is a different thing and needs none of this:\n * it carries `kind: \"date\"` already.\n */\nexport function isNativeDateNode(node: NativeNode): boolean {\n return refinesNative(node, NATIVE_DATE_CONCEPT_REF);\n}\n\n/**\n * Whether a node is a `native.Composite` — a named bag of contents.\n *\n * The third concept the kind vocabulary cannot name, and the one where it is\n * least able to: a composite declares no members at all, so its descriptor is\n * `kind: \"unknown\"` and its payload schema is `{additionalProperties: true}`\n * with no properties. Both are TRUE — the standard's escape hatch, honestly\n * used — and both leave a renderer with nothing to read, so the default\n * fallback prints the whole thing as a JSON blob.\n *\n * That is the worst available answer to a value that is, by definition, a map\n * of ordinary `StuffContent`s. Keyed by concept, a renderer can at least show\n * the members as the named things they are. See `CompositeValue`.\n */\nexport function isNativeCompositeNode(node: NativeNode): boolean {\n return refinesNative(node, NATIVE_COMPOSITE_CONCEPT_REF);\n}\n\n/**\n * Whether a node is one of the three natives the kind vocabulary cannot name —\n * a date, a page, a composite — which a renderer reads by CONCEPT before it\n * reads the kind. A list of one answers no (the predicates refuse a `list`\n * node), and its item answers yes.\n *\n * One answer, read twice: the result view renders a list whose item answers yes\n * one value per line rather than as a table, and the generative layer delegates\n * that list to the kernel, because no catalog component reads a native value.\n * Not re-exported: a host asks the three predicates it needs.\n */\nexport function isNativeValueNode(node: NativeNode): boolean {\n return isNativeDateNode(node) || isNativeHtmlNode(node) || isNativeCompositeNode(node);\n}\n\n/** What the native predicates read off a node: its stated kind and its concept. */\ninterface NativeNode {\n kind?: string;\n conceptRef?: string;\n refines?: readonly string[];\n}\n\n/**\n * The node IS one of the named native, or of a concept refining it.\n *\n * **A list of them is not one of them.** Plurality is not on the concept: a\n * plural node's `concept_ref` is its ELEMENT's, with the multiplicity stripped,\n * so a `native.Date[]` result is a `list` node whose concept reads\n * `native.Date`. Asking the concept alone answered yes for the whole list, and\n * every caller then treated the list as ONE date, one page or one composite: a\n * list of dates rendered as a single absent date, and a list of pages collected\n * no page at all. So a node whose stated kind is `list`\n * answers no, and its `item` answers for itself. The kind is the descriptor's\n * own statement, so this reads a stated fact and inspects no value.\n */\nfunction refinesNative(node: NativeNode, ref: string): boolean {\n if (node.kind === 'list') return false;\n if (node.conceptRef === ref) return true;\n return node.refines?.includes(ref) ?? false;\n}\n\n/**\n * Read a `date`-kind value, in any of the three shapes a run produces.\n *\n * The `date` member is read one level deep, because `native.Date`'s own `date`\n * member is a `datetime.date` and therefore arrives inside the same typed-scalar\n * envelope the whole value may already be wrapped in. One level is enough and\n * the recursion is bounded on purpose: a second envelope would be a\n * serialization bug, and following it forever would turn one into a hang.\n */\nexport function readDateContent(value: unknown): DateContentView | undefined {\n if (typeof value === 'string') {\n return value.length > 0 ? { date: value } : undefined;\n }\n if (!isRecord(value)) return undefined;\n\n const inner = ownProp(value, 'date');\n const date =\n typeof inner === 'string' ? inner : isRecord(inner) ? readText(inner, 'date') : undefined;\n if (date === undefined) return undefined;\n return { date, time: readText(value, 'time') };\n}\n\n/** `{date}` / `{date, time}` as one line, which is how both are read aloud. */\nexport function formatDateContent(content: DateContentView): string {\n return content.time ? `${content.date} ${content.time}` : content.date;\n}\n\n/**\n * The media types a `data:` URL may carry and still be viewable.\n *\n * An allow-list rather than a deny-list, because the question a sink asks is\n * \"can this paint without executing\", and only a closed set answers it. The\n * raster types are the ones the preview arms already name; `application/pdf` is\n * here because the input control previews a `data:application/pdf` value a\n * storage-less host wrote back, through an `<object>`, and reads this same\n * predicate to decide.\n *\n * `image/svg+xml` is deliberately absent: an SVG paints as a picture and\n * EXECUTES as a document the moment it is opened in a tab, which is one click\n * away from every image this package paints.\n */\nconst VIEWABLE_DATA_MEDIA_TYPES = new Set([\n 'image/png',\n 'image/jpeg',\n 'image/gif',\n 'image/webp',\n 'image/avif',\n 'application/pdf',\n]);\n\n/**\n * An origin no host can be, to resolve a relative reference against.\n *\n * `.invalid` is reserved by RFC 2606 and resolves nowhere, so nothing can be\n * fetched from it by accident. It exists only so a path can be parsed at all;\n * the answer taken from the parse is whether the reference STAYED on it.\n */\nconst RELATIVE_SENTINEL_ORIGIN = 'https://url-gate.invalid';\n\n/**\n * A scheme, by RFC 3986's grammar: a letter, then letters, digits, `+`, `-`, `.`\n *\n * Read off the string rather than inferred from a parse, because a parse needs a\n * base and the base is what makes the answer wrong — see {@link viewableUrl}.\n */\nconst OWN_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;\n\n/**\n * What the WHATWG URL parser strips before it parses, applied before we judge.\n *\n * Leading and trailing C0 controls and spaces are removed, and every internal\n * tab, line feed and carriage return. This is not tidying: a scheme test run on\n * the raw string and a browser running on the parsed one disagree about\n * `\" https://cdn/x.png\"` — `new URL()` reads it as `https:` and `/^https?:/`\n * does not — and a host that validated a member by parsing while this gate\n * prefix-matched would have judged a different string than the one painted.\n */\nfunction stripUrlWhitespace(candidate: string): string {\n // Written out rather than as a character-class regex: the range IS the control\n // characters, which is exactly what a regex may not spell (`no-control-regex`).\n let start = 0;\n let end = candidate.length;\n while (start < end && candidate.charCodeAt(start) <= 0x20) start += 1;\n while (end > start && candidate.charCodeAt(end - 1) <= 0x20) end -= 1;\n // Scan before rebuilding, and rebuild only from the first character that has\n // to go. Almost every URL has nothing to strip inside it, and the one that\n // does is the one that is huge: an inline `data:` image is judged three or\n // four times per render, and a per-character rebuild of a megabyte-long\n // payload each time is hundreds of milliseconds of frozen main thread for a\n // string that comes back identical.\n for (let index = start; index < end; index += 1) {\n const code = candidate.charCodeAt(index);\n // Tab, line feed, carriage return - removed wherever they appear, not only\n // at the edges, which is what the parser does with them.\n if (code === 0x09 || code === 0x0a || code === 0x0d) {\n let stripped = candidate.slice(start, index);\n for (let rest = index; rest < end; rest += 1) {\n const restCode = candidate.charCodeAt(rest);\n if (restCode !== 0x09 && restCode !== 0x0a && restCode !== 0x0d)\n stripped += candidate[rest];\n }\n return stripped;\n }\n }\n return start === 0 && end === candidate.length ? candidate : candidate.slice(start, end);\n}\n\n/** What a `data:` URL says about the bytes it carries. */\nexport interface DataUrlView {\n /** Lowercased, without its parameters; `text/plain` when the URL declares none. */\n mediaType: string;\n /** The size of the DECODED payload, in bytes. */\n bytes: number;\n}\n\n/**\n * A `data:` URL's media type and decoded size, or `undefined` for any other URL.\n *\n * A host that encodes a picked file in the browser writes the file itself into\n * the value's `url`, so a thirty-kilobyte PDF is a forty-thousand-character\n * string, and printed where a reference would be it tells a person nothing. Its\n * type and its size are what they can read.\n *\n * The size is COUNTED rather than decoded. A base64 payload's size follows from\n * how many symbols it holds, and decoding a megabyte to measure it would be the\n * frozen main thread {@link stripUrlWhitespace} is written to avoid. This is a\n * reading for display, not a gate: whether the URL may be painted is still\n * {@link viewableUrl}'s answer alone.\n */\nexport function readDataUrl(candidate: string): DataUrlView | undefined {\n const url = candidate.trimStart();\n if (!/^data:/i.test(url)) return undefined;\n const comma = url.indexOf(',');\n if (comma === -1) return undefined;\n const [declared = '', ...parameters] = url.slice('data:'.length, comma).split(';');\n const trimmed = declared.trim().toLowerCase();\n // A fragment is not payload. `#page=2` on an inline PDF is the viewer's, and\n // counting it as bytes is counting the URL rather than the file.\n const fragment = url.indexOf('#', comma);\n const payload = fragment === -1 ? url.slice(comma + 1) : url.slice(comma + 1, fragment);\n const base64 = parameters.some((parameter) => parameter.trim().toLowerCase() === 'base64');\n return {\n mediaType: trimmed === '' ? 'text/plain' : trimmed,\n bytes: base64 ? base64Bytes(payload) : percentEncodedBytes(payload),\n };\n}\n\n/**\n * Three bytes for every four symbols, ignoring what is not one: the `=`\n * padding, and the line breaks a MIME encoder wraps its output at. Both\n * alphabets count, the standard one and the URL-safe one.\n *\n * A percent-escape is resolved to the character it stands for before it is\n * judged, because a payload may be escaped anywhere — `YQ%3D%3D` is `YQ==`,\n * one byte, and counting `3` and `D` as symbols made it four.\n */\nfunction base64Bytes(payload: string): number {\n let symbols = 0;\n for (let index = 0; index < payload.length; index += 1) {\n let code = payload.charCodeAt(index);\n if (code === 0x25) {\n const escaped = Number.parseInt(payload.slice(index + 1, index + 3), 16);\n if (!Number.isNaN(escaped) && index + 2 < payload.length) {\n code = escaped;\n index += 2;\n }\n }\n if (\n (code >= 0x41 && code <= 0x5a) ||\n (code >= 0x61 && code <= 0x7a) ||\n (code >= 0x30 && code <= 0x39) ||\n code === 0x2b ||\n code === 0x2f ||\n code === 0x2d ||\n code === 0x5f\n )\n symbols += 1;\n }\n return Math.floor((symbols * 3) / 4);\n}\n\n/** A percent-escape is one byte; any other character is its UTF-8 length. */\nfunction percentEncodedBytes(payload: string): number {\n const escapes = payload.match(/%[0-9a-f]{2}/gi)?.length ?? 0;\n return new TextEncoder().encode(payload).length - escapes * 2;\n}\n\n/** The media type a `data:` URL declares, lowercased; `text/plain` when it declares none. */\nfunction dataUrlMediaType(parsed: URL): string {\n const declared = parsed.pathname.split(/[;,]/, 1)[0] ?? '';\n const trimmed = declared.trim().toLowerCase();\n return trimmed === '' ? 'text/plain' : trimmed;\n}\n\n/**\n * The URL a browser can paint, normalised — or `undefined` when there is none.\n *\n * **The string this returns is the string a sink must use.** That is the whole\n * point of returning one rather than answering yes or no: the gate judges a\n * normalised URL, so handing the caller back the raw member would let the two\n * diverge again on exactly the whitespace the parser strips.\n *\n * The gate parses rather than prefix-matches, and branches on the protocol the\n * parser reports:\n *\n * - `http:` and `https:` are viewable.\n * - `blob:` is viewable. A blob URL is bound to the origin that minted it, so a\n * payload cannot forge one that points anywhere else.\n * - `data:` is viewable only for a media type in {@link VIEWABLE_DATA_MEDIA_TYPES}.\n * `data:text/html` is a document at the EMBEDDING page's own origin, which is\n * what made an unsandboxed frame over a payload URL a real hole.\n * - Everything else is not: `javascript:`, `file:` (a run on a developer's\n * machine writes one, and a browser refuses to load it from an http page) and\n * `pipelex-storage://`, which cannot be resolved client-side at all — that is\n * the upload seam's job (see [../../docs/upload-seam.md]), and a renderer with\n * no resolver must show the reference rather than a broken `<img>`.\n *\n * **A root-relative path counts**, and leaving it out was a real bug rather\n * than an omission. A host's URL resolver naturally hands back a path on its\n * OWN origin — `/api/assets/…`, an authenticated route that streams the object\n * — which is the whole point of resolving rather than exposing storage. This\n * predicate rejected it for having no scheme, so the resolved URL was thrown\n * away and the arms fell back to the payload's `public_url`: a presigned URL\n * that had already expired. The image stayed broken with the fix in place.\n *\n * A path is rejected when it is protocol-relative — `//host/x`, and the two\n * backslash spellings the parser reads the same way (`\\\\host\\x`, `/\\host/x`) —\n * and then checked against the sentinel as well. An accepted path is returned\n * relative, because making it absolute against a sentinel would point it at\n * nowhere.\n */\nexport function viewableUrl(candidate: string | undefined): string | undefined {\n if (!candidate) return undefined;\n const stripped = stripUrlWhitespace(candidate);\n if (stripped === '') return undefined;\n\n // Whether the string carries a scheme is read OFF THE STRING, before any base\n // is applied, because the parser reads a candidate whose scheme equals the\n // base's as relative to that base. Deciding it with a second, base-less parse\n // let the two disagree: `https:cdn.example/x.png` was judged absolute and\n // resolved against the sentinel, so the gate handed a sink\n // `https://url-gate.invalid/cdn.example/x.png` — an internal placeholder, in a\n // real `<img src>`, in place of a URL that had worked. The grammar is RFC\n // 3986's, and it agrees with the parser on every string either accepts.\n if (OWN_SCHEME_RE.test(stripped)) {\n let parsed: URL;\n try {\n parsed = new URL(stripped);\n } catch {\n return undefined;\n }\n switch (parsed.protocol) {\n case 'http:':\n case 'https:':\n case 'blob:':\n return parsed.href;\n case 'data:':\n return VIEWABLE_DATA_MEDIA_TYPES.has(dataUrlMediaType(parsed)) ? parsed.href : undefined;\n default:\n return undefined;\n }\n }\n\n // No scheme of its own: a reference relative to wherever the page is. Only a\n // root-relative path qualifies.\n if (!stripped.startsWith('/')) return undefined;\n // Protocol-relative, rejected on the SPELLING. \"Did it stay on the sentinel\"\n // reads as the same rule and is blind in exactly one place — the sentinel's\n // own host — so `//url-gate.invalid/x` passed the test written to stop it.\n const afterSlash = stripped.charCodeAt(1);\n if (afterSlash === 0x2f || afterSlash === 0x5c) return undefined;\n let parsed: URL;\n try {\n parsed = new URL(stripped, RELATIVE_SENTINEL_ORIGIN);\n } catch {\n return undefined;\n }\n return parsed.origin === RELATIVE_SENTINEL_ORIGIN ? stripped : undefined;\n}\n\n/**\n * Whether a browser can paint this URL as-is — {@link viewableUrl} as a guard.\n *\n * Prefer `viewableUrl` wherever the URL is then USED: this answers the question\n * without handing back the normalised string, so a caller that acts on the raw\n * candidate acts on a string the gate did not judge.\n */\nexport function isViewableUrl(url: string | undefined): url is string {\n return viewableUrl(url) !== undefined;\n}\n\n/**\n * The typed-scalar markers the serialization layer stamps onto a value.\n *\n * Exported so a host can recognise (and strip) them; nothing in the kernel\n * BRANCHES on them, which is the point — a reader keyed by these would be\n * reading the serializer instead of the standard.\n */\nexport const TYPED_SCALAR_MARKERS = ['__class__', '__module__'] as const;\n\n/** Whether a record carries the typed-scalar markers. Informational. */\nexport function hasTypedScalarMarkers(value: unknown): boolean {\n return isRecord(value) && TYPED_SCALAR_MARKERS.every((marker) => hasOwnProp(value, marker));\n}\n"]}
@@ -0,0 +1,38 @@
1
+ // src/core/file-formats.ts
2
+ var DOCUMENT_FORMATS = [
3
+ { mimeType: "application/pdf", extensions: [".pdf"], label: "PDF" },
4
+ { mimeType: "image/jpeg", extensions: [".jpg", ".jpeg"], label: "JPG" },
5
+ { mimeType: "image/png", extensions: [".png"], label: "PNG" }
6
+ ];
7
+ var IMAGE_FORMATS = [
8
+ { mimeType: "image/png", extensions: [".png"], label: "PNG" },
9
+ { mimeType: "image/jpeg", extensions: [".jpg", ".jpeg"], label: "JPG" },
10
+ { mimeType: "image/webp", extensions: [".webp"], label: "WEBP" }
11
+ ];
12
+ function formatsForKind(kind) {
13
+ return kind === "image" ? IMAGE_FORMATS : DOCUMENT_FORMATS;
14
+ }
15
+ function normalizeMimeType(type) {
16
+ return type.split(";", 1)[0]?.trim().toLowerCase() ?? "";
17
+ }
18
+ function acceptLabel(formats) {
19
+ return formats.map((format) => format.label).join(", ");
20
+ }
21
+ function formatOfFilename(formats, filename) {
22
+ const name = filename.toLowerCase();
23
+ return formats.find((format) => format.extensions.some((ext) => name.endsWith(ext)));
24
+ }
25
+ function isAcceptedFile(formats, file) {
26
+ const mimeType = normalizeMimeType(file.type);
27
+ if (mimeType) return formats.some((format) => format.mimeType === mimeType);
28
+ return formatOfFilename(formats, file.name) !== void 0;
29
+ }
30
+ function acceptMap(formats) {
31
+ const map = {};
32
+ for (const format of formats) map[format.mimeType] = [...format.extensions];
33
+ return map;
34
+ }
35
+
36
+ export { DOCUMENT_FORMATS, IMAGE_FORMATS, acceptLabel, acceptMap, formatOfFilename, formatsForKind, isAcceptedFile, normalizeMimeType };
37
+ //# sourceMappingURL=chunk-XCO6GTEC.js.map
38
+ //# sourceMappingURL=chunk-XCO6GTEC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/file-formats.ts"],"names":[],"mappings":";AA2EO,IAAM,gBAAA,GAA0C;AAAA,EACrD,EAAE,UAAU,iBAAA,EAAmB,UAAA,EAAY,CAAC,MAAM,CAAA,EAAG,OAAO,KAAA,EAAM;AAAA,EAClE,EAAE,UAAU,YAAA,EAAc,UAAA,EAAY,CAAC,MAAA,EAAQ,OAAO,CAAA,EAAG,KAAA,EAAO,KAAA,EAAM;AAAA,EACtE,EAAE,UAAU,WAAA,EAAa,UAAA,EAAY,CAAC,MAAM,CAAA,EAAG,OAAO,KAAA;AACxD;AAUO,IAAM,aAAA,GAAuC;AAAA,EAClD,EAAE,UAAU,WAAA,EAAa,UAAA,EAAY,CAAC,MAAM,CAAA,EAAG,OAAO,KAAA,EAAM;AAAA,EAC5D,EAAE,UAAU,YAAA,EAAc,UAAA,EAAY,CAAC,MAAA,EAAQ,OAAO,CAAA,EAAG,KAAA,EAAO,KAAA,EAAM;AAAA,EACtE,EAAE,UAAU,YAAA,EAAc,UAAA,EAAY,CAAC,OAAO,CAAA,EAAG,OAAO,MAAA;AAC1D;AASO,SAAS,eAAe,IAAA,EAAmD;AAChF,EAAA,OAAO,IAAA,KAAS,UAAU,aAAA,GAAgB,gBAAA;AAC5C;AAMO,SAAS,kBAAkB,IAAA,EAAsB;AACtD,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,GAAA,EAAK,CAAC,CAAA,CAAE,CAAC,CAAA,EAAG,IAAA,EAAK,CAAE,WAAA,EAAY,IAAK,EAAA;AACxD;AAGO,SAAS,YAAY,OAAA,EAAwC;AAClE,EAAA,OAAO,OAAA,CAAQ,IAAI,CAAC,MAAA,KAAW,OAAO,KAAK,CAAA,CAAE,KAAK,IAAI,CAAA;AACxD;AAMO,SAAS,gBAAA,CACd,SACA,QAAA,EACwB;AACxB,EAAA,MAAM,IAAA,GAAO,SAAS,WAAA,EAAY;AAClC,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,CAAC,MAAA,KAAW,MAAA,CAAO,UAAA,CAAW,IAAA,CAAK,CAAC,GAAA,KAAQ,IAAA,CAAK,QAAA,CAAS,GAAG,CAAC,CAAC,CAAA;AACrF;AAcO,SAAS,cAAA,CACd,SACA,IAAA,EACS;AACT,EAAA,MAAM,QAAA,GAAW,iBAAA,CAAkB,IAAA,CAAK,IAAI,CAAA;AAC5C,EAAA,IAAI,QAAA,SAAiB,OAAA,CAAQ,IAAA,CAAK,CAAC,MAAA,KAAW,MAAA,CAAO,aAAa,QAAQ,CAAA;AAC1E,EAAA,OAAO,gBAAA,CAAiB,OAAA,EAAS,IAAA,CAAK,IAAI,CAAA,KAAM,MAAA;AAClD;AASO,SAAS,UAAU,OAAA,EAA0D;AAClF,EAAA,MAAM,MAAgC,EAAC;AACvC,EAAA,KAAA,MAAW,MAAA,IAAU,SAAS,GAAA,CAAI,MAAA,CAAO,QAAQ,CAAA,GAAI,CAAC,GAAG,MAAA,CAAO,UAAU,CAAA;AAC1E,EAAA,OAAO,GAAA;AACT","file":"chunk-XCO6GTEC.js","sourcesContent":["/**\n * What a `document` or an `image` slot actually accepts.\n *\n * **This is a client-side mirror of a runtime fact, and the fact was measured\n * rather than read off a list.** The wire says a slot's kind is `document` or\n * `image` and stops there — which bytes a runtime can decode is a property of\n * that runtime, not of the method — so the list has to live on this side, and\n * the only honest place is one module that says where it came from.\n *\n * There is no single enum to copy. In `pipelex`, what a slot accepts is derived\n * per model:\n *\n * ModelSpec.supported_document_types = {\"pdf\",\"docx\",\"pptx\"} & set(inputs)\n * ModelSpec.is_vision_supported = \"images\" in inputs\n *\n * so the effective set is that vocabulary intersected with the **model deck's**\n * declared `inputs`. No model in the shipped deck declares `docx` or `pptx`;\n * every LLM entry is `[\"text\", \"images\", \"pdf\"]`, and the default extract model\n * (`azure-document-intelligence`) is `[\"image\", \"pdf\"]`.\n *\n * Confirmed by running each format end to end:\n *\n * | Format | PipeExtract | PipeLLM |\n * | --- | --- | --- |\n * | PDF | yes | yes |\n * | PNG | yes | n/a |\n * | JPEG | yes | n/a |\n * | WEBP | no | no |\n * | DOCX | no | no — `does not support docx documents` |\n * | PPTX | no | no — detected as `zip`, so it never even reaches the check |\n *\n * The gateway states its own list in the failure: *\"Supported formats:\n * application/pdf, image/jpeg, image/png as base64 data URLs.\"*\n *\n * Images were measured the same way: PNG, JPEG and WEBP pass; BMP and TIFF fail\n * on the provider's image enum; GIF fails too, though it is *in* that enum — it\n * arrives at the provider as a document block rather than an image one, which\n * looks like a routing bug upstream rather than an unsupported format.\n *\n * **A document slot's PNG and JPEG only work in an extract pipe.** The\n * descriptor never says which operator consumes the slot, so this table cannot\n * distinguish them; it matches the extract model's declared inputs, because\n * extraction is the operator that actually reads a document's bytes.\n *\n * What was here before was built on `DocumentFormat` (PDF/DOCX/PPTX), an enum\n * that is referenced nowhere in the runtime outside commented-out code and is\n * being deleted. A dead enum is the worst kind of source: it reads exactly like\n * a live one.\n *\n * A stale entry here is worse than no list at all, because it refuses a file the\n * runtime would have taken. If the deck grows a format, this table moves with it.\n *\n * **The table is the source; a field's `formats` is what gets read.** The\n * helpers below take a format LIST rather than a kind, because what a given\n * slot accepts can be narrower than its kind: a host whose server takes only\n * some of these types narrows the field tree once (`narrowFileFormats`), and\n * the dropzone's hint, its picker filter and its check all read the narrowed\n * list, so the three cannot disagree with each other or with that server.\n *\n * Pure data and pure functions over it. No React, no ajv, nothing imported.\n */\n\n/** One accepted format: its MIME type and the extensions that carry it. */\nexport interface FileFormat {\n mimeType: string;\n /** Leading dot, lowercase — the shape a file input's `accept` wants. */\n extensions: string[];\n /** How the format is named to a user, uppercase. */\n label: string;\n}\n\n/**\n * What a `document` slot takes: PDF, plus the two image formats the extract\n * model reads as a single-page document.\n */\nexport const DOCUMENT_FORMATS: readonly FileFormat[] = [\n { mimeType: 'application/pdf', extensions: ['.pdf'], label: 'PDF' },\n { mimeType: 'image/jpeg', extensions: ['.jpg', '.jpeg'], label: 'JPG' },\n { mimeType: 'image/png', extensions: ['.png'], label: 'PNG' },\n];\n\n/**\n * What an `image` slot takes: PNG, JPEG, WEBP — all three measured through the\n * vision path.\n *\n * `.jpg` and `.jpeg` both ride `image/jpeg`. `JPG` is the label because that is\n * the spelling the runtime uses, but a file named `.jpeg` is the same bytes and\n * must not be refused over its spelling.\n */\nexport const IMAGE_FORMATS: readonly FileFormat[] = [\n { mimeType: 'image/png', extensions: ['.png'], label: 'PNG' },\n { mimeType: 'image/jpeg', extensions: ['.jpg', '.jpeg'], label: 'JPG' },\n { mimeType: 'image/webp', extensions: ['.webp'], label: 'WEBP' },\n];\n\n/**\n * The source table: every format a slot of this kind can take, before a host\n * narrows it. `buildRunFields` stamps this onto each `document` and `image`\n * field as its `formats`, and everything downstream reads the field's list\n * rather than coming back here - which is what lets a host narrow one list and\n * have the hint, the picker and the check all follow it.\n */\nexport function formatsForKind(kind: 'document' | 'image'): readonly FileFormat[] {\n return kind === 'image' ? IMAGE_FORMATS : DOCUMENT_FORMATS;\n}\n\n/**\n * A MIME type as the table spells it: no parameters, no surrounding space,\n * lowercase. `APPLICATION/PDF; version=1.7` is `application/pdf`.\n */\nexport function normalizeMimeType(type: string): string {\n return type.split(';', 1)[0]?.trim().toLowerCase() ?? '';\n}\n\n/** `\"PDF, JPG, PNG\"` - the hint shown under a dropzone. */\nexport function acceptLabel(formats: readonly FileFormat[]): string {\n return formats.map((format) => format.label).join(', ');\n}\n\n/**\n * The format a filename's extension names, among these formats, or `undefined`\n * when it names none of them. Case-insensitive, because `PHOTO.PNG` is a PNG.\n */\nexport function formatOfFilename(\n formats: readonly FileFormat[],\n filename: string,\n): FileFormat | undefined {\n const name = filename.toLowerCase();\n return formats.find((format) => format.extensions.some((ext) => name.endsWith(ext)));\n}\n\n/**\n * Whether a picked file is one of these formats.\n *\n * Checks the MIME type first and falls back to the extension, because a\n * browser's `File.type` is empty often enough to matter: an OS with no handler\n * registered for `.docx` reports `''`, and refusing that file would be refusing\n * a valid one over a fact about the user's machine. A wrong-but-present MIME\n * type is still a rejection — that is the case this exists for.\n *\n * It takes the field's own list, never the kind's, so a slot a host narrowed\n * refuses exactly what its hint no longer names.\n */\nexport function isAcceptedFile(\n formats: readonly FileFormat[],\n file: { name: string; type: string },\n): boolean {\n const mimeType = normalizeMimeType(file.type);\n if (mimeType) return formats.some((format) => format.mimeType === mimeType);\n return formatOfFilename(formats, file.name) !== undefined;\n}\n\n/**\n * The accept map a file input wants: MIME type to extensions.\n *\n * Shaped for `react-dropzone`'s `accept`, which is the same shape the DOM's\n * `accept` attribute is built from. Listing extensions BESIDE the MIME type is\n * what makes the empty-`File.type` case above work in the OS picker too.\n */\nexport function acceptMap(formats: readonly FileFormat[]): Record<string, string[]> {\n const map: Record<string, string[]> = {};\n for (const format of formats) map[format.mimeType] = [...format.extensions];\n return map;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { acceptLabelForKind } from './chunk-2JWRG53S.js';
1
+ import { formatsForKind } from './chunk-XCO6GTEC.js';
2
2
  import { collectSchemaDefs, resolveSchemaNode } from './chunk-OD3VYXUY.js';
3
3
  import { buildPipeRef } from './chunk-WYH56SOZ.js';
4
4
  import { ownProp } from './chunk-V3OV2XQT.js';
@@ -85,7 +85,7 @@ function mapNode(node, name, rawSchema, defs) {
85
85
  return { ...common, kind: "enum", options: node.choices.map(String) };
86
86
  case "document":
87
87
  case "image":
88
- return { ...common, kind: node.kind, accept: acceptLabelForKind(node.kind) };
88
+ return { ...common, kind: node.kind, formats: formatsForKind(node.kind) };
89
89
  case "object": {
90
90
  const props = schema?.properties;
91
91
  return {
@@ -133,5 +133,5 @@ function buildRunFields(descriptor, inputs) {
133
133
  }
134
134
 
135
135
  export { buildResultField, buildRunFields, getPipeInputForm };
136
- //# sourceMappingURL=chunk-KIEOLP2L.js.map
137
- //# sourceMappingURL=chunk-KIEOLP2L.js.map
136
+ //# sourceMappingURL=chunk-ZB4RYUKV.js.map
137
+ //# sourceMappingURL=chunk-ZB4RYUKV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/derive.ts"],"names":[],"mappings":"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","file":"chunk-ZB4RYUKV.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 { formatsForKind } from './file-formats';\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 case 'image':\n // `formats` is a renderer-side affordance the wire deliberately does not\n // state - which bytes a runtime can decode is a property of the runtime,\n // not of the method. The list is therefore ours, and it is one table\n // (`./file-formats`) rather than a literal here. The field carries the\n // LIST, not a label made from it, so the hint a user reads, the filter the\n // dropzone applies and the check it enforces all read one value and cannot\n // disagree - and a host narrowing it (`narrowFileFormats`) moves all three.\n // They used to disagree: this line advertised `TXT`, which no format\n // covered, and later the hint was a label while the filter and the check\n // went back to the kind's table, so rewriting the label moved nothing else.\n return { ...common, kind: node.kind, formats: formatsForKind(node.kind) };\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 `mthds` does not\n // define. The switch above is exhaustive over `InputFormItem`, so\n // `satisfies never` keeps the build LOUD when the PIN grows a kind - and\n // this return keeps the mapper TOTAL when a SERVER is ahead of that pin,\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 */\n/**\n * The same mapping, for a single node that belongs to no slot — a pipe's OUTPUT.\n *\n * `buildRunFields` maps a descriptor's fields and then stamps each with the slot\n * facts (`presence`, `gating`) the wire states per input. An output has no slot,\n * so this stamps nothing: the node arrives without them and leaves without them,\n * which is exactly what the standard's optional members are for.\n *\n * Everything else is shared, deliberately. An output is a concept ref like an\n * input is, so its kinds, its nesting, its list bounds and its `contentKey` are\n * the same questions with the same answers — and a second mapper would be a\n * second place for them to drift.\n *\n * ## `schema` is REQUIRED, and that is the whole point\n *\n * It was optional once, and the renderer paid for it: with no schema it could\n * not know that `native.Text`'s payload sits under `text`, so it worked the\n * unwrapping out by COUNTING the value's properties, and worked a plural payload\n * out by looking for an `items` key. Both are shape sniffing — the exact pattern\n * [../../docs/derivation-swap.md] records deleting from the input side, where\n * `contentKey` is read off a schema and handed to a control as a property NAME.\n *\n * So the parameter is required, the two heuristics are gone, and what the\n * argument must be is stated precisely: **the schema of the PAYLOAD**, which for\n * every kind but `object` is the content model that wraps it —\n * `TextContent {text}` for a `native.Text` output, `ListContent {items}` for a\n * plural one. That is a change the standard has to make on the output contract\n * (see `./output-form`); until it does, a producer supplies it beside the\n * descriptor.\n */\nexport function buildResultField(\n descriptor: { field: InputFormField },\n schema: Record<string, unknown>,\n): RunField {\n const node = descriptor.field;\n const defs: Record<string, JsonSchema> = {};\n collectSchemaDefs(schema as JsonSchema, defs, { traverseArrays: true });\n\n // Unwrap the content model, ONCE, at the top.\n //\n // A result's payload is its concept's content model, and for every kind but\n // `object` that model is a wrapper: the value sits under a single property the\n // schema names. Reading it here rather than in `mapNode` is what keeps the\n // schema walk ALIGNED with the descriptor beneath it — a plural output's node\n // is a `list`, so the schema it must be walked against is the `items` array,\n // not the `ListContent` object around it.\n //\n // Gated on the node's stated KIND, never on the value: an `object` output IS\n // its content model, and a structured concept that happens to declare exactly\n // one field would otherwise be mistaken for a wrapper. The kind comes from the\n // descriptor, so this is a read of what the field is, not a guess at it.\n const wrapperKey = node.kind === 'object' ? undefined : scalarWrapperKey(schema as JsonSchema);\n const inner =\n wrapperKey === undefined\n ? (schema as JsonSchema)\n : ((schema as JsonSchema).properties as Record<string, JsonSchema>)[wrapperKey];\n\n const field = mapNode(node, node.name, inner, defs);\n return wrapperKey === undefined ? field : { ...field, contentKey: wrapperKey };\n}\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"]}
@@ -1,6 +1,7 @@
1
1
  import { InputFormField, PipeInputFormDescriptor, PipeInputContract, InputForm } from 'mthds/protocol';
2
2
  import { RunField } from './descriptor.js';
3
3
  import './contracts.js';
4
+ import './file-formats.js';
4
5
 
5
6
  /**
6
7
  * The ONE derivation function: wire input-form descriptor → `RunField[]`.
@@ -1,5 +1,5 @@
1
- export { buildResultField, buildRunFields, getPipeInputForm } from '../chunk-KIEOLP2L.js';
2
- import '../chunk-2JWRG53S.js';
1
+ export { buildResultField, buildRunFields, getPipeInputForm } from '../chunk-ZB4RYUKV.js';
2
+ import '../chunk-XCO6GTEC.js';
3
3
  import '../chunk-OD3VYXUY.js';
4
4
  import '../chunk-WYH56SOZ.js';
5
5
  import '../chunk-V3OV2XQT.js';
@@ -1,4 +1,5 @@
1
1
  import { InputPresence } from './contracts.js';
2
+ import { FileFormat } from './file-formats.js';
2
3
  import 'mthds/protocol';
3
4
 
4
5
  /**
@@ -123,8 +124,18 @@ interface EnumRunField extends RunFieldCommon {
123
124
  }
124
125
  interface FileRunField extends RunFieldCommon {
125
126
  kind: 'document' | 'image';
126
- /** Accept hint shown to the user, e.g. "PDF, PNG, JPG". */
127
- accept?: string;
127
+ /**
128
+ * The formats this slot accepts, in the order the hint names them. The ONE
129
+ * list the file control reads for all three of its answers - the hint under
130
+ * the dropzone, the OS picker's filter and the check a picked or dropped file
131
+ * must pass - so none of them can promise what another refuses.
132
+ *
133
+ * Not a wire fact: which bytes a runtime can decode is a property of the
134
+ * runtime, so `buildRunFields` stamps the kind's whole table here
135
+ * (`formatsForKind`), and a host whose own upload path takes less narrows the
136
+ * tree with `narrowFileFormats`.
137
+ */
138
+ formats: readonly FileFormat[];
128
139
  }
129
140
  interface ObjectRunField extends RunFieldCommon {
130
141
  kind: 'object';
@@ -1,3 +1,3 @@
1
- export { conceptCategory } from '../chunk-25I6JDIK.js';
1
+ export { conceptCategory } from '../chunk-FABY3DEY.js';
2
2
  //# sourceMappingURL=descriptor.js.map
3
3
  //# sourceMappingURL=descriptor.js.map
@@ -50,7 +50,14 @@
50
50
  * A stale entry here is worse than no list at all, because it refuses a file the
51
51
  * runtime would have taken. If the deck grows a format, this table moves with it.
52
52
  *
53
- * Pure data. No React, no ajv, nothing imported.
53
+ * **The table is the source; a field's `formats` is what gets read.** The
54
+ * helpers below take a format LIST rather than a kind, because what a given
55
+ * slot accepts can be narrower than its kind: a host whose server takes only
56
+ * some of these types narrows the field tree once (`narrowFileFormats`), and
57
+ * the dropzone's hint, its picker filter and its check all read the narrowed
58
+ * list, so the three cannot disagree with each other or with that server.
59
+ *
60
+ * Pure data and pure functions over it. No React, no ajv, nothing imported.
54
61
  */
55
62
  /** One accepted format: its MIME type and the extensions that carry it. */
56
63
  interface FileFormat {
@@ -74,19 +81,39 @@ declare const DOCUMENT_FORMATS: readonly FileFormat[];
74
81
  * must not be refused over its spelling.
75
82
  */
76
83
  declare const IMAGE_FORMATS: readonly FileFormat[];
84
+ /**
85
+ * The source table: every format a slot of this kind can take, before a host
86
+ * narrows it. `buildRunFields` stamps this onto each `document` and `image`
87
+ * field as its `formats`, and everything downstream reads the field's list
88
+ * rather than coming back here - which is what lets a host narrow one list and
89
+ * have the hint, the picker and the check all follow it.
90
+ */
77
91
  declare function formatsForKind(kind: 'document' | 'image'): readonly FileFormat[];
78
- /** `"PDF, DOCX, PPTX"` — the hint shown under a dropzone. */
79
- declare function acceptLabelForKind(kind: 'document' | 'image'): string;
80
92
  /**
81
- * Whether a picked file is one this kind accepts.
93
+ * A MIME type as the table spells it: no parameters, no surrounding space,
94
+ * lowercase. `APPLICATION/PDF; version=1.7` is `application/pdf`.
95
+ */
96
+ declare function normalizeMimeType(type: string): string;
97
+ /** `"PDF, JPG, PNG"` - the hint shown under a dropzone. */
98
+ declare function acceptLabel(formats: readonly FileFormat[]): string;
99
+ /**
100
+ * The format a filename's extension names, among these formats, or `undefined`
101
+ * when it names none of them. Case-insensitive, because `PHOTO.PNG` is a PNG.
102
+ */
103
+ declare function formatOfFilename(formats: readonly FileFormat[], filename: string): FileFormat | undefined;
104
+ /**
105
+ * Whether a picked file is one of these formats.
82
106
  *
83
107
  * Checks the MIME type first and falls back to the extension, because a
84
108
  * browser's `File.type` is empty often enough to matter: an OS with no handler
85
109
  * registered for `.docx` reports `''`, and refusing that file would be refusing
86
110
  * a valid one over a fact about the user's machine. A wrong-but-present MIME
87
111
  * type is still a rejection — that is the case this exists for.
112
+ *
113
+ * It takes the field's own list, never the kind's, so a slot a host narrowed
114
+ * refuses exactly what its hint no longer names.
88
115
  */
89
- declare function isAcceptedFile(kind: 'document' | 'image', file: {
116
+ declare function isAcceptedFile(formats: readonly FileFormat[], file: {
90
117
  name: string;
91
118
  type: string;
92
119
  }): boolean;
@@ -97,6 +124,6 @@ declare function isAcceptedFile(kind: 'document' | 'image', file: {
97
124
  * `accept` attribute is built from. Listing extensions BESIDE the MIME type is
98
125
  * what makes the empty-`File.type` case above work in the OS picker too.
99
126
  */
100
- declare function acceptMapForKind(kind: 'document' | 'image'): Record<string, string[]>;
127
+ declare function acceptMap(formats: readonly FileFormat[]): Record<string, string[]>;
101
128
 
102
- export { DOCUMENT_FORMATS, type FileFormat, IMAGE_FORMATS, acceptLabelForKind, acceptMapForKind, formatsForKind, isAcceptedFile };
129
+ export { DOCUMENT_FORMATS, type FileFormat, IMAGE_FORMATS, acceptLabel, acceptMap, formatOfFilename, formatsForKind, isAcceptedFile, normalizeMimeType };
@@ -1,3 +1,3 @@
1
- export { DOCUMENT_FORMATS, IMAGE_FORMATS, acceptLabelForKind, acceptMapForKind, formatsForKind, isAcceptedFile } from '../chunk-2JWRG53S.js';
1
+ export { DOCUMENT_FORMATS, IMAGE_FORMATS, acceptLabel, acceptMap, formatOfFilename, formatsForKind, isAcceptedFile, normalizeMimeType } from '../chunk-XCO6GTEC.js';
2
2
  //# sourceMappingURL=file-formats.js.map
3
3
  //# sourceMappingURL=file-formats.js.map
@@ -1,6 +1,7 @@
1
1
  import { PipeInputContract } from 'mthds/protocol';
2
2
  import { RunField } from './descriptor.js';
3
3
  import './contracts.js';
4
+ import './file-formats.js';
4
5
 
5
6
  /**
6
7
  * The gate's own field tree - structural, schema-derived, and private.
@@ -3,7 +3,8 @@ export { IOMultiplicity, InputForm, InputFormTopLevelField, OutputForm, PipeIOCo
3
3
  export { buildResultField, buildRunFields, getPipeInputForm } from './derive.js';
4
4
  export { getPipeOutputForm } from './output-form.js';
5
5
  export { StuffFile, collectStuffFiles } from './stuff-files.js';
6
- export { DOCUMENT_FORMATS, FileFormat, IMAGE_FORMATS, acceptLabelForKind, acceptMapForKind, formatsForKind, isAcceptedFile } from './file-formats.js';
6
+ export { DOCUMENT_FORMATS, FileFormat, IMAGE_FORMATS, acceptLabel, acceptMap, formatsForKind, isAcceptedFile } from './file-formats.js';
7
+ export { narrowFileFormats } from './narrow-file-formats.js';
7
8
  export { CompositeMember, DataUrlView, DateContentView, DocumentContentView, HtmlContentView, ImageContentView, NATIVE_COMPOSITE_CONCEPT_REF, NATIVE_DATE_CONCEPT_REF, NATIVE_HTML_CONCEPT_REF, TYPED_SCALAR_MARKERS, formatDateContent, hasTypedScalarMarkers, isNativeCompositeNode, isNativeDateNode, isNativeHtmlNode, isViewableUrl, readCompositeContent, readDataUrl, readDateContent, readDocumentContent, readHtmlContent, readImageContent, viewableUrl } from './native-content.js';
8
9
  export { Readiness, computeReadiness, fieldFilled, isFilled, mustBeFilled } from './readiness.js';
9
10
  export { InputPresence, buildPipeRef, getPipeIOContract, inputMustBeFilled, isFixedCountInput, isOptionalInput, isPluralInput } from './contracts.js';
@@ -1,11 +1,12 @@
1
1
  export { describeValidationError, displayValue, valueAtProperty } from '../chunk-RPA7DNSK.js';
2
- export { apiInputsFromRunValues, fieldsForContract, inputDataFromWorkingMemory, outputsFromPipeOutput, rjsfDataFromRunValues, runValuesFromStore, setValueAtPath, storeInputDataFromRunValues } from '../chunk-YABRYTQ4.js';
2
+ export { apiInputsFromRunValues, fieldsForContract, inputDataFromWorkingMemory, outputsFromPipeOutput, rjsfDataFromRunValues, runValuesFromStore, setValueAtPath, storeInputDataFromRunValues } from '../chunk-4KGQ65TQ.js';
3
+ export { collectStuffFiles } from '../chunk-4JQAJT7C.js';
4
+ export { narrowFileFormats } from '../chunk-CAKQ5VFT.js';
5
+ export { NATIVE_COMPOSITE_CONCEPT_REF, NATIVE_DATE_CONCEPT_REF, NATIVE_HTML_CONCEPT_REF, TYPED_SCALAR_MARKERS, formatDateContent, hasTypedScalarMarkers, isNativeCompositeNode, isNativeDateNode, isNativeHtmlNode, isViewableUrl, readCompositeContent, readDataUrl, readDateContent, readDocumentContent, readHtmlContent, readImageContent, viewableUrl } from '../chunk-TID7ZN63.js';
3
6
  export { getPipeOutputForm } from '../chunk-DARLDVJM.js';
4
- export { collectStuffFiles } from '../chunk-S4CB423P.js';
5
- export { NATIVE_COMPOSITE_CONCEPT_REF, NATIVE_DATE_CONCEPT_REF, NATIVE_HTML_CONCEPT_REF, TYPED_SCALAR_MARKERS, formatDateContent, hasTypedScalarMarkers, isNativeCompositeNode, isNativeDateNode, isNativeHtmlNode, isViewableUrl, readCompositeContent, readDataUrl, readDateContent, readDocumentContent, readHtmlContent, readImageContent, viewableUrl } from '../chunk-AZZAAGNX.js';
6
- export { buildResultField, buildRunFields, getPipeInputForm } from '../chunk-KIEOLP2L.js';
7
- export { conceptCategory } from '../chunk-25I6JDIK.js';
8
- export { DOCUMENT_FORMATS, IMAGE_FORMATS, acceptLabelForKind, acceptMapForKind, formatsForKind, isAcceptedFile } from '../chunk-2JWRG53S.js';
7
+ export { buildResultField, buildRunFields, getPipeInputForm } from '../chunk-ZB4RYUKV.js';
8
+ export { conceptCategory } from '../chunk-FABY3DEY.js';
9
+ export { DOCUMENT_FORMATS, IMAGE_FORMATS, acceptLabel, acceptMap, formatsForKind, isAcceptedFile } from '../chunk-XCO6GTEC.js';
9
10
  export { apiInputsFromSchemaData, buildRunInputsSchema, gateRunInputs, prepareRunInputs, validateRunInputs } from '../chunk-IUWLOSAM.js';
10
11
  export { deflateAllInputs, deflateInput, healStringWrappers, inflateAllInputs, inflateInput, pruneEmptyOptionals, resolveConceptCode } from '../chunk-GCXV76WU.js';
11
12
  export { normalizeSchemaForRjsf, prepareSchemaForRjsf } from '../chunk-LBFZXYCY.js';
@@ -0,0 +1,50 @@
1
+ import { RunField } from './descriptor.js';
2
+ import './contracts.js';
3
+ import 'mthds/protocol';
4
+ import './file-formats.js';
5
+
6
+ /**
7
+ * Narrowing what a form's file slots accept to what a host will take.
8
+ *
9
+ * `buildRunFields` gives every `document` and `image` field the whole of its
10
+ * kind's table (`./file-formats`): everything the runtime can decode. A host's
11
+ * own upload path can be narrower - a method that only ever reads photographs,
12
+ * a server that stores only some types - and a dropzone that advertises more
13
+ * than the server takes refuses the file only after the upload has been asked
14
+ * for. So a host narrows the tree once, with the same list its server checks
15
+ * uploads against, and the control reads the narrowed list for its hint, its
16
+ * picker filter and its check.
17
+ *
18
+ * It reads `RunField`, the kernel's own output, and never a JSON Schema: which
19
+ * bytes a runtime can decode is not a wire fact, so there is nothing in the
20
+ * schema to read, and the two schema walks the kernel allows stay the only two.
21
+ *
22
+ * It lives in the core rather than on `FieldEnv` so that a host's server, which
23
+ * renders no control, can hold the very list its form was narrowed with.
24
+ *
25
+ * Pure: no React, no ajv, and the input tree is never mutated.
26
+ */
27
+
28
+ /**
29
+ * The field tree with every `document` and `image` field narrowed to the
30
+ * formats whose MIME type is in `mimeTypes`, walking nested structures and
31
+ * list items.
32
+ *
33
+ * One list serves every slot: it is intersected with each slot's own formats,
34
+ * so a list of PDF, PNG and JPEG leaves a document slot with all three and an
35
+ * image slot with PNG and JPEG. Narrowing never widens a slot - a MIME type the
36
+ * slot's kind cannot take is simply not in the intersection - and each slot
37
+ * keeps its own table's order, whatever order the list is in. MIME types are
38
+ * compared the way `isAcceptedFile` compares them: without parameters, and
39
+ * case-insensitively.
40
+ *
41
+ * **Throws when a slot would be left accepting nothing**, naming the field. A
42
+ * dropzone that refuses every file is a host's configuration error, and a form
43
+ * that renders one has already failed the person holding the file.
44
+ *
45
+ * The input tree is never mutated: a file slot, a structure or a list comes
46
+ * back as a copy, and every other field as the same object it was.
47
+ */
48
+ declare function narrowFileFormats(fields: readonly RunField[], mimeTypes: readonly string[]): RunField[];
49
+
50
+ export { narrowFileFormats };
@@ -0,0 +1,4 @@
1
+ export { narrowFileFormats } from '../chunk-CAKQ5VFT.js';
2
+ import '../chunk-XCO6GTEC.js';
3
+ //# sourceMappingURL=narrow-file-formats.js.map
4
+ //# sourceMappingURL=narrow-file-formats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"narrow-file-formats.js"}
@@ -132,10 +132,7 @@ declare function readCompositeContent(value: unknown): CompositeMember[] | undef
132
132
  * wants the markup rendered just the same. `refines` is on the wire for exactly
133
133
  * this question.
134
134
  */
135
- declare function isNativeHtmlNode(node: {
136
- conceptRef?: string;
137
- refines?: readonly string[];
138
- }): boolean;
135
+ declare function isNativeHtmlNode(node: NativeNode): boolean;
139
136
  /**
140
137
  * Whether a node IS a `native.Date` — the other content model the kind
141
138
  * vocabulary cannot name.
@@ -150,10 +147,7 @@ declare function isNativeHtmlNode(node: {
150
147
  * A `date` FIELD inside a structure is a different thing and needs none of this:
151
148
  * it carries `kind: "date"` already.
152
149
  */
153
- declare function isNativeDateNode(node: {
154
- conceptRef?: string;
155
- refines?: readonly string[];
156
- }): boolean;
150
+ declare function isNativeDateNode(node: NativeNode): boolean;
157
151
  /**
158
152
  * Whether a node is a `native.Composite` — a named bag of contents.
159
153
  *
@@ -168,10 +162,25 @@ declare function isNativeDateNode(node: {
168
162
  * of ordinary `StuffContent`s. Keyed by concept, a renderer can at least show
169
163
  * the members as the named things they are. See `CompositeValue`.
170
164
  */
171
- declare function isNativeCompositeNode(node: {
165
+ declare function isNativeCompositeNode(node: NativeNode): boolean;
166
+ /**
167
+ * Whether a node is one of the three natives the kind vocabulary cannot name —
168
+ * a date, a page, a composite — which a renderer reads by CONCEPT before it
169
+ * reads the kind. A list of one answers no (the predicates refuse a `list`
170
+ * node), and its item answers yes.
171
+ *
172
+ * One answer, read twice: the result view renders a list whose item answers yes
173
+ * one value per line rather than as a table, and the generative layer delegates
174
+ * that list to the kernel, because no catalog component reads a native value.
175
+ * Not re-exported: a host asks the three predicates it needs.
176
+ */
177
+ declare function isNativeValueNode(node: NativeNode): boolean;
178
+ /** What the native predicates read off a node: its stated kind and its concept. */
179
+ interface NativeNode {
180
+ kind?: string;
172
181
  conceptRef?: string;
173
182
  refines?: readonly string[];
174
- }): boolean;
183
+ }
175
184
  /**
176
185
  * Read a `date`-kind value, in any of the three shapes a run produces.
177
186
  *
@@ -263,4 +272,4 @@ declare const TYPED_SCALAR_MARKERS: readonly ["__class__", "__module__"];
263
272
  /** Whether a record carries the typed-scalar markers. Informational. */
264
273
  declare function hasTypedScalarMarkers(value: unknown): boolean;
265
274
 
266
- export { type CompositeMember, type DataUrlView, type DateContentView, type DocumentContentView, type HtmlContentView, type ImageContentView, NATIVE_COMPOSITE_CONCEPT_REF, NATIVE_DATE_CONCEPT_REF, NATIVE_HTML_CONCEPT_REF, TYPED_SCALAR_MARKERS, formatDateContent, hasTypedScalarMarkers, isNativeCompositeNode, isNativeDateNode, isNativeHtmlNode, isViewableUrl, readCompositeContent, readDataUrl, readDateContent, readDocumentContent, readHtmlContent, readImageContent, viewableUrl };
275
+ export { type CompositeMember, type DataUrlView, type DateContentView, type DocumentContentView, type HtmlContentView, type ImageContentView, NATIVE_COMPOSITE_CONCEPT_REF, NATIVE_DATE_CONCEPT_REF, NATIVE_HTML_CONCEPT_REF, TYPED_SCALAR_MARKERS, formatDateContent, hasTypedScalarMarkers, isNativeCompositeNode, isNativeDateNode, isNativeHtmlNode, isNativeValueNode, isViewableUrl, readCompositeContent, readDataUrl, readDateContent, readDocumentContent, readHtmlContent, readImageContent, viewableUrl };
@@ -1,4 +1,4 @@
1
- export { NATIVE_COMPOSITE_CONCEPT_REF, NATIVE_DATE_CONCEPT_REF, NATIVE_HTML_CONCEPT_REF, TYPED_SCALAR_MARKERS, formatDateContent, hasTypedScalarMarkers, isNativeCompositeNode, isNativeDateNode, isNativeHtmlNode, isViewableUrl, readCompositeContent, readDataUrl, readDateContent, readDocumentContent, readHtmlContent, readImageContent, viewableUrl } from '../chunk-AZZAAGNX.js';
1
+ export { NATIVE_COMPOSITE_CONCEPT_REF, NATIVE_DATE_CONCEPT_REF, NATIVE_HTML_CONCEPT_REF, TYPED_SCALAR_MARKERS, formatDateContent, hasTypedScalarMarkers, isNativeCompositeNode, isNativeDateNode, isNativeHtmlNode, isNativeValueNode, isViewableUrl, readCompositeContent, readDataUrl, readDateContent, readDocumentContent, readHtmlContent, readImageContent, viewableUrl } from '../chunk-TID7ZN63.js';
2
2
  import '../chunk-V3OV2XQT.js';
3
3
  //# sourceMappingURL=native-content.js.map
4
4
  //# sourceMappingURL=native-content.js.map
@@ -1,6 +1,7 @@
1
1
  import { RunField } from './descriptor.js';
2
2
  import './contracts.js';
3
3
  import 'mthds/protocol';
4
+ import './file-formats.js';
4
5
 
5
6
  /**
6
7
  * Value readiness - the helpers the runner uses to decide whether the Run
@@ -1,6 +1,7 @@
1
1
  import { RunField } from './descriptor.js';
2
2
  import './contracts.js';
3
3
  import 'mthds/protocol';
4
+ import './file-formats.js';
4
5
 
5
6
  /**
6
7
  * One file a stuff carries: what to fetch, and what to call it once saved.
@@ -1,5 +1,5 @@
1
- export { collectStuffFiles } from '../chunk-S4CB423P.js';
2
- import '../chunk-AZZAAGNX.js';
1
+ export { collectStuffFiles } from '../chunk-4JQAJT7C.js';
2
+ import '../chunk-TID7ZN63.js';
3
3
  import '../chunk-V3OV2XQT.js';
4
4
  //# sourceMappingURL=stuff-files.js.map
5
5
  //# sourceMappingURL=stuff-files.js.map
@@ -1,6 +1,7 @@
1
1
  import { PipeInputContract, PipeIOContract, PipeInputFormDescriptor } from 'mthds/protocol';
2
2
  import { RunField } from './descriptor.js';
3
3
  import './contracts.js';
4
+ import './file-formats.js';
4
5
 
5
6
  /**
6
7
  * Bridges the `MethodRunner`'s field values to the rest of the host.
@@ -1,6 +1,6 @@
1
- export { apiInputsFromRunValues, fieldsForContract, inputDataFromWorkingMemory, outputsFromPipeOutput, rjsfDataFromRunValues, runValuesFromStore, setValueAtPath, storeInputDataFromRunValues } from '../chunk-YABRYTQ4.js';
2
- import '../chunk-KIEOLP2L.js';
3
- import '../chunk-2JWRG53S.js';
1
+ export { apiInputsFromRunValues, fieldsForContract, inputDataFromWorkingMemory, outputsFromPipeOutput, rjsfDataFromRunValues, runValuesFromStore, setValueAtPath, storeInputDataFromRunValues } from '../chunk-4KGQ65TQ.js';
2
+ import '../chunk-ZB4RYUKV.js';
3
+ import '../chunk-XCO6GTEC.js';
4
4
  import '../chunk-GCXV76WU.js';
5
5
  import '../chunk-PM55AHRO.js';
6
6
  import '../chunk-GKV77RAS.js';