@evolu/common 7.4.0 → 8.0.0-next.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 (251) hide show
  1. package/README.md +4 -61
  2. package/dist/src/Array.d.ts +343 -102
  3. package/dist/src/Array.d.ts.map +1 -1
  4. package/dist/src/Array.js +181 -85
  5. package/dist/src/Assert.d.ts +57 -11
  6. package/dist/src/Assert.d.ts.map +1 -1
  7. package/dist/src/Assert.js +47 -11
  8. package/dist/src/BigInt.d.ts +6 -1
  9. package/dist/src/BigInt.d.ts.map +1 -1
  10. package/dist/src/BigInt.js +5 -0
  11. package/dist/src/Brand.d.ts +40 -12
  12. package/dist/src/Brand.d.ts.map +1 -1
  13. package/dist/src/Brand.js +5 -0
  14. package/dist/src/Buffer.d.ts +6 -1
  15. package/dist/src/Buffer.d.ts.map +1 -1
  16. package/dist/src/Buffer.js +7 -2
  17. package/dist/src/Cache.d.ts +10 -2
  18. package/dist/src/Cache.d.ts.map +1 -1
  19. package/dist/src/Cache.js +6 -0
  20. package/dist/src/Callbacks.d.ts +10 -7
  21. package/dist/src/Callbacks.d.ts.map +1 -1
  22. package/dist/src/Callbacks.js +23 -13
  23. package/dist/src/Console.d.ts +361 -69
  24. package/dist/src/Console.d.ts.map +1 -1
  25. package/dist/src/Console.js +217 -117
  26. package/dist/src/Crypto.d.ts +70 -21
  27. package/dist/src/Crypto.d.ts.map +1 -1
  28. package/dist/src/Crypto.js +72 -27
  29. package/dist/src/Eq.d.ts +22 -2
  30. package/dist/src/Eq.d.ts.map +1 -1
  31. package/dist/src/Eq.js +21 -1
  32. package/dist/src/Error.d.ts +23 -12
  33. package/dist/src/Error.d.ts.map +1 -1
  34. package/dist/src/Error.js +27 -11
  35. package/dist/src/Function.d.ts +128 -56
  36. package/dist/src/Function.d.ts.map +1 -1
  37. package/dist/src/Function.js +118 -14
  38. package/dist/src/Identicon.d.ts +5 -0
  39. package/dist/src/Identicon.d.ts.map +1 -1
  40. package/dist/src/Identicon.js +6 -1
  41. package/dist/src/Lookup.d.ts +160 -0
  42. package/dist/src/Lookup.d.ts.map +1 -0
  43. package/dist/src/Lookup.js +192 -0
  44. package/dist/src/Microtask.d.ts +21 -0
  45. package/dist/src/Microtask.d.ts.map +1 -0
  46. package/dist/src/Microtask.js +37 -0
  47. package/dist/src/Number.d.ts +18 -4
  48. package/dist/src/Number.d.ts.map +1 -1
  49. package/dist/src/Number.js +23 -1
  50. package/dist/src/Object.d.ts +110 -5
  51. package/dist/src/Object.d.ts.map +1 -1
  52. package/dist/src/Object.js +108 -5
  53. package/dist/src/Option.d.ts +58 -0
  54. package/dist/src/Option.d.ts.map +1 -0
  55. package/dist/src/Option.js +43 -0
  56. package/dist/src/Order.d.ts +5 -0
  57. package/dist/src/Order.d.ts.map +1 -1
  58. package/dist/src/Order.js +8 -3
  59. package/dist/src/Platform.d.ts +36 -2
  60. package/dist/src/Platform.d.ts.map +1 -1
  61. package/dist/src/Platform.js +10 -6
  62. package/dist/src/Polyfills.d.ts +27 -0
  63. package/dist/src/Polyfills.d.ts.map +1 -0
  64. package/dist/src/Polyfills.js +299 -0
  65. package/dist/src/Random.d.ts +18 -7
  66. package/dist/src/Random.d.ts.map +1 -1
  67. package/dist/src/Random.js +9 -7
  68. package/dist/src/Redacted.d.ts +7 -4
  69. package/dist/src/Redacted.d.ts.map +1 -1
  70. package/dist/src/Redacted.js +5 -0
  71. package/dist/src/Ref.d.ts +31 -16
  72. package/dist/src/Ref.d.ts.map +1 -1
  73. package/dist/src/Ref.js +35 -7
  74. package/dist/src/RefCount.d.ts +62 -0
  75. package/dist/src/RefCount.d.ts.map +1 -0
  76. package/dist/src/RefCount.js +83 -0
  77. package/dist/src/Relation.d.ts +84 -29
  78. package/dist/src/Relation.d.ts.map +1 -1
  79. package/dist/src/Relation.js +83 -105
  80. package/dist/src/Resource.d.ts +263 -0
  81. package/dist/src/Resource.d.ts.map +1 -0
  82. package/dist/src/Resource.js +389 -0
  83. package/dist/src/Result.d.ts +390 -374
  84. package/dist/src/Result.d.ts.map +1 -1
  85. package/dist/src/Result.js +142 -70
  86. package/dist/src/Schedule.d.ts +953 -0
  87. package/dist/src/Schedule.d.ts.map +1 -0
  88. package/dist/src/Schedule.js +1199 -0
  89. package/dist/src/Set.d.ts +181 -0
  90. package/dist/src/Set.d.ts.map +1 -0
  91. package/dist/src/Set.js +137 -0
  92. package/dist/src/Skiplist.d.ts +6 -1
  93. package/dist/src/Skiplist.d.ts.map +1 -1
  94. package/dist/src/Skiplist.js +5 -0
  95. package/dist/src/Sqlite.d.ts +160 -60
  96. package/dist/src/Sqlite.d.ts.map +1 -1
  97. package/dist/src/Sqlite.js +290 -190
  98. package/dist/src/Store.d.ts +36 -28
  99. package/dist/src/Store.d.ts.map +1 -1
  100. package/dist/src/Store.js +55 -15
  101. package/dist/src/String.d.ts +5 -0
  102. package/dist/src/String.d.ts.map +1 -1
  103. package/dist/src/String.js +5 -0
  104. package/dist/src/Task.d.ts +2263 -423
  105. package/dist/src/Task.d.ts.map +1 -1
  106. package/dist/src/Task.js +1488 -348
  107. package/dist/src/Test.d.ts +122 -0
  108. package/dist/src/Test.d.ts.map +1 -0
  109. package/dist/src/Test.js +66 -0
  110. package/dist/src/Time.d.ts +201 -48
  111. package/dist/src/Time.d.ts.map +1 -1
  112. package/dist/src/Time.js +190 -86
  113. package/dist/src/Tracer.d.ts +48 -0
  114. package/dist/src/Tracer.d.ts.map +1 -0
  115. package/dist/src/Tracer.js +6 -0
  116. package/dist/src/Type.d.ts +582 -209
  117. package/dist/src/Type.d.ts.map +1 -1
  118. package/dist/src/Type.js +362 -240
  119. package/dist/src/Types.d.ts +160 -6
  120. package/dist/src/Types.d.ts.map +1 -1
  121. package/dist/src/Types.js +22 -2
  122. package/dist/src/WebSocket.d.ts +113 -58
  123. package/dist/src/WebSocket.d.ts.map +1 -1
  124. package/dist/src/WebSocket.js +210 -118
  125. package/dist/src/Worker.d.ts +245 -60
  126. package/dist/src/Worker.d.ts.map +1 -1
  127. package/dist/src/Worker.js +220 -64
  128. package/dist/src/index.d.ts +25 -3
  129. package/dist/src/index.d.ts.map +1 -1
  130. package/dist/src/index.js +19 -3
  131. package/dist/src/local-first/Db.d.ts +24 -213
  132. package/dist/src/local-first/Db.d.ts.map +1 -1
  133. package/dist/src/local-first/Db.js +622 -293
  134. package/dist/src/local-first/Error.d.ts +12 -0
  135. package/dist/src/local-first/Error.d.ts.map +1 -0
  136. package/dist/src/local-first/Error.js +6 -0
  137. package/dist/src/local-first/Evolu.d.ts +330 -285
  138. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  139. package/dist/src/local-first/Evolu.js +472 -402
  140. package/dist/src/local-first/LocalAuth.d.ts +10 -10
  141. package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
  142. package/dist/src/local-first/LocalAuth.js +6 -1
  143. package/dist/src/local-first/Owner.d.ts +70 -27
  144. package/dist/src/local-first/Owner.d.ts.map +1 -1
  145. package/dist/src/local-first/Owner.js +27 -14
  146. package/dist/src/local-first/Protocol.d.ts +58 -50
  147. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  148. package/dist/src/local-first/Protocol.js +253 -155
  149. package/dist/src/local-first/Query.d.ts +133 -43
  150. package/dist/src/local-first/Query.d.ts.map +1 -1
  151. package/dist/src/local-first/Query.js +139 -90
  152. package/dist/src/local-first/Relay.d.ts +18 -38
  153. package/dist/src/local-first/Relay.d.ts.map +1 -1
  154. package/dist/src/local-first/Relay.js +59 -171
  155. package/dist/src/local-first/Schema.d.ts +139 -144
  156. package/dist/src/local-first/Schema.d.ts.map +1 -1
  157. package/dist/src/local-first/Schema.js +78 -163
  158. package/dist/src/local-first/Shared.d.ts +125 -0
  159. package/dist/src/local-first/Shared.d.ts.map +1 -0
  160. package/dist/src/local-first/Shared.js +569 -0
  161. package/dist/src/local-first/Storage.d.ts +50 -53
  162. package/dist/src/local-first/Storage.d.ts.map +1 -1
  163. package/dist/src/local-first/Storage.js +121 -173
  164. package/dist/src/local-first/Timestamp.d.ts +28 -35
  165. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  166. package/dist/src/local-first/Timestamp.js +24 -25
  167. package/dist/src/local-first/index.d.ts +2 -15
  168. package/dist/src/local-first/index.d.ts.map +1 -1
  169. package/dist/src/local-first/index.js +2 -15
  170. package/package.json +36 -26
  171. package/src/Array.ts +467 -106
  172. package/src/Assert.ts +87 -12
  173. package/src/BigInt.ts +7 -1
  174. package/src/Brand.ts +41 -12
  175. package/src/Buffer.ts +10 -4
  176. package/src/Cache.ts +11 -2
  177. package/src/Callbacks.ts +33 -23
  178. package/src/Console.ts +567 -178
  179. package/src/Crypto.ts +111 -62
  180. package/src/Eq.ts +30 -3
  181. package/src/Error.ts +50 -34
  182. package/src/Function.ts +140 -68
  183. package/src/Identicon.ts +7 -1
  184. package/src/Lookup.ts +415 -0
  185. package/src/Microtask.ts +58 -0
  186. package/src/Number.ts +40 -7
  187. package/src/Object.ts +155 -16
  188. package/src/Option.ts +74 -0
  189. package/src/Order.ts +11 -3
  190. package/src/Platform.ts +43 -7
  191. package/src/Polyfills.ts +465 -0
  192. package/src/Random.ts +25 -11
  193. package/src/Redacted.ts +8 -4
  194. package/src/Ref.ts +72 -21
  195. package/src/RefCount.ts +170 -0
  196. package/src/Relation.ts +188 -136
  197. package/src/Resource.ts +864 -0
  198. package/src/Result.ts +548 -381
  199. package/src/Schedule.ts +1471 -0
  200. package/src/Set.ts +247 -0
  201. package/src/Skiplist.ts +7 -1
  202. package/src/Sqlite.ts +409 -304
  203. package/src/Store.ts +94 -48
  204. package/src/String.ts +6 -0
  205. package/src/Task.ts +3685 -740
  206. package/src/Test.ts +162 -0
  207. package/src/Time.ts +348 -145
  208. package/src/Tracer.ts +54 -0
  209. package/src/Type.ts +1064 -630
  210. package/src/Types.ts +202 -7
  211. package/src/WebSocket.ts +311 -178
  212. package/src/Worker.ts +527 -147
  213. package/src/index.ts +74 -3
  214. package/src/local-first/Db.ts +871 -597
  215. package/src/local-first/Error.ts +17 -0
  216. package/src/local-first/Evolu.ts +884 -823
  217. package/src/local-first/LocalAuth.ts +10 -10
  218. package/src/local-first/Owner.ts +94 -42
  219. package/src/local-first/Protocol.ts +440 -303
  220. package/src/local-first/Query.ts +243 -194
  221. package/src/local-first/Relay.ts +91 -252
  222. package/src/local-first/Schema.ts +284 -394
  223. package/src/local-first/Shared.ts +932 -0
  224. package/src/local-first/Storage.ts +209 -282
  225. package/src/local-first/Timestamp.ts +38 -45
  226. package/src/local-first/index.ts +2 -16
  227. package/LICENSE +0 -21
  228. package/dist/src/Instances.d.ts +0 -34
  229. package/dist/src/Instances.d.ts.map +0 -1
  230. package/dist/src/Instances.js +0 -44
  231. package/dist/src/Resources.d.ts +0 -118
  232. package/dist/src/Resources.d.ts.map +0 -1
  233. package/dist/src/Resources.js +0 -197
  234. package/dist/src/local-first/Platform.d.ts +0 -25
  235. package/dist/src/local-first/Platform.d.ts.map +0 -1
  236. package/dist/src/local-first/Platform.js +0 -1
  237. package/dist/src/local-first/Public.d.ts +0 -22
  238. package/dist/src/local-first/Public.d.ts.map +0 -1
  239. package/dist/src/local-first/Public.js +0 -15
  240. package/dist/src/local-first/PublicKysely.d.ts +0 -148
  241. package/dist/src/local-first/PublicKysely.d.ts.map +0 -1
  242. package/dist/src/local-first/PublicKysely.js +0 -184
  243. package/dist/src/local-first/Sync.d.ts +0 -112
  244. package/dist/src/local-first/Sync.d.ts.map +0 -1
  245. package/dist/src/local-first/Sync.js +0 -529
  246. package/src/Instances.ts +0 -90
  247. package/src/Resources.ts +0 -367
  248. package/src/local-first/Platform.ts +0 -27
  249. package/src/local-first/Public.ts +0 -42
  250. package/src/local-first/PublicKysely.ts +0 -239
  251. package/src/local-first/Sync.ts +0 -960
@@ -1,19 +1,134 @@
1
- import { ConsoleDep } from "../Console.js";
2
- import { RandomBytesDep, SymmetricCryptoDecryptError } from "../Crypto.js";
3
- import { TransferableError } from "../Error.js";
4
- import { SqliteError } from "../Sqlite.js";
5
- import { StoreSubscribe } from "../Store.js";
6
- import { TimeDep } from "../Time.js";
7
- import { Mnemonic } from "../Type.js";
8
- import { CreateDbWorkerDep, DbConfig } from "./Db.js";
9
- import { AppOwner } from "./Owner.js";
10
- import { FlushSyncDep, ReloadAppDep } from "./Platform.js";
11
- import { ProtocolError } from "./Protocol.js";
12
- import { Queries, QueriesToQueryRowsPromises, Query, QueryRows, Row } from "./Query.js";
13
- import { CreateQuery, EvoluSchema, IndexesConfig, Mutation, ValidateSchema } from "./Schema.js";
14
- import { SyncOwner } from "./Sync.js";
15
- import { TimestampError } from "./Timestamp.js";
16
- export interface EvoluConfig extends Partial<DbConfig> {
1
+ /**
2
+ * Local-first platform.
3
+ *
4
+ * @module
5
+ */
6
+ import { type NonEmptyReadonlyArray } from "../Array.js";
7
+ import type { ConsoleDep } from "../Console.js";
8
+ import type { FlushSyncDep, ReloadAppDep } from "../Platform.js";
9
+ import type { Listener, ReadonlyStore, Unsubscribe } from "../Store.js";
10
+ import { type Task } from "../Task.js";
11
+ import type { TypeError } from "../Type.js";
12
+ import { Name } from "../Type.js";
13
+ import type { CreateMessageChannelDep } from "../Worker.js";
14
+ import type { CreateDbWorkerDep } from "./Db.js";
15
+ import type { EvoluError } from "./Error.js";
16
+ import type { AppOwner, Owner, OwnerTransport, ReadonlyOwner } from "./Owner.js";
17
+ import type { Queries, QueriesToQueryRowsPromises, Query, QueryRows, Row } from "./Query.js";
18
+ import type { EvoluSchema, IndexesConfig, Mutation, ValidateSchema } from "./Schema.js";
19
+ import type { SharedWorkerDep } from "./Shared.js";
20
+ export interface EvoluConfig {
21
+ /**
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.
25
+ *
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.
31
+ *
32
+ * ### Example
33
+ *
34
+ * ```ts
35
+ * // appName: AppName.orThrow("MyApp")
36
+ * ```
37
+ */
38
+ readonly appName: AppName;
39
+ /**
40
+ * {@link AppOwner} used to create this {@link Evolu} instance.
41
+ *
42
+ * Exposed as {@link Evolu.appOwner}. If `appOwner` is not passed, Evolu
43
+ * creates one.
44
+ *
45
+ * AppOwner controls access to the encrypted local SQLite database. If its
46
+ * secret material (Owner secret / Mnemonic) is not stored safely, data
47
+ * written by that instance is permanently inaccessible.
48
+ *
49
+ * Best onboarding UX is accountless first use: let users try a ready-to-use
50
+ * app, then prompt backup of `evolu.appOwner`.
51
+ *
52
+ * Recommended usage:
53
+ *
54
+ * - Omit `appOwner` for first run, then persist `evolu.appOwner` after user
55
+ * activity and guide the user to back it up.
56
+ * - Pass `appOwner` restored from secure storage (for example, Expo
57
+ * SecureStore, WebAuthn-backed storage, or app-managed account recovery
58
+ * flow).
59
+ */
60
+ readonly appOwner: AppOwner;
61
+ /**
62
+ * Transport configuration for sync and backup.
63
+ *
64
+ * If not specified, Evolu uses the default Evolu relay. Pass one or more
65
+ * transports to override it with your own relays. Pass an empty array to
66
+ * disable sync, which is useful when sync should be configured later.
67
+ *
68
+ * Empty transports start the instance without sync. In that case,
69
+ * {@link Evolu.useOwner} must be called with explicit non-empty transports to
70
+ * enable sync for any Owner, including the AppOwner.
71
+ *
72
+ * **Redundancy:** The ideal setup uses at least two completely independent
73
+ * relays - for example, a home relay and a geographically separate relay.
74
+ * Data is sent to both relays simultaneously, providing true redundancy
75
+ * similar to using two independent clouds. This eliminates vendor lock-in and
76
+ * ensures your app continues working regardless of circumstances - whether
77
+ * home relay hardware fails or disappears, or a remote relay provider shuts
78
+ * down.
79
+ *
80
+ * Currently supports:
81
+ *
82
+ * - WebSocket: Real-time bidirectional communication with relay servers
83
+ *
84
+ * Use {@link createOwnerWebSocketTransport} to create WebSocket transport
85
+ * configurations with proper URL formatting and {@link OwnerId} inclusion. The
86
+ * {@link OwnerId} in the URL enables relay authentication, allowing relay
87
+ * servers to control access (e.g., for paid tiers or private instances).
88
+ *
89
+ * The default value is:
90
+ *
91
+ * `{ type: "WebSocket", url: "wss://free.evoluhq.com" }`.
92
+ *
93
+ * ### Example
94
+ *
95
+ * ```ts
96
+ * // Single WebSocket relay
97
+ * transports: [{ type: "WebSocket", url: "wss://relay1.example.com" }];
98
+ *
99
+ * // Multiple WebSocket relays for redundancy
100
+ * transports: [
101
+ * { type: "WebSocket", url: "wss://relay1.example.com" },
102
+ * { type: "WebSocket", url: "wss://relay2.example.com" },
103
+ * { type: "WebSocket", url: "wss://relay3.example.com" },
104
+ * ];
105
+ *
106
+ * // Local-only instance (no sync) - useful for device settings or when relay
107
+ * // URL will be provided later (e.g., after authentication), allowing users
108
+ * // to work offline before the app connects
109
+ * transports: [];
110
+ *
111
+ * // Using createOwnerWebSocketTransport helper for relay authentication
112
+ * transports: [
113
+ * createOwnerWebSocketTransport({
114
+ * url: "ws://localhost:4000",
115
+ * ownerId,
116
+ * }),
117
+ * ];
118
+ * ```
119
+ */
120
+ readonly transports?: ReadonlyArray<OwnerTransport>;
121
+ /**
122
+ * Keep local data only in memory instead of persisting it on this device.
123
+ * Useful for testing, temporary data, or sensitive data that should not be
124
+ * recoverable from local storage after the process ends.
125
+ *
126
+ * Local data stored in memory is completely destroyed when the process ends.
127
+ * Sync can still persist data remotely when transports are enabled.
128
+ *
129
+ * The default value is: `false`.
130
+ */
131
+ readonly memoryOnly?: boolean;
17
132
  /**
18
133
  * Use the `indexes` option to define SQLite indexes.
19
134
  *
@@ -36,75 +151,139 @@ export interface EvoluConfig extends Partial<DbConfig> {
36
151
  */
37
152
  readonly indexes?: IndexesConfig;
38
153
  /**
39
- * URL to reload browser tabs after reset or restore.
154
+ * Called when this instance's local database is deleted.
40
155
  *
41
- * The default value is `/`.
156
+ * Apps can use this to update UI immediately because the corresponding
157
+ * {@link Evolu} instance becomes unusable after local database deletion.
158
+ */
159
+ readonly onDatabaseDeleted?: () => void;
160
+ /**
161
+ * Called when local data for an {@link Owner} is deleted.
42
162
  *
43
- * Note: This option will be moved to web platform deps in the next major
44
- * version.
163
+ * Apps can use this to update UI immediately because that owner stops being
164
+ * used across tabs and instances.
45
165
  */
46
- readonly reloadUrl?: string;
166
+ readonly onOwnerDeleted?: (owner: Owner) => void;
167
+ }
168
+ /**
169
+ * Application name.
170
+ *
171
+ * Evolu uses AppName as the base prefix for {@link Evolu.name}. The final
172
+ * instance name is derived per {@link AppOwner} as
173
+ * `${appName}-${createIdFromString(appOwner.id)}`.
174
+ *
175
+ * Uses the same safe alphabet as {@link UrlSafeString} (letters, digits, `-`,
176
+ * `_`) and must be between 1 and 41 characters.
177
+ */
178
+ export declare const AppName: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, "UrlSafeString", import("../Type.js").RegexError<"UrlSafeString">, import("../Type.js").StringError>, "AppName", AppNameError, import("../Type.js").StringError | import("../Type.js").RegexError<"UrlSafeString">>;
179
+ export type AppName = typeof AppName.Type;
180
+ export interface AppNameError extends TypeError<"AppName"> {
47
181
  }
48
- export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
182
+ export declare const testAppName: string & import("../Brand.js").Brand<"UrlSafeString"> & import("../Brand.js").Brand<"AppName">;
183
+ /**
184
+ * Local-first SQL database with typed queries, mutations, and sync.
185
+ *
186
+ * TODO: Better docs.
187
+ */
188
+ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposable {
49
189
  /**
50
- * Subscribe to {@link EvoluError} changes.
190
+ * Evolu instance name is derived from {@link EvoluConfig.appName} and
191
+ * {@link AppOwner}'s hash.
192
+ */
193
+ readonly name: Name;
194
+ /** {@link AppOwner}. */
195
+ readonly appOwner: AppOwner;
196
+ /**
197
+ * Inserts a row and returns the generated {@link Id}.
198
+ *
199
+ * All non-nullable columns are required, nullable columns are optional, and
200
+ * `id` is omitted because Evolu generates it automatically. This ensures
201
+ * every row has a globally unique, conflict-free identifier without
202
+ * coordination.
51
203
  *
52
204
  * ### Example
53
205
  *
54
206
  * ```ts
55
- * const unsubscribe = evolu.subscribeError(() => {
56
- * const error = evolu.getError();
57
- * console.log(error);
207
+ * const { id } = evolu.insert("todo", {
208
+ * title: NonEmptyString100.orThrow("Learn Evolu"),
58
209
  * });
210
+ *
211
+ * // With onComplete callback
212
+ * evolu.insert(
213
+ * "todo",
214
+ * { title: NonEmptyString100.orThrow("Another todo") },
215
+ * { onComplete: () => console.log("Insert completed") },
216
+ * );
59
217
  * ```
218
+ *
219
+ * @see {@link Mutation}
60
220
  */
61
- readonly subscribeError: StoreSubscribe;
62
- /** Get {@link EvoluError}. */
63
- readonly getError: () => EvoluError | null;
221
+ readonly insert: Mutation<S, "insert">;
64
222
  /**
65
- * Create type-safe SQL {@link Query}.
223
+ * Updates a row and returns the {@link Id}.
66
224
  *
67
- * Evolu uses Kysely - the type-safe SQL query builder for TypeScript. See
68
- * https://kysely.dev.
225
+ * Only `id` is required, all other columns are optional.
69
226
  *
70
- * All this function does is compile the Kysely query and serialize it into a
71
- * unique string. Both operations are fast and cheap.
227
+ * ### Example
72
228
  *
73
- * For mutations, use {@link Evolu#insert}, {@link Evolu#update}, or
74
- * {@link Evolu#upsert}.
229
+ * ```ts
230
+ * const { id } = evolu.update("todo", {
231
+ * id: todoId,
232
+ * title: NonEmptyString100.orThrow("Updated title"),
233
+ * });
234
+ *
235
+ * // Soft delete
236
+ * evolu.update("todo", { id: todoId, isDeleted: sqliteTrue });
237
+ * ```
238
+ *
239
+ * @see {@link Mutation}
240
+ */
241
+ readonly update: Mutation<S, "update">;
242
+ /**
243
+ * Upserts a row and returns the {@link Id}.
244
+ *
245
+ * Like insert, but requires an `id`. Useful for rows with external ID via
246
+ * {@link createIdFromString}. All other non-nullable columns are required,
247
+ * nullable columns are optional.
248
+ *
249
+ * `createdAt` and `updatedAt` cannot be set manually. Evolu derives both from
250
+ * the CRDT {@link Timestamp} — they share the same value, encoded once to
251
+ * avoid redundancy. Timestamps are always generated by Evolu to preserve CRDT
252
+ * consistency guarantees.
75
253
  *
76
254
  * ### Example
77
255
  *
78
256
  * ```ts
79
- * const allTodos = evolu.createQuery((db) =>
80
- * db.selectFrom("todo").selectAll(),
81
- * );
82
- *
83
- * const todoById = (id: TodoId) =>
84
- * evolu.createQuery((db) =>
85
- * db.selectFrom("todo").selectAll().where("id", "=", id),
86
- * );
257
+ * const stableId = createIdFromString("my-todo-1");
258
+ * const { id } = evolu.upsert("todo", {
259
+ * id: stableId,
260
+ * title: NonEmptyString100.orThrow("Learn Evolu"),
261
+ * });
87
262
  * ```
263
+ *
264
+ * @see {@link Mutation}
88
265
  */
89
- readonly createQuery: CreateQuery<S>;
266
+ readonly upsert: Mutation<S, "upsert">;
90
267
  /**
91
268
  * Load {@link Query} and return a promise with {@link QueryRows}.
92
269
  *
93
270
  * The returned promise always resolves successfully because there is no
94
- * reason why loading should fail. All data are local, and the query is typed.
95
- * Unexpected errors are handled with {@link Evolu#subscribeError}.
271
+ * reason why loading should fail. All data are local, and the query is
272
+ * typed.
96
273
  *
97
- * Loading is batched, and returned promises are cached until resolved to
98
- * prevent redundant database queries and to support React Suspense (which
99
- * requires stable promise references while pending).
274
+ * Loading is batched. Returned promises are cached while pending and can be
275
+ * reused after fulfillment until mutation-driven invalidation, which prevents
276
+ * redundant database queries and supports React Suspense (stable references
277
+ * while pending).
100
278
  *
101
279
  * To subscribe a query for automatic updates, use
102
- * {@link Evolu#subscribeQuery}.
280
+ * {@link Evolu.subscribeQuery}.
103
281
  *
104
282
  * ### Example
105
283
  *
106
284
  * ```ts
107
- * const allTodos = evolu.createQuery((db) =>
285
+ * const createQuery = createQueryBuilder(Schema);
286
+ * const allTodos = createQuery((db) =>
108
287
  * db.selectFrom("todo").selectAll(),
109
288
  * );
110
289
  * evolu.loadQuery(allTodos).then((rows) => {
@@ -112,7 +291,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
112
291
  * });
113
292
  * ```
114
293
  */
115
- readonly loadQuery: <R extends Row>(query: Query<R>) => Promise<QueryRows<R>>;
294
+ readonly loadQuery: <R extends Row>(query: Query<S, R>) => Promise<QueryRows<R>>;
116
295
  /**
117
296
  * Load an array of {@link Query} queries and return an array of
118
297
  * {@link QueryRows} promises. It's like `queries.map(loadQuery)` but with
@@ -124,7 +303,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
124
303
  * evolu.loadQueries([allTodos, todoById(1)]);
125
304
  * ```
126
305
  */
127
- readonly loadQueries: <R extends Row, Q extends Queries<R>>(queries: [...Q]) => [...QueriesToQueryRowsPromises<Q>];
306
+ readonly loadQueries: <Q extends Queries<S>>(queries: [...Q]) => [...QueriesToQueryRowsPromises<Q>];
128
307
  /**
129
308
  * Subscribe to {@link Query} {@link QueryRows} changes.
130
309
  *
@@ -136,7 +315,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
136
315
  * });
137
316
  * ```
138
317
  */
139
- readonly subscribeQuery: (query: Query) => StoreSubscribe;
318
+ readonly subscribeQuery: (query: Query<S>) => (listener: Listener) => Unsubscribe;
140
319
  /**
141
320
  * Get {@link QueryRows}.
142
321
  *
@@ -148,273 +327,139 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
148
327
  * });
149
328
  * ```
150
329
  */
151
- readonly getQueryRows: <R extends Row>(query: Query<R>) => QueryRows<R>;
330
+ readonly getQueryRows: <R extends Row>(query: Query<S, R>) => QueryRows<R>;
152
331
  /**
153
- * Promise that resolves to {@link AppOwner} when available.
154
- *
155
- * Note: With web-only deps, this promise will not resolve during SSR because
156
- * there is no AppOwner on the server.
332
+ * Exports the SQLite database file.
157
333
  *
158
- * ### Example
334
+ * Exports are sequential: concurrent calls share one pending export instead
335
+ * of starting parallel exports.
159
336
  *
160
- * ```ts
161
- * const owner = await evolu.appOwner;
162
- * ```
337
+ * The pending promise rejects if this {@link Evolu} instance is disposed
338
+ * before export completion.
163
339
  */
164
- readonly appOwner: Promise<AppOwner>;
340
+ readonly exportDatabase: () => Promise<Uint8Array<ArrayBuffer>>;
165
341
  /**
166
- * Inserts a row into the database and returns a {@link Result} with the new
167
- * {@link Id}.
168
- *
169
- * The first argument is the table name, and the second is an object
170
- * containing the row data. An optional third argument provides mutation
171
- * options including an `onComplete` callback and `onlyValidate` flag.
342
+ * Delete the local SQLite database for this {@link Evolu} instance on the
343
+ * current device.
172
344
  *
173
- * Returns a Result type - use `.ok` to check if the insertion succeeded, and
174
- * `.value.id` to access the generated ID on success, or `.error` to handle
175
- * validation errors.
345
+ * **Warning**: This first drops all tables. “The dropped table is completely
346
+ * removed from the database schema and the disk file. The table can not be
347
+ * recovered. All indices and triggers associated with the table are also
348
+ * deleted.” https://sqlite.org/lang_droptable.html
176
349
  *
177
- * Evolu does not use SQL for mutations to ensure data can be safely and
178
- * predictably merged without conflicts. Explicit mutations also allow Evolu
179
- * to automatically update {@link SystemColumns}.
180
- *
181
- * ### Example
182
- *
183
- * ```ts
184
- * const result = evolu.insert("todo", {
185
- * title: "Learn Evolu",
186
- * isCompleted: false,
187
- * });
350
+ * After that, it deletes the SQLite file identified by {@link Evolu.name},
351
+ * permanently forgetting all local data for that instance on this device.
188
352
  *
189
- * if (result.ok) {
190
- * console.log("Todo created with ID:", result.value.id);
191
- * } else {
192
- * console.error("Validation error:", result.error);
193
- * }
194
- *
195
- * // With onComplete callback
196
- * evolu.insert(
197
- * "todo",
198
- * { title: "Another todo" },
199
- * {
200
- * onComplete: () => {
201
- * console.log("Insert completed");
202
- * },
203
- * },
204
- * );
205
- * ```
353
+ * All instances identified by {@link Evolu.name} will be self-disposed. Use
354
+ * {@link EvoluConfig.onDatabaseDeleted} to update app UI when that happens.
206
355
  */
207
- insert: Mutation<S, "insert">;
356
+ readonly deleteDatabase: () => void;
208
357
  /**
209
- * Updates a row in the database and returns a {@link Result} with the existing
210
- * {@link Id}.
211
- *
212
- * The first argument is the table name, and the second is an object
213
- * containing the row data including the required `id` field. An optional
214
- * third argument provides mutation options including an `onComplete` callback
215
- * and `onlyValidate` flag.
216
- *
217
- * Returns a Result type - use `.ok` to check if the update succeeded, and
218
- * `.value.id` to access the ID on success, or `.error` to handle validation
219
- * errors.
220
- *
221
- * Evolu does not use SQL for mutations to ensure data can be safely and
222
- * predictably merged without conflicts. Explicit mutations also allow Evolu
223
- * to automatically update {@link SystemColumns}.
358
+ * Delete all local data for a specific {@link Owner}.
224
359
  *
225
- * ### Example
226
- *
227
- * ```ts
228
- * const result = evolu.update("todo", {
229
- * id: todoId,
230
- * title: "Updated title",
231
- * isCompleted: true,
232
- * });
360
+ * This deletes all rows whose `ownerId` matches the provided owner and
361
+ * deletes that owner's local history as well.
233
362
  *
234
- * if (result.ok) {
235
- * console.log("Todo updated with ID:", result.value.id);
236
- * } else {
237
- * console.error("Validation error:", result.error);
238
- * }
239
- *
240
- * // To delete a row, set isDeleted to true
241
- * evolu.update("todo", { id: todoId, isDeleted: true });
242
- *
243
- * // With onComplete callback
244
- * evolu.update(
245
- * "todo",
246
- * { id: todoId, title: "New title" },
247
- * {
248
- * onComplete: () => {
249
- * console.log("Update completed");
250
- * },
251
- * },
252
- * );
253
- * ```
363
+ * It also stops using that owner across all tabs and instances. Use
364
+ * {@link EvoluConfig.onOwnerDeleted} to update app UI when that happens.
254
365
  */
255
- update: Mutation<S, "update">;
366
+ readonly deleteOwner: (owner: Owner) => void;
256
367
  /**
257
- * Upserts a row in the database and returns a {@link Result} with the existing
258
- * {@link Id}.
259
- *
260
- * The first argument is the table name, and the second is an object
261
- * containing the row data including the required `id` field. An optional
262
- * third argument provides mutation options including an `onComplete` callback
263
- * and `onlyValidate` flag.
368
+ * Use an Owner for sync. Returns a {@link UnuseOwner}.
264
369
  *
265
- * This function allows you to use custom IDs and optionally set `createdAt`,
266
- * which is useful for external systems, data migrations, or when the same row
267
- * may already be created on a different device.
370
+ * Using an Owner means syncing it with the provided transports, or with the
371
+ * default transports defined in {@link EvoluConfig} when transports are
372
+ * omitted.
268
373
  *
269
- * Returns a Result type - use `.ok` to check if the upsert succeeded, and
270
- * `.value.id` to access the ID on success, or `.error` to handle validation
271
- * errors.
374
+ * If {@link EvoluConfig.transports} is an empty array, this method must be
375
+ * called with explicit non-empty transports.
272
376
  *
273
- * Evolu does not use SQL for mutations to ensure data can be safely and
274
- * predictably merged without conflicts. Explicit mutations also allow Evolu
275
- * to automatically update {@link SystemColumns}.
377
+ * Transports are automatically deduplicated and reference-counted, so
378
+ * multiple Owners using the same transport will share a single connection.
276
379
  *
277
380
  * ### Example
278
381
  *
279
382
  * ```ts
280
- * // Use deterministic ID for stable upserts across devices
281
- * const stableId = createIdFromString("my-todo-1");
282
- *
283
- * const result = evolu.upsert("todo", {
284
- * id: stableId,
285
- * title: "Learn Evolu",
286
- * isCompleted: false,
287
- * });
288
- *
289
- * if (result.ok) {
290
- * console.log("Todo upserted with ID:", result.value.id);
291
- * } else {
292
- * console.error("Validation error:", result.error);
293
- * }
294
- *
295
- * // Data migration with custom createdAt
296
- * evolu.upsert("todo", {
297
- * id: externalId,
298
- * title: "Migrated todo",
299
- * createdAt: new Date("2023-01-01"), // Preserve original timestamp
300
- * });
383
+ * // Use an Owner (starts syncing).
384
+ * const unuseOwner = evolu.useOwner(shardOwner, [
385
+ * createOwnerWebSocketTransport({
386
+ * url: "ws://localhost:4000",
387
+ * ownerId: shardOwner.id,
388
+ * }),
389
+ * ]);
390
+ *
391
+ * // Later, stop using the Owner.
392
+ * unuseOwner();
301
393
  *
302
- * // With onComplete callback
303
- * evolu.upsert(
304
- * "todo",
305
- * { id: stableId, title: "Updated title" },
306
- * {
307
- * onComplete: () => {
308
- * console.log("Upsert completed");
309
- * },
310
- * },
311
- * );
394
+ * // Bulk operations.
395
+ * const unuseOwners = owners.map(evolu.useOwner);
396
+ * // Later: for (const unuse of unuseOwners) unuse();
312
397
  * ```
313
398
  */
314
- upsert: Mutation<S, "upsert">;
315
- /**
316
- * Delete {@link AppOwner} and all their data from the current device. After
317
- * the deletion, Evolu will purge the application state. For browsers, this
318
- * will reload all tabs using Evolu. For native apps, it will restart the
319
- * app.
320
- *
321
- * Reloading can be turned off via options if you want to provide a different
322
- * UX.
323
- */
324
- readonly resetAppOwner: (options?: {
325
- readonly reload?: boolean;
326
- }) => Promise<void>;
327
- /**
328
- * Restore {@link AppOwner} with all their synced data. It uses
329
- * {@link Evolu#resetAppOwner}, so be careful.
330
- */
331
- readonly restoreAppOwner: (mnemonic: Mnemonic, options?: {
332
- readonly reload?: boolean;
333
- }) => Promise<void>;
334
- /**
335
- * Reload the app in a platform-specific way. For browsers, this will reload
336
- * all tabs using Evolu. For native apps, it will restart the app.
337
- */
338
- readonly reloadApp: () => void;
339
- /**
340
- * Export SQLite database file as Uint8Array.
341
- *
342
- * In the future, it will be possible to import a database and export/import
343
- * history for 1:1 migrations across owners.
344
- */
345
- readonly exportDatabase: () => Promise<Uint8Array<ArrayBuffer>>;
399
+ readonly useOwner: (owner: ReadonlyOwner | Owner, transports?: NonEmptyReadonlyArray<OwnerTransport>) => UnuseOwner;
400
+ }
401
+ /** Function returned by {@link Evolu.useOwner} to stop using an Owner for sync. */
402
+ export type UnuseOwner = () => void;
403
+ export interface EvoluErrorDep {
346
404
  /**
347
- * Use a {@link SyncOwner}. Returns a {@link UnuseOwner}.
348
- *
349
- * Using an owner means syncing it with its transports, or the transports
350
- * defined in Evolu config if the owner has no transports defined.
405
+ * {@link ReadonlyStore} of {@link EvoluError} shared by all {@link Evolu}
406
+ * instances created from the same {@link createEvoluDeps} result.
351
407
  *
352
- * Transport are automatically deduplicated and reference-counted, so multiple
353
- * owners using the same transport will share a single connection.
408
+ * Subscribe once to show user-facing messages across all instances. Logging
409
+ * is handled by platform {@link createRun} global error handlers.
354
410
  *
355
411
  * ### Example
356
412
  *
357
413
  * ```ts
358
- * // Use an owner (starts syncing).
359
- * const unuseOwner = evolu.useOwner(shardOwner);
360
- *
361
- * // Later, stop using the owner.
362
- * unuseOwner();
363
- *
364
- * // Bulk operations.
365
- * const unuseOwners = owners.map((owner) => evolu.useOwner(owner));
366
- * // Later: for (const unuse of unuseOwners) unuse();
414
+ * deps.evoluError.subscribe(() => {
415
+ * const error = deps.evoluError.get();
416
+ * if (!error) return;
417
+ *
418
+ * switch (error.type) {
419
+ * case "InvalidComputerClock":
420
+ * // Show guidance specific to the detected error.
421
+ * showMessage(
422
+ * "Your system clock appears incorrect. Please fix it.",
423
+ * );
424
+ * break;
425
+ * default:
426
+ * // Show a generic user message for other operational errors.
427
+ * showMessage("Something went wrong. Please try again.");
428
+ * }
429
+ * });
367
430
  * ```
368
- *
369
- * @experimental
370
431
  */
371
- readonly useOwner: (owner: SyncOwner) => UnuseOwner;
432
+ readonly evoluError: ReadonlyStore<EvoluError | null>;
372
433
  }
373
- /** Function returned by {@link Evolu#useOwner} to stop using an {@link SyncOwner}. */
374
- export type UnuseOwner = () => void;
375
- /** Represents errors that can occur in Evolu. */
376
- export type EvoluError = ProtocolError | SqliteError | SymmetricCryptoDecryptError | TimestampError | TransferableError;
377
- export type EvoluDeps = ConsoleDep & CreateDbWorkerDep & Partial<FlushSyncDep> & RandomBytesDep & ReloadAppDep & TimeDep;
378
434
  /**
379
- * Creates an {@link Evolu} instance for a platform configured with the specified
380
- * {@link EvoluSchema} and optional {@link EvoluConfig} providing a typed
381
- * interface for querying, mutating, and syncing your application's data.
382
- *
383
- * ### Example
435
+ * Shared platform dependencies for creating {@link Evolu} instances.
384
436
  *
385
- * ```ts
386
- * const TodoId = id("Todo");
387
- * type TodoId = InferType<typeof TodoId>;
388
- *
389
- * const TodoCategoryId = id("TodoCategory");
390
- * type TodoCategoryId = InferType<typeof TodoCategoryId>;
391
- *
392
- * const NonEmptyString50 = maxLength(50, NonEmptyString);
393
- * type NonEmptyString50 = InferType<typeof NonEmptyString50>;
394
- *
395
- * const Schema = {
396
- * todo: {
397
- * id: TodoId,
398
- * title: NonEmptyString1000,
399
- * isCompleted: nullOr(SqliteBoolean),
400
- * categoryId: nullOr(TodoCategoryId),
401
- * },
402
- * todoCategory: {
403
- * id: TodoCategoryId,
404
- * name: NonEmptyString50,
405
- * },
406
- * };
437
+ * Includes platform adapters, the shared {@link EvoluErrorDep.evoluError} store,
438
+ * and disposal for owned resources.
439
+ */
440
+ export type EvoluDeps = EvoluPlatformDeps & EvoluErrorDep & Disposable;
441
+ /**
442
+ * Platform-specific dependencies required to create {@link EvoluDeps}.
407
443
  *
408
- * const evolu = createEvolu(evoluReactDeps)(Schema);
409
- * ```
444
+ * Provides worker and channel adapters plus optional platform integrations for
445
+ * logging and synchronous UI flush.
446
+ */
447
+ export type EvoluPlatformDeps = CreateDbWorkerDep & CreateMessageChannelDep & ReloadAppDep & SharedWorkerDep & Partial<ConsoleDep> & Partial<FlushSyncDep>;
448
+ /**
449
+ * Creates shared dependencies used by all {@link createEvolu} instances on a
450
+ * platform.
410
451
  *
411
- * ### Instance Caching
452
+ * Call this once per platform and reuse the returned deps when creating
453
+ * multiple Evolu instances. The returned deps object owns long-lived resources
454
+ * such as worker channels and the shared {@link EvoluErrorDep.evoluError}
455
+ * store.
412
456
  *
413
- * `createEvolu` caches instances using {@link Instances} by {@link EvoluConfig}
414
- * name to enable hot reloading and prevent database corruption from multiple
415
- * connections. For testing, use unique instance names to ensure proper
416
- * isolation.
457
+ * Dispose it only during app shutdown.
458
+ */
459
+ export declare const createEvoluDeps: (deps: EvoluPlatformDeps) => EvoluDeps;
460
+ /**
461
+ * Creates an {@link Evolu} instance from {@link EvoluSchema} and
462
+ * {@link EvoluConfig}.
417
463
  */
418
- export declare const createEvolu: (deps: EvoluDeps) => <S extends EvoluSchema>(schema: ValidateSchema<S> extends never ? S : ValidateSchema<S>, config?: EvoluConfig) => Evolu<S>;
419
- export declare const createQuery: <R extends Row>(queryCallback: Parameters<CreateQuery<EvoluSchema>>[0], options?: Parameters<CreateQuery<EvoluSchema>>[1]) => Query<R>;
464
+ export declare const createEvolu: <S extends EvoluSchema>(schema: ValidateSchema<S> extends never ? S : ValidateSchema<S>, config: EvoluConfig) => Task<Evolu<S>, never, EvoluPlatformDeps>;
420
465
  //# sourceMappingURL=Evolu.d.ts.map