@pipelex/mthds-form 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +7 -2
  2. package/dist/chunk-6XD6UZSU.js +28 -0
  3. package/dist/chunk-6XD6UZSU.js.map +1 -0
  4. package/dist/chunk-7BMOPXDY.js +205 -0
  5. package/dist/chunk-7BMOPXDY.js.map +1 -0
  6. package/dist/chunk-GKV77RAS.js +46 -0
  7. package/dist/chunk-GKV77RAS.js.map +1 -0
  8. package/dist/chunk-HARYEWNG.js +31 -0
  9. package/dist/chunk-HARYEWNG.js.map +1 -0
  10. package/dist/chunk-KFZ5MZOM.js +44 -0
  11. package/dist/chunk-KFZ5MZOM.js.map +1 -0
  12. package/dist/chunk-NMT7BRLO.js +40 -0
  13. package/dist/chunk-NMT7BRLO.js.map +1 -0
  14. package/dist/chunk-O4O3QNVC.js +146 -0
  15. package/dist/chunk-O4O3QNVC.js.map +1 -0
  16. package/dist/chunk-PM55AHRO.js +52 -0
  17. package/dist/chunk-PM55AHRO.js.map +1 -0
  18. package/dist/chunk-RPA7DNSK.js +41 -0
  19. package/dist/chunk-RPA7DNSK.js.map +1 -0
  20. package/dist/chunk-V3OV2XQT.js +12 -0
  21. package/dist/chunk-V3OV2XQT.js.map +1 -0
  22. package/dist/chunk-VMLXO5JS.js +132 -0
  23. package/dist/chunk-VMLXO5JS.js.map +1 -0
  24. package/dist/chunk-VTPUDBSJ.js +61 -0
  25. package/dist/chunk-VTPUDBSJ.js.map +1 -0
  26. package/dist/chunk-WXBSM2CE.js +201 -0
  27. package/dist/chunk-WXBSM2CE.js.map +1 -0
  28. package/dist/chunk-XEPD5VJQ.js +99 -0
  29. package/dist/chunk-XEPD5VJQ.js.map +1 -0
  30. package/dist/core/contracts.d.ts +143 -0
  31. package/dist/core/contracts.js +4 -0
  32. package/dist/core/contracts.js.map +1 -0
  33. package/dist/core/date-format.d.ts +87 -0
  34. package/dist/core/date-format.js +3 -0
  35. package/dist/core/date-format.js.map +1 -0
  36. package/dist/core/derive.d.ts +20 -0
  37. package/dist/core/derive.js +7 -0
  38. package/dist/core/derive.js.map +1 -0
  39. package/dist/{descriptor-X6MwFIWu.d.ts → core/descriptor.d.ts} +42 -1
  40. package/dist/core/descriptor.js +3 -0
  41. package/dist/core/descriptor.js.map +1 -0
  42. package/dist/core/gate-validator.d.ts +27 -0
  43. package/dist/core/gate-validator.js +4 -0
  44. package/dist/core/gate-validator.js.map +1 -0
  45. package/dist/core/gate.d.ts +144 -0
  46. package/dist/core/gate.js +13 -0
  47. package/dist/core/gate.js.map +1 -0
  48. package/dist/core/index.d.ts +12 -615
  49. package/dist/core/index.js +14 -1
  50. package/dist/core/native-concepts.d.ts +78 -0
  51. package/dist/core/native-concepts.js +3 -0
  52. package/dist/core/native-concepts.js.map +1 -0
  53. package/dist/core/normalize-schema.d.ts +30 -0
  54. package/dist/core/normalize-schema.js +4 -0
  55. package/dist/core/normalize-schema.js.map +1 -0
  56. package/dist/core/own-property.d.ts +46 -0
  57. package/dist/core/own-property.js +3 -0
  58. package/dist/core/own-property.js.map +1 -0
  59. package/dist/core/readiness.d.ts +89 -0
  60. package/dist/core/readiness.js +4 -0
  61. package/dist/core/readiness.js.map +1 -0
  62. package/dist/core/schema-utils.d.ts +74 -0
  63. package/dist/core/schema-utils.js +3 -0
  64. package/dist/core/schema-utils.js.map +1 -0
  65. package/dist/core/validation-message.d.ts +39 -0
  66. package/dist/core/validation-message.js +4 -0
  67. package/dist/core/validation-message.js.map +1 -0
  68. package/dist/core/values.d.ts +91 -0
  69. package/dist/core/values.js +11 -0
  70. package/dist/core/values.js.map +1 -0
  71. package/dist/core/wire-format.d.ts +95 -0
  72. package/dist/core/wire-format.js +7 -0
  73. package/dist/core/wire-format.js.map +1 -0
  74. package/dist/react/index.d.ts +22 -1
  75. package/dist/react/index.js +128 -48
  76. package/dist/react/index.js.map +1 -1
  77. package/dist/styles.css +1 -1
  78. package/package.json +5 -1
  79. package/dist/chunk-YWMUM7BC.js +0 -966
  80. package/dist/chunk-YWMUM7BC.js.map +0 -1
@@ -0,0 +1,3 @@
1
+ export { asCalendarDate, dayWithinDateTime, isAcceptableDate, isAcceptableDateTime, toDateInputValue, toStoredDateValue } from '../chunk-GKV77RAS.js';
2
+ //# sourceMappingURL=date-format.js.map
3
+ //# sourceMappingURL=date-format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"date-format.js"}
@@ -0,0 +1,20 @@
1
+ import { PipeInputContract } from './contracts.js';
2
+ import { RunField } from './descriptor.js';
3
+
4
+ /**
5
+ * The ONE derivation function: `PipeInputContract` map → `RunField[]`.
6
+ *
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.
12
+ */
13
+
14
+ /**
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).
17
+ */
18
+ declare function buildRunFields(inputs: Record<string, PipeInputContract>): RunField[];
19
+
20
+ export { buildRunFields };
@@ -0,0 +1,7 @@
1
+ export { buildRunFields } from '../chunk-VMLXO5JS.js';
2
+ import '../chunk-O4O3QNVC.js';
3
+ import '../chunk-HARYEWNG.js';
4
+ import '../chunk-V3OV2XQT.js';
5
+ import '../chunk-NMT7BRLO.js';
6
+ //# sourceMappingURL=derive.js.map
7
+ //# sourceMappingURL=derive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"derive.js"}
@@ -30,6 +30,20 @@ interface RunFieldCommon {
30
30
  * they are gated through their parent's `fieldFilled`.
31
31
  */
32
32
  gating?: boolean;
33
+ /**
34
+ * The single property this field's value sits inside on the wire, when its
35
+ * concept declares a scalar content model: `native.Text` is `TextContent
36
+ * {text}`, `native.Number` is `NumberContent {number}`, `native.YesNo` is
37
+ * `YesNoContent {yes_no}`. The control still holds the plain scalar; the
38
+ * value bridge wraps into this property on the way out and unwraps on the way
39
+ * back in.
40
+ *
41
+ * A property NAME, never a schema - the descriptor stays the only currency
42
+ * and `buildRunFields` stays the only reader of JSON Schema. Absent whenever
43
+ * the value is already the whole content (a structured concept, a file, a
44
+ * child property of a structure): wrapping those would double-nest them.
45
+ */
46
+ contentKey?: string;
33
47
  }
34
48
  interface TextRunField extends RunFieldCommon {
35
49
  kind: 'text';
@@ -75,6 +89,33 @@ interface ListRunField extends RunFieldCommon {
75
89
  kind: 'list';
76
90
  /** The element descriptor (its `name` is unused; the index labels items). */
77
91
  item: RunField;
92
+ /**
93
+ * The FEWEST items the slot accepts, when the schema states a lower bound.
94
+ * Absent for a variable `Concept[]` list, which demands none.
95
+ *
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.
101
+ *
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.
107
+ */
108
+ itemCount?: number;
109
+ /**
110
+ * The MOST items the slot accepts, off the schema's `maxItems`.
111
+ *
112
+ * A separate field because it is a separate fact, and conflating them is a
113
+ * bug that hides: `itemCount` was read as a minimum by readiness and as a
114
+ * maximum by the control that stops offering `Add`, which agree only while
115
+ * a contract states both bounds equal. A list told "at least two" was then
116
+ * presented as a list of exactly two.
117
+ */
118
+ maxItemCount?: number;
78
119
  }
79
120
  interface UnknownRunField extends RunFieldCommon {
80
121
  kind: 'unknown';
@@ -84,4 +125,4 @@ type RunField = TextRunField | ProseRunField | DateRunField | NumberRunField | B
84
125
  type ConceptCategory = 'text' | 'date' | 'document' | 'image' | 'number' | 'boolean' | 'choice' | 'structured' | 'list';
85
126
  declare function conceptCategory(field: RunField): ConceptCategory;
86
127
 
87
- export { type BooleanRunField as B, type ConceptCategory as C, type DateRunField as D, type EnumRunField as E, type FileRunField as F, type ListRunField as L, type NumberRunField as N, type ObjectRunField as O, type ProseRunField as P, type RunField as R, type TextRunField as T, type UnknownRunField as U, type RunFieldCommon as a, type RunFieldKind as b, conceptCategory as c };
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 };
@@ -0,0 +1,3 @@
1
+ export { conceptCategory } from '../chunk-6XD6UZSU.js';
2
+ //# sourceMappingURL=descriptor.js.map
3
+ //# sourceMappingURL=descriptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"descriptor.js"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * One validation error, in the shape hosts read (`property`, `message`,
3
+ * `name`, `stack`, `params.format`). Structurally a superset-compatible twin of
4
+ * RJSF's `RJSFValidationError`, so a host surface still holding RJSF form errors
5
+ * (an RJSF-based inputs panel) can hand them to the same message renderer.
6
+ */
7
+ interface RunInputError {
8
+ /** The ajv keyword that failed (`required`, `format`, `type`, …). */
9
+ name?: string;
10
+ /** Dotted path into the form data (`.quote_date.date`); for a `required`
11
+ * error the missing property name is appended (top-level: no leading dot). */
12
+ property?: string;
13
+ message?: string;
14
+ params?: Record<string, unknown>;
15
+ /** The human line: `property message`, or `'title' message` when the parent
16
+ * schema titles the field. */
17
+ stack: string;
18
+ schemaPath?: string;
19
+ }
20
+ /**
21
+ * Validate `data` against `schema`, returning mapped errors (empty = valid).
22
+ * MUTATES `data` where ajv coerces (`"20"` → `20`) - deliberate and relied on:
23
+ * the string the user typed is stored as a number going forward.
24
+ */
25
+ declare function validateRunInputsSchema(data: unknown, schema: object): RunInputError[];
26
+
27
+ export { type RunInputError, validateRunInputsSchema };
@@ -0,0 +1,4 @@
1
+ export { validateRunInputsSchema } from '../chunk-VTPUDBSJ.js';
2
+ import '../chunk-GKV77RAS.js';
3
+ //# sourceMappingURL=gate-validator.js.map
4
+ //# sourceMappingURL=gate-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"gate-validator.js"}
@@ -0,0 +1,144 @@
1
+ import { RunInputError } from './gate-validator.js';
2
+ import { PipeInputContract, PipeIOContract } from './contracts.js';
3
+
4
+ type Dict = Record<string, unknown>;
5
+ /**
6
+ * Combine the per-input schemas into one object schema.
7
+ *
8
+ * Each input variable becomes a property, titled with the variable name and
9
+ * described with the concept code. Only the inputs the method actually demands
10
+ * land in `required` - an optional (`?`) or variable-plural (`[]`) input must
11
+ * not block the form (see `inputMustBeFilled`).
12
+ *
13
+ * The per-input schema travels verbatim, which is how a fixed-count (`[N]`)
14
+ * list's declared count reaches ajv: pipelex states it as `minItems`/`maxItems`
15
+ * on the array wrapper, so the count is enforced here without the kernel
16
+ * restating it.
17
+ */
18
+ declare function buildRunInputsSchema(inputs: Record<string, PipeInputContract>): Dict;
19
+ /**
20
+ * Last-gate repair, in two passes against the exact schema ajv validates.
21
+ *
22
+ * 1. **HEAL** - persisted `inputData` may still carry the legacy double-wrapped
23
+ * `{ text: { text } }` shape (or a form's state may lag a store fix).
24
+ * 2. **PRUNE** - RJSF fills every unset string with `""` on mount, which an
25
+ * optional CONSTRAINED field rejects (`DateContent.time` is `format: "time"`)
26
+ * - blocking a run on a field the user never opened. An absent optional field
27
+ * is what pipelex means by `None` anyway, so dropping it is the semantically
28
+ * correct repair, not a validation dodge.
29
+ */
30
+ declare function prepareRunInputs(data: Dict, schema: Dict): Dict;
31
+ interface RunInputsVerdict {
32
+ isValid: boolean;
33
+ /** Variable names the scan could pin a missing required field on. */
34
+ missingInputs: string[];
35
+ /** Raw ajv errors, for when the scan cannot name anything. */
36
+ errors: RunInputError[];
37
+ }
38
+ /**
39
+ * Validate PREPARED data against the combined schema.
40
+ *
41
+ * `missingInputs` is reported by VARIABLE NAME - the name on the node the user
42
+ * clicks - never by `concept_ref`, which used to produce "Missing required
43
+ * fields in: native.Text" and named neither the input at fault nor, when several
44
+ * inputs share a concept, which of them. Inputs the method declared omittable
45
+ * are skipped: an empty `?` input is not a missing one.
46
+ *
47
+ * The scan can come up empty even on an invalid form (a wrong value shape, a
48
+ * nested mismatch); `errors` is what the caller falls back to then, so a failure
49
+ * is never undiagnosable.
50
+ *
51
+ * `preparedData` is `unknown` for the same reason `gateRunInputs`' `data` is: on
52
+ * a public endpoint the body is whatever was sent, and ajv must be shown that
53
+ * rather than a repair of it, or `must be object` is a verdict no caller can
54
+ * ever receive. The name-the-variable scan below needs something indexable, so
55
+ * a body that is not a record scans against nothing and names every input the
56
+ * method demands - which is the honest answer for a body that carried none.
57
+ */
58
+ declare function validateRunInputs(preparedData: unknown, inputs: Record<string, PipeInputContract>, schema: Dict): RunInputsVerdict;
59
+ /**
60
+ * Build the `{ concept, content }` map a run expects, from PREPARED data.
61
+ *
62
+ * The two ways a method says "this may be nothing" land differently on the wire:
63
+ * - an **optional (`?`)** input left blank is OMITTED, so the runtime records a
64
+ * real absence the method can branch on - sending `{ text: "" }` would look
65
+ * like the caller supplied an empty string;
66
+ * - a **plural (`[]`)** input keeps its key, because a plural slot is never
67
+ * absent - its empty form IS the empty list, and the runtime requires the key.
68
+ * When that list is EMPTY it is sent BARE, without the envelope: the envelope
69
+ * is the runtime's "explicit form", which bypasses the top-down shaper and
70
+ * hands the value to the bottom-up factory, and that factory types a list from
71
+ * its first item - so an empty list there raises "Cannot create Stuff from
72
+ * empty list in content". The bare form keeps the shaper, which reads the
73
+ * DECLARED concept and builds the empty list correctly. (pipelex/#1096 makes
74
+ * the envelope agree; the bare form runs today and stays correct after.)
75
+ *
76
+ * A fixed-count (`[N]`) list takes that same empty-list path, and an empty one
77
+ * is not a payload the method can accept. It is unreachable through the gate,
78
+ * which demands the input and rejects a short list on `minItems`; building the
79
+ * payload straight from unvalidated data is what would reach it, and inventing
80
+ * a different absence here would only hide that.
81
+ */
82
+ declare function apiInputsFromSchemaData(preparedData: Dict, inputs: Record<string, PipeInputContract>): Dict;
83
+ /** The gate's verdict: the payload to send, or why the run may not start. */
84
+ type RunInputsGateResult = {
85
+ ok: true;
86
+ inputs: Dict;
87
+ } | {
88
+ ok: false;
89
+ /** Variable names the caller left empty or short. */
90
+ missingInputs: string[];
91
+ /** Raw ajv errors, for when the scan cannot name anything. */
92
+ errors: RunInputError[];
93
+ /** The repaired data the verdict was reached on - what
94
+ * `describeValidationError` needs to quote the value it received. */
95
+ preparedData: Dict;
96
+ };
97
+ /**
98
+ * Gate a run: repair the caller's data, validate it against the contract,
99
+ * refuse anything the Run button would have refused, and build the payload.
100
+ *
101
+ * Returns a verdict rather than throwing. A server endpoint must not throw
102
+ * across the boundary to its client - frameworks routinely strip the message to
103
+ * an opaque digest in a production build - and a rejection here is an ordinary
104
+ * outcome, not an exceptional one.
105
+ *
106
+ * **`data` is `unknown` because that is what it is.** A run endpoint is public
107
+ * and no framework enforces a declared parameter type, so the argument is
108
+ * whatever the caller put in the body. The chain indexes the payload by
109
+ * variable name without first checking it is indexable, so a `null` body would
110
+ * throw *after* ajv had already reported `must be object` and before any
111
+ * verdict came back.
112
+ *
113
+ * So the two uses are separated rather than collapsed into one repair. **ajv
114
+ * judges the value the caller actually sent**, which is what makes `must be
115
+ * object` the verdict for a body that is not one; the indexing that follows
116
+ * uses a safe `{}` stand-in, which is what keeps the gate from throwing. Repair
117
+ * FIRST - coercing a non-object to `{}` before validating - is the shape that
118
+ * looks equivalent and is not: a contract whose inputs are all optional has an
119
+ * empty `required` list, so `{}` validates, and `gateRunInputs("garbage", …)`
120
+ * came back `ok: true` on a body the caller never meant as a run. Fail-closed
121
+ * costs a malformed caller an error it earned; the other direction bills a run.
122
+ *
123
+ * **The schema alone is not the rule.** ajv's `required` asserts only that a
124
+ * key is PRESENT, and a content model carries no `minLength` - so a required
125
+ * input that arrived empty (`{document: {url: ""}}`, `{text: {text: ""}}`)
126
+ * satisfies the schema. That is the natural payload, not a contrived one:
127
+ * `rjsfDataFromRunValues({}, fields)` emits exactly that when nothing is
128
+ * selected. So the gate re-applies the emptiness rule using
129
+ * `computeReadiness`'s OWN two functions over the same derived fields, which is
130
+ * the only way to be sure the two sides cannot disagree.
131
+ *
132
+ * Picking a pair that merely looks equivalent is not enough, and this is the
133
+ * whole reason the assembly lives here rather than in each host: the obvious
134
+ * choice, `inputMustBeFilled` + `isFilled`, agrees on every leaf kind and
135
+ * diverges on a structured concept in BOTH directions - `isFilled` on an object
136
+ * is `some(child filled)` where `fieldFilled` is `every(required child
137
+ * filled)`. That accepts a half-filled struct the browser refuses (a paid run
138
+ * past a disabled button) and rejects a filled all-optional struct the browser
139
+ * accepts. A host whose methods happen to use only native concepts has no test
140
+ * that can catch either.
141
+ */
142
+ declare function gateRunInputs(contract: PipeIOContract, data: unknown): RunInputsGateResult;
143
+
144
+ export { type RunInputsGateResult, type RunInputsVerdict, apiInputsFromSchemaData, buildRunInputsSchema, gateRunInputs, prepareRunInputs, validateRunInputs };
@@ -0,0 +1,13 @@
1
+ export { apiInputsFromSchemaData, buildRunInputsSchema, gateRunInputs, prepareRunInputs, validateRunInputs } from '../chunk-XEPD5VJQ.js';
2
+ import '../chunk-KFZ5MZOM.js';
3
+ import '../chunk-7BMOPXDY.js';
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
+ import '../chunk-VTPUDBSJ.js';
10
+ import '../chunk-GKV77RAS.js';
11
+ import '../chunk-NMT7BRLO.js';
12
+ //# sourceMappingURL=gate.js.map
13
+ //# sourceMappingURL=gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"gate.js"}