@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/dist/src/Fs.js ADDED
@@ -0,0 +1,113 @@
1
+ /**
2
+ * File system operations for {@link Task}s.
3
+ *
4
+ * {@link Fs} reads, writes, copies, and renames files; lists and manages
5
+ * directories; and provides metadata and existence checks. Each operation
6
+ * returns a Task.
7
+ *
8
+ * Tasks can sequence file operations without synchronous I/O. Node.js's
9
+ * synchronous methods are intentionally omitted to avoid accidentally blocking
10
+ * the event loop.
11
+ *
12
+ * Inject {@link @evolu/nodejs!createNodeFs | createNodeFs} through
13
+ * {@link @evolu/nodejs!runMain | runMain} or {@link createRun}. Tasks declare
14
+ * {@link FsDep} and access the file system through `run.deps.fs`.
15
+ *
16
+ * {@link FsError} includes the path, a diagnostic message, and a
17
+ * {@link FsErrorReason} such as `NotFound` or `PermissionDenied`.
18
+ * {@link Fs.exists} returns `false` for `NotFound` and preserves other errors.
19
+ *
20
+ * ### Example
21
+ *
22
+ * ```ts
23
+ * import {
24
+ * assertEqual,
25
+ * ok,
26
+ * type FsDep,
27
+ * type FsError,
28
+ * type Task,
29
+ * } from "@evolu/common";
30
+ * import { createNodeFs, runMain } from "@evolu/nodejs";
31
+ * import { join } from "node:path";
32
+ *
33
+ * const main: Task<void, FsError, FsDep> = async (run) => {
34
+ * const { fs } = run.deps;
35
+ * const temp = await run(
36
+ * fs.createTempDirectory({ prefix: "evolu-fs-" }),
37
+ * );
38
+ * if (!temp.ok) return temp;
39
+ *
40
+ * await using directory = temp.value;
41
+ * const path = join(directory.path, "message.txt");
42
+ *
43
+ * const result = await run(fs.writeFile(path, "hello"));
44
+ * if (!result.ok) return result;
45
+ *
46
+ * const text = await run(fs.readFile(path, "utf8"));
47
+ * if (!text.ok) return text;
48
+ * assertEqual(text.value, "hello");
49
+ *
50
+ * return ok();
51
+ * };
52
+ *
53
+ * await runMain({ fs: createNodeFs() }, { mode: "command" })(main);
54
+ * ```
55
+ *
56
+ * @module
57
+ */
58
+ /**
59
+ * Creates a test {@link Fs} with the supplied operation overrides.
60
+ *
61
+ * Unconfigured operations throw a defect naming the method when their Task
62
+ * runs. Constructing a Task does not execute it. This helper performs no file
63
+ * system I/O; overrides provide the behavior needed by each test.
64
+ *
65
+ * ### Example
66
+ *
67
+ * ```ts
68
+ * import {
69
+ * assertEqual,
70
+ * assertOk,
71
+ * ok,
72
+ * testCreateFs,
73
+ * testCreateRun,
74
+ * type FsDep,
75
+ * type FsError,
76
+ * type Task,
77
+ * } from "@evolu/common";
78
+ *
79
+ * const saveMessage: Task<void, FsError, FsDep> = (run) =>
80
+ * run(run.deps.fs.writeFile("message.txt", "hello"));
81
+ *
82
+ * await using run = testCreateRun({
83
+ * fs: testCreateFs({
84
+ * writeFile: (path, data) => () => {
85
+ * assertEqual(path, "message.txt");
86
+ * assertEqual(data, "hello");
87
+ * return ok();
88
+ * },
89
+ * }),
90
+ * });
91
+ *
92
+ * assertOk(await run(saveMessage));
93
+ * ```
94
+ *
95
+ * @group Testing
96
+ */
97
+ export const testCreateFs = (overrides = {}) => ({
98
+ readFile: createUnexpectedFsOperation("readFile"),
99
+ writeFile: createUnexpectedFsOperation("writeFile"),
100
+ readDirectory: createUnexpectedFsOperation("readDirectory"),
101
+ createDirectory: createUnexpectedFsOperation("createDirectory"),
102
+ copy: createUnexpectedFsOperation("copy"),
103
+ copyFile: createUnexpectedFsOperation("copyFile"),
104
+ rename: createUnexpectedFsOperation("rename"),
105
+ remove: createUnexpectedFsOperation("remove"),
106
+ getMetadata: createUnexpectedFsOperation("getMetadata"),
107
+ exists: createUnexpectedFsOperation("exists"),
108
+ createTempDirectory: createUnexpectedFsOperation("createTempDirectory"),
109
+ ...overrides,
110
+ });
111
+ const createUnexpectedFsOperation = (method) => () => () => {
112
+ throw new Error(`Unexpected Fs.${method} call`);
113
+ };
@@ -32,6 +32,7 @@ export type IdenticonStyle = "github" | "quadrant" | "gradient" | "sutnar";
32
32
  * assertTrue,
33
33
  * createIdFromString,
34
34
  * createIdenticon,
35
+ * testTodoId,
35
36
  * } from "@evolu/common";
36
37
  *
37
38
  * const id = createIdFromString("identicon-example");
@@ -42,8 +43,7 @@ export type IdenticonStyle = "github" | "quadrant" | "gradient" | "sutnar";
42
43
  * );
43
44
  *
44
45
  * // Branded IDs work too.
45
- * const todoId = createIdFromString<"Todo">("todo-1");
46
- * const todoSvg = createIdenticon(todoId);
46
+ * const todoSvg = createIdenticon(testTodoId);
47
47
  *
48
48
  * assertTrue(svg.startsWith("<svg"));
49
49
  * assertEqual(new Set([svg, ...alternativeSvgs]).size, 4);
@@ -25,6 +25,7 @@ import { Id, idToIdBytes } from "./Type.js";
25
25
  * assertTrue,
26
26
  * createIdFromString,
27
27
  * createIdenticon,
28
+ * testTodoId,
28
29
  * } from "@evolu/common";
29
30
  *
30
31
  * const id = createIdFromString("identicon-example");
@@ -35,8 +36,7 @@ import { Id, idToIdBytes } from "./Type.js";
35
36
  * );
36
37
  *
37
38
  * // Branded IDs work too.
38
- * const todoId = createIdFromString<"Todo">("todo-1");
39
- * const todoSvg = createIdenticon(todoId);
39
+ * const todoSvg = createIdenticon(testTodoId);
40
40
  *
41
41
  * assertTrue(svg.startsWith("<svg"));
42
42
  * assertEqual(new Set([svg, ...alternativeSvgs]).size, 4);
@@ -19,6 +19,8 @@ import { type ConsoleDep } from "./Console.ts";
19
19
  * a warning may come late or, in short-lived processes, never. It is a
20
20
  * development canary, not a guarantee. Production uses
21
21
  * {@link noopLeakDetector}.
22
+ *
23
+ * @group Core
22
24
  */
23
25
  export interface LeakDetector {
24
26
  /**
@@ -33,7 +35,11 @@ export interface LeakDetector {
33
35
  /** Stops tracking the target registered with `unregisterToken`. */
34
36
  readonly untrack: (unregisterToken: object) => void;
35
37
  }
36
- /** Describes a tracked handle for {@link LeakDetector.track}. */
38
+ /**
39
+ * Describes a tracked handle for {@link LeakDetector.track}.
40
+ *
41
+ * @group Core
42
+ */
37
43
  export interface Leak {
38
44
  /** Handle name used in the warning, for example `"Lease"`. */
39
45
  readonly name: string;
@@ -43,6 +49,7 @@ export interface Leak {
43
49
  /**
44
50
  * Dependency wrapper for {@link LeakDetector}.
45
51
  *
52
+ * @group Core
46
53
  * @see {@link LeakDetector}
47
54
  */
48
55
  export interface LeakDetectorDep {
@@ -53,13 +60,20 @@ export interface LeakDetectorDep {
53
60
  *
54
61
  * Capturing a stack per track call is too expensive for production; use
55
62
  * {@link noopLeakDetector} there.
63
+ *
64
+ * @group Core
56
65
  */
57
66
  export declare const createLeakDetector: (deps: ConsoleDep) => LeakDetector;
58
- /** No-op {@link LeakDetector} for production. */
67
+ /**
68
+ * No-op {@link LeakDetector} for production.
69
+ *
70
+ * @group Core
71
+ */
59
72
  export declare const noopLeakDetector: LeakDetector;
60
73
  /**
61
74
  * Test {@link LeakDetector} with deterministic collection.
62
75
  *
76
+ * @group Testing
63
77
  * @see {@link testCreateLeakDetector}
64
78
  */
65
79
  export interface TestLeakDetector extends LeakDetector {
@@ -78,11 +92,16 @@ export interface TestLeakDetector extends LeakDetector {
78
92
  /**
79
93
  * Dependency wrapper for {@link TestLeakDetector}.
80
94
  *
95
+ * @group Testing
81
96
  * @see {@link TestLeakDetector}
82
97
  */
83
98
  export interface TestLeakDetectorDep extends LeakDetectorDep {
84
99
  readonly leakDetector: TestLeakDetector;
85
100
  }
86
- /** Creates {@link TestLeakDetector}. */
101
+ /**
102
+ * Creates {@link TestLeakDetector}.
103
+ *
104
+ * @group Testing
105
+ */
87
106
  export declare const testCreateLeakDetector: (deps: ConsoleDep) => TestLeakDetector;
88
107
  //# sourceMappingURL=LeakDetector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LeakDetector.d.ts","sourceRoot":"","sources":["../../src/LeakDetector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;IAE9E,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED,iEAAiE;AACjE,MAAM,WAAW,IAAI;IACnB,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC;CAClC;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;CACrC;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,SAAU,UAAU,KAAG,YAsBrD,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,gBAAgB,EAAE,YAG9B,CAAC;AAyBF;;;;GAIG;AACH,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,MAAM,CAAC;IAE/B,uDAAuD;IACvD,QAAQ,CAAC,eAAe,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CACnE;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAoB,SAAQ,eAAe;IAC1D,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC;CACzC;AAED,wCAAwC;AACxC,eAAO,MAAM,sBAAsB,SAAU,UAAU,KAAG,gBAsCzD,CAAC"}
1
+ {"version":3,"file":"LeakDetector.d.ts","sourceRoot":"","sources":["../../src/LeakDetector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;IAE9E,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED;;;;GAIG;AACH,MAAM,WAAW,IAAI;IACnB,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC;CAClC;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,SAAU,UAAU,KAAG,YAsBrD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,YAG9B,CAAC;AAyBF;;;;;GAKG;AACH,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,MAAM,CAAC;IAE/B,uDAAuD;IACvD,QAAQ,CAAC,eAAe,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CACnE;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAoB,SAAQ,eAAe;IAC1D,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC;CACzC;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,SAAU,UAAU,KAAG,gBAsCzD,CAAC"}
@@ -10,6 +10,8 @@ import { constVoid } from "./Function.js";
10
10
  *
11
11
  * Capturing a stack per track call is too expensive for production; use
12
12
  * {@link noopLeakDetector} there.
13
+ *
14
+ * @group Core
13
15
  */
14
16
  export const createLeakDetector = (deps) => {
15
17
  if (typeof globalThis.FinalizationRegistry !== "function")
@@ -28,7 +30,11 @@ export const createLeakDetector = (deps) => {
28
30
  },
29
31
  };
30
32
  };
31
- /** No-op {@link LeakDetector} for production. */
33
+ /**
34
+ * No-op {@link LeakDetector} for production.
35
+ *
36
+ * @group Core
37
+ */
32
38
  export const noopLeakDetector = {
33
39
  track: constVoid,
34
40
  untrack: constVoid,
@@ -47,7 +53,11 @@ const reportLeak = (deps) => (leak) => {
47
53
  deps.console.warn(`${leak.name} was garbage-collected without cleanup. Tracked at:`, leak.stack);
48
54
  return true;
49
55
  };
50
- /** Creates {@link TestLeakDetector}. */
56
+ /**
57
+ * Creates {@link TestLeakDetector}.
58
+ *
59
+ * @group Testing
60
+ */
51
61
  export const testCreateLeakDetector = (deps) => {
52
62
  const trackedLeaksByToken = new Map();
53
63
  const report = reportLeak(deps);
@@ -41,6 +41,8 @@ import type { Callback } from "./Types.ts";
41
41
  * );
42
42
  * assertEqual(result, "example");
43
43
  * ```
44
+ *
45
+ * @group Core
44
46
  */
45
47
  export interface LockManagerDep {
46
48
  readonly lockManager: LockManager;
@@ -57,6 +59,8 @@ export interface LockManagerDep {
57
59
  * via internal namespacing, so tests can reuse the same lock names without
58
60
  * contending through the global Web Locks. Query results are filtered to that
59
61
  * private namespace and returned with the original visible names.
62
+ *
63
+ * @group Testing
60
64
  */
61
65
  export declare const testCreateLockManager: (nativeLockManager?: LockManager) => LockManager;
62
66
  /**
@@ -68,6 +72,8 @@ export declare const testCreateLockManager: (nativeLockManager?: LockManager) =>
68
72
  * Leadership is held until the returned handle is disposed. Once released,
69
73
  * another waiting caller may become the next leader. Waiting for leadership is
70
74
  * abortable via the calling {@link Task}'s signal.
75
+ *
76
+ * @group Leader election
71
77
  */
72
78
  export declare const acquireLeaderLock: (name: string) => Task<AsyncDisposable, never, LockManagerDep>;
73
79
  /**
@@ -80,6 +86,8 @@ export declare const acquireLeaderLock: (name: string) => Task<AsyncDisposable,
80
86
  * Leadership is held until the returned handle is disposed. Once released,
81
87
  * another waiting caller may become the next leader. Waiting for leadership is
82
88
  * abortable by disposing the returned handle.
89
+ *
90
+ * @group Leader election
83
91
  */
84
92
  export declare const acquireLeaderLockCallback: (deps: LockManagerDep) => (name: string, callback: Callback<void>) => Disposable;
85
93
  //# sourceMappingURL=LockManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LockManager.d.ts","sourceRoot":"","sources":["../../src/LockManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;CACnC;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,uBACb,WAAW,KAC7B,WAwCF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,SACrB,MAAM,KAAG,IAAI,CAAC,eAAe,EAAE,KAAK,EAAE,cAAc,CAuB1D,CAAC;AAEJ;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,SAC7B,cAAc,YACd,MAAM,YAAY,QAAQ,CAAC,IAAI,CAAC,KAAG,UAsBzC,CAAC"}
1
+ {"version":3,"file":"LockManager.d.ts","sourceRoot":"","sources":["../../src/LockManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;CACnC;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,qBAAqB,uBACb,WAAW,KAC7B,WAwCF,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,SACrB,MAAM,KAAG,IAAI,CAAC,eAAe,EAAE,KAAK,EAAE,cAAc,CAuB1D,CAAC;AAEJ;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB,SAC7B,cAAc,YACd,MAAM,YAAY,QAAQ,CAAC,IAAI,CAAC,KAAG,UAsBzC,CAAC"}
@@ -19,6 +19,8 @@ import { createId } from "./Type.js";
19
19
  * via internal namespacing, so tests can reuse the same lock names without
20
20
  * contending through the global Web Locks. Query results are filtered to that
21
21
  * private namespace and returned with the original visible names.
22
+ *
23
+ * @group Testing
22
24
  */
23
25
  export const testCreateLockManager = (nativeLockManager = navigator.locks) => {
24
26
  const namespace = createId({ randomBytes: createRandomBytes() });
@@ -54,6 +56,8 @@ export const testCreateLockManager = (nativeLockManager = navigator.locks) => {
54
56
  * Leadership is held until the returned handle is disposed. Once released,
55
57
  * another waiting caller may become the next leader. Waiting for leadership is
56
58
  * abortable via the calling {@link Task}'s signal.
59
+ *
60
+ * @group Leader election
57
61
  */
58
62
  export const acquireLeaderLock = (name) => async (run) => {
59
63
  const acquisition = Promise.withResolvers();
@@ -81,6 +85,8 @@ export const acquireLeaderLock = (name) => async (run) => {
81
85
  * Leadership is held until the returned handle is disposed. Once released,
82
86
  * another waiting caller may become the next leader. Waiting for leadership is
83
87
  * abortable by disposing the returned handle.
88
+ *
89
+ * @group Leader election
84
90
  */
85
91
  export const acquireLeaderLockCallback = (deps) => (name, callback) => {
86
92
  const abortController = new AbortController();
@@ -6,7 +6,7 @@
6
6
  import type { NonEmptyReadonlyArray } from "./Array.ts";
7
7
  import type { IsBranded } from "./Brand.ts";
8
8
  import type { Result } from "./Result.ts";
9
- import { Digit1To99, NonNegativeInt, PositiveInt, Ratio } from "./Type.ts";
9
+ import { type Type, type TypeError, type UnionError, Digit1To9, Digit1To99, NonNegativeInt, PositiveInt, Ratio } from "./Type.ts";
10
10
  import type { Predicate, WidenLiteral } from "./Types.ts";
11
11
  /** Integer literal from `1` to `99`. */
12
12
  export type Int1To99 = Digit1To99 extends `${infer Value extends number}` ? Value : never;
@@ -76,14 +76,57 @@ export type Int1To100OrPositiveInt = Int1To100 | PositiveInt;
76
76
  * ```
77
77
  */
78
78
  export type Percentage = PercentageLiteral | Ratio;
79
+ export type PercentageLiteral = "0%" | "100%" | `${Digit1To99}%` | `${"0" | Digit1To99}.${Digit1To9}%`;
79
80
  /**
80
- * Percentage literal from `"0%"` to `"100%"`.
81
+ * Percentage literal Type with compile-time and runtime validation.
81
82
  *
82
- * Decimal literals support one decimal place. Use {@link Ratio} for computed
83
- * values or greater precision.
83
+ * Supported formats:
84
+ *
85
+ * - Integers: `0%`, `50%`, `100%` (0-100)
86
+ * - One decimal place: `0.1%`, `12.5%`, `99.9%` (0.1-99.9)
87
+ *
88
+ * The decimal digit is never zero, so `12.0%` must be written as `"12%"`, and
89
+ * `100%` has no decimal form. For computed values or more precision, use
90
+ * {@link Ratio} directly.
91
+ *
92
+ * See {@link Percentage} for a type that also accepts {@link Ratio}. Use
93
+ * {@link percentageToRatio} to convert.
94
+ *
95
+ * Invalid values produce a {@link PercentageLiteralError}.
96
+ *
97
+ * ### Example
98
+ *
99
+ * ```ts
100
+ * import {
101
+ * assertFalse,
102
+ * assertOk,
103
+ * assertType,
104
+ * PercentageLiteral,
105
+ * } from "@evolu/common";
106
+ *
107
+ * // The TypeScript type accepts valid spellings and rejects the rest.
108
+ * const literal: PercentageLiteral = "12.5%";
109
+ * assertType<
110
+ * Extract<PercentageLiteral, "101%" | "12.0%" | "12.55%">,
111
+ * never
112
+ * >();
113
+ *
114
+ * // The runtime Type validates the same grammar.
115
+ * assertOk(PercentageLiteral.fromUnknown(literal), "12.5%");
116
+ * assertFalse(PercentageLiteral.is("101%"));
117
+ * ```
84
118
  */
85
- export declare const PercentageLiteral: import("./Type.ts").UnionType<readonly [import("./Type.ts").LiteralType<"0%">, import("./Type.ts").LiteralType<"100%">, import("./Type.ts").TemplateLiteralType<readonly [import("./Type.ts").UnionType<readonly [import("./Type.ts").UnionType<readonly [import("./Type.ts").LiteralType<"1">, import("./Type.ts").LiteralType<"2">, import("./Type.ts").LiteralType<"3">, import("./Type.ts").LiteralType<"4">, import("./Type.ts").LiteralType<"5">, import("./Type.ts").LiteralType<"6">, import("./Type.ts").LiteralType<"7">, import("./Type.ts").LiteralType<"8">, import("./Type.ts").LiteralType<"9">]>, import("./Type.ts").TemplateLiteralType<readonly [import("./Type.ts").UnionType<readonly [import("./Type.ts").LiteralType<"1">, import("./Type.ts").LiteralType<"2">, import("./Type.ts").LiteralType<"3">, import("./Type.ts").LiteralType<"4">, import("./Type.ts").LiteralType<"5">, import("./Type.ts").LiteralType<"6">, import("./Type.ts").LiteralType<"7">, import("./Type.ts").LiteralType<"8">, import("./Type.ts").LiteralType<"9">]>, import("./Type.ts").UnionType<readonly [import("./Type.ts").LiteralType<"0">, import("./Type.ts").LiteralType<"1">, import("./Type.ts").LiteralType<"2">, import("./Type.ts").LiteralType<"3">, import("./Type.ts").LiteralType<"4">, import("./Type.ts").LiteralType<"5">, import("./Type.ts").LiteralType<"6">, import("./Type.ts").LiteralType<"7">, import("./Type.ts").LiteralType<"8">, import("./Type.ts").LiteralType<"9">]>]>]>, "%"]>, import("./Type.ts").TemplateLiteralType<readonly [import("./Type.ts").UnionType<readonly [import("./Type.ts").LiteralType<"0">, import("./Type.ts").UnionType<readonly [import("./Type.ts").UnionType<readonly [import("./Type.ts").LiteralType<"1">, import("./Type.ts").LiteralType<"2">, import("./Type.ts").LiteralType<"3">, import("./Type.ts").LiteralType<"4">, import("./Type.ts").LiteralType<"5">, import("./Type.ts").LiteralType<"6">, import("./Type.ts").LiteralType<"7">, import("./Type.ts").LiteralType<"8">, import("./Type.ts").LiteralType<"9">]>, import("./Type.ts").TemplateLiteralType<readonly [import("./Type.ts").UnionType<readonly [import("./Type.ts").LiteralType<"1">, import("./Type.ts").LiteralType<"2">, import("./Type.ts").LiteralType<"3">, import("./Type.ts").LiteralType<"4">, import("./Type.ts").LiteralType<"5">, import("./Type.ts").LiteralType<"6">, import("./Type.ts").LiteralType<"7">, import("./Type.ts").LiteralType<"8">, import("./Type.ts").LiteralType<"9">]>, import("./Type.ts").UnionType<readonly [import("./Type.ts").LiteralType<"0">, import("./Type.ts").LiteralType<"1">, import("./Type.ts").LiteralType<"2">, import("./Type.ts").LiteralType<"3">, import("./Type.ts").LiteralType<"4">, import("./Type.ts").LiteralType<"5">, import("./Type.ts").LiteralType<"6">, import("./Type.ts").LiteralType<"7">, import("./Type.ts").LiteralType<"8">, import("./Type.ts").LiteralType<"9">]>]>]>]>, ".", import("./Type.ts").UnionType<readonly [import("./Type.ts").LiteralType<"1">, import("./Type.ts").LiteralType<"2">, import("./Type.ts").LiteralType<"3">, import("./Type.ts").LiteralType<"4">, import("./Type.ts").LiteralType<"5">, import("./Type.ts").LiteralType<"6">, import("./Type.ts").LiteralType<"7">, import("./Type.ts").LiteralType<"8">, import("./Type.ts").LiteralType<"9">]>, "%"]>]>;
86
- export type PercentageLiteral = typeof PercentageLiteral.Output;
119
+ export declare const PercentageLiteral: Type<"PercentageLiteral", PercentageLiteral, PercentageLiteral, PercentageLiteralError>;
120
+ /** Error returned when {@link PercentageLiteral} rejects a value. */
121
+ export interface PercentageLiteralError extends TypeError<"PercentageLiteral"> {
122
+ readonly value: unknown;
123
+ /**
124
+ * The underlying union failure, retained for diagnostics.
125
+ *
126
+ * With `{ errors: "all" }`, includes every failed alternative.
127
+ */
128
+ readonly cause: UnionError;
129
+ }
87
130
  /** Converts a {@link Percentage} to its numeric {@link Ratio}. */
88
131
  export declare const percentageToRatio: (percentage: Percentage) => Ratio;
89
132
  export declare const increment: (n: number) => number;
@@ -150,7 +193,7 @@ minNumberOfItemsPerBucket?: number & import("./Brand.ts").Brand<"NonNaN"> & impo
150
193
  *
151
194
  * Limited to 78 because F(79) exceeds JavaScript's `MAX_SAFE_INTEGER`.
152
195
  */
153
- export declare const FibonacciIndex: import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").Type<"Number", number, number, import("./Type.ts").TypeOfError<"Number">, null, import("./Type.ts").TypeOfError<"Number">, never, number, true>, "NonNaN", import("./Type.ts").NonNaNError>, "Finite", import("./Type.ts").FiniteError>, "Int", import("./Type.ts").IntError>, "NonNegative", import("./Type.ts").NonNegativeError>, "Positive", import("./Type.ts").PositiveError>, "LessThanOrEqualTo78", import("./Type.ts").LessThanOrEqualToError<78>>, "FibonacciIndex", never>;
196
+ export declare const FibonacciIndex: import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<Type<"Number", number, number, import("./Type.ts").TypeOfError<"Number">, null, import("./Type.ts").TypeOfError<"Number">, never, number, true>, "NonNaN", import("./Type.ts").NonNaNError>, "Finite", import("./Type.ts").FiniteError>, "Int", import("./Type.ts").IntError>, "NonNegative", import("./Type.ts").NonNegativeError>, "Positive", import("./Type.ts").PositiveError>, "LessThanOrEqualTo78", import("./Type.ts").LessThanOrEqualToError<78>>, "FibonacciIndex", never>;
154
197
  export type FibonacciIndex = typeof FibonacciIndex.Output;
155
198
  /** Returns the Fibonacci number at the given index (1-indexed: 1,1,2,3,5,8,...). */
156
199
  export declare const fibonacciAt: (index: FibonacciIndex) => PositiveInt;
@@ -1 +1 @@
1
- {"version":3,"file":"Number.d.ts","sourceRoot":"","sources":["../../src/Number.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAGL,UAAU,EAGV,cAAc,EACd,WAAW,EACX,KAAK,EAGN,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1D,wCAAwC;AACxC,MAAM,MAAM,QAAQ,GAAG,UAAU,SAAS,GAAG,MAAM,KAAK,SAAS,MAAM,EAAE,GACrE,KAAK,GACL,KAAK,CAAC;AAEV,yCAAyC;AACzC,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,GAAG,CAAC;AAEvC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,GAAG,SAAS,GAAG,cAAc,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,WAAW,CAAC;AAE7D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,UAAU,GAAG,iBAAiB,GAAG,KAAK,CAAC;AAEnD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,ysGAU7B,CAAC;AACF,MAAM,MAAM,iBAAiB,GAAG,OAAO,iBAAiB,CAAC,MAAM,CAAC;AAEhE,kEAAkE;AAClE,eAAO,MAAM,iBAAiB,eAAgB,UAAU,KAAG,KAGH,CAAC;AAEzD,eAAO,MAAM,SAAS,MAAO,MAAM,KAAG,MAAe,CAAC;AAEtD,eAAO,MAAM,SAAS,MAAO,MAAM,KAAG,MAAe,CAAC;AAEtD,4CAA4C;AAC5C,eAAO,MAAM,KAAK,QACV,MAAM,OAAO,MAAM,SACrB,MAAM,KAAG,MACoB,CAAC;AAEpC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS,QACd,MAAM,OAAO,MAAM,KAAG,SAAS,CAAC,MAAM,CAEd,CAAC;AAEjC,wEAAwE;AACxE,eAAO,MAAM,GAAG,GAAI,CAAC,SAAS,MAAM,aACvB,CAAC,CAAC,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,KAClC,SAAS,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC,CACE,CAAC;AAEpD,wEAAwE;AACxE,eAAO,MAAM,GAAG,GAAI,CAAC,SAAS,MAAM,aACvB,CAAC,CAAC,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,KAClC,SAAS,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC,CACE,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,sBAAsB,kBAClB,cAAc;AAE7B,kBAAkB;;AAGlB,iBAAiB;8OAEhB,MAAM,CAAC,qBAAqB,CAAC,WAAW,CAAC,EAAE,WAAW,CAoBxD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,cAAc,6rBAG1B,CAAC;AACF,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,MAAM,CAAC;AAE1D,oFAAoF;AACpF,eAAO,MAAM,WAAW,UAAW,cAAc,KAAG,WAMnD,CAAC"}
1
+ {"version":3,"file":"Number.d.ts","sourceRoot":"","sources":["../../src/Number.ts"],"names":[],"mappings":"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"}
@@ -4,18 +4,57 @@
4
4
  * @module
5
5
  */
6
6
  import { assertNonEmptyReadonlyArray } from "./Assert.js";
7
+ import { safelyStringifyUnknownValue } from "./String.js";
7
8
  import { err, ok } from "./Result.js";
8
- import { brand, Digit1To9, Digit1To99, lessThanOrEqualTo, onePositiveInt, NonNegativeInt, PositiveInt, Ratio, templateLiteral, union, } from "./Type.js";
9
- /**
10
- * Percentage literal from `"0%"` to `"100%"`.
11
- *
12
- * Decimal literals support one decimal place. Use {@link Ratio} for computed
13
- * values or greater precision.
14
- */
15
- export const PercentageLiteral = /*#__PURE__*/ union("0%", "100%",
9
+ import { brand, createTypeWithError, Digit1To9, Digit1To99, lessThanOrEqualTo, onePositiveInt, NonNegativeInt, PositiveInt, Ratio, templateLiteral, union, } from "./Type.js";
10
+ const percentageLiteralSyntax = /*#__PURE__*/ union("0%", "100%",
16
11
  /*#__PURE__*/ templateLiteral(Digit1To99, "%"),
17
12
  /*#__PURE__*/ templateLiteral(
18
13
  /*#__PURE__*/ union("0", Digit1To99), ".", Digit1To9, "%"));
14
+ /**
15
+ * Percentage literal Type with compile-time and runtime validation.
16
+ *
17
+ * Supported formats:
18
+ *
19
+ * - Integers: `0%`, `50%`, `100%` (0-100)
20
+ * - One decimal place: `0.1%`, `12.5%`, `99.9%` (0.1-99.9)
21
+ *
22
+ * The decimal digit is never zero, so `12.0%` must be written as `"12%"`, and
23
+ * `100%` has no decimal form. For computed values or more precision, use
24
+ * {@link Ratio} directly.
25
+ *
26
+ * See {@link Percentage} for a type that also accepts {@link Ratio}. Use
27
+ * {@link percentageToRatio} to convert.
28
+ *
29
+ * Invalid values produce a {@link PercentageLiteralError}.
30
+ *
31
+ * ### Example
32
+ *
33
+ * ```ts
34
+ * import {
35
+ * assertFalse,
36
+ * assertOk,
37
+ * assertType,
38
+ * PercentageLiteral,
39
+ * } from "@evolu/common";
40
+ *
41
+ * // The TypeScript type accepts valid spellings and rejects the rest.
42
+ * const literal: PercentageLiteral = "12.5%";
43
+ * assertType<
44
+ * Extract<PercentageLiteral, "101%" | "12.0%" | "12.55%">,
45
+ * never
46
+ * >();
47
+ *
48
+ * // The runtime Type validates the same grammar.
49
+ * assertOk(PercentageLiteral.fromUnknown(literal), "12.5%");
50
+ * assertFalse(PercentageLiteral.is("101%"));
51
+ * ```
52
+ */
53
+ export const PercentageLiteral = /*#__PURE__*/ createTypeWithError("PercentageLiteral", percentageLiteralSyntax, (cause, value) => ({
54
+ type: "PercentageLiteral",
55
+ value,
56
+ cause,
57
+ }), (error) => `The value ${safelyStringifyUnknownValue(error.value)} is not a percentage literal. Use a value such as "50%" or "12.5%".`);
19
58
  /** Converts a {@link Percentage} to its numeric {@link Ratio}. */
20
59
  export const percentageToRatio = (percentage) => typeof percentage === "number"
21
60
  ? percentage
@@ -175,6 +175,38 @@ export declare const objectFrom: <K extends string, V>(keys: ReadonlyArray<K>, g
175
175
  * Uses `K extends string` for precision.
176
176
  */
177
177
  export declare const mapObject: <K extends string, V, U>(record: ReadonlyRecord<K, V>, fn: (value: V, key: K) => U) => ReadonlyRecord<K, U>;
178
+ /**
179
+ * Selects own string-keyed properties while preserving their descriptors.
180
+ *
181
+ * Visits enumerable and non-enumerable properties, ignoring inherited and
182
+ * symbol properties. The predicate receives only the key; property values and
183
+ * getters are never read. The result is a new ordinary object with matching
184
+ * descriptors, including accessor functions and property flags. Declared
185
+ * properties are optional because the predicate may exclude any of them.
186
+ * Numeric property names are visited as strings.
187
+ *
188
+ * ### Example
189
+ *
190
+ * ```ts
191
+ * import {
192
+ * assertEqual,
193
+ * assertType,
194
+ * filterObjectKeys,
195
+ * } from "@evolu/common";
196
+ *
197
+ * const source = { APP_PORT: "4000", HOME: "/home/evolu" };
198
+ * const selected = filterObjectKeys(source, (key) =>
199
+ * key.startsWith("APP_"),
200
+ * );
201
+ *
202
+ * assertEqual(selected, { APP_PORT: "4000" });
203
+ * assertType<
204
+ * typeof selected,
205
+ * { readonly APP_PORT?: string; readonly HOME?: string }
206
+ * >();
207
+ * ```
208
+ */
209
+ export declare const filterObjectKeys: <T extends object>(source: T, predicate: (key: string) => boolean) => Readonly<Partial<Pick<T, Exclude<keyof T, symbol>>>>;
178
210
  /** Conditionally excludes a property from an object. */
179
211
  export declare const excludeProp: <T extends object, K extends keyof T>(obj: T, prop: K, condition?: boolean) => typeof condition extends true ? T : Omit<T, K>;
180
212
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"Object.d.ts","sourceRoot":"","sources":["../../src/Object.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Object.d.ts","sourceRoot":"","sources":["../../src/Object.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,MAAM,GAAG,EAAE,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAE5E,oEAAoE;AACpE,MAAM,MAAM,UAAU,GACpB,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,KAAK,GAAG,YAAY,GAAG,aAAa,CAAC;AAE7E;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,aAAa,UAAW,MAAM,KAAG,UAgB7C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,aAAa,UACjB,OAAO,KACb,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAiBjC,CAAC;AAEF;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,UAAU,UAAW,OAAO,KAAG,KAAK,IAAI,UAAU,CAAC,QACnC,CAAC;AAE9B;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,UAAW,OAAO,KAAG,KAAK,IAAI,QAAQ,CAAC,OAAO,CAEA,CAAC;AAEtE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,UACnD,CAAC,KACR,aAAa,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CACkB,CAAC;AAGvE,KAAK,WAAW,CAAC,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,WAC1C,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KACjC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAwD,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,QACtC,aAAa,CAAC,CAAC,CAAC,YACZ,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,KACtB,cAAc,CAAC,CAAC,EAAE,CAAC,CACyD,CAAC;AAEhF;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,UACtC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,MACxB,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAC1B,cAAc,CAAC,CAAC,EAAE,CAAC,CAQrB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,SAAS,MAAM,UACvC,CAAC,aACE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAClC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAQrD,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,CAAC,OACxD,CAAC,QACA,CAAC,cACK,OAAO,KAClB,OAAO,SAAS,SAAS,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAM/C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqFG;AACH,wBAAgB,mBAAmB,CACjC,CAAC,SAAS,MAAM,GAAG,MAAM,EACzB,CAAC,GAAG,OAAO,KACR,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAElB,0DAA0D;AAC1D,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,EAClD,MAAM,EAAE,CAAC,GACR;IAAE,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC;AAMtC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAGrD,CAAC;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,UACpC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,OACvB,OAAO,CAAC,CAAC,CAAC,KACd,CAAC,GAAG,SAAmE,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,SAAU,SAAQ,UAAU;IAC3C,8DAA8D;IAC9D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,iEAAiE;AACjE,eAAO,MAAM,eAAe,SAAU,IAAI,KAAG,SAQ5C,CAAC"}
@@ -74,6 +74,11 @@ export const isPlainObject = (value) => {
74
74
  const prototype = Object.getPrototypeOf(value);
75
75
  if (prototype === null)
76
76
  return true;
77
+ // This realm's Object.prototype has an immutable null prototype, so `in`
78
+ // checks the same own properties as the structural test below, faster.
79
+ if (prototype === Object.prototype) {
80
+ return "hasOwnProperty" in prototype && "isPrototypeOf" in prototype;
81
+ }
77
82
  return (Object.getPrototypeOf(prototype) === null &&
78
83
  Object.hasOwn(prototype, "hasOwnProperty") &&
79
84
  Object.hasOwn(prototype, "isPrototypeOf"));
@@ -202,6 +207,47 @@ export const mapObject = (record, fn) => {
202
207
  }
203
208
  return out;
204
209
  };
210
+ /**
211
+ * Selects own string-keyed properties while preserving their descriptors.
212
+ *
213
+ * Visits enumerable and non-enumerable properties, ignoring inherited and
214
+ * symbol properties. The predicate receives only the key; property values and
215
+ * getters are never read. The result is a new ordinary object with matching
216
+ * descriptors, including accessor functions and property flags. Declared
217
+ * properties are optional because the predicate may exclude any of them.
218
+ * Numeric property names are visited as strings.
219
+ *
220
+ * ### Example
221
+ *
222
+ * ```ts
223
+ * import {
224
+ * assertEqual,
225
+ * assertType,
226
+ * filterObjectKeys,
227
+ * } from "@evolu/common";
228
+ *
229
+ * const source = { APP_PORT: "4000", HOME: "/home/evolu" };
230
+ * const selected = filterObjectKeys(source, (key) =>
231
+ * key.startsWith("APP_"),
232
+ * );
233
+ *
234
+ * assertEqual(selected, { APP_PORT: "4000" });
235
+ * assertType<
236
+ * typeof selected,
237
+ * { readonly APP_PORT?: string; readonly HOME?: string }
238
+ * >();
239
+ * ```
240
+ */
241
+ export const filterObjectKeys = (source, predicate) => {
242
+ const selected = {};
243
+ for (const key of Object.getOwnPropertyNames(source)) {
244
+ if (!predicate(key))
245
+ continue;
246
+ const descriptor = Object.getOwnPropertyDescriptor(source, key);
247
+ Object.defineProperty(selected, key, descriptor);
248
+ }
249
+ return selected;
250
+ };
205
251
  /** Conditionally excludes a property from an object. */
206
252
  export const excludeProp = (obj, prop, condition) => {
207
253
  if (condition) {