@fougere/schema 0.2.0-alpha.0 → 0.2.0-alpha.2

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 (188) hide show
  1. package/dist/entity.d.ts +9 -106
  2. package/dist/entity.d.ts.map +1 -1
  3. package/dist/entity.js +16 -266
  4. package/dist/entity.js.map +1 -1
  5. package/dist/field/boundary.d.ts +26 -43
  6. package/dist/field/boundary.d.ts.map +1 -1
  7. package/dist/field/boundary.js +30 -42
  8. package/dist/field/boundary.js.map +1 -1
  9. package/dist/field/field.d.ts +13 -56
  10. package/dist/field/field.d.ts.map +1 -1
  11. package/dist/field/field.js +22 -26
  12. package/dist/field/field.js.map +1 -1
  13. package/dist/field/format.d.ts +29 -0
  14. package/dist/field/format.d.ts.map +1 -0
  15. package/dist/field/format.js +24 -0
  16. package/dist/field/format.js.map +1 -0
  17. package/dist/field/index.d.ts +7 -6
  18. package/dist/field/index.d.ts.map +1 -1
  19. package/dist/field/index.js +6 -5
  20. package/dist/field/index.js.map +1 -1
  21. package/dist/field/lifecycle.d.ts +15 -24
  22. package/dist/field/lifecycle.d.ts.map +1 -1
  23. package/dist/field/lifecycle.js +10 -17
  24. package/dist/field/lifecycle.js.map +1 -1
  25. package/dist/field/meta.d.ts +1 -5
  26. package/dist/field/meta.d.ts.map +1 -1
  27. package/dist/field/meta.js +2 -4
  28. package/dist/field/meta.js.map +1 -1
  29. package/dist/field/role.d.ts +15 -22
  30. package/dist/field/role.d.ts.map +1 -1
  31. package/dist/field/role.js +11 -31
  32. package/dist/field/role.js.map +1 -1
  33. package/dist/field/shape.d.ts +24 -12
  34. package/dist/field/shape.d.ts.map +1 -1
  35. package/dist/field/shape.js +45 -27
  36. package/dist/field/shape.js.map +1 -1
  37. package/dist/hints.d.ts +10 -15
  38. package/dist/hints.d.ts.map +1 -1
  39. package/dist/hints.js +22 -1
  40. package/dist/hints.js.map +1 -1
  41. package/dist/index.d.ts +37 -36
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +37 -36
  44. package/dist/index.js.map +1 -1
  45. package/dist/name.d.ts +4 -12
  46. package/dist/name.d.ts.map +1 -1
  47. package/dist/name.js +4 -12
  48. package/dist/name.js.map +1 -1
  49. package/dist/projections/card.d.ts +39 -58
  50. package/dist/projections/card.d.ts.map +1 -1
  51. package/dist/projections/card.js.map +1 -1
  52. package/dist/projections/describe.d.ts +4 -4
  53. package/dist/projections/describe.d.ts.map +1 -1
  54. package/dist/projections/describe.js +4 -9
  55. package/dist/projections/describe.js.map +1 -1
  56. package/dist/projections/io.d.ts +5 -11
  57. package/dist/projections/io.d.ts.map +1 -1
  58. package/dist/projections/io.js +5 -11
  59. package/dist/projections/io.js.map +1 -1
  60. package/dist/projections/lifecycle.d.ts +5 -19
  61. package/dist/projections/lifecycle.d.ts.map +1 -1
  62. package/dist/projections/lifecycle.js +7 -29
  63. package/dist/projections/lifecycle.js.map +1 -1
  64. package/dist/projections/reconstruct.d.ts +11 -16
  65. package/dist/projections/reconstruct.d.ts.map +1 -1
  66. package/dist/projections/reconstruct.js +29 -32
  67. package/dist/projections/reconstruct.js.map +1 -1
  68. package/dist/projections/source.d.ts +11 -34
  69. package/dist/projections/source.d.ts.map +1 -1
  70. package/dist/projections/source.js +4 -23
  71. package/dist/projections/source.js.map +1 -1
  72. package/dist/projections/typescript.d.ts +6 -22
  73. package/dist/projections/typescript.d.ts.map +1 -1
  74. package/dist/projections/typescript.js +16 -43
  75. package/dist/projections/typescript.js.map +1 -1
  76. package/dist/schema/index.d.ts +3 -0
  77. package/dist/schema/index.d.ts.map +1 -0
  78. package/dist/schema/index.js +2 -0
  79. package/dist/schema/index.js.map +1 -0
  80. package/dist/schema/schema.d.ts +74 -0
  81. package/dist/schema/schema.d.ts.map +1 -0
  82. package/dist/schema/schema.js +162 -0
  83. package/dist/schema/schema.js.map +1 -0
  84. package/dist/schema/view.d.ts +26 -0
  85. package/dist/schema/view.d.ts.map +1 -0
  86. package/dist/schema/view.js +2 -0
  87. package/dist/schema/view.js.map +1 -0
  88. package/dist/unique.d.ts +12 -37
  89. package/dist/unique.d.ts.map +1 -1
  90. package/dist/unique.js +11 -34
  91. package/dist/unique.js.map +1 -1
  92. package/dist/validation/index.d.ts +4 -0
  93. package/dist/validation/index.d.ts.map +1 -0
  94. package/dist/validation/index.js +2 -0
  95. package/dist/validation/index.js.map +1 -0
  96. package/dist/validation/judge.d.ts +55 -0
  97. package/dist/validation/judge.d.ts.map +1 -0
  98. package/dist/validation/judge.js +351 -0
  99. package/dist/validation/judge.js.map +1 -0
  100. package/dist/validation/options.d.ts +6 -0
  101. package/dist/validation/options.d.ts.map +1 -0
  102. package/dist/validation/options.js +3 -0
  103. package/dist/validation/options.js.map +1 -0
  104. package/dist/validation/result.d.ts +20 -0
  105. package/dist/validation/result.d.ts.map +1 -0
  106. package/dist/validation/result.js +3 -0
  107. package/dist/validation/result.js.map +1 -0
  108. package/dist/vocabulary/bool.d.ts +1 -1
  109. package/dist/vocabulary/bool.d.ts.map +1 -1
  110. package/dist/vocabulary/bool.js +2 -2
  111. package/dist/vocabulary/bool.js.map +1 -1
  112. package/dist/vocabulary/created.d.ts +4 -10
  113. package/dist/vocabulary/created.d.ts.map +1 -1
  114. package/dist/vocabulary/created.js +5 -12
  115. package/dist/vocabulary/created.js.map +1 -1
  116. package/dist/vocabulary/date.d.ts +1 -1
  117. package/dist/vocabulary/date.d.ts.map +1 -1
  118. package/dist/vocabulary/date.js +2 -2
  119. package/dist/vocabulary/date.js.map +1 -1
  120. package/dist/vocabulary/immutable.d.ts +4 -6
  121. package/dist/vocabulary/immutable.d.ts.map +1 -1
  122. package/dist/vocabulary/immutable.js +3 -6
  123. package/dist/vocabulary/immutable.js.map +1 -1
  124. package/dist/vocabulary/indexed.d.ts +5 -16
  125. package/dist/vocabulary/indexed.d.ts.map +1 -1
  126. package/dist/vocabulary/indexed.js +4 -16
  127. package/dist/vocabulary/indexed.js.map +1 -1
  128. package/dist/vocabulary/json.d.ts +8 -13
  129. package/dist/vocabulary/json.d.ts.map +1 -1
  130. package/dist/vocabulary/json.js +3 -3
  131. package/dist/vocabulary/json.js.map +1 -1
  132. package/dist/vocabulary/list.d.ts +3 -6
  133. package/dist/vocabulary/list.d.ts.map +1 -1
  134. package/dist/vocabulary/list.js +6 -5
  135. package/dist/vocabulary/list.js.map +1 -1
  136. package/dist/vocabulary/many.d.ts +3 -4
  137. package/dist/vocabulary/many.d.ts.map +1 -1
  138. package/dist/vocabulary/many.js +5 -5
  139. package/dist/vocabulary/many.js.map +1 -1
  140. package/dist/vocabulary/nullable.d.ts +2 -4
  141. package/dist/vocabulary/nullable.d.ts.map +1 -1
  142. package/dist/vocabulary/nullable.js +4 -8
  143. package/dist/vocabulary/nullable.js.map +1 -1
  144. package/dist/vocabulary/number.d.ts +1 -1
  145. package/dist/vocabulary/number.d.ts.map +1 -1
  146. package/dist/vocabulary/number.js +2 -2
  147. package/dist/vocabulary/number.js.map +1 -1
  148. package/dist/vocabulary/oneOf.d.ts +1 -1
  149. package/dist/vocabulary/oneOf.d.ts.map +1 -1
  150. package/dist/vocabulary/oneOf.js +2 -2
  151. package/dist/vocabulary/oneOf.js.map +1 -1
  152. package/dist/vocabulary/optional.d.ts +1 -1
  153. package/dist/vocabulary/optional.d.ts.map +1 -1
  154. package/dist/vocabulary/optional.js +3 -3
  155. package/dist/vocabulary/optional.js.map +1 -1
  156. package/dist/vocabulary/primary.d.ts +5 -5
  157. package/dist/vocabulary/primary.d.ts.map +1 -1
  158. package/dist/vocabulary/primary.js +14 -11
  159. package/dist/vocabulary/primary.js.map +1 -1
  160. package/dist/vocabulary/readOnly.d.ts +4 -7
  161. package/dist/vocabulary/readOnly.d.ts.map +1 -1
  162. package/dist/vocabulary/readOnly.js +4 -7
  163. package/dist/vocabulary/readOnly.js.map +1 -1
  164. package/dist/vocabulary/ref.d.ts +1 -1
  165. package/dist/vocabulary/ref.d.ts.map +1 -1
  166. package/dist/vocabulary/ref.js +2 -2
  167. package/dist/vocabulary/ref.js.map +1 -1
  168. package/dist/vocabulary/text.d.ts +1 -1
  169. package/dist/vocabulary/text.d.ts.map +1 -1
  170. package/dist/vocabulary/text.js +2 -2
  171. package/dist/vocabulary/text.js.map +1 -1
  172. package/dist/vocabulary/unique.d.ts +8 -18
  173. package/dist/vocabulary/unique.d.ts.map +1 -1
  174. package/dist/vocabulary/unique.js +7 -18
  175. package/dist/vocabulary/unique.js.map +1 -1
  176. package/dist/vocabulary/updated.d.ts +2 -2
  177. package/dist/vocabulary/updated.d.ts.map +1 -1
  178. package/dist/vocabulary/updated.js +1 -2
  179. package/dist/vocabulary/updated.js.map +1 -1
  180. package/dist/vocabulary/writeOnly.d.ts +4 -6
  181. package/dist/vocabulary/writeOnly.d.ts.map +1 -1
  182. package/dist/vocabulary/writeOnly.js +4 -6
  183. package/dist/vocabulary/writeOnly.js.map +1 -1
  184. package/package.json +2 -2
  185. package/dist/projections/validation.d.ts +0 -57
  186. package/dist/projections/validation.d.ts.map +0 -1
  187. package/dist/projections/validation.js +0 -148
  188. package/dist/projections/validation.js.map +0 -1
@@ -1,54 +1,44 @@
1
- import type { BoundaryRef, Lifecycle } from '../field/index.js';
1
+ import type { BoundaryRef, Lifecycle, Relation, Role, Shape } from '../field/index.js';
2
2
  /**
3
- * The portable schema descriptor — Fougère's "carte d'identité" of an entity.
3
+ * The portable schema descriptor — an entity's "carte d'identité".
4
4
  *
5
- * It is a JSON Schema document (the `shape` axis, a near-identity projection now
6
- * that {@link FieldDescriptor} already speaks JSON Schema) carrying the three axes JSON
7
- * Schema cannot express under a single `x-fougere` extension key per field: `role`
8
- * (identity/relations), `lifecycle` (write rules), `boundary` (wire↔domain).
9
- * The normal forms (named tokens, pure JSON) ARE the wire form — lifecycle and
10
- * boundary travel verbatim, no descriptor twin to maintain.
5
+ * A JSON Schema document: the `shape` axis at the top level, the three axes JSON Schema
6
+ * cannot express under one `x-fougere` key per field. The normal forms ARE the wire form
7
+ * lifecycle and boundary travel verbatim, no descriptor twin to maintain.
11
8
  *
12
- * It is the structural counterpart of Standard Schema (`~standard`): where
13
- * `~standard` is the live, opaque "I can validate" interface, the descriptor is the
14
- * transparent, serialisable description that crosses the wire. `describe()` produces
15
- * it; a single `reconstruct()` reads it back into a working schema (validate + from).
16
- *
17
- * Honest losses vs the live field map — a reference becomes a name, a live function
18
- * does not travel:
19
- * - `role.relation.to` (a `() => Entity` thunk) → {@link RelationDescriptor.to}, a name.
20
- * - a custom generator or boundary decoder/encoder travels by NAME, re-resolved
21
- * against the consumer's registry ("unknown generator/alias" is loud and local).
9
+ * What cannot travel becomes a NAME, re-resolved against the consumer's registry: a
10
+ * relation's thunk, a custom generator, a boundary codec.
22
11
  */
23
12
  /** JSON Schema's `type` values, plus `null` for the nullable union form. */
24
13
  export type JsonSchemaType = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null';
14
+ /**
15
+ * A shape's constraint keywords, all optional and flattened — the union's branches merged.
16
+ * `type` is NOT here: intersecting the branches would make the discriminant impossible,
17
+ * and the wire genuinely allows a form memory never produces (see below).
18
+ */
19
+ type ShapeKeywords = UnionToIntersection<KeywordsOf<Shape>>;
20
+ type KeywordsOf<S> = S extends unknown ? Partial<Omit<S, 'type' | 'items' | 'properties'>> : never;
21
+ type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
25
22
  /**
26
23
  * One field as a JSON Schema property. The shape keywords sit at the top level
27
24
  * (so an external JSON Schema tool reads them directly); the Fougère-only axes
28
25
  * live under `x-fougere`. A nullable field folds into the union `type: ['T','null']`.
29
26
  */
30
- export interface FieldDescriptor {
27
+ export type FieldDescriptor = ShapeKeywords & {
28
+ /**
29
+ * WIDER than `Shape`, which only ever emits `T` or the canonical `[T,'null']` tuple.
30
+ * A card can come from another language, so the door judges the form; `reconstruct`
31
+ * refuses what it cannot represent rather than pretending it read it.
32
+ */
31
33
  type?: JsonSchemaType | JsonSchemaType[];
32
- /** JSON Schema format predicate (`date-time` for a date value, email, uuid, uri…). */
33
- format?: 'date-time' | 'date' | 'time' | 'email' | 'uuid' | 'uri';
34
- enum?: readonly (string | null)[];
35
- minLength?: number;
36
- maxLength?: number;
37
- pattern?: string;
38
- minimum?: number;
39
- maximum?: number;
40
34
  /** A value list's element shape (`list(text())`). A bare `many` relation has none. */
41
35
  items?: FieldDescriptor;
42
- minItems?: number;
43
- maxItems?: number;
44
36
  /** An embedded value object (`json(Entity)`): the nested shape-only properties. */
45
37
  properties?: Record<string, FieldDescriptor>;
46
- /** The embedded object's required keys (JSON Schema nesting, travels verbatim). */
47
- required?: readonly string[];
48
38
  /** JSON Schema standard keyword — mirrors the field's `description`. */
49
39
  description?: string;
50
40
  'x-fougere'?: FieldExtension;
51
- }
41
+ };
52
42
  /** The three axes JSON Schema can't express, namespaced under a field's `x-fougere`. */
53
43
  export interface FieldExtension {
54
44
  role?: RoleDescriptor;
@@ -56,35 +46,28 @@ export interface FieldExtension {
56
46
  lifecycle?: Lifecycle;
57
47
  boundary?: BoundaryRef;
58
48
  }
59
- export interface RoleDescriptor {
60
- primary?: boolean;
61
- /**
62
- * The unique constraints this field is a member of one member list each, member
63
- * names spelled out. `[["slug"]]` is unique on its own; `[["listId","docId"]]` on both
64
- * members says the pair is unique together, which is the fact a foreign consumer could
65
- * not read before: the card carried one boolean per field and the pair vanished.
66
- *
67
- * Self-reference is resolved on the way out (a lone `unique()` holds `[]` in memory,
68
- * because a field does not know its own key) — a card always names its members, so a
69
- * reader never has to know which field a group hangs on.
70
- */
49
+ /**
50
+ * The role, with its one unportable member replaced: `unique` names its members on the
51
+ * wire, where in memory a lone `unique()` holds `[]` — a field does not know its own key,
52
+ * a reader of the card must not have to guess it.
53
+ *
54
+ * Names what it KEEPS, like `describeRole` and `reconstructRole` do. Two of the four
55
+ * members do not travel as they are, so portability is not the default a new one gets.
56
+ */
57
+ export type RoleDescriptor = Pick<Role, 'primary' | 'index'> & {
71
58
  unique?: string[][];
72
- index?: boolean;
73
59
  relation?: RelationDescriptor;
74
- }
75
- /** A relation as portable data: the target is a NAME, not a live entity thunk. */
76
- export interface RelationDescriptor {
60
+ };
61
+ /** The relation, with its thunk replaced: the target is a NAME. */
62
+ export type RelationDescriptor = Pick<Relation, 'kind' | 'onDelete'> & {
77
63
  to: string;
78
- kind: 'one' | 'many';
79
- onDelete?: 'cascade' | 'restrict' | 'set null';
80
- }
64
+ };
81
65
  /**
82
66
  * A whole entity as a JSON Schema object document. `version`/`vendor` mirror Standard
83
67
  * Schema's own (versioned + vendored), under `x-` extension keywords so the document
84
68
  * stays a valid JSON Schema for external tooling.
85
69
  */
86
70
  export interface SchemaDescriptor {
87
- /** The entity name. */
88
71
  title?: string;
89
72
  type: 'object';
90
73
  properties: Record<string, FieldDescriptor>;
@@ -100,12 +83,9 @@ export interface SchemaDescriptor {
100
83
  'x-fougere-vendor': 'fougere';
101
84
  }
102
85
  /**
103
- * A self-contained set of entity cards a JSON Schema bundle. Every entity lives
104
- * under `$defs`, keyed by name; a relation's `to` is that namethe `$ref` into
105
- * `$defs`. The document is portable AND circular-safe: a relation is a pointer, never
106
- * an inlined sub-schema, so `Post → Author → Post` is two references, not infinite
107
- * nesting. `reconstructSet` resolves those `$ref`s so a synced relation hands back the
108
- * real reconstructed target (it feeds adapters), not just a name.
86
+ * A self-contained set of entity cards. Every entity lives under `$defs`, keyed by name,
87
+ * and a relation's `to` is that keya pointer, never an inlined sub-schema, so
88
+ * `Post Author Post` is two references and not infinite nesting.
109
89
  */
110
90
  export interface SchemaBundle {
111
91
  $defs: Record<string, SchemaDescriptor>;
@@ -114,4 +94,5 @@ export interface SchemaBundle {
114
94
  }
115
95
  /** Drop keys whose value is `undefined`, so the descriptor stays clean JSON. */
116
96
  export declare function clean<T extends Record<string, unknown>>(obj: T): T;
97
+ export {};
117
98
  //# sourceMappingURL=card.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../src/projections/card.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,4EAA4E;AAC5E,MAAM,MAAM,cAAc,GACtB,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,SAAS,GACT,QAAQ,GACR,OAAO,GACP,MAAM,CAAC;AAEX;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,cAAc,GAAG,cAAc,EAAE,CAAC;IACzC,sFAAsF;IACtF,MAAM,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;IAClE,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sFAAsF;IACtF,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC7C,mFAAmF;IACnF,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,cAAc,CAAC;CAC9B;AAED,wFAAwF;AACxF,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,kEAAkE;IAClE,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED,kFAAkF;AAClF,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;CAChD;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uBAAuB;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC5C;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,mBAAmB,EAAE,CAAC,CAAC;IACvB,kBAAkB,EAAE,SAAS,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACxC,mBAAmB,EAAE,CAAC,CAAC;IACvB,kBAAkB,EAAE,SAAS,CAAC;CAC/B;AAED,gFAAgF;AAChF,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAGlE"}
1
+ {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../src/projections/card.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEvF;;;;;;;;;GASG;AAEH,4EAA4E;AAC5E,MAAM,MAAM,cAAc,GACtB,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,SAAS,GACT,QAAQ,GACR,OAAO,GACP,MAAM,CAAC;AAEX;;;;GAIG;AACH,KAAK,aAAa,GAAG,mBAAmB,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;AAI5D,KAAK,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,YAAY,CAAC,CAAC,GAAG,KAAK,CAAC;AACnG,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC;AAEpH;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG;IAC5C;;;;OAIG;IACH,IAAI,CAAC,EAAE,cAAc,GAAG,cAAc,EAAE,CAAC;IACzC,sFAAsF;IACtF,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,mFAAmF;IACnF,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC7C,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,cAAc,CAAC;CAC9B,CAAC;AAEF,wFAAwF;AACxF,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,kEAAkE;IAClE,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,GAAG;IAC7D,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B,CAAC;AAEF,mEAAmE;AACnE,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtF;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC5C;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,mBAAmB,EAAE,CAAC,CAAC;IACvB,kBAAkB,EAAE,SAAS,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACxC,mBAAmB,EAAE,CAAC,CAAC;IACvB,kBAAkB,EAAE,SAAS,CAAC;CAC/B;AAED,gFAAgF;AAChF,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAGlE"}
@@ -1 +1 @@
1
- {"version":3,"file":"card.js","sourceRoot":"","sources":["../../src/projections/card.ts"],"names":[],"mappings":"AAkIA,gFAAgF;AAChF,MAAM,UAAU,KAAK,CAAoC,GAAM;IAC7D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS;YAAE,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;IAChF,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"card.js","sourceRoot":"","sources":["../../src/projections/card.ts"],"names":[],"mappings":"AAgHA,gFAAgF;AAChF,MAAM,UAAU,KAAK,CAAoC,GAAM;IAC7D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS;YAAE,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;IAChF,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -1,11 +1,11 @@
1
- import type { SchemaLike } from '../field/index.js';
1
+ import type { SchemaView } from '../schema/index.js';
2
2
  import { type SchemaBundle, type SchemaDescriptor } from './card.js';
3
3
  /**
4
4
  * Produce the portable card for a schema — THE single canonical serialiser
5
5
  * (the hand-rolled copies in adapters call this). `name` titles the entity; it
6
6
  * falls back to the schema's source/class name when omitted.
7
7
  */
8
- export declare function describe(schema: SchemaLike, name?: string): SchemaDescriptor;
8
+ export declare function describe(schema: SchemaView, name?: string): SchemaDescriptor;
9
9
  /**
10
10
  * The name of the schema a view came from — `Post` for `Post`, and `Post` for
11
11
  * `Post.pick('title')` too, since a derivation carries its `source`.
@@ -14,12 +14,12 @@ export declare function describe(schema: SchemaLike, name?: string): SchemaDescr
14
14
  * and GraphQL names a field's enum type with it — an enum named after the view would give
15
15
  * `Post.status` and `CreatePostInput.status` two incompatible types for one set of values.
16
16
  */
17
- export declare function sourceNameOf(schema: SchemaLike): string | undefined;
17
+ export declare function sourceNameOf(schema: SchemaView): string | undefined;
18
18
  /**
19
19
  * Describe a whole set of entities as one self-contained bundle (the `$defs`
20
20
  * document). Accepts a name→schema record or an array (names taken from the
21
21
  * schemas). Keys carry the registration key, the same spelling `describe` gives a
22
22
  * relation's `to`, so `$ref`-by-name resolves cleanly in {@link reconstructSet}.
23
23
  */
24
- export declare function describeSet(schemas: Record<string, SchemaLike> | SchemaLike[]): SchemaBundle;
24
+ export declare function describeSet(schemas: Record<string, SchemaView> | SchemaView[]): SchemaBundle;
25
25
  //# sourceMappingURL=describe.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"describe.d.ts","sourceRoot":"","sources":["../../src/projections/describe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpE,OAAO,EAML,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACtB,MAAM,WAAW,CAAC;AAuEnB;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAiB5E;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAGnE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,UAAU,EAAE,GAAG,YAAY,CAU5F"}
1
+ {"version":3,"file":"describe.d.ts","sourceRoot":"","sources":["../../src/projections/describe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD,OAAO,EAML,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACtB,MAAM,WAAW,CAAC;AAmEnB;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAiB5E;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAGnE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,UAAU,EAAE,GAAG,YAAY,CAU5F"}
@@ -61,15 +61,10 @@ function describeField(field, key) {
61
61
  // Shape is already JSON Schema's vocabulary — nullability included, as the
62
62
  // `[T,'null']` type union — so its keywords copy verbatim (an embedded object's
63
63
  // `properties`/`required` too, themselves shape-only).
64
- if (field.shape) {
65
- for (const [key, value] of Object.entries(field.shape)) {
66
- if (value === undefined)
67
- continue;
68
- out[key] = value;
69
- }
70
- }
71
- else if (field.role?.relation?.kind === 'many') {
72
- out.type = 'array';
64
+ for (const [key, value] of Object.entries(field.shape)) {
65
+ if (value === undefined)
66
+ continue;
67
+ out[key] = value;
73
68
  }
74
69
  if (field.meta?.description)
75
70
  out.description = field.meta.description;
@@ -1 +1 @@
1
- {"version":3,"file":"describe.js","sourceRoot":"","sources":["../../src/projections/describe.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"describe.js","sourceRoot":"","sources":["../../src/projections/describe.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,11 @@
1
1
  import type { Fields } from '../field/index.js';
2
2
  /**
3
- * The two dual projections of a field set onto a client surface — membership
4
- * only, derived from the axes.
3
+ * The two dual projections of a field set onto a client surface — membership only. The
4
+ * create/patch MODE changes omissibility, which the view carries, never membership.
5
5
  *
6
- * The create/patch MODE never changes membership, it only changes omissibility, which
7
- * the view (`partial()`) carries.
8
- *
9
- * ⚠️ The audience lives in this comment, not in the data — no axis says "client", so
10
- * these two functions are the only place the word exists. Surfaces are SUPPOSED to read
11
- * them instead of restating the rules, and several don't: the GraphQL public
12
- * `registerInput`, the runtime judge and the CLI each answer "what may a client supply"
13
- * with a different set. The judge is the most permissive — a client-forged primary key
14
- * reaches the ORM. Reconciling them needs the audience to become data.
6
+ * ⚠️ The audience lives here and not in the data: no axis says "client". Surfaces are
7
+ * supposed to read these two functions, and the GraphQL input, the judge and the CLI each
8
+ * restate the rules with a different set — the judge being the most permissive.
15
9
  */
16
10
  /**
17
11
  * Ingress: what a CLIENT may supply. Excluded —
@@ -1 +1 @@
1
- {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../src/projections/io.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAGhD;;;;;;;;;;;;;GAaG;AAEH;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOnD"}
1
+ {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../src/projections/io.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAGhD;;;;;;;GAOG;AAEH;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOnD"}
@@ -1,17 +1,11 @@
1
1
  import { boundaryOf } from '../field/index.js';
2
2
  /**
3
- * The two dual projections of a field set onto a client surface — membership
4
- * only, derived from the axes.
3
+ * The two dual projections of a field set onto a client surface — membership only. The
4
+ * create/patch MODE changes omissibility, which the view carries, never membership.
5
5
  *
6
- * The create/patch MODE never changes membership, it only changes omissibility, which
7
- * the view (`partial()`) carries.
8
- *
9
- * ⚠️ The audience lives in this comment, not in the data — no axis says "client", so
10
- * these two functions are the only place the word exists. Surfaces are SUPPOSED to read
11
- * them instead of restating the rules, and several don't: the GraphQL public
12
- * `registerInput`, the runtime judge and the CLI each answer "what may a client supply"
13
- * with a different set. The judge is the most permissive — a client-forged primary key
14
- * reaches the ORM. Reconciling them needs the audience to become data.
6
+ * ⚠️ The audience lives here and not in the data: no axis says "client". Surfaces are
7
+ * supposed to read these two functions, and the GraphQL input, the judge and the CLI each
8
+ * restate the rules with a different set — the judge being the most permissive.
15
9
  */
16
10
  /**
17
11
  * Ingress: what a CLIENT may supply. Excluded —
@@ -1 +1 @@
1
- {"version":3,"file":"io.js","sourceRoot":"","sources":["../../src/projections/io.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,MAAM,MAAM,GAAW,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnD,IAAI,KAAK,CAAC,IAAI,EAAE,OAAO;YAAE,SAAS;QAClC,IAAI,KAAK,CAAC,SAAS,EAAE,MAAM,KAAK,KAAK;YAAE,SAAS;QAChD,IAAI,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,KAAK,MAAM;YAAE,SAAS;QACpD,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,QAAQ;YAAE,SAAS;QAChD,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACvB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,MAAM,MAAM,GAAW,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnD,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,QAAQ;YAAE,SAAS;QACjD,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACvB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"io.js","sourceRoot":"","sources":["../../src/projections/io.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;;;;;;GAOG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,MAAM,MAAM,GAAW,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnD,IAAI,KAAK,CAAC,IAAI,EAAE,OAAO;YAAE,SAAS;QAClC,IAAI,KAAK,CAAC,SAAS,EAAE,MAAM,KAAK,KAAK;YAAE,SAAS;QAChD,IAAI,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,KAAK,MAAM;YAAE,SAAS;QACpD,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,QAAQ;YAAE,SAAS;QAChD,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACvB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,MAAM,MAAM,GAAW,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnD,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,QAAQ;YAAE,SAAS;QACjD,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACvB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,25 +1,11 @@
1
1
  /**
2
2
  * The lifecycle axis, realized — once, for every storage.
3
3
  *
4
- * `validation.ts` states the split: the judge answers "is this value legal?" and never
5
- * fills a hole; filling it — stamp `'now'`, apply `{ value }`, call `{ generate }` — is
6
- * the storage's role at the point of persistence. The split is right. What was missing
7
- * is that the framework shipped the RULE and never its realization, so each storage
8
- * rewrote it and they drifted:
9
- *
10
- * - `schema-sql` realized `{ generate }` and `'now'` in its ORM, and `{ value }` in its
11
- * DDL — as a column `DEFAULT` the database fills. A mechanism only SQL has.
12
- * - The Nuxt module's fallback ORM realized none of the three: its signature is
13
- * `(_entity, _name)`, both ignored, so it forces the name `id` and a random uuid.
14
- * - A third-party adapter (MongoDB, written outside the repo on 2026-08-08) found the
15
- * gap the only way available: a test that expected `'draft'` and got `undefined`.
16
- *
17
- * Measured, one entity, `oneOf('draft','published',{ default:'draft' })`: SQLite answered
18
- * `'draft'`, MongoDB answered `undefined`. Same declaration, same port, two answers.
19
- *
20
- * So the rule and its realization live together now, and a storage adapter calls this
21
- * instead of re-deriving it. `update: 'forbidden'` is NOT here: refusing a value is a
22
- * judgment, and the façade already does it (`validation.ts`, patch mode).
4
+ * The judge answers "is this value legal" and never fills a hole; filling it — stamp
5
+ * `'now'`, apply `{ value }`, call `{ generate }` — belongs to the storage at the point of
6
+ * persistence. Shipping the rule without its realization made each storage rewrite it, and
7
+ * they drifted: one entity with a `default` answered `'draft'` on SQL and `undefined` on
8
+ * Mongo. `update: 'forbidden'` is NOT here — refusing is a judgment.
23
9
  */
24
10
  import { type Fields } from '../field/index.js';
25
11
  type Row = Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/projections/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAyC,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAGvF,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AA8BnC;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,GAAG,CAqB3D;AAgBD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,GAAG,CAS3D"}
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/projections/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAsC,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAGpF,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAsBnC;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,GAAG,CAqB3D;AAgBD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,GAAG,CAS3D"}
@@ -1,37 +1,15 @@
1
1
  /**
2
2
  * The lifecycle axis, realized — once, for every storage.
3
3
  *
4
- * `validation.ts` states the split: the judge answers "is this value legal?" and never
5
- * fills a hole; filling it — stamp `'now'`, apply `{ value }`, call `{ generate }` — is
6
- * the storage's role at the point of persistence. The split is right. What was missing
7
- * is that the framework shipped the RULE and never its realization, so each storage
8
- * rewrote it and they drifted:
9
- *
10
- * - `schema-sql` realized `{ generate }` and `'now'` in its ORM, and `{ value }` in its
11
- * DDL — as a column `DEFAULT` the database fills. A mechanism only SQL has.
12
- * - The Nuxt module's fallback ORM realized none of the three: its signature is
13
- * `(_entity, _name)`, both ignored, so it forces the name `id` and a random uuid.
14
- * - A third-party adapter (MongoDB, written outside the repo on 2026-08-08) found the
15
- * gap the only way available: a test that expected `'draft'` and got `undefined`.
16
- *
17
- * Measured, one entity, `oneOf('draft','published',{ default:'draft' })`: SQLite answered
18
- * `'draft'`, MongoDB answered `undefined`. Same declaration, same port, two answers.
19
- *
20
- * So the rule and its realization live together now, and a storage adapter calls this
21
- * instead of re-deriving it. `update: 'forbidden'` is NOT here: refusing a value is a
22
- * judgment, and the façade already does it (`validation.ts`, patch mode).
4
+ * The judge answers "is this value legal" and never fills a hole; filling it — stamp
5
+ * `'now'`, apply `{ value }`, call `{ generate }` — belongs to the storage at the point of
6
+ * persistence. Shipping the rule without its realization made each storage rewrite it, and
7
+ * they drifted: one entity with a `default` answered `'draft'` on SQL and `undefined` on
8
+ * Mongo. `update: 'forbidden'` is NOT here — refusing is a judgment.
23
9
  */
24
10
  import { resolveCustomGenerator } from '../field/index.js';
25
11
  import { createId } from '@paralleldrive/cuid2';
26
- /**
27
- * Resolve a generator TOKEN to a function: a custom name registered via
28
- * `registerGenerator` wins, then the built-ins. An unknown name throws — loud and
29
- * local, instead of a silent divergence between two storages.
30
- *
31
- * The built-ins used to live storage-side, which put the inversion in plain sight: a
32
- * generator YOU invent travelled to every adapter, and the three the framework ships
33
- * did not.
34
- */
12
+ /** Resolve a generator TOKEN to a function — a registered name wins over a built-in. */
35
13
  function generatorFor(ref) {
36
14
  const custom = resolveCustomGenerator(ref);
37
15
  if (custom)
@@ -91,7 +69,7 @@ export function applyCreate(fields, input) {
91
69
  *
92
70
  * Every default the vocabulary can express is a primitive (`text`, `number`, `bool`,
93
71
  * `oneOf`; `list` and `json` take none), so this only pays for itself under the escape
94
- * hatch — `createField({ lifecycle: { create: { value: {…} } } })`. Cheap insurance
72
+ * hatch — `new Field({ shape, lifecycle: { create: { value: {…} } } })`. Cheap insurance
95
73
  * against the one failure mode nobody would ever debug from the symptom.
96
74
  */
97
75
  function freshValue(value) {
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/projections/lifecycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/projections/lifecycle.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,13 @@
1
- import { type Field, type Fields } from '../field/index.js';
2
- import { type SchemaConstructor, type SchemaViewInfer } from '../entity.js';
1
+ import { Field, type Fields } from '../field/index.js';
2
+ import { type SchemaConstructor, type SchemaView, type Row } from '../schema/index.js';
3
3
  import { type SchemaBundle, type SchemaDescriptor } from './card.js';
4
4
  /**
5
- * The field map a stated row shape implies.
6
- *
7
- * Every member is marked auto-at-creation, so `CtorInput` asks for nothing: a card
8
- * describes rows as they are READ, and "what a caller must supply at creation" is a
9
- * different question — one `required` answers, and one a synced consumer never asks,
10
- * since it calls the host rather than constructing.
5
+ * The field map a stated row shape implies. A card describes rows as they are READ, so
6
+ * `required` answers what a creation payload must carry — a question a synced consumer
7
+ * never asks, since it calls the host rather than constructing.
11
8
  */
12
9
  type FieldsOf<T> = {
13
- [K in keyof T]-?: Field<T[K], true>;
10
+ [K in keyof T]-?: Field<T[K]>;
14
11
  };
15
12
  /**
16
13
  * Read a lone card back into a working schema — THE single reconstructor. The result
@@ -18,19 +15,17 @@ type FieldsOf<T> = {
18
15
  * the wire as data, the behaviour is reconstituted here. Relations stay name stand-ins
19
16
  * (no set to resolve against — use {@link reconstructSet} for live targets).
20
17
  *
21
- * `T` states the shape of a row, and that is what makes a rebuilt schema a CLASS rather
22
- * than a type and a value declared side by side: `class Post extends reconstruct<{…}>(card) {}`
23
- * is one declaration carrying both, exactly like `class Post extends entity({…}) {}`.
24
- * Without it the instance type is an index signature, so a synced entity validated
25
- * perfectly and taught the compiler nothing — `post.titel` compiled.
18
+ * `T` states the row, which is what makes a rebuilt schema a CLASS and not a type beside a
19
+ * value: `class Post extends reconstruct<{…}>(card) {}`, one declaration carrying both.
20
+ * Without it the instance type is an index signature, so `post.titel` compiled.
26
21
  */
27
- export declare function reconstruct<T = SchemaViewInfer<Fields>>(descriptor: SchemaDescriptor): SchemaConstructor<FieldsOf<T>>;
22
+ export declare function reconstruct<T = Row<Fields>>(descriptor: SchemaDescriptor): SchemaConstructor<FieldsOf<T>>;
28
23
  /**
29
24
  * Read a whole bundle back into live schemas, keyed by name — THE set reconstructor.
30
25
  * Every entity is rebuilt against a shared `$defs` resolver, so a relation's `to()`
31
26
  * hands back the real reconstructed target (feeds adapters), not a name stand-in.
32
27
  * Targets absent from the set (external/cross-frond `$ref`) keep the stand-in.
33
28
  */
34
- export declare function reconstructSet(bundle: SchemaBundle): Record<string, SchemaConstructor<Fields>>;
29
+ export declare function reconstructSet(bundle: SchemaBundle): Record<string, SchemaView>;
35
30
  export {};
36
31
  //# sourceMappingURL=reconstruct.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reconstruct.d.ts","sourceRoot":"","sources":["../../src/projections/reconstruct.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,KAAK,EACV,KAAK,MAAM,EAGZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAA2B,KAAK,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACrG,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACtB,MAAM,WAAW,CAAC;AAsHnB;;;;;;;GAOG;AACH,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;CAAE,CAAC;AAE3D;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAG,eAAe,CAAC,MAAM,CAAC,EACrD,UAAU,EAAE,gBAAgB,GAC3B,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAEhC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAc9F"}
1
+ {"version":3,"file":"reconstruct.d.ts","sourceRoot":"","sources":["../../src/projections/reconstruct.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EAEL,KAAK,MAAM,EAGZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAU,KAAK,iBAAiB,EAAE,KAAK,UAAU,EAAE,KAAK,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC/F,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACtB,MAAM,WAAW,CAAC;AAyHnB;;;;GAIG;AACH,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC;AAErD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,EACzC,UAAU,EAAE,gBAAgB,GAC3B,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAEhC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAa/E"}
@@ -1,5 +1,5 @@
1
- import { createField, } from '../field/index.js';
2
- import { createSchemaConstructor } from '../entity.js';
1
+ import { Field, } from '../field/index.js';
2
+ import { Schema } from '../schema/index.js';
3
3
  import { clean, } from './card.js';
4
4
  // ─── reconstruct — card → schema (the single reconstructor) ────────
5
5
  /**
@@ -13,12 +13,11 @@ function reconstructShape(prop) {
13
13
  if (base === undefined)
14
14
  return undefined;
15
15
  const type = prop.type;
16
- // `array` is two distinct things: with `items` it is a value list (a real shape);
17
- // without, it is a bare `many` relation marker no shape, the role carries it.
16
+ // `array` with `items` is a value list, without it a `many` relation whose elements
17
+ // live on the other side. Both are array shapes; only the role tells them apart, and
18
+ // it travels in `x-fougere`. Nothing to branch on here — the keywords copy back.
18
19
  if (base === 'array') {
19
- if (!prop.items)
20
- return undefined;
21
- const items = reconstructShape(prop.items);
20
+ const items = prop.items ? reconstructShape(prop.items) : undefined;
22
21
  return clean({ type, items, minItems: prop.minItems, maxItems: prop.maxItems });
23
22
  }
24
23
  switch (base) {
@@ -58,10 +57,18 @@ function reconstructRole(role, resolve) {
58
57
  }
59
58
  return out;
60
59
  }
61
- function reconstructField(prop, resolve) {
60
+ function reconstructField(prop, key, resolve) {
62
61
  const ext = prop['x-fougere'];
63
- return createField({
64
- shape: reconstructShape(prop),
62
+ const shape = reconstructShape(prop);
63
+ // A card that names no type for a property cannot become a field: every field states a
64
+ // shape. Loud and local, at the property that is missing it — the alternative is a field
65
+ // that judges nothing, which is what this whole rule exists to stop.
66
+ if (!shape) {
67
+ throw new Error(`Field '${key}': the card carries no \`type\` for it, so there is no shape to rebuild. `
68
+ + `A field always states one.`);
69
+ }
70
+ return new Field({
71
+ shape,
65
72
  role: ext?.role ? reconstructRole(ext.role, resolve) : undefined,
66
73
  // The normal forms are pure JSON — they travelled verbatim, they read back verbatim.
67
74
  lifecycle: ext?.lifecycle,
@@ -81,9 +88,7 @@ function compositeFromFields(fields) {
81
88
  for (const group of field.role?.unique ?? []) {
82
89
  if (group.length < 2)
83
90
  continue;
84
- // A key that cannot collide with a field name `JSON.stringify` rather than a
85
- // separator byte: a NUL in the source made every `grep` read this whole file as
86
- // binary and skip it silently, a poor price for a de-duplication key.
91
+ // `JSON.stringify` and not a separator byte: a NUL made `grep` read the file as binary.
87
92
  seen.set(JSON.stringify(group), [...group]);
88
93
  }
89
94
  }
@@ -93,18 +98,13 @@ function compositeFromFields(fields) {
93
98
  function buildSchema(descriptor, resolve) {
94
99
  const fields = {};
95
100
  for (const [key, prop] of Object.entries(descriptor.properties)) {
96
- fields[key] = reconstructField(prop, resolve);
101
+ fields[key] = reconstructField(prop, key, resolve);
97
102
  }
98
- // Recover the entity-level declaration from what the members carry. The card holds the
99
- // fact once per member; a group of two arrives twice, so the set is de-duplicated —
100
- // `getUnique()` then answers what the original author wrote, and the DDL on this side
101
- // emits the same constraint as the DDL on the other.
102
- const schema = createSchemaConstructor(fields, undefined, undefined, {}, compositeFromFields(fields));
103
- // The name is the identity everything downstream keys on — the registration key, the
104
- // table, the GraphQL type, what a relation's `to` points at. `describe` writes it as
105
- // `title`; dropping it here left a rebuilt schema called `Schema`, so a card could not
106
- // round-trip and an adapter standing on one had no entity name to work from.
107
- // `reconstructSet` still overrides with the bundle key, which is the more specific truth.
103
+ // The card holds the fact once per MEMBER, so a group of two arrives twice — de-duplicate
104
+ // it and `getUnique()` answers what the author wrote.
105
+ const schema = Schema.of(fields, undefined, undefined, {}, compositeFromFields(fields));
106
+ // The name is what everything downstream keys on the table, the GraphQL type, a
107
+ // relation's `to`. `reconstructSet` overrides it with the bundle key, more specific.
108
108
  if (descriptor.title) {
109
109
  Object.defineProperty(schema, 'name', { value: descriptor.title, configurable: true });
110
110
  }
@@ -116,11 +116,9 @@ function buildSchema(descriptor, resolve) {
116
116
  * the wire as data, the behaviour is reconstituted here. Relations stay name stand-ins
117
117
  * (no set to resolve against — use {@link reconstructSet} for live targets).
118
118
  *
119
- * `T` states the shape of a row, and that is what makes a rebuilt schema a CLASS rather
120
- * than a type and a value declared side by side: `class Post extends reconstruct<{…}>(card) {}`
121
- * is one declaration carrying both, exactly like `class Post extends entity({…}) {}`.
122
- * Without it the instance type is an index signature, so a synced entity validated
123
- * perfectly and taught the compiler nothing — `post.titel` compiled.
119
+ * `T` states the row, which is what makes a rebuilt schema a CLASS and not a type beside a
120
+ * value: `class Post extends reconstruct<{…}>(card) {}`, one declaration carrying both.
121
+ * Without it the instance type is an index signature, so `post.titel` compiled.
124
122
  */
125
123
  export function reconstruct(descriptor) {
126
124
  return buildSchema(descriptor);
@@ -137,9 +135,8 @@ export function reconstructSet(bundle) {
137
135
  const out = {};
138
136
  for (const [name, descriptor] of Object.entries(bundle.$defs)) {
139
137
  const schema = buildSchema(descriptor, resolve);
140
- // Name the rebuilt class after its key so re-describing it yields the same `to` name
141
- // (describe reads `relation.to().name`). Lazy `to` means the map need only be full
142
- // before any `.to()` call — true once this loop ends.
138
+ // Named after its key so re-describing yields the same `to`. `to` is lazy, so the map
139
+ // need only be full before the first call true once this loop ends.
143
140
  Object.defineProperty(schema, 'name', { value: name, configurable: true });
144
141
  map[name.toLowerCase()] = schema;
145
142
  out[name] = schema;