@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,25 +1,31 @@
1
- import { anatomy } from './shape.js';
1
+ import { Anatomy } from './shape.js';
2
2
  // ─── Registries (open, extensible — same spirit as FougereHints) ──
3
- const decoders = new Map();
4
- const encoders = new Map();
5
- const aliases = new Map();
6
- export function registerDecoder(name, fn) {
7
- decoders.set(name, fn);
8
- }
9
- export function registerEncoder(name, fn) {
10
- encoders.set(name, fn);
11
- }
12
- /** Register a named boundary the alias a field can reference. */
13
- export function registerBoundaryAlias(name, boundary) {
14
- aliases.set(name, boundary);
3
+ export class Boundaries {
4
+ static decoders = new Map();
5
+ static encoders = new Map();
6
+ static aliases = new Map();
7
+ static registerDecoder(name, fn) { this.decoders.set(name, fn); }
8
+ static registerEncoder(name, fn) { this.encoders.set(name, fn); }
9
+ /** Name a pair of directional rules, so a field declares `boundary: 'moneyCents'`. */
10
+ static registerAlias(name, boundary) { this.aliases.set(name, boundary); }
11
+ static alias(name) { return this.aliases.get(name); }
12
+ static decoder(name) { return this.named(this.decoders, name, 'decoder'); }
13
+ static encoder(name) { return this.named(this.encoders, name, 'encoder'); }
14
+ static named(registry, name, kind) {
15
+ const fn = registry.get(name);
16
+ if (!fn) {
17
+ throw new Error(`Unknown boundary ${kind}: '${name}'. Register it with ` +
18
+ `Boundaries.register${kind[0].toUpperCase()}${kind.slice(1)}('${name}', …).`);
19
+ }
20
+ return fn;
21
+ }
15
22
  }
16
- // ─── Built-ins ───────────────────────────────────────
17
23
  const identityDecoder = (value) => ({ value });
18
24
  const identityEncoder = (value) => value;
19
25
  // `isoDate`: the only non-identity built-in. Inbound accepts a Date or an ISO-ish
20
26
  // string and yields a Date; outbound yields an ISO string. Validity is already
21
27
  // guaranteed by `shape` (the date predicate) before decode runs.
22
- registerDecoder('isoDate', (value) => {
28
+ Boundaries.registerDecoder('isoDate', (value) => {
23
29
  if (value instanceof Date)
24
30
  return { value };
25
31
  if (typeof value === 'string') {
@@ -28,13 +34,13 @@ registerDecoder('isoDate', (value) => {
28
34
  }
29
35
  return { error: 'Expected a date' };
30
36
  });
31
- registerEncoder('isoDate', (value) => value instanceof Date ? value.toISOString() : value);
32
- registerBoundaryAlias('isoDate', { in: { decode: 'isoDate' }, out: { encode: 'isoDate' } });
37
+ Boundaries.registerEncoder('isoDate', (value) => value instanceof Date ? value.toISOString() : value);
38
+ Boundaries.registerAlias('isoDate', { in: { decode: 'isoDate' }, out: { encode: 'isoDate' } });
33
39
  /** Default boundary derived from a field's shape. A date-time string → isoDate, else identity. */
34
40
  function defaultBoundaryForShape(shape) {
35
- const base = anatomy(shape).base;
41
+ const base = Anatomy.of(shape).base;
36
42
  if (base && base.type === 'string' && base.format === 'date-time')
37
- return aliases.get('isoDate');
43
+ return Boundaries.alias('isoDate');
38
44
  return {};
39
45
  }
40
46
  // ─── Resolution ──────────────────────────────────────
@@ -44,7 +50,7 @@ export function declaredBoundary(field) {
44
50
  if (ref === undefined)
45
51
  return {};
46
52
  if (typeof ref === 'string') {
47
- const alias = aliases.get(ref);
53
+ const alias = Boundaries.alias(ref);
48
54
  if (!alias)
49
55
  throw new Error(`Unknown boundary alias: '${ref}'`);
50
56
  return alias;
@@ -63,32 +69,14 @@ export function boundaryOf(field) {
63
69
  return { in: declared.in ?? derived.in, out: declared.out ?? derived.out };
64
70
  }
65
71
  /**
66
- * A field's effective conversion functions. The permission facet is not read
67
- * here: a `'closed'` direction converts as identity its rejection/omission
68
- * happens in the readers (validation, encode) BEFORE any conversion.
69
- *
70
- * A NAMED codec that no one registered throws, exactly like an unknown alias
71
- * (`declaredBoundary`). It used to fall back to identity: a frond declared
72
- * `{ decode: 'celsius' }`, the consumer never called `registerDecoder`, and the
73
- * value arrived unconverted while the card said it had been converted — the same
74
- * silent loss this repo measured on Remult (`validate: [null, null]`) and on
75
- * zod v4 (a computed default frozen at export). One axis, two spellings, one
76
- * failure mode.
77
- *
78
- * It throws where the conversion is needed, not at boot: nothing walks every
79
- * field at startup. Loud and late beats silent and never.
72
+ * A field's effective conversion functions. A closed direction converts as identity — the
73
+ * permission facet is judged by the façade, not here.
80
74
  */
81
75
  export function resolveBoundary(field) {
82
76
  const boundary = boundaryOf(field);
83
77
  return {
84
- decode: typeof boundary.in === 'object' ? named(decoders, boundary.in.decode, 'decoder') : identityDecoder,
85
- encode: typeof boundary.out === 'object' ? named(encoders, boundary.out.encode, 'encoder') : identityEncoder,
78
+ decode: typeof boundary.in === 'object' ? Boundaries.decoder(boundary.in.decode) : identityDecoder,
79
+ encode: typeof boundary.out === 'object' ? Boundaries.encoder(boundary.out.encode) : identityEncoder,
86
80
  };
87
81
  }
88
- function named(registry, name, kind) {
89
- const fn = registry.get(name);
90
- if (!fn)
91
- throw new Error(`Unknown boundary ${kind}: '${name}'. Register it with register${kind[0].toUpperCase()}${kind.slice(1)}('${name}', …).`);
92
- return fn;
93
- }
94
82
  //# sourceMappingURL=boundary.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"boundary.js","sourceRoot":"","sources":["../../src/field/boundary.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"boundary.js","sourceRoot":"","sources":["../../src/field/boundary.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAc,MAAM,YAAY,CAAC;AAmCjD,qEAAqE;AAErE,MAAM,OAAO,UAAU;IACb,MAAM,CAAU,QAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;IACtD,MAAM,CAAU,QAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;IACtD,MAAM,CAAU,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE9D,MAAM,CAAC,eAAe,CAAC,IAAY,EAAE,EAAW,IAAU,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACxF,MAAM,CAAC,eAAe,CAAC,IAAY,EAAE,EAAW,IAAU,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAExF,sFAAsF;IACtF,MAAM,CAAC,aAAa,CAAC,IAAY,EAAE,QAAkB,IAAU,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAElG,MAAM,CAAC,KAAK,CAAC,IAAY,IAA0B,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEnF,MAAM,CAAC,OAAO,CAAC,IAAY,IAAa,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IAC5F,MAAM,CAAC,OAAO,CAAC,IAAY,IAAa,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IAEpF,MAAM,CAAC,KAAK,CAAI,QAAwB,EAAE,IAAY,EAAE,IAAY;QAC1E,MAAM,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,MAAM,IAAI,KAAK,CACb,oBAAoB,IAAI,MAAM,IAAI,sBAAsB;gBACtD,sBAAsB,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,QAAQ,CAC/E,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;CACF;AAED,MAAM,eAAe,GAAY,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AACxD,MAAM,eAAe,GAAY,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC;AAElD,kFAAkF;AAClF,+EAA+E;AAC/E,iEAAiE;AACjE,UAAU,CAAC,eAAe,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;IAC9C,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IAC9E,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;AACtC,CAAC,CAAC,CAAC;AACH,UAAU,CAAC,eAAe,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAC9C,KAAK,YAAY,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,KAAK,CACpD,CAAC;AACF,UAAU,CAAC,aAAa,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;AAE/F,kGAAkG;AAClG,SAAS,uBAAuB,CAAC,KAAwB;IACvD,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;IACpC,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW;QAAE,OAAO,UAAU,CAAC,KAAK,CAAC,SAAS,CAAE,CAAC;IACvG,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,wDAAwD;AAExD,0FAA0F;AAC1F,MAAM,UAAU,gBAAgB,CAAC,KAAY;IAC3C,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC;IAC3B,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACjC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,GAAG,CAAC,CAAC;QAChE,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,KAAY;IACrC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,uBAAuB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrD,OAAO,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,IAAI,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;AAC7E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAY;IAC1C,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACnC,OAAO;QACL,MAAM,EAAE,OAAO,QAAQ,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,eAAe;QAClG,MAAM,EAAE,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,eAAe;KACrG,CAAC;AACJ,CAAC"}
@@ -1,64 +1,21 @@
1
- import type { Shape } from './shape.js';
2
- import type { Role } from './role.js';
3
- import type { Lifecycle } from './lifecycle.js';
4
- import type { BoundaryRef } from './boundary.js';
5
- import type { Meta } from './meta.js';
6
- /**
7
- * A field — the single source of truth, decomposed on four orthogonal axes
8
- * plus one documentary compartment:
9
- * `shape` (is the value valid? — nullability included, as the `[T,'null']` union),
10
- * `role` (place in the entity graph), `lifecycle` (who writes the value, at which
11
- * moment), `boundary` (how a value crosses wire↔domain), `meta` (human-facing,
12
- * never decides). Adapters read the axes they care about; nothing reads all of
13
- * them at once. `boundary` is usually absent — its default is derived from
14
- * `shape` and the slot only overrides it.
15
- *
16
- * @typeParam T - the data type this field carries (phantom, TS inference only)
17
- * @typeParam A - "auto-supplied at creation" (primary/auto/default/optional) →
18
- * the field is optional in `new X(input)`. Phantom, type-level only.
19
- */
20
- export interface Field<T = unknown, A extends boolean = false> {
21
- readonly __brand: 'fougere_field';
22
- readonly shape?: Shape;
1
+ import type { Shape } from "./shape.js";
2
+ import type { Role } from "./role.js";
3
+ import type { Lifecycle } from "./lifecycle.js";
4
+ import type { BoundaryRef } from "./boundary.js";
5
+ import type { Meta } from "./meta.js";
6
+ export declare class Field<T = unknown> {
7
+ readonly shape: Shape;
23
8
  readonly role?: Role;
24
9
  readonly lifecycle?: Lifecycle;
25
10
  readonly boundary?: BoundaryRef;
26
11
  readonly meta?: Meta;
27
- /** Phantom — data type, never read at runtime. */
28
12
  readonly _type?: T;
29
- /** Phantom — auto-at-creation flag, never read at runtime. */
30
- readonly _auto?: A;
13
+ constructor(init: FieldData, key?: string);
14
+ with<U = T>(overrides: Partial<FieldData>): Field<U>;
31
15
  }
32
- /** Any field, regardless of its T/A parameters — the correct generic bound. */
33
- export type AnyField = Field<any, boolean>;
34
16
  /** A record of fields — the input to `entity()` and every derivation. */
35
- export type Fields = Record<string, AnyField>;
36
- export interface FieldInit {
37
- shape?: Shape;
38
- role?: Role;
39
- lifecycle?: Lifecycle;
40
- boundary?: BoundaryRef;
41
- meta?: Meta;
42
- }
43
- export declare function createField<T, A extends boolean = false>(init?: FieldInit): Field<T, A>;
44
- /**
45
- * Copy a field, overriding only the named axes — every OTHER axis is preserved.
46
- * This is the invariant every field transform must hold: change what you mean,
47
- * keep the rest. Enumerating axes by hand (the old `optional`/`primary`) silently
48
- * drops whatever axis was added last — `codec` did exactly that. Spread + override,
49
- * so a future 6th slot travels for free. (Spread props skip excess-property checks,
50
- * so the field's `__brand`/phantoms ride along harmlessly and `createField` resets them.)
51
- */
52
- export declare function cloneField(field: AnyField, overrides?: FieldInit): AnyField;
53
- /** Duck type for anything with fields — Entity, SchemaConstructor. */
54
- export interface SchemaLike {
55
- getFields(): Fields;
56
- /** The view's validation mode (patch…) — carried by SchemaConstructor, optional on bare wrappers. */
57
- getOpts?(): {
58
- patch?: boolean;
59
- };
60
- /** Field groups unique together — carried by SchemaConstructor, absent on bare wrappers. */
61
- getUnique?(): ReadonlyArray<ReadonlyArray<string>> | undefined;
62
- }
63
- export declare function isField(value: unknown): value is AnyField;
17
+ export type Fields = Record<string, Field>;
18
+ export type FieldData = {
19
+ [K in keyof Field as Field[K] extends (...args: never[]) => unknown ? never : K]: Field[K];
20
+ };
64
21
  //# sourceMappingURL=field.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../src/field/field.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,SAAS,OAAO,GAAG,KAAK;IAC3D,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,WAAW,CAAC;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IACrB,kDAAkD;IAClD,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACnB,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;CACpB;AAED,+EAA+E;AAC/E,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAE3C,yEAAyE;AACzE,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAE9C,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,IAAI,CAAC,EAAE,IAAI,CAAC;CACb;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,OAAO,GAAG,KAAK,EAAE,IAAI,GAAE,SAAc,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAS3F;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,GAAE,SAAc,GAAG,QAAQ,CAE/E;AAED,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,SAAS,IAAI,MAAM,CAAC;IACpB,qGAAqG;IACrG,OAAO,CAAC,IAAI;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAChC,4FAA4F;IAC5F,SAAS,CAAC,IAAI,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;CAChE;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAOzD"}
1
+ {"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../src/field/field.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,qBAAa,KAAK,CAAC,CAAC,GAAG,OAAO;IAC5B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,WAAW,CAAC;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IACrB,SAAiB,KAAK,CAAC,EAAE,CAAC,CAAC;IAE3B,YAAY,IAAI,EAAE,SAAS,EAAE,GAAG,CAAC,EAAE,MAAM,EAexC;IAED,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAEnD;CACF;AAED,yEAAyE;AACzE,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAE3C,MAAM,MAAM,SAAS,GAAG;KACrB,CAAC,IAAI,MAAM,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,GAC/D,KAAK,GACL,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;CACjB,CAAC"}
@@ -1,28 +1,24 @@
1
- export function createField(init = {}) {
2
- return {
3
- __brand: 'fougere_field',
4
- shape: init.shape,
5
- role: init.role,
6
- lifecycle: init.lifecycle,
7
- boundary: init.boundary,
8
- meta: init.meta,
9
- };
10
- }
11
- /**
12
- * Copy a field, overriding only the named axes — every OTHER axis is preserved.
13
- * This is the invariant every field transform must hold: change what you mean,
14
- * keep the rest. Enumerating axes by hand (the old `optional`/`primary`) silently
15
- * drops whatever axis was added last — `codec` did exactly that. Spread + override,
16
- * so a future 6th slot travels for free. (Spread props skip excess-property checks,
17
- * so the field's `__brand`/phantoms ride along harmlessly and `createField` resets them.)
18
- */
19
- export function cloneField(field, overrides = {}) {
20
- return createField({ ...field, ...overrides });
21
- }
22
- export function isField(value) {
23
- return (typeof value === 'object' &&
24
- value !== null &&
25
- '__brand' in value &&
26
- value.__brand === 'fougere_field');
1
+ import { Judge } from "../validation/index.js";
2
+ export class Field {
3
+ shape;
4
+ role;
5
+ lifecycle;
6
+ boundary;
7
+ meta;
8
+ constructor(init, key) {
9
+ const verdict = Judge.field(init);
10
+ if (!verdict.success) {
11
+ throw new Error(`${key ? `Field '${key}': ` : ""}` +
12
+ verdict.errors.map((e) => `${e.path}: ${e.message}`).join("; "));
13
+ }
14
+ this.shape = init.shape;
15
+ this.role = init.role;
16
+ this.lifecycle = init.lifecycle;
17
+ this.boundary = init.boundary;
18
+ this.meta = init.meta;
19
+ }
20
+ with(overrides) {
21
+ return new Field({ ...this, ...overrides });
22
+ }
27
23
  }
28
24
  //# sourceMappingURL=field.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"field.js","sourceRoot":"","sources":["../../src/field/field.ts"],"names":[],"mappings":"AA+CA,MAAM,UAAU,WAAW,CAA+B,IAAI,GAAc,EAAE;IAC5E,OAAO;QACL,OAAO,EAAE,eAAe;QACxB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,IAAI,EAAE,IAAI,CAAC,IAAI;KAChB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,KAAe,EAAE,SAAS,GAAc,EAAE;IACnE,OAAO,WAAW,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,SAAS,EAAE,CAAC,CAAC;AACjD,CAAC;AAWD,MAAM,UAAU,OAAO,CAAC,KAAc;IACpC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,SAAS,IAAI,KAAK;QACjB,KAAa,CAAC,OAAO,KAAK,eAAe,CAC3C,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"field.js","sourceRoot":"","sources":["../../src/field/field.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAM/C,MAAM,OAAO,KAAK;IACP,KAAK,CAAQ;IACb,IAAI,CAAQ;IACZ,SAAS,CAAa;IACtB,QAAQ,CAAe;IACvB,IAAI,CAAQ;IAGrB,YAAY,IAAe,EAAE,GAAY;QACvC,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAElC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CACb,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBAChC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAClE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACxB,CAAC;IAED,IAAI,CAAQ,SAA6B;QACvC,OAAO,IAAI,KAAK,CAAI,EAAE,GAAG,IAAI,EAAE,GAAG,SAAS,EAAE,CAAC,CAAC;IACjD,CAAC;CACF"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The `format` keyword — JSON Schema's one openly extensible vocabulary, which is why a
3
+ * custom predicate rides here and not in a keyword of our own.
4
+ */
5
+ export type StringFormat = 'date-time' | 'date' | 'time' | 'email' | 'uuid' | 'uri' | (string & {});
6
+ /**
7
+ * A custom format's predicate: one value, one verdict.
8
+ *
9
+ * No message, deliberately — a custom format fails exactly like `email` does,
10
+ * because the NAME is the contract and a consumer reading the card cannot tell
11
+ * ours from the standard's.
12
+ */
13
+ export type FormatPredicate = (value: string) => boolean;
14
+ /**
15
+ * Register a format the engine does not ship — `Formats.register('siret', luhn)` makes
16
+ * `text({ format: 'siret' })` judged. The field declares a NAME and a module supplies the
17
+ * realization, so the rule crosses a process or a language: the card carries
18
+ * `"format": "siret"`, legal JSON Schema, and each runtime resolves it locally.
19
+ *
20
+ * Registering a name the engine already judges is cumulative — both predicates must pass.
21
+ */
22
+ export declare class Formats {
23
+ private static readonly registry;
24
+ /** Register a format the engine does not ship — `text({ format: 'siret' })` becomes judged. */
25
+ static register(name: string, predicate: FormatPredicate): void;
26
+ /** A registered custom predicate, or undefined — the reader the judge goes through. */
27
+ static resolve(name: string): FormatPredicate | undefined;
28
+ }
29
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/field/format.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,YAAY,GACpB,WAAW,GACX,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,KAAK,GACL,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAIlB;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;AAEzD;;;;;;;GAOG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAsC;IAEtE,+FAA+F;IAC/F,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,GAAG,IAAI,CAE9D;IAED,uFAAuF;IACvF,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAExD;CACF"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The `format` keyword — JSON Schema's one openly extensible vocabulary, which is why a
3
+ * custom predicate rides here and not in a keyword of our own.
4
+ */
5
+ /**
6
+ * Register a format the engine does not ship — `Formats.register('siret', luhn)` makes
7
+ * `text({ format: 'siret' })` judged. The field declares a NAME and a module supplies the
8
+ * realization, so the rule crosses a process or a language: the card carries
9
+ * `"format": "siret"`, legal JSON Schema, and each runtime resolves it locally.
10
+ *
11
+ * Registering a name the engine already judges is cumulative — both predicates must pass.
12
+ */
13
+ export class Formats {
14
+ static registry = new Map();
15
+ /** Register a format the engine does not ship — `text({ format: 'siret' })` becomes judged. */
16
+ static register(name, predicate) {
17
+ this.registry.set(name, predicate);
18
+ }
19
+ /** A registered custom predicate, or undefined — the reader the judge goes through. */
20
+ static resolve(name) {
21
+ return this.registry.get(name);
22
+ }
23
+ }
24
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/field/format.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAsBH;;;;;;;GAOG;AACH,MAAM,OAAO,OAAO;IACV,MAAM,CAAU,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEtE,+FAA+F;IAC/F,MAAM,CAAC,QAAQ,CAAC,IAAY,EAAE,SAA0B;QACtD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACrC,CAAC;IAED,uFAAuF;IACvF,MAAM,CAAC,OAAO,CAAC,IAAY;QACzB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;CACF"}
@@ -1,7 +1,8 @@
1
- export { type Shape, type ShapeType, type BaseShape, type ShapeAnatomy, type StringFormat, nullableShape, anatomy, isNullable, } from './shape.js';
2
- export { type Role, type Relation, type EntityConstructor, toTargetThunk, uniqueMembers } from './role.js';
3
- export { type Lifecycle, type GeneratorRef, registerGenerator, resolveCustomGenerator, } from './lifecycle.js';
4
- export { type Boundary, type BoundaryRef, type Decoder, type Encoder, resolveBoundary, declaredBoundary, boundaryOf, registerDecoder, registerEncoder, registerBoundaryAlias, } from './boundary.js';
5
- export { type Meta } from './meta.js';
6
- export { type Field, type AnyField, type Fields, type FieldInit, type SchemaLike, createField, cloneField, isField, } from './field.js';
1
+ export { type Shape, SHAPE_TYPES, isShape, type ShapeType, type BaseShape, type ShapeAnatomy, nullableShape, Anatomy, } from "./shape.js";
2
+ export { Formats, type FormatPredicate, type StringFormat } from "./format.js";
3
+ export { type Role, type Relation, type EntityConstructor, toTargetThunk, uniqueMembers, } from "./role.js";
4
+ export { type Lifecycle, type GeneratorRef, registerGenerator, resolveCustomGenerator, } from "./lifecycle.js";
5
+ export { type Boundary, type BoundaryRef, type Decoder, type Encoder, resolveBoundary, declaredBoundary, boundaryOf, Boundaries, } from "./boundary.js";
6
+ export { type Meta } from "./meta.js";
7
+ export { Field, type Fields, type FieldData, } from "./field.js";
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/field/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,KAAK,EACV,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,aAAa,EACb,OAAO,EACP,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,KAAK,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC3G,OAAO,EACL,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,eAAe,EACf,qBAAqB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,SAAS,EACd,KAAK,UAAU,EACf,WAAW,EACX,UAAU,EACV,OAAO,GACR,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/field/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,KAAK,EACV,WAAW,EACX,OAAO,EACP,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,aAAa,EACb,OAAO,GACR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EACL,KAAK,IAAI,EACT,KAAK,QAAQ,EACb,KAAK,iBAAiB,EACtB,aAAa,EACb,aAAa,GACd,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,KAAK,EACL,KAAK,MAAM,EACX,KAAK,SAAS,GACf,MAAM,YAAY,CAAC"}
@@ -1,9 +1,10 @@
1
1
  // The primitive — a Field decomposed on four orthogonal axes plus the meta
2
2
  // compartment. Each axis lives in its own file; this barrel is the
3
3
  // package-internal (and index-level) view.
4
- export { nullableShape, anatomy, isNullable, } from './shape.js';
5
- export { toTargetThunk, uniqueMembers } from './role.js';
6
- export { registerGenerator, resolveCustomGenerator, } from './lifecycle.js';
7
- export { resolveBoundary, declaredBoundary, boundaryOf, registerDecoder, registerEncoder, registerBoundaryAlias, } from './boundary.js';
8
- export { createField, cloneField, isField, } from './field.js';
4
+ export { SHAPE_TYPES, isShape, nullableShape, Anatomy, } from "./shape.js";
5
+ export { Formats } from "./format.js";
6
+ export { toTargetThunk, uniqueMembers, } from "./role.js";
7
+ export { registerGenerator, resolveCustomGenerator, } from "./lifecycle.js";
8
+ export { resolveBoundary, declaredBoundary, boundaryOf, Boundaries, } from "./boundary.js";
9
+ export { Field, } from "./field.js";
9
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/field/index.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,mEAAmE;AACnE,2CAA2C;AAC3C,OAAO,EAML,aAAa,EACb,OAAO,EACP,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAoD,aAAa,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC3G,OAAO,EAGL,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAKL,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,eAAe,EACf,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAML,WAAW,EACX,UAAU,EACV,OAAO,GACR,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/field/index.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,mEAAmE;AACnE,2CAA2C;AAC3C,OAAO,EAEL,WAAW,EACX,OAAO,EAIP,aAAa,EACb,OAAO,GACR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,OAAO,EAA2C,MAAM,aAAa,CAAC;AAC/E,OAAO,EAIL,aAAa,EACb,aAAa,GACd,MAAM,WAAW,CAAC;AACnB,OAAO,EAGL,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAKL,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,UAAU,GACX,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,KAAK,GAGN,MAAM,YAAY,CAAC"}
@@ -1,38 +1,29 @@
1
1
  /**
2
- * Generator TOKEN — a built-in preset or a name registered via
3
- * {@link registerGenerator}. Never a closure: a function would silently vanish
4
- * through describe/reconstruct (JSON.stringify drops it without an error) and
5
- * the remote frond would pay. With a name, the failure is loud and local
6
- * ("unknown generator") instead of silent and at the neighbour's.
2
+ * Generator TOKEN — a preset, or a name registered via {@link registerGenerator}. Never a
3
+ * closure: a function vanishes through describe/reconstruct without an error, and the
4
+ * remote frond pays. A name fails loudly and locally instead.
7
5
  */
8
6
  export type GeneratorRef = 'cuid2' | 'uuid' | 'nanoid' | (string & {});
7
+ /** The moments a value can be written at — the runtime list, from which the types derive. */
8
+ export declare const CREATE_TOKENS: readonly ['now', 'optional'];
9
+ export declare const UPDATE_TOKENS: readonly ['now', 'forbidden'];
9
10
  export interface Lifecycle {
10
11
  /**
11
- * The CREATE rule — what happens when the input omits the value:
12
- * - key absent → required, the caller must supply it
13
- * - `{ value }` → filled with this literal (a `default`)
14
- * - `'now'` → stamped `new Date()` (a managed creation timestamp)
15
- * - `{ generate }` → the storage adapter stamps a fresh id at insert
16
- * - `'optional'` → absence permitted, nothing produced
17
- * A supplied value is always accepted (create); restricting WHAT a surface
18
- * accepts is a derivation (`pick`), never a rule here.
12
+ * What happens when the input omits the value. Absent → required. `{ value }` fills a
13
+ * literal, `'now'` stamps, `{ generate }` has the storage stamp an id, `'optional'`
14
+ * permits absence and produces nothing. A supplied value is always accepted.
19
15
  */
20
16
  create?: {
21
17
  value: unknown;
22
- } | 'now' | {
18
+ } | {
23
19
  generate: GeneratorRef;
24
- } | 'optional';
20
+ } | (typeof CREATE_TOKENS)[number];
25
21
  /**
26
- * The UPDATE rule what happens on a patch:
27
- * - key absent → the field is only written if the client supplies it
28
- * - `'now'` → stamped `new Date()` at every update even when absent
29
- * (the canonical `updatedAt`); a supplied value is accepted
30
- * - `'forbidden'` → immutable: supplying the field in a patch is a
31
- * validation error; absent, nothing happens
32
- * The validation only JUDGES these rules; realising `'now'` (stamping) is the
33
- * storage adapter's role at the point of persistence — same split as create.
22
+ * What happens on a patch. Absent written only if supplied. `'now'` stamps at every
23
+ * update (the canonical `updatedAt`). `'forbidden'` makes supplying it an error.
24
+ * The judge only JUDGES; stamping is the storage's, at the point of persistence.
34
25
  */
35
- update?: 'now' | 'forbidden';
26
+ update?: (typeof UPDATE_TOKENS)[number];
36
27
  }
37
28
  export declare function registerGenerator(name: string, fn: () => string): void;
38
29
  /** A registered custom generator, or undefined (built-in presets live storage-side). */
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/field/lifecycle.ts"],"names":[],"mappings":"AAQA;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAEvE,MAAM,WAAW,SAAS;IACxB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,KAAK,GAAG;QAAE,QAAQ,EAAE,YAAY,CAAA;KAAE,GAAG,UAAU,CAAC;IAC9E;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC;CAC9B;AAgBD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,MAAM,GAAG,IAAI,CAEtE;AAED,wFAAwF;AACxF,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,YAAY,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAEpF"}
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/field/lifecycle.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAEvE,6FAA6F;AAC7F,eAAO,MAAM,aAAa,YAAI,KAAK,EAAE,UAAU,CAAU,CAAC;AAC1D,eAAO,MAAM,aAAa,YAAI,KAAK,EAAE,WAAW,CAAU,CAAC;AAE3D,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG;QAAE,QAAQ,EAAE,YAAY,CAAA;KAAE,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;IAC1F;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;CACzC;AASD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,MAAM,GAAG,IAAI,CAEtE;AAED,wFAAwF;AACxF,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,YAAY,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAEpF"}
@@ -1,21 +1,14 @@
1
1
  // ─── Axis 3 · lifecycle — WHO WRITES THE VALUE, AT WHICH MOMENT ────
2
- // The normal form is indexed by the situation (the write moment); reading is a
3
- // key access plus a switch on a named token never an interpreter function.
4
- // The interpretation happened ONCE, at declaration (the vocabulary translates
5
- // its sugar into this form). Declarative, named onlynever an opaque closure
6
- // (a value mutation invisible to adapters is forbidden).
7
- // (Coercion converting a supplied value — is NOT here; that is the `boundary` axis.)
8
- // ─── Generator registry (open, same spirit as the boundary registries) ──
9
- // CUSTOM generators, declared once per module:
10
- // registerGenerator('monId', () => ) → primary({ generate: 'monId' })
11
- //
12
- // The BUILT-IN presets (cuid2/uuid/nanoid) used to be resolved by each storage adapter,
13
- // on the grounds that this package took no dependency. It took one already
14
- // (`@cfworker/json-schema`, for the other projection), and the arrangement put the
15
- // inversion in plain sight: a generator YOU invented reached every adapter, and the
16
- // three the framework ships did not — so a second adapter honoured `cuid2` differently
17
- // or not at all. They live with the realization now (`projections/lifecycle.ts`), which
18
- // consults this registry first.
2
+ // Indexed by the write moment; reading is a key access and a switch on a named token,
3
+ // never an interpreter. Declarative and named — never a closure, which would be a value
4
+ // mutation invisible to adapters. Coercion is the `boundary` axis, not this one.
5
+ /** The moments a value can be written atthe runtime list, from which the types derive. */
6
+ export const CREATE_TOKENS = ['now', 'optional'];
7
+ export const UPDATE_TOKENS = ['now', 'forbidden'];
8
+ // ─── Generator registry ──────────────────────────────────
9
+ // `registerGenerator('monId', fn)` `primary({ generate: 'monId' })`. The built-in
10
+ // presets live with the realization (`projections/lifecycle.ts`), which consults this
11
+ // first — resolving them per adapter is what made two adapters honour `cuid2` differently.
19
12
  const generators = new Map();
20
13
  export function registerGenerator(name, fn) {
21
14
  generators.set(name, fn);
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/field/lifecycle.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,+EAA+E;AAC/E,6EAA6E;AAC7E,8EAA8E;AAC9E,+EAA+E;AAC/E,yDAAyD;AACzD,uFAAuF;AAoCvF,2EAA2E;AAC3E,+CAA+C;AAC/C,2EAA2E;AAC3E,EAAE;AACF,wFAAwF;AACxF,2EAA2E;AAC3E,mFAAmF;AACnF,oFAAoF;AACpF,uFAAuF;AACvF,wFAAwF;AACxF,gCAAgC;AAEhC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAwB,CAAC;AAEnD,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,EAAgB;IAC9D,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,sBAAsB,CAAC,GAAiB;IACtD,OAAO,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC"}
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/field/lifecycle.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,sFAAsF;AACtF,wFAAwF;AACxF,iFAAiF;AASjF,6FAA6F;AAC7F,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,UAAU,CAAU,CAAC;AAC1D,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,WAAW,CAAU,CAAC;AAiB3D,4DAA4D;AAC5D,oFAAoF;AACpF,sFAAsF;AACtF,2FAA2F;AAE3F,MAAM,UAAU,GAAG,IAAI,GAAG,EAAwB,CAAC;AAEnD,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,EAAgB;IAC9D,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,sBAAsB,CAAC,GAAiB;IACtD,OAAO,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC"}
@@ -1,9 +1,5 @@
1
1
  export interface Meta {
2
- /**
3
- * Human-readable annotation. Read by CLI help (`cli/bridge.ts`) and carried by the
4
- * portable card — that is the whole current reach. No OpenAPI generation exists in
5
- * this repo, and `schema-graphql` never reads meta.
6
- */
2
+ /** Read by CLI help and carried by the card — that is the whole reach today. */
7
3
  description?: string;
8
4
  }
9
5
  //# sourceMappingURL=meta.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../src/field/meta.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,IAAI;IACnB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
1
+ {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../src/field/meta.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,IAAI;IACnB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
@@ -1,7 +1,5 @@
1
1
  // ─── meta — the documentary compartment (NOT an axis) ────────────
2
- // Universal, human-facing information. The contract is strict and holds: NO consumer
3
- // ever DECIDES by reading meta — the axes govern behaviour, meta informs humans.
4
- // Per-consumer specifics belong to `hints`, not here. Future candidates of the same
5
- // nature: title, example, deprecated.
2
+ // Human-facing only. NO consumer ever DECIDES by reading meta — the axes govern
3
+ // behaviour. Per-consumer specifics belong to `hints`.
6
4
  export {};
7
5
  //# sourceMappingURL=meta.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../src/field/meta.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,qFAAqF;AACrF,iFAAiF;AACjF,oFAAoF;AACpF,sCAAsC"}
1
+ {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../src/field/meta.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,gFAAgF;AAChF,uDAAuD"}
@@ -7,30 +7,26 @@ export type EntityConstructor = abstract new (...args: any[]) => any;
7
7
  * `getFields`; anything else is treated as the thunk itself.
8
8
  */
9
9
  export declare function toTargetThunk<E extends EntityConstructor>(target: E | (() => E)): () => E;
10
+ /** A relation's closed vocabularies — the runtime lists the types derive from. */
11
+ export declare const RELATION_KINDS: readonly ['one', 'many'];
12
+ export declare const ON_DELETE: readonly ['cascade', 'restrict', 'set null'];
10
13
  export interface Relation {
11
14
  to: () => EntityConstructor;
12
- kind: 'one' | 'many';
13
- onDelete?: 'cascade' | 'restrict' | 'set null';
15
+ kind: (typeof RELATION_KINDS)[number];
16
+ onDelete?: (typeof ON_DELETE)[number];
14
17
  }
15
18
  export interface Role {
16
19
  primary?: boolean;
17
20
  /**
18
- * The unique constraints this field is a member of — one member list per constraint.
21
+ * The constraints this field belongs to — one member list each. A lone `unique(slug)` is
22
+ * the degenerate case, a set of one, so there is one shape and not two.
19
23
  *
20
- * A constraint is a NAMED SET of fields, and a lone `unique(slug)` is the degenerate
21
- * case: a set of one. So there is one shape, not two `boolean` could say "unique on
22
- * its own" and nothing else, neither "unique together with docId" nor "in two
23
- * constraints at once".
24
+ * **An empty list denotes the field carrying it** it does not know its own key. A named
25
+ * group comes from the entity's own declaration, where a fact about a pair belongs.
26
+ * NEVER read a group directly: {@link uniqueMembers} is the accessor.
24
27
  *
25
- * **An empty member list denotes the field carrying it.** `unique(text())` applies to a
26
- * field that does not yet know its own key — `slug` exists only once `entity({...})`
27
- * assembles the object — so the self-reference is written as `[]` and stays that way:
28
- * nothing to resolve, nothing to remap when a view renames the key, and a reader that
29
- * never went through `entity()` still reads something true. A group with named members
30
- * comes from the entity's own declaration (`entity(fields, { unique: [[...]] })`), which
31
- * is where a fact about a pair belongs — no field holds it alone.
32
- *
33
- * So NEVER read a group directly — {@link uniqueMembers} is the accessor.
28
+ * `describe` resolves it on the way out, so a card always names its members. Keeping it
29
+ * unresolved in memory is what makes `rename()` free: nothing to remap.
34
30
  */
35
31
  unique?: ReadonlyArray<ReadonlyArray<string>>;
36
32
  index?: boolean;
@@ -41,14 +37,11 @@ export interface Role {
41
37
  * accessor every reader of `role.unique` goes through.
42
38
  *
43
39
  * ```ts
44
- * uniqueMembers([], 'slug') // ['slug'] — the self-reference
45
- * uniqueMembers(['listId', 'docId'], 'docId') // ['listId','docId'] — already named
40
+ * uniqueMembers([], 'slug') // ['slug'] — the self-reference
41
+ * uniqueMembers(['listId', 'docId'], 'docId') // ['listId','docId'] — already named
46
42
  * ```
47
43
  *
48
- * `ownKey` is the half the field is missing, and only its holder can supply it: iterate
49
- * `Object.entries(getFields())`, never the field alone. Two spellings for one constraint
50
- * is the price of a self-reference that survives `rename()` untouched; this function is
51
- * what makes them one, and it is why the two forms never need to be compared as data.
44
+ * `ownKey` is the half the field is missing: iterate `Object.entries(getFields())`.
52
45
  */
53
46
  export declare function uniqueMembers(group: ReadonlyArray<string>, ownKey: string): string[];
54
47
  //# sourceMappingURL=role.d.ts.map