@pipelex/mthds-form 0.4.0 → 0.6.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 (76) hide show
  1. package/README.md +15 -6
  2. package/dist/{chunk-6XD6UZSU.js → chunk-25I6JDIK.js} +2 -2
  3. package/dist/chunk-25I6JDIK.js.map +1 -0
  4. package/dist/chunk-2JWRG53S.js +33 -0
  5. package/dist/chunk-2JWRG53S.js.map +1 -0
  6. package/dist/chunk-45C2MKK6.js +94 -0
  7. package/dist/chunk-45C2MKK6.js.map +1 -0
  8. package/dist/chunk-4BSBBG2T.js +80 -0
  9. package/dist/chunk-4BSBBG2T.js.map +1 -0
  10. package/dist/{chunk-7BMOPXDY.js → chunk-GCXV76WU.js} +17 -9
  11. package/dist/chunk-GCXV76WU.js.map +1 -0
  12. package/dist/chunk-IIU3YK4O.js +16 -0
  13. package/dist/chunk-IIU3YK4O.js.map +1 -0
  14. package/dist/chunk-J4L32LD6.js +137 -0
  15. package/dist/chunk-J4L32LD6.js.map +1 -0
  16. package/dist/{chunk-KFZ5MZOM.js → chunk-LBFZXYCY.js} +3 -3
  17. package/dist/{chunk-KFZ5MZOM.js.map → chunk-LBFZXYCY.js.map} +1 -1
  18. package/dist/{chunk-O4O3QNVC.js → chunk-OD3VYXUY.js} +13 -3
  19. package/dist/chunk-OD3VYXUY.js.map +1 -0
  20. package/dist/{chunk-XEPD5VJQ.js → chunk-R7B7ID25.js} +8 -8
  21. package/dist/chunk-R7B7ID25.js.map +1 -0
  22. package/dist/{chunk-WXBSM2CE.js → chunk-T4NSAGOS.js} +8 -8
  23. package/dist/chunk-T4NSAGOS.js.map +1 -0
  24. package/dist/{chunk-HARYEWNG.js → chunk-XYQ7NXQZ.js} +2 -2
  25. package/dist/chunk-XYQ7NXQZ.js.map +1 -0
  26. package/dist/chunk-YEVVR6FE.js +66 -0
  27. package/dist/chunk-YEVVR6FE.js.map +1 -0
  28. package/dist/core/contracts.d.ts +27 -56
  29. package/dist/core/contracts.js +1 -1
  30. package/dist/core/derive.d.ts +79 -11
  31. package/dist/core/derive.js +4 -4
  32. package/dist/core/descriptor.d.ts +70 -26
  33. package/dist/core/descriptor.js +1 -1
  34. package/dist/core/file-formats.d.ts +102 -0
  35. package/dist/core/file-formats.js +3 -0
  36. package/dist/core/file-formats.js.map +1 -0
  37. package/dist/core/gate.d.ts +1 -1
  38. package/dist/core/gate.js +7 -8
  39. package/dist/core/gating-fields.d.ts +38 -0
  40. package/dist/core/gating-fields.js +6 -0
  41. package/dist/core/gating-fields.js.map +1 -0
  42. package/dist/core/index.d.ts +8 -3
  43. package/dist/core/index.js +14 -10
  44. package/dist/core/native-content.d.ts +219 -0
  45. package/dist/core/native-content.js +4 -0
  46. package/dist/core/{native-concepts.js.map → native-content.js.map} +1 -1
  47. package/dist/core/normalize-schema.js +2 -2
  48. package/dist/core/output-form.d.ts +45 -0
  49. package/dist/core/output-form.js +5 -0
  50. package/dist/core/output-form.js.map +1 -0
  51. package/dist/core/readiness.d.ts +2 -0
  52. package/dist/core/schema-utils.d.ts +13 -1
  53. package/dist/core/schema-utils.js +1 -1
  54. package/dist/core/stuff-files.d.ts +52 -0
  55. package/dist/core/stuff-files.js +5 -0
  56. package/dist/core/stuff-files.js.map +1 -0
  57. package/dist/core/values.d.ts +10 -3
  58. package/dist/core/values.js +7 -7
  59. package/dist/core/wire-format.js +3 -4
  60. package/dist/react/index.d.ts +278 -1
  61. package/dist/react/index.js +1378 -29
  62. package/dist/react/index.js.map +1 -1
  63. package/dist/styles.css +1 -1
  64. package/package.json +17 -3
  65. package/dist/chunk-6XD6UZSU.js.map +0 -1
  66. package/dist/chunk-7BMOPXDY.js.map +0 -1
  67. package/dist/chunk-HARYEWNG.js.map +0 -1
  68. package/dist/chunk-NMT7BRLO.js +0 -40
  69. package/dist/chunk-NMT7BRLO.js.map +0 -1
  70. package/dist/chunk-O4O3QNVC.js.map +0 -1
  71. package/dist/chunk-VMLXO5JS.js +0 -132
  72. package/dist/chunk-VMLXO5JS.js.map +0 -1
  73. package/dist/chunk-WXBSM2CE.js.map +0 -1
  74. package/dist/chunk-XEPD5VJQ.js.map +0 -1
  75. package/dist/core/native-concepts.d.ts +0 -78
  76. package/dist/core/native-concepts.js +0 -3
@@ -1,16 +1,30 @@
1
+ import { PresenceMarker, PipeIOContracts, PipeIOContract, PipeInputContract } from 'mthds/protocol';
2
+ export { IOMultiplicity, PipeIOContract, PipeIOContracts, PipeInputContract, PipeOutputContract } from 'mthds/protocol';
3
+
1
4
  /**
2
- * The typed `pipe_io_contracts` mirror and its gating predicates.
5
+ * The `pipe_io_contracts` types and the kernel's gating predicates over them.
6
+ *
7
+ * The types are the STANDARD'S, imported from `mthds/protocol` and re-exported
8
+ * under the names this package has always exported. `pipe_io_contracts` is an
9
+ * MTHDS artifact - the standard specifies it (the "Pipe I/O Contracts" page)
10
+ * and its TypeScript client declares it - so this module states no shape of its
11
+ * own any more. What it keeps is the half that is genuinely the kernel's: the
12
+ * predicates that turn a declared slot into a gating answer, and the lookup
13
+ * that tolerates both key conventions a real payload arrives with.
3
14
  *
4
- * Mirrors pipelex's `PipeIOContract` (pipelex/pipeline/pipe_io_contracts.py).
5
- * The SDK deliberately keeps `pipe_io_contracts` opaque, so the kernel is the
6
- * canonical TS home for this shape until the D-track specs it.
15
+ * `mthds` is a TYPES-ONLY peer dependency: every import here is `import type`,
16
+ * so nothing survives into `dist/` and no consumer ships the standard's CLI.
17
+ * `scripts/assert-bundle.mjs` holds that on the built graph and lint holds it
18
+ * on the source. See docs/dependency-budget.md.
7
19
  *
8
20
  * The map itself is keyed by namespaced pipe ref (`<domain>.<pipe_code>`),
9
21
  * NOT bare pipe code - use `getPipeIOContract` to look entries up by the bare
10
22
  * codes the UI tracks.
11
23
  */
24
+
12
25
  /**
13
- * The authored presence marker on an input slot, verbatim.
26
+ * The authored presence marker on an input slot, verbatim - the standard's
27
+ * `PresenceMarker` under the name this package exports.
14
28
  *
15
29
  * - `plain` - no marker: the caller must supply the input.
16
30
  * - `optional` (`?`) - the caller may omit it and the pipe handles the absence
@@ -18,56 +32,13 @@
18
32
  * - `force` (`!`) - a use-site assertion that the value IS present. It must be
19
33
  * supplied, exactly like `plain`; the distinction is the authored assertion,
20
34
  * which lint and graph surfaces read and a form does not.
21
- */
22
- type InputPresence = 'plain' | 'optional' | 'force';
23
- /**
24
- * How many items a slot carries.
25
35
  *
26
- * - `single` - one item. `Concept[1]` is single too: no list framing.
27
- * - `variable` (`Concept[]`) - a list of any length, the empty list included.
28
- * - `fixed` (`Concept[N]`, N > 1) - a list of exactly `item_count` items.
36
+ * Kept as an alias rather than renamed because a consumer imports it by this
37
+ * name; a host that would rather read the standard's spelling has `mthds`
38
+ * installed through this package's peer and can import `PresenceMarker`
39
+ * straight from `mthds/protocol`.
29
40
  */
30
- type IOMultiplicity = 'single' | 'variable' | 'fixed';
31
- interface PipeInputContract {
32
- concept_ref: string;
33
- /** The declared presence marker - see `InputPresence`. */
34
- presence: InputPresence;
35
- /** The declared multiplicity - see `IOMultiplicity`. */
36
- multiplicity: IOMultiplicity;
37
- /**
38
- * The exact item count, non-null exactly when `multiplicity` is `fixed`. The
39
- * slot is always on the wire, `null` off the fixed arm.
40
- */
41
- item_count: number | null;
42
- /**
43
- * The input's JSON Schema. A plural slot (`variable` or `fixed`) is an array
44
- * wrapper around the item schema, and a `fixed` one additionally carries
45
- * `minItems` / `maxItems` set to `item_count` - which is what makes the gate's
46
- * ajv pass enforce the declared count without the kernel restating it.
47
- */
48
- json_schema: Record<string, unknown>;
49
- }
50
- interface PipeOutputContract {
51
- concept_ref: string;
52
- multiplicity: IOMultiplicity;
53
- /** As on the input: non-null exactly on the `fixed` arm, always on the wire. */
54
- item_count: number | null;
55
- /**
56
- * `true` when the output is declared optional (`?`) - the pipe may resolve it
57
- * as a recorded absence instead of a value.
58
- *
59
- * Deliberately still a boolean while the INPUT side carries three-valued
60
- * `presence`: output presence is genuinely two-valued, because `!` is
61
- * rejected on an output. The asymmetry is the wire's, not ours.
62
- */
63
- optional: boolean;
64
- }
65
- interface PipeIOContract {
66
- inputs: Record<string, PipeInputContract>;
67
- output: PipeOutputContract;
68
- }
69
- /** The `pipe_io_contracts` map: namespaced `pipe_ref` → IO contract. */
70
- type PipeIOContracts = Record<string, PipeIOContract>;
41
+ type InputPresence = PresenceMarker;
71
42
  /** Namespaced pipe ref (`<domain>.<pipe_code>`) - the identity convention the
72
43
  * validate artifacts key on. */
73
44
  declare function buildPipeRef(domain: string, pipeCode: string): string;
@@ -107,8 +78,8 @@ declare function isOptionalInput(input: PipeInputContract): boolean;
107
78
  * maps and therefore what the user is shown; a predicate reading the other
108
79
  * field could disagree with the rendered control, which is the exact failure
109
80
  * mode `mustBeFilled` (readiness.ts) exists to prevent. The two agree by
110
- * construction upstream - pipelex wraps the schema in an array exactly when it
111
- * reports `variable` or `fixed`.
81
+ * construction upstream - the engine wraps the schema in an array exactly when
82
+ * it reports `variable` or `fixed`.
112
83
  */
113
84
  declare function isPluralInput(input: PipeInputContract): boolean;
114
85
  /**
@@ -140,4 +111,4 @@ declare function isFixedCountInput(input: PipeInputContract): boolean;
140
111
  */
141
112
  declare function inputMustBeFilled(input: PipeInputContract): boolean;
142
113
 
143
- export { type IOMultiplicity, type InputPresence, type PipeIOContract, type PipeIOContracts, type PipeInputContract, type PipeOutputContract, buildPipeRef, getPipeIOContract, inputMustBeFilled, isFixedCountInput, isOptionalInput, isPluralInput };
114
+ export { type InputPresence, buildPipeRef, getPipeIOContract, inputMustBeFilled, isFixedCountInput, isOptionalInput, isPluralInput };
@@ -1,4 +1,4 @@
1
- export { buildPipeRef, getPipeIOContract, inputMustBeFilled, isFixedCountInput, isOptionalInput, isPluralInput } from '../chunk-HARYEWNG.js';
1
+ export { buildPipeRef, getPipeIOContract, inputMustBeFilled, isFixedCountInput, isOptionalInput, isPluralInput } from '../chunk-XYQ7NXQZ.js';
2
2
  import '../chunk-V3OV2XQT.js';
3
3
  //# sourceMappingURL=contracts.js.map
4
4
  //# sourceMappingURL=contracts.js.map
@@ -1,20 +1,88 @@
1
- import { PipeInputContract } from './contracts.js';
1
+ import { InputFormField, PipeInputFormDescriptor, PipeInputContract, InputForm } from 'mthds/protocol';
2
2
  import { RunField } from './descriptor.js';
3
+ import './contracts.js';
3
4
 
4
5
  /**
5
- * The ONE derivation function: `PipeInputContract` map → `RunField[]`.
6
+ * The ONE derivation function: wire input-form descriptor → `RunField[]`.
6
7
  *
7
- * Everything heuristic stays module-private behind `buildRunFields`: the
8
- * native-concept taxonomy, `isDocumentObject`, the depth-based prose/label
9
- * rule, the `accept` strings, list splitting. Nothing here is exported except
10
- * the function itself - so the M1 milestone can swap the source of the
11
- * descriptor (server-derived) without touching consumers.
8
+ * `buildRunFields` maps the standard's per-pipe descriptor STRUCTURALLY onto
9
+ * the kernel's `RunField` shape. It decides nothing: what a field IS - its
10
+ * kind, its constraints, its refinement chain, whether Run gates on it - is
11
+ * stated by the wire, derived by the engine from the resolved library. The
12
+ * heuristics that used to live here (native-concept sets, the url-bearing
13
+ * object test, the depth-based prose/label rule) are deleted, not bypassed;
14
+ * docs/derivation-swap.md is the record of that swap and of every behaviour
15
+ * that moved with it.
16
+ *
17
+ * The contract is still consulted, for exactly two facts the wire deliberately
18
+ * does not carry:
19
+ *
20
+ * - **`contentKey`** - the single property a native scalar's value sits inside
21
+ * on the wire (`TextContent {text}`, `NumberContent {number}`). A renderer
22
+ * holds the bare scalar; the value bridge wraps by this name. It is read off
23
+ * the contract's `json_schema` because it is a fact about the PAYLOAD shape,
24
+ * which is the schema's job - the descriptor describes the form, never the
25
+ * payload.
26
+ * - **Nested list bounds** - the wire puts `item_count` only on a top-level
27
+ * fixed `[N]` slot, but the model behind a structured concept may state
28
+ * `minItems`/`maxItems` on an array property of its own, and ajv enforces
29
+ * them. Reading them off the schema is what keeps readiness from being more
30
+ * permissive than the gate.
31
+ *
32
+ * Both are structural reads (a property count, two keywords ajv itself
33
+ * enforces), not judgements - the mapper stays honest about owning no taxonomy.
12
34
  */
13
35
 
14
36
  /**
15
- * Convert the API's per-input contracts into the runner's field descriptors.
16
- * The map's insertion order is preserved (required-first is the caller's job).
37
+ * Look up a pipe's input-form descriptor by pipe code, tolerant of both key
38
+ * conventions - the exact mirror of `getPipeIOContract`, because the standard
39
+ * keys `input_form` by the same `pipe_ref` set as `pipe_io_contracts` and a
40
+ * host tracks the same bare codes either way.
41
+ */
42
+ declare function getPipeInputForm(inputForm: InputForm | null | undefined, domain: string | null | undefined, pipeCode: string | null | undefined): PipeInputFormDescriptor | undefined;
43
+ /**
44
+ * Map a pipe's wire input-form descriptor onto the kernel's field descriptors,
45
+ * with the pipe's input contracts beside it for the two schema-derived facts.
46
+ *
47
+ * The order is the DESCRIPTOR's - authored input order, the fact the contract's
48
+ * `inputs` map deliberately does not carry. `required`, `presence` and `gating`
49
+ * are taken from the wire verbatim: the standard's top-level type ties
50
+ * `required` to the presence marker, and `gating` is the producer-derived
51
+ * answer `mustBeFilled` reads - the kernel re-derives none of them.
52
+ */
53
+ /**
54
+ * The same mapping, for a single node that belongs to no slot — a pipe's OUTPUT.
55
+ *
56
+ * `buildRunFields` maps a descriptor's fields and then stamps each with the slot
57
+ * facts (`presence`, `gating`) the wire states per input. An output has no slot,
58
+ * so this stamps nothing: the node arrives without them and leaves without them,
59
+ * which is exactly what the standard's optional members are for.
60
+ *
61
+ * Everything else is shared, deliberately. An output is a concept ref like an
62
+ * input is, so its kinds, its nesting, its list bounds and its `contentKey` are
63
+ * the same questions with the same answers — and a second mapper would be a
64
+ * second place for them to drift.
65
+ *
66
+ * ## `schema` is REQUIRED, and that is the whole point
67
+ *
68
+ * It was optional once, and the renderer paid for it: with no schema it could
69
+ * not know that `native.Text`'s payload sits under `text`, so it worked the
70
+ * unwrapping out by COUNTING the value's properties, and worked a plural payload
71
+ * out by looking for an `items` key. Both are shape sniffing — the exact pattern
72
+ * [../../docs/derivation-swap.md] records deleting from the input side, where
73
+ * `contentKey` is read off a schema and handed to a control as a property NAME.
74
+ *
75
+ * So the parameter is required, the two heuristics are gone, and what the
76
+ * argument must be is stated precisely: **the schema of the PAYLOAD**, which for
77
+ * every kind but `object` is the content model that wraps it —
78
+ * `TextContent {text}` for a `native.Text` output, `ListContent {items}` for a
79
+ * plural one. That is a change the standard has to make on the output contract
80
+ * (see `./output-form`); until it does, a producer supplies it beside the
81
+ * descriptor.
17
82
  */
18
- declare function buildRunFields(inputs: Record<string, PipeInputContract>): RunField[];
83
+ declare function buildResultField(descriptor: {
84
+ field: InputFormField;
85
+ }, schema: Record<string, unknown>): RunField;
86
+ declare function buildRunFields(descriptor: PipeInputFormDescriptor, inputs: Record<string, PipeInputContract>): RunField[];
19
87
 
20
- export { buildRunFields };
88
+ export { buildResultField, buildRunFields, getPipeInputForm };
@@ -1,7 +1,7 @@
1
- export { buildRunFields } from '../chunk-VMLXO5JS.js';
2
- import '../chunk-O4O3QNVC.js';
3
- import '../chunk-HARYEWNG.js';
1
+ export { buildResultField, buildRunFields, getPipeInputForm } from '../chunk-J4L32LD6.js';
2
+ import '../chunk-2JWRG53S.js';
3
+ import '../chunk-OD3VYXUY.js';
4
+ import '../chunk-XYQ7NXQZ.js';
4
5
  import '../chunk-V3OV2XQT.js';
5
- import '../chunk-NMT7BRLO.js';
6
6
  //# sourceMappingURL=derive.js.map
7
7
  //# sourceMappingURL=derive.js.map
@@ -1,16 +1,20 @@
1
+ import { InputPresence } from './contracts.js';
2
+ import 'mthds/protocol';
3
+
1
4
  /**
2
5
  * The `RunField` descriptor - the consumer-facing currency of the form kernel.
3
6
  *
4
- * A method's inputs arrive from the API as a map of variable name →
5
- * `PipeInputContract` ({ concept_ref, json_schema }). That JSON Schema is rich
6
- * (Pydantic-generated) and not pleasant to render directly. `buildRunFields`
7
- * (in `derive.ts`) normalizes it once into a flat, recursive `RunField[]`
8
- * descriptor that the presentational field components consume - so the
9
- * components never touch raw JSON Schema, and stories can describe any input
10
- * shape declaratively.
7
+ * A method's inputs arrive from the API as two sibling artifacts: the wire
8
+ * input-form descriptor (`input_form`, the ordered presentation view the MTHDS
9
+ * standard specifies) and the `pipe_io_contracts` entry whose `json_schema`
10
+ * stays the validation contract. `buildRunFields` (in `derive.ts`) maps the
11
+ * wire descriptor structurally onto this `RunField[]` shape - so the
12
+ * presentational field components never touch either wire artifact directly,
13
+ * and stories can describe any input shape declaratively.
11
14
  *
12
15
  * Pure module: no React, no API calls. Trivially unit-testable.
13
16
  */
17
+
14
18
  type RunFieldKind = 'text' | 'prose' | 'date' | 'number' | 'boolean' | 'enum' | 'document' | 'image' | 'object' | 'list' | 'unknown';
15
19
  interface RunFieldCommon {
16
20
  /** The variable identifier as written in the method (rendered in mono). */
@@ -19,10 +23,38 @@ interface RunFieldCommon {
19
23
  title?: string;
20
24
  /** The concept this input carries, e.g. `native.Document`, `demo.Invoice`. */
21
25
  conceptRef?: string;
26
+ /**
27
+ * The concept's refinement chain, immediate parent first, walked to its end
28
+ * (`['legal.BaseClause', 'native.Text']`). Straight off the wire descriptor;
29
+ * absent when the concept refines nothing. "Does this refine `native.X`?" is
30
+ * a membership test on this list, never shape sniffing.
31
+ */
32
+ refines?: string[];
22
33
  /** One-line helper text shown under the label. */
23
34
  description?: string;
24
35
  /** Required inputs always show; optional ones can collapse. */
25
36
  required: boolean;
37
+ /**
38
+ * The authored presence marker of the pipe's input slot, verbatim - set on
39
+ * TOP-LEVEL fields only, like `gating`. `required` is its two-valued
40
+ * projection (`presence !== 'optional'`); the marker itself is carried so a
41
+ * renderer can distinguish the authored `!` assertion from a plain slot.
42
+ */
43
+ presence?: InputPresence;
44
+ /**
45
+ * The value applied when the caller omits the field - present only when a
46
+ * default was AUTHORED, never the `null` a schema projection attaches to an
47
+ * optional field. A defaulted field always arrives `required: false`.
48
+ */
49
+ defaultValue?: unknown;
50
+ /** Example values for the field, when the wire carries any. */
51
+ examples?: unknown[];
52
+ /**
53
+ * The node's effective intent hints - the flat `string → string` merge the
54
+ * language defines, carried verbatim. Non-normative: a renderer that ignores
55
+ * them stays correct, and nothing in the kernel's gating reads them.
56
+ */
57
+ hints?: Record<string, string>;
26
58
  /**
27
59
  * Whether Run waits for this input - set on TOP-LEVEL fields only, straight
28
60
  * from `inputMustBeFilled` (see `mustBeFilled` in `readiness.ts` for why this
@@ -45,21 +77,34 @@ interface RunFieldCommon {
45
77
  */
46
78
  contentKey?: string;
47
79
  }
48
- interface TextRunField extends RunFieldCommon {
80
+ /**
81
+ * The constraint slots the two text kinds share, mapped from the wire's
82
+ * `min_length` / `max_length` / `pattern` / `format`. `format` is the open
83
+ * string set carrying schema formats the `date` kind does not absorb
84
+ * (`'time'`, `'uri'`, …); a renderer may hint on it and ignore it safely.
85
+ */
86
+ interface TextConstraints {
87
+ minLength?: number;
88
+ maxLength?: number;
89
+ pattern?: string;
90
+ format?: string;
91
+ }
92
+ interface TextRunField extends RunFieldCommon, TextConstraints {
49
93
  kind: 'text';
50
94
  placeholder?: string;
51
95
  }
52
- interface ProseRunField extends RunFieldCommon {
96
+ interface ProseRunField extends RunFieldCommon, TextConstraints {
53
97
  kind: 'prose';
54
98
  placeholder?: string;
55
99
  }
56
100
  interface DateRunField extends RunFieldCommon {
57
101
  kind: 'date';
58
102
  /**
59
- * True when the backing schema is `format: date-time`: the stored value is a
60
- * full RFC 3339 timestamp (`2026-07-06T00:00:00Z`) so it passes the API's
103
+ * The wire's `datetime` flag - true when the value carries a time of day
104
+ * (the backing schema is `format: date-time`): the stored value is a full
105
+ * RFC 3339 timestamp (`2026-07-06T00:00:00Z`) so it passes the API's
61
106
  * `date-time` validation, even though the control only asks for a day. False
62
- * for a bare `format: date`, where the value stays `YYYY-MM-DD`.
107
+ * for a bare calendar date, where the value stays `YYYY-MM-DD`.
63
108
  */
64
109
  datetime: boolean;
65
110
  }
@@ -90,24 +135,23 @@ interface ListRunField extends RunFieldCommon {
90
135
  /** The element descriptor (its `name` is unused; the index labels items). */
91
136
  item: RunField;
92
137
  /**
93
- * The FEWEST items the slot accepts, when the schema states a lower bound.
94
- * Absent for a variable `Concept[]` list, which demands none.
138
+ * The FEWEST items the slot accepts. Absent for a variable `Concept[]` list,
139
+ * which demands none.
95
140
  *
96
- * Read off the array schema's `minItems` rather than off the contract's
97
- * `item_count`, which states the same number: this exists so `fieldFilled` can
98
- * answer the question **ajv** answers, and `minItems` is the keyword ajv
99
- * reads. pipelex emits `minItems`/`maxItems` = N for a `[N]` slot and neither
100
- * for `[]`, so on a top-level slot the two sources agree by construction.
141
+ * On a top-level slot this is the wire descriptor's `item_count` (present
142
+ * exactly on a fixed `[N]` slot); an engine emits `minItems`/`maxItems` = N
143
+ * on the same slot's schema, so the number `fieldFilled` gates on and the
144
+ * keyword ajv reads agree by construction.
101
145
  *
102
- * A schema may still state a lower bound alone - `mapSchema` recurses, so a
103
- * nested array inside a structured concept reaches here with whatever its
104
- * model declared and no MTHDS multiplicity behind it. Gating on that bound is
105
- * the same rule, and it is the direction that cannot leave readiness more
106
- * permissive than the gate.
146
+ * The wire never puts `item_count` on a NESTED list, but the model behind a
147
+ * structured concept may state `minItems` on an array property of its own -
148
+ * so on nested nodes this is read off the schema, which is the direction
149
+ * that cannot leave readiness more permissive than the gate.
107
150
  */
108
151
  itemCount?: number;
109
152
  /**
110
- * The MOST items the slot accepts, off the schema's `maxItems`.
153
+ * The MOST items the slot accepts, off the schema's `maxItems` (which a
154
+ * fixed `[N]` slot also states as N).
111
155
  *
112
156
  * A separate field because it is a separate fact, and conflating them is a
113
157
  * bug that hides: `itemCount` was read as a minimum by readiness and as a
@@ -125,4 +169,4 @@ type RunField = TextRunField | ProseRunField | DateRunField | NumberRunField | B
125
169
  type ConceptCategory = 'text' | 'date' | 'document' | 'image' | 'number' | 'boolean' | 'choice' | 'structured' | 'list';
126
170
  declare function conceptCategory(field: RunField): ConceptCategory;
127
171
 
128
- export { type BooleanRunField, type ConceptCategory, type DateRunField, type EnumRunField, type FileRunField, type ListRunField, type NumberRunField, type ObjectRunField, type ProseRunField, type RunField, type RunFieldCommon, type RunFieldKind, type TextRunField, type UnknownRunField, conceptCategory };
172
+ export { type BooleanRunField, type ConceptCategory, type DateRunField, type EnumRunField, type FileRunField, type ListRunField, type NumberRunField, type ObjectRunField, type ProseRunField, type RunField, type RunFieldCommon, type RunFieldKind, type TextConstraints, type TextRunField, type UnknownRunField, conceptCategory };
@@ -1,3 +1,3 @@
1
- export { conceptCategory } from '../chunk-6XD6UZSU.js';
1
+ export { conceptCategory } from '../chunk-25I6JDIK.js';
2
2
  //# sourceMappingURL=descriptor.js.map
3
3
  //# sourceMappingURL=descriptor.js.map
@@ -0,0 +1,102 @@
1
+ /**
2
+ * What a `document` or an `image` slot actually accepts.
3
+ *
4
+ * **This is a client-side mirror of a runtime fact, and the fact was measured
5
+ * rather than read off a list.** The wire says a slot's kind is `document` or
6
+ * `image` and stops there — which bytes a runtime can decode is a property of
7
+ * that runtime, not of the method — so the list has to live on this side, and
8
+ * the only honest place is one module that says where it came from.
9
+ *
10
+ * There is no single enum to copy. In `pipelex`, what a slot accepts is derived
11
+ * per model:
12
+ *
13
+ * ModelSpec.supported_document_types = {"pdf","docx","pptx"} & set(inputs)
14
+ * ModelSpec.is_vision_supported = "images" in inputs
15
+ *
16
+ * so the effective set is that vocabulary intersected with the **model deck's**
17
+ * declared `inputs`. No model in the shipped deck declares `docx` or `pptx`;
18
+ * every LLM entry is `["text", "images", "pdf"]`, and the default extract model
19
+ * (`azure-document-intelligence`) is `["image", "pdf"]`.
20
+ *
21
+ * Confirmed by running each format end to end:
22
+ *
23
+ * | Format | PipeExtract | PipeLLM |
24
+ * | --- | --- | --- |
25
+ * | PDF | yes | yes |
26
+ * | PNG | yes | n/a |
27
+ * | JPEG | yes | n/a |
28
+ * | WEBP | no | no |
29
+ * | DOCX | no | no — `does not support docx documents` |
30
+ * | PPTX | no | no — detected as `zip`, so it never even reaches the check |
31
+ *
32
+ * The gateway states its own list in the failure: *"Supported formats:
33
+ * application/pdf, image/jpeg, image/png as base64 data URLs."*
34
+ *
35
+ * Images were measured the same way: PNG, JPEG and WEBP pass; BMP and TIFF fail
36
+ * on the provider's image enum; GIF fails too, though it is *in* that enum — it
37
+ * arrives at the provider as a document block rather than an image one, which
38
+ * looks like a routing bug upstream rather than an unsupported format.
39
+ *
40
+ * **A document slot's PNG and JPEG only work in an extract pipe.** The
41
+ * descriptor never says which operator consumes the slot, so this table cannot
42
+ * distinguish them; it matches the extract model's declared inputs, because
43
+ * extraction is the operator that actually reads a document's bytes.
44
+ *
45
+ * What was here before was built on `DocumentFormat` (PDF/DOCX/PPTX), an enum
46
+ * that is referenced nowhere in the runtime outside commented-out code and is
47
+ * being deleted. A dead enum is the worst kind of source: it reads exactly like
48
+ * a live one.
49
+ *
50
+ * A stale entry here is worse than no list at all, because it refuses a file the
51
+ * runtime would have taken. If the deck grows a format, this table moves with it.
52
+ *
53
+ * Pure data. No React, no ajv, nothing imported.
54
+ */
55
+ /** One accepted format: its MIME type and the extensions that carry it. */
56
+ interface FileFormat {
57
+ mimeType: string;
58
+ /** Leading dot, lowercase — the shape a file input's `accept` wants. */
59
+ extensions: string[];
60
+ /** How the format is named to a user, uppercase. */
61
+ label: string;
62
+ }
63
+ /**
64
+ * What a `document` slot takes: PDF, plus the two image formats the extract
65
+ * model reads as a single-page document.
66
+ */
67
+ declare const DOCUMENT_FORMATS: readonly FileFormat[];
68
+ /**
69
+ * What an `image` slot takes: PNG, JPEG, WEBP — all three measured through the
70
+ * vision path.
71
+ *
72
+ * `.jpg` and `.jpeg` both ride `image/jpeg`. `JPG` is the label because that is
73
+ * the spelling the runtime uses, but a file named `.jpeg` is the same bytes and
74
+ * must not be refused over its spelling.
75
+ */
76
+ declare const IMAGE_FORMATS: readonly FileFormat[];
77
+ 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
+ /**
81
+ * Whether a picked file is one this kind accepts.
82
+ *
83
+ * Checks the MIME type first and falls back to the extension, because a
84
+ * browser's `File.type` is empty often enough to matter: an OS with no handler
85
+ * registered for `.docx` reports `''`, and refusing that file would be refusing
86
+ * a valid one over a fact about the user's machine. A wrong-but-present MIME
87
+ * type is still a rejection — that is the case this exists for.
88
+ */
89
+ declare function isAcceptedFile(kind: 'document' | 'image', file: {
90
+ name: string;
91
+ type: string;
92
+ }): boolean;
93
+ /**
94
+ * The accept map a file input wants: MIME type to extensions.
95
+ *
96
+ * Shaped for `react-dropzone`'s `accept`, which is the same shape the DOM's
97
+ * `accept` attribute is built from. Listing extensions BESIDE the MIME type is
98
+ * what makes the empty-`File.type` case above work in the OS picker too.
99
+ */
100
+ declare function acceptMapForKind(kind: 'document' | 'image'): Record<string, string[]>;
101
+
102
+ export { DOCUMENT_FORMATS, type FileFormat, IMAGE_FORMATS, acceptLabelForKind, acceptMapForKind, formatsForKind, isAcceptedFile };
@@ -0,0 +1,3 @@
1
+ export { DOCUMENT_FORMATS, IMAGE_FORMATS, acceptLabelForKind, acceptMapForKind, formatsForKind, isAcceptedFile } from '../chunk-2JWRG53S.js';
2
+ //# sourceMappingURL=file-formats.js.map
3
+ //# sourceMappingURL=file-formats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"file-formats.js"}
@@ -1,5 +1,5 @@
1
1
  import { RunInputError } from './gate-validator.js';
2
- import { PipeInputContract, PipeIOContract } from './contracts.js';
2
+ import { PipeInputContract, PipeIOContract } from 'mthds/protocol';
3
3
 
4
4
  type Dict = Record<string, unknown>;
5
5
  /**
package/dist/core/gate.js CHANGED
@@ -1,13 +1,12 @@
1
- export { apiInputsFromSchemaData, buildRunInputsSchema, gateRunInputs, prepareRunInputs, validateRunInputs } from '../chunk-XEPD5VJQ.js';
2
- import '../chunk-KFZ5MZOM.js';
3
- import '../chunk-7BMOPXDY.js';
1
+ export { apiInputsFromSchemaData, buildRunInputsSchema, gateRunInputs, prepareRunInputs, validateRunInputs } from '../chunk-R7B7ID25.js';
2
+ import '../chunk-GCXV76WU.js';
3
+ import '../chunk-LBFZXYCY.js';
4
4
  import '../chunk-PM55AHRO.js';
5
- import '../chunk-VMLXO5JS.js';
6
- import '../chunk-O4O3QNVC.js';
7
- import '../chunk-HARYEWNG.js';
8
- import '../chunk-V3OV2XQT.js';
9
5
  import '../chunk-VTPUDBSJ.js';
10
6
  import '../chunk-GKV77RAS.js';
11
- import '../chunk-NMT7BRLO.js';
7
+ import '../chunk-YEVVR6FE.js';
8
+ import '../chunk-OD3VYXUY.js';
9
+ import '../chunk-XYQ7NXQZ.js';
10
+ import '../chunk-V3OV2XQT.js';
12
11
  //# sourceMappingURL=gate.js.map
13
12
  //# sourceMappingURL=gate.js.map
@@ -0,0 +1,38 @@
1
+ import { PipeInputContract } from 'mthds/protocol';
2
+ import { RunField } from './descriptor.js';
3
+ import './contracts.js';
4
+
5
+ /**
6
+ * The gate's own field tree - structural, schema-derived, and private.
7
+ *
8
+ * `gateRunInputs` re-applies the Run button's emptiness rule with
9
+ * `mustBeFilled`/`fieldFilled`, which read a `RunField` tree. The RENDER tree
10
+ * is built from the wire input-form descriptor - but the gate must not require
11
+ * that artifact: the descriptor is a presentation view, and the workspace
12
+ * doctrine is that a machine consumer never needs it to validate a payload -
13
+ * `json_schema` keeps that job. A server holds contracts; it may never have
14
+ * asked for the view.
15
+ *
16
+ * So the gate walks the contract's `json_schema` into the MINIMAL tree the
17
+ * emptiness predicates read: `object` nodes with their required children,
18
+ * `list` nodes with their declared bounds, and opaque leaves. This is not a
19
+ * revival of the deleted heuristics - it reads exactly the keywords ajv itself
20
+ * enforces (`type`, `properties`, `required`, `items`, `minItems`, `maxItems`)
21
+ * and decides nothing about what a field IS. No kind here ever reaches a
22
+ * renderer: the tree exists for one call inside `gateRunInputs` and is not
23
+ * exported from the package.
24
+ *
25
+ * Agreement with the browser's readiness (which runs over the render tree) is
26
+ * held by construction - both trees take required children and list bounds
27
+ * from the same model the engine derived both artifacts from - and asserted in
28
+ * `gate-agreement.test.ts`, which runs both sides over one table.
29
+ */
30
+
31
+ /**
32
+ * The tree `gateRunInputs`' emptiness re-check runs over, one node per input,
33
+ * with `gating` stamped from the contract - the same `inputMustBeFilled` the
34
+ * Run button's `required` list is built from.
35
+ */
36
+ declare function gatingFieldsFromInputs(inputs: Record<string, PipeInputContract>): RunField[];
37
+
38
+ export { gatingFieldsFromInputs };
@@ -0,0 +1,6 @@
1
+ export { gatingFieldsFromInputs } from '../chunk-YEVVR6FE.js';
2
+ import '../chunk-OD3VYXUY.js';
3
+ import '../chunk-XYQ7NXQZ.js';
4
+ import '../chunk-V3OV2XQT.js';
5
+ //# sourceMappingURL=gating-fields.js.map
6
+ //# sourceMappingURL=gating-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"gating-fields.js"}
@@ -1,7 +1,12 @@
1
- export { BooleanRunField, ConceptCategory, DateRunField, EnumRunField, FileRunField, ListRunField, NumberRunField, ObjectRunField, ProseRunField, RunField, RunFieldCommon, RunFieldKind, TextRunField, UnknownRunField, conceptCategory } from './descriptor.js';
2
- export { buildRunFields } from './derive.js';
1
+ export { BooleanRunField, ConceptCategory, DateRunField, EnumRunField, FileRunField, ListRunField, NumberRunField, ObjectRunField, ProseRunField, RunField, RunFieldCommon, RunFieldKind, TextConstraints, TextRunField, UnknownRunField, conceptCategory } from './descriptor.js';
2
+ export { IOMultiplicity, InputForm, InputFormTopLevelField, OutputForm, PipeIOContract, PipeIOContracts, PipeInputContract, PipeInputFormDescriptor, PipeOutputContract, PipeOutputFormDescriptor } from 'mthds/protocol';
3
+ export { buildResultField, buildRunFields, getPipeInputForm } from './derive.js';
4
+ export { getPipeOutputForm } from './output-form.js';
5
+ export { StuffFile, collectStuffFiles } from './stuff-files.js';
6
+ export { DOCUMENT_FORMATS, FileFormat, IMAGE_FORMATS, acceptLabelForKind, acceptMapForKind, formatsForKind, isAcceptedFile } from './file-formats.js';
7
+ export { CompositeMember, 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, readDateContent, readDocumentContent, readHtmlContent, readImageContent } from './native-content.js';
3
8
  export { Readiness, computeReadiness, fieldFilled, isFilled, mustBeFilled } from './readiness.js';
4
- export { IOMultiplicity, InputPresence, PipeIOContract, PipeIOContracts, PipeInputContract, PipeOutputContract, buildPipeRef, getPipeIOContract, inputMustBeFilled, isFixedCountInput, isOptionalInput, isPluralInput } from './contracts.js';
9
+ export { InputPresence, buildPipeRef, getPipeIOContract, inputMustBeFilled, isFixedCountInput, isOptionalInput, isPluralInput } from './contracts.js';
5
10
  export { RunInputsGateResult, RunInputsVerdict, apiInputsFromSchemaData, buildRunInputsSchema, gateRunInputs, prepareRunInputs, validateRunInputs } from './gate.js';
6
11
  export { RunInputError, validateRunInputsSchema } from './gate-validator.js';
7
12
  export { OutputEntry, apiInputsFromRunValues, fieldsForContract, inputDataFromWorkingMemory, outputsFromPipeOutput, rjsfDataFromRunValues, runValuesFromStore, setValueAtPath, storeInputDataFromRunValues } from './values.js';