@evolu/common 8.14.0 → 8.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/dist/src/Crypto.d.ts +2 -1
  2. package/dist/src/Crypto.d.ts.map +1 -1
  3. package/dist/src/Redacted.d.ts +19 -39
  4. package/dist/src/Redacted.d.ts.map +1 -1
  5. package/dist/src/Redacted.js +18 -33
  6. package/dist/src/Type.d.ts +161 -0
  7. package/dist/src/Type.d.ts.map +1 -1
  8. package/dist/src/Type.js +152 -2
  9. package/dist/src/WebSocket.d.ts +16 -1
  10. package/dist/src/WebSocket.d.ts.map +1 -1
  11. package/dist/src/WebSocket.js +14 -2
  12. package/dist/src/intl/_en.d.ts +5 -1
  13. package/dist/src/intl/_en.d.ts.map +1 -1
  14. package/dist/src/intl/_en.js +4 -0
  15. package/dist/src/intl/ar.d.ts +5 -1
  16. package/dist/src/intl/ar.d.ts.map +1 -1
  17. package/dist/src/intl/ar.js +4 -0
  18. package/dist/src/intl/bn.d.ts +5 -1
  19. package/dist/src/intl/bn.d.ts.map +1 -1
  20. package/dist/src/intl/bn.js +4 -0
  21. package/dist/src/intl/ca.d.ts +5 -1
  22. package/dist/src/intl/ca.d.ts.map +1 -1
  23. package/dist/src/intl/ca.js +4 -0
  24. package/dist/src/intl/cs.d.ts +5 -1
  25. package/dist/src/intl/cs.d.ts.map +1 -1
  26. package/dist/src/intl/cs.js +4 -0
  27. package/dist/src/intl/da.d.ts +5 -1
  28. package/dist/src/intl/da.d.ts.map +1 -1
  29. package/dist/src/intl/da.js +4 -0
  30. package/dist/src/intl/de.d.ts +5 -1
  31. package/dist/src/intl/de.d.ts.map +1 -1
  32. package/dist/src/intl/de.js +4 -0
  33. package/dist/src/intl/el.d.ts +5 -1
  34. package/dist/src/intl/el.d.ts.map +1 -1
  35. package/dist/src/intl/el.js +4 -0
  36. package/dist/src/intl/es.d.ts +5 -1
  37. package/dist/src/intl/es.d.ts.map +1 -1
  38. package/dist/src/intl/es.js +4 -0
  39. package/dist/src/intl/fa.d.ts +5 -1
  40. package/dist/src/intl/fa.d.ts.map +1 -1
  41. package/dist/src/intl/fa.js +4 -0
  42. package/dist/src/intl/fi.d.ts +5 -1
  43. package/dist/src/intl/fi.d.ts.map +1 -1
  44. package/dist/src/intl/fi.js +4 -0
  45. package/dist/src/intl/fil.d.ts +5 -1
  46. package/dist/src/intl/fil.d.ts.map +1 -1
  47. package/dist/src/intl/fil.js +4 -0
  48. package/dist/src/intl/fr.d.ts +5 -1
  49. package/dist/src/intl/fr.d.ts.map +1 -1
  50. package/dist/src/intl/fr.js +4 -0
  51. package/dist/src/intl/he.d.ts +5 -1
  52. package/dist/src/intl/he.d.ts.map +1 -1
  53. package/dist/src/intl/he.js +4 -0
  54. package/dist/src/intl/hi.d.ts +5 -1
  55. package/dist/src/intl/hi.d.ts.map +1 -1
  56. package/dist/src/intl/hi.js +4 -0
  57. package/dist/src/intl/hr.d.ts +5 -1
  58. package/dist/src/intl/hr.d.ts.map +1 -1
  59. package/dist/src/intl/hr.js +4 -0
  60. package/dist/src/intl/hu.d.ts +3 -1
  61. package/dist/src/intl/hu.d.ts.map +1 -1
  62. package/dist/src/intl/hu.js +2 -0
  63. package/dist/src/intl/id.d.ts +5 -1
  64. package/dist/src/intl/id.d.ts.map +1 -1
  65. package/dist/src/intl/id.js +4 -0
  66. package/dist/src/intl/it.d.ts +5 -1
  67. package/dist/src/intl/it.d.ts.map +1 -1
  68. package/dist/src/intl/it.js +4 -0
  69. package/dist/src/intl/ja.d.ts +5 -1
  70. package/dist/src/intl/ja.d.ts.map +1 -1
  71. package/dist/src/intl/ja.js +4 -0
  72. package/dist/src/intl/ko.d.ts +5 -1
  73. package/dist/src/intl/ko.d.ts.map +1 -1
  74. package/dist/src/intl/ko.js +4 -0
  75. package/dist/src/intl/ml.d.ts +5 -1
  76. package/dist/src/intl/ml.d.ts.map +1 -1
  77. package/dist/src/intl/ml.js +4 -0
  78. package/dist/src/intl/mr.d.ts +5 -1
  79. package/dist/src/intl/mr.d.ts.map +1 -1
  80. package/dist/src/intl/mr.js +4 -0
  81. package/dist/src/intl/ms.d.ts +5 -1
  82. package/dist/src/intl/ms.d.ts.map +1 -1
  83. package/dist/src/intl/ms.js +4 -0
  84. package/dist/src/intl/nb.d.ts +3 -1
  85. package/dist/src/intl/nb.d.ts.map +1 -1
  86. package/dist/src/intl/nb.js +2 -0
  87. package/dist/src/intl/nl.d.ts +5 -1
  88. package/dist/src/intl/nl.d.ts.map +1 -1
  89. package/dist/src/intl/nl.js +4 -0
  90. package/dist/src/intl/pa.d.ts +5 -1
  91. package/dist/src/intl/pa.d.ts.map +1 -1
  92. package/dist/src/intl/pa.js +4 -0
  93. package/dist/src/intl/pl.d.ts +4 -0
  94. package/dist/src/intl/pl.d.ts.map +1 -1
  95. package/dist/src/intl/pl.js +4 -0
  96. package/dist/src/intl/pt-BR.d.ts +5 -1
  97. package/dist/src/intl/pt-BR.d.ts.map +1 -1
  98. package/dist/src/intl/pt-BR.js +4 -0
  99. package/dist/src/intl/pt.d.ts +5 -1
  100. package/dist/src/intl/pt.d.ts.map +1 -1
  101. package/dist/src/intl/pt.js +4 -0
  102. package/dist/src/intl/ro.d.ts +5 -1
  103. package/dist/src/intl/ro.d.ts.map +1 -1
  104. package/dist/src/intl/ro.js +4 -0
  105. package/dist/src/intl/sk.d.ts +5 -1
  106. package/dist/src/intl/sk.d.ts.map +1 -1
  107. package/dist/src/intl/sk.js +4 -0
  108. package/dist/src/intl/sl.d.ts +5 -1
  109. package/dist/src/intl/sl.d.ts.map +1 -1
  110. package/dist/src/intl/sl.js +4 -0
  111. package/dist/src/intl/sv.d.ts +5 -1
  112. package/dist/src/intl/sv.d.ts.map +1 -1
  113. package/dist/src/intl/sv.js +4 -0
  114. package/dist/src/intl/sw.d.ts +2 -0
  115. package/dist/src/intl/sw.d.ts.map +1 -1
  116. package/dist/src/intl/sw.js +2 -0
  117. package/dist/src/intl/ta.d.ts +5 -1
  118. package/dist/src/intl/ta.d.ts.map +1 -1
  119. package/dist/src/intl/ta.js +4 -0
  120. package/dist/src/intl/te.d.ts +5 -1
  121. package/dist/src/intl/te.d.ts.map +1 -1
  122. package/dist/src/intl/te.js +4 -0
  123. package/dist/src/intl/th.d.ts +5 -1
  124. package/dist/src/intl/th.d.ts.map +1 -1
  125. package/dist/src/intl/th.js +4 -0
  126. package/dist/src/intl/tr.d.ts +5 -1
  127. package/dist/src/intl/tr.d.ts.map +1 -1
  128. package/dist/src/intl/tr.js +4 -0
  129. package/dist/src/intl/uk.d.ts +5 -1
  130. package/dist/src/intl/uk.d.ts.map +1 -1
  131. package/dist/src/intl/uk.js +4 -0
  132. package/dist/src/intl/ur.d.ts +5 -1
  133. package/dist/src/intl/ur.d.ts.map +1 -1
  134. package/dist/src/intl/ur.js +4 -0
  135. package/dist/src/intl/vi.d.ts +5 -1
  136. package/dist/src/intl/vi.d.ts.map +1 -1
  137. package/dist/src/intl/vi.js +4 -0
  138. package/dist/src/intl/zh-CN.d.ts +5 -1
  139. package/dist/src/intl/zh-CN.d.ts.map +1 -1
  140. package/dist/src/intl/zh-CN.js +4 -0
  141. package/dist/src/intl/zh-TW.d.ts +5 -1
  142. package/dist/src/intl/zh-TW.d.ts.map +1 -1
  143. package/dist/src/intl/zh-TW.js +4 -0
  144. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  145. package/dist/src/local-first/Evolu.js +6 -1
  146. package/package.json +1 -1
  147. package/src/Crypto.ts +2 -1
  148. package/src/Redacted.test.ts +231 -0
  149. package/src/Redacted.ts +36 -47
  150. package/src/Type.test.ts +166 -0
  151. package/src/Type.ts +198 -2
  152. package/src/WebSocket.ts +33 -4
  153. package/src/intl/_en.ts +10 -0
  154. package/src/intl/ar.ts +8 -0
  155. package/src/intl/bn.ts +10 -0
  156. package/src/intl/ca.ts +10 -0
  157. package/src/intl/cs.ts +10 -0
  158. package/src/intl/da.ts +10 -0
  159. package/src/intl/de.ts +10 -0
  160. package/src/intl/el.ts +10 -0
  161. package/src/intl/es.ts +10 -0
  162. package/src/intl/fa.ts +10 -0
  163. package/src/intl/fi.ts +10 -0
  164. package/src/intl/fil.ts +10 -0
  165. package/src/intl/fr.ts +10 -0
  166. package/src/intl/he.ts +10 -0
  167. package/src/intl/hi.ts +10 -0
  168. package/src/intl/hr.ts +10 -0
  169. package/src/intl/hu.ts +6 -0
  170. package/src/intl/id.ts +10 -0
  171. package/src/intl/intl.test.ts +88 -0
  172. package/src/intl/it.ts +10 -0
  173. package/src/intl/ja.ts +10 -0
  174. package/src/intl/ko.ts +10 -0
  175. package/src/intl/ml.ts +10 -0
  176. package/src/intl/mr.ts +10 -0
  177. package/src/intl/ms.ts +8 -0
  178. package/src/intl/nb.ts +6 -0
  179. package/src/intl/nl.ts +10 -0
  180. package/src/intl/pa.ts +10 -0
  181. package/src/intl/pl.ts +12 -0
  182. package/src/intl/pt-BR.ts +10 -0
  183. package/src/intl/pt.ts +8 -0
  184. package/src/intl/ro.ts +10 -0
  185. package/src/intl/sk.ts +8 -0
  186. package/src/intl/sl.ts +10 -0
  187. package/src/intl/sv.ts +10 -0
  188. package/src/intl/sw.ts +4 -0
  189. package/src/intl/ta.ts +10 -0
  190. package/src/intl/te.ts +10 -0
  191. package/src/intl/th.ts +10 -0
  192. package/src/intl/tr.ts +10 -0
  193. package/src/intl/uk.ts +10 -0
  194. package/src/intl/ur.ts +8 -0
  195. package/src/intl/vi.ts +8 -0
  196. package/src/intl/zh-CN.ts +10 -0
  197. package/src/intl/zh-TW.ts +10 -0
  198. package/src/local-first/Evolu.test.ts +62 -8
  199. package/src/local-first/Evolu.ts +7 -1
@@ -258,7 +258,8 @@ export declare const createPadmePadding: (length: NonNegativeInt) => Uint8Array;
258
258
  /**
259
259
  * Performs a timing-safe comparison of two Uint8Arrays. Returns true if they
260
260
  * are equal, false otherwise. Takes constant time regardless of where the
261
- * arrays differ.
261
+ * arrays differ. Arrays of different lengths are unequal, and the comparison
262
+ * does not hide their lengths.
262
263
  *
263
264
  * @group Comparison
264
265
  * @see https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b
@@ -1 +1 @@
1
- {"version":3,"file":"Crypto.d.ts","sourceRoot":"","sources":["../../src/Crypto.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Crypto.d.ts","sourceRoot":"","sources":["../../src/Crypto.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,6 @@
4
4
  * @module
5
5
  */
6
6
  import type { Brand } from "./Brand.ts";
7
- import type { Eq } from "./Eq.ts";
8
7
  /**
9
8
  * A wrapper type that prevents sensitive values from being accidentally exposed
10
9
  * through logging, serialization, or inspection.
@@ -15,13 +14,17 @@ import type { Eq } from "./Eq.ts";
15
14
  *
16
15
  * For type-level distinction between different secrets, use branded types.
17
16
  *
18
- * The actual value lives in a `WeakMap`, so it never appears as a property and
19
- * is automatically garbage collected when the wrapper is dropped. This is
20
- * better than a class with a private field because private fields are still
21
- * visible in devtools. Symbols can't be used because they don't support custom
22
- * `toString`.
17
+ * Redacted guards against accidental exposure, such as logs, error reports, and
18
+ * serialized payloads. It does not hide the value from a debugger: DevTools and
19
+ * heap snapshots can still reach it.
23
20
  *
24
- * Implements `Disposable` for automatic cleanup via the `using` syntax.
21
+ * A structured clone, such as a `postMessage` to a worker, does not copy the
22
+ * hidden value and arrives as an empty object. Reveal the value before posting
23
+ * it, and wrap it again on arrival if the receiver passes it to app code.
24
+ *
25
+ * Implements `Disposable`, so the `using` syntax detaches the value when the
26
+ * scope ends. Disposal does not overwrite the value or release other references
27
+ * to it.
25
28
  *
26
29
  * ### Example
27
30
  *
@@ -45,7 +48,6 @@ import type { Eq } from "./Eq.ts";
45
48
  * using redactedKey: RedactedApiKey = createRedacted(apiKey);
46
49
  * const fetchUser = (key: RedactedApiKey): ApiKey => revealRedacted(key);
47
50
  *
48
- * // oxlint-disable-next-line typescript/no-base-to-string -- Redacted intentionally implements a safe custom toString.
49
51
  * assertEqual(redactedKey.toString(), "<redacted>");
50
52
  * assertEqual(
51
53
  * JSON.stringify({ apiKey: redactedKey }),
@@ -61,13 +63,18 @@ import type { Eq } from "./Eq.ts";
61
63
  * using key = createRedacted(apiKey);
62
64
  * return key;
63
65
  * })();
64
- * // Leaving the `using` scope removes the value from memory.
66
+ * // Leaving the `using` scope detaches the value, so revealing it throws.
65
67
  * assertErr(trySync(() => revealRedacted(disposedKey)));
66
68
  * ```
67
69
  */
68
70
  export interface Redacted<A> extends Brand<"Redacted">, Disposable {
69
- /** The inner type. Useful for inference via `typeof redacted.Type`. */
71
+ /**
72
+ * The inner type. This is a type-only phantom property. Use it through
73
+ * `typeof redacted.Type`; it does not exist at runtime.
74
+ */
70
75
  readonly Type: A;
76
+ readonly toString: () => "<redacted>";
77
+ readonly toJSON: () => "<redacted>";
71
78
  }
72
79
  /** Creates a {@link Redacted} wrapper for a sensitive value. */
73
80
  export declare const createRedacted: <A>(value: A) => Redacted<A>;
@@ -77,37 +84,10 @@ export declare const createRedacted: <A>(value: A) => Redacted<A>;
77
84
  * This is a separate function rather than a method on {@link Redacted} to make
78
85
  * access visually explicit and easy to grep in code reviews. Accessing
79
86
  * sensitive values should feel intentional, not convenient.
87
+ *
88
+ * Throws when the wrapper was disposed or is a structured clone.
80
89
  */
81
90
  export declare const revealRedacted: <A>(redacted: Redacted<A>) => A;
82
91
  /** Checks if a value is a {@link Redacted} wrapper. */
83
92
  export declare const isRedacted: (value: unknown) => value is Redacted<unknown>;
84
- /**
85
- * Creates an {@link Eq} for {@link Redacted} values based on an equality function
86
- * for the underlying type.
87
- *
88
- * ### Example
89
- *
90
- * ```ts
91
- * import {
92
- * assertFalse,
93
- * assertTrue,
94
- * createEqRedacted,
95
- * createRedacted,
96
- * eqString,
97
- * type Brand,
98
- * } from "@evolu/common";
99
- *
100
- * type ApiKey = string & Brand<"ApiKey">;
101
- * const eqRedactedApiKey = createEqRedacted<ApiKey>(eqString);
102
- *
103
- * // Apply brands only after validation or at another trusted boundary.
104
- * using a = createRedacted("x" as ApiKey);
105
- * using b = createRedacted("x" as ApiKey);
106
- * using c = createRedacted("y" as ApiKey);
107
- *
108
- * assertTrue(eqRedactedApiKey(a, b));
109
- * assertFalse(eqRedactedApiKey(a, c));
110
- * ```
111
- */
112
- export declare const createEqRedacted: <A>(eq: Eq<A>) => Eq<Redacted<A>>;
113
93
  //# sourceMappingURL=Redacted.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Redacted.d.ts","sourceRoot":"","sources":["../../src/Redacted.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,CAAE,SAAQ,KAAK,CAAC,UAAU,CAAC,EAAE,UAAU;IAChE,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CAClB;AAED,gEAAgE;AAChE,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,CAAC,KAAG,QAAQ,CAAC,CAAC,CAItD,CAAC;AAaF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAG,CAGzD,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,UAAU,UAAW,OAAO,KAAG,KAAK,IAAI,QAAQ,CAAC,OAAO,CAG7B,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,gBAAgB,GAC1B,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,KAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAEY,CAAC"}
1
+ {"version":3,"file":"Redacted.d.ts","sourceRoot":"","sources":["../../src/Redacted.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,CAAE,SAAQ,KAAK,CAAC,UAAU,CAAC,EAAE,UAAU;IAChE;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB,QAAQ,CAAC,QAAQ,EAAE,MAAM,YAAY,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,YAAY,CAAC;CACrC;AAED,gEAAgE;AAChE,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,CAAC,KAAG,QAAQ,CAAC,CAAC,CAatD,CAAC;AAiBF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAI,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAG,CAGzD,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,UAAU,UAAW,OAAO,KAAG,KAAK,IAAI,QAAQ,CAAC,OAAO,CAG7B,CAAC"}
@@ -6,7 +6,16 @@
6
6
  import { assert } from "./Assert.js";
7
7
  /** Creates a {@link Redacted} wrapper for a sensitive value. */
8
8
  export const createRedacted = (value) => {
9
- const redacted = Object.create(proto);
9
+ // Symbol.dispose is read here rather than in proto because installPolyfills
10
+ // runs after imported modules are evaluated. An arrow function also keeps a
11
+ // detached dispose method working.
12
+ const redacted = Object.create(proto, {
13
+ [Symbol.dispose]: {
14
+ value: () => {
15
+ registry.delete(redacted);
16
+ },
17
+ },
18
+ });
10
19
  registry.set(redacted, value);
11
20
  return redacted;
12
21
  };
@@ -14,11 +23,14 @@ const proto = {
14
23
  toString: () => redactedString,
15
24
  toJSON: () => redactedString,
16
25
  [Symbol.for("nodejs.util.inspect.custom")]: () => redactedString,
17
- [Symbol.dispose]() {
18
- registry.delete(this);
19
- },
20
26
  };
21
27
  const redactedString = "<redacted>";
28
+ // The value lives in a WeakMap, so it is never a property: previews,
29
+ // enumeration, and serialization cannot show it, and it is garbage collected
30
+ // with the wrapper. A private field would show when DevTools expands the
31
+ // object. The wrapper is an object, not a symbol, because a symbol cannot
32
+ // customize toString or toJSON. DevTools can still reach the registry through
33
+ // the scopes of the wrapper's functions.
22
34
  const registry = new WeakMap();
23
35
  /**
24
36
  * Reveals the original value from a {@link Redacted} wrapper.
@@ -26,6 +38,8 @@ const registry = new WeakMap();
26
38
  * This is a separate function rather than a method on {@link Redacted} to make
27
39
  * access visually explicit and easy to grep in code reviews. Accessing
28
40
  * sensitive values should feel intentional, not convenient.
41
+ *
42
+ * Throws when the wrapper was disposed or is a structured clone.
29
43
  */
30
44
  export const revealRedacted = (redacted) => {
31
45
  assert(registry.has(redacted), "Redacted value was not in registry");
@@ -35,32 +49,3 @@ export const revealRedacted = (redacted) => {
35
49
  export const isRedacted = (value) => typeof value === "object" &&
36
50
  value !== null &&
37
51
  Object.getPrototypeOf(value) === proto;
38
- /**
39
- * Creates an {@link Eq} for {@link Redacted} values based on an equality function
40
- * for the underlying type.
41
- *
42
- * ### Example
43
- *
44
- * ```ts
45
- * import {
46
- * assertFalse,
47
- * assertTrue,
48
- * createEqRedacted,
49
- * createRedacted,
50
- * eqString,
51
- * type Brand,
52
- * } from "@evolu/common";
53
- *
54
- * type ApiKey = string & Brand<"ApiKey">;
55
- * const eqRedactedApiKey = createEqRedacted<ApiKey>(eqString);
56
- *
57
- * // Apply brands only after validation or at another trusted boundary.
58
- * using a = createRedacted("x" as ApiKey);
59
- * using b = createRedacted("x" as ApiKey);
60
- * using c = createRedacted("y" as ApiKey);
61
- *
62
- * assertTrue(eqRedactedApiKey(a, b));
63
- * assertFalse(eqRedactedApiKey(a, c));
64
- * ```
65
- */
66
- export const createEqRedacted = (eq) => (x, y) => eq(revealRedacted(x), revealRedacted(y));
@@ -3585,6 +3585,61 @@ export interface NameError extends TypeError<"Name"> {
3585
3585
  */
3586
3586
  export declare const Name: BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "UrlSafeString", RegexError<"UrlSafeString">>, "Name", NameError>;
3587
3587
  export type Name = typeof Name.Output;
3588
+ /**
3589
+ * Error returned when a string is not a valid {@link Email}.
3590
+ *
3591
+ * @group String
3592
+ */
3593
+ export interface EmailError extends TypeError<"Email"> {
3594
+ readonly value: string;
3595
+ }
3596
+ /**
3597
+ * Email address as defined by the WHATWG HTML Standard.
3598
+ *
3599
+ * Email accepts a [valid email
3600
+ * address](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address),
3601
+ * the syntax browsers enforce for `<input type="email">`. The HTML Standard
3602
+ * deliberately departs from RFC 5322: it rejects quoted local parts, comments,
3603
+ * IP address literals, and whitespace, and it accepts only ASCII. Use the ASCII
3604
+ * (`xn--`) form of internationalized domains.
3605
+ *
3606
+ * Email does not normalize. The local part is case-sensitive, so different
3607
+ * Email strings can still reach the same mailbox, and only a delivered message
3608
+ * proves that an address exists.
3609
+ *
3610
+ * The HTML Standard limits each domain label to 63 characters but sets no total
3611
+ * length. SMTP limits an address to 254 characters; compose
3612
+ * `maxLength(254)(Email)` when that limit matters.
3613
+ *
3614
+ * ### Example
3615
+ *
3616
+ * ```ts
3617
+ * import {
3618
+ * assertEqual,
3619
+ * assertErr,
3620
+ * assertOk,
3621
+ * Email,
3622
+ * maxLength,
3623
+ * } from "@evolu/common";
3624
+ *
3625
+ * assertOk(Email.fromUnknown("ada@example.com"), "ada@example.com");
3626
+ * assertOk(Email.fromUnknown("Ada@Example.com"), "Ada@Example.com");
3627
+ *
3628
+ * const invalid = Email.fromUnknown("Ada <ada@example.com>");
3629
+ * assertErr(invalid);
3630
+ * assertEqual(invalid.error, {
3631
+ * type: "Email",
3632
+ * value: "Ada <ada@example.com>",
3633
+ * });
3634
+ *
3635
+ * const SmtpEmail = maxLength(254)(Email);
3636
+ * assertErr(SmtpEmail.fromUnknown(`${"a".repeat(251)}@b.c`));
3637
+ * ```
3638
+ *
3639
+ * @group String
3640
+ */
3641
+ export declare const Email: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Email", EmailError>;
3642
+ export type Email = typeof Email.Output;
3588
3643
  /**
3589
3644
  * Stable valid {@link Name} for tests and internal fixtures.
3590
3645
  *
@@ -3829,6 +3884,112 @@ export declare const idToIdBytes: (value: Id) => IdBytes;
3829
3884
  * @group String
3830
3885
  */
3831
3886
  export declare const idBytesToId: (value: IdBytes) => Id;
3887
+ /**
3888
+ * Error returned when a string is not a canonical {@link Uuid}.
3889
+ *
3890
+ * @group String
3891
+ */
3892
+ export interface UuidError extends TypeError<"Uuid"> {
3893
+ readonly value: string;
3894
+ }
3895
+ /**
3896
+ * UUID in its canonical lowercase text form, as defined by [RFC
3897
+ * 9562](https://www.rfc-editor.org/rfc/rfc9562).
3898
+ *
3899
+ * Uuid accepts 32 lowercase hexadecimal digits in the 8-4-4-4-12 layout, as
3900
+ * produced by `crypto.randomUUID()`. It accepts every version and variant,
3901
+ * including the Nil and Max UUIDs, so every 128-bit value has exactly one
3902
+ * Uuid.
3903
+ *
3904
+ * RFC 9562 reads UUIDs in any case. Uuid requires lowercase so that equal UUIDs
3905
+ * are equal strings; lowercase text from other sources before validating it.
3906
+ *
3907
+ * Convert a Uuid to an {@link Id} with {@link uuidToId} and back with
3908
+ * {@link idToUuid}.
3909
+ *
3910
+ * ### Example
3911
+ *
3912
+ * ```ts
3913
+ * import { assertEqual, assertErr, assertOk, Uuid } from "@evolu/common";
3914
+ *
3915
+ * const value = "0190a6f4-8c3e-7b2a-9d41-5e6f7a8b9c0d";
3916
+ * assertOk(Uuid.fromUnknown(value), value);
3917
+ *
3918
+ * const uppercase = value.toUpperCase();
3919
+ * const invalid = Uuid.fromUnknown(uppercase);
3920
+ * assertErr(invalid);
3921
+ * assertEqual(invalid.error, { type: "Uuid", value: uppercase });
3922
+ * assertOk(Uuid.fromUnknown(uppercase.toLowerCase()), value);
3923
+ * ```
3924
+ *
3925
+ * @group String
3926
+ */
3927
+ export declare const Uuid: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Uuid", UuidError>;
3928
+ export type Uuid = typeof Uuid.Output;
3929
+ /**
3930
+ * Converts a {@link Uuid} to the {@link Id} with the same 16 bytes.
3931
+ *
3932
+ * Use this to store records whose external keys are UUIDs. Unlike
3933
+ * {@link createIdFromString}, the mapping is reversible with {@link idToUuid}, so
3934
+ * the original UUID does not need its own column. A time-based UUID, such as
3935
+ * version 1, 6, or 7, keeps its creation time in the Id.
3936
+ *
3937
+ * ### Example
3938
+ *
3939
+ * ```ts
3940
+ * import {
3941
+ * assertEqual,
3942
+ * assertType,
3943
+ * idToUuid,
3944
+ * Uuid,
3945
+ * uuidToId,
3946
+ * type Brand,
3947
+ * type Id,
3948
+ * } from "@evolu/common";
3949
+ *
3950
+ * const uuid = Uuid.orThrow("0190a6f4-8c3e-7b2a-9d41-5e6f7a8b9c0d");
3951
+ * const todoId = uuidToId<"Todo">(uuid);
3952
+ *
3953
+ * assertEqual(todoId, "AZCm9Iw-eyqdQV5veoucDQ");
3954
+ * assertType<typeof todoId, Id & Brand<"Todo">>();
3955
+ * assertEqual(idToUuid(todoId), uuid);
3956
+ * ```
3957
+ *
3958
+ * @group String
3959
+ */
3960
+ export declare const uuidToId: <B extends string = never>(value: Uuid, ..._validation: IdBrandValidation<B>) => CreatedId<B>;
3961
+ /**
3962
+ * Converts an {@link Id} to the {@link Uuid} with the same 16 bytes.
3963
+ *
3964
+ * The result is a Uuid of any version or variant, because Ids created by
3965
+ * {@link createId} are random 128-bit values. Ids created by
3966
+ * {@link createIdAsUuidv7} convert to version 7 UUIDs.
3967
+ *
3968
+ * ### Example
3969
+ *
3970
+ * ```ts
3971
+ * import {
3972
+ * assertEqual,
3973
+ * createIdAsUuidv7,
3974
+ * createRandomBytes,
3975
+ * createTime,
3976
+ * idToUuid,
3977
+ * uuidToId,
3978
+ * } from "@evolu/common";
3979
+ *
3980
+ * const id = createIdAsUuidv7({
3981
+ * randomBytes: createRandomBytes(),
3982
+ * time: createTime(),
3983
+ * });
3984
+ * const uuid = idToUuid(id);
3985
+ *
3986
+ * assertEqual(uuid[14], "7");
3987
+ * assertEqual(uuidToId(uuid), id);
3988
+ * ```
3989
+ *
3990
+ * @group String
3991
+ */
3992
+ export declare const idToUuid: (value: Id) => Uuid;
3832
3993
  /**
3833
3994
  * Error returned when a string is not a canonical {@link Int64String}.
3834
3995
  *