@evolu/common 8.9.0 → 8.11.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 (337) hide show
  1. package/dist/src/Bytes.d.ts +647 -0
  2. package/dist/src/Bytes.d.ts.map +1 -0
  3. package/dist/src/{Binary.js → Bytes.js} +266 -16
  4. package/dist/src/Config.d.ts +142 -0
  5. package/dist/src/Config.d.ts.map +1 -0
  6. package/dist/src/Config.js +181 -0
  7. package/dist/src/Console.d.ts +62 -7
  8. package/dist/src/Console.d.ts.map +1 -1
  9. package/dist/src/Console.js +20 -4
  10. package/dist/src/Crypto.d.ts +76 -4
  11. package/dist/src/Crypto.d.ts.map +1 -1
  12. package/dist/src/Crypto.js +55 -4
  13. package/dist/src/Error.d.ts +45 -0
  14. package/dist/src/Error.d.ts.map +1 -1
  15. package/dist/src/Error.js +69 -0
  16. package/dist/src/Fs.d.ts +376 -0
  17. package/dist/src/Fs.d.ts.map +1 -0
  18. package/dist/src/Fs.js +113 -0
  19. package/dist/src/Identicon.d.ts +2 -2
  20. package/dist/src/Identicon.js +2 -2
  21. package/dist/src/LeakDetector.d.ts +22 -3
  22. package/dist/src/LeakDetector.d.ts.map +1 -1
  23. package/dist/src/LeakDetector.js +12 -2
  24. package/dist/src/LockManager.d.ts +8 -0
  25. package/dist/src/LockManager.d.ts.map +1 -1
  26. package/dist/src/LockManager.js +6 -0
  27. package/dist/src/Number.d.ts +50 -7
  28. package/dist/src/Number.d.ts.map +1 -1
  29. package/dist/src/Number.js +47 -8
  30. package/dist/src/Object.d.ts +32 -0
  31. package/dist/src/Object.d.ts.map +1 -1
  32. package/dist/src/Object.js +46 -0
  33. package/dist/src/Platform.d.ts +47 -7
  34. package/dist/src/Platform.d.ts.map +1 -1
  35. package/dist/src/Platform.js +24 -5
  36. package/dist/src/Random.d.ts +25 -2
  37. package/dist/src/Random.d.ts.map +1 -1
  38. package/dist/src/Random.js +14 -2
  39. package/dist/src/Resource.d.ts +156 -1
  40. package/dist/src/Resource.d.ts.map +1 -1
  41. package/dist/src/Resource.js +201 -72
  42. package/dist/src/Schedule.d.ts +11 -10
  43. package/dist/src/Schedule.d.ts.map +1 -1
  44. package/dist/src/Schedule.js +1 -1
  45. package/dist/src/Sqlite.d.ts +132 -16
  46. package/dist/src/Sqlite.d.ts.map +1 -1
  47. package/dist/src/Sqlite.js +64 -10
  48. package/dist/src/Task.d.ts +15 -4
  49. package/dist/src/Task.d.ts.map +1 -1
  50. package/dist/src/Task.js +41 -15
  51. package/dist/src/Test.d.ts +9 -0
  52. package/dist/src/Test.d.ts.map +1 -1
  53. package/dist/src/Test.js +4 -0
  54. package/dist/src/Time.d.ts +179 -20
  55. package/dist/src/Time.d.ts.map +1 -1
  56. package/dist/src/Time.js +95 -6
  57. package/dist/src/Type.d.ts +3056 -1539
  58. package/dist/src/Type.d.ts.map +1 -1
  59. package/dist/src/Type.js +2548 -584
  60. package/dist/src/WebSocket.d.ts +164 -13
  61. package/dist/src/WebSocket.d.ts.map +1 -1
  62. package/dist/src/WebSocket.js +133 -24
  63. package/dist/src/Worker.d.ts +90 -8
  64. package/dist/src/Worker.d.ts.map +1 -1
  65. package/dist/src/Worker.js +28 -2
  66. package/dist/src/index.d.ts +9 -8
  67. package/dist/src/index.d.ts.map +1 -1
  68. package/dist/src/index.js +5 -4
  69. package/dist/src/intl/_en.d.ts +24 -1
  70. package/dist/src/intl/_en.d.ts.map +1 -1
  71. package/dist/src/intl/_en.js +20 -0
  72. package/dist/src/intl/ar.d.ts +24 -1
  73. package/dist/src/intl/ar.d.ts.map +1 -1
  74. package/dist/src/intl/ar.js +20 -0
  75. package/dist/src/intl/bn.d.ts +24 -1
  76. package/dist/src/intl/bn.d.ts.map +1 -1
  77. package/dist/src/intl/bn.js +20 -0
  78. package/dist/src/intl/ca.d.ts +24 -1
  79. package/dist/src/intl/ca.d.ts.map +1 -1
  80. package/dist/src/intl/ca.js +20 -0
  81. package/dist/src/intl/cs.d.ts +24 -1
  82. package/dist/src/intl/cs.d.ts.map +1 -1
  83. package/dist/src/intl/cs.js +20 -0
  84. package/dist/src/intl/da.d.ts +24 -1
  85. package/dist/src/intl/da.d.ts.map +1 -1
  86. package/dist/src/intl/da.js +20 -0
  87. package/dist/src/intl/de.d.ts +24 -1
  88. package/dist/src/intl/de.d.ts.map +1 -1
  89. package/dist/src/intl/de.js +20 -0
  90. package/dist/src/intl/el.d.ts +24 -1
  91. package/dist/src/intl/el.d.ts.map +1 -1
  92. package/dist/src/intl/el.js +20 -0
  93. package/dist/src/intl/es.d.ts +24 -1
  94. package/dist/src/intl/es.d.ts.map +1 -1
  95. package/dist/src/intl/es.js +20 -0
  96. package/dist/src/intl/fa.d.ts +24 -1
  97. package/dist/src/intl/fa.d.ts.map +1 -1
  98. package/dist/src/intl/fa.js +20 -0
  99. package/dist/src/intl/fi.d.ts +24 -1
  100. package/dist/src/intl/fi.d.ts.map +1 -1
  101. package/dist/src/intl/fi.js +20 -0
  102. package/dist/src/intl/fil.d.ts +24 -1
  103. package/dist/src/intl/fil.d.ts.map +1 -1
  104. package/dist/src/intl/fil.js +20 -0
  105. package/dist/src/intl/fr.d.ts +24 -1
  106. package/dist/src/intl/fr.d.ts.map +1 -1
  107. package/dist/src/intl/fr.js +20 -0
  108. package/dist/src/intl/he.d.ts +24 -1
  109. package/dist/src/intl/he.d.ts.map +1 -1
  110. package/dist/src/intl/he.js +20 -0
  111. package/dist/src/intl/hi.d.ts +24 -1
  112. package/dist/src/intl/hi.d.ts.map +1 -1
  113. package/dist/src/intl/hi.js +20 -0
  114. package/dist/src/intl/hr.d.ts +24 -1
  115. package/dist/src/intl/hr.d.ts.map +1 -1
  116. package/dist/src/intl/hr.js +20 -0
  117. package/dist/src/intl/hu.d.ts +22 -1
  118. package/dist/src/intl/hu.d.ts.map +1 -1
  119. package/dist/src/intl/hu.js +18 -0
  120. package/dist/src/intl/id.d.ts +24 -1
  121. package/dist/src/intl/id.d.ts.map +1 -1
  122. package/dist/src/intl/id.js +20 -0
  123. package/dist/src/intl/it.d.ts +24 -1
  124. package/dist/src/intl/it.d.ts.map +1 -1
  125. package/dist/src/intl/it.js +20 -0
  126. package/dist/src/intl/ja.d.ts +24 -1
  127. package/dist/src/intl/ja.d.ts.map +1 -1
  128. package/dist/src/intl/ja.js +20 -0
  129. package/dist/src/intl/ko.d.ts +24 -1
  130. package/dist/src/intl/ko.d.ts.map +1 -1
  131. package/dist/src/intl/ko.js +20 -0
  132. package/dist/src/intl/ml.d.ts +24 -1
  133. package/dist/src/intl/ml.d.ts.map +1 -1
  134. package/dist/src/intl/ml.js +20 -0
  135. package/dist/src/intl/mr.d.ts +24 -1
  136. package/dist/src/intl/mr.d.ts.map +1 -1
  137. package/dist/src/intl/mr.js +20 -0
  138. package/dist/src/intl/ms.d.ts +24 -1
  139. package/dist/src/intl/ms.d.ts.map +1 -1
  140. package/dist/src/intl/ms.js +20 -0
  141. package/dist/src/intl/nb.d.ts +22 -1
  142. package/dist/src/intl/nb.d.ts.map +1 -1
  143. package/dist/src/intl/nb.js +18 -0
  144. package/dist/src/intl/nl.d.ts +24 -1
  145. package/dist/src/intl/nl.d.ts.map +1 -1
  146. package/dist/src/intl/nl.js +20 -0
  147. package/dist/src/intl/pa.d.ts +24 -1
  148. package/dist/src/intl/pa.d.ts.map +1 -1
  149. package/dist/src/intl/pa.js +20 -0
  150. package/dist/src/intl/pl.d.ts +23 -0
  151. package/dist/src/intl/pl.d.ts.map +1 -1
  152. package/dist/src/intl/pl.js +20 -0
  153. package/dist/src/intl/pt-BR.d.ts +24 -1
  154. package/dist/src/intl/pt-BR.d.ts.map +1 -1
  155. package/dist/src/intl/pt-BR.js +20 -0
  156. package/dist/src/intl/pt.d.ts +24 -1
  157. package/dist/src/intl/pt.d.ts.map +1 -1
  158. package/dist/src/intl/pt.js +20 -0
  159. package/dist/src/intl/ro.d.ts +24 -1
  160. package/dist/src/intl/ro.d.ts.map +1 -1
  161. package/dist/src/intl/ro.js +20 -0
  162. package/dist/src/intl/sk.d.ts +24 -1
  163. package/dist/src/intl/sk.d.ts.map +1 -1
  164. package/dist/src/intl/sk.js +20 -0
  165. package/dist/src/intl/sl.d.ts +24 -1
  166. package/dist/src/intl/sl.d.ts.map +1 -1
  167. package/dist/src/intl/sl.js +20 -0
  168. package/dist/src/intl/sv.d.ts +24 -1
  169. package/dist/src/intl/sv.d.ts.map +1 -1
  170. package/dist/src/intl/sv.js +20 -0
  171. package/dist/src/intl/sw.d.ts +21 -0
  172. package/dist/src/intl/sw.d.ts.map +1 -1
  173. package/dist/src/intl/sw.js +18 -0
  174. package/dist/src/intl/ta.d.ts +24 -1
  175. package/dist/src/intl/ta.d.ts.map +1 -1
  176. package/dist/src/intl/ta.js +20 -0
  177. package/dist/src/intl/te.d.ts +24 -1
  178. package/dist/src/intl/te.d.ts.map +1 -1
  179. package/dist/src/intl/te.js +20 -0
  180. package/dist/src/intl/th.d.ts +24 -1
  181. package/dist/src/intl/th.d.ts.map +1 -1
  182. package/dist/src/intl/th.js +20 -0
  183. package/dist/src/intl/tr.d.ts +24 -1
  184. package/dist/src/intl/tr.d.ts.map +1 -1
  185. package/dist/src/intl/tr.js +20 -0
  186. package/dist/src/intl/uk.d.ts +80 -57
  187. package/dist/src/intl/uk.d.ts.map +1 -1
  188. package/dist/src/intl/uk.js +174 -149
  189. package/dist/src/intl/ur.d.ts +24 -1
  190. package/dist/src/intl/ur.d.ts.map +1 -1
  191. package/dist/src/intl/ur.js +20 -0
  192. package/dist/src/intl/vi.d.ts +24 -1
  193. package/dist/src/intl/vi.d.ts.map +1 -1
  194. package/dist/src/intl/vi.js +20 -0
  195. package/dist/src/intl/zh-CN.d.ts +24 -1
  196. package/dist/src/intl/zh-CN.d.ts.map +1 -1
  197. package/dist/src/intl/zh-CN.js +20 -0
  198. package/dist/src/intl/zh-TW.d.ts +24 -1
  199. package/dist/src/intl/zh-TW.d.ts.map +1 -1
  200. package/dist/src/intl/zh-TW.js +20 -0
  201. package/dist/src/local-first/Db.d.ts +52 -3
  202. package/dist/src/local-first/Db.d.ts.map +1 -1
  203. package/dist/src/local-first/Db.js +412 -137
  204. package/dist/src/local-first/Evolu.d.ts +336 -211
  205. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  206. package/dist/src/local-first/Evolu.js +102 -15
  207. package/dist/src/local-first/Owner.d.ts +13 -30
  208. package/dist/src/local-first/Owner.d.ts.map +1 -1
  209. package/dist/src/local-first/Owner.js +13 -30
  210. package/dist/src/local-first/Protocol.d.ts +95 -17
  211. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  212. package/dist/src/local-first/Protocol.js +119 -39
  213. package/dist/src/local-first/Query.d.ts +8 -15
  214. package/dist/src/local-first/Query.d.ts.map +1 -1
  215. package/dist/src/local-first/Schema.d.ts +345 -21
  216. package/dist/src/local-first/Schema.d.ts.map +1 -1
  217. package/dist/src/local-first/Schema.js +214 -17
  218. package/dist/src/local-first/Shared.d.ts +537 -22
  219. package/dist/src/local-first/Shared.d.ts.map +1 -1
  220. package/dist/src/local-first/Shared.js +1437 -234
  221. package/dist/src/local-first/Storage.d.ts +192 -14
  222. package/dist/src/local-first/Storage.d.ts.map +1 -1
  223. package/dist/src/local-first/Storage.js +82 -21
  224. package/dist/src/local-first/Timestamp.d.ts +392 -41
  225. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  226. package/dist/src/local-first/Timestamp.js +404 -82
  227. package/dist/src/local-first/index.d.ts +0 -1
  228. package/dist/src/local-first/index.d.ts.map +1 -1
  229. package/dist/src/local-first/index.js +0 -1
  230. package/package.json +1 -1
  231. package/src/Assert.test.ts +2 -5
  232. package/src/{Binary.test.ts → Bytes.test.ts} +286 -1
  233. package/src/{Binary.ts → Bytes.ts} +652 -21
  234. package/src/Config.test.ts +668 -0
  235. package/src/Config.ts +410 -0
  236. package/src/Console.ts +62 -7
  237. package/src/Crypto.ts +76 -4
  238. package/src/Eq.test.ts +2 -3
  239. package/src/Error.test.ts +76 -3
  240. package/src/Error.ts +71 -0
  241. package/src/Fs.test.ts +105 -0
  242. package/src/Fs.ts +488 -0
  243. package/src/Identicon.ts +2 -2
  244. package/src/LeakDetector.ts +22 -3
  245. package/src/LockManager.ts +8 -0
  246. package/src/Number.test.ts +82 -18
  247. package/src/Number.ts +76 -8
  248. package/src/Object.test.ts +139 -10
  249. package/src/Object.ts +49 -0
  250. package/src/Platform.ts +50 -8
  251. package/src/Random.ts +25 -2
  252. package/src/Resource.test.ts +837 -0
  253. package/src/Resource.ts +235 -15
  254. package/src/Schedule.test.ts +50 -12
  255. package/src/Schedule.ts +24 -14
  256. package/src/Sqlite.ts +138 -18
  257. package/src/Task.test.ts +189 -8
  258. package/src/Task.ts +56 -17
  259. package/src/Test.ts +9 -0
  260. package/src/Time.test.ts +82 -11
  261. package/src/Time.ts +246 -24
  262. package/src/Type.test.ts +3994 -1119
  263. package/src/Type.ts +7258 -3842
  264. package/src/Types.test.ts +4 -14
  265. package/src/WebSocket.ts +313 -40
  266. package/src/Worker.ts +90 -8
  267. package/src/index.ts +18 -7
  268. package/src/intl/_en.ts +70 -0
  269. package/src/intl/ar.ts +71 -0
  270. package/src/intl/bn.ts +70 -0
  271. package/src/intl/ca.ts +70 -0
  272. package/src/intl/cs.ts +70 -0
  273. package/src/intl/da.ts +70 -0
  274. package/src/intl/de.ts +70 -0
  275. package/src/intl/el.ts +70 -0
  276. package/src/intl/es.ts +70 -0
  277. package/src/intl/fa.ts +70 -0
  278. package/src/intl/fi.ts +70 -0
  279. package/src/intl/fil.ts +70 -0
  280. package/src/intl/fr.ts +70 -0
  281. package/src/intl/he.ts +70 -0
  282. package/src/intl/hi.ts +70 -0
  283. package/src/intl/hr.ts +70 -0
  284. package/src/intl/hu.ts +69 -0
  285. package/src/intl/id.ts +70 -0
  286. package/src/intl/intl.test.ts +819 -1
  287. package/src/intl/it.ts +70 -0
  288. package/src/intl/ja.ts +70 -0
  289. package/src/intl/ko.ts +68 -0
  290. package/src/intl/ml.ts +70 -0
  291. package/src/intl/mr.ts +70 -0
  292. package/src/intl/ms.ts +71 -0
  293. package/src/intl/nb.ts +69 -0
  294. package/src/intl/nl.ts +70 -0
  295. package/src/intl/pa.ts +70 -0
  296. package/src/intl/pl.ts +63 -0
  297. package/src/intl/pt-BR.ts +70 -0
  298. package/src/intl/pt.ts +71 -0
  299. package/src/intl/ro.ts +70 -0
  300. package/src/intl/sk.ts +71 -0
  301. package/src/intl/sl.ts +70 -0
  302. package/src/intl/sv.ts +70 -0
  303. package/src/intl/sw.ts +62 -0
  304. package/src/intl/ta.ts +70 -0
  305. package/src/intl/te.ts +70 -0
  306. package/src/intl/th.ts +68 -0
  307. package/src/intl/tr.ts +70 -0
  308. package/src/intl/uk.ts +228 -155
  309. package/src/intl/ur.ts +70 -0
  310. package/src/intl/vi.ts +70 -0
  311. package/src/intl/zh-CN.ts +68 -0
  312. package/src/intl/zh-TW.ts +68 -0
  313. package/src/local-first/Db.ts +644 -339
  314. package/src/local-first/Evolu.test.ts +686 -21
  315. package/src/local-first/Evolu.ts +450 -228
  316. package/src/local-first/Owner.ts +13 -30
  317. package/src/local-first/Protocol.test.ts +618 -11
  318. package/src/local-first/Protocol.ts +197 -73
  319. package/src/local-first/Query.ts +8 -15
  320. package/src/local-first/Schema.test.ts +143 -0
  321. package/src/local-first/Schema.ts +374 -24
  322. package/src/local-first/Shared.test.ts +7731 -559
  323. package/src/local-first/Shared.ts +2036 -267
  324. package/src/local-first/Storage.ts +219 -33
  325. package/src/local-first/Timestamp.test.ts +344 -70
  326. package/src/local-first/Timestamp.ts +435 -119
  327. package/src/local-first/index.ts +0 -1
  328. package/dist/src/Binary.d.ts +0 -254
  329. package/dist/src/Binary.d.ts.map +0 -1
  330. package/dist/src/local-first/Error.d.ts +0 -12
  331. package/dist/src/local-first/Error.d.ts.map +0 -1
  332. package/dist/src/local-first/Error.js +0 -6
  333. package/dist/src/local-first/LocalAuth.d.ts +0 -150
  334. package/dist/src/local-first/LocalAuth.d.ts.map +0 -1
  335. package/dist/src/local-first/LocalAuth.js +0 -179
  336. package/src/local-first/Error.ts +0 -17
  337. package/src/local-first/LocalAuth.ts +0 -457
package/src/Crypto.ts CHANGED
@@ -24,6 +24,11 @@ import {
24
24
  zeroNonNegativeInt,
25
25
  } from "./Type.ts";
26
26
 
27
+ /**
28
+ * Cryptographically secure random bytes with length-branded results.
29
+ *
30
+ * @group Random bytes
31
+ */
27
32
  export interface RandomBytes {
28
33
  /**
29
34
  * Creates cryptographically secure random bytes with type-safe length
@@ -77,6 +82,11 @@ export interface RandomBytes {
77
82
  create(bytesLength: number): Entropy;
78
83
  }
79
84
 
85
+ /**
86
+ * Dependency wrapper for {@link RandomBytes}.
87
+ *
88
+ * @group Random bytes
89
+ */
80
90
  export interface RandomBytesDep {
81
91
  readonly randomBytes: RandomBytes;
82
92
  }
@@ -84,23 +94,53 @@ export interface RandomBytesDep {
84
94
  const Entropy = /*#__PURE__*/ brand("Entropy", Uint8Array);
85
95
  type Entropy = typeof Entropy.Output;
86
96
 
97
+ /**
98
+ * Cryptographic entropy of exactly 16 bytes.
99
+ *
100
+ * @group Random bytes
101
+ */
87
102
  export const Entropy16 = /*#__PURE__*/ length(16)(Entropy);
88
103
  export type Entropy16 = typeof Entropy16.Output;
89
104
 
105
+ /**
106
+ * Cryptographic entropy of exactly 24 bytes.
107
+ *
108
+ * @group Random bytes
109
+ */
90
110
  export const Entropy24 = /*#__PURE__*/ length(24)(Entropy);
91
111
  export type Entropy24 = typeof Entropy24.Output;
92
112
 
113
+ /**
114
+ * Cryptographic entropy of exactly 32 bytes.
115
+ *
116
+ * @group Random bytes
117
+ */
93
118
  export const Entropy32 = /*#__PURE__*/ length(32)(Entropy);
94
119
  export type Entropy32 = typeof Entropy32.Output;
95
120
 
121
+ /**
122
+ * Cryptographic entropy of exactly 64 bytes.
123
+ *
124
+ * @group Random bytes
125
+ */
96
126
  export const Entropy64 = /*#__PURE__*/ length(64)(Entropy);
97
127
  export type Entropy64 = typeof Entropy64.Output;
98
128
 
129
+ /**
130
+ * Creates {@link RandomBytes} backed by the platform's secure random number
131
+ * generator.
132
+ *
133
+ * @group Random bytes
134
+ */
99
135
  export const createRandomBytes = (): RandomBytes => ({
100
136
  create: randomBytes as RandomBytes["create"],
101
137
  });
102
138
 
103
- /** Creates seeded random bytes for deterministic tests. */
139
+ /**
140
+ * Creates seeded random bytes for deterministic tests.
141
+ *
142
+ * @group Testing
143
+ */
104
144
  export const testCreateRandomBytes = (deps: RandomLibDep): RandomBytes =>
105
145
  ({
106
146
  create: (bytesLength: number) =>
@@ -113,6 +153,8 @@ export const testCreateRandomBytes = (deps: RandomLibDep): RandomBytes =>
113
153
  * SLIP21.
114
154
  *
115
155
  * https://github.com/satoshilabs/slips/blob/master/slip-0021.md
156
+ *
157
+ * @group Key derivation
116
158
  */
117
159
  export const createSlip21 = (
118
160
  seed: Entropy16 | Entropy32 | Entropy64,
@@ -135,6 +177,7 @@ export const createSlip21 = (
135
177
  /**
136
178
  * Derives a single node in the SLIP-21 hierarchical key derivation.
137
179
  *
180
+ * @group Key derivation
138
181
  * @see {@link createSlip21}
139
182
  */
140
183
  export const deriveSlip21Node = (
@@ -148,16 +191,25 @@ export const deriveSlip21Node = (
148
191
  return hmac(sha512, parentNode.slice(0, 32), message) as Entropy64;
149
192
  };
150
193
 
151
- /** The encryption key for symmetric encryption. */
194
+ /**
195
+ * The encryption key for symmetric encryption.
196
+ *
197
+ * @group Encryption
198
+ */
152
199
  export const EncryptionKey = /*#__PURE__*/ brand("EncryptionKey", Entropy32);
153
200
  export type EncryptionKey = typeof EncryptionKey.Output;
154
201
 
155
- /** The nonce length for XChaCha20-Poly1305 encryption. */
202
+ /**
203
+ * The nonce length for XChaCha20-Poly1305 encryption.
204
+ *
205
+ * @group Encryption
206
+ */
156
207
  export const xChaCha20Poly1305NonceLength = 24;
157
208
 
158
209
  /**
159
210
  * Branded Uint8Array for XChaCha20-Poly1305 encryption.
160
211
  *
212
+ * @group Encryption
161
213
  * @see {@link encryptWithXChaCha20Poly1305}
162
214
  */
163
215
  export const XChaCha20Poly1305Ciphertext = /*#__PURE__*/ brand(
@@ -196,6 +248,7 @@ export type XChaCha20Poly1305Ciphertext =
196
248
  * assertEqual(nonce.length, 24);
197
249
  * ```
198
250
  *
251
+ * @group Encryption
199
252
  * @see https://github.com/paulmillr/noble-ciphers
200
253
  */
201
254
  export const encryptWithXChaCha20Poly1305 =
@@ -211,6 +264,11 @@ export const encryptWithXChaCha20Poly1305 =
211
264
  return [ciphertext, nonce];
212
265
  };
213
266
 
267
+ /**
268
+ * Error returned by {@link decryptWithXChaCha20Poly1305} when decryption fails.
269
+ *
270
+ * @group Encryption
271
+ */
214
272
  export interface DecryptWithXChaCha20Poly1305Error extends Typed<"DecryptWithXChaCha20Poly1305Error"> {
215
273
  readonly error: unknown;
216
274
  }
@@ -254,6 +312,8 @@ export interface DecryptWithXChaCha20Poly1305Error extends Typed<"DecryptWithXCh
254
312
  *
255
313
  * assertOk(decryptMessage(), "secret message");
256
314
  * ```
315
+ *
316
+ * @group Encryption
257
317
  */
258
318
  export const decryptWithXChaCha20Poly1305 = (
259
319
  ciphertext: XChaCha20Poly1305Ciphertext,
@@ -275,6 +335,8 @@ export const decryptWithXChaCha20Poly1305 = (
275
335
  * wide range of encrypted data sizes.
276
336
  *
277
337
  * See the PURBs paper for details: https://bford.info/pub/sec/purb.pdf
338
+ *
339
+ * @group Padding
278
340
  */
279
341
  export const createPadmePaddedLength = (
280
342
  length: NonNegativeInt,
@@ -287,7 +349,11 @@ export const createPadmePaddedLength = (
287
349
  return NonNegativeInt.orThrow((length + mask) & ~mask);
288
350
  };
289
351
 
290
- /** Creates a PADMÉ padding array of zeros for the given input length. */
352
+ /**
353
+ * Creates a PADMÉ padding array of zeros for the given input length.
354
+ *
355
+ * @group Padding
356
+ */
291
357
  export const createPadmePadding = (length: NonNegativeInt): Uint8Array => {
292
358
  const paddedLength = createPadmePaddedLength(length);
293
359
  const paddingLength = NonNegativeInt.orThrow(paddedLength - length);
@@ -299,10 +365,16 @@ export const createPadmePadding = (length: NonNegativeInt): Uint8Array => {
299
365
  * are equal, false otherwise. Takes constant time regardless of where the
300
366
  * arrays differ.
301
367
  *
368
+ * @group Comparison
302
369
  * @see https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b
303
370
  */
304
371
  export type TimingSafeEqual = (a: Uint8Array, b: Uint8Array) => boolean;
305
372
 
373
+ /**
374
+ * Dependency wrapper for {@link TimingSafeEqual}.
375
+ *
376
+ * @group Comparison
377
+ */
306
378
  export interface TimingSafeEqualDep {
307
379
  readonly timingSafeEqual: TimingSafeEqual;
308
380
  }
package/src/Eq.test.ts CHANGED
@@ -293,13 +293,12 @@ test("eqData", () => {
293
293
  }
294
294
  const service: Service = { run: () => undefined };
295
295
  const broadObject: NonNullable<unknown> = new WeakMap();
296
- const compileTimeAssertions = () => {
296
+ void (() => {
297
297
  // @ts-expect-error ⛔ eqData error: Actual and expected values must consist only of Data.
298
298
  eqData(service, service);
299
299
  // @ts-expect-error ⛔ eqData error: Actual and expected values must consist only of Data.
300
300
  eqData(broadObject, broadObject);
301
- };
302
- assertEqual(typeof compileTimeAssertions, "function");
301
+ });
303
302
  });
304
303
 
305
304
  test("eqData compares deeply nested Set and Map data", () => {
package/src/Error.test.ts CHANGED
@@ -1,7 +1,15 @@
1
1
  import { describe, it } from "node:test";
2
- import { assertEqual, assertFalse, assertSame, assertTrue } from "./Assert.ts";
3
-
4
- import { UnknownError, createUnknownError } from "./Error.ts";
2
+ import { runInNewContext } from "node:vm";
3
+ import {
4
+ assertEqual,
5
+ assertFalse,
6
+ assertInstanceOf,
7
+ assertSame,
8
+ assertTrue,
9
+ } from "./Assert.ts";
10
+
11
+ import { UnknownError, createUnknownError, defectToError } from "./Error.ts";
12
+ import { createRun } from "./Task.ts";
5
13
  import { assertType, Object, String } from "./Type.ts";
6
14
 
7
15
  describe("createUnknownError", () => {
@@ -116,3 +124,68 @@ describe("createUnknownError", () => {
116
124
  assertSame(actual.self, actual);
117
125
  });
118
126
  });
127
+
128
+ describe("defectToError", () => {
129
+ it("converts a panic to its Error defect", async () => {
130
+ const reported: Array<unknown> = [];
131
+ await using run = createRun({
132
+ reportDefect: (defect) => {
133
+ reported.push(defect);
134
+ },
135
+ });
136
+ const defect = new Error("boom");
137
+
138
+ run.panic(defect);
139
+
140
+ assertSame(defectToError(reported[0]), defect);
141
+ });
142
+
143
+ it("returns an Error from another realm as it is", () => {
144
+ const defect: unknown = runInNewContext(
145
+ 'new TypeError("other realm failed")',
146
+ );
147
+ assertFalse(defect instanceof Error);
148
+
149
+ assertSame(defectToError(defect), defect);
150
+ });
151
+
152
+ it("describes a DOMException with its name and message", () => {
153
+ const defect = new DOMException("dom failed", "NotFoundError");
154
+
155
+ const error = defectToError(defect);
156
+
157
+ assertEqual(error.message, "NotFoundError: dom failed");
158
+ assertSame(error.cause, defect);
159
+ });
160
+
161
+ it("describes a panic's defect that is not an Error", async () => {
162
+ const reported: Array<unknown> = [];
163
+ await using run = createRun({
164
+ reportDefect: (defect) => {
165
+ reported.push(defect);
166
+ },
167
+ });
168
+
169
+ const abortError = run.panic({ type: "UnexpectedState", count: 1 });
170
+
171
+ const error = defectToError(reported[0]);
172
+ assertInstanceOf(error, Error);
173
+ assertEqual(error.message, 'Defect: {"type":"UnexpectedState","count":1}');
174
+ assertSame(error.cause, abortError);
175
+ });
176
+
177
+ it("describes an AbortError that is not a panic", () => {
178
+ const abortError = {
179
+ type: "AbortError",
180
+ reason: { type: "OtherAbortReason" },
181
+ } as const;
182
+
183
+ const error = defectToError(abortError);
184
+
185
+ assertEqual(
186
+ error.message,
187
+ 'Defect: {"type":"AbortError","reason":{"type":"OtherAbortReason"}}',
188
+ );
189
+ assertSame(error.cause, abortError);
190
+ });
191
+ });
package/src/Error.ts CHANGED
@@ -4,6 +4,8 @@
4
4
  * @module
5
5
  */
6
6
 
7
+ import { safelyStringifyUnknownValue } from "./String.ts";
8
+ import { AbortError, type createRun, type ReportDefect } from "./Task.ts";
7
9
  import { type InferType, typed, type TypedType, Unknown } from "./Type.ts";
8
10
 
9
11
  /**
@@ -84,3 +86,72 @@ export const createUnknownError = (error: unknown): UnknownError => {
84
86
  }
85
87
  }
86
88
  };
89
+
90
+ /**
91
+ * Converts a reported defect to an `Error` that a host error reporter shows
92
+ * readably.
93
+ *
94
+ * Hosts such as browsers and React Native show a reported value that is not an
95
+ * `Error` only as text such as "[object Object]", and a worker's error reaches
96
+ * its page, including an error tracker listening there, as that text alone. A
97
+ * panic reports a plain {@link AbortError}, so its defect is converted instead.
98
+ * An `Error` is returned as it is, including one from another realm, such as an
99
+ * iframe. A `DOMException` is described in an `Error` with its name and
100
+ * message, because Chromium reports one from a worker without them. Any other
101
+ * value is described in an `Error` whose cause is what was reported.
102
+ *
103
+ * Platform {@link createRun} adapters use it for their default reporting. A
104
+ * custom {@link ReportDefect} can use it too, such as before passing a defect to
105
+ * an error tracker.
106
+ *
107
+ * ### Example
108
+ *
109
+ * ```ts
110
+ * import {
111
+ * assertEqual,
112
+ * assertSame,
113
+ * createRun,
114
+ * defectToError,
115
+ * } from "@evolu/common";
116
+ *
117
+ * const errors: Array<Error> = [];
118
+ * await using run = createRun({
119
+ * reportDefect: (reported) => {
120
+ * errors.push(defectToError(reported));
121
+ * },
122
+ * });
123
+ * const defect = new Error("boom");
124
+ *
125
+ * run.panic(defect);
126
+ *
127
+ * assertSame(errors[0], defect);
128
+ * assertEqual(
129
+ * defectToError({ type: "UnexpectedState" }).message,
130
+ * 'Defect: {"type":"UnexpectedState"}',
131
+ * );
132
+ * ```
133
+ */
134
+ export const defectToError = (reported: unknown): Error => {
135
+ const defect =
136
+ AbortError.is(reported) && reported.reason.type === "PanicAbortReason"
137
+ ? reported.reason.defect
138
+ : reported;
139
+ // The internal tag survives crossing realms, such as from an iframe, where
140
+ // instanceof fails.
141
+ const tag = Object.prototype.toString.call(defect);
142
+ // Chromium reports a DOMException from a worker without its name or message,
143
+ // so it is described in an Error.
144
+ if (tag === "[object DOMException]") {
145
+ const { name, message } = defect as Error;
146
+ return new Error(`${name}: ${message}`, { cause: defect });
147
+ }
148
+ if (defect instanceof Error || tag === "[object Error]") {
149
+ return defect as Error;
150
+ }
151
+ // A value with a cycle or a bigint falls back to String, often
152
+ // "[object Object]", and a nested Error shows as "{}". That is enough:
153
+ // Evolu's own defects are Errors, and the cause still holds the value.
154
+ return new Error(`Defect: ${safelyStringifyUnknownValue(defect)}`, {
155
+ cause: reported,
156
+ });
157
+ };
package/src/Fs.test.ts ADDED
@@ -0,0 +1,105 @@
1
+ import { describe, it } from "node:test";
2
+ import {
3
+ assert,
4
+ assertEqual,
5
+ assertErr,
6
+ assertInstanceOf,
7
+ assertOk,
8
+ assertSame,
9
+ } from "./Assert.ts";
10
+ import { testCreateFs, type Fs, type FsDep, type FsError } from "./Fs.ts";
11
+ import { err, ok } from "./Result.ts";
12
+ import { AbortError, testCreateRun, type Task } from "./Task.ts";
13
+ import { assertType } from "./Type.ts";
14
+
15
+ describe("testCreateFs", () => {
16
+ it("accepts native copy options and rejects the former overwrite option", () => {
17
+ const fs = testCreateFs();
18
+ const task = fs.copy("source", "destination", {
19
+ force: false,
20
+ errorOnExist: true,
21
+ preserveTimestamps: true,
22
+ });
23
+ assertType<typeof task, Task<void, FsError>>();
24
+
25
+ // @ts-expect-error: FsCopyOptions has no overwrite property; use Node's force and errorOnExist options.
26
+ fs.copy("source", "destination", { overwrite: false });
27
+ });
28
+
29
+ for (const [method, createTask] of [
30
+ ["readFile", (fs: Fs) => fs.readFile("file.txt")],
31
+ ["writeFile", (fs: Fs) => fs.writeFile("file.txt", "content")],
32
+ ["readDirectory", (fs: Fs) => fs.readDirectory("directory")],
33
+ ["createDirectory", (fs: Fs) => fs.createDirectory("directory")],
34
+ ["copy", (fs: Fs) => fs.copy("source", "destination")],
35
+ ["copyFile", (fs: Fs) => fs.copyFile("source", "destination")],
36
+ ["rename", (fs: Fs) => fs.rename("source", "destination")],
37
+ ["remove", (fs: Fs) => fs.remove("file.txt")],
38
+ ["getMetadata", (fs: Fs) => fs.getMetadata("file.txt")],
39
+ ["exists", (fs: Fs) => fs.exists("file.txt")],
40
+ ["createTempDirectory", (fs: Fs) => fs.createTempDirectory()],
41
+ ] as const) {
42
+ it(`panics when an unconfigured ${method} Task runs`, async () => {
43
+ const fs = testCreateFs();
44
+ const task = createTask(fs);
45
+ await using run = testCreateRun();
46
+
47
+ const result = await run.abortable<unknown, FsError>(task);
48
+
49
+ assertErr(result);
50
+ assert(AbortError.is(result.error), "Unexpected Fs calls must abort.");
51
+ assertEqual(result.error.reason.type, "PanicAbortReason");
52
+ const { defect } = result.error.reason;
53
+ assertInstanceOf(defect, Error);
54
+ assertEqual(defect.message, `Unexpected Fs.${method} call`);
55
+ assertEqual(run.deps.reportDefect.getDefects(), [result.error]);
56
+ });
57
+ }
58
+
59
+ it("uses an injected override with the original arguments", async () => {
60
+ const path = new URL("file:///message.txt");
61
+ const data = new TextEncoder().encode("hello");
62
+ const options = { flag: "a" } as const;
63
+ let calls = 0;
64
+ const writeFile: Fs["writeFile"] =
65
+ (receivedPath, receivedData, receivedOptions) => () => {
66
+ calls += 1;
67
+ assertSame(receivedPath, path);
68
+ assertSame(receivedData, data);
69
+ assertSame(receivedOptions, options);
70
+ return ok();
71
+ };
72
+ const fs = testCreateFs({ writeFile });
73
+ assertSame(fs.writeFile, writeFile);
74
+ await using run = testCreateRun({ fs });
75
+ const saveMessage: Task<void, FsError, FsDep> = (run) =>
76
+ run(run.deps.fs.writeFile(path, data, options));
77
+
78
+ assertEqual(calls, 0);
79
+ assertOk(await run(saveMessage));
80
+ assertEqual(calls, 1);
81
+ });
82
+
83
+ it("preserves readFile overloads and injected errors", async () => {
84
+ const error: FsError = {
85
+ type: "FsError",
86
+ reason: "PermissionDenied",
87
+ path: "protected.txt",
88
+ syscall: "open",
89
+ message: "Permission denied",
90
+ };
91
+ const fs = testCreateFs({ readFile: () => () => err(error) });
92
+ await using run = testCreateRun();
93
+ const bytes = fs.readFile("protected.txt");
94
+ const text = fs.readFile("protected.txt", "utf8");
95
+ const encoded = fs.readFile("protected.txt", { encoding: "utf8" });
96
+ assertType<typeof bytes, Task<Uint8Array, FsError>>();
97
+ assertType<typeof text, Task<string, FsError>>();
98
+ assertType<typeof encoded, Task<string, FsError>>();
99
+
100
+ assertErr(await run(bytes), error);
101
+ assertErr(await run(text), error);
102
+ assertErr(await run(encoded), error);
103
+ assertEqual(run.deps.reportDefect.getDefects(), []);
104
+ });
105
+ });