@evolu/common 8.4.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 (353) hide show
  1. package/dist/src/Array.d.ts +191 -94
  2. package/dist/src/Array.d.ts.map +1 -1
  3. package/dist/src/Array.js +91 -40
  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 +151 -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/LeakDetector.d.ts.map +1 -1
  35. package/dist/src/LeakDetector.js +4 -1
  36. package/dist/src/LockManager.d.ts +12 -10
  37. package/dist/src/LockManager.d.ts.map +1 -1
  38. package/dist/src/Lookup.d.ts +4 -2
  39. package/dist/src/Lookup.d.ts.map +1 -1
  40. package/dist/src/Lookup.js +5 -2
  41. package/dist/src/Number.d.ts +28 -24
  42. package/dist/src/Number.d.ts.map +1 -1
  43. package/dist/src/Number.js +16 -17
  44. package/dist/src/Object.d.ts +89 -47
  45. package/dist/src/Object.d.ts.map +1 -1
  46. package/dist/src/Object.js +88 -41
  47. package/dist/src/Option.d.ts +14 -5
  48. package/dist/src/Option.d.ts.map +1 -1
  49. package/dist/src/Option.js +14 -5
  50. package/dist/src/Order.d.ts +12 -12
  51. package/dist/src/Order.js +12 -12
  52. package/dist/src/Platform.d.ts +2 -2
  53. package/dist/src/Platform.js +1 -0
  54. package/dist/src/Random.d.ts +7 -4
  55. package/dist/src/Random.d.ts.map +1 -1
  56. package/dist/src/Redacted.d.ts +13 -6
  57. package/dist/src/Redacted.d.ts.map +1 -1
  58. package/dist/src/Redacted.js +4 -2
  59. package/dist/src/Ref.d.ts +4 -4
  60. package/dist/src/Relation.d.ts +5 -7
  61. package/dist/src/Relation.d.ts.map +1 -1
  62. package/dist/src/Relation.js +3 -3
  63. package/dist/src/Resource.d.ts +27 -12
  64. package/dist/src/Resource.d.ts.map +1 -1
  65. package/dist/src/Resource.js +9 -3
  66. package/dist/src/Result.d.ts +258 -114
  67. package/dist/src/Result.d.ts.map +1 -1
  68. package/dist/src/Result.js +74 -39
  69. package/dist/src/Schedule.d.ts +233 -116
  70. package/dist/src/Schedule.d.ts.map +1 -1
  71. package/dist/src/Schedule.js +204 -110
  72. package/dist/src/Set.d.ts +43 -24
  73. package/dist/src/Set.d.ts.map +1 -1
  74. package/dist/src/Set.js +25 -13
  75. package/dist/src/Sqlite.d.ts +4 -4
  76. package/dist/src/Sqlite.d.ts.map +1 -1
  77. package/dist/src/Sqlite.js +18 -15
  78. package/dist/src/Store.d.ts.map +1 -1
  79. package/dist/src/Store.js +3 -1
  80. package/dist/src/String.d.ts.map +1 -1
  81. package/dist/src/String.js +1 -1
  82. package/dist/src/Task.d.ts +555 -264
  83. package/dist/src/Task.d.ts.map +1 -1
  84. package/dist/src/Task.js +278 -168
  85. package/dist/src/Test.d.ts +10 -4
  86. package/dist/src/Test.d.ts.map +1 -1
  87. package/dist/src/Test.js +11 -4
  88. package/dist/src/Time.d.ts +27 -17
  89. package/dist/src/Time.d.ts.map +1 -1
  90. package/dist/src/Time.js +25 -8
  91. package/dist/src/Type.d.ts +1218 -372
  92. package/dist/src/Type.d.ts.map +1 -1
  93. package/dist/src/Type.js +1056 -379
  94. package/dist/src/Types.d.ts +95 -40
  95. package/dist/src/Types.d.ts.map +1 -1
  96. package/dist/src/Types.js +13 -4
  97. package/dist/src/WebSocket.d.ts +14 -6
  98. package/dist/src/WebSocket.d.ts.map +1 -1
  99. package/dist/src/WebSocket.js +8 -0
  100. package/dist/src/Worker.d.ts +10 -6
  101. package/dist/src/Worker.d.ts.map +1 -1
  102. package/dist/src/Worker.js +1 -1
  103. package/dist/src/intl/_en.d.ts +3 -1
  104. package/dist/src/intl/_en.d.ts.map +1 -1
  105. package/dist/src/intl/_en.js +17 -3
  106. package/dist/src/intl/ar.d.ts +3 -1
  107. package/dist/src/intl/ar.d.ts.map +1 -1
  108. package/dist/src/intl/ar.js +15 -2
  109. package/dist/src/intl/bn.d.ts +3 -1
  110. package/dist/src/intl/bn.d.ts.map +1 -1
  111. package/dist/src/intl/bn.js +16 -3
  112. package/dist/src/intl/ca.d.ts +3 -1
  113. package/dist/src/intl/ca.d.ts.map +1 -1
  114. package/dist/src/intl/ca.js +16 -3
  115. package/dist/src/intl/cs.d.ts +3 -1
  116. package/dist/src/intl/cs.d.ts.map +1 -1
  117. package/dist/src/intl/cs.js +16 -3
  118. package/dist/src/intl/da.d.ts +3 -1
  119. package/dist/src/intl/da.d.ts.map +1 -1
  120. package/dist/src/intl/da.js +16 -3
  121. package/dist/src/intl/de.d.ts +3 -1
  122. package/dist/src/intl/de.d.ts.map +1 -1
  123. package/dist/src/intl/de.js +16 -3
  124. package/dist/src/intl/el.d.ts +3 -1
  125. package/dist/src/intl/el.d.ts.map +1 -1
  126. package/dist/src/intl/el.js +16 -3
  127. package/dist/src/intl/es.d.ts +3 -1
  128. package/dist/src/intl/es.d.ts.map +1 -1
  129. package/dist/src/intl/es.js +16 -3
  130. package/dist/src/intl/fa.d.ts +3 -1
  131. package/dist/src/intl/fa.d.ts.map +1 -1
  132. package/dist/src/intl/fa.js +16 -3
  133. package/dist/src/intl/fi.d.ts +3 -1
  134. package/dist/src/intl/fi.d.ts.map +1 -1
  135. package/dist/src/intl/fi.js +16 -3
  136. package/dist/src/intl/fil.d.ts +3 -1
  137. package/dist/src/intl/fil.d.ts.map +1 -1
  138. package/dist/src/intl/fil.js +16 -3
  139. package/dist/src/intl/fr.d.ts +3 -1
  140. package/dist/src/intl/fr.d.ts.map +1 -1
  141. package/dist/src/intl/fr.js +16 -3
  142. package/dist/src/intl/he.d.ts +3 -1
  143. package/dist/src/intl/he.d.ts.map +1 -1
  144. package/dist/src/intl/he.js +16 -3
  145. package/dist/src/intl/hi.d.ts +3 -1
  146. package/dist/src/intl/hi.d.ts.map +1 -1
  147. package/dist/src/intl/hi.js +16 -3
  148. package/dist/src/intl/hr.d.ts +3 -1
  149. package/dist/src/intl/hr.d.ts.map +1 -1
  150. package/dist/src/intl/hr.js +16 -3
  151. package/dist/src/intl/hu.d.ts +2 -1
  152. package/dist/src/intl/hu.d.ts.map +1 -1
  153. package/dist/src/intl/hu.js +15 -3
  154. package/dist/src/intl/id.d.ts +3 -1
  155. package/dist/src/intl/id.d.ts.map +1 -1
  156. package/dist/src/intl/id.js +16 -3
  157. package/dist/src/intl/it.d.ts +3 -1
  158. package/dist/src/intl/it.d.ts.map +1 -1
  159. package/dist/src/intl/it.js +16 -3
  160. package/dist/src/intl/ja.d.ts +3 -1
  161. package/dist/src/intl/ja.d.ts.map +1 -1
  162. package/dist/src/intl/ja.js +16 -3
  163. package/dist/src/intl/ko.d.ts +3 -1
  164. package/dist/src/intl/ko.d.ts.map +1 -1
  165. package/dist/src/intl/ko.js +16 -3
  166. package/dist/src/intl/ml.d.ts +3 -1
  167. package/dist/src/intl/ml.d.ts.map +1 -1
  168. package/dist/src/intl/ml.js +16 -3
  169. package/dist/src/intl/mr.d.ts +3 -1
  170. package/dist/src/intl/mr.d.ts.map +1 -1
  171. package/dist/src/intl/mr.js +16 -3
  172. package/dist/src/intl/ms.d.ts +3 -1
  173. package/dist/src/intl/ms.d.ts.map +1 -1
  174. package/dist/src/intl/ms.js +15 -2
  175. package/dist/src/intl/nb.d.ts +2 -1
  176. package/dist/src/intl/nb.d.ts.map +1 -1
  177. package/dist/src/intl/nb.js +14 -2
  178. package/dist/src/intl/nl.d.ts +3 -1
  179. package/dist/src/intl/nl.d.ts.map +1 -1
  180. package/dist/src/intl/nl.js +16 -3
  181. package/dist/src/intl/pa.d.ts +3 -1
  182. package/dist/src/intl/pa.d.ts.map +1 -1
  183. package/dist/src/intl/pa.js +16 -3
  184. package/dist/src/intl/pl.d.ts +2 -0
  185. package/dist/src/intl/pl.d.ts.map +1 -1
  186. package/dist/src/intl/pl.js +15 -2
  187. package/dist/src/intl/pt-BR.d.ts +3 -1
  188. package/dist/src/intl/pt-BR.d.ts.map +1 -1
  189. package/dist/src/intl/pt-BR.js +16 -3
  190. package/dist/src/intl/pt.d.ts +3 -1
  191. package/dist/src/intl/pt.d.ts.map +1 -1
  192. package/dist/src/intl/pt.js +15 -2
  193. package/dist/src/intl/ro.d.ts +3 -1
  194. package/dist/src/intl/ro.d.ts.map +1 -1
  195. package/dist/src/intl/ro.js +16 -3
  196. package/dist/src/intl/sk.d.ts +3 -1
  197. package/dist/src/intl/sk.d.ts.map +1 -1
  198. package/dist/src/intl/sk.js +15 -2
  199. package/dist/src/intl/sl.d.ts +3 -1
  200. package/dist/src/intl/sl.d.ts.map +1 -1
  201. package/dist/src/intl/sl.js +16 -3
  202. package/dist/src/intl/sv.d.ts +3 -1
  203. package/dist/src/intl/sv.d.ts.map +1 -1
  204. package/dist/src/intl/sv.js +16 -3
  205. package/dist/src/intl/sw.d.ts +1 -0
  206. package/dist/src/intl/sw.d.ts.map +1 -1
  207. package/dist/src/intl/sw.js +14 -2
  208. package/dist/src/intl/ta.d.ts +3 -1
  209. package/dist/src/intl/ta.d.ts.map +1 -1
  210. package/dist/src/intl/ta.js +16 -3
  211. package/dist/src/intl/te.d.ts +3 -1
  212. package/dist/src/intl/te.d.ts.map +1 -1
  213. package/dist/src/intl/te.js +16 -3
  214. package/dist/src/intl/th.d.ts +3 -1
  215. package/dist/src/intl/th.d.ts.map +1 -1
  216. package/dist/src/intl/th.js +16 -3
  217. package/dist/src/intl/tr.d.ts +3 -1
  218. package/dist/src/intl/tr.d.ts.map +1 -1
  219. package/dist/src/intl/tr.js +16 -3
  220. package/dist/src/intl/uk.d.ts +3 -1
  221. package/dist/src/intl/uk.d.ts.map +1 -1
  222. package/dist/src/intl/uk.js +16 -3
  223. package/dist/src/intl/ur.d.ts +3 -1
  224. package/dist/src/intl/ur.d.ts.map +1 -1
  225. package/dist/src/intl/ur.js +15 -2
  226. package/dist/src/intl/vi.d.ts +3 -1
  227. package/dist/src/intl/vi.d.ts.map +1 -1
  228. package/dist/src/intl/vi.js +16 -3
  229. package/dist/src/intl/zh-CN.d.ts +3 -1
  230. package/dist/src/intl/zh-CN.d.ts.map +1 -1
  231. package/dist/src/intl/zh-CN.js +16 -3
  232. package/dist/src/intl/zh-TW.d.ts +3 -1
  233. package/dist/src/intl/zh-TW.d.ts.map +1 -1
  234. package/dist/src/intl/zh-TW.js +16 -3
  235. package/dist/src/local-first/Db.js +3 -2
  236. package/dist/src/local-first/Evolu.d.ts +47 -24
  237. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  238. package/dist/src/local-first/Evolu.js +1 -0
  239. package/dist/src/local-first/Owner.d.ts +18 -14
  240. package/dist/src/local-first/Owner.d.ts.map +1 -1
  241. package/dist/src/local-first/Owner.js +14 -11
  242. package/dist/src/local-first/Protocol.d.ts +5 -5
  243. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  244. package/dist/src/local-first/Protocol.js +35 -29
  245. package/dist/src/local-first/Query.d.ts +34 -21
  246. package/dist/src/local-first/Query.d.ts.map +1 -1
  247. package/dist/src/local-first/Query.js +27 -14
  248. package/dist/src/local-first/Relay.d.ts +12 -5
  249. package/dist/src/local-first/Relay.d.ts.map +1 -1
  250. package/dist/src/local-first/Relay.js +1 -1
  251. package/dist/src/local-first/Schema.d.ts +19 -11
  252. package/dist/src/local-first/Schema.d.ts.map +1 -1
  253. package/dist/src/local-first/Schema.js +11 -6
  254. package/dist/src/local-first/Shared.d.ts.map +1 -1
  255. package/dist/src/local-first/Shared.js +4 -2
  256. package/dist/src/local-first/Storage.d.ts +4 -2
  257. package/dist/src/local-first/Storage.d.ts.map +1 -1
  258. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  259. package/dist/src/local-first/Timestamp.js +1 -1
  260. package/package.json +3 -4
  261. package/src/Array.ts +195 -95
  262. package/src/Assert.ts +337 -31
  263. package/src/BigInt.ts +3 -3
  264. package/src/Brand.ts +7 -7
  265. package/src/Buffer.ts +12 -4
  266. package/src/Cache.ts +8 -3
  267. package/src/Callbacks.ts +8 -4
  268. package/src/Console.ts +45 -30
  269. package/src/Crypto.ts +13 -8
  270. package/src/Eq.ts +450 -122
  271. package/src/Function.ts +54 -24
  272. package/src/Http.ts +52 -19
  273. package/src/Identicon.ts +9 -4
  274. package/src/LeakDetector.ts +4 -3
  275. package/src/LockManager.ts +12 -10
  276. package/src/Lookup.ts +5 -2
  277. package/src/Number.ts +28 -24
  278. package/src/Object.ts +115 -49
  279. package/src/Option.ts +14 -5
  280. package/src/Order.ts +12 -12
  281. package/src/Platform.ts +3 -2
  282. package/src/Random.ts +7 -4
  283. package/src/Redacted.ts +13 -6
  284. package/src/Ref.ts +4 -4
  285. package/src/Relation.ts +8 -10
  286. package/src/Resource.ts +36 -15
  287. package/src/Result.ts +263 -119
  288. package/src/Schedule.ts +233 -116
  289. package/src/Set.ts +43 -24
  290. package/src/Sqlite.ts +18 -15
  291. package/src/Store.ts +3 -1
  292. package/src/String.ts +1 -1
  293. package/src/Task.ts +566 -286
  294. package/src/Test.ts +11 -4
  295. package/src/Time.ts +36 -19
  296. package/src/Type.ts +2191 -590
  297. package/src/Types.ts +108 -40
  298. package/src/WebSocket.ts +22 -6
  299. package/src/Worker.ts +11 -7
  300. package/src/intl/_en.ts +20 -4
  301. package/src/intl/ar.ts +17 -2
  302. package/src/intl/bn.ts +19 -4
  303. package/src/intl/ca.ts +19 -4
  304. package/src/intl/cs.ts +19 -4
  305. package/src/intl/da.ts +19 -4
  306. package/src/intl/de.ts +19 -4
  307. package/src/intl/el.ts +19 -4
  308. package/src/intl/es.ts +19 -4
  309. package/src/intl/fa.ts +19 -4
  310. package/src/intl/fi.ts +19 -4
  311. package/src/intl/fil.ts +19 -4
  312. package/src/intl/fr.ts +19 -4
  313. package/src/intl/he.ts +19 -4
  314. package/src/intl/hi.ts +19 -4
  315. package/src/intl/hr.ts +19 -4
  316. package/src/intl/hu.ts +18 -4
  317. package/src/intl/id.ts +19 -4
  318. package/src/intl/it.ts +19 -4
  319. package/src/intl/ja.ts +19 -4
  320. package/src/intl/ko.ts +19 -4
  321. package/src/intl/ml.ts +19 -4
  322. package/src/intl/mr.ts +19 -4
  323. package/src/intl/ms.ts +17 -2
  324. package/src/intl/nb.ts +16 -2
  325. package/src/intl/nl.ts +19 -4
  326. package/src/intl/pa.ts +19 -4
  327. package/src/intl/pl.ts +18 -2
  328. package/src/intl/pt-BR.ts +19 -4
  329. package/src/intl/pt.ts +17 -2
  330. package/src/intl/ro.ts +19 -4
  331. package/src/intl/sk.ts +17 -2
  332. package/src/intl/sl.ts +19 -4
  333. package/src/intl/sv.ts +19 -4
  334. package/src/intl/sw.ts +15 -2
  335. package/src/intl/ta.ts +19 -4
  336. package/src/intl/te.ts +19 -4
  337. package/src/intl/th.ts +19 -4
  338. package/src/intl/tr.ts +19 -4
  339. package/src/intl/uk.ts +19 -4
  340. package/src/intl/ur.ts +17 -2
  341. package/src/intl/vi.ts +19 -3
  342. package/src/intl/zh-CN.ts +19 -4
  343. package/src/intl/zh-TW.ts +19 -4
  344. package/src/local-first/Db.ts +2 -1
  345. package/src/local-first/Evolu.ts +48 -24
  346. package/src/local-first/Owner.ts +18 -14
  347. package/src/local-first/Protocol.ts +45 -35
  348. package/src/local-first/Query.ts +40 -24
  349. package/src/local-first/Relay.ts +13 -6
  350. package/src/local-first/Schema.ts +19 -11
  351. package/src/local-first/Shared.ts +4 -2
  352. package/src/local-first/Storage.ts +4 -2
  353. package/src/local-first/Timestamp.ts +1 -1
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,23 +31,283 @@ 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: (
33
44
  condition: unknown,
34
45
  message: string,
35
46
  ) => asserts condition = (condition, message) => {
47
+ // oxlint-disable-next-line typescript/strict-boolean-expressions -- JavaScript truthiness is the contract of assert.
36
48
  if (!condition) {
37
49
  throw new Error(message);
38
50
  }
39
51
  };
40
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
+
41
311
  /**
42
312
  * Asserts that a value is non-nullable.
43
313
  *
@@ -64,15 +334,23 @@ export const assertNonNullable: <T>(
64
334
  * ### Example
65
335
  *
66
336
  * ```ts
67
- * import { assertNotNull } from "@evolu/common";
337
+ * import {
338
+ * assert,
339
+ * assertEqual,
340
+ * assertErr,
341
+ * assertNotNull,
342
+ * assertType,
343
+ * trySync,
344
+ * } from "@evolu/common";
68
345
  *
69
346
  * const value = undefined as string | null | undefined;
70
347
  * assertNotNull(value);
71
- * expectTypeOf(value).toEqualTypeOf<string | undefined>();
72
- * expect(value).toBeUndefined();
73
- * expect(() => assertNotNull(null)).toThrow(
74
- * "Expected value not to be null.",
75
- * );
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.");
76
354
  * ```
77
355
  */
78
356
  export const assertNotNull: <T>(
@@ -94,15 +372,23 @@ export const assertNotNull: <T>(
94
372
  * ### Example
95
373
  *
96
374
  * ```ts
97
- * import { assertNotUndefined } from "@evolu/common";
375
+ * import {
376
+ * assert,
377
+ * assertEqual,
378
+ * assertErr,
379
+ * assertNotUndefined,
380
+ * assertType,
381
+ * trySync,
382
+ * } from "@evolu/common";
98
383
  *
99
384
  * const value = null as string | null | undefined;
100
385
  * assertNotUndefined(value);
101
- * expectTypeOf(value).toEqualTypeOf<string | null>();
102
- * expect(value).toBeNull();
103
- * expect(() => assertNotUndefined(undefined)).toThrow(
104
- * "Expected value not to be undefined.",
105
- * );
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.");
106
392
  * ```
107
393
  */
108
394
  export const assertNotUndefined: <T>(
@@ -124,13 +410,21 @@ export const assertNotUndefined: <T>(
124
410
  * ### Example
125
411
  *
126
412
  * ```ts
127
- * 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";
128
421
  *
129
422
  * const values = [1, 2, 3];
130
423
  * assertNonEmptyArray(values);
131
- * expectTypeOf(values).toEqualTypeOf<NonEmptyArray<number>>();
132
- * expect(values[0]).toBe(1);
133
- * expect(() => assertNonEmptyArray([])).toThrow();
424
+ * assertType<NonEmptyArray<number>, typeof values>();
425
+ * assertEqual(values[0], 1);
426
+ * const result = trySync(() => assertNonEmptyArray([]));
427
+ * assertErr(result);
134
428
  * ```
135
429
  */
136
430
  export const assertNonEmptyArray: <T>(
@@ -153,15 +447,20 @@ export const assertNonEmptyArray: <T>(
153
447
  *
154
448
  * ```ts
155
449
  * import {
450
+ * assertEqual,
451
+ * assertErr,
156
452
  * assertNonEmptyReadonlyArray,
453
+ * assertType,
454
+ * trySync,
157
455
  * type NonEmptyReadonlyArray,
158
456
  * } from "@evolu/common";
159
457
  *
160
458
  * const values: ReadonlyArray<number> = [1, 2, 3];
161
459
  * assertNonEmptyReadonlyArray(values);
162
- * expectTypeOf(values).toEqualTypeOf<NonEmptyReadonlyArray<number>>();
163
- * expect(values[0]).toBe(1);
164
- * expect(() => assertNonEmptyReadonlyArray([])).toThrow();
460
+ * assertType<NonEmptyReadonlyArray<number>, typeof values>();
461
+ * assertEqual(values[0], 1);
462
+ * const result = trySync(() => assertNonEmptyReadonlyArray([]));
463
+ * assertErr(result);
165
464
  * ```
166
465
  */
167
466
  export const assertNonEmptyReadonlyArray: <T>(
@@ -182,14 +481,21 @@ export const assertNonEmptyReadonlyArray: <T>(
182
481
  * ### Example
183
482
  *
184
483
  * ```ts
185
- * import { assertNotDisposed } from "@evolu/common";
484
+ * import {
485
+ * assert,
486
+ * assertEqual,
487
+ * assertErr,
488
+ * assertNotDisposed,
489
+ * trySync,
490
+ * } from "@evolu/common";
186
491
  *
187
492
  * await using disposer = new globalThis.AsyncDisposableStack();
188
- * expect(() => assertNotDisposed(disposer)).not.toThrow();
493
+ * assertNotDisposed(disposer);
189
494
  * await disposer.disposeAsync();
190
- * expect(() => assertNotDisposed(disposer)).toThrow(
191
- * "Cannot use a disposed object.",
192
- * );
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.");
193
499
  * ```
194
500
  *
195
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