@evolu/common 8.2.0 → 8.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/dist/src/Function.d.ts +1 -0
  2. package/dist/src/Function.d.ts.map +1 -1
  3. package/dist/src/Http.d.ts +9 -0
  4. package/dist/src/Http.d.ts.map +1 -1
  5. package/dist/src/Object.d.ts +1 -0
  6. package/dist/src/Object.d.ts.map +1 -1
  7. package/dist/src/RefCount.d.ts +1 -0
  8. package/dist/src/RefCount.d.ts.map +1 -1
  9. package/dist/src/Relation.d.ts +2 -0
  10. package/dist/src/Relation.d.ts.map +1 -1
  11. package/dist/src/Resource.d.ts +1 -0
  12. package/dist/src/Resource.d.ts.map +1 -1
  13. package/dist/src/Result.d.ts +383 -548
  14. package/dist/src/Result.d.ts.map +1 -1
  15. package/dist/src/Result.js +296 -46
  16. package/dist/src/StackTrace.d.ts +1 -0
  17. package/dist/src/StackTrace.d.ts.map +1 -1
  18. package/dist/src/Task.d.ts +985 -1069
  19. package/dist/src/Task.d.ts.map +1 -1
  20. package/dist/src/Task.js +1007 -156
  21. package/dist/src/Time.d.ts +1 -0
  22. package/dist/src/Time.d.ts.map +1 -1
  23. package/dist/src/Type.d.ts +1285 -734
  24. package/dist/src/Type.d.ts.map +1 -1
  25. package/dist/src/Type.js +1057 -193
  26. package/dist/src/intl/_en.d.ts +126 -0
  27. package/dist/src/intl/_en.d.ts.map +1 -0
  28. package/dist/src/intl/_en.js +267 -0
  29. package/dist/src/intl/ar.d.ts +117 -0
  30. package/dist/src/intl/ar.d.ts.map +1 -0
  31. package/dist/src/intl/ar.js +245 -0
  32. package/dist/src/intl/bn.d.ts +117 -0
  33. package/dist/src/intl/bn.d.ts.map +1 -0
  34. package/dist/src/intl/bn.js +258 -0
  35. package/dist/src/intl/ca.d.ts +117 -0
  36. package/dist/src/intl/ca.d.ts.map +1 -0
  37. package/dist/src/intl/ca.js +258 -0
  38. package/dist/src/intl/cs.d.ts +20 -7
  39. package/dist/src/intl/cs.d.ts.map +1 -1
  40. package/dist/src/intl/cs.js +54 -27
  41. package/dist/src/intl/da.d.ts +117 -0
  42. package/dist/src/intl/da.d.ts.map +1 -0
  43. package/dist/src/intl/da.js +258 -0
  44. package/dist/src/intl/de.d.ts +117 -0
  45. package/dist/src/intl/de.d.ts.map +1 -0
  46. package/dist/src/intl/de.js +258 -0
  47. package/dist/src/intl/el.d.ts +117 -0
  48. package/dist/src/intl/el.d.ts.map +1 -0
  49. package/dist/src/intl/el.js +265 -0
  50. package/dist/src/intl/es.d.ts +117 -0
  51. package/dist/src/intl/es.d.ts.map +1 -0
  52. package/dist/src/intl/es.js +258 -0
  53. package/dist/src/intl/fa.d.ts +117 -0
  54. package/dist/src/intl/fa.d.ts.map +1 -0
  55. package/dist/src/intl/fa.js +258 -0
  56. package/dist/src/intl/fi.d.ts +117 -0
  57. package/dist/src/intl/fi.d.ts.map +1 -0
  58. package/dist/src/intl/fi.js +258 -0
  59. package/dist/src/intl/fil.d.ts +117 -0
  60. package/dist/src/intl/fil.d.ts.map +1 -0
  61. package/dist/src/intl/fil.js +258 -0
  62. package/dist/src/intl/fr.d.ts +117 -0
  63. package/dist/src/intl/fr.d.ts.map +1 -0
  64. package/dist/src/intl/fr.js +258 -0
  65. package/dist/src/intl/he.d.ts +117 -0
  66. package/dist/src/intl/he.d.ts.map +1 -0
  67. package/dist/src/intl/he.js +258 -0
  68. package/dist/src/intl/hi.d.ts +117 -0
  69. package/dist/src/intl/hi.d.ts.map +1 -0
  70. package/dist/src/intl/hi.js +258 -0
  71. package/dist/src/intl/hr.d.ts +117 -0
  72. package/dist/src/intl/hr.d.ts.map +1 -0
  73. package/dist/src/intl/hr.js +265 -0
  74. package/dist/src/intl/hu.d.ts +63 -0
  75. package/dist/src/intl/hu.d.ts.map +1 -0
  76. package/dist/src/intl/hu.js +204 -0
  77. package/dist/src/intl/id.d.ts +117 -0
  78. package/dist/src/intl/id.d.ts.map +1 -0
  79. package/dist/src/intl/id.js +258 -0
  80. package/dist/src/intl/index.d.ts +42 -0
  81. package/dist/src/intl/index.d.ts.map +1 -1
  82. package/dist/src/intl/index.js +42 -0
  83. package/dist/src/intl/it.d.ts +117 -0
  84. package/dist/src/intl/it.d.ts.map +1 -0
  85. package/dist/src/intl/it.js +258 -0
  86. package/dist/src/intl/ja.d.ts +117 -0
  87. package/dist/src/intl/ja.d.ts.map +1 -0
  88. package/dist/src/intl/ja.js +258 -0
  89. package/dist/src/intl/ko.d.ts +117 -0
  90. package/dist/src/intl/ko.d.ts.map +1 -0
  91. package/dist/src/intl/ko.js +258 -0
  92. package/dist/src/intl/ml.d.ts +117 -0
  93. package/dist/src/intl/ml.d.ts.map +1 -0
  94. package/dist/src/intl/ml.js +258 -0
  95. package/dist/src/intl/mr.d.ts +117 -0
  96. package/dist/src/intl/mr.d.ts.map +1 -0
  97. package/dist/src/intl/mr.js +258 -0
  98. package/dist/src/intl/ms.d.ts +117 -0
  99. package/dist/src/intl/ms.d.ts.map +1 -0
  100. package/dist/src/intl/ms.js +245 -0
  101. package/dist/src/intl/nb.d.ts +63 -0
  102. package/dist/src/intl/nb.d.ts.map +1 -0
  103. package/dist/src/intl/nb.js +191 -0
  104. package/dist/src/intl/nl.d.ts +117 -0
  105. package/dist/src/intl/nl.d.ts.map +1 -0
  106. package/dist/src/intl/nl.js +258 -0
  107. package/dist/src/intl/pa.d.ts +117 -0
  108. package/dist/src/intl/pa.d.ts.map +1 -0
  109. package/dist/src/intl/pa.js +258 -0
  110. package/dist/src/intl/pl.d.ts +117 -0
  111. package/dist/src/intl/pl.d.ts.map +1 -0
  112. package/dist/src/intl/pl.js +242 -0
  113. package/dist/src/intl/pt-BR.d.ts +117 -0
  114. package/dist/src/intl/pt-BR.d.ts.map +1 -0
  115. package/dist/src/intl/pt-BR.js +258 -0
  116. package/dist/src/intl/pt.d.ts +117 -0
  117. package/dist/src/intl/pt.d.ts.map +1 -0
  118. package/dist/src/intl/pt.js +246 -0
  119. package/dist/src/intl/ro.d.ts +117 -0
  120. package/dist/src/intl/ro.d.ts.map +1 -0
  121. package/dist/src/intl/ro.js +258 -0
  122. package/dist/src/intl/sk.d.ts +117 -0
  123. package/dist/src/intl/sk.d.ts.map +1 -0
  124. package/dist/src/intl/sk.js +244 -0
  125. package/dist/src/intl/sl.d.ts +117 -0
  126. package/dist/src/intl/sl.d.ts.map +1 -0
  127. package/dist/src/intl/sl.js +258 -0
  128. package/dist/src/intl/sv.d.ts +117 -0
  129. package/dist/src/intl/sv.d.ts.map +1 -0
  130. package/dist/src/intl/sv.js +258 -0
  131. package/dist/src/intl/sw.d.ts +63 -0
  132. package/dist/src/intl/sw.d.ts.map +1 -0
  133. package/dist/src/intl/sw.js +191 -0
  134. package/dist/src/intl/ta.d.ts +117 -0
  135. package/dist/src/intl/ta.d.ts.map +1 -0
  136. package/dist/src/intl/ta.js +258 -0
  137. package/dist/src/intl/te.d.ts +117 -0
  138. package/dist/src/intl/te.d.ts.map +1 -0
  139. package/dist/src/intl/te.js +258 -0
  140. package/dist/src/intl/th.d.ts +117 -0
  141. package/dist/src/intl/th.d.ts.map +1 -0
  142. package/dist/src/intl/th.js +258 -0
  143. package/dist/src/intl/tr.d.ts +117 -0
  144. package/dist/src/intl/tr.d.ts.map +1 -0
  145. package/dist/src/intl/tr.js +255 -0
  146. package/dist/src/intl/uk.d.ts +117 -0
  147. package/dist/src/intl/uk.d.ts.map +1 -0
  148. package/dist/src/intl/uk.js +258 -0
  149. package/dist/src/intl/ur.d.ts +117 -0
  150. package/dist/src/intl/ur.d.ts.map +1 -0
  151. package/dist/src/intl/ur.js +245 -0
  152. package/dist/src/intl/vi.d.ts +117 -0
  153. package/dist/src/intl/vi.d.ts.map +1 -0
  154. package/dist/src/intl/vi.js +255 -0
  155. package/dist/src/intl/zh-CN.d.ts +117 -0
  156. package/dist/src/intl/zh-CN.d.ts.map +1 -0
  157. package/dist/src/intl/zh-CN.js +258 -0
  158. package/dist/src/intl/zh-TW.d.ts +117 -0
  159. package/dist/src/intl/zh-TW.d.ts.map +1 -0
  160. package/dist/src/intl/zh-TW.js +258 -0
  161. package/dist/src/local-first/Owner.d.ts +156 -62
  162. package/dist/src/local-first/Owner.d.ts.map +1 -1
  163. package/dist/src/local-first/Owner.js +119 -20
  164. package/package.json +1 -1
  165. package/src/Function.ts +2 -0
  166. package/src/Http.ts +9 -0
  167. package/src/Object.ts +2 -0
  168. package/src/RefCount.ts +2 -0
  169. package/src/Relation.ts +4 -0
  170. package/src/Resource.ts +2 -0
  171. package/src/Result.ts +397 -560
  172. package/src/StackTrace.ts +2 -0
  173. package/src/Task.ts +1143 -1222
  174. package/src/Time.ts +2 -0
  175. package/src/Type.ts +1598 -712
  176. package/src/intl/_en.ts +497 -0
  177. package/src/intl/ar.ts +417 -0
  178. package/src/intl/bn.ts +486 -0
  179. package/src/intl/ca.ts +488 -0
  180. package/src/intl/cs.ts +95 -31
  181. package/src/intl/da.ts +488 -0
  182. package/src/intl/de.ts +488 -0
  183. package/src/intl/el.ts +494 -0
  184. package/src/intl/es.ts +488 -0
  185. package/src/intl/fa.ts +487 -0
  186. package/src/intl/fi.ts +487 -0
  187. package/src/intl/fil.ts +488 -0
  188. package/src/intl/fr.ts +488 -0
  189. package/src/intl/he.ts +486 -0
  190. package/src/intl/hi.ts +487 -0
  191. package/src/intl/hr.ts +494 -0
  192. package/src/intl/hu.ts +387 -0
  193. package/src/intl/id.ts +487 -0
  194. package/src/intl/index.ts +42 -0
  195. package/src/intl/it.ts +488 -0
  196. package/src/intl/ja.ts +488 -0
  197. package/src/intl/ko.ts +487 -0
  198. package/src/intl/ml.ts +487 -0
  199. package/src/intl/mr.ts +487 -0
  200. package/src/intl/ms.ts +410 -0
  201. package/src/intl/nb.ts +364 -0
  202. package/src/intl/nl.ts +488 -0
  203. package/src/intl/pa.ts +487 -0
  204. package/src/intl/pl.ts +450 -0
  205. package/src/intl/pt-BR.ts +487 -0
  206. package/src/intl/pt.ts +424 -0
  207. package/src/intl/ro.ts +488 -0
  208. package/src/intl/sk.ts +412 -0
  209. package/src/intl/sl.ts +487 -0
  210. package/src/intl/sv.ts +488 -0
  211. package/src/intl/sw.ts +324 -0
  212. package/src/intl/ta.ts +487 -0
  213. package/src/intl/te.ts +487 -0
  214. package/src/intl/th.ts +484 -0
  215. package/src/intl/tr.ts +487 -0
  216. package/src/intl/uk.ts +488 -0
  217. package/src/intl/ur.ts +410 -0
  218. package/src/intl/vi.ts +435 -0
  219. package/src/intl/zh-CN.ts +482 -0
  220. package/src/intl/zh-TW.ts +482 -0
  221. package/src/local-first/Owner.ts +156 -62
@@ -1,8 +1,3 @@
1
- /**
2
- * Runtime types.
3
- *
4
- * @module
5
- */
6
1
  import type { StandardSchemaV1 } from "@standard-schema/spec";
7
2
  import type { AtLeastTwoReadonlyArray, NonEmptyReadonlyArray } from "./Array.ts";
8
3
  import type { Brand } from "./Brand.ts";
@@ -12,359 +7,12 @@ import { type Result } from "./Result.ts";
12
7
  import type { TimeDep } from "./Time.ts";
13
8
  import { type CompileTimeError, type IsUnion, type Literal, type Simplify, type ValueWithLength, type WidenLiteral } from "./Types.ts";
14
9
  /**
15
- * A runtime representation of a TypeScript type with typed structured errors.
16
- *
17
- * Evolu Type reports expected decoding failures through {@link Result} rather
18
- * than exceptions. It represents both an encoded `Input` and its semantic
19
- * `Output`, supporting validation, transformation, and canonical encoding.
20
- *
21
- * Evolu Type is designed for correctness and developer experience. Correctness
22
- * is especially important for local-first data: application authors cannot
23
- * inspect or repair a user's data on a server because they do not have access
24
- * to it. Type declarations must reject invalid data at system boundaries, then
25
- * preserve those guarantees wherever the data travels.
26
- *
27
- * To make correct code the easiest code to write, Evolu Type preserves as much
28
- * information as TypeScript can express. Invalid declarations produce readable
29
- * {@link CompileTimeError} types when the compiler can detect them, while
30
- * runtime assertions enforce construction contracts it cannot prove. Together,
31
- * these choices create a pit of success.
32
- *
33
- * The implementation is optimized for minimal bundle size. Less descriptive
34
- * assertion messages could make it even smaller, but Evolu keeps actionable
35
- * messages as a deliberate tradeoff for developer experience.
36
- *
37
- * The main properties of Evolu Type are:
38
- *
39
- * - **Result-based error handling** – expected failures are explicit values.
40
- * - **Typed errors with decoupled formatters** – validation logic stays
41
- * independent of user-facing messages, and errors can be handled
42
- * exhaustively.
43
- * - **Type-safe, tree-shakeable localization** – formatter requirements are
44
- * inferred from selected Types, while apps bundle exactly the locales they
45
- * support so users can change language offline.
46
- * - **Consistent constraints through {@link Brand}** – every refinement constraint
47
- * is represented in the TypeScript type, so an unconstrained parent value
48
- * cannot be used where the constrained value is required.
49
- * - **Typed inputs** – prefer `from` and its `.parent` entry points to connect
50
- * precise producer and consumer contracts while preserving typed remaining
51
- * errors; reserve `fromUnknown` for genuinely unknown values.
52
- * - **Lawful codecs** – Types partially decode `Input` to `Output` and totally
53
- * encode every legitimate `Output` to `CanonicalInput`, the statically known
54
- * subtype of `Input` returned by complete encoding.
55
- * - **A top-down implementation** – the source is intended to be read from
56
- * beginning to end.
57
- *
58
- * Evolu Type supports [Standard Schema](https://standardschema.dev/) for
59
- * interoperability with compatible tools and frameworks while preserving each
60
- * Type's exact Input and Output.
61
- *
62
- * Evolu Type assumes that all executing code, including third-party
63
- * dependencies, has been audited and is trusted. It validates data contracts
64
- * under that assumption. Trusting code does not require trusting every value it
65
- * returns, so uncertain values from legacy code or another realm can still be
66
- * decoded at an explicit boundary. It does not protect against hostile
67
- * executable behavior such as sabotaged Proxies or throwing traps; Type
68
- * validation is not a security boundary for untrusted JavaScript.
69
- *
70
- * Type declarations and their callbacks are trusted construction code. Evolu
71
- * Type leverages that trust for better developer experience and does not try to
72
- * recover from code that defeats the type system with `any` or casts, including
73
- * fabricating an `Err` for `Result<_, never>`. Runtime assertions still enforce
74
- * contracts TypeScript cannot express, and every Type declaration must be
75
- * tested for its expected successes and failures.
76
- *
77
- * `fromUnknown` validates untyped input through the complete pipeline. `from`
78
- * and its `.parent` operations use their declared boundary to determine which
79
- * remaining stages can return validation errors, but assert that boundary at
80
- * runtime. `orThrow` and `orNull` reuse the deepest `from` operation accepting
81
- * `Input`, while `to` asserts its Output boundary. A failed assertion means
82
- * application code violated its static contract; it is a developer error, not
83
- * an expected validation failure. Its message identifies the expected Type and
84
- * its cause preserves the exact structured Output validation error.
85
- *
86
- * Prefer the most precise typed boundary available. A value is not unknown
87
- * merely because it originated outside the application: forms, components, and
88
- * other producers often expose a `string` or a branded value that can connect
89
- * directly to a matching `from` boundary. Reserve `fromUnknown` for values
90
- * whose TypeScript type is genuinely `unknown`. `is` means exact membership in
91
- * the output domain, not merely that output-side parsing could succeed. A
92
- * successful `fromUnknown` result always satisfies `is`.
93
- *
94
- * Decoding accepts a representation outside the Output domain only when the
95
- * Type explicitly declares that representation, such as a transformation Input.
96
- * Structural Types do not implicitly repair another JavaScript representation.
97
- * In particular, {@link array} and {@link tuple} require dense own data elements,
98
- * while the predefined {@link Object}, {@link object}, and {@link record} require
99
- * plain objects with own enumerable data properties. They do not invoke
100
- * accessors or materialize inherited and non-enumerable properties.
101
- *
102
- * TypeScript object types are structural and do not encode JavaScript realm
103
- * identity. Structural Types therefore accept legitimate representations from
104
- * other realms. Prototype checks remain when the prototype defines the semantic
105
- * domain. Plain-object Types accept a `null` prototype or an immediate root
106
- * prototype whose own prototype is `null`; ordinary class instances and deeper
107
- * prototype chains are rejected. When Record decoding must construct a
108
- * normalized value, it uses a `null` prototype so every string key remains
109
- * ordinary data.
110
- *
111
- * Evolu Type requires TypeScript 7 or newer and expects the
112
- * `exactOptionalPropertyTypes` compiler option to be enabled.
113
- *
114
- * Predefined Types intentionally use the names of corresponding JavaScript
115
- * built-ins because they represent those familiar value categories. If an
116
- * imported Type shadows a built-in in the same scope, access the built-in
117
- * through `globalThis`, JavaScript's standard cross-environment global object,
118
- * such as `globalThis.String` or `globalThis.Date`.
119
- *
120
- * ### Example
121
- *
122
- * ```ts
123
- * import { String, type Result } from "@evolu/common";
124
- *
125
- * const value: unknown = "hello";
126
- * const result = String.fromUnknown(value);
127
- *
128
- * expectTypeOf(result).toEqualTypeOf<
129
- * Result<
130
- * string,
131
- * {
132
- * readonly type: "TypeOf";
133
- * readonly expected: "String";
134
- * readonly value: unknown;
135
- * }
136
- * >
137
- * >();
138
- * expectOk(result, "hello");
139
- * ```
140
- *
141
- * ## FAQ
142
- *
143
- * ### What does a Type represent?
144
- *
145
- * A Type is a lawful, pure codec for an exact semantic domain:
146
- *
147
- * ```text
148
- * Input ── partial decode ──▶ Output
149
- * CanonicalInput ◀─── total encode ─── Output
150
- *
151
- * CanonicalInput ⊆ Input
152
- * ```
153
- *
154
- * Read each line in the direction of its arrowhead. `Input` is the complete
155
- * typed decoding boundary, including candidates that validation can reject and
156
- * noncanonical representations that decoding can normalize. `Output` is the
157
- * validated semantic value. `CanonicalInput` is the statically known subtype of
158
- * `Input` returned by the complete `to` operation. It can be wider than the
159
- * values actually emitted when a refinement follows an arbitrary transformation
160
- * because TypeScript cannot determine which values its encoder returns for the
161
- * narrowed Output. `fromUnknown` and the `from` operations decode; `to`
162
- * encodes.
163
- *
164
- * A lawful Type round-trips every Output:
165
- *
166
- * ```text
167
- * fromUnknown(to(output)) ≈ ok(output)
168
- * ```
169
- *
170
- * Encoding can canonicalize a valid Input:
171
- *
172
- * ```text
173
- * "0042" ──decode──▶ 42 ──encode──▶ "42"
174
- * ```
175
- *
176
- * Once canonicalized, repeating the decode-encode cycle must preserve that
177
- * representation:
178
- *
179
- * ```text
180
- * "42" ──decode──▶ 42 ──encode──▶ "42"
181
- * ```
182
- *
183
- * Here `decode` means running the complete decoding pipeline, as `fromUnknown`
184
- * does, and `≈` means equality appropriate for the semantic domain. Validation
185
- * refinements, {@link ArrayType | Array Types}, and
186
- * {@link ObjectType | Object Types} preserve these laws when their contained
187
- * Types do. A {@link union} additionally requires compatible dispatch: it
188
- * encodes through the first member matching the Output and decodes through the
189
- * first member accepting the Input. Member ordering is lawful only when those
190
- * choices agree semantically. Encoded representations can overlap even when
191
- * member Output types are disjoint.
192
- *
193
- * When encoding returns a refined value unchanged, the refinement can narrow
194
- * `CanonicalInput` without changing its JavaScript representation. For example,
195
- * {@link FiniteNumber} has `number` as its Input, while its Output and
196
- * CanonicalInput are `FiniteNumber`: decoding can reject non-finite number
197
- * candidates, and encoding only receives validated finite Outputs. A
198
- * transformation can change the representation entirely. For
199
- * {@link Int64FromInt64String}, Input is `string`, Output is `Int64`, and
200
- * CanonicalInput is `Int64String`. Structural Type factories derive their
201
- * CanonicalInput recursively from their contained Types.
202
- *
203
- * ### Why is to total?
204
- *
205
- * Suppose a Type accepts only strings containing decimal digits and decodes
206
- * them to JavaScript numbers. Parsing `"42"` is possible, but the Type cannot
207
- * lawfully declare its Output as `number`:
208
- *
209
- * ```text
210
- * digits-only string ──partial decode──▶ number
211
- * digits-only string ◀─── total encode ── number // impossible
212
- * ```
213
- *
214
- * `number` also contains negative and fractional numbers, `NaN`, positive and
215
- * negative infinity, and `-0`. None of those values has a digits-only
216
- * representation, so `to` could not encode every valid Output.
10
+ * A runtime representation of a TypeScript type, including its encoded input,
11
+ * semantic output, structured errors, and canonical encoding.
217
12
  *
218
- * One lawful design narrows the Output to the exact representable domain:
13
+ * See the {@link @evolu/common!Type | Type overview}.
219
14
  *
220
- * ```text
221
- * digits-only string ──partial decode──▶ NonNegativeSafeInteger
222
- * digits-only string ◀─── total encode ── NonNegativeSafeInteger
223
- *
224
- * "0042" ──decode──▶ 42 ──encode──▶ "42"
225
- * ```
226
- *
227
- * Another lawful design keeps `number` as the Output but expands the Input
228
- * representation to include a canonical string for every number, including
229
- * `"NaN"`, `"Infinity"`, `"-Infinity"`, and `"-0"`, as well as negative and
230
- * fractional numbers.
231
- *
232
- * The same principle applies when converting between two representations. Give
233
- * each representation its own Type with the same exact Output. For example, a
234
- * string representation and a number representation can both decode to the
235
- * shared `SafeInteger` domain:
236
- *
237
- * ```text
238
- * string ──partial decode──▶ SafeInteger
239
- * string ◀─── total encode ── SafeInteger
240
- *
241
- * number ──partial decode──▶ SafeInteger
242
- * number ◀─── total encode ── SafeInteger
243
- * ```
244
- *
245
- * Conversion decodes the source representation, then total-encodes the shared
246
- * Output into the target representation. If no lossless shared domain exists,
247
- * the operation is a partial conversion, migration, or policy decision and
248
- * should be an explicit function returning Result, not a Type transformation.
249
- *
250
- * ### Why can a typed operation throw?
251
- *
252
- * TypeScript proves structural assignability, but it cannot describe every
253
- * runtime invariant. For example, it cannot express whether an object property
254
- * is own, enumerable, or a data property. It also permits a wider object with
255
- * excess properties where a narrower object type is expected.
256
- *
257
- * `fromUnknown` treats such invalid external values as expected data and
258
- * returns a typed error. Typed boundaries instead assert the domain promised by
259
- * their parameter type. If application code claims an accessor-backed object or
260
- * an object with excess properties is an Object Output, the assertion throws
261
- * because the application contract is broken. `orThrow` and `orNull` preserve
262
- * the assertion at their typed `Input` boundary, then apply {@link getOrThrow}
263
- * or {@link getOrNull} only to validation failures returned by the remaining
264
- * pipeline.
265
- *
266
- * Consequently, structural representation errors such as sparse Arrays,
267
- * accessors, and excess properties normally do not enter user-facing validation
268
- * in typed application flows. They violate the producer's declared contract and
269
- * throw as developer errors. At a genuinely unknown boundary, such as a
270
- * schema-authoring tool, import, or external protocol, the same issues are
271
- * legitimate typed validation errors and their formatter messages are useful.
272
- *
273
- * This distinction applies to data failures. Any Type operation, including
274
- * `fromUnknown`, can throw when trusted Type-declaration code, such as a
275
- * successful transformation callback, violates its declared contract.
276
- *
277
- * Materialize accessor values into plain data, remove properties the Type does
278
- * not represent, or use a different Type. Silently discarding excess data would
279
- * make the code constructing it dead while appearing to encode it successfully.
280
- * One exact Object policy also keeps Output membership independent of parsing
281
- * configuration. Exact structural policies also keep Output membership
282
- * independent of whether a transformation happens to allocate a new value.
283
- * Evolu Type therefore does not invoke accessors, discard excess properties, or
284
- * make `to` fallible. This keeps `to` total for every legitimate Output and
285
- * lets transformations compose without an encoding-error channel.
286
- *
287
- * ### How should values from another realm be handled?
288
- *
289
- * Code trust and data validation are separate decisions. Values returned by
290
- * trusted legacy code or another realm can still be uncertain and should be
291
- * validated. Realm-neutral Types accept an otherwise legitimate representation
292
- * without requiring conversion merely because its built-ins belong to another
293
- * realm.
294
- *
295
- * When an application trusts both the producer and its return contract, it can
296
- * cast the boundary API's `unknown` because validation is redundant. Use a
297
- * specialized Type or explicit transformation when the producer actually uses a
298
- * different representation that needs adaptation or normalization.
299
- *
300
- * All executing JavaScript remains trusted. Deliberately forged built-ins,
301
- * hostile Proxies, throwing traps, or sabotaged executable behavior can throw;
302
- * Evolu Type does not selectively contain them or claim to be a security
303
- * boundary for untrusted code.
304
- *
305
- * ### Why doesn't Evolu Type extract data from rich objects?
306
- *
307
- * Some validation libraries parse an object's data projection. An imaginary
308
- * validation library can enumerate own enumerable string properties and decode
309
- * them into a fresh plain object. That lets a class instance decode as plain
310
- * data while its prototype and methods are ignored. The same general policy can
311
- * treat a `Date` or `Map` as an empty Record and can invoke enumerable getters.
312
- * This is a coherent but intentionally forgiving normalization model.
313
- *
314
- * Evolu Type validates exactly the runtime representation defined by each Type;
315
- * it does not implicitly project one representation into another. The
316
- * predefined {@link Object} defines an open plain-object representation with
317
- * unknown values, {@link object} defines a closed plain-object representation,
318
- * and {@link record} defines a plain-dictionary representation whose complete
319
- * set of own properties are its entries. Their realm-neutral plain-object rule
320
- * accepts a `null` prototype or an immediate root prototype whose own prototype
321
- * is `null`; ordinary class instances and deeper prototype chains are rejected.
322
- * Every property must be an enumerable data property; inherited members are not
323
- * entries, while accessors and hidden properties are invalid instead of being
324
- * invoked or ignored. {@link array} similarly defines a dense sequence whose
325
- * only own properties are `length` and its indexed data properties;
326
- * {@link tuple} applies the same representation rules with a fixed length and a
327
- * distinct Type for each position. Only an explicit {@link transform} changes
328
- * the representation. Consequently, `is` tests exact Output membership and `to`
329
- * stays total for valid Outputs.
330
- *
331
- * ### Why is JsonValue stricter than JSON.stringify?
332
- *
333
- * `JSON.stringify` is a forgiving data projection. It can invoke `toJSON` and
334
- * accessors, discard object properties, replace unsupported array elements and
335
- * non-finite numbers with `null`, and normalize `-0` to `0`. Those rules are
336
- * useful for ordinary serialization, but they do not preserve an exact value.
337
- *
338
- * {@link JsonValue} instead defines data that is already represented as data.
339
- * Invalid runtime behavior and values are rejected rather than interpreted or
340
- * silently discarded. Its encoder is total and stack-safe for every valid
341
- * Output, and {@link JsonValueFromJson} preserves the semantic value when it is
342
- * encoded and decoded, including JavaScript's distinction between `-0` and `0`.
343
- * Use an explicit transformation before this boundary when a projection or
344
- * other normalization is desired.
345
- *
346
- * ### Why are Types pure and synchronous?
347
- *
348
- * A Type describes data meaning, not work. Time, I/O, dependencies, external
349
- * state, authorization, and other contextual decisions belong in a {@link Task}.
350
- * Use a Type to decode the data required by that work, then pass the decoded
351
- * value to a Task. A pure synchronous conversion that can fail can be an
352
- * ordinary function returning Result.
353
- *
354
- * Keeping those responsibilities separate prevents an Evolu Type from becoming
355
- * a hidden application workflow. It also keeps validation deterministic,
356
- * dependency-free, immediately composable, and straightforward to test.
357
- *
358
- * ### What if only decoding is needed?
359
- *
360
- * Use `fromUnknown` for unknown data. For typed application data, call `from`
361
- * at the boundary its input type proves, or use `orThrow` or `orNull` for a
362
- * flat conversion from `Input`. The canonical `to` encoder still keeps the Type
363
- * lawful and composable with transformations and structural Types. A genuinely
364
- * irreversible operation is a separate function or Task, not a Type
365
- * transformation.
366
- *
367
- * @group Core Types
15
+ * @group Core
368
16
  */
369
17
  export interface Type<Name extends TypeName, in out Input, in out Output, Error extends TypeError, in out Parent extends TypeNode | null = null, in out Errors extends TypeError = Error | ([Parent] extends [infer P extends TypeNode] ? InferErrors<P> : never), in out CustomFrom extends CustomFromOperation = never, in out CanonicalInput extends Input = Input, in out IdentityEncoding extends boolean = true> extends TypeNode {
370
18
  /** The name identifying this Type node. */
@@ -423,7 +71,20 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
423
71
  readonly [identityEncodingSymbol]: IdentityEncoding;
424
72
  /** The one preceding Type node, or `null` for a root Type. */
425
73
  readonly parent: Parent;
426
- /** Decodes an unknown value through the complete Type pipeline. */
74
+ /**
75
+ * Decodes an unknown value through the complete Type pipeline.
76
+ *
77
+ * ### Example
78
+ *
79
+ * ```ts
80
+ * import { PositiveInt } from "@evolu/common";
81
+ *
82
+ * const value: unknown = 42;
83
+ * const result = PositiveInt.fromUnknown(value);
84
+ *
85
+ * expectOk(result, 42);
86
+ * ```
87
+ */
427
88
  readonly fromUnknown: (value: unknown, options?: ValidationOptions) => Result<Output, Errors>;
428
89
  /**
429
90
  * Formats an error returned by `fromUnknown` or `from` as one human-readable
@@ -433,6 +94,19 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
433
94
  * Structural errors retain nested errors and their locations in the typed
434
95
  * error value. This formatter does not encode paths or enumerate nested
435
96
  * errors in its message.
97
+ *
98
+ * ### Example
99
+ *
100
+ * ```ts
101
+ * import { String } from "@evolu/common";
102
+ *
103
+ * const result = String.fromUnknown(42);
104
+ *
105
+ * expectErr(result, { type: "TypeOf", expected: "String", value: 42 });
106
+ * expect(String.formatError(result.error)).toBe(
107
+ * "A value 42 is not a string.",
108
+ * );
109
+ * ```
436
110
  */
437
111
  readonly formatError: TypeErrorFormatter<Errors>;
438
112
  /**
@@ -468,6 +142,52 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
468
142
  * developer error. The Error message identifies the expected boundary Type,
469
143
  * and its cause preserves the structured validation error. Only failures
470
144
  * introduced after that boundary are returned through `Result`.
145
+ *
146
+ * ### Example
147
+ *
148
+ * A form already guarantees every constraint on a title, while a new note
149
+ * input guarantees only trimmed text. The note's parent boundary validates
150
+ * only the constraints that the form does not guarantee:
151
+ *
152
+ * ```ts
153
+ * import {
154
+ * flatMapResult,
155
+ * NonEmptyTrimmedString100,
156
+ * object,
157
+ * TrimmedString,
158
+ * type MaxLengthError,
159
+ * type MinLengthError,
160
+ * type Result,
161
+ * } from "@evolu/common";
162
+ *
163
+ * const Todo = object({
164
+ * title: NonEmptyTrimmedString100,
165
+ * note: NonEmptyTrimmedString100,
166
+ * });
167
+ *
168
+ * const saveTodo = (
169
+ * title: NonEmptyTrimmedString100,
170
+ * note: TrimmedString,
171
+ * ) => {
172
+ * // @ts-expect-error TrimmedString does not guarantee a non-empty value
173
+ * // with at most 100 characters.
174
+ * Todo.from({ title, note });
175
+ *
176
+ * return flatMapResult(
177
+ * Todo.props.note.from.parent.parent(note),
178
+ * (note) => Todo.from({ title, note }),
179
+ * );
180
+ * };
181
+ *
182
+ * const title = NonEmptyTrimmedString100.orThrow("Buy milk");
183
+ * const note = TrimmedString.orThrow("Remember oat milk");
184
+ * const result = saveTodo(title, note);
185
+ *
186
+ * expectTypeOf(result).toEqualTypeOf<
187
+ * Result<typeof Todo.Output, MaxLengthError<100> | MinLengthError<1>>
188
+ * >();
189
+ * expectOk(result, { title, note });
190
+ * ```
471
191
  */
472
192
  readonly from: [CustomFrom] extends [never] ? [Parent] extends [infer P extends TypeNode] ? FromOperation<Output, Error, P> : TypeOperationFn<"from", Output, Output, never> : CustomFrom;
473
193
  /**
@@ -477,6 +197,16 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
477
197
  * `to` runs the complete encoding pipeline. Its first `.parent` stops at the
478
198
  * immediate parent Output, and each additional suffix stops one Type closer
479
199
  * to the root. Every entry point accepts this Type's `Output`.
200
+ *
201
+ * ### Example
202
+ *
203
+ * ```ts
204
+ * import { Int64, Int64FromInt64String } from "@evolu/common";
205
+ *
206
+ * const value = Int64.orThrow(42n);
207
+ *
208
+ * expect(Int64FromInt64String.to(value)).toBe("42");
209
+ * ```
480
210
  */
481
211
  readonly to: [Parent] extends [infer P extends TypeNode] ? ToOperation<Output, CanonicalInput, P> : (value: Output) => CanonicalInput;
482
212
  /**
@@ -506,6 +236,9 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
506
236
  *
507
237
  * // Equivalent because `from.parent` is this Type's deepest `from` operation:
508
238
  * const sameValue = getOrThrow(NonEmptyString.from.parent("Evolu"));
239
+ *
240
+ * expect(value).toBe("Evolu");
241
+ * expect(sameValue).toBe(value);
509
242
  * ```
510
243
  */
511
244
  readonly orThrow: TypeOperationFn<"orThrow", Input, Output, never>;
@@ -536,11 +269,19 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
536
269
  *
537
270
  * // Equivalent because `from.parent` is this Type's deepest `from` operation:
538
271
  * const sameValue = getOrNull(NonEmptyString.from.parent("Evolu"));
272
+ *
273
+ * expect(value).toBe("Evolu");
274
+ * expect(sameValue).toBe(value);
275
+ * expect(NonEmptyString.orNull("")).toBeNull();
539
276
  * ```
540
277
  */
541
278
  readonly orNull: TypeOperationFn<"orNull", Input, Output, never>;
542
279
  }
543
- /** @group Core Types */
280
+ /**
281
+ * A capitalized name identifying a {@link Type} node.
282
+ *
283
+ * @group Core
284
+ */
544
285
  export type TypeName = Capitalize<string>;
545
286
  /**
546
287
  * A plain structured error produced by a {@link Type} operation.
@@ -552,7 +293,7 @@ export type TypeName = Capitalize<string>;
552
293
  * only when it intentionally represents the same error contract. Accidental
553
294
  * reuse prevents reliable discriminated-union narrowing.
554
295
  *
555
- * @group Core Types
296
+ * @group Core
556
297
  */
557
298
  export interface TypeError<Name extends TypeName = TypeName> {
558
299
  readonly type: Name;
@@ -567,7 +308,7 @@ interface TransparentTypeError {
567
308
  * Structural errors such as Array and Union errors extend {@link TypeError}
568
309
  * instead because they locate nested errors rather than own one value.
569
310
  *
570
- * @group Core Types
311
+ * @group Core
571
312
  */
572
313
  export interface TypeValueError<Name extends TypeName = TypeName> extends TypeError<Name> {
573
314
  readonly value: unknown;
@@ -575,10 +316,15 @@ export interface TypeValueError<Name extends TypeName = TypeName> extends TypeEr
575
316
  /**
576
317
  * Formats a structured {@link TypeError} as a human-readable message.
577
318
  *
578
- * @group Core Types
319
+ * @group Core
579
320
  */
580
321
  export type TypeErrorFormatter<Error extends TypeError> = (error: Error) => string;
581
- /** @group Core Types */
322
+ /**
323
+ * The common structural shape of every {@link Type}, with its specific type
324
+ * parameters erased.
325
+ *
326
+ * @group Core
327
+ */
582
328
  export interface TypeNode {
583
329
  readonly name: TypeName;
584
330
  readonly "~standard": StandardSchemaV1.Props<unknown, unknown>;
@@ -601,7 +347,7 @@ export interface TypeNode {
601
347
  * Asserts that a value belongs to a {@link Type} Output domain.
602
348
  *
603
349
  * Use this for internal invariants, not external input. Validate external input
604
- * with `Type.fromUnknown` so expected failures remain typed values. A failed
350
+ * with `Type.fromUnknown` so validation failures remain typed values. A failed
605
351
  * assertion uses the Type name for its message and preserves the exact Output
606
352
  * validation error as the thrown Error's cause.
607
353
  *
@@ -621,38 +367,36 @@ export interface TypeNode {
621
367
  * >();
622
368
  * ```
623
369
  *
624
- * @group Core Types
370
+ * @group Core
625
371
  */
626
372
  export declare const assertType: <T extends TypeNode>(type: T, value: unknown) => asserts value is T["Output"];
627
373
  /**
628
- * Localized copies of selected {@link Type} declarations for every locale.
374
+ * Creates localized copies of selected {@link Type} declarations.
629
375
  *
630
- * Each locale supplies one formatter for every Type that can own a formatted
631
- * error. Structural Types use their own formatter for structural failures and
632
- * delegate contained failures to the Type that produced them. A Union owns its
633
- * complete failure because no member matched. Formatter requirements are
634
- * inferred recursively from structured errors, including mutually recursive
635
- * Lazy error interfaces.
376
+ * Pass the Types used together in one localization scope and formatter maps
377
+ * keyed by locale. TypeScript infers every formatter required by the selected
378
+ * Types, including errors from nested structural Types and recursive Lazy
379
+ * Types. Every locale must provide the complete inferred formatter set;
380
+ * missing and unrelated formatters are compile-time errors.
636
381
  *
637
- * Parents and Types exposed through public reflection are localized recursively
638
- * through one shared cache. Lazy definitions stay opaque and are not evaluated;
639
- * their declared error types provide the formatter requirements instead.
382
+ * The result preserves the locale names, selected Type names, and exact
383
+ * TypeScript types. A localized Type validates exactly like its source Type;
384
+ * only its human-readable `formatError` and Standard Schema messages change.
385
+ * The source Types remain unchanged.
640
386
  *
641
- * The selected Type map, locale map, and each formatter map must be plain
642
- * objects whose entries are own enumerable string-keyed data properties.
387
+ * Parents and reflected child Types are localized with the same formatter set.
388
+ * Structural Types retain error paths and delegate nested messages to the Type
389
+ * that produced them. Different localized Type sets can coexist in separate
390
+ * application or dependency-injection scopes.
643
391
  *
644
- * All localized Types for one locale share the same formatter set. The result
645
- * preserves the selected names and exact TypeScript types under every locale
646
- * key, making one localized set easy to provide through dependency injection or
647
- * application context. Canonical Types remain unchanged.
392
+ * Localization is scoped to the selected Types instead of a package-wide
393
+ * translation registry. Static imports give bundlers an explicit dependency
394
+ * graph, so unrelated Types, locales, and formatters can be removed. Bundling
395
+ * every locale an app supports also allows language changes without a network
396
+ * connection.
648
397
  *
649
- * Localization is scoped to the Types an app imports instead of a package-wide
650
- * translation registry. Ordinary static imports give bundlers an explicit
651
- * dependency graph from those Types to their formatters, so unrelated Type and
652
- * localization code can be removed. An app supplies all locales it supports in
653
- * the same self-contained bundle, allowing users to change language without a
654
- * network connection. Different localized Type sets can coexist on one page or
655
- * in separate dependency-injection scopes.
398
+ * The selected Type map, locale map, and formatter maps must be plain objects
399
+ * with own enumerable string-keyed data properties.
656
400
  *
657
401
  * ### Example
658
402
  *
@@ -662,7 +406,7 @@ export declare const assertType: <T extends TypeNode>(type: T, value: unknown) =
662
406
  *
663
407
  * const Label = minLength(1)(String);
664
408
  *
665
- * const TypesByLocale = localizeTypes(
409
+ * const typesByLocale = localizeTypes(
666
410
  * { Label },
667
411
  * {
668
412
  * cs: {
@@ -672,11 +416,66 @@ export declare const assertType: <T extends TypeNode>(type: T, value: unknown) =
672
416
  * },
673
417
  * );
674
418
  *
675
- * expectTypeOf<typeof TypesByLocale.cs.Label>().toEqualTypeOf<
419
+ * expectTypeOf<typeof typesByLocale.cs.Label>().toEqualTypeOf<
676
420
  * typeof Label
677
421
  * >();
422
+ *
423
+ * const result = typesByLocale.cs.Label.fromUnknown("");
424
+ * expectErr(result, { type: "MinLength1", min: 1, value: "" });
425
+ * expect(typesByLocale.cs.Label.formatError(result.error)).toBe(
426
+ * "Text nesmí být prázdný.",
427
+ * );
678
428
  * ```
679
429
  *
430
+ * ### Supported locales
431
+ *
432
+ * English is built in; use {@link Type} directly for its default formatters.
433
+ * The following additional locales are available:
434
+ *
435
+ * - Arabic (`ar`)
436
+ * - Bengali (`bn`)
437
+ * - Catalan (`ca`)
438
+ * - Chinese, Simplified (`zhCN`)
439
+ * - Chinese, Traditional (`zhTW`)
440
+ * - Croatian (`hr`)
441
+ * - Czech (`cs`)
442
+ * - Danish (`da`)
443
+ * - Dutch (`nl`)
444
+ * - Filipino (`fil`)
445
+ * - Finnish (`fi`)
446
+ * - French (`fr`)
447
+ * - German (`de`)
448
+ * - Greek (`el`)
449
+ * - Hebrew (`he`)
450
+ * - Hindi (`hi`)
451
+ * - Hungarian (`hu`)
452
+ * - Indonesian (`id`)
453
+ * - Italian (`it`)
454
+ * - Japanese (`ja`)
455
+ * - Korean (`ko`)
456
+ * - Malay (`ms`)
457
+ * - Malayalam (`ml`)
458
+ * - Marathi (`mr`)
459
+ * - Norwegian Bokmål (`nb`)
460
+ * - Persian (`fa`)
461
+ * - Polish (`pl`)
462
+ * - Portuguese (`pt`)
463
+ * - Portuguese, Brazilian (`ptBR`)
464
+ * - Punjabi (`pa`)
465
+ * - Romanian (`ro`)
466
+ * - Slovak (`sk`)
467
+ * - Slovenian (`sl`)
468
+ * - Spanish (`es`)
469
+ * - Swahili (`sw`)
470
+ * - Swedish (`sv`)
471
+ * - Tamil (`ta`)
472
+ * - Telugu (`te`)
473
+ * - Thai (`th`)
474
+ * - Turkish (`tr`)
475
+ * - Ukrainian (`uk`)
476
+ * - Urdu (`ur`)
477
+ * - Vietnamese (`vi`)
478
+ *
680
479
  * @group Localization
681
480
  */
682
481
  export declare const localizeTypes: LocalizeTypes;
@@ -762,15 +561,20 @@ declare const identityEncodingSymbol: unique symbol;
762
561
  * age: optional(PositiveInt),
763
562
  * });
764
563
  * interface User extends InferType<typeof User> {}
564
+ *
565
+ * const user = User.orThrow({ name: "Ada", age: 37 });
566
+ *
567
+ * expectTypeOf(user).toExtend<User>();
568
+ * expect(user.name).toBe("Ada");
765
569
  * ```
766
570
  *
767
- * @group Type utilities
571
+ * @group Core
768
572
  */
769
573
  export type InferType<T extends TypeNode> = T["Output"];
770
574
  /**
771
575
  * The union of errors a {@link Type} can return from `fromUnknown`.
772
576
  *
773
- * @group Type utilities
577
+ * @group Core
774
578
  */
775
579
  export type InferErrors<T extends TypeNode> = T[typeof errorsSymbol];
776
580
  type CanonicalInputOf<T extends TypeNode> = T extends TypeNode ? T["CanonicalInput"] : never;
@@ -842,7 +646,7 @@ type TypeOperationFn<Kind extends "from" | "orThrow" | "orNull", Input, Output,
842
646
  /**
843
647
  * Configures how container {@link Type} operations report errors.
844
648
  *
845
- * @group Core Types
649
+ * @group Core
846
650
  */
847
651
  export interface ValidationOptions {
848
652
  /** Controls whether container {@link Type} operations return one or all errors. */
@@ -914,10 +718,12 @@ type ConcreteChildTypeNameError = CompileTimeError<"Type", "Name must be one con
914
718
  * expectErr(Text.fromUnknown(42), { type: "Text", value: 42 });
915
719
  * ```
916
720
  *
917
- * @group Type construction
721
+ * @group Construction
918
722
  */
919
723
  export declare function createType<Name extends TypeName, Output, Error extends TypeError>(name: ValidateConcreteTypeName<Name>, fromUnknown: (value: unknown) => Result<Output, Error>, formatError: TypeErrorFormatter<NoInfer<Error>>): Type<Name, Output, Output, Error, null, Error, never, Output>;
724
+ /** Creates an infallible child Type that preserves its parent's Output. */
920
725
  export declare function createType<Name extends TypeName, ParentType extends ConcreteTypeNode>(name: ValidateConcreteTypeName<Name>, parent: ValidateParent<ParentType>, fromParent: (value: ParentType["Output"]) => Result<ParentType["Output"], never>): Type<Name, ParentType["Input"], ParentType["Output"], never, ParentType, InferErrors<ParentType>, ChildCustomFrom<ParentType, ParentType["Output"], never>, CanonicalInputForChild<ParentType, ParentType["Output"]>, IdentityEncodingOf<ParentType>>;
726
+ /** Creates a fallible child Type that narrows its parent's Output. */
921
727
  export declare function createType<Name extends TypeName, ParentType extends ConcreteTypeNode, Output extends ParentType["Output"], Error extends TypeError<Name>>(name: Name, parent: ValidateBrandParent<Name, ParentType>, fromParent: (value: ParentType["Output"]) => Result<Output, Error>, formatError: [Error] extends [never] ? never : TypeErrorFormatter<NoInfer<Error>>): Type<Name, ParentType["Input"], Output, Error, ParentType, Error | InferErrors<ParentType>, ChildCustomFrom<ParentType, Output, Error>, CanonicalInputForChild<ParentType, Output>, IdentityEncodingOf<ParentType>>;
922
728
  /**
923
729
  * Transform {@link Type}.
@@ -925,12 +731,19 @@ export declare function createType<Name extends TypeName, ParentType extends Con
925
731
  * `from` accepts the semantic Output. `from.parent` converts the parent Output
926
732
  * to the output Type Input, then runs the complete output Type pipeline. `to`
927
733
  * canonically encodes every output Type value before converting it back through
928
- * the parent Type. Transformation callbacks are Type construction code. Their
929
- * successful results are asserted against the declared boundary so a broken
930
- * callback fails as a developer error rather than becoming a validation error.
931
- * Like all Type-construction callbacks, they are trusted to follow their
932
- * declared TypeScript types. A `Result<_, never>` callback is therefore trusted
933
- * never to return an `Err`.
734
+ * the parent Type.
735
+ *
736
+ * The callbacks must form a lawful codec: decoding `to(output)` must reproduce
737
+ * the same semantic Output for every valid output value. Encoding may
738
+ * canonicalize multiple parent representations, but it must be total and must
739
+ * not lose distinctions present in the Output domain.
740
+ *
741
+ * Transformation callbacks are Type construction code. Their successful
742
+ * results are asserted against the declared boundary so a broken callback fails
743
+ * as a developer error rather than becoming a validation error. Like all
744
+ * Type-construction callbacks, they are trusted to follow their declared
745
+ * TypeScript types. A `Result<_, never>` callback is therefore trusted never to
746
+ * return an `Err`.
934
747
  *
935
748
  * Errors from the parent and the forward callback remain unchanged. A forward
936
749
  * callback error must use the transformation name as its type. Errors from the
@@ -943,23 +756,36 @@ export declare function createType<Name extends TypeName, ParentType extends Con
943
756
  * ### Example
944
757
  *
945
758
  * ```ts
946
- * import { Number, String, ok, transform } from "@evolu/common";
759
+ * import {
760
+ * Boolean,
761
+ * literal,
762
+ * ok,
763
+ * transform,
764
+ * union,
765
+ * } from "@evolu/common";
947
766
  *
948
- * const NumberFromString = transform("NumberFromString", String, Number, {
949
- * from: (value) => ok(globalThis.Number(value)),
950
- * to: globalThis.String,
951
- * });
767
+ * const BooleanString = union(literal("false"), literal("true"));
768
+ * const BooleanFromString = transform(
769
+ * "BooleanFromString",
770
+ * BooleanString,
771
+ * Boolean,
772
+ * {
773
+ * from: (value) => ok(value === "true"),
774
+ * to: (value) => (value ? "true" : "false"),
775
+ * },
776
+ * );
952
777
  *
953
- * expectOk(NumberFromString.from.parent("42"), 42);
954
- * assert(NumberFromString.to(42) === "42");
778
+ * expectOk(BooleanFromString.from.parent("true"), true);
779
+ * expect(BooleanFromString.to(false)).toBe("false");
955
780
  * ```
956
781
  *
957
- * @group Type construction
782
+ * @group Construction
958
783
  */
959
784
  export declare function transform<Name extends TypeName, ParentType extends ConcreteTypeNode, OutputType extends ConcreteTypeNode, ToOutput extends ParentType["Output"]>(name: ValidateChildTypeName<Name, ParentType>, parent: ValidateParent<ParentType>, output: ValidateOutput<OutputType>, operations: {
960
785
  readonly from: (value: ParentType["Output"]) => Result<OutputType["Input"], never>;
961
786
  readonly to: (value: CanonicalInputOf<OutputType>) => ToOutput;
962
787
  }): TransformType<ParentType, OutputType, Name, never, ToOutput>;
788
+ /** Creates a fallible transformed Type with its own error formatter. */
963
789
  export declare function transform<Name extends TypeName, ParentType extends ConcreteTypeNode, OutputType extends ConcreteTypeNode, ToOutput extends ParentType["Output"], FromError extends {
964
790
  readonly type: Name;
965
791
  readonly outputError?: never;
@@ -967,17 +793,26 @@ export declare function transform<Name extends TypeName, ParentType extends Conc
967
793
  readonly from: (value: ParentType["Output"]) => Result<OutputType["Input"], FromError>;
968
794
  readonly to: (value: CanonicalInputOf<OutputType>) => ToOutput;
969
795
  }, formatError: [FromError] extends [never] ? never : TypeErrorFormatter<NoInfer<FromError>>): TransformType<ParentType, OutputType, Name, FromError, ToOutput>;
970
- /** @group Type construction */
796
+ /**
797
+ * The {@link Type} returned by {@link transform}.
798
+ *
799
+ * @group Construction
800
+ */
971
801
  export interface TransformType<ParentType extends TypeNode, OutputType extends TypeNode, Name extends TypeName, FromError extends TypeError<Name>, ToOutput extends ParentType["Output"] = ParentType["Output"]> extends Type<Name, ParentType["Input"], OutputType["Output"], TransformError<Name, FromError, TypeFromError<OutputType>>, ParentType, TransformError<Name, FromError, TypeFromError<OutputType>> | InferErrors<ParentType>, ChildCustomFrom<ParentType, OutputType["Output"], TransformError<Name, FromError, TypeFromError<OutputType>>>, CanonicalInputForChild<ParentType, ToOutput>, false> {
972
802
  readonly [reflectedTypesSymbol]?: OutputType;
973
803
  readonly output: OutputType;
974
804
  }
975
- /** @group Type construction */
805
+ /**
806
+ * An error produced by {@link transform} while decoding or validating its
807
+ * output.
808
+ *
809
+ * @group Construction
810
+ */
976
811
  export type TransformError<Name extends TypeName, OwnError extends TypeError<Name>, OutputError extends TypeError> = OwnError | ([OutputError] extends [never] ? never : TransformOutputError<Name, OutputError>);
977
812
  /**
978
813
  * Wraps an error produced by the output {@link Type} of {@link transform}.
979
814
  *
980
- * @group Type construction
815
+ * @group Construction
981
816
  */
982
817
  export interface TransformOutputError<Name extends TypeName, OutputError extends TypeError> extends TypeError<Name>, TransparentTypeError {
983
818
  /** The error returned by the output Type. */
@@ -990,10 +825,23 @@ type DeepestFromError<Operation> = DeepestFromOperation<Operation> extends (...a
990
825
  type TypeFromError<T extends TypeNode> = unknown extends T[typeof customFromSymbol] ? DeepestFromError<TypeFromOperation<T>> : [T[typeof customFromSymbol]] extends [never] ? NonRootErrors<T> : DeepestFromError<T[typeof customFromSymbol]>;
991
826
  declare const templateLiteralSyntaxSymbolType: unique symbol;
992
827
  declare const templateLiteralSyntaxSymbol: typeof templateLiteralSyntaxSymbolType;
993
- /** @group Base Types */
828
+ /**
829
+ * An infallible {@link Type} accepting every value.
830
+ *
831
+ * @group Base
832
+ */
994
833
  export declare const Unknown: Type<"Unknown", unknown, unknown, never, null, never, never, unknown, true>;
995
- /** @group Base Types */
834
+ /**
835
+ * A {@link Type} rejecting every value.
836
+ *
837
+ * @group Base
838
+ */
996
839
  export declare const Never: Type<"Never", never, never, NeverError, null, NeverError, never, never, true>;
840
+ /**
841
+ * Error returned by {@link Never} for every value.
842
+ *
843
+ * @group Base
844
+ */
997
845
  export interface NeverError extends TypeError<"Never"> {
998
846
  readonly value: unknown;
999
847
  }
@@ -1005,7 +853,11 @@ interface TypeOfOutputByName {
1005
853
  readonly Symbol: symbol;
1006
854
  readonly Function: globalThis.Function;
1007
855
  }
1008
- /** @group Base Types */
856
+ /**
857
+ * Error returned when `typeof` does not match the expected JavaScript type.
858
+ *
859
+ * @group Base
860
+ */
1009
861
  export interface TypeOfError<Name extends keyof TypeOfOutputByName> extends TypeError<"TypeOf"> {
1010
862
  readonly expected: Name;
1011
863
  readonly value: unknown;
@@ -1033,6 +885,8 @@ export interface TypeOfError<Name extends keyof TypeOfOutputByName> extends Type
1033
885
  * expectTypeOf<WireValue100>().toEqualTypeOf<
1034
886
  * string & Brand<"MaxLength100">
1035
887
  * >();
888
+ * expectOk(WireValue100.fromUnknown(""), "");
889
+ * expectOk(WireValue100.fromUnknown(" value "), " value ");
1036
890
  * ```
1037
891
  *
1038
892
  * @group String
@@ -1107,21 +961,37 @@ export declare const String: Type<"String", string, string, TypeOfError<"String"
1107
961
  * @group Number
1108
962
  */
1109
963
  export declare const Number: Type<"Number", number, number, TypeOfError<"Number">, null, TypeOfError<"Number">, never, number, true>;
1110
- /** @group Base Types */
964
+ /**
965
+ * A JavaScript bigint {@link Type}.
966
+ *
967
+ * @group Base
968
+ */
1111
969
  export declare const BigInt: Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>;
1112
- /** @group Base Types */
970
+ /**
971
+ * A JavaScript boolean {@link Type}.
972
+ *
973
+ * @group Base
974
+ */
1113
975
  export declare const Boolean: Type<"Boolean", boolean, boolean, TypeOfError<"Boolean">, null, TypeOfError<"Boolean">, never, boolean, true>;
1114
- /** @group Base Types */
976
+ /**
977
+ * A JavaScript symbol {@link Type}.
978
+ *
979
+ * @group Base
980
+ */
1115
981
  export declare const Symbol: Type<"Symbol", symbol, symbol, TypeOfError<"Symbol">, null, TypeOfError<"Symbol">, never, symbol, true>;
1116
- /** @group Base Types */
982
+ /**
983
+ * A JavaScript function {@link Type}.
984
+ *
985
+ * @group Base
986
+ */
1117
987
  export declare const Function: Type<"Function", Function, Function, TypeOfError<"Function">, null, TypeOfError<"Function">, never, Function, true>;
1118
988
  /**
1119
- * An Evolu {@link Type} validating other Evolu Types.
989
+ * A {@link Type} validating Evolu Type declarations.
1120
990
  *
1121
991
  * This is useful when a Type itself crosses an unknown boundary or must be
1122
992
  * asserted with {@link assertType}.
1123
993
  *
1124
- * @group Core Types
994
+ * @group Core
1125
995
  */
1126
996
  export declare const EvoluType: Type<"EvoluType", AnyType, AnyType, EvoluTypeError, null, EvoluTypeError, never, AnyType, true>;
1127
997
  /**
@@ -1134,22 +1004,22 @@ export declare const EvoluType: Type<"EvoluType", AnyType, AnyType, EvoluTypeErr
1134
1004
  * the recursive `TypeNode` shape so composing Types does not repeatedly add its
1135
1005
  * compiler cost; {@link EvoluType} bridges that runtime evidence to this type.
1136
1006
  *
1137
- * @group Core Types
1007
+ * @group Core
1138
1008
  */
1139
1009
  export interface AnyType extends TypeNode {
1140
1010
  readonly [concreteTypeSymbol]: true;
1141
1011
  }
1142
1012
  /**
1143
- * Error returned when a value is not an Evolu {@link Type}.
1013
+ * Error returned when {@link EvoluType} rejects a value.
1144
1014
  *
1145
- * @group Core Types
1015
+ * @group Core
1146
1016
  */
1147
1017
  export interface EvoluTypeError extends TypeValueError<"EvoluType"> {
1148
1018
  }
1149
1019
  /**
1150
1020
  * Nominal evidence that a value has one object tag.
1151
1021
  *
1152
- * @group Base Types
1022
+ * @group Base
1153
1023
  */
1154
1024
  export interface ObjectTag<Name extends TypeName> {
1155
1025
  readonly [objectTagSymbol]: Name;
@@ -1157,7 +1027,7 @@ export interface ObjectTag<Name extends TypeName> {
1157
1027
  /**
1158
1028
  * The {@link Type} returned by {@link objectTag}.
1159
1029
  *
1160
- * @group Base Types
1030
+ * @group Base
1161
1031
  */
1162
1032
  export interface ObjectTagType<Name extends TypeName, OutputType extends TypeNode & {
1163
1033
  readonly Output: object;
@@ -1168,7 +1038,7 @@ export interface ObjectTagType<Name extends TypeName, OutputType extends TypeNod
1168
1038
  /**
1169
1039
  * An error returned when an object does not report the expected tag.
1170
1040
  *
1171
- * @group Base Types
1041
+ * @group Base
1172
1042
  */
1173
1043
  export interface ObjectTagError<Expected extends TypeName = TypeName> extends TypeError<"ObjectTag"> {
1174
1044
  readonly expected: Expected;
@@ -1195,9 +1065,21 @@ interface ObjectTagOutputByName {
1195
1065
  * assumption of the predefined Type. Primitive Outputs are rejected at compile
1196
1066
  * time.
1197
1067
  *
1198
- * @group Base Types
1068
+ * ### Example
1069
+ *
1070
+ * ```ts
1071
+ * import { objectTag } from "@evolu/common";
1072
+ *
1073
+ * const DateType = objectTag("Date");
1074
+ * const date = new globalThis.Date("2025-01-01T00:00:00.000Z");
1075
+ *
1076
+ * expectOk(DateType.fromUnknown(date), date);
1077
+ * ```
1078
+ *
1079
+ * @group Base
1199
1080
  */
1200
1081
  export declare function objectTag<Name extends keyof ObjectTagOutputByName>(name: ValidateConcreteTypeName<Name>): Type<Name, ObjectTagOutputByName[Name], ObjectTagOutputByName[Name], ObjectTagError<Name>, null, ObjectTagError<Name>, never, ObjectTagOutputByName[Name]>;
1082
+ /** Creates an object-tag Type by refining an existing object Type. */
1201
1083
  export declare function objectTag<Name extends TypeName, OutputType extends ConcreteTypeNode & {
1202
1084
  readonly Output: object;
1203
1085
  }>(name: ValidateConcreteTypeName<Name>, outputType: ValidateOutput<OutputType> & ([ChildTypeNameValidationError<"ObjectTag", OutputType>] extends [never] ? unknown : ChildTypeNameValidationError<"ObjectTag", OutputType>)): ObjectTagType<Name, OutputType>;
@@ -1207,7 +1089,7 @@ declare const objectTagSymbol: unique symbol;
1207
1089
  *
1208
1090
  * It trusts the reported object tag and does not verify Date internal slots.
1209
1091
  *
1210
- * @group Base Types
1092
+ * @group Base
1211
1093
  */
1212
1094
  export declare const Date: Type<"Date", Date, Date, ObjectTagError<"Date">, null, ObjectTagError<"Date">, never, Date, true>;
1213
1095
  /**
@@ -1216,7 +1098,7 @@ export declare const Date: Type<"Date", Date, Date, ObjectTagError<"Date">, null
1216
1098
  * It trusts the reported object tag and does not verify Uint8Array internal
1217
1099
  * slots.
1218
1100
  *
1219
- * @group Base Types
1101
+ * @group Base
1220
1102
  */
1221
1103
  export declare const Uint8Array: Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, ObjectTagError<"Uint8Array">, null, ObjectTagError<"Uint8Array">, never, Uint8Array<ArrayBufferLike>, true>;
1222
1104
  /**
@@ -1225,7 +1107,7 @@ export declare const Uint8Array: Type<"Uint8Array", Uint8Array<ArrayBufferLike>,
1225
1107
  * It trusts the reported object tag and does not verify ArrayBuffer internal
1226
1108
  * slots.
1227
1109
  *
1228
- * @group Base Types
1110
+ * @group Base
1229
1111
  */
1230
1112
  export declare const ArrayBuffer: Type<"ArrayBuffer", ArrayBuffer, ArrayBuffer, ObjectTagError<"ArrayBuffer">, null, ObjectTagError<"ArrayBuffer">, never, ArrayBuffer, true>;
1231
1113
  /**
@@ -1256,25 +1138,33 @@ export declare const ArrayBuffer: Type<"ArrayBuffer", ArrayBuffer, ArrayBuffer,
1256
1138
  * assert(!UserInstance.is({ name: "Ada" }));
1257
1139
  * ```
1258
1140
  *
1259
- * @group Base Types
1141
+ * @group Base
1260
1142
  */
1261
1143
  export declare const instanceOf: <Constructor extends InstanceConstructor>(constructor: ValidateInstanceConstructor<Constructor>) => InstanceOfType<Constructor>;
1262
1144
  /**
1263
1145
  * A JavaScript class constructor accepted by {@link instanceOf}.
1264
1146
  *
1265
- * @group Base Types
1147
+ * @group Base
1266
1148
  */
1267
1149
  export type InstanceConstructor<Instance extends object = object> = (abstract new (...args: ReadonlyArray<never>) => Instance) & {
1268
1150
  readonly name: string;
1269
1151
  };
1270
- /** @group Base Types */
1152
+ /**
1153
+ * The {@link Type} returned by {@link instanceOf}.
1154
+ *
1155
+ * @group Base
1156
+ */
1271
1157
  export interface InstanceOfType<Constructor extends InstanceConstructor> extends Type<"InstanceOf", InstanceOfOutput<Constructor>, InstanceOfOutput<Constructor>, InstanceOfError, null, InstanceOfError, never, InstanceOfOutput<Constructor>> {
1272
1158
  readonly constructor: Constructor;
1273
1159
  }
1274
1160
  type InstanceOfOutput<Constructor extends InstanceConstructor> = Constructor extends {
1275
1161
  readonly prototype: infer Output extends object;
1276
1162
  } ? Output : InstanceType<Constructor>;
1277
- /** @group Base Types */
1163
+ /**
1164
+ * Error returned when a value is not an instance of the expected constructor.
1165
+ *
1166
+ * @group Base
1167
+ */
1278
1168
  export interface InstanceOfError extends TypeValueError<"InstanceOf"> {
1279
1169
  readonly constructorName: string;
1280
1170
  }
@@ -1311,7 +1201,11 @@ type InstanceConstructorCompileTimeError = CompileTimeError<"Type", "Constructor
1311
1201
  * @group Unions
1312
1202
  */
1313
1203
  export declare const literal: <const Expected extends Literal>(expected: ValidateLiteral<Expected>) => LiteralType<Expected>;
1314
- /** @group Unions */
1204
+ /**
1205
+ * The {@link Type} returned by {@link literal}.
1206
+ *
1207
+ * @group Unions
1208
+ */
1315
1209
  export interface LiteralType<Expected extends Literal> extends Type<"Literal", WidenLiteral<Expected>, Expected, LiteralError<Expected>, LiteralParent<Expected>, LiteralError<Expected> | LiteralParentErrors<Expected>, never, CanonicalInputSubset<WidenLiteral<Expected>, CanonicalInputForParent<LiteralParent<Expected>, Expected>>, IdentityEncodingForParent<LiteralParent<Expected>>> {
1316
1210
  readonly [templateLiteralSyntaxSymbol]: true;
1317
1211
  readonly expected: Expected;
@@ -1320,14 +1214,26 @@ type LiteralParent<Expected extends Literal> = Expected extends string ? typeof
1320
1214
  type LiteralParentErrors<Expected extends Literal> = LiteralParent<Expected> extends infer Parent extends TypeNode ? InferErrors<Parent> : never;
1321
1215
  type ValidateLiteral<Expected extends Literal> = IsUnion<Expected> extends false ? {} extends Readonly<Record<`${Expected}`, never>> ? LiteralCompileTimeError : Expected : LiteralCompileTimeError;
1322
1216
  type LiteralCompileTimeError = CompileTimeError<"Type", "Expected must be one concrete literal value.">;
1323
- /** @group Unions */
1217
+ /**
1218
+ * Error returned when a value does not equal the expected literal.
1219
+ *
1220
+ * @group Unions
1221
+ */
1324
1222
  export interface LiteralError<Expected extends Literal = Literal> extends TypeError<"Literal"> {
1325
1223
  readonly expected: Expected;
1326
1224
  readonly value: unknown;
1327
1225
  }
1328
- /** @group Unions */
1226
+ /**
1227
+ * Literal {@link Type} accepting only `undefined`.
1228
+ *
1229
+ * @group Unions
1230
+ */
1329
1231
  export declare const Undefined: LiteralType<undefined>;
1330
- /** @group Unions */
1232
+ /**
1233
+ * Literal {@link Type} accepting only `null`.
1234
+ *
1235
+ * @group Unions
1236
+ */
1331
1237
  export declare const Null: LiteralType<null>;
1332
1238
  /**
1333
1239
  * Union {@link Type}.
@@ -1352,7 +1258,10 @@ export declare const Null: LiteralType<null>;
1352
1258
  * within each member.
1353
1259
  *
1354
1260
  * Member order matters when multiple members accept the same value: validation
1355
- * and encoding use the first matching member.
1261
+ * and encoding use the first matching member. When member Inputs overlap,
1262
+ * decoding the value emitted by the first member selected for an Output must
1263
+ * reproduce that semantic Output; otherwise the Union violates the round-trip
1264
+ * law.
1356
1265
  *
1357
1266
  * ### Example
1358
1267
  *
@@ -1389,9 +1298,11 @@ export declare function union<const Expected extends AtLeastTwoReadonlyArray<Lit
1389
1298
  }): UnionType<{
1390
1299
  readonly [Index in keyof Expected]: LiteralType<Expected[Index]>;
1391
1300
  }>;
1301
+ /** Creates a Union Type from Type members. */
1392
1302
  export declare function union<const Members extends AtLeastTwoReadonlyArray<TypeNode>>(...members: {
1393
1303
  readonly [Index in keyof Members]: ValidateUnionTypeMember<Members[Index]>;
1394
1304
  }): UnionType<Members>;
1305
+ /** Creates a Union Type from Type and literal members. */
1395
1306
  export declare function union<const Members extends AtLeastTwoReadonlyArray<TypeNode | Literal>>(...members: {
1396
1307
  readonly [Index in keyof Members]: ValidateUnionMember<Members[Index]>;
1397
1308
  }): UnionType<NormalizeUnionMembers<Members>>;
@@ -1401,18 +1312,49 @@ export declare function union<const Members extends AtLeastTwoReadonlyArray<Type
1401
1312
  * This does not make an object property optional. It changes only the values
1402
1313
  * accepted when the property is present.
1403
1314
  *
1315
+ * ### Example
1316
+ *
1317
+ * ```ts
1318
+ * import { String, undefinedOr } from "@evolu/common";
1319
+ *
1320
+ * const StringOrUndefined = undefinedOr(String);
1321
+ *
1322
+ * expectOk(StringOrUndefined.fromUnknown(undefined), undefined);
1323
+ * ```
1324
+ *
1404
1325
  * @group Unions
1405
1326
  */
1406
1327
  export declare const undefinedOr: <ValueType extends TypeNode>(type: ValidateUnionTypeMember<ValueType>) => UnionType<readonly [ValueType, typeof Undefined]>;
1407
1328
  /**
1408
1329
  * Union {@link Type} containing the supplied Type and `null`.
1409
1330
  *
1331
+ * ### Example
1332
+ *
1333
+ * ```ts
1334
+ * import { String, nullOr } from "@evolu/common";
1335
+ *
1336
+ * const NullableString = nullOr(String);
1337
+ *
1338
+ * expectOk(NullableString.fromUnknown(null), null);
1339
+ * ```
1340
+ *
1410
1341
  * @group Unions
1411
1342
  */
1412
1343
  export declare const nullOr: <ValueType extends TypeNode>(type: ValidateUnionTypeMember<ValueType>) => UnionType<readonly [ValueType, typeof Null]>;
1413
1344
  /**
1414
1345
  * Union {@link Type} containing the supplied Type, `null`, and `undefined`.
1415
1346
  *
1347
+ * ### Example
1348
+ *
1349
+ * ```ts
1350
+ * import { String, nullishOr } from "@evolu/common";
1351
+ *
1352
+ * const NullishString = nullishOr(String);
1353
+ *
1354
+ * expectOk(NullishString.fromUnknown(undefined), undefined);
1355
+ * expectOk(NullishString.fromUnknown(null), null);
1356
+ * ```
1357
+ *
1416
1358
  * @group Unions
1417
1359
  */
1418
1360
  export declare const nullishOr: <ValueType extends TypeNode>(type: ValidateUnionTypeMember<ValueType>) => UnionType<readonly [ValueType, typeof Null, typeof Undefined]>;
@@ -1424,7 +1366,11 @@ type UnionMemberConcreteTypeError = CompileTimeError<"Type", "Union member must
1424
1366
  type NormalizeUnionMembers<Members extends AtLeastTwoReadonlyArray<TypeNode | Literal>> = {
1425
1367
  readonly [Index in keyof Members]: Members[Index] extends TypeNode ? Members[Index] : Members[Index] extends Literal ? LiteralType<Members[Index]> : never;
1426
1368
  } extends infer Normalized extends AtLeastTwoReadonlyArray<TypeNode> ? Normalized : never;
1427
- /** @group Unions */
1369
+ /**
1370
+ * The {@link Type} returned by {@link union}.
1371
+ *
1372
+ * @group Unions
1373
+ */
1428
1374
  export interface UnionType<Members extends AtLeastTwoReadonlyArray<TypeNode>> extends Type<"Union", Members[number]["Input"], Members[number]["Output"], UnionTypeError<Members>, UnionInputParent<Members>, UnionTypeError<Members>, never, CanonicalInputOf<Members[number]>, AllTypesUseIdentityEncoding<Members[number]>> {
1429
1375
  readonly [templateLiteralSyntaxSymbol]: true;
1430
1376
  readonly [reflectedTypesSymbol]?: Members[number];
@@ -1442,9 +1388,17 @@ type UnionInputTypeError<Members extends AtLeastTwoReadonlyArray<TypeNode>, Root
1442
1388
  type RootUnionMembers<Members extends AtLeastTwoReadonlyArray<TypeNode>> = {
1443
1389
  readonly [Index in keyof Members]: RootType<Members[Index]>;
1444
1390
  } extends infer RootMembers extends AtLeastTwoReadonlyArray<TypeNode> ? RootMembers : never;
1445
- /** @group Unions */
1391
+ /**
1392
+ * Error returned when every member of a {@link union} rejects an input.
1393
+ *
1394
+ * @group Unions
1395
+ */
1446
1396
  export type UnionError<Error extends TypeError = TypeError, MemberError extends UnionMemberError<Error> = UnionMemberError<Error>> = [Error] extends [never] ? never : UnionErrorValue<Error, MemberError>;
1447
- /** @group Unions */
1397
+ /**
1398
+ * An error returned by one {@link union} member and its index.
1399
+ *
1400
+ * @group Unions
1401
+ */
1448
1402
  export interface UnionMemberError<Error extends TypeError, Index extends number = number> {
1449
1403
  readonly index: Index;
1450
1404
  readonly error: Error;
@@ -1472,9 +1426,7 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
1472
1426
  readonly errors: NonEmptyReadonlyArray<MemberError>;
1473
1427
  }
1474
1428
  /**
1475
- * Template literal {@link Type} for validation and parsing.
1476
- *
1477
- * Parses and creates structured strings.
1429
+ * Template literal {@link Type} that parses canonical strings into Tuples.
1478
1430
  *
1479
1431
  * Accepts the same template parts as {@link templateLiteral}: fixed string
1480
1432
  * literals and Types canonically encoded as strings. Instead of keeping Output
@@ -1490,10 +1442,10 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
1490
1442
  * reversibility and keeps capture boundaries unambiguous. Different capture
1491
1443
  * Tuples must never encode to the same string. The parser provides predictable
1492
1444
  * parsing without pathological backtracking and decodes each capture once, so
1493
- * adversarial input cannot trigger exponential parser work. Fixed-width captures
1494
- * may be adjacent, but only one variable-width capture is allowed. Declarations
1495
- * that could join UTF-16 surrogate halves across parts are rejected during
1496
- * construction.
1445
+ * adversarial input cannot trigger exponential parser work. Fixed-width
1446
+ * captures may be adjacent, but only one variable-width capture is allowed.
1447
+ * Declarations that could join UTF-16 surrogate halves across parts are
1448
+ * rejected during construction.
1497
1449
  *
1498
1450
  * Keep capture unions reasonably small to avoid excessive compiler work.
1499
1451
  *
@@ -1530,10 +1482,9 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
1530
1482
  *
1531
1483
  * // Parse an unknown string into structured data.
1532
1484
  * const result = SupportedLocale.fromUnknown("cs-CZ");
1533
- * assert(result.ok);
1485
+ * expectOk(result, ["cs", "CZ"]);
1534
1486
  * const locale = result.value;
1535
1487
  * expectTypeOf(locale).toEqualTypeOf<SupportedLocale>();
1536
- * expect(locale).toEqual(["cs", "CZ"]);
1537
1488
  * expectErr(SupportedLocale.fromUnknown("cs/CZ"), {
1538
1489
  * type: "TemplateLiteral",
1539
1490
  * value: "cs/CZ",
@@ -1592,10 +1543,9 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
1592
1543
  *
1593
1544
  * // Decode the string into structured data.
1594
1545
  * const result = ItemId.fromUnknown("item-42");
1595
- * assert(result.ok);
1546
+ * expectOk(result, [42n]);
1596
1547
  * const itemId = result.value;
1597
1548
  * expectTypeOf(itemId).toEqualTypeOf<ItemId>();
1598
- * expect(itemId).toEqual([42n]);
1599
1549
  *
1600
1550
  * // Encode the structured data into its canonical string.
1601
1551
  * const itemIdLiteral = ItemId.to(itemId);
@@ -1645,14 +1595,22 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
1645
1595
  * @group Template literals
1646
1596
  */
1647
1597
  export declare const templateLiteralParser: <const Parts extends TemplateLiteralParts>(...parts: { readonly [Index in keyof Parts]: ValidateTemplateLiteralPart<Parts[Index]>; } & TemplateLiteralValidation<Parts>) => TemplateLiteralParserType<Parts>;
1648
- /** @group Template literals */
1598
+ /**
1599
+ * The parsing {@link Type} returned by {@link templateLiteralParser}.
1600
+ *
1601
+ * @group Template literals
1602
+ */
1649
1603
  export interface TemplateLiteralParserType<Parts extends TemplateLiteralParts> extends Type<"TemplateLiteral", string, TemplateLiteralCaptureTuple<Parts>["Output"], never, TemplateLiteralType<Parts>, InferErrors<TemplateLiteralType<Parts>>, never, TemplateLiteralStringOutput<Parts>, false> {
1650
1604
  readonly [templateLiteralSyntaxSymbol]: true;
1651
1605
  readonly [reflectedTypesSymbol]?: TemplateLiteralCaptureTuple<Parts>;
1652
1606
  readonly output: TemplateLiteralCaptureTuple<Parts>;
1653
1607
  readonly parts: Parts;
1654
1608
  }
1655
- /** @group Template literals */
1609
+ /**
1610
+ * The validating string {@link Type} returned by {@link templateLiteral}.
1611
+ *
1612
+ * @group Template literals
1613
+ */
1656
1614
  export interface TemplateLiteralType<Parts extends TemplateLiteralParts> extends Type<"TemplateLiteral", string, TemplateLiteralStringOutput<Parts>, TemplateLiteralParseError<Parts>, typeof String, TypeOfError<"String"> | TemplateLiteralParseError<Parts>, never, TemplateLiteralStringOutput<Parts>, true> {
1657
1615
  readonly [templateLiteralSyntaxSymbol]: true;
1658
1616
  readonly [reflectedTypesSymbol]?: TemplateLiteralCaptureTuple<Parts>;
@@ -1665,8 +1623,8 @@ export interface TemplateLiteralType<Parts extends TemplateLiteralParts> extends
1665
1623
  * Creates a canonical string Type from fixed strings and string-encoded Types.
1666
1624
  *
1667
1625
  * Use this factory when Output should remain a string. Switch to
1668
- * {@link templateLiteralParser} when the individual Type parts should be
1669
- * decoded into a Tuple.
1626
+ * {@link templateLiteralParser} when the individual Type parts should be decoded
1627
+ * into a Tuple.
1670
1628
  *
1671
1629
  * ### Example
1672
1630
  *
@@ -1690,7 +1648,11 @@ export declare const templateLiteral: <const Parts extends TemplateLiteralParts>
1690
1648
  type TemplateLiteralParseError<Parts extends TemplateLiteralParts> = TransformError<"TemplateLiteral", TemplateLiteralIsFrameless<Parts> extends true ? never : TemplateLiteralError, TemplateLiteralCaptureTupleError<Parts>>;
1691
1649
  type TemplateLiteralCaptureTupleError<Parts extends TemplateLiteralParts> = TupleElementsError<TemplateLiteralCaptureFromStringError<TemplateLiteralCaptureTypes<Parts>[number]>>;
1692
1650
  type TemplateLiteralCaptureFromStringError<T extends TypeNode> = T extends TypeNode ? string extends RootType<T>["Output"] ? TypeFromError<T> : InferErrors<T> : never;
1693
- /** @group Template literals */
1651
+ /**
1652
+ * Error returned when a string does not match a template literal declaration.
1653
+ *
1654
+ * @group Template literals
1655
+ */
1694
1656
  export interface TemplateLiteralError extends TypeError<"TemplateLiteral"> {
1695
1657
  readonly value: string;
1696
1658
  }
@@ -1780,72 +1742,19 @@ type TemplateLiteralStringWidth<Value extends string, Width extends ReadonlyArra
1780
1742
  * });
1781
1743
  * ```
1782
1744
  *
1783
- * To reuse a Brand constraint with different parent Types, define a
1784
- * {@link BrandFactory}. Brand Factories can then be composed:
1785
- *
1786
- * ```ts
1787
- * import {
1788
- * String,
1789
- * brand,
1790
- * err,
1791
- * minLength,
1792
- * ok,
1793
- * type Brand,
1794
- * type BrandFactory,
1795
- * type TypeError,
1796
- * } from "@evolu/common";
1797
- *
1798
- * const trimmed: BrandFactory<"Trimmed", string, TrimmedError> = (
1799
- * parent,
1800
- * ) =>
1801
- * brand(
1802
- * "Trimmed",
1803
- * parent,
1804
- * (value) =>
1805
- * value === value.trim()
1806
- * ? ok()
1807
- * : err<TrimmedError>({ type: "Trimmed", value }),
1808
- * () => "Expected a string without surrounding whitespace.",
1809
- * );
1810
- *
1811
- * const TrimmedString = trimmed(String);
1812
- * type TrimmedString = typeof TrimmedString.Output;
1813
- *
1814
- * expectTypeOf<TrimmedString>().toEqualTypeOf<string & Brand<"Trimmed">>();
1815
- *
1816
- * const NonEmptyString = minLength(1)(String);
1817
- * type NonEmptyString = typeof NonEmptyString.Output;
1818
- *
1819
- * expectTypeOf<NonEmptyString>().toEqualTypeOf<
1820
- * string & Brand<"MinLength1">
1821
- * >();
1822
- *
1823
- * const NonEmptyTrimmedString = minLength(1)(TrimmedString);
1824
- * type NonEmptyTrimmedString = typeof NonEmptyTrimmedString.Output;
1825
- *
1826
- * expectTypeOf<NonEmptyTrimmedString>().toEqualTypeOf<
1827
- * string & Brand<"Trimmed"> & Brand<"MinLength1">
1828
- * >();
1829
- *
1830
- * interface TrimmedError extends TypeError<"Trimmed"> {
1831
- * readonly value: string;
1832
- * }
1833
- *
1834
- * // Validation from unknown.
1835
- * expectOk(NonEmptyTrimmedString.fromUnknown("Evolu"), "Evolu");
1836
- *
1837
- * // The typed input selects TrimmedString as the validated boundary.
1838
- * expectOk(
1839
- * NonEmptyTrimmedString.from.parent(TrimmedString.orThrow("Evolu")),
1840
- * "Evolu",
1841
- * );
1842
- * ```
1745
+ * To reuse and compose a Brand constraint with different parent Types, define a
1746
+ * {@link BrandFactory}.
1843
1747
  *
1844
- * @group Type construction
1748
+ * @group Construction
1845
1749
  */
1846
1750
  export declare function brand<Name extends TypeName, ParentType extends ConcreteTypeNode>(name: ValidateConcreteTypeName<Name>, parent: ValidateParent<ParentType>, validate?: (value: ParentType["Output"]) => Result<void, never>): BrandType<ParentType, Name, never>;
1751
+ /** Creates a validated Brand Type with its own error formatter. */
1847
1752
  export declare function brand<Name extends TypeName, ParentType extends ConcreteTypeNode, Error extends TypeError<NoInfer<Name>>>(name: Name, parent: ValidateBrandParent<Name, ParentType>, validate: (value: ParentType["Output"]) => Result<void, Error>, formatError: TypeErrorFormatter<NoInfer<Error>>): BrandType<ParentType, Name, Error>;
1848
- /** @group Type construction */
1753
+ /**
1754
+ * The {@link Type} returned by {@link brand}.
1755
+ *
1756
+ * @group Construction
1757
+ */
1849
1758
  export interface BrandType<ParentType extends TypeNode, Name extends TypeName, Error extends TypeError> extends Type<Name, ParentType["Input"], ParentType["Output"] & Brand<Name>, Error, ParentType, Error | InferErrors<ParentType>, ChildCustomFrom<ParentType, ParentType["Output"] & Brand<Name>, Error>, CanonicalInputForChild<ParentType, ParentType["Output"] & Brand<Name>>, IdentityEncodingOf<ParentType>> {
1850
1759
  }
1851
1760
  /**
@@ -1878,17 +1787,37 @@ export interface BrandType<ParentType extends TypeNode, Name extends TypeName, E
1878
1787
  */
1879
1788
  export declare const DateIso: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DateIso", DateIsoError>;
1880
1789
  export type DateIso = typeof DateIso.Output;
1881
- /** @group String */
1790
+ /**
1791
+ * Error returned when a string is not a canonical {@link DateIso}.
1792
+ *
1793
+ * @group String
1794
+ */
1882
1795
  export interface DateIsoError extends TypeError<"DateIso"> {
1883
1796
  readonly value: string;
1884
1797
  }
1885
1798
  /**
1886
1799
  * Safely transforms a {@link Date} into a canonical {@link DateIso}.
1887
1800
  *
1888
- * @group String
1889
- */
1890
- export declare const DateIsoFromDate: TransformType<Type<"Date", Date, Date, ObjectTagError<"Date">, null, ObjectTagError<"Date">, never, Date, true>, BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DateIso", DateIsoError>, "DateIsoFromDate", DateIsoFromDateError, Date>;
1891
- /** @group String */
1801
+ * ### Example
1802
+ *
1803
+ * ```ts
1804
+ * import { DateIsoFromDate } from "@evolu/common";
1805
+ *
1806
+ * const date = new globalThis.Date("2025-01-01T12:00:00.000Z");
1807
+ * const result = DateIsoFromDate.fromUnknown(date);
1808
+ *
1809
+ * expectOk(result, "2025-01-01T12:00:00.000Z");
1810
+ * expect(DateIsoFromDate.to(result.value)).toEqual(date);
1811
+ * ```
1812
+ *
1813
+ * @group String
1814
+ */
1815
+ export declare const DateIsoFromDate: TransformType<Type<"Date", Date, Date, ObjectTagError<"Date">, null, ObjectTagError<"Date">, never, Date, true>, BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DateIso", DateIsoError>, "DateIsoFromDate", DateIsoFromDateError, Date>;
1816
+ /**
1817
+ * Error returned when a {@link Date} cannot be represented as {@link DateIso}.
1818
+ *
1819
+ * @group String
1820
+ */
1892
1821
  export interface DateIsoFromDateError extends TypeError<"DateIsoFromDate"> {
1893
1822
  readonly value: globalThis.Date;
1894
1823
  }
@@ -1899,7 +1828,11 @@ export interface DateIsoFromDateError extends TypeError<"DateIsoFromDate"> {
1899
1828
  */
1900
1829
  export declare const Int64: BrandType<Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>, "Int64", Int64Error>;
1901
1830
  export type Int64 = typeof Int64.Output;
1902
- /** @group Number */
1831
+ /**
1832
+ * Error returned when a bigint is outside the signed 64-bit {@link Int64} range.
1833
+ *
1834
+ * @group Number
1835
+ */
1903
1836
  export interface Int64Error extends TypeError<"Int64"> {
1904
1837
  readonly value: bigint;
1905
1838
  }
@@ -1910,7 +1843,12 @@ export interface Int64Error extends TypeError<"Int64"> {
1910
1843
  */
1911
1844
  export declare const UInt64: BrandType<Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>, "UInt64", UInt64Error>;
1912
1845
  export type UInt64 = typeof UInt64.Output;
1913
- /** @group Number */
1846
+ /**
1847
+ * Error returned when a bigint is outside the unsigned 64-bit {@link UInt64}
1848
+ * range.
1849
+ *
1850
+ * @group Number
1851
+ */
1914
1852
  export interface UInt64Error extends TypeError<"UInt64"> {
1915
1853
  readonly value: bigint;
1916
1854
  }
@@ -1966,7 +1904,7 @@ export interface UInt64Error extends TypeError<"UInt64"> {
1966
1904
  * For numeric parameters encoded in a Brand name, use
1967
1905
  * {@link ValidateBrandFactoryNumber}.
1968
1906
  *
1969
- * @group Type construction
1907
+ * @group Construction
1970
1908
  */
1971
1909
  export type BrandFactory<Name extends TypeName, Value, Error extends TypeError<Name>> = <ParentType extends ConcreteTypeNode & {
1972
1910
  readonly Output: Value;
@@ -2031,7 +1969,7 @@ export type BrandFactory<Name extends TypeName, Value, Error extends TypeError<N
2031
1969
  * lessThan(100 - 1)(Number);
2032
1970
  * ```
2033
1971
  *
2034
- * @group Type utilities
1972
+ * @group Construction
2035
1973
  */
2036
1974
  export type ValidateBrandFactoryNumber<Value extends number> = IsUnion<Value> extends false ? {} extends Record<`${Value}`, never> ? Value & Readonly<Record<BrandFactoryNumberError, never>> : Value : Value & Readonly<Record<BrandFactoryNumberError, never>>;
2037
1975
  type BrandFactoryNumberError = CompileTimeError<"Brand Factory", "Parameter must be one concrete numeric literal instead of a widened, union, or branded number.">;
@@ -2062,7 +2000,11 @@ type BrandFactoryNumberError = CompileTimeError<"Brand Factory", "Parameter must
2062
2000
  * @group String
2063
2001
  */
2064
2002
  export declare const capitalized: BrandFactory<"Capitalized", string, CapitalizedError>;
2065
- /** @group String */
2003
+ /**
2004
+ * Error returned when {@link capitalized} rejects a string.
2005
+ *
2006
+ * @group String
2007
+ */
2066
2008
  export interface CapitalizedError extends TypeError<"Capitalized"> {
2067
2009
  readonly value: string;
2068
2010
  }
@@ -2076,10 +2018,24 @@ export type CapitalizedString = typeof CapitalizedString.Output;
2076
2018
  /**
2077
2019
  * String {@link Brand} without surrounding whitespace.
2078
2020
  *
2021
+ * ### Example
2022
+ *
2023
+ * ```ts
2024
+ * import { String, trimmed } from "@evolu/common";
2025
+ *
2026
+ * const Trimmed = trimmed(String);
2027
+ *
2028
+ * expectOk(Trimmed.fromUnknown("Evolu"), "Evolu");
2029
+ * ```
2030
+ *
2079
2031
  * @group String
2080
2032
  */
2081
2033
  export declare const trimmed: BrandFactory<"Trimmed", string, TrimmedError>;
2082
- /** @group String */
2034
+ /**
2035
+ * Error returned when {@link trimmed} rejects a string.
2036
+ *
2037
+ * @group String
2038
+ */
2083
2039
  export interface TrimmedError extends TypeError<"Trimmed"> {
2084
2040
  readonly value: string;
2085
2041
  }
@@ -2099,17 +2055,41 @@ export type TrimmedString = typeof TrimmedString.Output;
2099
2055
  /**
2100
2056
  * Trims a string and returns a {@link TrimmedString}.
2101
2057
  *
2058
+ * ### Example
2059
+ *
2060
+ * ```ts
2061
+ * import { trim } from "@evolu/common";
2062
+ *
2063
+ * expect(trim(" Evolu ")).toBe("Evolu");
2064
+ * ```
2065
+ *
2102
2066
  * @group String
2103
2067
  */
2104
2068
  export declare const trim: (value: string) => TrimmedString;
2105
2069
  /**
2106
- * Minimum-length {@link Brand} requiring a value to have at least `min` items.
2070
+ * Minimum-length {@link Brand} for values whose `length` is at least `min`.
2071
+ *
2072
+ * ### Example
2073
+ *
2074
+ * ```ts
2075
+ * import { String, array, minLength } from "@evolu/common";
2076
+ *
2077
+ * const AtLeastThreeCharacters = minLength(3)(String);
2078
+ * const AtLeastTwoItems = minLength(2)(array(String));
2079
+ *
2080
+ * expectOk(AtLeastThreeCharacters.fromUnknown("abc"), "abc");
2081
+ * expectOk(AtLeastTwoItems.fromUnknown(["a", "b"]), ["a", "b"]);
2082
+ * ```
2107
2083
  *
2108
2084
  * @group String
2109
2085
  * @group Collection
2110
2086
  */
2111
2087
  export declare const minLength: <Min extends number>(min: ValidateBrandFactoryNumber<Min>) => BrandFactory<`MinLength${Min}`, ValueWithLength, MinLengthError<Min>>;
2112
- /** @group Collection */
2088
+ /**
2089
+ * Error returned when {@link minLength} rejects a value.
2090
+ *
2091
+ * @group Collection
2092
+ */
2113
2093
  export interface MinLengthError<Min extends number = number> extends TypeError<`MinLength${Min}`> {
2114
2094
  readonly value: ValueWithLength;
2115
2095
  readonly min: Min;
@@ -2131,13 +2111,29 @@ export interface MinLengthError<Min extends number = number> extends TypeError<`
2131
2111
  export declare const NonEmptyTrimmedString: BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>;
2132
2112
  export type NonEmptyTrimmedString = typeof NonEmptyTrimmedString.Output;
2133
2113
  /**
2134
- * Maximum-length {@link Brand} requiring a value to have at most `max` items.
2114
+ * Maximum-length {@link Brand} for values whose `length` is at most `max`.
2115
+ *
2116
+ * ### Example
2117
+ *
2118
+ * ```ts
2119
+ * import { String, array, maxLength } from "@evolu/common";
2120
+ *
2121
+ * const AtMostThreeCharacters = maxLength(3)(String);
2122
+ * const AtMostTwoItems = maxLength(2)(array(String));
2123
+ *
2124
+ * expectOk(AtMostThreeCharacters.fromUnknown("abc"), "abc");
2125
+ * expectOk(AtMostTwoItems.fromUnknown(["a", "b"]), ["a", "b"]);
2126
+ * ```
2135
2127
  *
2136
2128
  * @group String
2137
2129
  * @group Collection
2138
2130
  */
2139
2131
  export declare const maxLength: <Max extends number>(max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`MaxLength${Max}`, ValueWithLength, MaxLengthError<Max>>;
2140
- /** @group Collection */
2132
+ /**
2133
+ * Error returned when {@link maxLength} rejects a value.
2134
+ *
2135
+ * @group Collection
2136
+ */
2141
2137
  export interface MaxLengthError<Max extends number = number> extends TypeError<`MaxLength${Max}`> {
2142
2138
  readonly value: ValueWithLength;
2143
2139
  readonly max: Max;
@@ -2157,13 +2153,29 @@ export type NonEmptyTrimmedString100 = typeof NonEmptyTrimmedString100.Output;
2157
2153
  export declare const NonEmptyTrimmedString1000: BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>, "MaxLength1000", MaxLengthError<1000>>;
2158
2154
  export type NonEmptyTrimmedString1000 = typeof NonEmptyTrimmedString1000.Output;
2159
2155
  /**
2160
- * Exact-length {@link Brand} requiring a value to have exactly `exact` items.
2156
+ * Exact-length {@link Brand} for values whose `length` equals `exact`.
2157
+ *
2158
+ * ### Example
2159
+ *
2160
+ * ```ts
2161
+ * import { String, array, length } from "@evolu/common";
2162
+ *
2163
+ * const ThreeCharacters = length(3)(String);
2164
+ * const TwoItems = length(2)(array(String));
2165
+ *
2166
+ * expectOk(ThreeCharacters.fromUnknown("abc"), "abc");
2167
+ * expectOk(TwoItems.fromUnknown(["a", "b"]), ["a", "b"]);
2168
+ * ```
2161
2169
  *
2162
2170
  * @group String
2163
2171
  * @group Collection
2164
2172
  */
2165
2173
  export declare const length: <Exact extends number>(exact: ValidateBrandFactoryNumber<Exact>) => BrandFactory<`Length${Exact}`, ValueWithLength, LengthError<Exact>>;
2166
- /** @group Collection */
2174
+ /**
2175
+ * Error returned when {@link length} rejects a value.
2176
+ *
2177
+ * @group Collection
2178
+ */
2167
2179
  export interface LengthError<Exact extends number = number> extends TypeError<`Length${Exact}`> {
2168
2180
  readonly value: ValueWithLength;
2169
2181
  readonly exact: Exact;
@@ -2197,7 +2209,12 @@ export interface LengthError<Exact extends number = number> extends TypeError<`L
2197
2209
  * @group String
2198
2210
  */
2199
2211
  export declare const regex: <const Name extends TypeName>(name: ValidateConcreteTypeName<Name>, pattern: RegExp) => BrandFactory<Name, string, RegexError<Name>>;
2200
- /** @group String */
2212
+ /**
2213
+ * Error returned when a string does not match the regular expression supplied
2214
+ * to {@link regex}.
2215
+ *
2216
+ * @group String
2217
+ */
2201
2218
  export interface RegexError<Name extends TypeName = TypeName> extends TypeError<Name> {
2202
2219
  readonly value: string;
2203
2220
  readonly source: string;
@@ -2224,19 +2241,45 @@ export type UrlSafeString = typeof UrlSafeString.Output;
2224
2241
  */
2225
2242
  export declare const Base64Url: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Base64Url", Base64UrlError>;
2226
2243
  export type Base64Url = typeof Base64Url.Output;
2227
- /** @group String */
2244
+ /**
2245
+ * Error returned when a string is not valid {@link Base64Url} text.
2246
+ *
2247
+ * @group String
2248
+ */
2228
2249
  export interface Base64UrlError extends TypeError<"Base64Url"> {
2229
2250
  readonly value: string;
2230
2251
  }
2231
2252
  /**
2232
2253
  * Encodes bytes as {@link Base64Url}.
2233
2254
  *
2255
+ * ### Example
2256
+ *
2257
+ * ```ts
2258
+ * import { uint8ArrayToBase64Url } from "@evolu/common";
2259
+ *
2260
+ * expect(uint8ArrayToBase64Url(new Uint8Array([0, 1, 2, 255]))).toBe(
2261
+ * "AAEC_w",
2262
+ * );
2263
+ * ```
2264
+ *
2234
2265
  * @group String
2235
2266
  */
2236
2267
  export declare const uint8ArrayToBase64Url: (bytes: Uint8Array) => Base64Url;
2237
2268
  /**
2238
2269
  * Decodes {@link Base64Url} as bytes.
2239
2270
  *
2271
+ * ### Example
2272
+ *
2273
+ * ```ts
2274
+ * import { Base64Url, base64UrlToUint8Array } from "@evolu/common";
2275
+ *
2276
+ * const value = Base64Url.orThrow("AAEC_w");
2277
+ *
2278
+ * expect(base64UrlToUint8Array(value)).toEqual(
2279
+ * new Uint8Array([0, 1, 2, 255]),
2280
+ * );
2281
+ * ```
2282
+ *
2240
2283
  * @group String
2241
2284
  */
2242
2285
  export declare const base64UrlToUint8Array: (value: Base64Url) => Uint8Array;
@@ -2247,7 +2290,11 @@ export declare const base64UrlToUint8Array: (value: Base64Url) => Uint8Array;
2247
2290
  */
2248
2291
  export declare const Name: BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "UrlSafeString", RegexError<"UrlSafeString">>, "Name", NameError>;
2249
2292
  export type Name = typeof Name.Output;
2250
- /** @group String */
2293
+ /**
2294
+ * Error returned when a string is not a valid {@link Name}.
2295
+ *
2296
+ * @group String
2297
+ */
2251
2298
  export interface NameError extends TypeError<"Name"> {
2252
2299
  readonly value: string;
2253
2300
  }
@@ -2271,7 +2318,11 @@ export type SimplePassword = typeof SimplePassword.Output;
2271
2318
  */
2272
2319
  export declare const Mnemonic: BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>, "Mnemonic", MnemonicError>;
2273
2320
  export type Mnemonic = typeof Mnemonic.Output;
2274
- /** @group String */
2321
+ /**
2322
+ * Error returned when a string is not a valid English BIP39 {@link Mnemonic}.
2323
+ *
2324
+ * @group String
2325
+ */
2275
2326
  export interface MnemonicError extends TypeError<"Mnemonic"> {
2276
2327
  readonly value: string;
2277
2328
  }
@@ -2287,7 +2338,11 @@ export interface MnemonicError extends TypeError<"Mnemonic"> {
2287
2338
  */
2288
2339
  export declare const Id: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Id", IdError>;
2289
2340
  export type Id = typeof Id.Output;
2290
- /** @group String */
2341
+ /**
2342
+ * Error returned when a string is not a valid {@link Id}.
2343
+ *
2344
+ * @group String
2345
+ */
2291
2346
  export interface IdError extends TypeError<"Id"> {
2292
2347
  readonly value: string;
2293
2348
  }
@@ -2297,6 +2352,22 @@ export interface IdError extends TypeError<"Id"> {
2297
2352
  * This is the recommended default because it does not encode creation time.
2298
2353
  * Pass a Brand name when the returned Id belongs to one domain entity.
2299
2354
  *
2355
+ * ### Example
2356
+ *
2357
+ * ```ts
2358
+ * import {
2359
+ * Id,
2360
+ * createId,
2361
+ * createRandomBytes,
2362
+ * type Brand,
2363
+ * } from "@evolu/common";
2364
+ *
2365
+ * const userId = createId<"User">({ randomBytes: createRandomBytes() });
2366
+ *
2367
+ * expect(Id.is(userId)).toBe(true);
2368
+ * expectTypeOf(userId).toEqualTypeOf<Id & Brand<"User">>();
2369
+ * ```
2370
+ *
2300
2371
  * @group String
2301
2372
  */
2302
2373
  export declare const createId: <B extends string = never>(deps: RandomBytesDep, ..._validation: IdBrandValidation<B>) => CreatedId<B>;
@@ -2331,20 +2402,64 @@ export declare const createIdFromString: <B extends string = never>(value: strin
2331
2402
  * logs, URLs, and exports. Prefer {@link createId} unless that tradeoff is
2332
2403
  * deliberate.
2333
2404
  *
2405
+ * ### Example
2406
+ *
2407
+ * ```ts
2408
+ * import {
2409
+ * createIdAsUuidv7,
2410
+ * createRandomBytes,
2411
+ * createTime,
2412
+ * idToIdBytes,
2413
+ * } from "@evolu/common";
2414
+ *
2415
+ * const value = createIdAsUuidv7({
2416
+ * randomBytes: createRandomBytes(),
2417
+ * time: createTime(),
2418
+ * });
2419
+ * const bytes = idToIdBytes(value);
2420
+ *
2421
+ * expect(bytes[6] >> 4).toBe(0x7);
2422
+ * expect(bytes[8] & 0xc0).toBe(0x80);
2423
+ * ```
2424
+ *
2334
2425
  * @group String
2335
2426
  */
2336
2427
  export declare const createIdAsUuidv7: <B extends string = never>(deps: RandomBytesDep & TimeDep, ..._validation: IdBrandValidation<B>) => CreatedId<B>;
2337
2428
  /**
2338
2429
  * Table-specific {@link Id} Type.
2339
2430
  *
2431
+ * ### Example
2432
+ *
2433
+ * ```ts
2434
+ * import {
2435
+ * createIdFromString,
2436
+ * id,
2437
+ * type Brand,
2438
+ * type Id,
2439
+ * } from "@evolu/common";
2440
+ *
2441
+ * const TodoId = id("Todo");
2442
+ * const todoId = TodoId.orThrow(createIdFromString("todo"));
2443
+ *
2444
+ * expectTypeOf(todoId).toEqualTypeOf<Id & Brand<"Todo">>();
2445
+ * ```
2446
+ *
2340
2447
  * @group String
2341
2448
  */
2342
2449
  export declare const id: <Table extends TypeName>(table: ValidateTableName<Table>) => TableId<Table>;
2343
- /** @group String */
2450
+ /**
2451
+ * The {@link Type} returned by {@link id} for one table.
2452
+ *
2453
+ * @group String
2454
+ */
2344
2455
  export interface TableId<Table extends TypeName> extends Type<"TableId", string, Id & Brand<Table>, TableIdError<Table>, typeof String, TableIdError<Table> | InferErrors<typeof String>, ChildCustomFrom<typeof String, Id & Brand<Table>, TableIdError<Table>>, CanonicalInputForChild<typeof String, Id & Brand<Table>>, IdentityEncodingOf<typeof String>> {
2345
2456
  readonly table: Table;
2346
2457
  }
2347
- /** @group String */
2458
+ /**
2459
+ * Error returned when a string is not a valid {@link Id} for the expected table.
2460
+ *
2461
+ * @group String
2462
+ */
2348
2463
  export interface TableIdError<Table extends TypeName = TypeName> extends TypeError<"TableId"> {
2349
2464
  readonly table: Table;
2350
2465
  readonly value: string;
@@ -2364,11 +2479,47 @@ type ConcreteIdBrandError = CompileTimeError<"Id", "Brand must be one concrete s
2364
2479
  */
2365
2480
  export declare const IdBytes: BrandType<BrandType<Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, ObjectTagError<"Uint8Array">, null, ObjectTagError<"Uint8Array">, never, Uint8Array<ArrayBufferLike>, true>, "Length16", LengthError<16>>, "IdBytes", never>;
2366
2481
  export type IdBytes = typeof IdBytes.Output;
2367
- /** @group String */
2482
+ /**
2483
+ * Byte length of an {@link IdBytes} value.
2484
+ *
2485
+ * @group String
2486
+ */
2368
2487
  export declare const idBytesTypeValueLength: NonNegativeInt;
2369
- /** @group String */
2488
+ /**
2489
+ * Converts an {@link Id} to {@link IdBytes}.
2490
+ *
2491
+ * ### Example
2492
+ *
2493
+ * ```ts
2494
+ * import { createIdFromString, idToIdBytes } from "@evolu/common";
2495
+ *
2496
+ * const bytes = idToIdBytes(createIdFromString("todo"));
2497
+ *
2498
+ * expect(bytes).toHaveLength(16);
2499
+ * ```
2500
+ *
2501
+ * @group String
2502
+ */
2370
2503
  export declare const idToIdBytes: (value: Id) => IdBytes;
2371
- /** @group String */
2504
+ /**
2505
+ * Converts {@link IdBytes} to an {@link Id}.
2506
+ *
2507
+ * ### Example
2508
+ *
2509
+ * ```ts
2510
+ * import {
2511
+ * createIdFromString,
2512
+ * idBytesToId,
2513
+ * idToIdBytes,
2514
+ * } from "@evolu/common";
2515
+ *
2516
+ * const value = createIdFromString("todo");
2517
+ *
2518
+ * expect(idBytesToId(idToIdBytes(value))).toBe(value);
2519
+ * ```
2520
+ *
2521
+ * @group String
2522
+ */
2372
2523
  export declare const idBytesToId: (value: IdBytes) => Id;
2373
2524
  /**
2374
2525
  * Decimal string representation of a signed {@link Int64}.
@@ -2377,7 +2528,11 @@ export declare const idBytesToId: (value: IdBytes) => Id;
2377
2528
  */
2378
2529
  export declare const Int64String: BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>, "Int64String", Int64StringError>;
2379
2530
  export type Int64String = typeof Int64String.Output;
2380
- /** @group Number */
2531
+ /**
2532
+ * Error returned when a string is not a canonical {@link Int64String}.
2533
+ *
2534
+ * @group Number
2535
+ */
2381
2536
  export interface Int64StringError extends TypeError<"Int64String"> {
2382
2537
  readonly value: string;
2383
2538
  }
@@ -2388,16 +2543,41 @@ export interface Int64StringError extends TypeError<"Int64String"> {
2388
2543
  * text, including SQLite queries that cast INTEGER values to TEXT to avoid a
2389
2544
  * lossy JavaScript number conversion.
2390
2545
  *
2546
+ * ### Example
2547
+ *
2548
+ * ```ts
2549
+ * import { Int64FromInt64String } from "@evolu/common";
2550
+ *
2551
+ * const result = Int64FromInt64String.fromUnknown("9223372036854775807");
2552
+ *
2553
+ * expectOk(result, 9223372036854775807n);
2554
+ * expect(Int64FromInt64String.to(result.value)).toBe("9223372036854775807");
2555
+ * ```
2556
+ *
2391
2557
  * @group Number
2392
2558
  */
2393
2559
  export declare const Int64FromInt64String: TransformType<BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>, "Int64String", Int64StringError>, BrandType<Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>, "Int64", Int64Error>, "Int64FromInt64String", never, string & Brand<"Trimmed"> & Brand<"MinLength1"> & Brand<"Int64String">>;
2394
2560
  /**
2395
2561
  * Number {@link Brand} requiring a value greater than or equal to zero.
2396
2562
  *
2563
+ * ### Example
2564
+ *
2565
+ * ```ts
2566
+ * import { Number, nonNegative } from "@evolu/common";
2567
+ *
2568
+ * const NonNegative = nonNegative(Number);
2569
+ *
2570
+ * expectOk(NonNegative.fromUnknown(0), 0);
2571
+ * ```
2572
+ *
2397
2573
  * @group Number
2398
2574
  */
2399
2575
  export declare const nonNegative: BrandFactory<"NonNegative", number, NonNegativeError>;
2400
- /** @group Number */
2576
+ /**
2577
+ * Error returned when {@link nonNegative} rejects a number.
2578
+ *
2579
+ * @group Number
2580
+ */
2401
2581
  export interface NonNegativeError extends TypeError<"NonNegative"> {
2402
2582
  readonly value: number;
2403
2583
  }
@@ -2411,10 +2591,24 @@ export type NonNegativeNumber = typeof NonNegativeNumber.Output;
2411
2591
  /**
2412
2592
  * Number {@link Brand} requiring a value greater than zero.
2413
2593
  *
2594
+ * ### Example
2595
+ *
2596
+ * ```ts
2597
+ * import { Number, positive } from "@evolu/common";
2598
+ *
2599
+ * const Positive = positive(Number);
2600
+ *
2601
+ * expectOk(Positive.fromUnknown(1), 1);
2602
+ * ```
2603
+ *
2414
2604
  * @group Number
2415
2605
  */
2416
2606
  export declare const positive: BrandFactory<"Positive", number, PositiveError>;
2417
- /** @group Number */
2607
+ /**
2608
+ * Error returned when {@link positive} rejects a number.
2609
+ *
2610
+ * @group Number
2611
+ */
2418
2612
  export interface PositiveError extends TypeError<"Positive"> {
2419
2613
  readonly value: number;
2420
2614
  }
@@ -2431,10 +2625,24 @@ export type PositiveNumber = typeof PositiveNumber.Output;
2431
2625
  /**
2432
2626
  * Number {@link Brand} requiring a value less than or equal to zero.
2433
2627
  *
2628
+ * ### Example
2629
+ *
2630
+ * ```ts
2631
+ * import { Number, nonPositive } from "@evolu/common";
2632
+ *
2633
+ * const NonPositive = nonPositive(Number);
2634
+ *
2635
+ * expectOk(NonPositive.fromUnknown(0), 0);
2636
+ * ```
2637
+ *
2434
2638
  * @group Number
2435
2639
  */
2436
2640
  export declare const nonPositive: BrandFactory<"NonPositive", number, NonPositiveError>;
2437
- /** @group Number */
2641
+ /**
2642
+ * Error returned when {@link nonPositive} rejects a number.
2643
+ *
2644
+ * @group Number
2645
+ */
2438
2646
  export interface NonPositiveError extends TypeError<"NonPositive"> {
2439
2647
  readonly value: number;
2440
2648
  }
@@ -2448,10 +2656,24 @@ export type NonPositiveNumber = typeof NonPositiveNumber.Output;
2448
2656
  /**
2449
2657
  * Number {@link Brand} requiring a value less than zero.
2450
2658
  *
2659
+ * ### Example
2660
+ *
2661
+ * ```ts
2662
+ * import { Number, negative } from "@evolu/common";
2663
+ *
2664
+ * const Negative = negative(Number);
2665
+ *
2666
+ * expectOk(Negative.fromUnknown(-1), -1);
2667
+ * ```
2668
+ *
2451
2669
  * @group Number
2452
2670
  */
2453
2671
  export declare const negative: BrandFactory<"Negative", number, NegativeError>;
2454
- /** @group Number */
2672
+ /**
2673
+ * Error returned when {@link negative} rejects a number.
2674
+ *
2675
+ * @group Number
2676
+ */
2455
2677
  export interface NegativeError extends TypeError<"Negative"> {
2456
2678
  readonly value: number;
2457
2679
  }
@@ -2468,10 +2690,24 @@ export type NegativeNumber = typeof NegativeNumber.Output;
2468
2690
  /**
2469
2691
  * Number {@link Brand} requiring a value other than `NaN`.
2470
2692
  *
2693
+ * ### Example
2694
+ *
2695
+ * ```ts
2696
+ * import { Number, nonNaN } from "@evolu/common";
2697
+ *
2698
+ * const NonNaN = nonNaN(Number);
2699
+ *
2700
+ * expectOk(NonNaN.fromUnknown(Infinity), Infinity);
2701
+ * ```
2702
+ *
2471
2703
  * @group Number
2472
2704
  */
2473
2705
  export declare const nonNaN: BrandFactory<"NonNaN", number, NonNaNError>;
2474
- /** @group Number */
2706
+ /**
2707
+ * Error returned when {@link nonNaN} rejects `NaN`.
2708
+ *
2709
+ * @group Number
2710
+ */
2475
2711
  export interface NonNaNError extends TypeError<"NonNaN"> {
2476
2712
  readonly value: number;
2477
2713
  }
@@ -2490,10 +2726,24 @@ export type NonNaNNumber = typeof NonNaNNumber.Output;
2490
2726
  /**
2491
2727
  * Number {@link Brand} requiring a finite value.
2492
2728
  *
2729
+ * ### Example
2730
+ *
2731
+ * ```ts
2732
+ * import { Number, finite } from "@evolu/common";
2733
+ *
2734
+ * const Finite = finite(Number);
2735
+ *
2736
+ * expectOk(Finite.fromUnknown(42), 42);
2737
+ * ```
2738
+ *
2493
2739
  * @group Number
2494
2740
  */
2495
2741
  export declare const finite: BrandFactory<"Finite", number, FiniteError>;
2496
- /** @group Number */
2742
+ /**
2743
+ * Error returned when {@link finite} rejects a non-finite number.
2744
+ *
2745
+ * @group Number
2746
+ */
2497
2747
  export interface FiniteError extends TypeError<"Finite"> {
2498
2748
  readonly value: number;
2499
2749
  }
@@ -2541,7 +2791,11 @@ export type PositiveFiniteNumber = typeof PositiveFiniteNumber.Output;
2541
2791
  * @group Number
2542
2792
  */
2543
2793
  export declare const int: BrandFactory<"Int", number, IntError>;
2544
- /** @group Number */
2794
+ /**
2795
+ * Error returned when {@link int} rejects a number that is not a safe integer.
2796
+ *
2797
+ * @group Number
2798
+ */
2545
2799
  export interface IntError extends TypeError<"Int"> {
2546
2800
  readonly value: number;
2547
2801
  }
@@ -2607,10 +2861,24 @@ export type NegativeInt = typeof NegativeInt.Output;
2607
2861
  /**
2608
2862
  * Number {@link Brand} requiring a value greater than `min`.
2609
2863
  *
2864
+ * ### Example
2865
+ *
2866
+ * ```ts
2867
+ * import { Number, greaterThan } from "@evolu/common";
2868
+ *
2869
+ * const GreaterThanTen = greaterThan(10)(Number);
2870
+ *
2871
+ * expectOk(GreaterThanTen.fromUnknown(11), 11);
2872
+ * ```
2873
+ *
2610
2874
  * @group Number
2611
2875
  */
2612
2876
  export declare const greaterThan: <Min extends number>(min: ValidateBrandFactoryNumber<Min>) => BrandFactory<`GreaterThan${Min}`, number, GreaterThanError<Min>>;
2613
- /** @group Number */
2877
+ /**
2878
+ * Error returned when {@link greaterThan} rejects a number.
2879
+ *
2880
+ * @group Number
2881
+ */
2614
2882
  export interface GreaterThanError<Min extends number = number> extends TypeError<`GreaterThan${Min}`> {
2615
2883
  readonly value: number;
2616
2884
  readonly min: Min;
@@ -2618,10 +2886,24 @@ export interface GreaterThanError<Min extends number = number> extends TypeError
2618
2886
  /**
2619
2887
  * Number {@link Brand} requiring a value greater than or equal to `min`.
2620
2888
  *
2889
+ * ### Example
2890
+ *
2891
+ * ```ts
2892
+ * import { Number, greaterThanOrEqualTo } from "@evolu/common";
2893
+ *
2894
+ * const AtLeastTen = greaterThanOrEqualTo(10)(Number);
2895
+ *
2896
+ * expectOk(AtLeastTen.fromUnknown(10), 10);
2897
+ * ```
2898
+ *
2621
2899
  * @group Number
2622
2900
  */
2623
2901
  export declare const greaterThanOrEqualTo: <Min extends number>(min: ValidateBrandFactoryNumber<Min>) => BrandFactory<`GreaterThanOrEqualTo${Min}`, number, GreaterThanOrEqualToError<Min>>;
2624
- /** @group Number */
2902
+ /**
2903
+ * Error returned when {@link greaterThanOrEqualTo} rejects a number.
2904
+ *
2905
+ * @group Number
2906
+ */
2625
2907
  export interface GreaterThanOrEqualToError<Min extends number = number> extends TypeError<`GreaterThanOrEqualTo${Min}`> {
2626
2908
  readonly value: number;
2627
2909
  readonly min: Min;
@@ -2629,10 +2911,24 @@ export interface GreaterThanOrEqualToError<Min extends number = number> extends
2629
2911
  /**
2630
2912
  * Number {@link Brand} requiring a value less than `max`.
2631
2913
  *
2914
+ * ### Example
2915
+ *
2916
+ * ```ts
2917
+ * import { Number, lessThan } from "@evolu/common";
2918
+ *
2919
+ * const LessThanTen = lessThan(10)(Number);
2920
+ *
2921
+ * expectOk(LessThanTen.fromUnknown(9), 9);
2922
+ * ```
2923
+ *
2632
2924
  * @group Number
2633
2925
  */
2634
2926
  export declare const lessThan: <Max extends number>(max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`LessThan${Max}`, number, LessThanError<Max>>;
2635
- /** @group Number */
2927
+ /**
2928
+ * Error returned when {@link lessThan} rejects a number.
2929
+ *
2930
+ * @group Number
2931
+ */
2636
2932
  export interface LessThanError<Max extends number = number> extends TypeError<`LessThan${Max}`> {
2637
2933
  readonly value: number;
2638
2934
  readonly max: Max;
@@ -2647,10 +2943,24 @@ export type Age = typeof Age.Output;
2647
2943
  /**
2648
2944
  * Number {@link Brand} requiring a value less than or equal to `max`.
2649
2945
  *
2946
+ * ### Example
2947
+ *
2948
+ * ```ts
2949
+ * import { Number, lessThanOrEqualTo } from "@evolu/common";
2950
+ *
2951
+ * const AtMostTen = lessThanOrEqualTo(10)(Number);
2952
+ *
2953
+ * expectOk(AtMostTen.fromUnknown(10), 10);
2954
+ * ```
2955
+ *
2650
2956
  * @group Number
2651
2957
  */
2652
2958
  export declare const lessThanOrEqualTo: <Max extends number>(max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`LessThanOrEqualTo${Max}`, number, LessThanOrEqualToError<Max>>;
2653
- /** @group Number */
2959
+ /**
2960
+ * Error returned when {@link lessThanOrEqualTo} rejects a number.
2961
+ *
2962
+ * @group Number
2963
+ */
2654
2964
  export interface LessThanOrEqualToError<Max extends number = number> extends TypeError<`LessThanOrEqualTo${Max}`> {
2655
2965
  readonly value: number;
2656
2966
  readonly max: Max;
@@ -2707,17 +3017,35 @@ export type Ratio = typeof Ratio.Output;
2707
3017
  */
2708
3018
  export declare const DecimalString: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DecimalString", DecimalStringError>;
2709
3019
  export type DecimalString = typeof DecimalString.Output;
2710
- /** @group Number */
3020
+ /**
3021
+ * Error returned when a string is not a canonical {@link DecimalString}.
3022
+ *
3023
+ * @group Number
3024
+ */
2711
3025
  export interface DecimalStringError extends TypeError<"DecimalString"> {
2712
3026
  readonly value: string;
2713
3027
  }
2714
3028
  /**
2715
3029
  * {@link DecimalString} Brand requiring a value greater than or equal to zero.
2716
3030
  *
3031
+ * ### Example
3032
+ *
3033
+ * ```ts
3034
+ * import { DecimalString, nonNegativeDecimalString } from "@evolu/common";
3035
+ *
3036
+ * const NonNegative = nonNegativeDecimalString(DecimalString);
3037
+ *
3038
+ * expectOk(NonNegative.fromUnknown("0.5"), "0.5");
3039
+ * ```
3040
+ *
2717
3041
  * @group Number
2718
3042
  */
2719
3043
  export declare const nonNegativeDecimalString: BrandFactory<"NonNegativeDecimalString", DecimalString, NonNegativeDecimalStringError>;
2720
- /** @group Number */
3044
+ /**
3045
+ * Error returned when {@link nonNegativeDecimalString} rejects a decimal string.
3046
+ *
3047
+ * @group Number
3048
+ */
2721
3049
  export interface NonNegativeDecimalStringError extends TypeError<"NonNegativeDecimalString"> {
2722
3050
  readonly value: string;
2723
3051
  }
@@ -2731,10 +3059,24 @@ export type NonNegativeDecimalString = typeof NonNegativeDecimalString.Output;
2731
3059
  /**
2732
3060
  * {@link DecimalString} Brand requiring a value greater than zero.
2733
3061
  *
3062
+ * ### Example
3063
+ *
3064
+ * ```ts
3065
+ * import { DecimalString, positiveDecimalString } from "@evolu/common";
3066
+ *
3067
+ * const Positive = positiveDecimalString(DecimalString);
3068
+ *
3069
+ * expectOk(Positive.fromUnknown("0.5"), "0.5");
3070
+ * ```
3071
+ *
2734
3072
  * @group Number
2735
3073
  */
2736
3074
  export declare const positiveDecimalString: BrandFactory<"PositiveDecimalString", DecimalString, PositiveDecimalStringError>;
2737
- /** @group Number */
3075
+ /**
3076
+ * Error returned when {@link positiveDecimalString} rejects a decimal string.
3077
+ *
3078
+ * @group Number
3079
+ */
2738
3080
  export interface PositiveDecimalStringError extends TypeError<"PositiveDecimalString"> {
2739
3081
  readonly value: string;
2740
3082
  }
@@ -2749,12 +3091,26 @@ export interface PositiveDecimalStringError extends TypeError<"PositiveDecimalSt
2749
3091
  export declare const PositiveDecimalString: BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DecimalString", DecimalStringError>, "NonNegativeDecimalString", NonNegativeDecimalStringError>, "PositiveDecimalString", PositiveDecimalStringError>;
2750
3092
  export type PositiveDecimalString = typeof PositiveDecimalString.Output;
2751
3093
  /**
2752
- * {@link DecimalString} Brand requiring a value less than or equal to zero.
3094
+ * {@link DecimalString} Brand requiring a value less than or equal to zero.
3095
+ *
3096
+ * ### Example
3097
+ *
3098
+ * ```ts
3099
+ * import { DecimalString, nonPositiveDecimalString } from "@evolu/common";
3100
+ *
3101
+ * const NonPositive = nonPositiveDecimalString(DecimalString);
3102
+ *
3103
+ * expectOk(NonPositive.fromUnknown("-0.5"), "-0.5");
3104
+ * ```
3105
+ *
3106
+ * @group Number
3107
+ */
3108
+ export declare const nonPositiveDecimalString: BrandFactory<"NonPositiveDecimalString", DecimalString, NonPositiveDecimalStringError>;
3109
+ /**
3110
+ * Error returned when {@link nonPositiveDecimalString} rejects a decimal string.
2753
3111
  *
2754
3112
  * @group Number
2755
3113
  */
2756
- export declare const nonPositiveDecimalString: BrandFactory<"NonPositiveDecimalString", DecimalString, NonPositiveDecimalStringError>;
2757
- /** @group Number */
2758
3114
  export interface NonPositiveDecimalStringError extends TypeError<"NonPositiveDecimalString"> {
2759
3115
  readonly value: string;
2760
3116
  }
@@ -2768,10 +3124,24 @@ export type NonPositiveDecimalString = typeof NonPositiveDecimalString.Output;
2768
3124
  /**
2769
3125
  * {@link DecimalString} Brand requiring a value less than zero.
2770
3126
  *
3127
+ * ### Example
3128
+ *
3129
+ * ```ts
3130
+ * import { DecimalString, negativeDecimalString } from "@evolu/common";
3131
+ *
3132
+ * const Negative = negativeDecimalString(DecimalString);
3133
+ *
3134
+ * expectOk(Negative.fromUnknown("-0.5"), "-0.5");
3135
+ * ```
3136
+ *
2771
3137
  * @group Number
2772
3138
  */
2773
3139
  export declare const negativeDecimalString: BrandFactory<"NegativeDecimalString", DecimalString, NegativeDecimalStringError>;
2774
- /** @group Number */
3140
+ /**
3141
+ * Error returned when {@link negativeDecimalString} rejects a decimal string.
3142
+ *
3143
+ * @group Number
3144
+ */
2775
3145
  export interface NegativeDecimalStringError extends TypeError<"NegativeDecimalString"> {
2776
3146
  readonly value: string;
2777
3147
  }
@@ -2818,7 +3188,11 @@ export type NegativeDecimalString = typeof NegativeDecimalString.Output;
2818
3188
  * @group Number
2819
3189
  */
2820
3190
  export declare const multipleOf: <const Divisor extends string>(divisor: ValidateMultipleOfDivisor<Divisor>) => BrandFactory<`MultipleOf${Divisor}`, number, MultipleOfError<Divisor>>;
2821
- /** @group Number */
3191
+ /**
3192
+ * Error returned when {@link multipleOf} rejects a number.
3193
+ *
3194
+ * @group Number
3195
+ */
2822
3196
  export interface MultipleOfError<Divisor extends string = string> extends TypeError<`MultipleOf${Divisor}`> {
2823
3197
  readonly value: number;
2824
3198
  readonly divisor: Divisor;
@@ -2834,10 +3208,24 @@ type MultipleOfDivisorError = CompileTimeError<"MultipleOf", 'Divisor must be on
2834
3208
  /**
2835
3209
  * Number {@link Brand} requiring a value within an inclusive range.
2836
3210
  *
3211
+ * ### Example
3212
+ *
3213
+ * ```ts
3214
+ * import { Number, between } from "@evolu/common";
3215
+ *
3216
+ * const Percentage = between(0, 100)(Number);
3217
+ *
3218
+ * expectOk(Percentage.fromUnknown(75), 75);
3219
+ * ```
3220
+ *
2837
3221
  * @group Number
2838
3222
  */
2839
3223
  export declare const between: <Min extends number, Max extends number>(min: ValidateBrandFactoryNumber<Min>, max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`Between${Min}-${Max}`, number, BetweenError<Min, Max>>;
2840
- /** @group Number */
3224
+ /**
3225
+ * Error returned when {@link between} rejects a number.
3226
+ *
3227
+ * @group Number
3228
+ */
2841
3229
  export interface BetweenError<Min extends number = number, Max extends number = number> extends TypeError<`Between${Min}-${Max}`> {
2842
3230
  readonly value: number;
2843
3231
  readonly min: Min;
@@ -2894,7 +3282,11 @@ export interface BetweenError<Min extends number = number, Max extends number =
2894
3282
  * @group Collection
2895
3283
  */
2896
3284
  export declare const array: <ElementType extends ConcreteTypeNode>(element: ValidateElement<ElementType>) => ArrayType<ElementType>;
2897
- /** @group Collection */
3285
+ /**
3286
+ * The homogeneous readonly-array {@link Type} returned by {@link array}.
3287
+ *
3288
+ * @group Collection
3289
+ */
2898
3290
  export interface ArrayType<ElementType extends TypeNode> extends Type<"Array", ReadonlyArray<ElementType["Input"]>, ReadonlyArray<ElementType["Output"]>, ArrayNodeError<ElementType>, ArrayParent<ElementType>, ArrayError<InferErrors<ElementType>>, ArrayCustomFrom<ElementType>, ReadonlyArray<CanonicalInputOf<ElementType>>, AllTypesUseIdentityEncoding<ElementType>> {
2899
3291
  readonly [reflectedTypesSymbol]?: ElementType;
2900
3292
  readonly element: ElementType;
@@ -2915,42 +3307,78 @@ type ArrayParent<ElementType extends TypeNode> = [
2915
3307
  type ArrayNodeError<ElementType extends TypeNode> = [
2916
3308
  ElementType["parent"]
2917
3309
  ] extends [TypeNode] ? ArrayElementsError<ElementType["Error"]> : ArrayError<ElementType["Error"]>;
2918
- /** @group Collection */
3310
+ /**
3311
+ * Error returned by {@link array} for a non-array value or invalid array items.
3312
+ *
3313
+ * @group Collection
3314
+ */
2919
3315
  export type ArrayError<Error extends TypeError = TypeError> = ArrayNotArrayError | ArrayItemsErrorValue<Error, true>;
2920
- /** @group Collection */
3316
+ /**
3317
+ * Error returned when an {@link array} input is not an array.
3318
+ *
3319
+ * @group Collection
3320
+ */
2921
3321
  export interface ArrayNotArrayError extends TypeError<"Array"> {
2922
3322
  readonly reason: {
2923
3323
  readonly kind: "NotArray";
2924
3324
  readonly value: unknown;
2925
3325
  };
2926
3326
  }
2927
- /** @group Collection */
3327
+ /**
3328
+ * An {@link array} error containing structural or element issues.
3329
+ *
3330
+ * @group Collection
3331
+ */
2928
3332
  export type ArrayItemsError<Error extends TypeError> = ArrayItemsErrorValue<Error, true>;
2929
- /** @group Collection */
3333
+ /**
3334
+ * One structural or element issue found by {@link array}.
3335
+ *
3336
+ * @group Collection
3337
+ */
2930
3338
  export type ArrayIssue<Error extends TypeError> = ArrayStructuralIssue | ArrayElementIssue<Error>;
2931
- /** @group Collection */
3339
+ /**
3340
+ * A missing array element.
3341
+ *
3342
+ * @group Collection
3343
+ */
2932
3344
  export interface ArrayHoleIssue {
2933
3345
  readonly kind: "Hole";
2934
3346
  readonly index: number;
2935
3347
  }
2936
- /** @group Collection */
3348
+ /**
3349
+ * An array element defined by an accessor instead of a data property.
3350
+ *
3351
+ * @group Collection
3352
+ */
2937
3353
  export interface ArrayAccessorIssue {
2938
3354
  readonly kind: "Accessor";
2939
3355
  readonly index: number;
2940
3356
  }
2941
- /** @group Collection */
3357
+ /**
3358
+ * An own array property other than `length` or an indexed element.
3359
+ *
3360
+ * @group Collection
3361
+ */
2942
3362
  export interface ArrayExcessPropertyIssue {
2943
3363
  readonly kind: "ExcessProperty";
2944
3364
  readonly key: string | symbol;
2945
3365
  }
2946
3366
  type ArrayStructuralIssue = ArrayHoleIssue | ArrayAccessorIssue | ArrayExcessPropertyIssue;
2947
- /** @group Collection */
3367
+ /**
3368
+ * An invalid array element and its index.
3369
+ *
3370
+ * @group Collection
3371
+ */
2948
3372
  export type ArrayElementIssue<Error extends TypeError> = Error extends TypeError ? {
2949
3373
  readonly kind: "Element";
2950
3374
  readonly index: number;
2951
3375
  readonly error: Error;
2952
3376
  } : never;
2953
- /** @group Collection */
3377
+ /**
3378
+ * An {@link array} error containing element errors from a typed boundary.
3379
+ *
3380
+ * @group Collection
3381
+ */
2954
3382
  export type ArrayElementsError<Error extends TypeError> = [Error] extends [
2955
3383
  never
2956
3384
  ] ? never : ArrayItemsErrorValue<Error, false>;
@@ -2968,10 +3396,25 @@ interface ArrayItemsErrorValue<Error extends TypeError, IncludeStructuralIssues
2968
3396
  * iteration order. Classification uses the realm-neutral object tag and
2969
3397
  * prototype structure under Evolu Type's trusted JavaScript policy.
2970
3398
  *
3399
+ * ### Example
3400
+ *
3401
+ * ```ts
3402
+ * import { String, set } from "@evolu/common";
3403
+ *
3404
+ * const Tags = set(String);
3405
+ * const tags = new Set(["local-first", "offline"]);
3406
+ *
3407
+ * expectOk(Tags.fromUnknown(tags), tags);
3408
+ * ```
3409
+ *
2971
3410
  * @group Collection
2972
3411
  */
2973
3412
  export declare const set: <ElementType extends ConcreteTypeNode>(element: ValidateElement<ElementType>) => SetType<ElementType>;
2974
- /** @group Collection */
3413
+ /**
3414
+ * The homogeneous readonly-set {@link Type} returned by {@link set}.
3415
+ *
3416
+ * @group Collection
3417
+ */
2975
3418
  export interface SetType<ElementType extends TypeNode> extends Type<"Set", ReadonlySet<ElementType["Input"]>, ReadonlySet<ElementType["Output"]>, SetNodeError<ElementType>, SetParent<ElementType>, SetError<InferErrors<ElementType>>, SetCustomFrom<ElementType>, ReadonlySet<CanonicalInputOf<ElementType>>, AllTypesUseIdentityEncoding<ElementType>> {
2976
3419
  readonly [reflectedTypesSymbol]?: ElementType;
2977
3420
  readonly element: ElementType;
@@ -2991,9 +3434,18 @@ type SetParent<ElementType extends TypeNode> = [ElementType["parent"]] extends [
2991
3434
  type SetNodeError<ElementType extends TypeNode> = [
2992
3435
  ElementType["parent"]
2993
3436
  ] extends [TypeNode] ? SetElementsError<ElementType["Error"]> : SetError<ElementType["Error"]>;
2994
- /** @group Collection */
3437
+ /**
3438
+ * Error returned by {@link set} for a non-Set value, an invalid Set prototype,
3439
+ * or invalid Set items.
3440
+ *
3441
+ * @group Collection
3442
+ */
2995
3443
  export type SetError<Error extends TypeError = TypeError> = SetNotSetError | SetUnexpectedPrototypeError | SetItemsErrorValue<Error, true>;
2996
- /** @group Collection */
3444
+ /**
3445
+ * Error returned when a {@link set} input is not a Set.
3446
+ *
3447
+ * @group Collection
3448
+ */
2997
3449
  export interface SetNotSetError extends TypeError<"Set"> {
2998
3450
  readonly reason: {
2999
3451
  readonly kind: "NotSet";
@@ -3011,21 +3463,37 @@ export interface SetUnexpectedPrototypeError extends TypeError<"Set"> {
3011
3463
  readonly value: ReadonlySet<unknown>;
3012
3464
  };
3013
3465
  }
3014
- /** @group Collection */
3466
+ /**
3467
+ * An own property found on a Set value.
3468
+ *
3469
+ * @group Collection
3470
+ */
3015
3471
  export interface SetExcessPropertyIssue {
3016
3472
  readonly kind: "ExcessProperty";
3017
3473
  readonly key: string | symbol;
3018
3474
  }
3019
3475
  type SetStructuralIssue = SetExcessPropertyIssue;
3020
- /** @group Collection */
3476
+ /**
3477
+ * An invalid Set element and its iteration index.
3478
+ *
3479
+ * @group Collection
3480
+ */
3021
3481
  export type SetElementIssue<Error extends TypeError> = Error extends TypeError ? {
3022
3482
  readonly kind: "Element";
3023
3483
  readonly index: number;
3024
3484
  readonly error: Error;
3025
3485
  } : never;
3026
- /** @group Collection */
3486
+ /**
3487
+ * A {@link set} error containing structural or element issues.
3488
+ *
3489
+ * @group Collection
3490
+ */
3027
3491
  export type SetItemsError<Error extends TypeError> = SetItemsErrorValue<Error, true>;
3028
- /** @group Collection */
3492
+ /**
3493
+ * A {@link set} error containing element errors from a typed boundary.
3494
+ *
3495
+ * @group Collection
3496
+ */
3029
3497
  export type SetElementsError<Error extends TypeError> = [Error] extends [never] ? never : SetItemsErrorValue<Error, false>;
3030
3498
  interface SetItemsErrorValue<Error extends TypeError, IncludeStructuralIssues extends boolean> extends TypeError<"Set"> {
3031
3499
  readonly reason: {
@@ -3058,17 +3526,12 @@ interface SetItemsErrorValue<Error extends TypeError, IncludeStructuralIssues ex
3058
3526
  * ### Example
3059
3527
  *
3060
3528
  * ```ts
3061
- * import { Number, String, ok, transform, tuple } from "@evolu/common";
3062
- *
3063
- * const NumberFromString = transform("NumberFromString", String, Number, {
3064
- * from: (value) => ok(globalThis.Number(value)),
3065
- * to: globalThis.String,
3066
- * });
3529
+ * import { Int64FromInt64String, String, tuple } from "@evolu/common";
3067
3530
  *
3068
- * const Entry = tuple(String, NumberFromString);
3531
+ * const Entry = tuple(String, Int64FromInt64String);
3069
3532
  *
3070
- * expectOk(Entry.fromUnknown(["count", "1"]), ["count", 1]);
3071
- * expectOk(Entry.from.parent(["count", "1"]), ["count", 1]);
3533
+ * expectOk(Entry.fromUnknown(["count", "1"]), ["count", 1n]);
3534
+ * expectOk(Entry.from.parent(["count", "1"]), ["count", 1n]);
3072
3535
  * ```
3073
3536
  *
3074
3537
  * @group Collection
@@ -3267,7 +3730,7 @@ type PlainObjectError = ObjectError<Readonly<Record<never, never>>, ObjectProper
3267
3730
  * values have their own Types, and {@link instanceOf} when an instance belongs
3268
3731
  * to the domain.
3269
3732
  *
3270
- * @group Base Types
3733
+ * @group Base
3271
3734
  */
3272
3735
  export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, Readonly<Record<string, unknown>>, PlainObjectError, null, PlainObjectError, never, Readonly<Record<string, unknown>>>;
3273
3736
  /**
@@ -3300,20 +3763,13 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
3300
3763
  *
3301
3764
  * ```ts
3302
3765
  * import {
3303
- * Number,
3766
+ * Int64FromInt64String,
3304
3767
  * String,
3305
- * ok,
3306
3768
  * record,
3307
- * transform,
3308
- * type Result,
3769
+ * type Int64,
3309
3770
  * } from "@evolu/common";
3310
3771
  *
3311
- * const ScoreFromString = transform("ScoreFromString", String, Number, {
3312
- * from: (value) => ok(globalThis.Number(value)),
3313
- * to: globalThis.String,
3314
- * });
3315
- *
3316
- * const ScoresByUser = record(String, ScoreFromString);
3772
+ * const ScoresByUser = record(String, Int64FromInt64String);
3317
3773
  * type ScoresByUser = typeof ScoresByUser.Output;
3318
3774
  *
3319
3775
  * // Validate an unknown value.
@@ -3322,7 +3778,7 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
3322
3778
  * grace: "20",
3323
3779
  * });
3324
3780
  *
3325
- * expectOk(scoresFromUnknown, { ada: 10, grace: 20 });
3781
+ * expectOk(scoresFromUnknown, { ada: 10n, grace: 20n });
3326
3782
  *
3327
3783
  * // Validate keys and values with their root Types.
3328
3784
  * const scoresInput = ScoresByUser.parent.fromUnknown({
@@ -3334,11 +3790,10 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
3334
3790
  * // Run the remaining key and value stages.
3335
3791
  * const scoresFromInput = ScoresByUser.from.parent(scoresInput.value);
3336
3792
  *
3337
- * expectTypeOf(scoresFromInput).toEqualTypeOf<
3338
- * Result<Readonly<Partial<Record<string, number>>>, never>
3793
+ * expectOk(scoresFromInput, { ada: 10n, grace: 20n });
3794
+ * expectTypeOf(scoresFromInput.value).toEqualTypeOf<
3795
+ * Readonly<Partial<Record<string, Int64>>>
3339
3796
  * >();
3340
- *
3341
- * expectOk(scoresFromInput, { ada: 10, grace: 20 });
3342
3797
  * ```
3343
3798
  *
3344
3799
  * Note that TypeScript does not model an object's runtime prototype. This can
@@ -3382,7 +3837,11 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
3382
3837
  * @group Objects
3383
3838
  */
3384
3839
  export declare const record: <KeyType extends ConcreteTypeNode, ValueType extends ConcreteTypeNode>(key: ValidateRecordKeyType<KeyType>, value: ValidateRecordValueType<ValueType>) => RecordType<KeyType, ValueType>;
3385
- /** @group Objects */
3840
+ /**
3841
+ * The {@link Type} returned by {@link record}.
3842
+ *
3843
+ * @group Objects
3844
+ */
3386
3845
  export interface RecordType<KeyType extends TypeNode, ValueType extends TypeNode> extends Type<"Record", RecordShape<KeyType, ValueType, "Input">, RecordShape<KeyType, ValueType, "Output">, RecordNodeError<KeyType, ValueType>, RecordParent<KeyType, ValueType>, RecordError<InferErrors<KeyType>, InferErrors<ValueType>, RecordCollisionFor<KeyType>>, never, CanonicalInputSubset<RecordShape<KeyType, ValueType, "Input">, RecordShape<KeyType, ValueType, "CanonicalInput">>, AllTypesUseIdentityEncoding<KeyType | ValueType>> {
3387
3846
  readonly [reflectedTypesSymbol]?: KeyType | ValueType;
3388
3847
  readonly key: KeyType;
@@ -3412,16 +3871,28 @@ type ValidateRecordValueType<T extends ConcreteTypeNode> = IsUnion<T> extends fa
3412
3871
  type RecordKeyConcreteTypeError = CompileTimeError<"Type", "Record key must use one concrete Type node. Pass a Union Type node instead of a union of Type nodes.">;
3413
3872
  type RecordValueConcreteTypeError = CompileTimeError<"Type", "Record value must use one concrete Type node. Pass a Union Type node instead of a union of Type nodes.">;
3414
3873
  type RecordKeyStringTypeError = CompileTimeError<"Type", "Record key Type Input and Output must extend string.">;
3415
- /** @group Objects */
3874
+ /**
3875
+ * Error returned while validating a {@link record} and its entries.
3876
+ *
3877
+ * @group Objects
3878
+ */
3416
3879
  export type RecordError<KeyError extends TypeError = TypeError, ValueError extends TypeError = TypeError, Collision extends RecordCollisionIssue = RecordCollisionIssue> = RecordNotRecordError | RecordNotPlainRecordError | RecordEntriesErrorValue<KeyError, ValueError, Collision | RecordAccessorIssue | RecordNonEnumerableIssue>;
3417
- /** @group Objects */
3880
+ /**
3881
+ * Error returned when a {@link record} input is not an object.
3882
+ *
3883
+ * @group Objects
3884
+ */
3418
3885
  export interface RecordNotRecordError extends TypeError<"Record"> {
3419
3886
  readonly reason: {
3420
3887
  readonly kind: "NotRecord";
3421
3888
  readonly value: unknown;
3422
3889
  };
3423
3890
  }
3424
- /** @group Objects */
3891
+ /**
3892
+ * Error returned when a {@link record} input is not a plain object.
3893
+ *
3894
+ * @group Objects
3895
+ */
3425
3896
  export interface RecordNotPlainRecordError extends TypeError<"Record"> {
3426
3897
  readonly reason: {
3427
3898
  readonly kind: "NotPlainRecord";
@@ -3438,9 +3909,17 @@ export interface RecordNotPlainRecordError extends TypeError<"Record"> {
3438
3909
  * @group Objects
3439
3910
  */
3440
3911
  export type RecordEntriesError<KeyError extends TypeError, ValueError extends TypeError, StructuralIssue extends RecordStructuralIssue = RecordCollisionIssue> = [KeyError | ValueError | StructuralIssue] extends [never] ? never : RecordEntriesErrorValue<KeyError, ValueError, StructuralIssue>;
3441
- /** @group Objects */
3912
+ /**
3913
+ * An invalid key, value, or property structure in a {@link record}.
3914
+ *
3915
+ * @group Objects
3916
+ */
3442
3917
  export type RecordIssue<KeyError extends TypeError, ValueError extends TypeError, StructuralIssue extends RecordStructuralIssue = RecordCollisionIssue> = RecordKeyIssue<KeyError> | RecordValueIssue<ValueError> | StructuralIssue;
3443
- /** @group Objects */
3918
+ /**
3919
+ * A property-structure issue returned by {@link record}.
3920
+ *
3921
+ * @group Objects
3922
+ */
3444
3923
  export type RecordStructuralIssue = RecordAccessorIssue | RecordCollisionIssue | RecordNonEnumerableIssue;
3445
3924
  /**
3446
3925
  * An accessor property rejected by {@link record}.
@@ -3460,19 +3939,31 @@ export interface RecordNonEnumerableIssue {
3460
3939
  readonly kind: "NonEnumerable";
3461
3940
  readonly key: string | symbol;
3462
3941
  }
3463
- /** @group Objects */
3942
+ /**
3943
+ * An invalid key and its source property key in a {@link record}.
3944
+ *
3945
+ * @group Objects
3946
+ */
3464
3947
  export type RecordKeyIssue<Error extends TypeError> = Error extends TypeError ? {
3465
3948
  readonly kind: "Key";
3466
3949
  readonly key: string | symbol;
3467
3950
  readonly error: Error;
3468
3951
  } : never;
3469
- /** @group Objects */
3952
+ /**
3953
+ * An invalid value and its property key in a {@link record}.
3954
+ *
3955
+ * @group Objects
3956
+ */
3470
3957
  export type RecordValueIssue<Error extends TypeError> = Error extends TypeError ? {
3471
3958
  readonly kind: "Value";
3472
3959
  readonly key: string | symbol;
3473
3960
  readonly error: Error;
3474
3961
  } : never;
3475
- /** @group Objects */
3962
+ /**
3963
+ * Two {@link record} keys that decode to the same output key.
3964
+ *
3965
+ * @group Objects
3966
+ */
3476
3967
  export interface RecordCollisionIssue {
3477
3968
  readonly kind: "Collision";
3478
3969
  readonly key: string | symbol;
@@ -3563,48 +4054,38 @@ type ObjectProperty = ObjectProps[string];
3563
4054
  *
3564
4055
  * ```ts
3565
4056
  * import {
3566
- * Number,
4057
+ * Int64FromInt64String,
3567
4058
  * String,
3568
4059
  * object,
3569
- * ok,
3570
- * transform,
3571
4060
  * type InferType,
3572
- * type Result,
3573
4061
  * } from "@evolu/common";
3574
4062
  *
3575
- * const AgeFromString = transform("AgeFromString", String, Number, {
3576
- * from: (value) => ok(globalThis.Number(value)),
3577
- * to: globalThis.String,
3578
- * });
3579
- *
3580
4063
  * const User = object({
3581
4064
  * name: String,
3582
- * age: AgeFromString,
4065
+ * loginCount: Int64FromInt64String,
3583
4066
  * });
3584
4067
  * interface User extends InferType<typeof User> {}
3585
4068
  *
3586
4069
  * // Validate an unknown value.
3587
- * const userFromUnknown = User.fromUnknown({ name: "Ada", age: "42" });
4070
+ * const userFromUnknown = User.fromUnknown({
4071
+ * name: "Ada",
4072
+ * loginCount: "42",
4073
+ * });
3588
4074
  *
3589
- * expectOk(userFromUnknown, { name: "Ada", age: 42 });
4075
+ * expectOk(userFromUnknown, { name: "Ada", loginCount: 42n });
3590
4076
  *
3591
4077
  * // Validate the object and root property Types.
3592
4078
  * const userInput = User.parent.fromUnknown({
3593
4079
  * name: "Ada",
3594
- * age: "42",
4080
+ * loginCount: "42",
3595
4081
  * });
3596
- * expectOk(userInput, { name: "Ada", age: "42" });
4082
+ * expectOk(userInput, { name: "Ada", loginCount: "42" });
3597
4083
  *
3598
4084
  * // Run the remaining property stages.
3599
- * const userFromInput: Result<
3600
- * { readonly name: string; readonly age: number },
3601
- * never
3602
- * > = User.from.parent(userInput.value);
4085
+ * const userFromInput = User.from.parent(userInput.value);
3603
4086
  *
3604
- * expectTypeOf(userFromInput).toEqualTypeOf<
3605
- * Result<{ readonly name: string; readonly age: number }, never>
3606
- * >();
3607
- * expectOk(userFromInput, { name: "Ada", age: 42 });
4087
+ * expectOk(userFromInput, { name: "Ada", loginCount: 42n });
4088
+ * expectTypeOf(userFromInput.value).toExtend<User>();
3608
4089
  * ```
3609
4090
  *
3610
4091
  * Note that TypeScript does not model an object's runtime prototype. This can
@@ -3652,6 +4133,7 @@ type ObjectProperty = ObjectProps[string];
3652
4133
  * @group Objects
3653
4134
  */
3654
4135
  export declare function object<const Props extends ObjectProps>(props: Props, ...validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]): StrictObjectType<Props>;
4136
+ /** Creates an Object Type with additional record properties. */
3655
4137
  export declare function object<const Props extends ObjectProps, const Rest extends RecordTypeNode & ConcreteTypeNode>(props: Props, record: Rest, ...validation: [
3656
4138
  ObjectValidationError<Props> | ObjectRecordValidationError<Props, Rest>
3657
4139
  ] extends [never] ? [] : [
@@ -3693,7 +4175,11 @@ type ObjectRecordKeyTypeError = CompileTimeError<"Type", "Object Record key must
3693
4175
  type ObjectRecordInputTypeError = CompileTimeError<"Type", "Every declared property Type Input must extend the Object Record value Type Input.">;
3694
4176
  type ObjectRecordOutputTypeError = CompileTimeError<"Type", "Every declared property Type Output must extend the Object Record value Type Output.">;
3695
4177
  type ObjectRecordCanonicalInputTypeError = CompileTimeError<"Type", "Every declared property Type CanonicalInput must extend the Object Record value Type CanonicalInput.">;
3696
- /** @group Objects */
4178
+ /**
4179
+ * The {@link Type} returned by {@link object}.
4180
+ *
4181
+ * @group Objects
4182
+ */
3697
4183
  export type ObjectType<Props extends ObjectProps, Rest extends ObjectRecordTypeNode | undefined = undefined> = Rest extends ObjectRecordTypeNode ? ObjectWithRecordType<Props, Rest> : StrictObjectType<Props>;
3698
4184
  type StrictObjectType<Props extends ObjectProps> = Type<"Object", StrictObjectShape<Props, "Input">, StrictObjectShape<Props, "Output">, [
3699
4185
  StrictObjectParents<Props>
@@ -3883,7 +4369,11 @@ type ObjectRestFromParentError<Rest extends ObjectRecordTypeNode | undefined> =
3883
4369
  * @group Objects
3884
4370
  */
3885
4371
  export declare const partial: <const Props extends ObjectProps>(props: Props, ..._validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]) => ObjectType<PartialObjectProps<Props>>;
3886
- /** @group Objects */
4372
+ /**
4373
+ * Maps every required object property Type to an optional property.
4374
+ *
4375
+ * @group Objects
4376
+ */
3887
4377
  export type PartialObjectProps<Props extends ObjectProps> = {
3888
4378
  readonly [Key in keyof Props]: Props[Key] extends OptionalProperty<TypeNode> ? Props[Key] : Props[Key] extends TypeNode ? OptionalProperty<Props[Key]> : never;
3889
4379
  };
@@ -3915,13 +4405,29 @@ export type PartialObjectProps<Props extends ObjectProps> = {
3915
4405
  * @group Objects
3916
4406
  */
3917
4407
  export declare const nullableToOptional: <const Props extends ObjectProps>(props: Props, ..._validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]) => ObjectType<NullableToOptionalProps<Props>>;
3918
- /** @group Objects */
4408
+ /**
4409
+ * Maps object properties whose Union Type includes {@link Null} to optional
4410
+ * properties.
4411
+ *
4412
+ * @group Objects
4413
+ */
3919
4414
  export type NullableToOptionalProps<Props extends ObjectProps> = {
3920
4415
  readonly [Key in keyof Props]: Props[Key] extends OptionalProperty<TypeNode> ? Props[Key] : Props[Key] extends UnionType<infer Members> ? typeof Null extends Members[number] ? OptionalProperty<Props[Key]> : Props[Key] : Props[Key];
3921
4416
  };
3922
4417
  /**
3923
4418
  * Object {@link Type} without the selected declared properties.
3924
4419
  *
4420
+ * ### Example
4421
+ *
4422
+ * ```ts
4423
+ * import { String, object, omit } from "@evolu/common";
4424
+ *
4425
+ * const User = object({ name: String, password: String });
4426
+ * const PublicUser = omit(User, "password");
4427
+ *
4428
+ * expectOk(PublicUser.fromUnknown({ name: "Ada" }), { name: "Ada" });
4429
+ * ```
4430
+ *
3925
4431
  * @group Objects
3926
4432
  */
3927
4433
  export declare const omit: <const Props extends ObjectProps, const Keys extends ReadonlyArray<keyof Props>, Rest extends ObjectRecordTypeNode | undefined = undefined>(objectType: ObjectType<Props, Rest>, ...keys: Keys & ([ValidateOmitKeys<Keys>] extends [never] ? unknown : readonly [ValidationFailure<ValidateOmitKeys<Keys>>])) => ObjectType<Omit<Props, Keys[number]>, Rest>;
@@ -3931,11 +4437,11 @@ type ValidateOmitKeys<Keys extends ReadonlyArray<PropertyKey>> = number extends
3931
4437
  type OmitKeysTupleError = CompileTimeError<"Type", "Omitted keys must use one concrete finite tuple.">;
3932
4438
  type OmitKeyConcreteTypeError = CompileTimeError<"Type", "Each omitted key must be one concrete property key.">;
3933
4439
  /**
3934
- * {@link Result} {@link Type} for typed success and error values.
4440
+ * Creates a {@link Type} for {@link Result} values.
3935
4441
  *
3936
4442
  * Use this to validate Results crossing a storage, worker, API, or other
3937
- * serialization boundary. The operation returns an outer validation Result. Its
3938
- * successful value is the inner domain Result described by `okType` and
4443
+ * serialization boundary. `fromUnknown` returns an outer validation Result.
4444
+ * Its successful value is the inner domain Result described by `okType` and
3939
4445
  * `errorType`.
3940
4446
  *
3941
4447
  * ### Example
@@ -3951,34 +4457,16 @@ type OmitKeyConcreteTypeError = CompileTimeError<"Type", "Each omitted key must
3951
4457
  *
3952
4458
  * const SyncResponse = result(
3953
4459
  * object({ timestamp: NonNegativeInt }),
3954
- * typed("SyncError", { message: String }),
4460
+ * typed("SyncFailed", { message: String }),
3955
4461
  * );
3956
4462
  *
3957
- * const describeResponse = (input: unknown): string => {
3958
- * const validated = SyncResponse.fromUnknown(input);
3959
- * if (!validated.ok) return "Invalid response";
3960
- *
3961
- * const response = validated.value;
3962
- * return response.ok
3963
- * ? `Synced at ${response.value.timestamp}`
3964
- * : response.error.message;
3965
- * };
4463
+ * const validated = SyncResponse.fromUnknown({
4464
+ * ok: true,
4465
+ * value: { timestamp: 42 },
4466
+ * });
3966
4467
  *
3967
- * expect(
3968
- * describeResponse({
3969
- * ok: true,
3970
- * value: { timestamp: 42 },
3971
- * }),
3972
- * ).toBe("Synced at 42");
3973
- * expect(
3974
- * describeResponse({
3975
- * ok: false,
3976
- * error: { type: "SyncError", message: "Offline" },
3977
- * }),
3978
- * ).toBe("Offline");
3979
- * expect(describeResponse({ ok: true, value: { timestamp: -1 } })).toBe(
3980
- * "Invalid response",
3981
- * );
4468
+ * expectOk(validated, { ok: true, value: { timestamp: 42 } });
4469
+ * expectOk(validated.value, { timestamp: 42 });
3982
4470
  * ```
3983
4471
  *
3984
4472
  * @group Results
@@ -4010,7 +4498,7 @@ export declare const UnknownResult: DiscriminatedUnionType<"ok", readonly [Stric
4010
4498
  }>]>;
4011
4499
  export type UnknownResult = typeof UnknownResult.Output;
4012
4500
  /**
4013
- * Tagged {@link ObjectType}.
4501
+ * Creates an {@link ObjectType} with a literal `type` property.
4014
4502
  *
4015
4503
  * The discriminator belongs to `typed`, so additional properties cannot declare
4016
4504
  * `type`. The discriminator Input is `string`, inherited from {@link String},
@@ -4022,35 +4510,38 @@ export type UnknownResult = typeof UnknownResult.Output;
4022
4510
  * ### Example
4023
4511
  *
4024
4512
  * ```ts
4025
- * import { String, discriminatedUnion, typed } from "@evolu/common";
4513
+ * import { String, typed } from "@evolu/common";
4026
4514
  *
4027
4515
  * const Pending = typed("Pending", {
4028
4516
  * label: String,
4029
4517
  * });
4030
4518
  *
4031
- * const Completed = typed("Completed");
4032
- * const Status = discriminatedUnion(Pending, Completed);
4033
- *
4034
- * expectOk(Status.fromUnknown({ type: "Pending", label: "Waiting" }), {
4519
+ * expectOk(Pending.fromUnknown({ type: "Pending", label: "Waiting" }), {
4035
4520
  * type: "Pending",
4036
4521
  * label: "Waiting",
4037
4522
  * });
4038
- * expectOk(Status.fromUnknown({ type: "Completed" }), {
4039
- * type: "Completed",
4040
- * });
4041
4523
  * ```
4042
4524
  *
4043
4525
  * @group Discriminated unions
4044
4526
  */
4045
4527
  export declare function typed<const Tag extends TypeName>(tag: ValidateTypedTag<Tag>): TypedType<Tag>;
4528
+ /** Creates a Tagged Object Type with declared properties. */
4046
4529
  export declare function typed<const Tag extends TypeName, const Props extends ObjectProps>(tag: ValidateTypedTag<Tag>, props: Props, ...validation: [TypedValidationError<Props>] extends [never] ? [] : [ValidationFailure<TypedValidationError<Props>>]): TypedType<Tag, Props>;
4530
+ /** Creates a Tagged Object Type with additional record properties. */
4047
4531
  export declare function typed<const Tag extends TypeName, const Props extends ObjectProps, const Rest extends RecordTypeNode & ConcreteTypeNode>(tag: ValidateTypedTag<Tag>, props: Props, record: Rest, ...validation: [
4048
4532
  TypedValidationError<Props> | ObjectRecordValidationError<TypedProps<Tag, Props>, Rest>
4049
4533
  ] extends [never] ? [] : [
4050
4534
  ValidationFailure<TypedValidationError<Props> | ObjectRecordValidationError<TypedProps<Tag, Props>, Rest>>
4051
4535
  ]): TypedType<Tag, Props, Rest extends ObjectRecordTypeNode ? Rest : never>;
4052
4536
  /**
4053
- * A structurally tagged value created by {@link typed}.
4537
+ * A TypeScript interface with a literal `type` property.
4538
+ *
4539
+ * Use `Typed` for both domain objects in discriminated unions and plain domain
4540
+ * errors returned by {@link Result}. Name a domain error interface `XError`.
4541
+ * When `X` already describes a failure, use `X` for its `type` discriminant
4542
+ * because `Error` describes the interface's role rather than the runtime error
4543
+ * kind. Keep `Error` when it is needed to make the discriminant unambiguous,
4544
+ * such as `TimeoutError`.
4054
4545
  *
4055
4546
  * Typed unions model mutually exclusive states as separate variants instead of
4056
4547
  * combinations of flags and optional properties. TypeScript narrows a union by
@@ -4061,20 +4552,23 @@ export declare function typed<const Tag extends TypeName, const Props extends Ob
4061
4552
  * ### Example
4062
4553
  *
4063
4554
  * ```ts
4064
- * import { type Typed } from "@evolu/common";
4555
+ * import { err, ok, type Result, type Typed } from "@evolu/common";
4556
+ *
4557
+ * interface User extends Typed<"User"> {
4558
+ * readonly id: string;
4559
+ * }
4065
4560
  *
4066
- * type Status = Typed<"Pending"> | Typed<"Completed">;
4561
+ * const getUser = (id: string): Result<User, UserNotFoundError> =>
4562
+ * id === "user-1"
4563
+ * ? ok({ type: "User", id })
4564
+ * : err({ type: "UserNotFound", id });
4067
4565
  *
4068
- * const getStatusMessage = (status: Status): string => {
4069
- * switch (status.type) {
4070
- * case "Pending":
4071
- * return "Waiting";
4072
- * case "Completed":
4073
- * return "Done";
4074
- * }
4075
- * };
4566
+ * interface UserNotFoundError extends Typed<"UserNotFound"> {
4567
+ * readonly id: string;
4568
+ * }
4076
4569
  *
4077
- * expect(getStatusMessage({ type: "Pending" })).toBe("Waiting");
4570
+ * expectOk(getUser("user-1"), { type: "User", id: "user-1" });
4571
+ * expectErr(getUser("missing"), { type: "UserNotFound", id: "missing" });
4078
4572
  * ```
4079
4573
  *
4080
4574
  * @group Discriminated unions
@@ -4085,9 +4579,8 @@ export interface Typed<Tag extends TypeName> {
4085
4579
  /**
4086
4580
  * Extracts members of a {@link Typed} Output union by their `type` literal.
4087
4581
  *
4088
- * The requested name is constrained to the union's actual discriminator values,
4089
- * so a misspelling is a TypeScript error instead of silently producing
4090
- * `never`.
4582
+ * The requested tag is constrained to the union's actual discriminator values,
4583
+ * so a misspelling is a TypeScript error instead of silently producing `never`.
4091
4584
  *
4092
4585
  * ### Example
4093
4586
  *
@@ -4131,7 +4624,8 @@ type ConcreteTypedTagError = CompileTimeError<"Type", "Tag must be one concrete
4131
4624
  type TypedValidationError<Props extends ObjectProps> = "type" extends keyof Props ? TypedTypePropertyError : ObjectValidationError<Props>;
4132
4625
  type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties must not declare the reserved "type" property.'>;
4133
4626
  /**
4134
- * Producer-result {@link Type} for value, error, or done outcomes.
4627
+ * Creates a {@link Type} for producer Results with value, error, or done
4628
+ * outcomes.
4135
4629
  *
4136
4630
  * The three outcomes are `Ok<Value>`, `Err<Error>`, and `Err<Typed<"Done"> & {
4137
4631
  * done: Done }>`. This keeps normal completion distinct from failure while
@@ -4144,7 +4638,7 @@ type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties mu
4144
4638
  *
4145
4639
  * const StringNextResult = nextResult(
4146
4640
  * String,
4147
- * typed("ProducerError", { message: String }),
4641
+ * typed("ReadFailed", { message: String }),
4148
4642
  * String,
4149
4643
  * );
4150
4644
  *
@@ -4168,7 +4662,7 @@ type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties mu
4168
4662
  * expect(
4169
4663
  * describeNext({
4170
4664
  * ok: false,
4171
- * error: { type: "ProducerError", message: "Offline" },
4665
+ * error: { type: "ReadFailed", message: "Offline" },
4172
4666
  * }),
4173
4667
  * ).toBe("Error: Offline");
4174
4668
  * ```
@@ -4200,7 +4694,7 @@ export declare const UnknownNextResult: DiscriminatedUnionType<"ok", readonly [S
4200
4694
  }>]>;
4201
4695
  export type UnknownNextResult = typeof UnknownNextResult.Output;
4202
4696
  /**
4203
- * Discriminated Union {@link Type}.
4697
+ * Discriminated union {@link Type}.
4204
4698
  *
4205
4699
  * With no explicit key, the conventional `type` property created by
4206
4700
  * {@link typed} is used. Pass a key first to discriminate
@@ -4231,6 +4725,34 @@ export type UnknownNextResult = typeof UnknownNextResult.Output;
4231
4725
  * @group Discriminated unions
4232
4726
  */
4233
4727
  export declare function discriminatedUnion<const Members extends DiscriminatedUnionMembers>(...members: Members & DiscriminatedUnionValidation<"type", Members>): DiscriminatedUnionType<"type", Members>;
4728
+ /**
4729
+ * Creates a Discriminated Union Type with an explicit discriminator key.
4730
+ *
4731
+ * ### Example
4732
+ *
4733
+ * ```ts
4734
+ * import {
4735
+ * Number,
4736
+ * String,
4737
+ * discriminatedUnion,
4738
+ * literal,
4739
+ * object,
4740
+ * } from "@evolu/common";
4741
+ *
4742
+ * const Added = object({ kind: literal("added"), value: String });
4743
+ * const Removed = object({ kind: literal("removed"), id: Number });
4744
+ * const Event = discriminatedUnion("kind", Added, Removed);
4745
+ *
4746
+ * expectOk(Event.fromUnknown({ kind: "added", value: "Evolu" }), {
4747
+ * kind: "added",
4748
+ * value: "Evolu",
4749
+ * });
4750
+ * expectOk(Event.fromUnknown({ kind: "removed", id: 1 }), {
4751
+ * kind: "removed",
4752
+ * id: 1,
4753
+ * });
4754
+ * ```
4755
+ */
4234
4756
  export declare function discriminatedUnion<const Key extends string, const Members extends DiscriminatedUnionMembers>(key: ValidateDiscriminatedUnionKey<Key>, ...members: Members & DiscriminatedUnionValidation<Key, Members>): DiscriminatedUnionType<Key, Members>;
4235
4757
  /**
4236
4758
  * The routed {@link Type} returned by {@link discriminatedUnion}.
@@ -4353,10 +4875,10 @@ type DiscriminatedUnionMemberConcreteTypeError = CompileTimeError<"Type", "Membe
4353
4875
  type DiscriminatedUnionPropertyError<Key extends string> = CompileTimeError<"Type", `Property "${Key}" must be a required String, Number, BigInt, or Boolean Literal Type in every member.`>;
4354
4876
  type DiscriminatedUnionDuplicateValueError<Key extends string, Expected extends DiscriminatedUnionLiteral> = CompileTimeError<"Type", `Duplicate value "${Expected}" at property "${Key}".`>;
4355
4877
  /**
4356
- * Lazy {@link Type} for recursive definitions.
4878
+ * Creates a lazy {@link Type} for recursive definitions.
4357
4879
  *
4358
- * Lazy defers and caches a Type definition, allowing recursive data such as
4359
- * trees and mutually recursive models.
4880
+ * The definition is evaluated on first use and then cached, allowing recursive
4881
+ * data such as trees and mutually recursive models.
4360
4882
  *
4361
4883
  * A recursive declaration refers to its own variable while that variable is
4362
4884
  * being initialized, so TypeScript cannot infer it reliably. Getter-based
@@ -4376,12 +4898,10 @@ type DiscriminatedUnionDuplicateValueError<Key extends string, Expected extends
4376
4898
  *
4377
4899
  * ```ts
4378
4900
  * import {
4379
- * Number,
4380
4901
  * String,
4381
4902
  * array,
4382
4903
  * lazy,
4383
4904
  * object,
4384
- * optional,
4385
4905
  * type ArrayError,
4386
4906
  * type LazyType,
4387
4907
  * type ObjectError,
@@ -4402,35 +4922,19 @@ type DiscriminatedUnionDuplicateValueError<Key extends string, Expected extends
4402
4922
  * () => object({ value: String, children: array(Tree) }),
4403
4923
  * );
4404
4924
  *
4405
- * interface Left {
4406
- * readonly label: string;
4407
- * readonly right?: Right;
4408
- * }
4409
- *
4410
- * interface Right {
4411
- * readonly count: number;
4412
- * readonly left?: Left;
4413
- * }
4414
- *
4415
- * interface LeftError extends ObjectError<{
4416
- * readonly label: TypeOfError<"String">;
4417
- * readonly right?: RightError;
4418
- * }> {}
4419
- *
4420
- * interface RightError extends ObjectError<{
4421
- * readonly count: TypeOfError<"Number">;
4422
- * readonly left?: LeftError;
4423
- * }> {}
4424
- *
4425
- * const Left: LazyType<Left, Left, never, LeftError, LeftError> = lazy(
4426
- * () => object({ label: String, right: optional(Right) }),
4427
- * );
4925
+ * const result = Tree.fromUnknown({
4926
+ * value: "root",
4927
+ * children: [{ value: "leaf", children: [] }],
4928
+ * });
4428
4929
  *
4429
- * const Right: LazyType<Right, Right, never, RightError, RightError> =
4430
- * lazy(() => object({ count: Number, left: optional(Left) }));
4930
+ * expectOk(result, {
4931
+ * value: "root",
4932
+ * children: [{ value: "leaf", children: [] }],
4933
+ * });
4934
+ * expectTypeOf(result.value).toEqualTypeOf<Tree>();
4431
4935
  * ```
4432
4936
  *
4433
- * @group Recursive Types
4937
+ * @group Recursive
4434
4938
  */
4435
4939
  export declare function lazy<Target extends ConcreteTypeNode>(getType: Thunk<ValidateLazyTarget<Target>>): LazyType<Target["Input"], Target["Output"], TypeFromError<Target>, InferErrors<RootType<Target>>, InferErrors<Target>, CanonicalInputOf<Target>, IdentityEncodingOf<Target>>;
4436
4940
  /**
@@ -4448,7 +4952,7 @@ export declare function lazy<Target extends ConcreteTypeNode>(getType: Thunk<Val
4448
4952
  * recursive declaration finite for TypeScript while preserving structured
4449
4953
  * errors at every boundary.
4450
4954
  *
4451
- * @group Recursive Types
4955
+ * @group Recursive
4452
4956
  */
4453
4957
  export interface LazyType<in out Input, in out Output, in out FromError extends TypeError, in out InputError extends TypeError, in out Errors extends TypeError, in out CanonicalInput extends Input = Input, in out UsesIdentityEncoding extends boolean = true> extends Type<"Lazy", Input, Output, FromError, Type<"Lazy", Input, Input, InputError, null, InputError, never, Input>, Errors, never, CanonicalInput, UsesIdentityEncoding> {
4454
4958
  readonly [lazyTypeSymbol]: true;
@@ -4504,7 +5008,7 @@ export interface JsonObject {
4504
5008
  readonly [key: string]: JsonValue;
4505
5009
  }
4506
5010
  /**
4507
- * One issue found while validating an exact {@link JsonValue}.
5011
+ * One issue found while validating a candidate as an exact {@link JsonValue}.
4508
5012
  *
4509
5013
  * @group JSON
4510
5014
  */
@@ -4542,7 +5046,8 @@ export type JsonValueIssue = {
4542
5046
  readonly ancestorPath: ReadonlyArray<string | number | symbol>;
4543
5047
  };
4544
5048
  /**
4545
- * An error containing one or more issues found in a {@link JsonValue}.
5049
+ * An error containing one or more issues found while validating a candidate as
5050
+ * an exact {@link JsonValue}.
4546
5051
  *
4547
5052
  * @group JSON
4548
5053
  */
@@ -4580,6 +5085,21 @@ export interface JsonError extends TypeError<"Json"> {
4580
5085
  /**
4581
5086
  * Exact root Type for {@link JsonValue} data trees.
4582
5087
  *
5088
+ * ### Example
5089
+ *
5090
+ * ```ts
5091
+ * import { JsonValue, type JsonValueInput } from "@evolu/common";
5092
+ *
5093
+ * const input: JsonValueInput = {
5094
+ * name: "Ada",
5095
+ * scores: [10, 20],
5096
+ * };
5097
+ * const result = JsonValue.fromUnknown(input);
5098
+ *
5099
+ * expectOk(result, input);
5100
+ * expectTypeOf(result.value).toEqualTypeOf<JsonValue>();
5101
+ * ```
5102
+ *
4583
5103
  * @group JSON
4584
5104
  */
4585
5105
  export declare const JsonValue: JsonValueType;
@@ -4609,21 +5129,52 @@ export type Json = typeof Json.Output;
4609
5129
  /**
4610
5130
  * Totally parses proven {@link Json} text into an exact {@link JsonValue}.
4611
5131
  *
5132
+ * ### Example
5133
+ *
5134
+ * ```ts
5135
+ * import { Json, jsonToJsonValue } from "@evolu/common";
5136
+ *
5137
+ * const value = jsonToJsonValue(Json.orThrow('{"name":"Ada"}'));
5138
+ *
5139
+ * expect(value).toEqual({ name: "Ada" });
5140
+ * ```
5141
+ *
4612
5142
  * @group JSON
4613
5143
  */
4614
5144
  export declare const jsonToJsonValue: (value: Json) => JsonValue;
4615
5145
  /**
4616
5146
  * Totally encodes an exact {@link JsonValue} as canonical {@link Json} text.
4617
5147
  *
5148
+ * ### Example
5149
+ *
5150
+ * ```ts
5151
+ * import { jsonValueToJson, type JsonValue } from "@evolu/common";
5152
+ *
5153
+ * const value: JsonValue = { name: "Ada" };
5154
+ *
5155
+ * expect(jsonValueToJson(value)).toBe('{"name":"Ada"}');
5156
+ * ```
5157
+ *
4618
5158
  * @group JSON
4619
5159
  */
4620
5160
  export declare const jsonValueToJson: (value: JsonValue) => Json;
4621
5161
  /**
4622
- * {@link Json} to {@link JsonValue} transformation.
5162
+ * Transformation {@link Type} that parses {@link Json} into {@link JsonValue}.
4623
5163
  *
4624
5164
  * Decoding unknown input first validates the Json Brand. Starting from the
4625
5165
  * typed Json parent is infallible. Encoding canonicalizes JSON text.
4626
5166
  *
5167
+ * ### Example
5168
+ *
5169
+ * ```ts
5170
+ * import { JsonValueFromJson } from "@evolu/common";
5171
+ *
5172
+ * const result = JsonValueFromJson.fromUnknown('{ "name": "Ada" }');
5173
+ *
5174
+ * expectOk(result, { name: "Ada" });
5175
+ * expect(JsonValueFromJson.to(result.value)).toBe('{"name":"Ada"}');
5176
+ * ```
5177
+ *
4627
5178
  * @group JSON
4628
5179
  */
4629
5180
  export declare const JsonValueFromJson: TransformType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Json", JsonError>, JsonValueType, "JsonValueFromJson", never, string & Brand<"Json">>;