@evolu/common 8.5.0 → 8.6.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 (328) hide show
  1. package/dist/src/Array.d.ts +170 -97
  2. package/dist/src/Array.d.ts.map +1 -1
  3. package/dist/src/Array.js +67 -42
  4. package/dist/src/Assert.d.ts +233 -30
  5. package/dist/src/Assert.d.ts.map +1 -1
  6. package/dist/src/Assert.js +150 -30
  7. package/dist/src/BigInt.d.ts +3 -3
  8. package/dist/src/BigInt.js +3 -3
  9. package/dist/src/Brand.d.ts +7 -7
  10. package/dist/src/Buffer.d.ts +12 -4
  11. package/dist/src/Buffer.d.ts.map +1 -1
  12. package/dist/src/Cache.d.ts +8 -3
  13. package/dist/src/Cache.d.ts.map +1 -1
  14. package/dist/src/Cache.js +8 -3
  15. package/dist/src/Callbacks.d.ts +8 -4
  16. package/dist/src/Callbacks.d.ts.map +1 -1
  17. package/dist/src/Console.d.ts +45 -30
  18. package/dist/src/Console.d.ts.map +1 -1
  19. package/dist/src/Console.js +32 -21
  20. package/dist/src/Crypto.d.ts +13 -8
  21. package/dist/src/Crypto.d.ts.map +1 -1
  22. package/dist/src/Crypto.js +6 -3
  23. package/dist/src/Eq.d.ts +107 -58
  24. package/dist/src/Eq.d.ts.map +1 -1
  25. package/dist/src/Eq.js +308 -112
  26. package/dist/src/Function.d.ts +54 -24
  27. package/dist/src/Function.d.ts.map +1 -1
  28. package/dist/src/Function.js +34 -17
  29. package/dist/src/Http.d.ts +52 -19
  30. package/dist/src/Http.d.ts.map +1 -1
  31. package/dist/src/Identicon.d.ts +9 -4
  32. package/dist/src/Identicon.d.ts.map +1 -1
  33. package/dist/src/Identicon.js +9 -4
  34. package/dist/src/LockManager.d.ts +12 -10
  35. package/dist/src/LockManager.d.ts.map +1 -1
  36. package/dist/src/Lookup.d.ts +4 -2
  37. package/dist/src/Lookup.d.ts.map +1 -1
  38. package/dist/src/Lookup.js +4 -2
  39. package/dist/src/Number.d.ts +28 -24
  40. package/dist/src/Number.d.ts.map +1 -1
  41. package/dist/src/Number.js +16 -17
  42. package/dist/src/Object.d.ts +89 -47
  43. package/dist/src/Object.d.ts.map +1 -1
  44. package/dist/src/Object.js +88 -41
  45. package/dist/src/Option.d.ts +14 -5
  46. package/dist/src/Option.d.ts.map +1 -1
  47. package/dist/src/Option.js +14 -5
  48. package/dist/src/Order.d.ts +12 -12
  49. package/dist/src/Order.js +12 -12
  50. package/dist/src/Platform.d.ts +2 -2
  51. package/dist/src/Random.d.ts +7 -4
  52. package/dist/src/Random.d.ts.map +1 -1
  53. package/dist/src/Redacted.d.ts +13 -6
  54. package/dist/src/Redacted.d.ts.map +1 -1
  55. package/dist/src/Redacted.js +4 -2
  56. package/dist/src/Ref.d.ts +4 -4
  57. package/dist/src/Relation.d.ts +5 -7
  58. package/dist/src/Relation.d.ts.map +1 -1
  59. package/dist/src/Resource.d.ts +27 -12
  60. package/dist/src/Resource.d.ts.map +1 -1
  61. package/dist/src/Result.d.ts +258 -114
  62. package/dist/src/Result.d.ts.map +1 -1
  63. package/dist/src/Result.js +71 -34
  64. package/dist/src/Schedule.d.ts +233 -116
  65. package/dist/src/Schedule.d.ts.map +1 -1
  66. package/dist/src/Schedule.js +204 -110
  67. package/dist/src/Set.d.ts +43 -24
  68. package/dist/src/Set.d.ts.map +1 -1
  69. package/dist/src/Set.js +25 -13
  70. package/dist/src/Sqlite.d.ts +4 -4
  71. package/dist/src/Sqlite.d.ts.map +1 -1
  72. package/dist/src/Sqlite.js +9 -8
  73. package/dist/src/Task.d.ts +441 -212
  74. package/dist/src/Task.d.ts.map +1 -1
  75. package/dist/src/Task.js +238 -115
  76. package/dist/src/Test.d.ts +10 -4
  77. package/dist/src/Test.d.ts.map +1 -1
  78. package/dist/src/Test.js +10 -4
  79. package/dist/src/Time.d.ts +27 -17
  80. package/dist/src/Time.d.ts.map +1 -1
  81. package/dist/src/Time.js +16 -6
  82. package/dist/src/Type.d.ts +1096 -387
  83. package/dist/src/Type.d.ts.map +1 -1
  84. package/dist/src/Type.js +1046 -372
  85. package/dist/src/Types.d.ts +95 -40
  86. package/dist/src/Types.d.ts.map +1 -1
  87. package/dist/src/Types.js +13 -4
  88. package/dist/src/WebSocket.d.ts +14 -6
  89. package/dist/src/WebSocket.d.ts.map +1 -1
  90. package/dist/src/Worker.d.ts +10 -6
  91. package/dist/src/Worker.d.ts.map +1 -1
  92. package/dist/src/intl/_en.d.ts +3 -1
  93. package/dist/src/intl/_en.d.ts.map +1 -1
  94. package/dist/src/intl/_en.js +17 -3
  95. package/dist/src/intl/ar.d.ts +3 -1
  96. package/dist/src/intl/ar.d.ts.map +1 -1
  97. package/dist/src/intl/ar.js +15 -2
  98. package/dist/src/intl/bn.d.ts +3 -1
  99. package/dist/src/intl/bn.d.ts.map +1 -1
  100. package/dist/src/intl/bn.js +16 -3
  101. package/dist/src/intl/ca.d.ts +3 -1
  102. package/dist/src/intl/ca.d.ts.map +1 -1
  103. package/dist/src/intl/ca.js +16 -3
  104. package/dist/src/intl/cs.d.ts +3 -1
  105. package/dist/src/intl/cs.d.ts.map +1 -1
  106. package/dist/src/intl/cs.js +16 -3
  107. package/dist/src/intl/da.d.ts +3 -1
  108. package/dist/src/intl/da.d.ts.map +1 -1
  109. package/dist/src/intl/da.js +16 -3
  110. package/dist/src/intl/de.d.ts +3 -1
  111. package/dist/src/intl/de.d.ts.map +1 -1
  112. package/dist/src/intl/de.js +16 -3
  113. package/dist/src/intl/el.d.ts +3 -1
  114. package/dist/src/intl/el.d.ts.map +1 -1
  115. package/dist/src/intl/el.js +16 -3
  116. package/dist/src/intl/es.d.ts +3 -1
  117. package/dist/src/intl/es.d.ts.map +1 -1
  118. package/dist/src/intl/es.js +16 -3
  119. package/dist/src/intl/fa.d.ts +3 -1
  120. package/dist/src/intl/fa.d.ts.map +1 -1
  121. package/dist/src/intl/fa.js +16 -3
  122. package/dist/src/intl/fi.d.ts +3 -1
  123. package/dist/src/intl/fi.d.ts.map +1 -1
  124. package/dist/src/intl/fi.js +16 -3
  125. package/dist/src/intl/fil.d.ts +3 -1
  126. package/dist/src/intl/fil.d.ts.map +1 -1
  127. package/dist/src/intl/fil.js +16 -3
  128. package/dist/src/intl/fr.d.ts +3 -1
  129. package/dist/src/intl/fr.d.ts.map +1 -1
  130. package/dist/src/intl/fr.js +16 -3
  131. package/dist/src/intl/he.d.ts +3 -1
  132. package/dist/src/intl/he.d.ts.map +1 -1
  133. package/dist/src/intl/he.js +16 -3
  134. package/dist/src/intl/hi.d.ts +3 -1
  135. package/dist/src/intl/hi.d.ts.map +1 -1
  136. package/dist/src/intl/hi.js +16 -3
  137. package/dist/src/intl/hr.d.ts +3 -1
  138. package/dist/src/intl/hr.d.ts.map +1 -1
  139. package/dist/src/intl/hr.js +16 -3
  140. package/dist/src/intl/hu.d.ts +2 -1
  141. package/dist/src/intl/hu.d.ts.map +1 -1
  142. package/dist/src/intl/hu.js +15 -3
  143. package/dist/src/intl/id.d.ts +3 -1
  144. package/dist/src/intl/id.d.ts.map +1 -1
  145. package/dist/src/intl/id.js +16 -3
  146. package/dist/src/intl/it.d.ts +3 -1
  147. package/dist/src/intl/it.d.ts.map +1 -1
  148. package/dist/src/intl/it.js +16 -3
  149. package/dist/src/intl/ja.d.ts +3 -1
  150. package/dist/src/intl/ja.d.ts.map +1 -1
  151. package/dist/src/intl/ja.js +16 -3
  152. package/dist/src/intl/ko.d.ts +3 -1
  153. package/dist/src/intl/ko.d.ts.map +1 -1
  154. package/dist/src/intl/ko.js +16 -3
  155. package/dist/src/intl/ml.d.ts +3 -1
  156. package/dist/src/intl/ml.d.ts.map +1 -1
  157. package/dist/src/intl/ml.js +16 -3
  158. package/dist/src/intl/mr.d.ts +3 -1
  159. package/dist/src/intl/mr.d.ts.map +1 -1
  160. package/dist/src/intl/mr.js +16 -3
  161. package/dist/src/intl/ms.d.ts +3 -1
  162. package/dist/src/intl/ms.d.ts.map +1 -1
  163. package/dist/src/intl/ms.js +15 -2
  164. package/dist/src/intl/nb.d.ts +2 -1
  165. package/dist/src/intl/nb.d.ts.map +1 -1
  166. package/dist/src/intl/nb.js +14 -2
  167. package/dist/src/intl/nl.d.ts +3 -1
  168. package/dist/src/intl/nl.d.ts.map +1 -1
  169. package/dist/src/intl/nl.js +16 -3
  170. package/dist/src/intl/pa.d.ts +3 -1
  171. package/dist/src/intl/pa.d.ts.map +1 -1
  172. package/dist/src/intl/pa.js +16 -3
  173. package/dist/src/intl/pl.d.ts +2 -0
  174. package/dist/src/intl/pl.d.ts.map +1 -1
  175. package/dist/src/intl/pl.js +15 -2
  176. package/dist/src/intl/pt-BR.d.ts +3 -1
  177. package/dist/src/intl/pt-BR.d.ts.map +1 -1
  178. package/dist/src/intl/pt-BR.js +16 -3
  179. package/dist/src/intl/pt.d.ts +3 -1
  180. package/dist/src/intl/pt.d.ts.map +1 -1
  181. package/dist/src/intl/pt.js +15 -2
  182. package/dist/src/intl/ro.d.ts +3 -1
  183. package/dist/src/intl/ro.d.ts.map +1 -1
  184. package/dist/src/intl/ro.js +16 -3
  185. package/dist/src/intl/sk.d.ts +3 -1
  186. package/dist/src/intl/sk.d.ts.map +1 -1
  187. package/dist/src/intl/sk.js +15 -2
  188. package/dist/src/intl/sl.d.ts +3 -1
  189. package/dist/src/intl/sl.d.ts.map +1 -1
  190. package/dist/src/intl/sl.js +16 -3
  191. package/dist/src/intl/sv.d.ts +3 -1
  192. package/dist/src/intl/sv.d.ts.map +1 -1
  193. package/dist/src/intl/sv.js +16 -3
  194. package/dist/src/intl/sw.d.ts +1 -0
  195. package/dist/src/intl/sw.d.ts.map +1 -1
  196. package/dist/src/intl/sw.js +14 -2
  197. package/dist/src/intl/ta.d.ts +3 -1
  198. package/dist/src/intl/ta.d.ts.map +1 -1
  199. package/dist/src/intl/ta.js +16 -3
  200. package/dist/src/intl/te.d.ts +3 -1
  201. package/dist/src/intl/te.d.ts.map +1 -1
  202. package/dist/src/intl/te.js +16 -3
  203. package/dist/src/intl/th.d.ts +3 -1
  204. package/dist/src/intl/th.d.ts.map +1 -1
  205. package/dist/src/intl/th.js +16 -3
  206. package/dist/src/intl/tr.d.ts +3 -1
  207. package/dist/src/intl/tr.d.ts.map +1 -1
  208. package/dist/src/intl/tr.js +16 -3
  209. package/dist/src/intl/uk.d.ts +3 -1
  210. package/dist/src/intl/uk.d.ts.map +1 -1
  211. package/dist/src/intl/uk.js +16 -3
  212. package/dist/src/intl/ur.d.ts +3 -1
  213. package/dist/src/intl/ur.d.ts.map +1 -1
  214. package/dist/src/intl/ur.js +15 -2
  215. package/dist/src/intl/vi.d.ts +3 -1
  216. package/dist/src/intl/vi.d.ts.map +1 -1
  217. package/dist/src/intl/vi.js +16 -3
  218. package/dist/src/intl/zh-CN.d.ts +3 -1
  219. package/dist/src/intl/zh-CN.d.ts.map +1 -1
  220. package/dist/src/intl/zh-CN.js +16 -3
  221. package/dist/src/intl/zh-TW.d.ts +3 -1
  222. package/dist/src/intl/zh-TW.d.ts.map +1 -1
  223. package/dist/src/intl/zh-TW.js +16 -3
  224. package/dist/src/local-first/Evolu.d.ts +47 -24
  225. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  226. package/dist/src/local-first/Owner.d.ts +10 -7
  227. package/dist/src/local-first/Owner.d.ts.map +1 -1
  228. package/dist/src/local-first/Owner.js +10 -7
  229. package/dist/src/local-first/Protocol.d.ts +5 -5
  230. package/dist/src/local-first/Protocol.js +5 -5
  231. package/dist/src/local-first/Query.d.ts +34 -21
  232. package/dist/src/local-first/Query.d.ts.map +1 -1
  233. package/dist/src/local-first/Query.js +25 -13
  234. package/dist/src/local-first/Relay.d.ts +12 -5
  235. package/dist/src/local-first/Relay.d.ts.map +1 -1
  236. package/dist/src/local-first/Schema.d.ts +19 -11
  237. package/dist/src/local-first/Schema.d.ts.map +1 -1
  238. package/dist/src/local-first/Schema.js +11 -6
  239. package/dist/src/local-first/Storage.d.ts +4 -2
  240. package/dist/src/local-first/Storage.d.ts.map +1 -1
  241. package/package.json +3 -4
  242. package/src/Array.ts +170 -97
  243. package/src/Assert.ts +336 -31
  244. package/src/BigInt.ts +3 -3
  245. package/src/Brand.ts +7 -7
  246. package/src/Buffer.ts +12 -4
  247. package/src/Cache.ts +8 -3
  248. package/src/Callbacks.ts +8 -4
  249. package/src/Console.ts +45 -30
  250. package/src/Crypto.ts +13 -8
  251. package/src/Eq.ts +450 -122
  252. package/src/Function.ts +54 -24
  253. package/src/Http.ts +52 -19
  254. package/src/Identicon.ts +9 -4
  255. package/src/LockManager.ts +12 -10
  256. package/src/Lookup.ts +4 -2
  257. package/src/Number.ts +28 -24
  258. package/src/Object.ts +115 -49
  259. package/src/Option.ts +14 -5
  260. package/src/Order.ts +12 -12
  261. package/src/Platform.ts +2 -2
  262. package/src/Random.ts +7 -4
  263. package/src/Redacted.ts +13 -6
  264. package/src/Ref.ts +4 -4
  265. package/src/Relation.ts +5 -7
  266. package/src/Resource.ts +27 -12
  267. package/src/Result.ts +258 -114
  268. package/src/Schedule.ts +233 -116
  269. package/src/Set.ts +43 -24
  270. package/src/Sqlite.ts +9 -8
  271. package/src/Task.ts +441 -212
  272. package/src/Test.ts +10 -4
  273. package/src/Time.ts +27 -17
  274. package/src/Type.ts +2077 -620
  275. package/src/Types.ts +108 -40
  276. package/src/WebSocket.ts +14 -6
  277. package/src/Worker.ts +10 -6
  278. package/src/intl/_en.ts +20 -4
  279. package/src/intl/ar.ts +17 -2
  280. package/src/intl/bn.ts +19 -4
  281. package/src/intl/ca.ts +19 -4
  282. package/src/intl/cs.ts +19 -4
  283. package/src/intl/da.ts +19 -4
  284. package/src/intl/de.ts +19 -4
  285. package/src/intl/el.ts +19 -4
  286. package/src/intl/es.ts +19 -4
  287. package/src/intl/fa.ts +19 -4
  288. package/src/intl/fi.ts +19 -4
  289. package/src/intl/fil.ts +19 -4
  290. package/src/intl/fr.ts +19 -4
  291. package/src/intl/he.ts +19 -4
  292. package/src/intl/hi.ts +19 -4
  293. package/src/intl/hr.ts +19 -4
  294. package/src/intl/hu.ts +18 -4
  295. package/src/intl/id.ts +19 -4
  296. package/src/intl/it.ts +19 -4
  297. package/src/intl/ja.ts +19 -4
  298. package/src/intl/ko.ts +19 -4
  299. package/src/intl/ml.ts +19 -4
  300. package/src/intl/mr.ts +19 -4
  301. package/src/intl/ms.ts +17 -2
  302. package/src/intl/nb.ts +16 -2
  303. package/src/intl/nl.ts +19 -4
  304. package/src/intl/pa.ts +19 -4
  305. package/src/intl/pl.ts +18 -2
  306. package/src/intl/pt-BR.ts +19 -4
  307. package/src/intl/pt.ts +17 -2
  308. package/src/intl/ro.ts +19 -4
  309. package/src/intl/sk.ts +17 -2
  310. package/src/intl/sl.ts +19 -4
  311. package/src/intl/sv.ts +19 -4
  312. package/src/intl/sw.ts +15 -2
  313. package/src/intl/ta.ts +19 -4
  314. package/src/intl/te.ts +19 -4
  315. package/src/intl/th.ts +19 -4
  316. package/src/intl/tr.ts +19 -4
  317. package/src/intl/uk.ts +19 -4
  318. package/src/intl/ur.ts +17 -2
  319. package/src/intl/vi.ts +19 -3
  320. package/src/intl/zh-CN.ts +19 -4
  321. package/src/intl/zh-TW.ts +19 -4
  322. package/src/local-first/Evolu.ts +47 -24
  323. package/src/local-first/Owner.ts +10 -7
  324. package/src/local-first/Protocol.ts +5 -5
  325. package/src/local-first/Query.ts +34 -21
  326. package/src/local-first/Relay.ts +12 -5
  327. package/src/local-first/Schema.ts +19 -11
  328. package/src/local-first/Storage.ts +4 -2
package/src/Assert.ts CHANGED
@@ -1,11 +1,21 @@
1
1
  /**
2
- * Runtime assertions for invariant checking.
2
+ * Runtime assertions for invariants and value checks.
3
3
  *
4
4
  * @module
5
5
  */
6
6
 
7
7
  import type { NonEmptyArray, NonEmptyReadonlyArray } from "./Array.ts";
8
- import type { Type } from "./Type.ts";
8
+ import { eqData, eqStrict, type Eq } from "./Eq.ts";
9
+ import type {
10
+ AnyResult,
11
+ Err,
12
+ InferErr,
13
+ InferOk,
14
+ Ok,
15
+ Result,
16
+ } from "./Result.ts";
17
+ import type { Data, IsData, Type } from "./Type.ts";
18
+ import type { CompileTimeError } from "./Types.ts";
9
19
 
10
20
  /**
11
21
  * Ensures a condition is true, throwing an error with the provided message if
@@ -21,12 +31,13 @@ import type { Type } from "./Type.ts";
21
31
  * ### Example
22
32
  *
23
33
  * ```ts
24
- * import { assert as assertInvariant } from "@evolu/common";
34
+ * import { assert, assertEqual, assertErr, trySync } from "@evolu/common";
25
35
  *
26
- * expect(() => assertInvariant(true, "Expected true.")).not.toThrow();
27
- * expect(() => assertInvariant(false, "Expected true.")).toThrow(
28
- * "Expected true.",
29
- * );
36
+ * assert(true, "Expected true.");
37
+ * const result = trySync(() => assert(false, "Expected true."));
38
+ * assertErr(result);
39
+ * assert(result.error instanceof Error, "Expected an Error.");
40
+ * assertEqual(result.error.message, "Expected true.");
30
41
  * ```
31
42
  */
32
43
  export const assert: (
@@ -39,6 +50,264 @@ export const assert: (
39
50
  }
40
51
  };
41
52
 
53
+ /**
54
+ * Asserts that two values are the same according to {@link eqStrict}.
55
+ *
56
+ * `eqStrict` uses SameValue equality: it considers `NaN` the same as itself,
57
+ * distinguishes `0` from `-0`, and compares objects by reference identity.
58
+ *
59
+ * ### Example
60
+ *
61
+ * ```ts
62
+ * import { assertSame, assertType } from "@evolu/common";
63
+ *
64
+ * interface User {
65
+ * readonly name: string;
66
+ * }
67
+ *
68
+ * const user: User = { name: "Ada" };
69
+ * const value: unknown = user;
70
+ *
71
+ * assertSame(value, user);
72
+ * assertType<User, typeof value>();
73
+ * ```
74
+ */
75
+ export const assertSame: <Expected>(
76
+ actual: unknown,
77
+ expected: Expected,
78
+ ) => asserts actual is Expected = (actual, expected) => {
79
+ assert(eqStrict(actual, expected), "Expected values to be the same.");
80
+ };
81
+
82
+ /**
83
+ * Asserts that a value is exactly `true` and narrows it to `true`.
84
+ *
85
+ * Unlike {@link assert}, this checks an exact boolean value instead of
86
+ * truthiness and does not require a custom message.
87
+ *
88
+ * ### Example
89
+ *
90
+ * ```ts
91
+ * import { assertTrue, assertType } from "@evolu/common";
92
+ *
93
+ * const value: unknown = true;
94
+ * assertTrue(value);
95
+ * assertType<true, typeof value>();
96
+ * ```
97
+ */
98
+ export const assertTrue: (value: unknown) => asserts value is true = (
99
+ value,
100
+ ) => {
101
+ assert(value === true, "Expected true.");
102
+ };
103
+
104
+ /**
105
+ * Asserts that a value is exactly `false` and narrows it to `false`.
106
+ *
107
+ * Unlike {@link assert}, this checks an exact boolean value instead of falsiness
108
+ * and does not require a custom message.
109
+ *
110
+ * ### Example
111
+ *
112
+ * ```ts
113
+ * import { assertFalse, assertType } from "@evolu/common";
114
+ *
115
+ * const value: unknown = false;
116
+ * assertFalse(value);
117
+ * assertType<false, typeof value>();
118
+ * ```
119
+ */
120
+ export const assertFalse: (value: unknown) => asserts value is false = (
121
+ value,
122
+ ) => {
123
+ assert(value === false, "Expected false.");
124
+ };
125
+
126
+ /**
127
+ * Asserts that two {@link Data} values are equal according to {@link eqData}.
128
+ *
129
+ * Use this for concise value checks in platform-independent examples. Use
130
+ * {@link assert} with a descriptive message for application invariants.
131
+ *
132
+ * ### Example
133
+ *
134
+ * ```ts
135
+ * import { assertEqual } from "@evolu/common";
136
+ *
137
+ * const actual = new Map([["roles", new Set(["admin", "author"])]]);
138
+ * const expected = new Map([["roles", new Set(["author", "admin"])]]);
139
+ *
140
+ * assertEqual(actual, expected);
141
+ * ```
142
+ */
143
+ export function assertEqual<Actual, Expected>(
144
+ actual: Actual,
145
+ expected: Expected,
146
+ ...dataError: AssertEqualError<Actual | Expected>
147
+ ): void;
148
+ export function assertEqual(actual: Data, expected: Data): void {
149
+ assert(eqData(actual, expected), "Expected values to be equal.");
150
+ }
151
+
152
+ type AssertEqualError<Value> =
153
+ IsData<Value> extends true
154
+ ? []
155
+ : [
156
+ error: CompileTimeError<
157
+ "assertEqual",
158
+ "Actual and expected values must consist only of Data."
159
+ >,
160
+ ];
161
+
162
+ /**
163
+ * Asserts that a {@link Result} is an {@link Ok}, optionally compares its value,
164
+ * and narrows the Result.
165
+ *
166
+ * With only a Result, this checks the variant without inspecting the value.
167
+ * When an expected value is provided, it uses {@link eqData}; its Data type is
168
+ * inferred independently, so an unbranded literal can compare a branded
169
+ * primitive or collection. Pass a custom {@link Eq} when either value is outside
170
+ * {@link Data} or needs domain-specific equality.
171
+ *
172
+ * ### Example
173
+ *
174
+ * ```ts
175
+ * import {
176
+ * assertEqual,
177
+ * assertOk,
178
+ * assertType,
179
+ * ok,
180
+ * type Ok,
181
+ * type Result,
182
+ * type Typed,
183
+ * } from "@evolu/common";
184
+ *
185
+ * interface User {
186
+ * readonly id: string;
187
+ * }
188
+ *
189
+ * interface UserNotFoundError extends Typed<"UserNotFound"> {}
190
+ *
191
+ * const result: Result<User, UserNotFoundError> = ok({ id: "user-1" });
192
+ *
193
+ * assertOk(result);
194
+ * assertType<Ok<User>, typeof result>();
195
+ * assertEqual(result.value.id, "user-1");
196
+ * ```
197
+ */
198
+ export function assertOk<R extends Result<unknown, unknown>>(
199
+ result: R,
200
+ ): asserts result is Extract<R, Ok<unknown>>;
201
+ export function assertOk<R extends Result<unknown, unknown>>(
202
+ result: R,
203
+ expectedValue: InferOk<R>,
204
+ eq: Eq<InferOk<R>>,
205
+ ): asserts result is Extract<R, Ok<unknown>>;
206
+ // Constrain the argument tuple so any cannot absorb the CompileTimeError.
207
+ export function assertOk<R extends Result<unknown, unknown>, ExpectedValue>(
208
+ result: R,
209
+ ...comparison: [expectedValue: ExpectedValue] &
210
+ (IsData<InferOk<R> | ExpectedValue> extends true
211
+ ? unknown
212
+ : {
213
+ readonly [
214
+ Error in CompileTimeError<
215
+ "assertOk",
216
+ "Result value and expected value must consist only of Data when no custom Eq is provided."
217
+ >
218
+ ]: never;
219
+ })
220
+ ): asserts result is Extract<R, Ok<unknown>>;
221
+ export function assertOk(
222
+ result: AnyResult,
223
+ ...comparison: [] | [expectedValue: unknown, eq?: Eq<any>]
224
+ ): asserts result is Ok<unknown> {
225
+ assert(result.ok, "Expected an Ok result.");
226
+ if (comparison.length === 0) return;
227
+
228
+ const expectedValue = comparison[0];
229
+ const eq: Eq<any> = comparison[1] ?? eqData;
230
+ assert(
231
+ eq(result.value, expectedValue),
232
+ "Expected the value to equal the expected value.",
233
+ );
234
+ }
235
+
236
+ /**
237
+ * Asserts that a {@link Result} is an {@link Err}, optionally compares its error,
238
+ * and narrows the Result.
239
+ *
240
+ * With only a Result, this checks the variant without inspecting the error.
241
+ * When an expected error is provided, it uses {@link eqData}; its Data type is
242
+ * inferred independently, so an unbranded literal can compare a branded
243
+ * primitive or collection. Pass a custom {@link Eq} when either value is outside
244
+ * {@link Data} or needs domain-specific equality.
245
+ *
246
+ * ### Example
247
+ *
248
+ * ```ts
249
+ * import {
250
+ * assertEqual,
251
+ * assertErr,
252
+ * assertType,
253
+ * err,
254
+ * type Err,
255
+ * type Result,
256
+ * type Typed,
257
+ * } from "@evolu/common";
258
+ *
259
+ * interface UserNotFoundError extends Typed<"UserNotFound"> {
260
+ * readonly id: string;
261
+ * }
262
+ *
263
+ * const result: Result<string, UserNotFoundError> = err({
264
+ * type: "UserNotFound",
265
+ * id: "user-1",
266
+ * });
267
+ *
268
+ * assertErr(result);
269
+ * assertType<Err<UserNotFoundError>, typeof result>();
270
+ * assertEqual(result.error.id, "user-1");
271
+ * ```
272
+ */
273
+ export function assertErr<R extends Result<unknown, unknown>>(
274
+ result: R,
275
+ ): asserts result is Extract<R, Err<unknown>>;
276
+ export function assertErr<R extends Result<unknown, unknown>>(
277
+ result: R,
278
+ expectedError: InferErr<R>,
279
+ eq: Eq<InferErr<R>>,
280
+ ): asserts result is Extract<R, Err<unknown>>;
281
+ // Constrain the argument tuple so any cannot absorb the CompileTimeError.
282
+ export function assertErr<R extends Result<unknown, unknown>, ExpectedError>(
283
+ result: R,
284
+ ...comparison: [expectedError: ExpectedError] &
285
+ (IsData<InferErr<R> | ExpectedError> extends true
286
+ ? unknown
287
+ : {
288
+ readonly [
289
+ Error in CompileTimeError<
290
+ "assertErr",
291
+ "Result error and expected error must consist only of Data when no custom Eq is provided."
292
+ >
293
+ ]: never;
294
+ })
295
+ ): asserts result is Extract<R, Err<unknown>>;
296
+ export function assertErr(
297
+ result: AnyResult,
298
+ ...comparison: [] | [expectedError: unknown, eq?: Eq<any>]
299
+ ): asserts result is Err<unknown> {
300
+ assert(!result.ok, "Expected an Err result.");
301
+ if (comparison.length === 0) return;
302
+
303
+ const expectedError = comparison[0];
304
+ const eq: Eq<any> = comparison[1] ?? eqData;
305
+ assert(
306
+ eq(result.error, expectedError),
307
+ "Expected the error to equal the expected error.",
308
+ );
309
+ }
310
+
42
311
  /**
43
312
  * Asserts that a value is non-nullable.
44
313
  *
@@ -65,15 +334,23 @@ export const assertNonNullable: <T>(
65
334
  * ### Example
66
335
  *
67
336
  * ```ts
68
- * import { assertNotNull } from "@evolu/common";
337
+ * import {
338
+ * assert,
339
+ * assertEqual,
340
+ * assertErr,
341
+ * assertNotNull,
342
+ * assertType,
343
+ * trySync,
344
+ * } from "@evolu/common";
69
345
  *
70
346
  * const value = undefined as string | null | undefined;
71
347
  * assertNotNull(value);
72
- * expectTypeOf(value).toEqualTypeOf<string | undefined>();
73
- * expect(value).toBeUndefined();
74
- * expect(() => assertNotNull(null)).toThrow(
75
- * "Expected value not to be null.",
76
- * );
348
+ * assertType<string | undefined, typeof value>();
349
+ * assertEqual(value, undefined);
350
+ * const result = trySync(() => assertNotNull(null));
351
+ * assertErr(result);
352
+ * assert(result.error instanceof Error, "Expected an Error.");
353
+ * assertEqual(result.error.message, "Expected value not to be null.");
77
354
  * ```
78
355
  */
79
356
  export const assertNotNull: <T>(
@@ -95,15 +372,23 @@ export const assertNotNull: <T>(
95
372
  * ### Example
96
373
  *
97
374
  * ```ts
98
- * import { assertNotUndefined } from "@evolu/common";
375
+ * import {
376
+ * assert,
377
+ * assertEqual,
378
+ * assertErr,
379
+ * assertNotUndefined,
380
+ * assertType,
381
+ * trySync,
382
+ * } from "@evolu/common";
99
383
  *
100
384
  * const value = null as string | null | undefined;
101
385
  * assertNotUndefined(value);
102
- * expectTypeOf(value).toEqualTypeOf<string | null>();
103
- * expect(value).toBeNull();
104
- * expect(() => assertNotUndefined(undefined)).toThrow(
105
- * "Expected value not to be undefined.",
106
- * );
386
+ * assertType<string | null, typeof value>();
387
+ * assertEqual(value, null);
388
+ * const result = trySync(() => assertNotUndefined(undefined));
389
+ * assertErr(result);
390
+ * assert(result.error instanceof Error, "Expected an Error.");
391
+ * assertEqual(result.error.message, "Expected value not to be undefined.");
107
392
  * ```
108
393
  */
109
394
  export const assertNotUndefined: <T>(
@@ -125,13 +410,21 @@ export const assertNotUndefined: <T>(
125
410
  * ### Example
126
411
  *
127
412
  * ```ts
128
- * import { assertNonEmptyArray, type NonEmptyArray } from "@evolu/common";
413
+ * import {
414
+ * assertEqual,
415
+ * assertErr,
416
+ * assertNonEmptyArray,
417
+ * assertType,
418
+ * trySync,
419
+ * type NonEmptyArray,
420
+ * } from "@evolu/common";
129
421
  *
130
422
  * const values = [1, 2, 3];
131
423
  * assertNonEmptyArray(values);
132
- * expectTypeOf(values).toEqualTypeOf<NonEmptyArray<number>>();
133
- * expect(values[0]).toBe(1);
134
- * expect(() => assertNonEmptyArray([])).toThrow();
424
+ * assertType<NonEmptyArray<number>, typeof values>();
425
+ * assertEqual(values[0], 1);
426
+ * const result = trySync(() => assertNonEmptyArray([]));
427
+ * assertErr(result);
135
428
  * ```
136
429
  */
137
430
  export const assertNonEmptyArray: <T>(
@@ -154,15 +447,20 @@ export const assertNonEmptyArray: <T>(
154
447
  *
155
448
  * ```ts
156
449
  * import {
450
+ * assertEqual,
451
+ * assertErr,
157
452
  * assertNonEmptyReadonlyArray,
453
+ * assertType,
454
+ * trySync,
158
455
  * type NonEmptyReadonlyArray,
159
456
  * } from "@evolu/common";
160
457
  *
161
458
  * const values: ReadonlyArray<number> = [1, 2, 3];
162
459
  * assertNonEmptyReadonlyArray(values);
163
- * expectTypeOf(values).toEqualTypeOf<NonEmptyReadonlyArray<number>>();
164
- * expect(values[0]).toBe(1);
165
- * expect(() => assertNonEmptyReadonlyArray([])).toThrow();
460
+ * assertType<NonEmptyReadonlyArray<number>, typeof values>();
461
+ * assertEqual(values[0], 1);
462
+ * const result = trySync(() => assertNonEmptyReadonlyArray([]));
463
+ * assertErr(result);
166
464
  * ```
167
465
  */
168
466
  export const assertNonEmptyReadonlyArray: <T>(
@@ -183,14 +481,21 @@ export const assertNonEmptyReadonlyArray: <T>(
183
481
  * ### Example
184
482
  *
185
483
  * ```ts
186
- * import { assertNotDisposed } from "@evolu/common";
484
+ * import {
485
+ * assert,
486
+ * assertEqual,
487
+ * assertErr,
488
+ * assertNotDisposed,
489
+ * trySync,
490
+ * } from "@evolu/common";
187
491
  *
188
492
  * await using disposer = new globalThis.AsyncDisposableStack();
189
- * expect(() => assertNotDisposed(disposer)).not.toThrow();
493
+ * assertNotDisposed(disposer);
190
494
  * await disposer.disposeAsync();
191
- * expect(() => assertNotDisposed(disposer)).toThrow(
192
- * "Cannot use a disposed object.",
193
- * );
495
+ * const result = trySync(() => assertNotDisposed(disposer));
496
+ * assertErr(result);
497
+ * assert(result.error instanceof Error, "Expected an Error.");
498
+ * assertEqual(result.error.message, "Cannot use a disposed object.");
194
499
  * ```
195
500
  *
196
501
  * This is the JavaScript equivalent of the .NET `ObjectDisposedException`
package/src/BigInt.ts CHANGED
@@ -24,12 +24,12 @@ export const clampBigInt =
24
24
  * ### Example
25
25
  *
26
26
  * ```ts
27
- * import { isBetweenBigInt } from "@evolu/common";
27
+ * import { assertFalse, assertTrue, isBetweenBigInt } from "@evolu/common";
28
28
  *
29
29
  * const isBetween10And20 = isBetweenBigInt(10n, 20n);
30
30
  *
31
- * expect(isBetween10And20(20n)).toBe(true);
32
- * expect(isBetween10And20(25n)).toBe(false);
31
+ * assertTrue(isBetween10And20(20n));
32
+ * assertFalse(isBetween10And20(25n));
33
33
  * ```
34
34
  */
35
35
  export const isBetweenBigInt =
package/src/Brand.ts CHANGED
@@ -18,7 +18,7 @@
18
18
  * ### Single brand
19
19
  *
20
20
  * ```ts
21
- * import type { Brand } from "@evolu/common";
21
+ * import { assertEqual, type Brand } from "@evolu/common";
22
22
  *
23
23
  * type UserId = number & Brand<"UserId">;
24
24
  *
@@ -27,7 +27,7 @@
27
27
  * const createUserId = (value: number): UserId => value as UserId;
28
28
  * const getUser = (id: UserId): number => id;
29
29
  * const userId = createUserId(123);
30
- * expect(getUser(userId)).toBe(123);
30
+ * assertEqual(getUser(userId), 123);
31
31
  * // @ts-expect-error A plain number is not a UserId.
32
32
  * getUser(123);
33
33
  * ```
@@ -35,7 +35,7 @@
35
35
  * ### Multiple brands
36
36
  *
37
37
  * ```ts
38
- * import type { Brand } from "@evolu/common";
38
+ * import { assertEqual, type Brand } from "@evolu/common";
39
39
  *
40
40
  * type Min1 = string & Brand<"Min1">;
41
41
  * type Max100 = string & Brand<"Max100">;
@@ -46,8 +46,8 @@
46
46
  *
47
47
  * const min1Max100Value: Min1Max100 = "typescript" as Min1Max100;
48
48
  *
49
- * expect(requiresMin1(min1Max100Value)).toBe("typescript");
50
- * expect(requiresMax100(min1Max100Value)).toBe("typescript");
49
+ * assertEqual(requiresMin1(min1Max100Value), "typescript");
50
+ * assertEqual(requiresMax100(min1Max100Value), "typescript");
51
51
  * ```
52
52
  *
53
53
  * ### Standalone brand
@@ -59,7 +59,7 @@
59
59
  * code platform-agnostic.
60
60
  *
61
61
  * ```ts
62
- * import type { Brand } from "@evolu/common";
62
+ * import { assertSame, type Brand } from "@evolu/common";
63
63
  *
64
64
  * type NativePort = Brand<"NativePort">;
65
65
  *
@@ -67,7 +67,7 @@
67
67
  *
68
68
  * const nativeValue: unknown = { id: 1 };
69
69
  * const port = nativeValue as NativePort;
70
- * expect(requiresNativePort(port)).toBe(nativeValue);
70
+ * assertSame(requiresNativePort(port), nativeValue);
71
71
  * // @ts-expect-error An unknown value is not a NativePort.
72
72
  * requiresNativePort(nativeValue);
73
73
  * ```
package/src/Buffer.ts CHANGED
@@ -52,6 +52,9 @@ export class BufferError extends Error {
52
52
  *
53
53
  * ```ts
54
54
  * import {
55
+ * assert,
56
+ * assertEqual,
57
+ * assertErr,
55
58
  * createBuffer,
56
59
  * createIdFromString,
57
60
  * IdBytes,
@@ -59,6 +62,7 @@ export class BufferError extends Error {
59
62
  * idBytesTypeValueLength,
60
63
  * idToIdBytes,
61
64
  * NonNegativeInt,
65
+ * trySync,
62
66
  * } from "@evolu/common";
63
67
  * import {
64
68
  * decodeNonNegativeInt,
@@ -71,13 +75,17 @@ export class BufferError extends Error {
71
75
  * buffer.extend(idToIdBytes(id));
72
76
  *
73
77
  * const decoder = createBuffer(buffer.unwrap());
74
- * expect(decodeNonNegativeInt(decoder)).toBe(300);
78
+ * assertEqual(decodeNonNegativeInt(decoder), 300);
75
79
  * const decodedId = idBytesToId(
76
80
  * IdBytes.orThrow(decoder.shiftN(idBytesTypeValueLength)),
77
81
  * );
78
- * expect(decodedId).toBe(id);
79
- * expect(() => decodeNonNegativeInt(decoder)).toThrow(
80
- * "Buffer parse ended prematurely",
82
+ * assertEqual(decodedId, id);
83
+ * const result = trySync(() => decodeNonNegativeInt(decoder));
84
+ * assertErr(result);
85
+ * assert(
86
+ * result.error instanceof Error &&
87
+ * result.error.message === "Buffer parse ended prematurely",
88
+ * "Expected the premature-buffer-end error.",
81
89
  * );
82
90
  * ```
83
91
  *
package/src/Cache.ts CHANGED
@@ -43,16 +43,21 @@ export interface Cache<K, V> {
43
43
  * ### Example
44
44
  *
45
45
  * ```ts
46
- * import { createLruCache, PositiveInt } from "@evolu/common";
46
+ * import {
47
+ * assertEqual,
48
+ * assertFalse,
49
+ * createLruCache,
50
+ * PositiveInt,
51
+ * } from "@evolu/common";
47
52
  *
48
53
  * const cache = createLruCache<string, number>(PositiveInt.orThrow(2));
49
54
  * cache.set("a", 1);
50
55
  * cache.set("b", 2);
51
56
  * // Reading "a" makes "b" the least recently used entry.
52
- * expect(cache.get("a")).toBe(1);
57
+ * assertEqual(cache.get("a"), 1);
53
58
  * cache.set("c", 3);
54
59
  *
55
- * expect(cache.has("b")).toBe(false);
60
+ * assertFalse(cache.has("b"));
56
61
  * ```
57
62
  */
58
63
  export const createLruCache = <K, V>(capacity: PositiveInt): Cache<K, V> => {
package/src/Callbacks.ts CHANGED
@@ -25,7 +25,11 @@ import type { Callback } from "./Types.ts";
25
25
  * ### Correlating callback responses
26
26
  *
27
27
  * ```ts
28
- * import { createCallbacks, testCreateDeps } from "@evolu/common";
28
+ * import {
29
+ * assertEqual,
30
+ * createCallbacks,
31
+ * testCreateDeps,
32
+ * } from "@evolu/common";
29
33
  *
30
34
  * const deps = testCreateDeps();
31
35
  *
@@ -37,7 +41,7 @@ import type { Callback } from "./Types.ts";
37
41
  * });
38
42
  * callbacks.execute(noArgumentId);
39
43
  * callbacks.execute(noArgumentId);
40
- * expect(noArgumentCalls).toBe(1);
44
+ * assertEqual(noArgumentCalls, 1);
41
45
  *
42
46
  * // Typed callback
43
47
  * using stringCallbacks = createCallbacks<string>(deps);
@@ -46,14 +50,14 @@ import type { Callback } from "./Types.ts";
46
50
  * received = value;
47
51
  * });
48
52
  * stringCallbacks.execute(stringCallbackId, "hello");
49
- * expect(received).toBe("hello");
53
+ * assertEqual(received, "hello");
50
54
  *
51
55
  * // Promise.withResolvers
52
56
  * using promiseCallbacks = createCallbacks<string>(deps);
53
57
  * const { promise, resolve } = Promise.withResolvers<string>();
54
58
  * const promiseCallbackId = promiseCallbacks.register(resolve);
55
59
  * promiseCallbacks.execute(promiseCallbackId, "resolved value");
56
- * expect(await promise).toBe("resolved value");
60
+ * assertEqual(await promise, "resolved value");
57
61
  * ```
58
62
  *
59
63
  * @template T - The type of argument passed to callbacks (defaults to undefined