@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
@@ -5,29 +5,47 @@
5
5
  */
6
6
  import { type NonEmptyReadonlyArray } from "../Array.ts";
7
7
  import type { ConsoleDep } from "../Console.ts";
8
+ import type { DecryptWithXChaCha20Poly1305Error } from "../Crypto.ts";
9
+ import type { UnknownError } from "../Error.ts";
8
10
  import { type LockManagerDep } from "../LockManager.ts";
9
11
  import type { FlushSyncDep, ReloadAppDep } from "../Platform.ts";
10
12
  import type { Listener, ReadonlyStore, Unsubscribe } from "../Store.ts";
11
13
  import type { Task } from "../Task.ts";
12
14
  import { Name, type TypeError, UrlSafeString } from "../Type.ts";
13
15
  import type { CreateBroadcastChannelDep, CreateMessageChannelDep } from "../Worker.ts";
14
- import type { CreateDbWorkerDep } from "./Db.ts";
15
- import type { EvoluError } from "./Error.ts";
16
- import type { AppOwner, Owner, OwnerTransport, ReadonlyOwner } from "./Owner.ts";
16
+ import type { CreateDbWorkerDep, UnsupportedDbVersionError } from "./Db.ts";
17
+ import type { AppOwner, Owner, OwnerId, OwnerTransport, ReadonlyOwner } from "./Owner.ts";
18
+ import type { ProtocolError } from "./Protocol.ts";
17
19
  import type { Queries, QueriesToQueryRowsPromises, Query, QueryRows, Row } from "./Query.ts";
18
20
  import type { EvoluSchema, IndexesConfig, Mutation, ValidateSchema } from "./Schema.ts";
19
- import type { SharedWorkerDep } from "./Shared.ts";
21
+ import type { OtherBuildRunningError, SharedWorkerDep, SyncState } from "./Shared.ts";
22
+ import { type StorageQuotaError } from "./Storage.ts";
23
+ /**
24
+ * Configuration for {@link createEvolu}.
25
+ *
26
+ * @group Configuration
27
+ */
20
28
  export interface EvoluConfig {
21
29
  /**
22
- * The app name. Evolu is multitenant - it can run multiple instances
23
- * concurrently. The same app can have multiple instances for different
24
- * accounts.
30
+ * An application name used in logs and local database names.
31
+ *
32
+ * Evolu combines `appName` with the {@link AppOwner} identity to identify the
33
+ * local database. Changing either opens a different database. Keep `appName`
34
+ * stable across ordinary application updates.
25
35
  *
26
- * Evolu derives the final instance name from `appName` and `appOwner` in
27
- * {@link EvoluConfig}. The derived instance name is used as the SQLite
28
- * database filename and as the log prefix. This ensures that each
29
- * {@link Owner} gets a separate local database while preserving a readable app
30
- * prefix.
36
+ * Instances that share an `appName` and AppOwner open the same database and
37
+ * must use the same schema. Evolu applies the schema of the first instance
38
+ * and later instances join it.
39
+ *
40
+ * A different app name lets you create a separate local replica for the same
41
+ * AppOwner—for example, to test a different SQLite implementation or index
42
+ * configuration, or rebuild a replica for debugging while preserving the
43
+ * existing database.
44
+ *
45
+ * Evolu supports running these databases concurrently. Their local separation
46
+ * does not isolate synchronization: replicas synchronizing the same owners
47
+ * through the same relay can still exchange changes. Changing `appName`
48
+ * neither migrates existing local data nor isolates incompatible schemas.
31
49
  *
32
50
  * ### Example
33
51
  *
@@ -61,6 +79,69 @@ export interface EvoluConfig {
61
79
  * flow).
62
80
  */
63
81
  readonly appOwner: AppOwner;
82
+ /**
83
+ * Keep the database in memory instead of persisting it on this device.
84
+ *
85
+ * This option controls device persistence independently of synchronization.
86
+ * When synchronization is enabled, data can still be synchronized and
87
+ * persisted remotely.
88
+ *
89
+ * Useful for testing or temporary sessions. Data that exists only in this
90
+ * database is lost when the database closes.
91
+ *
92
+ * The default value is: `false`.
93
+ */
94
+ readonly memoryOnly?: boolean;
95
+ /**
96
+ * Use the `indexes` option to define SQLite indexes.
97
+ *
98
+ * Table and column names are not typed because Kysely doesn't support it.
99
+ *
100
+ * https://medium.com/@JasonWyatt/squeezing-performance-from-sqlite-indexes-indexes-c4e175f3c346
101
+ *
102
+ * ### Example
103
+ *
104
+ * ```ts
105
+ * import {
106
+ * createEvolu,
107
+ * id,
108
+ * testAppName,
109
+ * testAppOwner,
110
+ * } from "@evolu/common";
111
+ *
112
+ * const Schema = {
113
+ * todo: { id: id("Todo") },
114
+ * todoCategory: { id: id("TodoCategory") },
115
+ * };
116
+ *
117
+ * const _createTodoEvolu = createEvolu(Schema, {
118
+ * appName: testAppName,
119
+ * appOwner: testAppOwner,
120
+ * transports: [],
121
+ * indexes: (create) => [
122
+ * create("todoCreatedAt").on("todo").column("createdAt"),
123
+ * create("todoCategoryCreatedAt")
124
+ * .on("todoCategory")
125
+ * .column("createdAt"),
126
+ * ],
127
+ * });
128
+ * ```
129
+ */
130
+ readonly indexes?: IndexesConfig;
131
+ /**
132
+ * Called when this instance's local database is deleted.
133
+ *
134
+ * Apps can use this to update UI immediately because the corresponding
135
+ * {@link Evolu} instance becomes unusable after local database deletion.
136
+ */
137
+ readonly onDatabaseDeleted?: () => void;
138
+ /**
139
+ * Called when local data for an {@link Owner} is deleted.
140
+ *
141
+ * Apps can use this to update UI immediately because that owner stops being
142
+ * used across tabs and instances.
143
+ */
144
+ readonly onOwnerDeleted?: (owner: Owner) => void;
64
145
  /**
65
146
  * Transport configuration for sync and backup.
66
147
  *
@@ -98,18 +179,11 @@ export interface EvoluConfig {
98
179
  * ```ts
99
180
  * import {
100
181
  * assertEqual,
101
- * createAppOwner,
102
182
  * createOwnerWebSocketTransport,
103
- * createOwnerSecret,
104
- * createRandomBytes,
183
+ * testAppOwner,
105
184
  * type OwnerTransport,
106
185
  * } from "@evolu/common";
107
186
  *
108
- * // Create once, persist the mnemonic securely, and restore it on later runs.
109
- * const appOwner = createAppOwner(
110
- * createOwnerSecret({ randomBytes: createRandomBytes() }),
111
- * );
112
- *
113
187
  * // Use one relay.
114
188
  * const _singleRelay = [
115
189
  * { type: "WebSocket", url: "wss://relay1.example.com" },
@@ -130,87 +204,17 @@ export interface EvoluConfig {
130
204
  * const authenticatedRelay = [
131
205
  * createOwnerWebSocketTransport({
132
206
  * url: "wss://relay.example.com",
133
- * ownerId: appOwner.id,
207
+ * ownerId: testAppOwner.id,
134
208
  * }),
135
209
  * ];
136
210
  *
137
211
  * assertEqual(
138
212
  * authenticatedRelay[0]?.url,
139
- * `wss://relay.example.com?ownerId=${appOwner.id}`,
213
+ * `wss://relay.example.com?ownerId=${testAppOwner.id}`,
140
214
  * );
141
215
  * ```
142
216
  */
143
217
  readonly transports?: ReadonlyArray<OwnerTransport>;
144
- /**
145
- * Keep local data only in memory instead of persisting it on this device.
146
- * Useful for testing, temporary data, or sensitive data that should not be
147
- * recoverable from local storage after the process ends.
148
- *
149
- * Local data stored in memory is completely destroyed when the process ends.
150
- * Sync can still persist data remotely when transports are enabled.
151
- *
152
- * The default value is: `false`.
153
- */
154
- readonly memoryOnly?: boolean;
155
- /**
156
- * Use the `indexes` option to define SQLite indexes.
157
- *
158
- * Table and column names are not typed because Kysely doesn't support it.
159
- *
160
- * https://medium.com/@JasonWyatt/squeezing-performance-from-sqlite-indexes-indexes-c4e175f3c346
161
- *
162
- * ### Example
163
- *
164
- * ```ts
165
- * import {
166
- * AppName,
167
- * assertTrue,
168
- * createAppOwner,
169
- * createEvolu,
170
- * createOwnerSecret,
171
- * createRandomBytes,
172
- * id,
173
- * } from "@evolu/common";
174
- *
175
- * const Schema = {
176
- * todo: { id: id("Todo") },
177
- * todoCategory: { id: id("TodoCategory") },
178
- * };
179
- * // Create once, persist the mnemonic securely, and restore it on later runs.
180
- * const appOwner = createAppOwner(
181
- * createOwnerSecret({ randomBytes: createRandomBytes() }),
182
- * );
183
- *
184
- * const createTodoEvolu = createEvolu(Schema, {
185
- * appName: AppName.orThrow("IndexedTodos"),
186
- * appOwner,
187
- * transports: [],
188
- * indexes: (create) => [
189
- * create("todoCreatedAt").on("todo").column("createdAt"),
190
- * create("todoCategoryCreatedAt")
191
- * .on("todoCategory")
192
- * .column("createdAt"),
193
- * ],
194
- * });
195
- *
196
- * assertTrue(typeof createTodoEvolu === "function");
197
- * ```
198
- */
199
- readonly indexes?: IndexesConfig;
200
- /**
201
- * Called when this instance's local database is deleted.
202
- *
203
- * Apps can use this to update UI immediately because the corresponding
204
- * {@link Evolu} instance becomes unusable after local database deletion.
205
- */
206
- readonly onDatabaseDeleted?: () => void;
207
- /**
208
- * Called when local data for an {@link Owner} is deleted.
209
- *
210
- * Apps can use this to update UI immediately because that owner stops being
211
- * used across tabs and instances.
212
- */
213
- readonly onOwnerDeleted?: (owner: Owner) => void;
214
218
  }
215
219
  /**
216
220
  * Application name.
@@ -221,17 +225,38 @@ export interface EvoluConfig {
221
225
  *
222
226
  * Uses the same safe alphabet as {@link UrlSafeString} (letters, digits, `-`,
223
227
  * `_`) and must be between 1 and 41 characters.
228
+ *
229
+ * @group Configuration
224
230
  */
225
231
  export declare const AppName: import("../Type.ts").BrandType<import("../Type.ts").BrandType<import("../Type.ts").Type<"String", string, string, import("../Type.ts").TypeOfError<"String">, null, import("../Type.ts").TypeOfError<"String">, never, string, true>, "UrlSafeString", import("../Type.ts").RegexError<"UrlSafeString">>, "AppName", AppNameError>;
226
232
  export type AppName = typeof AppName.Output;
233
+ /**
234
+ * Error produced when a value is not a valid {@link AppName}.
235
+ *
236
+ * @group Configuration
237
+ */
227
238
  export interface AppNameError extends TypeError<"AppName"> {
228
239
  readonly value: UrlSafeString;
229
240
  }
241
+ /**
242
+ * Stable valid {@link AppName} for tests and examples.
243
+ *
244
+ * @group Testing
245
+ */
230
246
  export declare const testAppName: string & import("../Brand.ts").Brand<"UrlSafeString"> & import("../Brand.ts").Brand<"AppName">;
231
247
  /**
232
- * Local-first SQL database with typed queries, mutations, and sync.
248
+ * A local-first SQL database.
249
+ *
250
+ * Stores application data in SQLite on the device, so reads and writes work
251
+ * offline. Provides typed queries, mutations, and reactive subscriptions, with
252
+ * synchronization between devices. Persistent SQLite is encrypted with the
253
+ * {@link AppOwner} key, and synchronized data is end-to-end encrypted.
233
254
  *
234
- * TODO: Better docs.
255
+ * Tables whose names start with `_` stay local, even when the instance
256
+ * synchronizes other data. Use them for device-local data such as application
257
+ * settings or an app-owner registry.
258
+ *
259
+ * @group Core
235
260
  */
236
261
  export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposable {
237
262
  /**
@@ -249,32 +274,29 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
249
274
  * every row has a globally unique, conflict-free identifier without
250
275
  * coordination.
251
276
  *
252
- * Pass `onComplete` when follow-up work must wait until the mutation and its
253
- * query patches have been applied.
277
+ * Pass `onComplete` when follow-up work must wait until the mutation is
278
+ * stored and subscribed queries reflect it. It never runs when the database
279
+ * is unavailable; see {@link Evolu.loadQuery}. A stored change is not always
280
+ * visible; see {@link MutationOptions.onComplete}.
254
281
  *
255
282
  * ### Example
256
283
  *
257
284
  * ```ts
258
285
  * import {
259
286
  * assertType,
260
- * id,
287
+ * type TestEvoluSchema,
261
288
  * NonEmptyTrimmedString100,
262
289
  * type Evolu,
290
+ * type TestTodoId,
263
291
  * } from "@evolu/common";
264
292
  *
265
- * const TodoId = id("Todo");
266
- * type TodoId = typeof TodoId.Output;
267
- * const Schema = {
268
- * todo: { id: TodoId, title: NonEmptyTrimmedString100 },
269
- * };
270
- *
271
- * const insertTodo = (evolu: Evolu<typeof Schema>) =>
293
+ * const insertTodo = (evolu: Evolu<TestEvoluSchema>) =>
272
294
  * evolu.insert("todo", {
273
295
  * title: NonEmptyTrimmedString100.orThrow("Learn Evolu"),
274
296
  * }).id;
275
297
  *
276
298
  * const insertTodoAndNotify = (
277
- * evolu: Evolu<typeof Schema>,
299
+ * evolu: Evolu<TestEvoluSchema>,
278
300
  * onComplete: () => void,
279
301
  * ) =>
280
302
  * evolu.insert(
@@ -288,7 +310,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
288
310
  * ReturnType<typeof insertTodo>,
289
311
  * ReturnType<typeof insertTodoAndNotify>,
290
312
  * ],
291
- * [TodoId, TodoId]
313
+ * [TestTodoId, TestTodoId]
292
314
  * >();
293
315
  * ```
294
316
  *
@@ -305,30 +327,30 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
305
327
  * ```ts
306
328
  * import {
307
329
  * assertType,
308
- * id,
330
+ * type TestEvoluSchema,
309
331
  * NonEmptyTrimmedString100,
310
332
  * sqliteTrue,
311
333
  * type Evolu,
334
+ * type TestTodoId,
312
335
  * } from "@evolu/common";
313
336
  *
314
- * const TodoId = id("Todo");
315
- * type TodoId = typeof TodoId.Output;
316
- * const Schema = {
317
- * todo: { id: TodoId, title: NonEmptyTrimmedString100 },
318
- * };
319
- *
320
- * const renameTodo = (evolu: Evolu<typeof Schema>, todoId: TodoId) =>
337
+ * const renameTodo = (
338
+ * evolu: Evolu<TestEvoluSchema>,
339
+ * todoId: TestTodoId,
340
+ * ) =>
321
341
  * evolu.update("todo", {
322
342
  * id: todoId,
323
343
  * title: NonEmptyTrimmedString100.orThrow("Updated title"),
324
344
  * }).id;
325
345
  *
326
- * const softDeleteTodo = (evolu: Evolu<typeof Schema>, todoId: TodoId) =>
327
- * evolu.update("todo", { id: todoId, isDeleted: sqliteTrue }).id;
346
+ * const softDeleteTodo = (
347
+ * evolu: Evolu<TestEvoluSchema>,
348
+ * todoId: TestTodoId,
349
+ * ) => evolu.update("todo", { id: todoId, isDeleted: sqliteTrue }).id;
328
350
  *
329
351
  * assertType<
330
352
  * [ReturnType<typeof renameTodo>, ReturnType<typeof softDeleteTodo>],
331
- * [TodoId, TodoId]
353
+ * [TestTodoId, TestTodoId]
332
354
  * >();
333
355
  * ```
334
356
  *
@@ -353,24 +375,20 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
353
375
  * import {
354
376
  * assertType,
355
377
  * createIdFromString,
356
- * id,
378
+ * type TestEvoluSchema,
357
379
  * NonEmptyTrimmedString100,
358
380
  * type Evolu,
381
+ * TestTodoId,
359
382
  * } from "@evolu/common";
360
383
  *
361
- * const TodoId = id("Todo");
362
- * type TodoId = typeof TodoId.Output;
363
- * const Schema = {
364
- * todo: { id: TodoId, title: NonEmptyTrimmedString100 },
365
- * };
366
- * const stableId = TodoId.orThrow(createIdFromString("my-todo-1"));
367
- * const upsertTodo = (evolu: Evolu<typeof Schema>) =>
384
+ * const stableId = TestTodoId.orThrow(createIdFromString("my-todo-1"));
385
+ * const upsertTodo = (evolu: Evolu<TestEvoluSchema>) =>
368
386
  * evolu.upsert("todo", {
369
387
  * id: stableId,
370
388
  * title: NonEmptyTrimmedString100.orThrow("Learn Evolu"),
371
389
  * }).id;
372
390
  *
373
- * assertType<ReturnType<typeof upsertTodo>, TodoId>();
391
+ * assertType<ReturnType<typeof upsertTodo>, TestTodoId>();
374
392
  * ```
375
393
  *
376
394
  * @see {@link Mutation}
@@ -379,14 +397,19 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
379
397
  /**
380
398
  * Load {@link Query} and return a promise with {@link QueryRows}.
381
399
  *
382
- * The returned promise always resolves successfully because there is no
383
- * reason why loading should fail. All data are local, and the query is
384
- * typed.
400
+ * The returned promise always resolves successfully because all data are
401
+ * local and the query is typed. If the database refuses startup, unanswered
402
+ * loads stay pending until disposal resolves them with empty rows. Observe
403
+ * {@link EvoluErrorDep.evoluError} to display the refusal independently of
404
+ * query loading.
385
405
  *
386
406
  * Loading is batched. Returned promises are cached while pending and can be
387
- * reused after fulfillment until mutation-driven invalidation, which prevents
388
- * redundant database queries and supports React Suspense (stable references
389
- * while pending).
407
+ * reused after fulfillment, which prevents redundant database queries and
408
+ * supports React Suspense (stable references while pending). A mutation or
409
+ * incoming sync invalidates the cache of an unsubscribed query, so its next
410
+ * load reads again. A subscribed query keeps its cached rows and the
411
+ * subscription refreshes them, so a load can return rows that a pending
412
+ * refresh is about to replace.
390
413
  *
391
414
  * To subscribe a query for automatic updates, use
392
415
  * {@link Evolu.subscribeQuery}.
@@ -397,20 +420,17 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
397
420
  * import {
398
421
  * assertType,
399
422
  * createQueryBuilder,
400
- * id,
401
- * NonEmptyTrimmedString100,
423
+ * testEvoluSchema,
424
+ * type TestEvoluSchema,
402
425
  * type Evolu,
403
426
  * type QueryRows,
404
427
  * } from "@evolu/common";
405
428
  *
406
- * const Schema = {
407
- * todo: { id: id("Todo"), title: NonEmptyTrimmedString100 },
408
- * };
409
- * const createQuery = createQueryBuilder(Schema);
429
+ * const createQuery = createQueryBuilder(testEvoluSchema);
410
430
  * const allTodos = createQuery((db) =>
411
431
  * db.selectFrom("todo").selectAll(),
412
432
  * );
413
- * const loadTodos = async (evolu: Evolu<typeof Schema>) => {
433
+ * const loadTodos = async (evolu: Evolu<TestEvoluSchema>) => {
414
434
  * const rows = await evolu.loadQuery(allTodos);
415
435
  * return rows;
416
436
  * };
@@ -432,31 +452,22 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
432
452
  * ```ts
433
453
  * import {
434
454
  * assertType,
435
- * createIdFromString,
436
455
  * createQueryBuilder,
437
- * id,
438
- * NonEmptyTrimmedString100,
456
+ * testEvoluSchema,
457
+ * type TestEvoluSchema,
458
+ * testTodoId,
439
459
  * type Evolu,
440
460
  * type QueryRows,
441
461
  * } from "@evolu/common";
442
462
  *
443
- * const TodoId = id("Todo");
444
- * type TodoId = typeof TodoId.Output;
445
- * const Schema = {
446
- * todo: { id: TodoId, title: NonEmptyTrimmedString100 },
447
- * };
448
- * const createQuery = createQueryBuilder(Schema);
463
+ * const createQuery = createQueryBuilder(testEvoluSchema);
449
464
  * const allTodos = createQuery((db) =>
450
465
  * db.selectFrom("todo").select(["id", "title"]),
451
466
  * );
452
- * const todoById = (todoId: TodoId) =>
453
- * createQuery((db) =>
454
- * db.selectFrom("todo").select("title").where("id", "=", todoId),
455
- * );
456
- * const firstTodo = todoById(
457
- * TodoId.orThrow(createIdFromString("first-todo")),
467
+ * const firstTodo = createQuery((db) =>
468
+ * db.selectFrom("todo").select("title").where("id", "=", testTodoId),
458
469
  * );
459
- * const loadTodoQueries = (evolu: Evolu<typeof Schema>) =>
470
+ * const loadTodoQueries = (evolu: Evolu<TestEvoluSchema>) =>
460
471
  * evolu.loadQueries([allTodos, firstTodo]);
461
472
  *
462
473
  * assertType<
@@ -472,28 +483,28 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
472
483
  /**
473
484
  * Subscribe to {@link Query} {@link QueryRows} changes.
474
485
  *
486
+ * Cached rows invalidated before subscription are refreshed. Subscribing
487
+ * alone does not load a query that has no cached rows.
488
+ *
475
489
  * ### Example
476
490
  *
477
491
  * ```ts
478
492
  * import {
479
493
  * assertType,
480
494
  * createQueryBuilder,
481
- * id,
482
- * NonEmptyTrimmedString100,
495
+ * testEvoluSchema,
496
+ * type TestEvoluSchema,
483
497
  * type Evolu,
484
498
  * type QueryRows,
485
499
  * type Unsubscribe,
486
500
  * } from "@evolu/common";
487
501
  *
488
- * const Schema = {
489
- * todo: { id: id("Todo"), title: NonEmptyTrimmedString100 },
490
- * };
491
- * const createQuery = createQueryBuilder(Schema);
502
+ * const createQuery = createQueryBuilder(testEvoluSchema);
492
503
  * const allTodos = createQuery((db) =>
493
504
  * db.selectFrom("todo").select("title"),
494
505
  * );
495
506
  * const subscribeToTodos = (
496
- * evolu: Evolu<typeof Schema>,
507
+ * evolu: Evolu<TestEvoluSchema>,
497
508
  * onRows: (rows: QueryRows<typeof allTodos.Row>) => void,
498
509
  * ) =>
499
510
  * evolu.subscribeQuery(allTodos)(() => {
@@ -513,20 +524,17 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
513
524
  * import {
514
525
  * assertType,
515
526
  * createQueryBuilder,
516
- * id,
517
- * NonEmptyTrimmedString100,
527
+ * testEvoluSchema,
528
+ * type TestEvoluSchema,
518
529
  * type Evolu,
519
530
  * type QueryRows,
520
531
  * } from "@evolu/common";
521
532
  *
522
- * const Schema = {
523
- * todo: { id: id("Todo"), title: NonEmptyTrimmedString100 },
524
- * };
525
- * const createQuery = createQueryBuilder(Schema);
533
+ * const createQuery = createQueryBuilder(testEvoluSchema);
526
534
  * const allTodos = createQuery((db) =>
527
535
  * db.selectFrom("todo").select("title"),
528
536
  * );
529
- * const getTodos = (evolu: Evolu<typeof Schema>) =>
537
+ * const getTodos = (evolu: Evolu<TestEvoluSchema>) =>
530
538
  * evolu.getQueryRows(allTodos);
531
539
  *
532
540
  * assertType<
@@ -543,7 +551,8 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
543
551
  * of starting parallel exports.
544
552
  *
545
553
  * The pending promise rejects if this {@link Evolu} instance is disposed
546
- * before export completion.
554
+ * before export completion. If the database refuses startup, export stays
555
+ * pending until disposal; see {@link Evolu.loadQuery}.
547
556
  */
548
557
  readonly exportDatabase: () => Promise<Uint8Array<ArrayBuffer>>;
549
558
  /**
@@ -594,21 +603,15 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
594
603
  * ```ts
595
604
  * import {
596
605
  * assertEqual,
597
- * createAppOwner,
598
606
  * createOwnerWebSocketTransport,
599
- * createOwnerSecret,
600
- * createRandomBytes,
601
607
  * deriveShardOwner,
608
+ * testAppOwner,
602
609
  * type Evolu,
603
610
  * type ReadonlyOwner,
604
611
  * type UnuseOwner,
605
612
  * } from "@evolu/common";
606
613
  *
607
- * // Create once, persist the mnemonic securely, and restore it on later runs.
608
- * const appOwner = createAppOwner(
609
- * createOwnerSecret({ randomBytes: createRandomBytes() }),
610
- * );
611
- * const shardOwner = deriveShardOwner(appOwner, ["todos", 1]);
614
+ * const shardOwner = deriveShardOwner(testAppOwner, ["todos", 1]);
612
615
  * const shardTransport = createOwnerWebSocketTransport({
613
616
  * url: "wss://relay.example.com",
614
617
  * ownerId: shardOwner.id,
@@ -641,15 +644,80 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
641
644
  * ```
642
645
  */
643
646
  readonly useOwner: (owner: ReadonlyOwner | Owner, transports?: NonEmptyReadonlyArray<OwnerTransport>) => UnuseOwner;
647
+ /**
648
+ * Requests a new synchronization round for an active {@link OwnerId}.
649
+ *
650
+ * Reconciles locally stored changes, including writes previously rejected
651
+ * with {@link ProtocolQuotaError}, through the owner's active transports. Call
652
+ * this after the relay provider confirms additional quota is available.
653
+ * Existing connections and {@link Evolu.useOwner} registrations are retained,
654
+ * including registrations shared by multiple instances or tabs.
655
+ *
656
+ * The owner must have an active writable registration in this database.
657
+ * Unregistered or read-only owners are ignored. Requests are skipped while
658
+ * all of the owner's transports are closed; they synchronize when they
659
+ * reopen. Disposal drops locally buffered requests. Calling a disposed
660
+ * instance throws, like other Evolu operations.
661
+ *
662
+ * Returns immediately, without waiting for synchronization to complete.
663
+ * Errors are reported through {@link EvoluErrorDep.evoluError}.
664
+ *
665
+ * ### Example
666
+ *
667
+ * ```ts
668
+ * import { assertType, type Evolu, type OwnerId } from "@evolu/common";
669
+ *
670
+ * // Call after successfully increasing the affected owner's relay quota.
671
+ * const onQuotaIncreased = (evolu: Evolu, ownerId: OwnerId) => {
672
+ * evolu.requestSync(ownerId);
673
+ * };
674
+ *
675
+ * assertType<
676
+ * typeof onQuotaIncreased,
677
+ * (evolu: Evolu, ownerId: OwnerId) => void
678
+ * >();
679
+ * ```
680
+ */
681
+ readonly requestSync: (ownerId: OwnerId) => void;
644
682
  }
645
- /** Function returned by {@link Evolu.useOwner} to stop using an Owner for sync. */
683
+ /**
684
+ * Function returned by {@link Evolu.useOwner} to stop using an Owner for sync.
685
+ *
686
+ * @group Core
687
+ */
646
688
  export type UnuseOwner = () => void;
689
+ /**
690
+ * Represents errors that can occur in {@link Evolu}.
691
+ *
692
+ * @group Core
693
+ */
694
+ export type EvoluError = DecryptWithXChaCha20Poly1305Error | OtherBuildRunningError | ProtocolError | StorageQuotaError | UnknownError | UnsupportedDbVersionError;
695
+ /**
696
+ * Dependency wrapper for the shared {@link EvoluError} store.
697
+ *
698
+ * @group Construction
699
+ */
647
700
  export interface EvoluErrorDep {
648
701
  /**
649
702
  * {@link ReadonlyStore} of {@link EvoluError} shared by all {@link Evolu}
650
703
  * instances created from the same {@link createEvoluDeps} result.
651
704
  *
705
+ * Starts at `null` and otherwise holds the latest reported error until the
706
+ * first {@link UnsupportedDbVersionError}. That refusal remains for the
707
+ * lifetime of these dependencies, even if a tenant is disposed and recreated.
708
+ * Later errors are still logged but do not replace it or notify this store's
709
+ * subscribers. Fresh dependencies start with a fresh error store. An
710
+ * {@link OtherBuildRunningError} reports a wait, so the store returns to
711
+ * `null` when the wait ends, unless another error replaced it.
712
+ *
652
713
  * Subscribe once to show user-facing error messages across all instances.
714
+ * While a refused database's tenant remains alive, the SharedWorker sends the
715
+ * refusal to each tab once, including tabs that connect later, and starts no
716
+ * replacement database workers. After all instances release that tenant and
717
+ * it is disposed when idle, creating another instance retries startup and may
718
+ * send the refusal again. On the web, a refused tab first reloads once
719
+ * instead; see {@link UnsupportedDbVersionError}. Show that blocking message
720
+ * outside any query-loading boundary, so pending queries do not hide it.
653
721
  *
654
722
  * ### Example
655
723
  *
@@ -657,62 +725,115 @@ export interface EvoluErrorDep {
657
725
  * import {
658
726
  * assertEqual,
659
727
  * createStore,
660
- * Millis,
661
728
  * type EvoluError,
662
729
  * } from "@evolu/common";
663
730
  * import type { EvoluErrorDep } from "@evolu/common/local-first";
664
731
  *
732
+ * // The message for the current error, or null for none.
733
+ * const errorMessage = (error: EvoluError | null): string | null => {
734
+ * if (!error) return null;
735
+ * // oxlint-disable-next-line typescript/switch-exhaustiveness-check -- The default handles every other EvoluError.
736
+ * switch (error.type) {
737
+ * case "UnsupportedDbVersionError":
738
+ * return "Your data requires a newer version of this app. Please update it.";
739
+ * case "OtherBuildRunningError":
740
+ * return "This app is open in another tab with a different version. Close that tab to continue.";
741
+ * default:
742
+ * return "Something went wrong. Please try again.";
743
+ * }
744
+ * };
745
+ *
665
746
  * // Stand-in for run.deps.evoluError from createEvoluDeps.
666
747
  * using evoluError = createStore<EvoluError | null>(null);
667
748
  * const deps = { evoluError } satisfies EvoluErrorDep;
668
- * let displayedMessage = "";
669
- * const showMessage = (message: string) => {
670
- * displayedMessage = message;
671
- * };
749
+ * // What the app showed over time; null hides the message.
750
+ * const shown: Array<string | null> = [];
672
751
  *
673
752
  * deps.evoluError.subscribe(() => {
674
- * const error = deps.evoluError.get();
675
- * if (!error) return;
676
- *
677
- * // oxlint-disable-next-line typescript/switch-exhaustiveness-check -- The default intentionally handles every other EvoluError.
678
- * switch (error.type) {
679
- * case "TimestampDriftError":
680
- * // Show guidance specific to the detected error.
681
- * showMessage(
682
- * "Your system clock appears incorrect. Please fix it.",
683
- * );
684
- * break;
685
- * default:
686
- * // Show a generic user message for other operational errors.
687
- * showMessage("Something went wrong. Please try again.");
688
- * }
753
+ * shown.push(errorMessage(deps.evoluError.get()));
689
754
  * });
690
755
  *
691
- * deps.evoluError.set({
692
- * type: "TimestampDriftError",
693
- * next: Millis.orThrow(360000),
694
- * now: Millis.orThrow(0),
695
- * });
696
- * assertEqual(
697
- * displayedMessage,
698
- * "Your system clock appears incorrect. Please fix it.",
699
- * );
756
+ * // Another version keeps this tab waiting, then the wait ends.
757
+ * deps.evoluError.set({ type: "OtherBuildRunningError" });
758
+ * deps.evoluError.set(null);
759
+ *
760
+ * assertEqual(shown, [
761
+ * "This app is open in another tab with a different version. Close that tab to continue.",
762
+ * null,
763
+ * ]);
700
764
  * ```
701
765
  */
702
766
  readonly evoluError: ReadonlyStore<EvoluError | null>;
703
767
  }
768
+ /**
769
+ * Dependency wrapper for the shared {@link SyncState} store.
770
+ *
771
+ * @group Construction
772
+ */
773
+ export interface SyncStateDep {
774
+ /**
775
+ * {@link ReadonlyStore} of the latest {@link SyncState} shared by all
776
+ * {@link Evolu} instances, or null before the shared worker sends its first
777
+ * snapshot. Derive what to show from it, such as one indicator per relay, or
778
+ * use {@link syncStateToOwnerSyncStates} for one state per owner.
779
+ *
780
+ * ### Example
781
+ *
782
+ * ```ts
783
+ * import {
784
+ * assertEqual,
785
+ * createId,
786
+ * createStore,
787
+ * testCreateDeps,
788
+ * } from "@evolu/common";
789
+ * import type {
790
+ * SyncState,
791
+ * SyncStateDep,
792
+ * } from "@evolu/common/local-first";
793
+ *
794
+ * const openRelayLabels = (deps: SyncStateDep): ReadonlyArray<string> =>
795
+ * (deps.syncState.get()?.transports ?? [])
796
+ * .filter(({ readyState }) => readyState === "open")
797
+ * .map(({ label }) => label);
798
+ *
799
+ * using syncState = createStore<SyncState | null>(null);
800
+ * assertEqual(openRelayLabels({ syncState }), []);
801
+ *
802
+ * const deps = testCreateDeps();
803
+ * syncState.set({
804
+ * transports: [
805
+ * {
806
+ * id: createId<"SyncTransport">(deps),
807
+ * label: "wss://relay.example",
808
+ * readyState: "open",
809
+ * openedAt: null,
810
+ * closedAt: null,
811
+ * error: null,
812
+ * },
813
+ * ],
814
+ * tenants: [],
815
+ * });
816
+ * assertEqual(openRelayLabels({ syncState }), ["wss://relay.example"]);
817
+ * ```
818
+ */
819
+ readonly syncState: ReadonlyStore<SyncState | null>;
820
+ }
704
821
  /**
705
822
  * Shared platform dependencies for creating {@link Evolu} instances.
706
823
  *
707
824
  * Includes platform adapters, the shared {@link EvoluErrorDep.evoluError} store,
708
825
  * and disposal for owned resources.
826
+ *
827
+ * @group Construction
709
828
  */
710
- export type EvoluDeps = EvoluPlatformDeps & ConsoleDep & EvoluErrorDep & Disposable;
829
+ export type EvoluDeps = EvoluPlatformDeps & ConsoleDep & EvoluErrorDep & SyncStateDep & Disposable;
711
830
  /**
712
831
  * Platform-specific dependencies required to create {@link EvoluDeps}.
713
832
  *
714
833
  * Provides worker and channel adapters plus optional platform integrations for
715
834
  * logging and synchronous UI flush.
835
+ *
836
+ * @group Construction
716
837
  */
717
838
  export type EvoluPlatformDeps = CreateDbWorkerDep & CreateBroadcastChannelDep & CreateMessageChannelDep & LockManagerDep & ReloadAppDep & SharedWorkerDep & Partial<ConsoleDep> & Partial<FlushSyncDep>;
718
839
  /**
@@ -721,15 +842,19 @@ export type EvoluPlatformDeps = CreateDbWorkerDep & CreateBroadcastChannelDep &
721
842
  *
722
843
  * Call this once per platform and reuse the returned deps when creating
723
844
  * multiple Evolu instances. The returned deps object owns long-lived resources
724
- * such as worker channels and the shared {@link EvoluErrorDep.evoluError}
725
- * store.
845
+ * such as worker channels and the shared {@link EvoluErrorDep.evoluError} and
846
+ * {@link SyncStateDep.syncState} stores.
726
847
  *
727
848
  * Dispose it only during app shutdown.
849
+ *
850
+ * @group Construction
728
851
  */
729
852
  export declare const createEvoluDeps: (deps: EvoluPlatformDeps) => EvoluDeps;
730
853
  /**
731
854
  * Creates an {@link Evolu} instance from {@link EvoluSchema} and
732
855
  * {@link EvoluConfig}.
856
+ *
857
+ * @group Construction
733
858
  */
734
859
  export declare const createEvolu: <S extends EvoluSchema>(schema: ValidateSchema<S> extends never ? S : ValidateSchema<S>, config: EvoluConfig) => Task<Evolu<S>, never, EvoluPlatformDeps>;
735
860
  //# sourceMappingURL=Evolu.d.ts.map