@evolu/common 8.10.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 (144) hide show
  1. package/dist/src/Config.d.ts +22 -22
  2. package/dist/src/Config.d.ts.map +1 -1
  3. package/dist/src/Console.d.ts +62 -7
  4. package/dist/src/Console.d.ts.map +1 -1
  5. package/dist/src/Console.js +20 -4
  6. package/dist/src/Crypto.d.ts +76 -4
  7. package/dist/src/Crypto.d.ts.map +1 -1
  8. package/dist/src/Crypto.js +55 -4
  9. package/dist/src/Error.d.ts +45 -0
  10. package/dist/src/Error.d.ts.map +1 -1
  11. package/dist/src/Error.js +69 -0
  12. package/dist/src/Fs.d.ts +92 -18
  13. package/dist/src/Fs.d.ts.map +1 -1
  14. package/dist/src/Fs.js +2 -0
  15. package/dist/src/Identicon.d.ts +2 -2
  16. package/dist/src/Identicon.js +2 -2
  17. package/dist/src/LeakDetector.d.ts +22 -3
  18. package/dist/src/LeakDetector.d.ts.map +1 -1
  19. package/dist/src/LeakDetector.js +12 -2
  20. package/dist/src/LockManager.d.ts +8 -0
  21. package/dist/src/LockManager.d.ts.map +1 -1
  22. package/dist/src/LockManager.js +6 -0
  23. package/dist/src/Object.d.ts.map +1 -1
  24. package/dist/src/Object.js +5 -0
  25. package/dist/src/Platform.d.ts +47 -7
  26. package/dist/src/Platform.d.ts.map +1 -1
  27. package/dist/src/Platform.js +24 -5
  28. package/dist/src/Random.d.ts +25 -2
  29. package/dist/src/Random.d.ts.map +1 -1
  30. package/dist/src/Random.js +14 -2
  31. package/dist/src/Resource.d.ts +156 -1
  32. package/dist/src/Resource.d.ts.map +1 -1
  33. package/dist/src/Resource.js +201 -72
  34. package/dist/src/Schedule.d.ts +11 -10
  35. package/dist/src/Schedule.d.ts.map +1 -1
  36. package/dist/src/Schedule.js +1 -1
  37. package/dist/src/Sqlite.d.ts +132 -16
  38. package/dist/src/Sqlite.d.ts.map +1 -1
  39. package/dist/src/Sqlite.js +63 -9
  40. package/dist/src/Task.d.ts +15 -4
  41. package/dist/src/Task.d.ts.map +1 -1
  42. package/dist/src/Task.js +41 -15
  43. package/dist/src/Test.d.ts +9 -0
  44. package/dist/src/Test.d.ts.map +1 -1
  45. package/dist/src/Test.js +4 -0
  46. package/dist/src/Time.d.ts +106 -9
  47. package/dist/src/Time.d.ts.map +1 -1
  48. package/dist/src/Time.js +55 -4
  49. package/dist/src/Type.d.ts +1455 -1310
  50. package/dist/src/Type.d.ts.map +1 -1
  51. package/dist/src/Type.js +1274 -517
  52. package/dist/src/WebSocket.d.ts +164 -13
  53. package/dist/src/WebSocket.d.ts.map +1 -1
  54. package/dist/src/WebSocket.js +133 -24
  55. package/dist/src/Worker.d.ts +90 -8
  56. package/dist/src/Worker.d.ts.map +1 -1
  57. package/dist/src/Worker.js +28 -2
  58. package/dist/src/index.d.ts +6 -7
  59. package/dist/src/index.d.ts.map +1 -1
  60. package/dist/src/index.js +2 -3
  61. package/dist/src/local-first/Db.d.ts +52 -3
  62. package/dist/src/local-first/Db.d.ts.map +1 -1
  63. package/dist/src/local-first/Db.js +412 -137
  64. package/dist/src/local-first/Evolu.d.ts +336 -211
  65. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  66. package/dist/src/local-first/Evolu.js +102 -15
  67. package/dist/src/local-first/Owner.d.ts +13 -30
  68. package/dist/src/local-first/Owner.d.ts.map +1 -1
  69. package/dist/src/local-first/Owner.js +13 -30
  70. package/dist/src/local-first/Protocol.d.ts +94 -16
  71. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  72. package/dist/src/local-first/Protocol.js +118 -38
  73. package/dist/src/local-first/Query.d.ts +8 -15
  74. package/dist/src/local-first/Query.d.ts.map +1 -1
  75. package/dist/src/local-first/Schema.d.ts +335 -21
  76. package/dist/src/local-first/Schema.d.ts.map +1 -1
  77. package/dist/src/local-first/Schema.js +214 -17
  78. package/dist/src/local-first/Shared.d.ts +537 -22
  79. package/dist/src/local-first/Shared.d.ts.map +1 -1
  80. package/dist/src/local-first/Shared.js +1437 -234
  81. package/dist/src/local-first/Storage.d.ts +192 -14
  82. package/dist/src/local-first/Storage.d.ts.map +1 -1
  83. package/dist/src/local-first/Storage.js +81 -20
  84. package/dist/src/local-first/Timestamp.d.ts +392 -41
  85. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  86. package/dist/src/local-first/Timestamp.js +403 -81
  87. package/dist/src/local-first/index.d.ts +0 -1
  88. package/dist/src/local-first/index.d.ts.map +1 -1
  89. package/dist/src/local-first/index.js +0 -1
  90. package/package.json +1 -1
  91. package/src/Assert.test.ts +2 -5
  92. package/src/Config.test.ts +2 -6
  93. package/src/Config.ts +133 -133
  94. package/src/Console.ts +62 -7
  95. package/src/Crypto.ts +76 -4
  96. package/src/Eq.test.ts +2 -3
  97. package/src/Error.test.ts +76 -3
  98. package/src/Error.ts +71 -0
  99. package/src/Fs.ts +92 -18
  100. package/src/Identicon.ts +2 -2
  101. package/src/LeakDetector.ts +22 -3
  102. package/src/LockManager.ts +8 -0
  103. package/src/Object.test.ts +27 -12
  104. package/src/Object.ts +5 -0
  105. package/src/Platform.ts +50 -8
  106. package/src/Random.ts +25 -2
  107. package/src/Resource.test.ts +837 -0
  108. package/src/Resource.ts +235 -15
  109. package/src/Schedule.test.ts +50 -12
  110. package/src/Schedule.ts +24 -14
  111. package/src/Sqlite.ts +137 -17
  112. package/src/Task.test.ts +189 -8
  113. package/src/Task.ts +56 -17
  114. package/src/Test.ts +9 -0
  115. package/src/Time.ts +106 -9
  116. package/src/Type.test.ts +946 -1028
  117. package/src/Type.ts +4195 -3136
  118. package/src/Types.test.ts +4 -14
  119. package/src/WebSocket.ts +313 -40
  120. package/src/Worker.ts +90 -8
  121. package/src/index.ts +15 -6
  122. package/src/local-first/Db.ts +644 -339
  123. package/src/local-first/Evolu.test.ts +686 -21
  124. package/src/local-first/Evolu.ts +450 -228
  125. package/src/local-first/Owner.ts +13 -30
  126. package/src/local-first/Protocol.test.ts +617 -10
  127. package/src/local-first/Protocol.ts +196 -72
  128. package/src/local-first/Query.ts +8 -15
  129. package/src/local-first/Schema.test.ts +143 -0
  130. package/src/local-first/Schema.ts +363 -24
  131. package/src/local-first/Shared.test.ts +7731 -559
  132. package/src/local-first/Shared.ts +2036 -267
  133. package/src/local-first/Storage.ts +218 -32
  134. package/src/local-first/Timestamp.test.ts +344 -70
  135. package/src/local-first/Timestamp.ts +434 -118
  136. package/src/local-first/index.ts +0 -1
  137. package/dist/src/local-first/Error.d.ts +0 -12
  138. package/dist/src/local-first/Error.d.ts.map +0 -1
  139. package/dist/src/local-first/Error.js +0 -6
  140. package/dist/src/local-first/LocalAuth.d.ts +0 -150
  141. package/dist/src/local-first/LocalAuth.d.ts.map +0 -1
  142. package/dist/src/local-first/LocalAuth.js +0 -179
  143. package/src/local-first/Error.ts +0 -17
  144. package/src/local-first/LocalAuth.ts +0 -457
@@ -23,13 +23,17 @@ import {
23
23
  type SqliteSchema,
24
24
  SqliteValue,
25
25
  } from "../Sqlite.ts";
26
+ import type { Millis } from "../Time.ts";
26
27
  import {
27
28
  assertType,
29
+ createIdFromString,
28
30
  DateIso,
29
31
  type FiniteNumber,
30
32
  type Id,
33
+ id,
31
34
  IdBytes,
32
35
  type InferType,
36
+ NonEmptyTrimmedString100,
33
37
  Null,
34
38
  nullOr,
35
39
  object,
@@ -38,8 +42,13 @@ import {
38
42
  type withDefault,
39
43
  } from "../Type.ts";
40
44
  import type { CompileTimeError, Simplify } from "../Types.ts";
41
- import type { AppOwner } from "./Owner.ts";
42
- import { OwnerId } from "./Owner.ts";
45
+ import type { AppOwner, OwnerIdBytes } from "./Owner.ts";
46
+ import {
47
+ OwnerEncryptionKey,
48
+ OwnerId,
49
+ OwnerSecret,
50
+ OwnerWriteKey,
51
+ } from "./Owner.ts";
43
52
  import type {
44
53
  evoluJsonArrayFrom,
45
54
  evoluJsonObjectFrom,
@@ -49,7 +58,11 @@ import type {
49
58
  import type { CrdtMessage, DbChange } from "./Storage.ts";
50
59
  import { TimestampBytes } from "./Timestamp.ts";
51
60
 
52
- /** Any Standard Schema V1 declaration. */
61
+ /**
62
+ * Any Standard Schema V1 declaration.
63
+ *
64
+ * @group Core
65
+ */
53
66
  export type AnyStandardSchemaV1 = StandardSchemaV1<any, any>;
54
67
 
55
68
  /**
@@ -121,6 +134,8 @@ export type AnyStandardSchemaV1 = StandardSchemaV1<any, any>;
121
134
  * };
122
135
  * assertTrue(ZodSchema.todo.title.safeParse("Write docs").success);
123
136
  * ```
137
+ *
138
+ * @group Core
124
139
  */
125
140
  export type EvoluSchema = ReadonlyRecord<
126
141
  string,
@@ -128,9 +143,127 @@ export type EvoluSchema = ReadonlyRecord<
128
143
  TableSchema
129
144
  >;
130
145
 
131
- /** A table schema: column names mapped to Standard Schema validators. */
146
+ /**
147
+ * A table schema: column names mapped to Standard Schema validators.
148
+ *
149
+ * @group Core
150
+ */
132
151
  export type TableSchema = ReadonlyRecord<string, AnyStandardSchemaV1>;
133
152
 
153
+ /**
154
+ * Whether a table is local-only: its name starts with an underscore, so its
155
+ * changes are stored without synchronization.
156
+ *
157
+ * @group Core
158
+ */
159
+ export const isLocalOnlyTable = (table: string): boolean =>
160
+ table.startsWith("_");
161
+
162
+ /**
163
+ * Todo ID Type for {@link testEvoluSchema}.
164
+ *
165
+ * @group Testing
166
+ */
167
+ export const TestTodoId = /*#__PURE__*/ id("Todo");
168
+ export type TestTodoId = typeof TestTodoId.Output;
169
+
170
+ /**
171
+ * Deterministic {@link TestTodoId} for tests and examples.
172
+ *
173
+ * @group Testing
174
+ */
175
+ export const testTodoId = /*#__PURE__*/ TestTodoId.orThrow(
176
+ /*#__PURE__*/ createIdFromString("testTodo"),
177
+ );
178
+
179
+ /**
180
+ * Project ID Type for {@link testEvoluSchema}.
181
+ *
182
+ * @group Testing
183
+ */
184
+ export const TestProjectId = /*#__PURE__*/ id("Project");
185
+ export type TestProjectId = typeof TestProjectId.Output;
186
+
187
+ /**
188
+ * Deterministic {@link TestProjectId} for tests and examples.
189
+ *
190
+ * @group Testing
191
+ */
192
+ export const testProjectId = /*#__PURE__*/ TestProjectId.orThrow(
193
+ /*#__PURE__*/ createIdFromString("testProject"),
194
+ );
195
+
196
+ /**
197
+ * Todo and project schema for tests and examples. A todo can belong to a
198
+ * project or have no project. Use an explicit schema when teaching schema
199
+ * definition.
200
+ *
201
+ * ### Example
202
+ *
203
+ * ```ts
204
+ * import {
205
+ * assertOk,
206
+ * testEvoluSchema,
207
+ * testProjectId,
208
+ * testTodoId,
209
+ * } from "@evolu/common";
210
+ *
211
+ * assertOk(testEvoluSchema.todo.id.from(testTodoId), testTodoId);
212
+ * assertOk(
213
+ * testEvoluSchema.todo.projectId.from(testProjectId),
214
+ * testProjectId,
215
+ * );
216
+ * ```
217
+ *
218
+ * @group Testing
219
+ */
220
+ export const testEvoluSchema = {
221
+ todo: {
222
+ id: TestTodoId,
223
+ title: NonEmptyTrimmedString100,
224
+ isCompleted: /*#__PURE__*/ nullOr(SqliteBoolean),
225
+ projectId: /*#__PURE__*/ nullOr(TestProjectId),
226
+ },
227
+ project: {
228
+ id: TestProjectId,
229
+ name: NonEmptyTrimmedString100,
230
+ },
231
+ } as const satisfies EvoluSchema;
232
+
233
+ /**
234
+ * Schema type of {@link testEvoluSchema}.
235
+ *
236
+ * @group Testing
237
+ */
238
+ export type TestEvoluSchema = typeof testEvoluSchema;
239
+
240
+ /**
241
+ * App-owner registry schema with local tables for tests and examples.
242
+ *
243
+ * Stores operational keys separately from optional recovery material. A null
244
+ * secret represents an owner whose recovery material is managed elsewhere or
245
+ * unavailable. Names are optional device-local labels; identicons can be
246
+ * derived from the owner identity without an additional column.
247
+ *
248
+ * This fixture does not define the production registry's persistence contract.
249
+ *
250
+ * @group Testing
251
+ */
252
+ export const testLocalOnlyEvoluSchema = {
253
+ _appOwner: {
254
+ id: OwnerId,
255
+ encryptionKey: OwnerEncryptionKey,
256
+ writeKey: OwnerWriteKey,
257
+ secret: /*#__PURE__*/ nullOr(OwnerSecret),
258
+ name: /*#__PURE__*/ nullOr(NonEmptyTrimmedString100),
259
+ },
260
+ } as const satisfies EvoluSchema;
261
+
262
+ /**
263
+ * Dependency wrapper for {@link SqliteSchema}.
264
+ *
265
+ * @group SQLite
266
+ */
134
267
  export interface SqliteSchemaDep {
135
268
  readonly sqliteSchema: SqliteSchema;
136
269
  }
@@ -147,6 +280,8 @@ export interface SqliteSchemaDep {
147
280
  * 2. The 'id' column output type must extend {@link Id}
148
281
  * 3. Tables cannot use system column names (createdAt, updatedAt, isDeleted)
149
282
  * 4. All column output types must be compatible with SQLite (extend SqliteValue)
283
+ *
284
+ * @group Validation
150
285
  */
151
286
  export type ValidateSchema<S extends EvoluSchema> =
152
287
  ValidateSchemaHasId<S> extends never
@@ -159,10 +294,106 @@ export type ValidateSchema<S extends EvoluSchema> =
159
294
  : ValidateIdColumnType<S>
160
295
  : ValidateSchemaHasId<S>;
161
296
 
297
+ /**
298
+ * Defines SQLite indexes with Kysely's index builder.
299
+ *
300
+ * @group SQLite
301
+ */
162
302
  export type IndexesConfig = (
163
303
  create: (indexName: string) => Kysely.CreateIndexBuilder,
164
304
  ) => ReadonlyArray<Kysely.CreateIndexBuilder<any>>;
165
305
 
306
+ /**
307
+ * Why a message is stored in `evolu_message_quarantine` instead of being
308
+ * applied to its table. Persisted codes: names may change, but numbers must not
309
+ * be reassigned.
310
+ *
311
+ * Quarantine is queryable state, not an error. An application subscribes to a
312
+ * query over `evolu_message_quarantine` to tell the user what is waiting. Each
313
+ * row is one column of a message, so distinct `ownerId` and `timestamp` pairs
314
+ * count messages. `origin` records whether this database stamped the message
315
+ * for a local mutation or received it from sync, see {@link QuarantineOrigin}.
316
+ * `quarantinedAt` is the system time captured for the request that quarantined
317
+ * the row, in milliseconds; it is null for rows written before Evolu recorded
318
+ * it. The clock-drift rules are described in the Timestamp module.
319
+ *
320
+ * ### Example
321
+ *
322
+ * ```ts
323
+ * import {
324
+ * assertType,
325
+ * createQueryBuilder,
326
+ * type Millis,
327
+ * type OwnerIdBytes,
328
+ * type QuarantineOrigin,
329
+ * QuarantineReason,
330
+ * testEvoluSchema,
331
+ * type TimestampBytes,
332
+ * } from "@evolu/common";
333
+ *
334
+ * const createQuery = createQueryBuilder(testEvoluSchema);
335
+ *
336
+ * // Messages waiting in drift quarantine, one row per message.
337
+ * const driftQuarantineQuery = createQuery((db) =>
338
+ * db
339
+ * .selectFrom("evolu_message_quarantine")
340
+ * .select(["ownerId", "timestamp", "origin", "quarantinedAt"])
341
+ * .where("reason", "=", QuarantineReason.TimestampDrift)
342
+ * .distinct(),
343
+ * );
344
+ *
345
+ * assertType<
346
+ * typeof driftQuarantineQuery.Row,
347
+ * {
348
+ * ownerId: OwnerIdBytes;
349
+ * timestamp: TimestampBytes;
350
+ * origin: QuarantineOrigin;
351
+ * quarantinedAt: Millis | null;
352
+ * }
353
+ * >();
354
+ * ```
355
+ *
356
+ * @group Queries
357
+ */
358
+ export const QuarantineReason = {
359
+ /**
360
+ * The message has a table or column the current schema does not define. It is
361
+ * applied automatically once a schema update defines them. A received change
362
+ * to a {@link isLocalOnlyTable | local-only} table is also stored here and is
363
+ * never applied.
364
+ */
365
+ Schema: 0,
366
+ /**
367
+ * The message's timestamp exceeded the drift limit when it was stored. It is
368
+ * applied when the database worker starts, once system time comes within the
369
+ * limit of the timestamp.
370
+ */
371
+ TimestampDrift: 1,
372
+ } as const;
373
+
374
+ export type QuarantineReason =
375
+ (typeof QuarantineReason)[keyof typeof QuarantineReason];
376
+
377
+ /**
378
+ * Whether a quarantined message was stamped by this database for a local
379
+ * mutation or received from sync. Persisted codes: names may change, but
380
+ * numbers must not be reassigned.
381
+ *
382
+ * @group Queries
383
+ */
384
+ export const QuarantineOrigin = {
385
+ LocalMutation: 0,
386
+ ReceivedMessage: 1,
387
+ } as const;
388
+
389
+ export type QuarantineOrigin =
390
+ (typeof QuarantineOrigin)[keyof typeof QuarantineOrigin];
391
+
392
+ /**
393
+ * Typed query factory returned by {@link createQueryBuilder}.
394
+ *
395
+ * @group Queries
396
+ */
166
397
  export type CreateQuery<S extends EvoluSchema> = <R extends Row>(
167
398
  queryCallback: (
168
399
  db: Pick<
@@ -175,6 +406,7 @@ export type CreateQuery<S extends EvoluSchema> = <R extends Row>(
175
406
  } & SystemColumns;
176
407
  } & {
177
408
  readonly evolu_history: {
409
+ readonly ownerId: OwnerIdBytes;
178
410
  readonly timestamp: TimestampBytes;
179
411
  readonly table: keyof S;
180
412
  readonly id: IdBytes;
@@ -182,11 +414,15 @@ export type CreateQuery<S extends EvoluSchema> = <R extends Row>(
182
414
  readonly value: SqliteValue;
183
415
  };
184
416
  readonly evolu_message_quarantine: {
417
+ readonly ownerId: OwnerIdBytes;
185
418
  readonly timestamp: TimestampBytes;
186
419
  readonly table: string;
187
420
  readonly id: IdBytes;
188
421
  readonly column: string;
189
422
  readonly value: SqliteValue;
423
+ readonly reason: QuarantineReason;
424
+ readonly origin: QuarantineOrigin;
425
+ readonly quarantinedAt: Millis | null;
190
426
  };
191
427
  }
192
428
  >,
@@ -204,6 +440,8 @@ export type CreateQuery<S extends EvoluSchema> = <R extends Row>(
204
440
  * - `isDeleted`: Soft delete flag created by Evolu and used by the developer to
205
441
  * mark rows as deleted.
206
442
  * - `ownerId`: Represents ownership and logically partitions the database.
443
+ *
444
+ * @group Core
207
445
  */
208
446
  export const SystemColumns: ObjectType<{
209
447
  readonly createdAt: typeof DateIso;
@@ -218,6 +456,11 @@ export const SystemColumns: ObjectType<{
218
456
  });
219
457
  export interface SystemColumns extends InferType<typeof SystemColumns> {}
220
458
 
459
+ /**
460
+ * Kind of a {@link Mutation}: insert, update, or upsert.
461
+ *
462
+ * @group Mutations
463
+ */
221
464
  export type MutationKind = "insert" | "update" | "upsert";
222
465
 
223
466
  /**
@@ -239,6 +482,8 @@ export type MutationKind = "insert" | "update" | "upsert";
239
482
  * `id` omitted (auto-generated)
240
483
  * - **update**: only `id` required, everything else optional
241
484
  * - **upsert**: like insert but `id` required too
485
+ *
486
+ * @group Mutations
242
487
  */
243
488
  export type Mutation<S extends EvoluSchema, Kind extends MutationKind> = <
244
489
  TableName extends keyof S,
@@ -248,11 +493,26 @@ export type Mutation<S extends EvoluSchema, Kind extends MutationKind> = <
248
493
  options?: MutationOptions,
249
494
  ) => { readonly id: StandardSchemaV1.InferOutput<S[TableName]["id"]> };
250
495
 
496
+ /**
497
+ * Options accepted by every {@link Mutation}.
498
+ *
499
+ * @group Mutations
500
+ */
251
501
  export interface MutationOptions {
252
502
  /**
253
- * Called after the mutation is completed and the local state is updated.
254
- * Useful for triggering side effects (e.g., notifications, UI updates) after
255
- * insert, update, or upsert.
503
+ * Called after the mutation's changes are stored and subscribed queries
504
+ * reflect them. Useful for follow-up work (e.g., notifications, navigation)
505
+ * after insert, update, or upsert. It never runs when the database is
506
+ * unavailable.
507
+ *
508
+ * Stored does not always mean visible. A change quarantined for
509
+ * {@link QuarantineReason.TimestampDrift} is stored in
510
+ * `evolu_message_quarantine` without changing application rows. `onComplete`
511
+ * still fires after storage commits; no drift error is reported. Applications
512
+ * can subscribe to the quarantine table; those query results reflect the
513
+ * change before `onComplete` runs. See the
514
+ * {@link @evolu/common!"local-first/Timestamp" | Timestamp module} for drift
515
+ * and release behavior.
256
516
  */
257
517
  readonly onComplete?: () => void;
258
518
 
@@ -317,6 +577,12 @@ export interface MutationOptions {
317
577
  readonly ownerId?: OwnerId;
318
578
  }
319
579
 
580
+ /**
581
+ * Database change produced by a {@link Mutation}, attributed to the
582
+ * {@link OwnerId} that owns the row.
583
+ *
584
+ * @group Mutations
585
+ */
320
586
  export interface MutationChange extends DbChange {
321
587
  readonly ownerId: OwnerId;
322
588
  }
@@ -324,6 +590,8 @@ export interface MutationChange extends DbChange {
324
590
  /**
325
591
  * Derives the expected values type for a mutation from a table's column schemas
326
592
  * and a {@link MutationKind}.
593
+ *
594
+ * @group Mutations
327
595
  */
328
596
  export type MutationValues<
329
597
  T extends TableSchema,
@@ -339,6 +607,8 @@ export type MutationValues<
339
607
  /**
340
608
  * Insert values: `id` omitted (auto-generated), nullable columns optional,
341
609
  * non-nullable columns required.
610
+ *
611
+ * @group Mutations
342
612
  */
343
613
  export type InsertValues<T extends TableSchema> = Omit<
344
614
  NullableColumnsToOptional<T>,
@@ -348,6 +618,8 @@ export type InsertValues<T extends TableSchema> = Omit<
348
618
  /**
349
619
  * Update values: `id` required, all other columns optional. Includes
350
620
  * `isDeleted` for soft deletes.
621
+ *
622
+ * @group Mutations
351
623
  */
352
624
  export type UpdateValues<T extends TableSchema> = {
353
625
  readonly id: StandardSchemaV1.InferOutput<T["id"]>;
@@ -360,12 +632,19 @@ export type UpdateValues<T extends TableSchema> = {
360
632
  /**
361
633
  * Upsert values: `id` required, nullable columns optional, non-nullable columns
362
634
  * required. Includes `isDeleted` for soft deletes.
635
+ *
636
+ * @group Mutations
363
637
  */
364
638
  export type UpsertValues<T extends TableSchema> =
365
639
  NullableColumnsToOptional<T> & {
366
640
  readonly isDeleted?: SqliteBoolean;
367
641
  };
368
642
 
643
+ /**
644
+ * Requires an `id` column in every table.
645
+ *
646
+ * @group Validation
647
+ */
369
648
  export type ValidateSchemaHasId<S extends EvoluSchema> =
370
649
  keyof S extends infer TableName
371
650
  ? TableName extends keyof S
@@ -375,6 +654,11 @@ export type ValidateSchemaHasId<S extends EvoluSchema> =
375
654
  : never
376
655
  : never;
377
656
 
657
+ /**
658
+ * Requires every `id` column output type to extend {@link Id}.
659
+ *
660
+ * @group Validation
661
+ */
378
662
  export type ValidateIdColumnType<S extends EvoluSchema> =
379
663
  keyof S extends infer TableName
380
664
  ? TableName extends keyof S
@@ -386,6 +670,11 @@ export type ValidateIdColumnType<S extends EvoluSchema> =
386
670
  : never
387
671
  : never;
388
672
 
673
+ /**
674
+ * Rejects tables that define system column names.
675
+ *
676
+ * @group Validation
677
+ */
389
678
  export type ValidateNoSystemColumns<S extends EvoluSchema> =
390
679
  keyof S extends infer TableName
391
680
  ? TableName extends keyof S
@@ -400,6 +689,11 @@ export type ValidateNoSystemColumns<S extends EvoluSchema> =
400
689
  : never
401
690
  : never;
402
691
 
692
+ /**
693
+ * Requires every column output type to be compatible with SQLite.
694
+ *
695
+ * @group Validation
696
+ */
403
697
  export type ValidateColumnTypes<S extends EvoluSchema> =
404
698
  keyof S extends infer TableName
405
699
  ? TableName extends keyof S
@@ -414,36 +708,69 @@ export type ValidateColumnTypes<S extends EvoluSchema> =
414
708
  : never
415
709
  : never;
416
710
 
417
- /** Schema validation error that shows clear, readable messages */
711
+ /**
712
+ * Schema validation error that shows clear, readable messages
713
+ *
714
+ * @group Validation
715
+ */
418
716
  export type SchemaValidationError<Message extends string> = CompileTimeError<
419
717
  "Schema",
420
718
  Message
421
719
  >;
422
720
 
423
- /** Makes columns whose output type includes `null` optional. */
721
+ /**
722
+ * Makes columns whose output type includes `null` optional.
723
+ *
724
+ * @group Mutations
725
+ */
424
726
  export type NullableColumnsToOptional<T extends TableSchema> = {
425
727
  readonly [K in RequiredColumnKeys<T>]: StandardSchemaV1.InferOutput<T[K]>;
426
728
  } & {
427
729
  readonly [K in OptionalColumnKeys<T>]?: StandardSchemaV1.InferOutput<T[K]>;
428
730
  };
429
731
 
732
+ /**
733
+ * Column names whose output type excludes `null`.
734
+ *
735
+ * @group Mutations
736
+ */
430
737
  export type RequiredColumnKeys<T extends TableSchema> = {
431
738
  [K in keyof T]: null extends StandardSchemaV1.InferOutput<T[K]> ? never : K;
432
739
  }[keyof T];
433
740
 
741
+ /**
742
+ * Column names whose output type includes `null`.
743
+ *
744
+ * @group Mutations
745
+ */
434
746
  export type OptionalColumnKeys<T extends TableSchema> = {
435
747
  [K in keyof T]: null extends StandardSchemaV1.InferOutput<T[K]> ? K : never;
436
748
  }[keyof T];
437
749
 
750
+ /**
751
+ * Names of {@link SystemColumns}.
752
+ *
753
+ * @group Core
754
+ */
438
755
  export const systemColumns: ReadonlySet<string> = /*#__PURE__*/ new Set(
439
756
  /*#__PURE__*/ Object.keys(SystemColumns.props),
440
757
  );
441
758
 
759
+ /**
760
+ * Names of {@link SystemColumns} together with `id`.
761
+ *
762
+ * @group Core
763
+ */
442
764
  export const systemColumnsWithId: ReadonlyArray<string> = [
443
765
  ...systemColumns,
444
766
  "id",
445
767
  ];
446
768
 
769
+ /**
770
+ * Derives {@link SqliteSchema} tables and indexes from an {@link EvoluSchema}.
771
+ *
772
+ * @group SQLite
773
+ */
447
774
  export const evoluSchemaToSqliteSchema = <S extends EvoluSchema>(
448
775
  schema: ValidateSchema<S> extends never ? S : ValidateSchema<S>,
449
776
  indexesConfig?: IndexesConfig,
@@ -480,24 +807,14 @@ export const evoluSchemaToSqliteSchema = <S extends EvoluSchema>(
480
807
  * import {
481
808
  * assertType,
482
809
  * createQueryBuilder,
483
- * id,
810
+ * testEvoluSchema,
811
+ * type TestTodoId,
484
812
  * NonEmptyTrimmedString100,
485
- * nullOr,
486
813
  * SqliteBoolean,
487
814
  * } from "@evolu/common";
488
815
  *
489
- * const TodoId = id("Todo");
490
- * type TodoId = typeof TodoId.Output;
491
- * const Schema = {
492
- * todo: {
493
- * id: TodoId,
494
- * title: NonEmptyTrimmedString100,
495
- * isCompleted: nullOr(SqliteBoolean),
496
- * },
497
- * };
498
- *
499
816
  * // Create one typed builder per schema and reuse it for every query.
500
- * const createQuery = createQueryBuilder(Schema);
817
+ * const createQuery = createQueryBuilder(testEvoluSchema);
501
818
  * const todosQuery = createQuery((db) =>
502
819
  * db.selectFrom("todo").select(["id", "title", "isCompleted"]),
503
820
  * );
@@ -505,12 +822,14 @@ export const evoluSchemaToSqliteSchema = <S extends EvoluSchema>(
505
822
  * assertType<
506
823
  * typeof todosQuery.Row,
507
824
  * {
508
- * id: TodoId;
825
+ * id: TestTodoId;
509
826
  * title: NonEmptyTrimmedString100 | null;
510
827
  * isCompleted: SqliteBoolean | null;
511
828
  * }
512
829
  * >();
513
830
  * ```
831
+ *
832
+ * @group Queries
514
833
  */
515
834
  export const createQueryBuilder = <S extends EvoluSchema>(
516
835
  _schema: S,
@@ -530,6 +849,12 @@ export const createQueryBuilder = <S extends EvoluSchema>(
530
849
  return createQuery;
531
850
  };
532
851
 
852
+ /**
853
+ * Creates missing tables, columns, and indexes, and drops indexes that the new
854
+ * schema no longer defines.
855
+ *
856
+ * @group SQLite
857
+ */
533
858
  export const ensureSqliteSchema =
534
859
  (deps: SqliteDep) =>
535
860
  (newSchema: SqliteSchema, currentSchema?: SqliteSchema): void => {
@@ -581,10 +906,24 @@ export const ensureSqliteSchema =
581
906
  }
582
907
  };
583
908
 
909
+ /**
910
+ * Reads the current application {@link SqliteSchema}, excluding Evolu's internal
911
+ * indexes.
912
+ *
913
+ * @group SQLite
914
+ */
584
915
  export const getEvoluSqliteSchema = (deps: SqliteDep) => (): SqliteSchema =>
585
916
  getSqliteSchema(deps)({ excludeIndexNamePrefix: "evolu_" });
586
917
 
587
- // https://kysely.dev/docs/recipes/splitting-query-building-and-execution
918
+ /**
919
+ * Kysely instance that only compiles queries to SQL. It never executes them;
920
+ * Evolu runs the compiled SQL itself.
921
+ *
922
+ * See [Splitting query building and
923
+ * execution](https://kysely.dev/docs/recipes/splitting-query-building-and-execution).
924
+ *
925
+ * @group Queries
926
+ */
588
927
  export const kysely = /*#__PURE__*/ new Kysely.Kysely({
589
928
  dialect: {
590
929
  createAdapter: () => new Kysely.SqliteAdapter(),