@evolu/common 8.2.0 → 8.3.1

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 +1322 -793
  24. package/dist/src/Type.d.ts.map +1 -1
  25. package/dist/src/Type.js +1192 -244
  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 +1759 -794
  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,16 +71,42 @@ 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
430
- * message. Built-in Types use English; {@link localizeTypes} derives Types
91
+ * message. Predefined Types use English; {@link localizeTypes} derives Types
431
92
  * with localized formatters.
432
93
  *
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; missing
380
+ * 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. The
433
+ * 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 results
742
+ * are asserted against the declared boundary so a broken callback fails as a
743
+ * 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,30 @@ 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 { Boolean, literal, ok, transform, union } from "@evolu/common";
947
760
  *
948
- * const NumberFromString = transform("NumberFromString", String, Number, {
949
- * from: (value) => ok(globalThis.Number(value)),
950
- * to: globalThis.String,
951
- * });
761
+ * const BooleanString = union(literal("false"), literal("true"));
762
+ * const BooleanFromString = transform(
763
+ * "BooleanFromString",
764
+ * BooleanString,
765
+ * Boolean,
766
+ * {
767
+ * from: (value) => ok(value === "true"),
768
+ * to: (value) => (value ? "true" : "false"),
769
+ * },
770
+ * );
952
771
  *
953
- * expectOk(NumberFromString.from.parent("42"), 42);
954
- * assert(NumberFromString.to(42) === "42");
772
+ * expectOk(BooleanFromString.from.parent("true"), true);
773
+ * expect(BooleanFromString.to(false)).toBe("false");
955
774
  * ```
956
775
  *
957
- * @group Type construction
776
+ * @group Construction
958
777
  */
959
778
  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
779
  readonly from: (value: ParentType["Output"]) => Result<OutputType["Input"], never>;
961
780
  readonly to: (value: CanonicalInputOf<OutputType>) => ToOutput;
962
781
  }): TransformType<ParentType, OutputType, Name, never, ToOutput>;
782
+ /** Creates a fallible transformed Type with its own error formatter. */
963
783
  export declare function transform<Name extends TypeName, ParentType extends ConcreteTypeNode, OutputType extends ConcreteTypeNode, ToOutput extends ParentType["Output"], FromError extends {
964
784
  readonly type: Name;
965
785
  readonly outputError?: never;
@@ -967,17 +787,26 @@ export declare function transform<Name extends TypeName, ParentType extends Conc
967
787
  readonly from: (value: ParentType["Output"]) => Result<OutputType["Input"], FromError>;
968
788
  readonly to: (value: CanonicalInputOf<OutputType>) => ToOutput;
969
789
  }, formatError: [FromError] extends [never] ? never : TypeErrorFormatter<NoInfer<FromError>>): TransformType<ParentType, OutputType, Name, FromError, ToOutput>;
970
- /** @group Type construction */
790
+ /**
791
+ * The {@link Type} returned by {@link transform}.
792
+ *
793
+ * @group Construction
794
+ */
971
795
  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
796
  readonly [reflectedTypesSymbol]?: OutputType;
973
797
  readonly output: OutputType;
974
798
  }
975
- /** @group Type construction */
799
+ /**
800
+ * An error produced by {@link transform} while decoding or validating its
801
+ * output.
802
+ *
803
+ * @group Construction
804
+ */
976
805
  export type TransformError<Name extends TypeName, OwnError extends TypeError<Name>, OutputError extends TypeError> = OwnError | ([OutputError] extends [never] ? never : TransformOutputError<Name, OutputError>);
977
806
  /**
978
807
  * Wraps an error produced by the output {@link Type} of {@link transform}.
979
808
  *
980
- * @group Type construction
809
+ * @group Construction
981
810
  */
982
811
  export interface TransformOutputError<Name extends TypeName, OutputError extends TypeError> extends TypeError<Name>, TransparentTypeError {
983
812
  /** The error returned by the output Type. */
@@ -990,10 +819,23 @@ type DeepestFromError<Operation> = DeepestFromOperation<Operation> extends (...a
990
819
  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
820
  declare const templateLiteralSyntaxSymbolType: unique symbol;
992
821
  declare const templateLiteralSyntaxSymbol: typeof templateLiteralSyntaxSymbolType;
993
- /** @group Base Types */
822
+ /**
823
+ * An infallible {@link Type} accepting every value.
824
+ *
825
+ * @group Base
826
+ */
994
827
  export declare const Unknown: Type<"Unknown", unknown, unknown, never, null, never, never, unknown, true>;
995
- /** @group Base Types */
828
+ /**
829
+ * A {@link Type} rejecting every value.
830
+ *
831
+ * @group Base
832
+ */
996
833
  export declare const Never: Type<"Never", never, never, NeverError, null, NeverError, never, never, true>;
834
+ /**
835
+ * Error returned by {@link Never} for every value.
836
+ *
837
+ * @group Base
838
+ */
997
839
  export interface NeverError extends TypeError<"Never"> {
998
840
  readonly value: unknown;
999
841
  }
@@ -1005,7 +847,11 @@ interface TypeOfOutputByName {
1005
847
  readonly Symbol: symbol;
1006
848
  readonly Function: globalThis.Function;
1007
849
  }
1008
- /** @group Base Types */
850
+ /**
851
+ * Error returned when `typeof` does not match the expected JavaScript type.
852
+ *
853
+ * @group Base
854
+ */
1009
855
  export interface TypeOfError<Name extends keyof TypeOfOutputByName> extends TypeError<"TypeOf"> {
1010
856
  readonly expected: Name;
1011
857
  readonly value: unknown;
@@ -1033,6 +879,8 @@ export interface TypeOfError<Name extends keyof TypeOfOutputByName> extends Type
1033
879
  * expectTypeOf<WireValue100>().toEqualTypeOf<
1034
880
  * string & Brand<"MaxLength100">
1035
881
  * >();
882
+ * expectOk(WireValue100.fromUnknown(""), "");
883
+ * expectOk(WireValue100.fromUnknown(" value "), " value ");
1036
884
  * ```
1037
885
  *
1038
886
  * @group String
@@ -1107,21 +955,37 @@ export declare const String: Type<"String", string, string, TypeOfError<"String"
1107
955
  * @group Number
1108
956
  */
1109
957
  export declare const Number: Type<"Number", number, number, TypeOfError<"Number">, null, TypeOfError<"Number">, never, number, true>;
1110
- /** @group Base Types */
958
+ /**
959
+ * A JavaScript bigint {@link Type}.
960
+ *
961
+ * @group Base
962
+ */
1111
963
  export declare const BigInt: Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>;
1112
- /** @group Base Types */
964
+ /**
965
+ * A JavaScript boolean {@link Type}.
966
+ *
967
+ * @group Base
968
+ */
1113
969
  export declare const Boolean: Type<"Boolean", boolean, boolean, TypeOfError<"Boolean">, null, TypeOfError<"Boolean">, never, boolean, true>;
1114
- /** @group Base Types */
970
+ /**
971
+ * A JavaScript symbol {@link Type}.
972
+ *
973
+ * @group Base
974
+ */
1115
975
  export declare const Symbol: Type<"Symbol", symbol, symbol, TypeOfError<"Symbol">, null, TypeOfError<"Symbol">, never, symbol, true>;
1116
- /** @group Base Types */
976
+ /**
977
+ * A JavaScript function {@link Type}.
978
+ *
979
+ * @group Base
980
+ */
1117
981
  export declare const Function: Type<"Function", Function, Function, TypeOfError<"Function">, null, TypeOfError<"Function">, never, Function, true>;
1118
982
  /**
1119
- * An Evolu {@link Type} validating other Evolu Types.
983
+ * A {@link Type} validating Evolu Type declarations.
1120
984
  *
1121
985
  * This is useful when a Type itself crosses an unknown boundary or must be
1122
986
  * asserted with {@link assertType}.
1123
987
  *
1124
- * @group Core Types
988
+ * @group Core
1125
989
  */
1126
990
  export declare const EvoluType: Type<"EvoluType", AnyType, AnyType, EvoluTypeError, null, EvoluTypeError, never, AnyType, true>;
1127
991
  /**
@@ -1134,22 +998,22 @@ export declare const EvoluType: Type<"EvoluType", AnyType, AnyType, EvoluTypeErr
1134
998
  * the recursive `TypeNode` shape so composing Types does not repeatedly add its
1135
999
  * compiler cost; {@link EvoluType} bridges that runtime evidence to this type.
1136
1000
  *
1137
- * @group Core Types
1001
+ * @group Core
1138
1002
  */
1139
1003
  export interface AnyType extends TypeNode {
1140
1004
  readonly [concreteTypeSymbol]: true;
1141
1005
  }
1142
1006
  /**
1143
- * Error returned when a value is not an Evolu {@link Type}.
1007
+ * Error returned when {@link EvoluType} rejects a value.
1144
1008
  *
1145
- * @group Core Types
1009
+ * @group Core
1146
1010
  */
1147
1011
  export interface EvoluTypeError extends TypeValueError<"EvoluType"> {
1148
1012
  }
1149
1013
  /**
1150
1014
  * Nominal evidence that a value has one object tag.
1151
1015
  *
1152
- * @group Base Types
1016
+ * @group Base
1153
1017
  */
1154
1018
  export interface ObjectTag<Name extends TypeName> {
1155
1019
  readonly [objectTagSymbol]: Name;
@@ -1157,7 +1021,7 @@ export interface ObjectTag<Name extends TypeName> {
1157
1021
  /**
1158
1022
  * The {@link Type} returned by {@link objectTag}.
1159
1023
  *
1160
- * @group Base Types
1024
+ * @group Base
1161
1025
  */
1162
1026
  export interface ObjectTagType<Name extends TypeName, OutputType extends TypeNode & {
1163
1027
  readonly Output: object;
@@ -1168,7 +1032,7 @@ export interface ObjectTagType<Name extends TypeName, OutputType extends TypeNod
1168
1032
  /**
1169
1033
  * An error returned when an object does not report the expected tag.
1170
1034
  *
1171
- * @group Base Types
1035
+ * @group Base
1172
1036
  */
1173
1037
  export interface ObjectTagError<Expected extends TypeName = TypeName> extends TypeError<"ObjectTag"> {
1174
1038
  readonly expected: Expected;
@@ -1182,22 +1046,34 @@ interface ObjectTagOutputByName {
1182
1046
  /**
1183
1047
  * Realm-neutral {@link Type} trusting an object's reported tag.
1184
1048
  *
1185
- * Predefined built-in tags expose their native Output type under the assumption
1186
- * that trusted code does not forge their tags. They do not verify native
1187
- * internal slots. A custom tag refines the supplied Type and adds nominal
1188
- * evidence to its Output, so only a value validated by the resulting Type is
1189
- * accepted by its typed operations.
1049
+ * Predefined tags for JavaScript built-ins expose their native Output type
1050
+ * under the assumption that trusted code does not forge their tags. They do not
1051
+ * verify native internal slots. A custom tag refines the supplied Type and adds
1052
+ * nominal evidence to its Output, so only a value validated by the resulting
1053
+ * Type is accepted by its typed operations.
1054
+ *
1055
+ * `Object.prototype.toString` recognizes legitimate JavaScript built-ins from
1056
+ * another realm, but any object can customize the result with
1057
+ * `Symbol.toStringTag`. Types returned by this factory therefore classify
1058
+ * trusted values; they are not security boundaries. Passing a forged JavaScript
1059
+ * built-in tag violates the trust assumption of the predefined Type. Primitive
1060
+ * Outputs are rejected at compile time.
1061
+ *
1062
+ * ### Example
1063
+ *
1064
+ * ```ts
1065
+ * import { objectTag } from "@evolu/common";
1066
+ *
1067
+ * const DateType = objectTag("Date");
1068
+ * const date = new globalThis.Date("2025-01-01T00:00:00.000Z");
1190
1069
  *
1191
- * `Object.prototype.toString` recognizes legitimate built-ins from another
1192
- * realm, but any object can customize the result with `Symbol.toStringTag`.
1193
- * Types returned by this factory therefore classify trusted values; they are
1194
- * not security boundaries. Passing a forged built-in tag violates the trust
1195
- * assumption of the predefined Type. Primitive Outputs are rejected at compile
1196
- * time.
1070
+ * expectOk(DateType.fromUnknown(date), date);
1071
+ * ```
1197
1072
  *
1198
- * @group Base Types
1073
+ * @group Base
1199
1074
  */
1200
1075
  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]>;
1076
+ /** Creates an object-tag Type by refining an existing object Type. */
1201
1077
  export declare function objectTag<Name extends TypeName, OutputType extends ConcreteTypeNode & {
1202
1078
  readonly Output: object;
1203
1079
  }>(name: ValidateConcreteTypeName<Name>, outputType: ValidateOutput<OutputType> & ([ChildTypeNameValidationError<"ObjectTag", OutputType>] extends [never] ? unknown : ChildTypeNameValidationError<"ObjectTag", OutputType>)): ObjectTagType<Name, OutputType>;
@@ -1207,7 +1083,7 @@ declare const objectTagSymbol: unique symbol;
1207
1083
  *
1208
1084
  * It trusts the reported object tag and does not verify Date internal slots.
1209
1085
  *
1210
- * @group Base Types
1086
+ * @group Base
1211
1087
  */
1212
1088
  export declare const Date: Type<"Date", Date, Date, ObjectTagError<"Date">, null, ObjectTagError<"Date">, never, Date, true>;
1213
1089
  /**
@@ -1216,7 +1092,7 @@ export declare const Date: Type<"Date", Date, Date, ObjectTagError<"Date">, null
1216
1092
  * It trusts the reported object tag and does not verify Uint8Array internal
1217
1093
  * slots.
1218
1094
  *
1219
- * @group Base Types
1095
+ * @group Base
1220
1096
  */
1221
1097
  export declare const Uint8Array: Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, ObjectTagError<"Uint8Array">, null, ObjectTagError<"Uint8Array">, never, Uint8Array<ArrayBufferLike>, true>;
1222
1098
  /**
@@ -1225,7 +1101,7 @@ export declare const Uint8Array: Type<"Uint8Array", Uint8Array<ArrayBufferLike>,
1225
1101
  * It trusts the reported object tag and does not verify ArrayBuffer internal
1226
1102
  * slots.
1227
1103
  *
1228
- * @group Base Types
1104
+ * @group Base
1229
1105
  */
1230
1106
  export declare const ArrayBuffer: Type<"ArrayBuffer", ArrayBuffer, ArrayBuffer, ObjectTagError<"ArrayBuffer">, null, ObjectTagError<"ArrayBuffer">, never, ArrayBuffer, true>;
1231
1107
  /**
@@ -1256,25 +1132,33 @@ export declare const ArrayBuffer: Type<"ArrayBuffer", ArrayBuffer, ArrayBuffer,
1256
1132
  * assert(!UserInstance.is({ name: "Ada" }));
1257
1133
  * ```
1258
1134
  *
1259
- * @group Base Types
1135
+ * @group Base
1260
1136
  */
1261
1137
  export declare const instanceOf: <Constructor extends InstanceConstructor>(constructor: ValidateInstanceConstructor<Constructor>) => InstanceOfType<Constructor>;
1262
1138
  /**
1263
1139
  * A JavaScript class constructor accepted by {@link instanceOf}.
1264
1140
  *
1265
- * @group Base Types
1141
+ * @group Base
1266
1142
  */
1267
1143
  export type InstanceConstructor<Instance extends object = object> = (abstract new (...args: ReadonlyArray<never>) => Instance) & {
1268
1144
  readonly name: string;
1269
1145
  };
1270
- /** @group Base Types */
1146
+ /**
1147
+ * The {@link Type} returned by {@link instanceOf}.
1148
+ *
1149
+ * @group Base
1150
+ */
1271
1151
  export interface InstanceOfType<Constructor extends InstanceConstructor> extends Type<"InstanceOf", InstanceOfOutput<Constructor>, InstanceOfOutput<Constructor>, InstanceOfError, null, InstanceOfError, never, InstanceOfOutput<Constructor>> {
1272
1152
  readonly constructor: Constructor;
1273
1153
  }
1274
1154
  type InstanceOfOutput<Constructor extends InstanceConstructor> = Constructor extends {
1275
1155
  readonly prototype: infer Output extends object;
1276
1156
  } ? Output : InstanceType<Constructor>;
1277
- /** @group Base Types */
1157
+ /**
1158
+ * Error returned when a value is not an instance of the expected constructor.
1159
+ *
1160
+ * @group Base
1161
+ */
1278
1162
  export interface InstanceOfError extends TypeValueError<"InstanceOf"> {
1279
1163
  readonly constructorName: string;
1280
1164
  }
@@ -1311,7 +1195,11 @@ type InstanceConstructorCompileTimeError = CompileTimeError<"Type", "Constructor
1311
1195
  * @group Unions
1312
1196
  */
1313
1197
  export declare const literal: <const Expected extends Literal>(expected: ValidateLiteral<Expected>) => LiteralType<Expected>;
1314
- /** @group Unions */
1198
+ /**
1199
+ * The {@link Type} returned by {@link literal}.
1200
+ *
1201
+ * @group Unions
1202
+ */
1315
1203
  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
1204
  readonly [templateLiteralSyntaxSymbol]: true;
1317
1205
  readonly expected: Expected;
@@ -1320,14 +1208,26 @@ type LiteralParent<Expected extends Literal> = Expected extends string ? typeof
1320
1208
  type LiteralParentErrors<Expected extends Literal> = LiteralParent<Expected> extends infer Parent extends TypeNode ? InferErrors<Parent> : never;
1321
1209
  type ValidateLiteral<Expected extends Literal> = IsUnion<Expected> extends false ? {} extends Readonly<Record<`${Expected}`, never>> ? LiteralCompileTimeError : Expected : LiteralCompileTimeError;
1322
1210
  type LiteralCompileTimeError = CompileTimeError<"Type", "Expected must be one concrete literal value.">;
1323
- /** @group Unions */
1211
+ /**
1212
+ * Error returned when a value does not equal the expected literal.
1213
+ *
1214
+ * @group Unions
1215
+ */
1324
1216
  export interface LiteralError<Expected extends Literal = Literal> extends TypeError<"Literal"> {
1325
1217
  readonly expected: Expected;
1326
1218
  readonly value: unknown;
1327
1219
  }
1328
- /** @group Unions */
1220
+ /**
1221
+ * Literal {@link Type} accepting only `undefined`.
1222
+ *
1223
+ * @group Unions
1224
+ */
1329
1225
  export declare const Undefined: LiteralType<undefined>;
1330
- /** @group Unions */
1226
+ /**
1227
+ * Literal {@link Type} accepting only `null`.
1228
+ *
1229
+ * @group Unions
1230
+ */
1331
1231
  export declare const Null: LiteralType<null>;
1332
1232
  /**
1333
1233
  * Union {@link Type}.
@@ -1352,7 +1252,10 @@ export declare const Null: LiteralType<null>;
1352
1252
  * within each member.
1353
1253
  *
1354
1254
  * Member order matters when multiple members accept the same value: validation
1355
- * and encoding use the first matching member.
1255
+ * and encoding use the first matching member. When member Inputs overlap,
1256
+ * decoding the value emitted by the first member selected for an Output must
1257
+ * reproduce that semantic Output; otherwise the Union violates the round-trip
1258
+ * law.
1356
1259
  *
1357
1260
  * ### Example
1358
1261
  *
@@ -1389,9 +1292,11 @@ export declare function union<const Expected extends AtLeastTwoReadonlyArray<Lit
1389
1292
  }): UnionType<{
1390
1293
  readonly [Index in keyof Expected]: LiteralType<Expected[Index]>;
1391
1294
  }>;
1295
+ /** Creates a Union Type from Type members. */
1392
1296
  export declare function union<const Members extends AtLeastTwoReadonlyArray<TypeNode>>(...members: {
1393
1297
  readonly [Index in keyof Members]: ValidateUnionTypeMember<Members[Index]>;
1394
1298
  }): UnionType<Members>;
1299
+ /** Creates a Union Type from Type and literal members. */
1395
1300
  export declare function union<const Members extends AtLeastTwoReadonlyArray<TypeNode | Literal>>(...members: {
1396
1301
  readonly [Index in keyof Members]: ValidateUnionMember<Members[Index]>;
1397
1302
  }): UnionType<NormalizeUnionMembers<Members>>;
@@ -1401,18 +1306,49 @@ export declare function union<const Members extends AtLeastTwoReadonlyArray<Type
1401
1306
  * This does not make an object property optional. It changes only the values
1402
1307
  * accepted when the property is present.
1403
1308
  *
1309
+ * ### Example
1310
+ *
1311
+ * ```ts
1312
+ * import { String, undefinedOr } from "@evolu/common";
1313
+ *
1314
+ * const StringOrUndefined = undefinedOr(String);
1315
+ *
1316
+ * expectOk(StringOrUndefined.fromUnknown(undefined), undefined);
1317
+ * ```
1318
+ *
1404
1319
  * @group Unions
1405
1320
  */
1406
1321
  export declare const undefinedOr: <ValueType extends TypeNode>(type: ValidateUnionTypeMember<ValueType>) => UnionType<readonly [ValueType, typeof Undefined]>;
1407
1322
  /**
1408
1323
  * Union {@link Type} containing the supplied Type and `null`.
1409
1324
  *
1325
+ * ### Example
1326
+ *
1327
+ * ```ts
1328
+ * import { String, nullOr } from "@evolu/common";
1329
+ *
1330
+ * const NullableString = nullOr(String);
1331
+ *
1332
+ * expectOk(NullableString.fromUnknown(null), null);
1333
+ * ```
1334
+ *
1410
1335
  * @group Unions
1411
1336
  */
1412
1337
  export declare const nullOr: <ValueType extends TypeNode>(type: ValidateUnionTypeMember<ValueType>) => UnionType<readonly [ValueType, typeof Null]>;
1413
1338
  /**
1414
1339
  * Union {@link Type} containing the supplied Type, `null`, and `undefined`.
1415
1340
  *
1341
+ * ### Example
1342
+ *
1343
+ * ```ts
1344
+ * import { String, nullishOr } from "@evolu/common";
1345
+ *
1346
+ * const NullishString = nullishOr(String);
1347
+ *
1348
+ * expectOk(NullishString.fromUnknown(undefined), undefined);
1349
+ * expectOk(NullishString.fromUnknown(null), null);
1350
+ * ```
1351
+ *
1416
1352
  * @group Unions
1417
1353
  */
1418
1354
  export declare const nullishOr: <ValueType extends TypeNode>(type: ValidateUnionTypeMember<ValueType>) => UnionType<readonly [ValueType, typeof Null, typeof Undefined]>;
@@ -1424,7 +1360,11 @@ type UnionMemberConcreteTypeError = CompileTimeError<"Type", "Union member must
1424
1360
  type NormalizeUnionMembers<Members extends AtLeastTwoReadonlyArray<TypeNode | Literal>> = {
1425
1361
  readonly [Index in keyof Members]: Members[Index] extends TypeNode ? Members[Index] : Members[Index] extends Literal ? LiteralType<Members[Index]> : never;
1426
1362
  } extends infer Normalized extends AtLeastTwoReadonlyArray<TypeNode> ? Normalized : never;
1427
- /** @group Unions */
1363
+ /**
1364
+ * The {@link Type} returned by {@link union}.
1365
+ *
1366
+ * @group Unions
1367
+ */
1428
1368
  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
1369
  readonly [templateLiteralSyntaxSymbol]: true;
1430
1370
  readonly [reflectedTypesSymbol]?: Members[number];
@@ -1442,9 +1382,17 @@ type UnionInputTypeError<Members extends AtLeastTwoReadonlyArray<TypeNode>, Root
1442
1382
  type RootUnionMembers<Members extends AtLeastTwoReadonlyArray<TypeNode>> = {
1443
1383
  readonly [Index in keyof Members]: RootType<Members[Index]>;
1444
1384
  } extends infer RootMembers extends AtLeastTwoReadonlyArray<TypeNode> ? RootMembers : never;
1445
- /** @group Unions */
1385
+ /**
1386
+ * Error returned when every member of a {@link union} rejects an input.
1387
+ *
1388
+ * @group Unions
1389
+ */
1446
1390
  export type UnionError<Error extends TypeError = TypeError, MemberError extends UnionMemberError<Error> = UnionMemberError<Error>> = [Error] extends [never] ? never : UnionErrorValue<Error, MemberError>;
1447
- /** @group Unions */
1391
+ /**
1392
+ * An error returned by one {@link union} member and its index.
1393
+ *
1394
+ * @group Unions
1395
+ */
1448
1396
  export interface UnionMemberError<Error extends TypeError, Index extends number = number> {
1449
1397
  readonly index: Index;
1450
1398
  readonly error: Error;
@@ -1472,9 +1420,7 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
1472
1420
  readonly errors: NonEmptyReadonlyArray<MemberError>;
1473
1421
  }
1474
1422
  /**
1475
- * Template literal {@link Type} for validation and parsing.
1476
- *
1477
- * Parses and creates structured strings.
1423
+ * Template literal {@link Type} that parses canonical strings into Tuples.
1478
1424
  *
1479
1425
  * Accepts the same template parts as {@link templateLiteral}: fixed string
1480
1426
  * literals and Types canonically encoded as strings. Instead of keeping Output
@@ -1490,10 +1436,10 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
1490
1436
  * reversibility and keeps capture boundaries unambiguous. Different capture
1491
1437
  * Tuples must never encode to the same string. The parser provides predictable
1492
1438
  * 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.
1439
+ * adversarial input cannot trigger exponential parser work. Fixed-width
1440
+ * captures may be adjacent, but only one variable-width capture is allowed.
1441
+ * Declarations that could join UTF-16 surrogate halves across parts are
1442
+ * rejected during construction.
1497
1443
  *
1498
1444
  * Keep capture unions reasonably small to avoid excessive compiler work.
1499
1445
  *
@@ -1530,10 +1476,9 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
1530
1476
  *
1531
1477
  * // Parse an unknown string into structured data.
1532
1478
  * const result = SupportedLocale.fromUnknown("cs-CZ");
1533
- * assert(result.ok);
1479
+ * expectOk(result, ["cs", "CZ"]);
1534
1480
  * const locale = result.value;
1535
1481
  * expectTypeOf(locale).toEqualTypeOf<SupportedLocale>();
1536
- * expect(locale).toEqual(["cs", "CZ"]);
1537
1482
  * expectErr(SupportedLocale.fromUnknown("cs/CZ"), {
1538
1483
  * type: "TemplateLiteral",
1539
1484
  * value: "cs/CZ",
@@ -1592,10 +1537,9 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
1592
1537
  *
1593
1538
  * // Decode the string into structured data.
1594
1539
  * const result = ItemId.fromUnknown("item-42");
1595
- * assert(result.ok);
1540
+ * expectOk(result, [42n]);
1596
1541
  * const itemId = result.value;
1597
1542
  * expectTypeOf(itemId).toEqualTypeOf<ItemId>();
1598
- * expect(itemId).toEqual([42n]);
1599
1543
  *
1600
1544
  * // Encode the structured data into its canonical string.
1601
1545
  * const itemIdLiteral = ItemId.to(itemId);
@@ -1645,14 +1589,22 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
1645
1589
  * @group Template literals
1646
1590
  */
1647
1591
  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 */
1592
+ /**
1593
+ * The parsing {@link Type} returned by {@link templateLiteralParser}.
1594
+ *
1595
+ * @group Template literals
1596
+ */
1649
1597
  export interface TemplateLiteralParserType<Parts extends TemplateLiteralParts> extends Type<"TemplateLiteral", string, TemplateLiteralCaptureTuple<Parts>["Output"], never, TemplateLiteralType<Parts>, InferErrors<TemplateLiteralType<Parts>>, never, TemplateLiteralStringOutput<Parts>, false> {
1650
1598
  readonly [templateLiteralSyntaxSymbol]: true;
1651
1599
  readonly [reflectedTypesSymbol]?: TemplateLiteralCaptureTuple<Parts>;
1652
1600
  readonly output: TemplateLiteralCaptureTuple<Parts>;
1653
1601
  readonly parts: Parts;
1654
1602
  }
1655
- /** @group Template literals */
1603
+ /**
1604
+ * The validating string {@link Type} returned by {@link templateLiteral}.
1605
+ *
1606
+ * @group Template literals
1607
+ */
1656
1608
  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
1609
  readonly [templateLiteralSyntaxSymbol]: true;
1658
1610
  readonly [reflectedTypesSymbol]?: TemplateLiteralCaptureTuple<Parts>;
@@ -1665,8 +1617,8 @@ export interface TemplateLiteralType<Parts extends TemplateLiteralParts> extends
1665
1617
  * Creates a canonical string Type from fixed strings and string-encoded Types.
1666
1618
  *
1667
1619
  * 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.
1620
+ * {@link templateLiteralParser} when the individual Type parts should be decoded
1621
+ * into a Tuple.
1670
1622
  *
1671
1623
  * ### Example
1672
1624
  *
@@ -1690,7 +1642,11 @@ export declare const templateLiteral: <const Parts extends TemplateLiteralParts>
1690
1642
  type TemplateLiteralParseError<Parts extends TemplateLiteralParts> = TransformError<"TemplateLiteral", TemplateLiteralIsFrameless<Parts> extends true ? never : TemplateLiteralError, TemplateLiteralCaptureTupleError<Parts>>;
1691
1643
  type TemplateLiteralCaptureTupleError<Parts extends TemplateLiteralParts> = TupleElementsError<TemplateLiteralCaptureFromStringError<TemplateLiteralCaptureTypes<Parts>[number]>>;
1692
1644
  type TemplateLiteralCaptureFromStringError<T extends TypeNode> = T extends TypeNode ? string extends RootType<T>["Output"] ? TypeFromError<T> : InferErrors<T> : never;
1693
- /** @group Template literals */
1645
+ /**
1646
+ * Error returned when a string does not match a template literal declaration.
1647
+ *
1648
+ * @group Template literals
1649
+ */
1694
1650
  export interface TemplateLiteralError extends TypeError<"TemplateLiteral"> {
1695
1651
  readonly value: string;
1696
1652
  }
@@ -1780,72 +1736,19 @@ type TemplateLiteralStringWidth<Value extends string, Width extends ReadonlyArra
1780
1736
  * });
1781
1737
  * ```
1782
1738
  *
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
- * ```
1739
+ * To reuse and compose a Brand constraint with different parent Types, define a
1740
+ * {@link BrandFactory}.
1843
1741
  *
1844
- * @group Type construction
1742
+ * @group Construction
1845
1743
  */
1846
1744
  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>;
1745
+ /** Creates a validated Brand Type with its own error formatter. */
1847
1746
  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 */
1747
+ /**
1748
+ * The {@link Type} returned by {@link brand}.
1749
+ *
1750
+ * @group Construction
1751
+ */
1849
1752
  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
1753
  }
1851
1754
  /**
@@ -1878,17 +1781,37 @@ export interface BrandType<ParentType extends TypeNode, Name extends TypeName, E
1878
1781
  */
1879
1782
  export declare const DateIso: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DateIso", DateIsoError>;
1880
1783
  export type DateIso = typeof DateIso.Output;
1881
- /** @group String */
1784
+ /**
1785
+ * Error returned when a string is not a canonical {@link DateIso}.
1786
+ *
1787
+ * @group String
1788
+ */
1882
1789
  export interface DateIsoError extends TypeError<"DateIso"> {
1883
1790
  readonly value: string;
1884
1791
  }
1885
1792
  /**
1886
1793
  * Safely transforms a {@link Date} into a canonical {@link DateIso}.
1887
1794
  *
1795
+ * ### Example
1796
+ *
1797
+ * ```ts
1798
+ * import { DateIsoFromDate } from "@evolu/common";
1799
+ *
1800
+ * const date = new globalThis.Date("2025-01-01T12:00:00.000Z");
1801
+ * const result = DateIsoFromDate.fromUnknown(date);
1802
+ *
1803
+ * expectOk(result, "2025-01-01T12:00:00.000Z");
1804
+ * expect(DateIsoFromDate.to(result.value)).toEqual(date);
1805
+ * ```
1806
+ *
1888
1807
  * @group String
1889
1808
  */
1890
1809
  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 */
1810
+ /**
1811
+ * Error returned when a {@link Date} cannot be represented as {@link DateIso}.
1812
+ *
1813
+ * @group String
1814
+ */
1892
1815
  export interface DateIsoFromDateError extends TypeError<"DateIsoFromDate"> {
1893
1816
  readonly value: globalThis.Date;
1894
1817
  }
@@ -1899,7 +1822,11 @@ export interface DateIsoFromDateError extends TypeError<"DateIsoFromDate"> {
1899
1822
  */
1900
1823
  export declare const Int64: BrandType<Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>, "Int64", Int64Error>;
1901
1824
  export type Int64 = typeof Int64.Output;
1902
- /** @group Number */
1825
+ /**
1826
+ * Error returned when a bigint is outside the signed 64-bit {@link Int64} range.
1827
+ *
1828
+ * @group Number
1829
+ */
1903
1830
  export interface Int64Error extends TypeError<"Int64"> {
1904
1831
  readonly value: bigint;
1905
1832
  }
@@ -1910,7 +1837,12 @@ export interface Int64Error extends TypeError<"Int64"> {
1910
1837
  */
1911
1838
  export declare const UInt64: BrandType<Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>, "UInt64", UInt64Error>;
1912
1839
  export type UInt64 = typeof UInt64.Output;
1913
- /** @group Number */
1840
+ /**
1841
+ * Error returned when a bigint is outside the unsigned 64-bit {@link UInt64}
1842
+ * range.
1843
+ *
1844
+ * @group Number
1845
+ */
1914
1846
  export interface UInt64Error extends TypeError<"UInt64"> {
1915
1847
  readonly value: bigint;
1916
1848
  }
@@ -1966,7 +1898,7 @@ export interface UInt64Error extends TypeError<"UInt64"> {
1966
1898
  * For numeric parameters encoded in a Brand name, use
1967
1899
  * {@link ValidateBrandFactoryNumber}.
1968
1900
  *
1969
- * @group Type construction
1901
+ * @group Construction
1970
1902
  */
1971
1903
  export type BrandFactory<Name extends TypeName, Value, Error extends TypeError<Name>> = <ParentType extends ConcreteTypeNode & {
1972
1904
  readonly Output: Value;
@@ -2031,7 +1963,7 @@ export type BrandFactory<Name extends TypeName, Value, Error extends TypeError<N
2031
1963
  * lessThan(100 - 1)(Number);
2032
1964
  * ```
2033
1965
  *
2034
- * @group Type utilities
1966
+ * @group Construction
2035
1967
  */
2036
1968
  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
1969
  type BrandFactoryNumberError = CompileTimeError<"Brand Factory", "Parameter must be one concrete numeric literal instead of a widened, union, or branded number.">;
@@ -2062,7 +1994,11 @@ type BrandFactoryNumberError = CompileTimeError<"Brand Factory", "Parameter must
2062
1994
  * @group String
2063
1995
  */
2064
1996
  export declare const capitalized: BrandFactory<"Capitalized", string, CapitalizedError>;
2065
- /** @group String */
1997
+ /**
1998
+ * Error returned when {@link capitalized} rejects a string.
1999
+ *
2000
+ * @group String
2001
+ */
2066
2002
  export interface CapitalizedError extends TypeError<"Capitalized"> {
2067
2003
  readonly value: string;
2068
2004
  }
@@ -2076,10 +2012,24 @@ export type CapitalizedString = typeof CapitalizedString.Output;
2076
2012
  /**
2077
2013
  * String {@link Brand} without surrounding whitespace.
2078
2014
  *
2015
+ * ### Example
2016
+ *
2017
+ * ```ts
2018
+ * import { String, trimmed } from "@evolu/common";
2019
+ *
2020
+ * const Trimmed = trimmed(String);
2021
+ *
2022
+ * expectOk(Trimmed.fromUnknown("Evolu"), "Evolu");
2023
+ * ```
2024
+ *
2079
2025
  * @group String
2080
2026
  */
2081
2027
  export declare const trimmed: BrandFactory<"Trimmed", string, TrimmedError>;
2082
- /** @group String */
2028
+ /**
2029
+ * Error returned when {@link trimmed} rejects a string.
2030
+ *
2031
+ * @group String
2032
+ */
2083
2033
  export interface TrimmedError extends TypeError<"Trimmed"> {
2084
2034
  readonly value: string;
2085
2035
  }
@@ -2099,17 +2049,41 @@ export type TrimmedString = typeof TrimmedString.Output;
2099
2049
  /**
2100
2050
  * Trims a string and returns a {@link TrimmedString}.
2101
2051
  *
2052
+ * ### Example
2053
+ *
2054
+ * ```ts
2055
+ * import { trim } from "@evolu/common";
2056
+ *
2057
+ * expect(trim(" Evolu ")).toBe("Evolu");
2058
+ * ```
2059
+ *
2102
2060
  * @group String
2103
2061
  */
2104
2062
  export declare const trim: (value: string) => TrimmedString;
2105
2063
  /**
2106
- * Minimum-length {@link Brand} requiring a value to have at least `min` items.
2064
+ * Minimum-length {@link Brand} for values whose `length` is at least `min`.
2065
+ *
2066
+ * ### Example
2067
+ *
2068
+ * ```ts
2069
+ * import { String, array, minLength } from "@evolu/common";
2070
+ *
2071
+ * const AtLeastThreeCharacters = minLength(3)(String);
2072
+ * const AtLeastTwoItems = minLength(2)(array(String));
2073
+ *
2074
+ * expectOk(AtLeastThreeCharacters.fromUnknown("abc"), "abc");
2075
+ * expectOk(AtLeastTwoItems.fromUnknown(["a", "b"]), ["a", "b"]);
2076
+ * ```
2107
2077
  *
2108
2078
  * @group String
2109
2079
  * @group Collection
2110
2080
  */
2111
2081
  export declare const minLength: <Min extends number>(min: ValidateBrandFactoryNumber<Min>) => BrandFactory<`MinLength${Min}`, ValueWithLength, MinLengthError<Min>>;
2112
- /** @group Collection */
2082
+ /**
2083
+ * Error returned when {@link minLength} rejects a value.
2084
+ *
2085
+ * @group Collection
2086
+ */
2113
2087
  export interface MinLengthError<Min extends number = number> extends TypeError<`MinLength${Min}`> {
2114
2088
  readonly value: ValueWithLength;
2115
2089
  readonly min: Min;
@@ -2131,13 +2105,29 @@ export interface MinLengthError<Min extends number = number> extends TypeError<`
2131
2105
  export declare const NonEmptyTrimmedString: BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>;
2132
2106
  export type NonEmptyTrimmedString = typeof NonEmptyTrimmedString.Output;
2133
2107
  /**
2134
- * Maximum-length {@link Brand} requiring a value to have at most `max` items.
2108
+ * Maximum-length {@link Brand} for values whose `length` is at most `max`.
2109
+ *
2110
+ * ### Example
2111
+ *
2112
+ * ```ts
2113
+ * import { String, array, maxLength } from "@evolu/common";
2114
+ *
2115
+ * const AtMostThreeCharacters = maxLength(3)(String);
2116
+ * const AtMostTwoItems = maxLength(2)(array(String));
2117
+ *
2118
+ * expectOk(AtMostThreeCharacters.fromUnknown("abc"), "abc");
2119
+ * expectOk(AtMostTwoItems.fromUnknown(["a", "b"]), ["a", "b"]);
2120
+ * ```
2135
2121
  *
2136
2122
  * @group String
2137
2123
  * @group Collection
2138
2124
  */
2139
2125
  export declare const maxLength: <Max extends number>(max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`MaxLength${Max}`, ValueWithLength, MaxLengthError<Max>>;
2140
- /** @group Collection */
2126
+ /**
2127
+ * Error returned when {@link maxLength} rejects a value.
2128
+ *
2129
+ * @group Collection
2130
+ */
2141
2131
  export interface MaxLengthError<Max extends number = number> extends TypeError<`MaxLength${Max}`> {
2142
2132
  readonly value: ValueWithLength;
2143
2133
  readonly max: Max;
@@ -2157,13 +2147,29 @@ export type NonEmptyTrimmedString100 = typeof NonEmptyTrimmedString100.Output;
2157
2147
  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
2148
  export type NonEmptyTrimmedString1000 = typeof NonEmptyTrimmedString1000.Output;
2159
2149
  /**
2160
- * Exact-length {@link Brand} requiring a value to have exactly `exact` items.
2150
+ * Exact-length {@link Brand} for values whose `length` equals `exact`.
2151
+ *
2152
+ * ### Example
2153
+ *
2154
+ * ```ts
2155
+ * import { String, array, length } from "@evolu/common";
2156
+ *
2157
+ * const ThreeCharacters = length(3)(String);
2158
+ * const TwoItems = length(2)(array(String));
2159
+ *
2160
+ * expectOk(ThreeCharacters.fromUnknown("abc"), "abc");
2161
+ * expectOk(TwoItems.fromUnknown(["a", "b"]), ["a", "b"]);
2162
+ * ```
2161
2163
  *
2162
2164
  * @group String
2163
2165
  * @group Collection
2164
2166
  */
2165
2167
  export declare const length: <Exact extends number>(exact: ValidateBrandFactoryNumber<Exact>) => BrandFactory<`Length${Exact}`, ValueWithLength, LengthError<Exact>>;
2166
- /** @group Collection */
2168
+ /**
2169
+ * Error returned when {@link length} rejects a value.
2170
+ *
2171
+ * @group Collection
2172
+ */
2167
2173
  export interface LengthError<Exact extends number = number> extends TypeError<`Length${Exact}`> {
2168
2174
  readonly value: ValueWithLength;
2169
2175
  readonly exact: Exact;
@@ -2197,7 +2203,12 @@ export interface LengthError<Exact extends number = number> extends TypeError<`L
2197
2203
  * @group String
2198
2204
  */
2199
2205
  export declare const regex: <const Name extends TypeName>(name: ValidateConcreteTypeName<Name>, pattern: RegExp) => BrandFactory<Name, string, RegexError<Name>>;
2200
- /** @group String */
2206
+ /**
2207
+ * Error returned when a string does not match the regular expression supplied
2208
+ * to {@link regex}.
2209
+ *
2210
+ * @group String
2211
+ */
2201
2212
  export interface RegexError<Name extends TypeName = TypeName> extends TypeError<Name> {
2202
2213
  readonly value: string;
2203
2214
  readonly source: string;
@@ -2217,25 +2228,51 @@ export type UrlSafeString = typeof UrlSafeString.Output;
2217
2228
  /**
2218
2229
  * Base64Url text without padding.
2219
2230
  *
2220
- * Encode bytes with {@link uint8ArrayToBase64Url} and decode them with
2221
- * {@link base64UrlToUint8Array}.
2231
+ * Convert bytes to Base64Url with {@link uint8ArrayToBase64Url} and convert
2232
+ * Base64Url to bytes with {@link base64UrlToUint8Array}.
2222
2233
  *
2223
2234
  * @group String
2224
2235
  */
2225
2236
  export declare const Base64Url: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Base64Url", Base64UrlError>;
2226
2237
  export type Base64Url = typeof Base64Url.Output;
2227
- /** @group String */
2238
+ /**
2239
+ * Error returned when a string is not valid {@link Base64Url} text.
2240
+ *
2241
+ * @group String
2242
+ */
2228
2243
  export interface Base64UrlError extends TypeError<"Base64Url"> {
2229
2244
  readonly value: string;
2230
2245
  }
2231
2246
  /**
2232
- * Encodes bytes as {@link Base64Url}.
2247
+ * Converts bytes to {@link Base64Url}.
2248
+ *
2249
+ * ### Example
2250
+ *
2251
+ * ```ts
2252
+ * import { uint8ArrayToBase64Url } from "@evolu/common";
2253
+ *
2254
+ * expect(uint8ArrayToBase64Url(new Uint8Array([0, 1, 2, 255]))).toBe(
2255
+ * "AAEC_w",
2256
+ * );
2257
+ * ```
2233
2258
  *
2234
2259
  * @group String
2235
2260
  */
2236
2261
  export declare const uint8ArrayToBase64Url: (bytes: Uint8Array) => Base64Url;
2237
2262
  /**
2238
- * Decodes {@link Base64Url} as bytes.
2263
+ * Converts {@link Base64Url} to bytes.
2264
+ *
2265
+ * ### Example
2266
+ *
2267
+ * ```ts
2268
+ * import { Base64Url, base64UrlToUint8Array } from "@evolu/common";
2269
+ *
2270
+ * const value = Base64Url.orThrow("AAEC_w");
2271
+ *
2272
+ * expect(base64UrlToUint8Array(value)).toEqual(
2273
+ * new Uint8Array([0, 1, 2, 255]),
2274
+ * );
2275
+ * ```
2239
2276
  *
2240
2277
  * @group String
2241
2278
  */
@@ -2247,7 +2284,11 @@ export declare const base64UrlToUint8Array: (value: Base64Url) => Uint8Array;
2247
2284
  */
2248
2285
  export declare const Name: BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "UrlSafeString", RegexError<"UrlSafeString">>, "Name", NameError>;
2249
2286
  export type Name = typeof Name.Output;
2250
- /** @group String */
2287
+ /**
2288
+ * Error returned when a string is not a valid {@link Name}.
2289
+ *
2290
+ * @group String
2291
+ */
2251
2292
  export interface NameError extends TypeError<"Name"> {
2252
2293
  readonly value: string;
2253
2294
  }
@@ -2271,7 +2312,11 @@ export type SimplePassword = typeof SimplePassword.Output;
2271
2312
  */
2272
2313
  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
2314
  export type Mnemonic = typeof Mnemonic.Output;
2274
- /** @group String */
2315
+ /**
2316
+ * Error returned when a string is not a valid English BIP39 {@link Mnemonic}.
2317
+ *
2318
+ * @group String
2319
+ */
2275
2320
  export interface MnemonicError extends TypeError<"Mnemonic"> {
2276
2321
  readonly value: string;
2277
2322
  }
@@ -2287,7 +2332,11 @@ export interface MnemonicError extends TypeError<"Mnemonic"> {
2287
2332
  */
2288
2333
  export declare const Id: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Id", IdError>;
2289
2334
  export type Id = typeof Id.Output;
2290
- /** @group String */
2335
+ /**
2336
+ * Error returned when a string is not a valid {@link Id}.
2337
+ *
2338
+ * @group String
2339
+ */
2291
2340
  export interface IdError extends TypeError<"Id"> {
2292
2341
  readonly value: string;
2293
2342
  }
@@ -2297,6 +2346,22 @@ export interface IdError extends TypeError<"Id"> {
2297
2346
  * This is the recommended default because it does not encode creation time.
2298
2347
  * Pass a Brand name when the returned Id belongs to one domain entity.
2299
2348
  *
2349
+ * ### Example
2350
+ *
2351
+ * ```ts
2352
+ * import {
2353
+ * Id,
2354
+ * createId,
2355
+ * createRandomBytes,
2356
+ * type Brand,
2357
+ * } from "@evolu/common";
2358
+ *
2359
+ * const userId = createId<"User">({ randomBytes: createRandomBytes() });
2360
+ *
2361
+ * expect(Id.is(userId)).toBe(true);
2362
+ * expectTypeOf(userId).toEqualTypeOf<Id & Brand<"User">>();
2363
+ * ```
2364
+ *
2300
2365
  * @group String
2301
2366
  */
2302
2367
  export declare const createId: <B extends string = never>(deps: RandomBytesDep, ..._validation: IdBrandValidation<B>) => CreatedId<B>;
@@ -2331,20 +2396,64 @@ export declare const createIdFromString: <B extends string = never>(value: strin
2331
2396
  * logs, URLs, and exports. Prefer {@link createId} unless that tradeoff is
2332
2397
  * deliberate.
2333
2398
  *
2399
+ * ### Example
2400
+ *
2401
+ * ```ts
2402
+ * import {
2403
+ * createIdAsUuidv7,
2404
+ * createRandomBytes,
2405
+ * createTime,
2406
+ * idToIdBytes,
2407
+ * } from "@evolu/common";
2408
+ *
2409
+ * const value = createIdAsUuidv7({
2410
+ * randomBytes: createRandomBytes(),
2411
+ * time: createTime(),
2412
+ * });
2413
+ * const bytes = idToIdBytes(value);
2414
+ *
2415
+ * expect(bytes[6] >> 4).toBe(0x7);
2416
+ * expect(bytes[8] & 0xc0).toBe(0x80);
2417
+ * ```
2418
+ *
2334
2419
  * @group String
2335
2420
  */
2336
2421
  export declare const createIdAsUuidv7: <B extends string = never>(deps: RandomBytesDep & TimeDep, ..._validation: IdBrandValidation<B>) => CreatedId<B>;
2337
2422
  /**
2338
2423
  * Table-specific {@link Id} Type.
2339
2424
  *
2425
+ * ### Example
2426
+ *
2427
+ * ```ts
2428
+ * import {
2429
+ * createIdFromString,
2430
+ * id,
2431
+ * type Brand,
2432
+ * type Id,
2433
+ * } from "@evolu/common";
2434
+ *
2435
+ * const TodoId = id("Todo");
2436
+ * const todoId = TodoId.orThrow(createIdFromString("todo"));
2437
+ *
2438
+ * expectTypeOf(todoId).toEqualTypeOf<Id & Brand<"Todo">>();
2439
+ * ```
2440
+ *
2340
2441
  * @group String
2341
2442
  */
2342
2443
  export declare const id: <Table extends TypeName>(table: ValidateTableName<Table>) => TableId<Table>;
2343
- /** @group String */
2444
+ /**
2445
+ * The {@link Type} returned by {@link id} for one table.
2446
+ *
2447
+ * @group String
2448
+ */
2344
2449
  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
2450
  readonly table: Table;
2346
2451
  }
2347
- /** @group String */
2452
+ /**
2453
+ * Error returned when a string is not a valid {@link Id} for the expected table.
2454
+ *
2455
+ * @group String
2456
+ */
2348
2457
  export interface TableIdError<Table extends TypeName = TypeName> extends TypeError<"TableId"> {
2349
2458
  readonly table: Table;
2350
2459
  readonly value: string;
@@ -2364,11 +2473,47 @@ type ConcreteIdBrandError = CompileTimeError<"Id", "Brand must be one concrete s
2364
2473
  */
2365
2474
  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
2475
  export type IdBytes = typeof IdBytes.Output;
2367
- /** @group String */
2476
+ /**
2477
+ * Byte length of an {@link IdBytes} value.
2478
+ *
2479
+ * @group String
2480
+ */
2368
2481
  export declare const idBytesTypeValueLength: NonNegativeInt;
2369
- /** @group String */
2482
+ /**
2483
+ * Converts an {@link Id} to {@link IdBytes}.
2484
+ *
2485
+ * ### Example
2486
+ *
2487
+ * ```ts
2488
+ * import { createIdFromString, idToIdBytes } from "@evolu/common";
2489
+ *
2490
+ * const bytes = idToIdBytes(createIdFromString("todo"));
2491
+ *
2492
+ * expect(bytes).toHaveLength(16);
2493
+ * ```
2494
+ *
2495
+ * @group String
2496
+ */
2370
2497
  export declare const idToIdBytes: (value: Id) => IdBytes;
2371
- /** @group String */
2498
+ /**
2499
+ * Converts {@link IdBytes} to an {@link Id}.
2500
+ *
2501
+ * ### Example
2502
+ *
2503
+ * ```ts
2504
+ * import {
2505
+ * createIdFromString,
2506
+ * idBytesToId,
2507
+ * idToIdBytes,
2508
+ * } from "@evolu/common";
2509
+ *
2510
+ * const value = createIdFromString("todo");
2511
+ *
2512
+ * expect(idBytesToId(idToIdBytes(value))).toBe(value);
2513
+ * ```
2514
+ *
2515
+ * @group String
2516
+ */
2372
2517
  export declare const idBytesToId: (value: IdBytes) => Id;
2373
2518
  /**
2374
2519
  * Decimal string representation of a signed {@link Int64}.
@@ -2377,7 +2522,11 @@ export declare const idBytesToId: (value: IdBytes) => Id;
2377
2522
  */
2378
2523
  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
2524
  export type Int64String = typeof Int64String.Output;
2380
- /** @group Number */
2525
+ /**
2526
+ * Error returned when a string is not a canonical {@link Int64String}.
2527
+ *
2528
+ * @group Number
2529
+ */
2381
2530
  export interface Int64StringError extends TypeError<"Int64String"> {
2382
2531
  readonly value: string;
2383
2532
  }
@@ -2388,16 +2537,43 @@ export interface Int64StringError extends TypeError<"Int64String"> {
2388
2537
  * text, including SQLite queries that cast INTEGER values to TEXT to avoid a
2389
2538
  * lossy JavaScript number conversion.
2390
2539
  *
2540
+ * ### Example
2541
+ *
2542
+ * ```ts
2543
+ * import { Int64FromInt64String } from "@evolu/common";
2544
+ *
2545
+ * const result = Int64FromInt64String.fromUnknown("9223372036854775807");
2546
+ *
2547
+ * expectOk(result, 9223372036854775807n);
2548
+ * expect(Int64FromInt64String.to(result.value)).toBe(
2549
+ * "9223372036854775807",
2550
+ * );
2551
+ * ```
2552
+ *
2391
2553
  * @group Number
2392
2554
  */
2393
2555
  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
2556
  /**
2395
2557
  * Number {@link Brand} requiring a value greater than or equal to zero.
2396
2558
  *
2559
+ * ### Example
2560
+ *
2561
+ * ```ts
2562
+ * import { Number, nonNegative } from "@evolu/common";
2563
+ *
2564
+ * const NonNegative = nonNegative(Number);
2565
+ *
2566
+ * expectOk(NonNegative.fromUnknown(0), 0);
2567
+ * ```
2568
+ *
2397
2569
  * @group Number
2398
2570
  */
2399
2571
  export declare const nonNegative: BrandFactory<"NonNegative", number, NonNegativeError>;
2400
- /** @group Number */
2572
+ /**
2573
+ * Error returned when {@link nonNegative} rejects a number.
2574
+ *
2575
+ * @group Number
2576
+ */
2401
2577
  export interface NonNegativeError extends TypeError<"NonNegative"> {
2402
2578
  readonly value: number;
2403
2579
  }
@@ -2411,10 +2587,24 @@ export type NonNegativeNumber = typeof NonNegativeNumber.Output;
2411
2587
  /**
2412
2588
  * Number {@link Brand} requiring a value greater than zero.
2413
2589
  *
2590
+ * ### Example
2591
+ *
2592
+ * ```ts
2593
+ * import { Number, positive } from "@evolu/common";
2594
+ *
2595
+ * const Positive = positive(Number);
2596
+ *
2597
+ * expectOk(Positive.fromUnknown(1), 1);
2598
+ * ```
2599
+ *
2414
2600
  * @group Number
2415
2601
  */
2416
2602
  export declare const positive: BrandFactory<"Positive", number, PositiveError>;
2417
- /** @group Number */
2603
+ /**
2604
+ * Error returned when {@link positive} rejects a number.
2605
+ *
2606
+ * @group Number
2607
+ */
2418
2608
  export interface PositiveError extends TypeError<"Positive"> {
2419
2609
  readonly value: number;
2420
2610
  }
@@ -2431,10 +2621,24 @@ export type PositiveNumber = typeof PositiveNumber.Output;
2431
2621
  /**
2432
2622
  * Number {@link Brand} requiring a value less than or equal to zero.
2433
2623
  *
2624
+ * ### Example
2625
+ *
2626
+ * ```ts
2627
+ * import { Number, nonPositive } from "@evolu/common";
2628
+ *
2629
+ * const NonPositive = nonPositive(Number);
2630
+ *
2631
+ * expectOk(NonPositive.fromUnknown(0), 0);
2632
+ * ```
2633
+ *
2434
2634
  * @group Number
2435
2635
  */
2436
2636
  export declare const nonPositive: BrandFactory<"NonPositive", number, NonPositiveError>;
2437
- /** @group Number */
2637
+ /**
2638
+ * Error returned when {@link nonPositive} rejects a number.
2639
+ *
2640
+ * @group Number
2641
+ */
2438
2642
  export interface NonPositiveError extends TypeError<"NonPositive"> {
2439
2643
  readonly value: number;
2440
2644
  }
@@ -2448,10 +2652,24 @@ export type NonPositiveNumber = typeof NonPositiveNumber.Output;
2448
2652
  /**
2449
2653
  * Number {@link Brand} requiring a value less than zero.
2450
2654
  *
2655
+ * ### Example
2656
+ *
2657
+ * ```ts
2658
+ * import { Number, negative } from "@evolu/common";
2659
+ *
2660
+ * const Negative = negative(Number);
2661
+ *
2662
+ * expectOk(Negative.fromUnknown(-1), -1);
2663
+ * ```
2664
+ *
2451
2665
  * @group Number
2452
2666
  */
2453
2667
  export declare const negative: BrandFactory<"Negative", number, NegativeError>;
2454
- /** @group Number */
2668
+ /**
2669
+ * Error returned when {@link negative} rejects a number.
2670
+ *
2671
+ * @group Number
2672
+ */
2455
2673
  export interface NegativeError extends TypeError<"Negative"> {
2456
2674
  readonly value: number;
2457
2675
  }
@@ -2468,10 +2686,24 @@ export type NegativeNumber = typeof NegativeNumber.Output;
2468
2686
  /**
2469
2687
  * Number {@link Brand} requiring a value other than `NaN`.
2470
2688
  *
2689
+ * ### Example
2690
+ *
2691
+ * ```ts
2692
+ * import { Number, nonNaN } from "@evolu/common";
2693
+ *
2694
+ * const NonNaN = nonNaN(Number);
2695
+ *
2696
+ * expectOk(NonNaN.fromUnknown(Infinity), Infinity);
2697
+ * ```
2698
+ *
2471
2699
  * @group Number
2472
2700
  */
2473
2701
  export declare const nonNaN: BrandFactory<"NonNaN", number, NonNaNError>;
2474
- /** @group Number */
2702
+ /**
2703
+ * Error returned when {@link nonNaN} rejects `NaN`.
2704
+ *
2705
+ * @group Number
2706
+ */
2475
2707
  export interface NonNaNError extends TypeError<"NonNaN"> {
2476
2708
  readonly value: number;
2477
2709
  }
@@ -2490,10 +2722,24 @@ export type NonNaNNumber = typeof NonNaNNumber.Output;
2490
2722
  /**
2491
2723
  * Number {@link Brand} requiring a finite value.
2492
2724
  *
2725
+ * ### Example
2726
+ *
2727
+ * ```ts
2728
+ * import { Number, finite } from "@evolu/common";
2729
+ *
2730
+ * const Finite = finite(Number);
2731
+ *
2732
+ * expectOk(Finite.fromUnknown(42), 42);
2733
+ * ```
2734
+ *
2493
2735
  * @group Number
2494
2736
  */
2495
2737
  export declare const finite: BrandFactory<"Finite", number, FiniteError>;
2496
- /** @group Number */
2738
+ /**
2739
+ * Error returned when {@link finite} rejects a non-finite number.
2740
+ *
2741
+ * @group Number
2742
+ */
2497
2743
  export interface FiniteError extends TypeError<"Finite"> {
2498
2744
  readonly value: number;
2499
2745
  }
@@ -2541,7 +2787,11 @@ export type PositiveFiniteNumber = typeof PositiveFiniteNumber.Output;
2541
2787
  * @group Number
2542
2788
  */
2543
2789
  export declare const int: BrandFactory<"Int", number, IntError>;
2544
- /** @group Number */
2790
+ /**
2791
+ * Error returned when {@link int} rejects a number that is not a safe integer.
2792
+ *
2793
+ * @group Number
2794
+ */
2545
2795
  export interface IntError extends TypeError<"Int"> {
2546
2796
  readonly value: number;
2547
2797
  }
@@ -2607,10 +2857,24 @@ export type NegativeInt = typeof NegativeInt.Output;
2607
2857
  /**
2608
2858
  * Number {@link Brand} requiring a value greater than `min`.
2609
2859
  *
2860
+ * ### Example
2861
+ *
2862
+ * ```ts
2863
+ * import { Number, greaterThan } from "@evolu/common";
2864
+ *
2865
+ * const GreaterThanTen = greaterThan(10)(Number);
2866
+ *
2867
+ * expectOk(GreaterThanTen.fromUnknown(11), 11);
2868
+ * ```
2869
+ *
2610
2870
  * @group Number
2611
2871
  */
2612
2872
  export declare const greaterThan: <Min extends number>(min: ValidateBrandFactoryNumber<Min>) => BrandFactory<`GreaterThan${Min}`, number, GreaterThanError<Min>>;
2613
- /** @group Number */
2873
+ /**
2874
+ * Error returned when {@link greaterThan} rejects a number.
2875
+ *
2876
+ * @group Number
2877
+ */
2614
2878
  export interface GreaterThanError<Min extends number = number> extends TypeError<`GreaterThan${Min}`> {
2615
2879
  readonly value: number;
2616
2880
  readonly min: Min;
@@ -2618,10 +2882,24 @@ export interface GreaterThanError<Min extends number = number> extends TypeError
2618
2882
  /**
2619
2883
  * Number {@link Brand} requiring a value greater than or equal to `min`.
2620
2884
  *
2885
+ * ### Example
2886
+ *
2887
+ * ```ts
2888
+ * import { Number, greaterThanOrEqualTo } from "@evolu/common";
2889
+ *
2890
+ * const AtLeastTen = greaterThanOrEqualTo(10)(Number);
2891
+ *
2892
+ * expectOk(AtLeastTen.fromUnknown(10), 10);
2893
+ * ```
2894
+ *
2621
2895
  * @group Number
2622
2896
  */
2623
2897
  export declare const greaterThanOrEqualTo: <Min extends number>(min: ValidateBrandFactoryNumber<Min>) => BrandFactory<`GreaterThanOrEqualTo${Min}`, number, GreaterThanOrEqualToError<Min>>;
2624
- /** @group Number */
2898
+ /**
2899
+ * Error returned when {@link greaterThanOrEqualTo} rejects a number.
2900
+ *
2901
+ * @group Number
2902
+ */
2625
2903
  export interface GreaterThanOrEqualToError<Min extends number = number> extends TypeError<`GreaterThanOrEqualTo${Min}`> {
2626
2904
  readonly value: number;
2627
2905
  readonly min: Min;
@@ -2629,10 +2907,24 @@ export interface GreaterThanOrEqualToError<Min extends number = number> extends
2629
2907
  /**
2630
2908
  * Number {@link Brand} requiring a value less than `max`.
2631
2909
  *
2910
+ * ### Example
2911
+ *
2912
+ * ```ts
2913
+ * import { Number, lessThan } from "@evolu/common";
2914
+ *
2915
+ * const LessThanTen = lessThan(10)(Number);
2916
+ *
2917
+ * expectOk(LessThanTen.fromUnknown(9), 9);
2918
+ * ```
2919
+ *
2632
2920
  * @group Number
2633
2921
  */
2634
2922
  export declare const lessThan: <Max extends number>(max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`LessThan${Max}`, number, LessThanError<Max>>;
2635
- /** @group Number */
2923
+ /**
2924
+ * Error returned when {@link lessThan} rejects a number.
2925
+ *
2926
+ * @group Number
2927
+ */
2636
2928
  export interface LessThanError<Max extends number = number> extends TypeError<`LessThan${Max}`> {
2637
2929
  readonly value: number;
2638
2930
  readonly max: Max;
@@ -2647,10 +2939,24 @@ export type Age = typeof Age.Output;
2647
2939
  /**
2648
2940
  * Number {@link Brand} requiring a value less than or equal to `max`.
2649
2941
  *
2942
+ * ### Example
2943
+ *
2944
+ * ```ts
2945
+ * import { Number, lessThanOrEqualTo } from "@evolu/common";
2946
+ *
2947
+ * const AtMostTen = lessThanOrEqualTo(10)(Number);
2948
+ *
2949
+ * expectOk(AtMostTen.fromUnknown(10), 10);
2950
+ * ```
2951
+ *
2650
2952
  * @group Number
2651
2953
  */
2652
2954
  export declare const lessThanOrEqualTo: <Max extends number>(max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`LessThanOrEqualTo${Max}`, number, LessThanOrEqualToError<Max>>;
2653
- /** @group Number */
2955
+ /**
2956
+ * Error returned when {@link lessThanOrEqualTo} rejects a number.
2957
+ *
2958
+ * @group Number
2959
+ */
2654
2960
  export interface LessThanOrEqualToError<Max extends number = number> extends TypeError<`LessThanOrEqualTo${Max}`> {
2655
2961
  readonly value: number;
2656
2962
  readonly max: Max;
@@ -2707,17 +3013,35 @@ export type Ratio = typeof Ratio.Output;
2707
3013
  */
2708
3014
  export declare const DecimalString: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DecimalString", DecimalStringError>;
2709
3015
  export type DecimalString = typeof DecimalString.Output;
2710
- /** @group Number */
3016
+ /**
3017
+ * Error returned when a string is not a canonical {@link DecimalString}.
3018
+ *
3019
+ * @group Number
3020
+ */
2711
3021
  export interface DecimalStringError extends TypeError<"DecimalString"> {
2712
3022
  readonly value: string;
2713
3023
  }
2714
3024
  /**
2715
3025
  * {@link DecimalString} Brand requiring a value greater than or equal to zero.
2716
3026
  *
3027
+ * ### Example
3028
+ *
3029
+ * ```ts
3030
+ * import { DecimalString, nonNegativeDecimalString } from "@evolu/common";
3031
+ *
3032
+ * const NonNegative = nonNegativeDecimalString(DecimalString);
3033
+ *
3034
+ * expectOk(NonNegative.fromUnknown("0.5"), "0.5");
3035
+ * ```
3036
+ *
2717
3037
  * @group Number
2718
3038
  */
2719
3039
  export declare const nonNegativeDecimalString: BrandFactory<"NonNegativeDecimalString", DecimalString, NonNegativeDecimalStringError>;
2720
- /** @group Number */
3040
+ /**
3041
+ * Error returned when {@link nonNegativeDecimalString} rejects a decimal string.
3042
+ *
3043
+ * @group Number
3044
+ */
2721
3045
  export interface NonNegativeDecimalStringError extends TypeError<"NonNegativeDecimalString"> {
2722
3046
  readonly value: string;
2723
3047
  }
@@ -2731,10 +3055,24 @@ export type NonNegativeDecimalString = typeof NonNegativeDecimalString.Output;
2731
3055
  /**
2732
3056
  * {@link DecimalString} Brand requiring a value greater than zero.
2733
3057
  *
3058
+ * ### Example
3059
+ *
3060
+ * ```ts
3061
+ * import { DecimalString, positiveDecimalString } from "@evolu/common";
3062
+ *
3063
+ * const Positive = positiveDecimalString(DecimalString);
3064
+ *
3065
+ * expectOk(Positive.fromUnknown("0.5"), "0.5");
3066
+ * ```
3067
+ *
2734
3068
  * @group Number
2735
3069
  */
2736
3070
  export declare const positiveDecimalString: BrandFactory<"PositiveDecimalString", DecimalString, PositiveDecimalStringError>;
2737
- /** @group Number */
3071
+ /**
3072
+ * Error returned when {@link positiveDecimalString} rejects a decimal string.
3073
+ *
3074
+ * @group Number
3075
+ */
2738
3076
  export interface PositiveDecimalStringError extends TypeError<"PositiveDecimalString"> {
2739
3077
  readonly value: string;
2740
3078
  }
@@ -2751,10 +3089,24 @@ export type PositiveDecimalString = typeof PositiveDecimalString.Output;
2751
3089
  /**
2752
3090
  * {@link DecimalString} Brand requiring a value less than or equal to zero.
2753
3091
  *
3092
+ * ### Example
3093
+ *
3094
+ * ```ts
3095
+ * import { DecimalString, nonPositiveDecimalString } from "@evolu/common";
3096
+ *
3097
+ * const NonPositive = nonPositiveDecimalString(DecimalString);
3098
+ *
3099
+ * expectOk(NonPositive.fromUnknown("-0.5"), "-0.5");
3100
+ * ```
3101
+ *
2754
3102
  * @group Number
2755
3103
  */
2756
3104
  export declare const nonPositiveDecimalString: BrandFactory<"NonPositiveDecimalString", DecimalString, NonPositiveDecimalStringError>;
2757
- /** @group Number */
3105
+ /**
3106
+ * Error returned when {@link nonPositiveDecimalString} rejects a decimal string.
3107
+ *
3108
+ * @group Number
3109
+ */
2758
3110
  export interface NonPositiveDecimalStringError extends TypeError<"NonPositiveDecimalString"> {
2759
3111
  readonly value: string;
2760
3112
  }
@@ -2768,10 +3120,24 @@ export type NonPositiveDecimalString = typeof NonPositiveDecimalString.Output;
2768
3120
  /**
2769
3121
  * {@link DecimalString} Brand requiring a value less than zero.
2770
3122
  *
3123
+ * ### Example
3124
+ *
3125
+ * ```ts
3126
+ * import { DecimalString, negativeDecimalString } from "@evolu/common";
3127
+ *
3128
+ * const Negative = negativeDecimalString(DecimalString);
3129
+ *
3130
+ * expectOk(Negative.fromUnknown("-0.5"), "-0.5");
3131
+ * ```
3132
+ *
2771
3133
  * @group Number
2772
3134
  */
2773
3135
  export declare const negativeDecimalString: BrandFactory<"NegativeDecimalString", DecimalString, NegativeDecimalStringError>;
2774
- /** @group Number */
3136
+ /**
3137
+ * Error returned when {@link negativeDecimalString} rejects a decimal string.
3138
+ *
3139
+ * @group Number
3140
+ */
2775
3141
  export interface NegativeDecimalStringError extends TypeError<"NegativeDecimalString"> {
2776
3142
  readonly value: string;
2777
3143
  }
@@ -2818,7 +3184,11 @@ export type NegativeDecimalString = typeof NegativeDecimalString.Output;
2818
3184
  * @group Number
2819
3185
  */
2820
3186
  export declare const multipleOf: <const Divisor extends string>(divisor: ValidateMultipleOfDivisor<Divisor>) => BrandFactory<`MultipleOf${Divisor}`, number, MultipleOfError<Divisor>>;
2821
- /** @group Number */
3187
+ /**
3188
+ * Error returned when {@link multipleOf} rejects a number.
3189
+ *
3190
+ * @group Number
3191
+ */
2822
3192
  export interface MultipleOfError<Divisor extends string = string> extends TypeError<`MultipleOf${Divisor}`> {
2823
3193
  readonly value: number;
2824
3194
  readonly divisor: Divisor;
@@ -2834,10 +3204,24 @@ type MultipleOfDivisorError = CompileTimeError<"MultipleOf", 'Divisor must be on
2834
3204
  /**
2835
3205
  * Number {@link Brand} requiring a value within an inclusive range.
2836
3206
  *
3207
+ * ### Example
3208
+ *
3209
+ * ```ts
3210
+ * import { Number, between } from "@evolu/common";
3211
+ *
3212
+ * const Percentage = between(0, 100)(Number);
3213
+ *
3214
+ * expectOk(Percentage.fromUnknown(75), 75);
3215
+ * ```
3216
+ *
2837
3217
  * @group Number
2838
3218
  */
2839
3219
  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 */
3220
+ /**
3221
+ * Error returned when {@link between} rejects a number.
3222
+ *
3223
+ * @group Number
3224
+ */
2841
3225
  export interface BetweenError<Min extends number = number, Max extends number = number> extends TypeError<`Between${Min}-${Max}`> {
2842
3226
  readonly value: number;
2843
3227
  readonly min: Min;
@@ -2894,7 +3278,11 @@ export interface BetweenError<Min extends number = number, Max extends number =
2894
3278
  * @group Collection
2895
3279
  */
2896
3280
  export declare const array: <ElementType extends ConcreteTypeNode>(element: ValidateElement<ElementType>) => ArrayType<ElementType>;
2897
- /** @group Collection */
3281
+ /**
3282
+ * The homogeneous readonly-array {@link Type} returned by {@link array}.
3283
+ *
3284
+ * @group Collection
3285
+ */
2898
3286
  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
3287
  readonly [reflectedTypesSymbol]?: ElementType;
2900
3288
  readonly element: ElementType;
@@ -2915,42 +3303,78 @@ type ArrayParent<ElementType extends TypeNode> = [
2915
3303
  type ArrayNodeError<ElementType extends TypeNode> = [
2916
3304
  ElementType["parent"]
2917
3305
  ] extends [TypeNode] ? ArrayElementsError<ElementType["Error"]> : ArrayError<ElementType["Error"]>;
2918
- /** @group Collection */
3306
+ /**
3307
+ * Error returned by {@link array} for a non-array value or invalid array items.
3308
+ *
3309
+ * @group Collection
3310
+ */
2919
3311
  export type ArrayError<Error extends TypeError = TypeError> = ArrayNotArrayError | ArrayItemsErrorValue<Error, true>;
2920
- /** @group Collection */
3312
+ /**
3313
+ * Error returned when an {@link array} input is not an array.
3314
+ *
3315
+ * @group Collection
3316
+ */
2921
3317
  export interface ArrayNotArrayError extends TypeError<"Array"> {
2922
3318
  readonly reason: {
2923
3319
  readonly kind: "NotArray";
2924
3320
  readonly value: unknown;
2925
3321
  };
2926
3322
  }
2927
- /** @group Collection */
3323
+ /**
3324
+ * An {@link array} error containing structural or element issues.
3325
+ *
3326
+ * @group Collection
3327
+ */
2928
3328
  export type ArrayItemsError<Error extends TypeError> = ArrayItemsErrorValue<Error, true>;
2929
- /** @group Collection */
3329
+ /**
3330
+ * One structural or element issue found by {@link array}.
3331
+ *
3332
+ * @group Collection
3333
+ */
2930
3334
  export type ArrayIssue<Error extends TypeError> = ArrayStructuralIssue | ArrayElementIssue<Error>;
2931
- /** @group Collection */
3335
+ /**
3336
+ * A missing array element.
3337
+ *
3338
+ * @group Collection
3339
+ */
2932
3340
  export interface ArrayHoleIssue {
2933
3341
  readonly kind: "Hole";
2934
3342
  readonly index: number;
2935
3343
  }
2936
- /** @group Collection */
3344
+ /**
3345
+ * An array element defined by an accessor instead of a data property.
3346
+ *
3347
+ * @group Collection
3348
+ */
2937
3349
  export interface ArrayAccessorIssue {
2938
3350
  readonly kind: "Accessor";
2939
3351
  readonly index: number;
2940
3352
  }
2941
- /** @group Collection */
3353
+ /**
3354
+ * An own array property other than `length` or an indexed element.
3355
+ *
3356
+ * @group Collection
3357
+ */
2942
3358
  export interface ArrayExcessPropertyIssue {
2943
3359
  readonly kind: "ExcessProperty";
2944
3360
  readonly key: string | symbol;
2945
3361
  }
2946
3362
  type ArrayStructuralIssue = ArrayHoleIssue | ArrayAccessorIssue | ArrayExcessPropertyIssue;
2947
- /** @group Collection */
3363
+ /**
3364
+ * An invalid array element and its index.
3365
+ *
3366
+ * @group Collection
3367
+ */
2948
3368
  export type ArrayElementIssue<Error extends TypeError> = Error extends TypeError ? {
2949
3369
  readonly kind: "Element";
2950
3370
  readonly index: number;
2951
3371
  readonly error: Error;
2952
3372
  } : never;
2953
- /** @group Collection */
3373
+ /**
3374
+ * An {@link array} error containing element errors from a typed boundary.
3375
+ *
3376
+ * @group Collection
3377
+ */
2954
3378
  export type ArrayElementsError<Error extends TypeError> = [Error] extends [
2955
3379
  never
2956
3380
  ] ? never : ArrayItemsErrorValue<Error, false>;
@@ -2968,10 +3392,25 @@ interface ArrayItemsErrorValue<Error extends TypeError, IncludeStructuralIssues
2968
3392
  * iteration order. Classification uses the realm-neutral object tag and
2969
3393
  * prototype structure under Evolu Type's trusted JavaScript policy.
2970
3394
  *
3395
+ * ### Example
3396
+ *
3397
+ * ```ts
3398
+ * import { String, set } from "@evolu/common";
3399
+ *
3400
+ * const Tags = set(String);
3401
+ * const tags = new Set(["local-first", "offline"]);
3402
+ *
3403
+ * expectOk(Tags.fromUnknown(tags), tags);
3404
+ * ```
3405
+ *
2971
3406
  * @group Collection
2972
3407
  */
2973
3408
  export declare const set: <ElementType extends ConcreteTypeNode>(element: ValidateElement<ElementType>) => SetType<ElementType>;
2974
- /** @group Collection */
3409
+ /**
3410
+ * The homogeneous readonly-set {@link Type} returned by {@link set}.
3411
+ *
3412
+ * @group Collection
3413
+ */
2975
3414
  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
3415
  readonly [reflectedTypesSymbol]?: ElementType;
2977
3416
  readonly element: ElementType;
@@ -2991,9 +3430,18 @@ type SetParent<ElementType extends TypeNode> = [ElementType["parent"]] extends [
2991
3430
  type SetNodeError<ElementType extends TypeNode> = [
2992
3431
  ElementType["parent"]
2993
3432
  ] extends [TypeNode] ? SetElementsError<ElementType["Error"]> : SetError<ElementType["Error"]>;
2994
- /** @group Collection */
3433
+ /**
3434
+ * Error returned by {@link set} for a non-Set value, an invalid Set prototype,
3435
+ * or invalid Set items.
3436
+ *
3437
+ * @group Collection
3438
+ */
2995
3439
  export type SetError<Error extends TypeError = TypeError> = SetNotSetError | SetUnexpectedPrototypeError | SetItemsErrorValue<Error, true>;
2996
- /** @group Collection */
3440
+ /**
3441
+ * Error returned when a {@link set} input is not a Set.
3442
+ *
3443
+ * @group Collection
3444
+ */
2997
3445
  export interface SetNotSetError extends TypeError<"Set"> {
2998
3446
  readonly reason: {
2999
3447
  readonly kind: "NotSet";
@@ -3011,21 +3459,37 @@ export interface SetUnexpectedPrototypeError extends TypeError<"Set"> {
3011
3459
  readonly value: ReadonlySet<unknown>;
3012
3460
  };
3013
3461
  }
3014
- /** @group Collection */
3462
+ /**
3463
+ * An own property found on a Set value.
3464
+ *
3465
+ * @group Collection
3466
+ */
3015
3467
  export interface SetExcessPropertyIssue {
3016
3468
  readonly kind: "ExcessProperty";
3017
3469
  readonly key: string | symbol;
3018
3470
  }
3019
3471
  type SetStructuralIssue = SetExcessPropertyIssue;
3020
- /** @group Collection */
3472
+ /**
3473
+ * An invalid Set element and its iteration index.
3474
+ *
3475
+ * @group Collection
3476
+ */
3021
3477
  export type SetElementIssue<Error extends TypeError> = Error extends TypeError ? {
3022
3478
  readonly kind: "Element";
3023
3479
  readonly index: number;
3024
3480
  readonly error: Error;
3025
3481
  } : never;
3026
- /** @group Collection */
3482
+ /**
3483
+ * A {@link set} error containing structural or element issues.
3484
+ *
3485
+ * @group Collection
3486
+ */
3027
3487
  export type SetItemsError<Error extends TypeError> = SetItemsErrorValue<Error, true>;
3028
- /** @group Collection */
3488
+ /**
3489
+ * A {@link set} error containing element errors from a typed boundary.
3490
+ *
3491
+ * @group Collection
3492
+ */
3029
3493
  export type SetElementsError<Error extends TypeError> = [Error] extends [never] ? never : SetItemsErrorValue<Error, false>;
3030
3494
  interface SetItemsErrorValue<Error extends TypeError, IncludeStructuralIssues extends boolean> extends TypeError<"Set"> {
3031
3495
  readonly reason: {
@@ -3058,17 +3522,12 @@ interface SetItemsErrorValue<Error extends TypeError, IncludeStructuralIssues ex
3058
3522
  * ### Example
3059
3523
  *
3060
3524
  * ```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
- * });
3525
+ * import { Int64FromInt64String, String, tuple } from "@evolu/common";
3067
3526
  *
3068
- * const Entry = tuple(String, NumberFromString);
3527
+ * const Entry = tuple(String, Int64FromInt64String);
3069
3528
  *
3070
- * expectOk(Entry.fromUnknown(["count", "1"]), ["count", 1]);
3071
- * expectOk(Entry.from.parent(["count", "1"]), ["count", 1]);
3529
+ * expectOk(Entry.fromUnknown(["count", "1"]), ["count", 1n]);
3530
+ * expectOk(Entry.from.parent(["count", "1"]), ["count", 1n]);
3072
3531
  * ```
3073
3532
  *
3074
3533
  * @group Collection
@@ -3267,7 +3726,7 @@ type PlainObjectError = ObjectError<Readonly<Record<never, never>>, ObjectProper
3267
3726
  * values have their own Types, and {@link instanceOf} when an instance belongs
3268
3727
  * to the domain.
3269
3728
  *
3270
- * @group Base Types
3729
+ * @group Base
3271
3730
  */
3272
3731
  export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, Readonly<Record<string, unknown>>, PlainObjectError, null, PlainObjectError, never, Readonly<Record<string, unknown>>>;
3273
3732
  /**
@@ -3300,20 +3759,13 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
3300
3759
  *
3301
3760
  * ```ts
3302
3761
  * import {
3303
- * Number,
3762
+ * Int64FromInt64String,
3304
3763
  * String,
3305
- * ok,
3306
3764
  * record,
3307
- * transform,
3308
- * type Result,
3765
+ * type Int64,
3309
3766
  * } from "@evolu/common";
3310
3767
  *
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);
3768
+ * const ScoresByUser = record(String, Int64FromInt64String);
3317
3769
  * type ScoresByUser = typeof ScoresByUser.Output;
3318
3770
  *
3319
3771
  * // Validate an unknown value.
@@ -3322,7 +3774,7 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
3322
3774
  * grace: "20",
3323
3775
  * });
3324
3776
  *
3325
- * expectOk(scoresFromUnknown, { ada: 10, grace: 20 });
3777
+ * expectOk(scoresFromUnknown, { ada: 10n, grace: 20n });
3326
3778
  *
3327
3779
  * // Validate keys and values with their root Types.
3328
3780
  * const scoresInput = ScoresByUser.parent.fromUnknown({
@@ -3334,11 +3786,10 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
3334
3786
  * // Run the remaining key and value stages.
3335
3787
  * const scoresFromInput = ScoresByUser.from.parent(scoresInput.value);
3336
3788
  *
3337
- * expectTypeOf(scoresFromInput).toEqualTypeOf<
3338
- * Result<Readonly<Partial<Record<string, number>>>, never>
3789
+ * expectOk(scoresFromInput, { ada: 10n, grace: 20n });
3790
+ * expectTypeOf(scoresFromInput.value).toEqualTypeOf<
3791
+ * Readonly<Partial<Record<string, Int64>>>
3339
3792
  * >();
3340
- *
3341
- * expectOk(scoresFromInput, { ada: 10, grace: 20 });
3342
3793
  * ```
3343
3794
  *
3344
3795
  * Note that TypeScript does not model an object's runtime prototype. This can
@@ -3382,7 +3833,11 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
3382
3833
  * @group Objects
3383
3834
  */
3384
3835
  export declare const record: <KeyType extends ConcreteTypeNode, ValueType extends ConcreteTypeNode>(key: ValidateRecordKeyType<KeyType>, value: ValidateRecordValueType<ValueType>) => RecordType<KeyType, ValueType>;
3385
- /** @group Objects */
3836
+ /**
3837
+ * The {@link Type} returned by {@link record}.
3838
+ *
3839
+ * @group Objects
3840
+ */
3386
3841
  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
3842
  readonly [reflectedTypesSymbol]?: KeyType | ValueType;
3388
3843
  readonly key: KeyType;
@@ -3412,16 +3867,28 @@ type ValidateRecordValueType<T extends ConcreteTypeNode> = IsUnion<T> extends fa
3412
3867
  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
3868
  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
3869
  type RecordKeyStringTypeError = CompileTimeError<"Type", "Record key Type Input and Output must extend string.">;
3415
- /** @group Objects */
3870
+ /**
3871
+ * Error returned while validating a {@link record} and its entries.
3872
+ *
3873
+ * @group Objects
3874
+ */
3416
3875
  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 */
3876
+ /**
3877
+ * Error returned when a {@link record} input is not an object.
3878
+ *
3879
+ * @group Objects
3880
+ */
3418
3881
  export interface RecordNotRecordError extends TypeError<"Record"> {
3419
3882
  readonly reason: {
3420
3883
  readonly kind: "NotRecord";
3421
3884
  readonly value: unknown;
3422
3885
  };
3423
3886
  }
3424
- /** @group Objects */
3887
+ /**
3888
+ * Error returned when a {@link record} input is not a plain object.
3889
+ *
3890
+ * @group Objects
3891
+ */
3425
3892
  export interface RecordNotPlainRecordError extends TypeError<"Record"> {
3426
3893
  readonly reason: {
3427
3894
  readonly kind: "NotPlainRecord";
@@ -3438,9 +3905,17 @@ export interface RecordNotPlainRecordError extends TypeError<"Record"> {
3438
3905
  * @group Objects
3439
3906
  */
3440
3907
  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 */
3908
+ /**
3909
+ * An invalid key, value, or property structure in a {@link record}.
3910
+ *
3911
+ * @group Objects
3912
+ */
3442
3913
  export type RecordIssue<KeyError extends TypeError, ValueError extends TypeError, StructuralIssue extends RecordStructuralIssue = RecordCollisionIssue> = RecordKeyIssue<KeyError> | RecordValueIssue<ValueError> | StructuralIssue;
3443
- /** @group Objects */
3914
+ /**
3915
+ * A property-structure issue returned by {@link record}.
3916
+ *
3917
+ * @group Objects
3918
+ */
3444
3919
  export type RecordStructuralIssue = RecordAccessorIssue | RecordCollisionIssue | RecordNonEnumerableIssue;
3445
3920
  /**
3446
3921
  * An accessor property rejected by {@link record}.
@@ -3460,19 +3935,31 @@ export interface RecordNonEnumerableIssue {
3460
3935
  readonly kind: "NonEnumerable";
3461
3936
  readonly key: string | symbol;
3462
3937
  }
3463
- /** @group Objects */
3938
+ /**
3939
+ * An invalid key and its source property key in a {@link record}.
3940
+ *
3941
+ * @group Objects
3942
+ */
3464
3943
  export type RecordKeyIssue<Error extends TypeError> = Error extends TypeError ? {
3465
3944
  readonly kind: "Key";
3466
3945
  readonly key: string | symbol;
3467
3946
  readonly error: Error;
3468
3947
  } : never;
3469
- /** @group Objects */
3948
+ /**
3949
+ * An invalid value and its property key in a {@link record}.
3950
+ *
3951
+ * @group Objects
3952
+ */
3470
3953
  export type RecordValueIssue<Error extends TypeError> = Error extends TypeError ? {
3471
3954
  readonly kind: "Value";
3472
3955
  readonly key: string | symbol;
3473
3956
  readonly error: Error;
3474
3957
  } : never;
3475
- /** @group Objects */
3958
+ /**
3959
+ * Two {@link record} keys that decode to the same output key.
3960
+ *
3961
+ * @group Objects
3962
+ */
3476
3963
  export interface RecordCollisionIssue {
3477
3964
  readonly kind: "Collision";
3478
3965
  readonly key: string | symbol;
@@ -3563,48 +4050,38 @@ type ObjectProperty = ObjectProps[string];
3563
4050
  *
3564
4051
  * ```ts
3565
4052
  * import {
3566
- * Number,
4053
+ * Int64FromInt64String,
3567
4054
  * String,
3568
4055
  * object,
3569
- * ok,
3570
- * transform,
3571
4056
  * type InferType,
3572
- * type Result,
3573
4057
  * } from "@evolu/common";
3574
4058
  *
3575
- * const AgeFromString = transform("AgeFromString", String, Number, {
3576
- * from: (value) => ok(globalThis.Number(value)),
3577
- * to: globalThis.String,
3578
- * });
3579
- *
3580
4059
  * const User = object({
3581
4060
  * name: String,
3582
- * age: AgeFromString,
4061
+ * loginCount: Int64FromInt64String,
3583
4062
  * });
3584
4063
  * interface User extends InferType<typeof User> {}
3585
4064
  *
3586
4065
  * // Validate an unknown value.
3587
- * const userFromUnknown = User.fromUnknown({ name: "Ada", age: "42" });
4066
+ * const userFromUnknown = User.fromUnknown({
4067
+ * name: "Ada",
4068
+ * loginCount: "42",
4069
+ * });
3588
4070
  *
3589
- * expectOk(userFromUnknown, { name: "Ada", age: 42 });
4071
+ * expectOk(userFromUnknown, { name: "Ada", loginCount: 42n });
3590
4072
  *
3591
4073
  * // Validate the object and root property Types.
3592
4074
  * const userInput = User.parent.fromUnknown({
3593
4075
  * name: "Ada",
3594
- * age: "42",
4076
+ * loginCount: "42",
3595
4077
  * });
3596
- * expectOk(userInput, { name: "Ada", age: "42" });
4078
+ * expectOk(userInput, { name: "Ada", loginCount: "42" });
3597
4079
  *
3598
4080
  * // Run the remaining property stages.
3599
- * const userFromInput: Result<
3600
- * { readonly name: string; readonly age: number },
3601
- * never
3602
- * > = User.from.parent(userInput.value);
4081
+ * const userFromInput = User.from.parent(userInput.value);
3603
4082
  *
3604
- * expectTypeOf(userFromInput).toEqualTypeOf<
3605
- * Result<{ readonly name: string; readonly age: number }, never>
3606
- * >();
3607
- * expectOk(userFromInput, { name: "Ada", age: 42 });
4083
+ * expectOk(userFromInput, { name: "Ada", loginCount: 42n });
4084
+ * expectTypeOf(userFromInput.value).toExtend<User>();
3608
4085
  * ```
3609
4086
  *
3610
4087
  * Note that TypeScript does not model an object's runtime prototype. This can
@@ -3652,6 +4129,7 @@ type ObjectProperty = ObjectProps[string];
3652
4129
  * @group Objects
3653
4130
  */
3654
4131
  export declare function object<const Props extends ObjectProps>(props: Props, ...validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]): StrictObjectType<Props>;
4132
+ /** Creates an Object Type with additional record properties. */
3655
4133
  export declare function object<const Props extends ObjectProps, const Rest extends RecordTypeNode & ConcreteTypeNode>(props: Props, record: Rest, ...validation: [
3656
4134
  ObjectValidationError<Props> | ObjectRecordValidationError<Props, Rest>
3657
4135
  ] extends [never] ? [] : [
@@ -3693,7 +4171,11 @@ type ObjectRecordKeyTypeError = CompileTimeError<"Type", "Object Record key must
3693
4171
  type ObjectRecordInputTypeError = CompileTimeError<"Type", "Every declared property Type Input must extend the Object Record value Type Input.">;
3694
4172
  type ObjectRecordOutputTypeError = CompileTimeError<"Type", "Every declared property Type Output must extend the Object Record value Type Output.">;
3695
4173
  type ObjectRecordCanonicalInputTypeError = CompileTimeError<"Type", "Every declared property Type CanonicalInput must extend the Object Record value Type CanonicalInput.">;
3696
- /** @group Objects */
4174
+ /**
4175
+ * The {@link Type} returned by {@link object}.
4176
+ *
4177
+ * @group Objects
4178
+ */
3697
4179
  export type ObjectType<Props extends ObjectProps, Rest extends ObjectRecordTypeNode | undefined = undefined> = Rest extends ObjectRecordTypeNode ? ObjectWithRecordType<Props, Rest> : StrictObjectType<Props>;
3698
4180
  type StrictObjectType<Props extends ObjectProps> = Type<"Object", StrictObjectShape<Props, "Input">, StrictObjectShape<Props, "Output">, [
3699
4181
  StrictObjectParents<Props>
@@ -3791,10 +4273,10 @@ export interface ObjectNotObjectError extends TypeError<"Object"> {
3791
4273
  *
3792
4274
  * Object Types accept a `null` prototype or a prototype whose own prototype is
3793
4275
  * `null`. This includes ordinary and cross-realm plain objects as well as
3794
- * objects created from an immediate root prototype. Arrays, built-in objects,
3795
- * class instances, and objects with deeper custom prototype chains return this
3796
- * error instead of having their prototype or inherited state discarded.
3797
- * `reason.value` is the rejected object.
4276
+ * objects created from an immediate root prototype. Arrays, JavaScript built-in
4277
+ * objects, class instances, and objects with deeper custom prototype chains
4278
+ * return this error instead of having their prototype or inherited state
4279
+ * discarded. `reason.value` is the rejected object.
3798
4280
  *
3799
4281
  * @group Objects
3800
4282
  */
@@ -3883,7 +4365,11 @@ type ObjectRestFromParentError<Rest extends ObjectRecordTypeNode | undefined> =
3883
4365
  * @group Objects
3884
4366
  */
3885
4367
  export declare const partial: <const Props extends ObjectProps>(props: Props, ..._validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]) => ObjectType<PartialObjectProps<Props>>;
3886
- /** @group Objects */
4368
+ /**
4369
+ * Maps every required object property Type to an optional property.
4370
+ *
4371
+ * @group Objects
4372
+ */
3887
4373
  export type PartialObjectProps<Props extends ObjectProps> = {
3888
4374
  readonly [Key in keyof Props]: Props[Key] extends OptionalProperty<TypeNode> ? Props[Key] : Props[Key] extends TypeNode ? OptionalProperty<Props[Key]> : never;
3889
4375
  };
@@ -3915,13 +4401,29 @@ export type PartialObjectProps<Props extends ObjectProps> = {
3915
4401
  * @group Objects
3916
4402
  */
3917
4403
  export declare const nullableToOptional: <const Props extends ObjectProps>(props: Props, ..._validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]) => ObjectType<NullableToOptionalProps<Props>>;
3918
- /** @group Objects */
4404
+ /**
4405
+ * Maps object properties whose Union Type includes {@link Null} to optional
4406
+ * properties.
4407
+ *
4408
+ * @group Objects
4409
+ */
3919
4410
  export type NullableToOptionalProps<Props extends ObjectProps> = {
3920
4411
  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
4412
  };
3922
4413
  /**
3923
4414
  * Object {@link Type} without the selected declared properties.
3924
4415
  *
4416
+ * ### Example
4417
+ *
4418
+ * ```ts
4419
+ * import { String, object, omit } from "@evolu/common";
4420
+ *
4421
+ * const User = object({ name: String, password: String });
4422
+ * const PublicUser = omit(User, "password");
4423
+ *
4424
+ * expectOk(PublicUser.fromUnknown({ name: "Ada" }), { name: "Ada" });
4425
+ * ```
4426
+ *
3925
4427
  * @group Objects
3926
4428
  */
3927
4429
  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,10 +4433,10 @@ type ValidateOmitKeys<Keys extends ReadonlyArray<PropertyKey>> = number extends
3931
4433
  type OmitKeysTupleError = CompileTimeError<"Type", "Omitted keys must use one concrete finite tuple.">;
3932
4434
  type OmitKeyConcreteTypeError = CompileTimeError<"Type", "Each omitted key must be one concrete property key.">;
3933
4435
  /**
3934
- * {@link Result} {@link Type} for typed success and error values.
4436
+ * Creates a {@link Type} for {@link Result} values.
3935
4437
  *
3936
4438
  * Use this to validate Results crossing a storage, worker, API, or other
3937
- * serialization boundary. The operation returns an outer validation Result. Its
4439
+ * serialization boundary. `fromUnknown` returns an outer validation Result. Its
3938
4440
  * successful value is the inner domain Result described by `okType` and
3939
4441
  * `errorType`.
3940
4442
  *
@@ -3951,34 +4453,16 @@ type OmitKeyConcreteTypeError = CompileTimeError<"Type", "Each omitted key must
3951
4453
  *
3952
4454
  * const SyncResponse = result(
3953
4455
  * object({ timestamp: NonNegativeInt }),
3954
- * typed("SyncError", { message: String }),
4456
+ * typed("SyncFailed", { message: String }),
3955
4457
  * );
3956
4458
  *
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
- * };
4459
+ * const validated = SyncResponse.fromUnknown({
4460
+ * ok: true,
4461
+ * value: { timestamp: 42 },
4462
+ * });
3966
4463
  *
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
- * );
4464
+ * expectOk(validated, { ok: true, value: { timestamp: 42 } });
4465
+ * expectOk(validated.value, { timestamp: 42 });
3982
4466
  * ```
3983
4467
  *
3984
4468
  * @group Results
@@ -4010,7 +4494,7 @@ export declare const UnknownResult: DiscriminatedUnionType<"ok", readonly [Stric
4010
4494
  }>]>;
4011
4495
  export type UnknownResult = typeof UnknownResult.Output;
4012
4496
  /**
4013
- * Tagged {@link ObjectType}.
4497
+ * Creates an {@link ObjectType} with a literal `type` property.
4014
4498
  *
4015
4499
  * The discriminator belongs to `typed`, so additional properties cannot declare
4016
4500
  * `type`. The discriminator Input is `string`, inherited from {@link String},
@@ -4022,35 +4506,38 @@ export type UnknownResult = typeof UnknownResult.Output;
4022
4506
  * ### Example
4023
4507
  *
4024
4508
  * ```ts
4025
- * import { String, discriminatedUnion, typed } from "@evolu/common";
4509
+ * import { String, typed } from "@evolu/common";
4026
4510
  *
4027
4511
  * const Pending = typed("Pending", {
4028
4512
  * label: String,
4029
4513
  * });
4030
4514
  *
4031
- * const Completed = typed("Completed");
4032
- * const Status = discriminatedUnion(Pending, Completed);
4033
- *
4034
- * expectOk(Status.fromUnknown({ type: "Pending", label: "Waiting" }), {
4515
+ * expectOk(Pending.fromUnknown({ type: "Pending", label: "Waiting" }), {
4035
4516
  * type: "Pending",
4036
4517
  * label: "Waiting",
4037
4518
  * });
4038
- * expectOk(Status.fromUnknown({ type: "Completed" }), {
4039
- * type: "Completed",
4040
- * });
4041
4519
  * ```
4042
4520
  *
4043
4521
  * @group Discriminated unions
4044
4522
  */
4045
4523
  export declare function typed<const Tag extends TypeName>(tag: ValidateTypedTag<Tag>): TypedType<Tag>;
4524
+ /** Creates a Tagged Object Type with declared properties. */
4046
4525
  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>;
4526
+ /** Creates a Tagged Object Type with additional record properties. */
4047
4527
  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
4528
  TypedValidationError<Props> | ObjectRecordValidationError<TypedProps<Tag, Props>, Rest>
4049
4529
  ] extends [never] ? [] : [
4050
4530
  ValidationFailure<TypedValidationError<Props> | ObjectRecordValidationError<TypedProps<Tag, Props>, Rest>>
4051
4531
  ]): TypedType<Tag, Props, Rest extends ObjectRecordTypeNode ? Rest : never>;
4052
4532
  /**
4053
- * A structurally tagged value created by {@link typed}.
4533
+ * A TypeScript interface with a literal `type` property.
4534
+ *
4535
+ * Use `Typed` for both domain objects in discriminated unions and plain domain
4536
+ * errors returned by {@link Result}. Name a domain error interface `XError`.
4537
+ * When `X` already describes a failure, use `X` for its `type` discriminant
4538
+ * because `Error` describes the interface's role rather than the runtime error
4539
+ * kind. Keep `Error` when it is needed to make the discriminant unambiguous,
4540
+ * such as `TimeoutError`.
4054
4541
  *
4055
4542
  * Typed unions model mutually exclusive states as separate variants instead of
4056
4543
  * combinations of flags and optional properties. TypeScript narrows a union by
@@ -4061,20 +4548,23 @@ export declare function typed<const Tag extends TypeName, const Props extends Ob
4061
4548
  * ### Example
4062
4549
  *
4063
4550
  * ```ts
4064
- * import { type Typed } from "@evolu/common";
4551
+ * import { err, ok, type Result, type Typed } from "@evolu/common";
4065
4552
  *
4066
- * type Status = Typed<"Pending"> | Typed<"Completed">;
4553
+ * interface User extends Typed<"User"> {
4554
+ * readonly id: string;
4555
+ * }
4067
4556
  *
4068
- * const getStatusMessage = (status: Status): string => {
4069
- * switch (status.type) {
4070
- * case "Pending":
4071
- * return "Waiting";
4072
- * case "Completed":
4073
- * return "Done";
4074
- * }
4075
- * };
4557
+ * const getUser = (id: string): Result<User, UserNotFoundError> =>
4558
+ * id === "user-1"
4559
+ * ? ok({ type: "User", id })
4560
+ * : err({ type: "UserNotFound", id });
4561
+ *
4562
+ * interface UserNotFoundError extends Typed<"UserNotFound"> {
4563
+ * readonly id: string;
4564
+ * }
4076
4565
  *
4077
- * expect(getStatusMessage({ type: "Pending" })).toBe("Waiting");
4566
+ * expectOk(getUser("user-1"), { type: "User", id: "user-1" });
4567
+ * expectErr(getUser("missing"), { type: "UserNotFound", id: "missing" });
4078
4568
  * ```
4079
4569
  *
4080
4570
  * @group Discriminated unions
@@ -4085,7 +4575,7 @@ export interface Typed<Tag extends TypeName> {
4085
4575
  /**
4086
4576
  * Extracts members of a {@link Typed} Output union by their `type` literal.
4087
4577
  *
4088
- * The requested name is constrained to the union's actual discriminator values,
4578
+ * The requested tag is constrained to the union's actual discriminator values,
4089
4579
  * so a misspelling is a TypeScript error instead of silently producing
4090
4580
  * `never`.
4091
4581
  *
@@ -4131,7 +4621,8 @@ type ConcreteTypedTagError = CompileTimeError<"Type", "Tag must be one concrete
4131
4621
  type TypedValidationError<Props extends ObjectProps> = "type" extends keyof Props ? TypedTypePropertyError : ObjectValidationError<Props>;
4132
4622
  type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties must not declare the reserved "type" property.'>;
4133
4623
  /**
4134
- * Producer-result {@link Type} for value, error, or done outcomes.
4624
+ * Creates a {@link Type} for producer Results with value, error, or done
4625
+ * outcomes.
4135
4626
  *
4136
4627
  * The three outcomes are `Ok<Value>`, `Err<Error>`, and `Err<Typed<"Done"> & {
4137
4628
  * done: Done }>`. This keeps normal completion distinct from failure while
@@ -4144,7 +4635,7 @@ type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties mu
4144
4635
  *
4145
4636
  * const StringNextResult = nextResult(
4146
4637
  * String,
4147
- * typed("ProducerError", { message: String }),
4638
+ * typed("ReadFailed", { message: String }),
4148
4639
  * String,
4149
4640
  * );
4150
4641
  *
@@ -4168,7 +4659,7 @@ type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties mu
4168
4659
  * expect(
4169
4660
  * describeNext({
4170
4661
  * ok: false,
4171
- * error: { type: "ProducerError", message: "Offline" },
4662
+ * error: { type: "ReadFailed", message: "Offline" },
4172
4663
  * }),
4173
4664
  * ).toBe("Error: Offline");
4174
4665
  * ```
@@ -4200,7 +4691,7 @@ export declare const UnknownNextResult: DiscriminatedUnionType<"ok", readonly [S
4200
4691
  }>]>;
4201
4692
  export type UnknownNextResult = typeof UnknownNextResult.Output;
4202
4693
  /**
4203
- * Discriminated Union {@link Type}.
4694
+ * Discriminated union {@link Type}.
4204
4695
  *
4205
4696
  * With no explicit key, the conventional `type` property created by
4206
4697
  * {@link typed} is used. Pass a key first to discriminate
@@ -4231,6 +4722,34 @@ export type UnknownNextResult = typeof UnknownNextResult.Output;
4231
4722
  * @group Discriminated unions
4232
4723
  */
4233
4724
  export declare function discriminatedUnion<const Members extends DiscriminatedUnionMembers>(...members: Members & DiscriminatedUnionValidation<"type", Members>): DiscriminatedUnionType<"type", Members>;
4725
+ /**
4726
+ * Creates a Discriminated Union Type with an explicit discriminator key.
4727
+ *
4728
+ * ### Example
4729
+ *
4730
+ * ```ts
4731
+ * import {
4732
+ * Number,
4733
+ * String,
4734
+ * discriminatedUnion,
4735
+ * literal,
4736
+ * object,
4737
+ * } from "@evolu/common";
4738
+ *
4739
+ * const Added = object({ kind: literal("added"), value: String });
4740
+ * const Removed = object({ kind: literal("removed"), id: Number });
4741
+ * const Event = discriminatedUnion("kind", Added, Removed);
4742
+ *
4743
+ * expectOk(Event.fromUnknown({ kind: "added", value: "Evolu" }), {
4744
+ * kind: "added",
4745
+ * value: "Evolu",
4746
+ * });
4747
+ * expectOk(Event.fromUnknown({ kind: "removed", id: 1 }), {
4748
+ * kind: "removed",
4749
+ * id: 1,
4750
+ * });
4751
+ * ```
4752
+ */
4234
4753
  export declare function discriminatedUnion<const Key extends string, const Members extends DiscriminatedUnionMembers>(key: ValidateDiscriminatedUnionKey<Key>, ...members: Members & DiscriminatedUnionValidation<Key, Members>): DiscriminatedUnionType<Key, Members>;
4235
4754
  /**
4236
4755
  * The routed {@link Type} returned by {@link discriminatedUnion}.
@@ -4353,10 +4872,10 @@ type DiscriminatedUnionMemberConcreteTypeError = CompileTimeError<"Type", "Membe
4353
4872
  type DiscriminatedUnionPropertyError<Key extends string> = CompileTimeError<"Type", `Property "${Key}" must be a required String, Number, BigInt, or Boolean Literal Type in every member.`>;
4354
4873
  type DiscriminatedUnionDuplicateValueError<Key extends string, Expected extends DiscriminatedUnionLiteral> = CompileTimeError<"Type", `Duplicate value "${Expected}" at property "${Key}".`>;
4355
4874
  /**
4356
- * Lazy {@link Type} for recursive definitions.
4875
+ * Creates a lazy {@link Type} for recursive definitions.
4357
4876
  *
4358
- * Lazy defers and caches a Type definition, allowing recursive data such as
4359
- * trees and mutually recursive models.
4877
+ * The definition is evaluated on first use and then cached, allowing recursive
4878
+ * data such as trees and mutually recursive models.
4360
4879
  *
4361
4880
  * A recursive declaration refers to its own variable while that variable is
4362
4881
  * being initialized, so TypeScript cannot infer it reliably. Getter-based
@@ -4376,12 +4895,10 @@ type DiscriminatedUnionDuplicateValueError<Key extends string, Expected extends
4376
4895
  *
4377
4896
  * ```ts
4378
4897
  * import {
4379
- * Number,
4380
4898
  * String,
4381
4899
  * array,
4382
4900
  * lazy,
4383
4901
  * object,
4384
- * optional,
4385
4902
  * type ArrayError,
4386
4903
  * type LazyType,
4387
4904
  * type ObjectError,
@@ -4402,35 +4919,19 @@ type DiscriminatedUnionDuplicateValueError<Key extends string, Expected extends
4402
4919
  * () => object({ value: String, children: array(Tree) }),
4403
4920
  * );
4404
4921
  *
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
- * );
4922
+ * const result = Tree.fromUnknown({
4923
+ * value: "root",
4924
+ * children: [{ value: "leaf", children: [] }],
4925
+ * });
4428
4926
  *
4429
- * const Right: LazyType<Right, Right, never, RightError, RightError> =
4430
- * lazy(() => object({ count: Number, left: optional(Left) }));
4927
+ * expectOk(result, {
4928
+ * value: "root",
4929
+ * children: [{ value: "leaf", children: [] }],
4930
+ * });
4931
+ * expectTypeOf(result.value).toEqualTypeOf<Tree>();
4431
4932
  * ```
4432
4933
  *
4433
- * @group Recursive Types
4934
+ * @group Recursive
4434
4935
  */
4435
4936
  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
4937
  /**
@@ -4448,7 +4949,7 @@ export declare function lazy<Target extends ConcreteTypeNode>(getType: Thunk<Val
4448
4949
  * recursive declaration finite for TypeScript while preserving structured
4449
4950
  * errors at every boundary.
4450
4951
  *
4451
- * @group Recursive Types
4952
+ * @group Recursive
4452
4953
  */
4453
4954
  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
4955
  readonly [lazyTypeSymbol]: true;
@@ -4504,7 +5005,7 @@ export interface JsonObject {
4504
5005
  readonly [key: string]: JsonValue;
4505
5006
  }
4506
5007
  /**
4507
- * One issue found while validating an exact {@link JsonValue}.
5008
+ * One issue found while validating a candidate as an exact {@link JsonValue}.
4508
5009
  *
4509
5010
  * @group JSON
4510
5011
  */
@@ -4542,7 +5043,8 @@ export type JsonValueIssue = {
4542
5043
  readonly ancestorPath: ReadonlyArray<string | number | symbol>;
4543
5044
  };
4544
5045
  /**
4545
- * An error containing one or more issues found in a {@link JsonValue}.
5046
+ * An error containing one or more issues found while validating a candidate as
5047
+ * an exact {@link JsonValue}.
4546
5048
  *
4547
5049
  * @group JSON
4548
5050
  */
@@ -4580,6 +5082,21 @@ export interface JsonError extends TypeError<"Json"> {
4580
5082
  /**
4581
5083
  * Exact root Type for {@link JsonValue} data trees.
4582
5084
  *
5085
+ * ### Example
5086
+ *
5087
+ * ```ts
5088
+ * import { JsonValue, type JsonValueInput } from "@evolu/common";
5089
+ *
5090
+ * const input: JsonValueInput = {
5091
+ * name: "Ada",
5092
+ * scores: [10, 20],
5093
+ * };
5094
+ * const result = JsonValue.fromUnknown(input);
5095
+ *
5096
+ * expectOk(result, input);
5097
+ * expectTypeOf(result.value).toEqualTypeOf<JsonValue>();
5098
+ * ```
5099
+ *
4583
5100
  * @group JSON
4584
5101
  */
4585
5102
  export declare const JsonValue: JsonValueType;
@@ -4599,7 +5116,7 @@ export declare const JsonObject: JsonObjectType;
4599
5116
  * A {@link String} Brand proving that its exact text parses to {@link JsonValue}.
4600
5117
  *
4601
5118
  * The Brand preserves whitespace, property order, and number spelling. Convert
4602
- * it totally to {@link JsonValue} through {@link JsonValueFromJson} or
5119
+ * it to {@link JsonValue} through {@link JsonValueFromJson} or
4603
5120
  * {@link jsonToJsonValue}.
4604
5121
  *
4605
5122
  * @group JSON
@@ -4607,88 +5124,100 @@ export declare const JsonObject: JsonObjectType;
4607
5124
  export declare const Json: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Json", JsonError>;
4608
5125
  export type Json = typeof Json.Output;
4609
5126
  /**
4610
- * Totally parses proven {@link Json} text into an exact {@link JsonValue}.
5127
+ * Converts proven {@link Json} text to an exact {@link JsonValue}.
5128
+ *
5129
+ * ### Example
5130
+ *
5131
+ * ```ts
5132
+ * import { Json, jsonToJsonValue } from "@evolu/common";
5133
+ *
5134
+ * const value = jsonToJsonValue(Json.orThrow('{"name":"Ada"}'));
5135
+ *
5136
+ * expect(value).toEqual({ name: "Ada" });
5137
+ * ```
4611
5138
  *
4612
5139
  * @group JSON
4613
5140
  */
4614
5141
  export declare const jsonToJsonValue: (value: Json) => JsonValue;
4615
5142
  /**
4616
- * Totally encodes an exact {@link JsonValue} as canonical {@link Json} text.
5143
+ * Converts an exact {@link JsonValue} to canonical {@link Json} text.
5144
+ *
5145
+ * ### Example
5146
+ *
5147
+ * ```ts
5148
+ * import { jsonValueToJson, type JsonValue } from "@evolu/common";
5149
+ *
5150
+ * const value: JsonValue = { name: "Ada" };
5151
+ *
5152
+ * expect(jsonValueToJson(value)).toBe('{"name":"Ada"}');
5153
+ * ```
4617
5154
  *
4618
5155
  * @group JSON
4619
5156
  */
4620
5157
  export declare const jsonValueToJson: (value: JsonValue) => Json;
4621
5158
  /**
4622
- * {@link Json} to {@link JsonValue} transformation.
5159
+ * Transformation {@link Type} that parses {@link Json} into {@link JsonValue}.
4623
5160
  *
4624
5161
  * Decoding unknown input first validates the Json Brand. Starting from the
4625
5162
  * typed Json parent is infallible. Encoding canonicalizes JSON text.
4626
5163
  *
5164
+ * ### Example
5165
+ *
5166
+ * ```ts
5167
+ * import { JsonValueFromJson } from "@evolu/common";
5168
+ *
5169
+ * const result = JsonValueFromJson.fromUnknown('{ "name": "Ada" }');
5170
+ *
5171
+ * expectOk(result, { name: "Ada" });
5172
+ * expect(JsonValueFromJson.to(result.value)).toBe('{"name":"Ada"}');
5173
+ * ```
5174
+ *
4627
5175
  * @group JSON
4628
5176
  */
4629
5177
  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">>;
4630
5178
  /**
4631
- * Branded {@link Json} Type and total conversions for another Type.
4632
- *
4633
- * Use this factory when a domain value must be stored as JSON text while its
4634
- * exact Type remains visible to TypeScript, such as a JSON column in an Evolu
4635
- * Schema. The returned tuple contains the branded Json Type, an encoder from
4636
- * the supplied Type's Output to Json, and a decoder from Json back to that
4637
- * Output.
4638
- *
4639
- * The supplied Type's `CanonicalInput` must be JSON-compatible. The encoder
4640
- * first uses the Type's canonical `to` operation, then encodes that
4641
- * representation as canonical Json. Runtime representation constraints
4642
- * TypeScript cannot prove, such as dense Arrays and enumerable data properties,
4643
- * are asserted as developer errors.
4644
- *
4645
- * The branded Json Type is the validation boundary for unknown JSON text. It
4646
- * grants its {@link Brand} only when the text is valid Json and decoding it
4647
- * through the supplied Type succeeds. The supplied Type is responsible for
4648
- * preserving semantic Outputs across canonical JSON encoding and decoding. This
4649
- * law cannot be checked generically because Types do not define semantic
4650
- * equality. Before granting the Brand, the encoder asserts the weaker runtime
4651
- * guarantee that the final Json successfully decodes through the supplied Type.
4652
- * Failed decodability therefore throws as a developer error.
4653
- *
4654
- * Consequently, the two typed conversions return their values directly without
4655
- * exposing a validation {@link Result}: an Output satisfying the JSON
4656
- * representation contract of a correctly declared Type can always be encoded,
4657
- * and the branded Json proves decoding will succeed. Decoding still runs the
4658
- * Type pipeline because transformations may need to construct different Output
4659
- * values.
5179
+ * Branded {@link Json} Type and conversions for another {@link Type}.
5180
+ *
5181
+ * Use this when a value must be stored as JSON text, such as in a JSON column
5182
+ * in an Evolu Schema. It returns a branded Json Type and functions for
5183
+ * converting the supplied Type's Output to and from that branded JSON
5184
+ * representation.
4660
5185
  *
4661
5186
  * ### Example
4662
5187
  *
4663
5188
  * ```ts
4664
5189
  * import {
4665
5190
  * Age,
5191
+ * NonEmptyTrimmedString100,
4666
5192
  * json,
4667
5193
  * object,
4668
- * String,
4669
5194
  * type Brand,
4670
- * type InferType,
4671
- * type Json,
4672
5195
  * } from "@evolu/common";
4673
5196
  *
4674
- * const Person = object({ name: String, age: Age });
4675
- * interface Person extends InferType<typeof Person> {}
5197
+ * const User = object({
5198
+ * name: NonEmptyTrimmedString100,
5199
+ * age: Age,
5200
+ * });
4676
5201
  *
4677
- * const [PersonJson, personToPersonJson, personJsonToPerson] = json(
4678
- * Person,
4679
- * "PersonJson",
5202
+ * const [UserJson, userToUserJson, userJsonToUser] = json(
5203
+ * User,
5204
+ * "UserJson",
4680
5205
  * );
4681
- * type PersonJson = typeof PersonJson.Output;
4682
- *
4683
- * expectTypeOf<PersonJson>().toEqualTypeOf<Json & Brand<"PersonJson">>();
4684
5206
  *
4685
- * const person = Person.orThrow({ name: "Ada", age: 42 });
4686
- * const personJson = personToPersonJson(person);
4687
- * const decodedPerson = personJsonToPerson(personJson);
5207
+ * const user = User.orThrow({ name: "Ada", age: 37 });
5208
+ * const userJson = userToUserJson(user);
4688
5209
  *
4689
- * expect(decodedPerson).toEqual(person);
5210
+ * expectTypeOf(userJson).toEqualTypeOf<
5211
+ * string & Brand<"Json"> & Brand<"UserJson">
5212
+ * >();
5213
+ * expect(userJson).toBe('{"name":"Ada","age":37}');
5214
+ * expect(userJsonToUser(userJson)).toEqual(user);
4690
5215
  * ```
4691
5216
  *
5217
+ * The supplied Type must have a JSON-compatible `CanonicalInput`. The branded
5218
+ * Json Type accepts only valid JSON text whose parsed value can be decoded by
5219
+ * the supplied Type.
5220
+ *
4692
5221
  * @group JSON
4693
5222
  */
4694
5223
  export declare const json: <T extends ConcreteTypeNode, Name extends TypeName>(type: T, name: ValidateChildTypeName<Name, typeof Json>, ..._validation: [JsonTypeValidationError<T>] extends [never] ? [] : [ValidationFailure<JsonTypeValidationError<T>>]) => readonly [jsonType: BrandType<typeof Json, Name, TypeError<Name> & TransparentTypeError & {