@evolu/common 8.10.0 → 8.12.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 (152) hide show
  1. package/dist/src/Bytes.d.ts +39 -2
  2. package/dist/src/Bytes.d.ts.map +1 -1
  3. package/dist/src/Bytes.js +50 -2
  4. package/dist/src/Config.d.ts +22 -22
  5. package/dist/src/Config.d.ts.map +1 -1
  6. package/dist/src/Console.d.ts +62 -7
  7. package/dist/src/Console.d.ts.map +1 -1
  8. package/dist/src/Console.js +20 -4
  9. package/dist/src/Crypto.d.ts +76 -4
  10. package/dist/src/Crypto.d.ts.map +1 -1
  11. package/dist/src/Crypto.js +55 -4
  12. package/dist/src/Error.d.ts +45 -0
  13. package/dist/src/Error.d.ts.map +1 -1
  14. package/dist/src/Error.js +69 -0
  15. package/dist/src/Fs.d.ts +92 -18
  16. package/dist/src/Fs.d.ts.map +1 -1
  17. package/dist/src/Fs.js +2 -0
  18. package/dist/src/Identicon.d.ts +2 -2
  19. package/dist/src/Identicon.js +2 -2
  20. package/dist/src/LeakDetector.d.ts +22 -3
  21. package/dist/src/LeakDetector.d.ts.map +1 -1
  22. package/dist/src/LeakDetector.js +12 -2
  23. package/dist/src/LockManager.d.ts +8 -0
  24. package/dist/src/LockManager.d.ts.map +1 -1
  25. package/dist/src/LockManager.js +6 -0
  26. package/dist/src/Object.d.ts.map +1 -1
  27. package/dist/src/Object.js +5 -0
  28. package/dist/src/Platform.d.ts +47 -7
  29. package/dist/src/Platform.d.ts.map +1 -1
  30. package/dist/src/Platform.js +24 -5
  31. package/dist/src/Random.d.ts +25 -2
  32. package/dist/src/Random.d.ts.map +1 -1
  33. package/dist/src/Random.js +14 -2
  34. package/dist/src/Resource.d.ts +156 -1
  35. package/dist/src/Resource.d.ts.map +1 -1
  36. package/dist/src/Resource.js +201 -72
  37. package/dist/src/Schedule.d.ts +11 -10
  38. package/dist/src/Schedule.d.ts.map +1 -1
  39. package/dist/src/Schedule.js +1 -1
  40. package/dist/src/Sqlite.d.ts +132 -16
  41. package/dist/src/Sqlite.d.ts.map +1 -1
  42. package/dist/src/Sqlite.js +63 -9
  43. package/dist/src/Task.d.ts +15 -4
  44. package/dist/src/Task.d.ts.map +1 -1
  45. package/dist/src/Task.js +41 -15
  46. package/dist/src/Test.d.ts +9 -0
  47. package/dist/src/Test.d.ts.map +1 -1
  48. package/dist/src/Test.js +4 -0
  49. package/dist/src/Time.d.ts +106 -9
  50. package/dist/src/Time.d.ts.map +1 -1
  51. package/dist/src/Time.js +55 -4
  52. package/dist/src/Type.d.ts +1455 -1310
  53. package/dist/src/Type.d.ts.map +1 -1
  54. package/dist/src/Type.js +1274 -517
  55. package/dist/src/WebSocket.d.ts +164 -13
  56. package/dist/src/WebSocket.d.ts.map +1 -1
  57. package/dist/src/WebSocket.js +133 -24
  58. package/dist/src/Worker.d.ts +90 -8
  59. package/dist/src/Worker.d.ts.map +1 -1
  60. package/dist/src/Worker.js +28 -2
  61. package/dist/src/index.d.ts +6 -7
  62. package/dist/src/index.d.ts.map +1 -1
  63. package/dist/src/index.js +2 -3
  64. package/dist/src/local-first/Db.d.ts +52 -3
  65. package/dist/src/local-first/Db.d.ts.map +1 -1
  66. package/dist/src/local-first/Db.js +412 -137
  67. package/dist/src/local-first/Evolu.d.ts +412 -213
  68. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  69. package/dist/src/local-first/Evolu.js +181 -18
  70. package/dist/src/local-first/Owner.d.ts +13 -30
  71. package/dist/src/local-first/Owner.d.ts.map +1 -1
  72. package/dist/src/local-first/Owner.js +13 -30
  73. package/dist/src/local-first/Protocol.d.ts +106 -19
  74. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  75. package/dist/src/local-first/Protocol.js +162 -60
  76. package/dist/src/local-first/Query.d.ts +8 -15
  77. package/dist/src/local-first/Query.d.ts.map +1 -1
  78. package/dist/src/local-first/Relay.d.ts.map +1 -1
  79. package/dist/src/local-first/Relay.js +4 -2
  80. package/dist/src/local-first/Schema.d.ts +346 -23
  81. package/dist/src/local-first/Schema.d.ts.map +1 -1
  82. package/dist/src/local-first/Schema.js +214 -17
  83. package/dist/src/local-first/Shared.d.ts +537 -22
  84. package/dist/src/local-first/Shared.d.ts.map +1 -1
  85. package/dist/src/local-first/Shared.js +1437 -234
  86. package/dist/src/local-first/Storage.d.ts +195 -17
  87. package/dist/src/local-first/Storage.d.ts.map +1 -1
  88. package/dist/src/local-first/Storage.js +85 -22
  89. package/dist/src/local-first/Timestamp.d.ts +392 -41
  90. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  91. package/dist/src/local-first/Timestamp.js +403 -81
  92. package/dist/src/local-first/index.d.ts +0 -1
  93. package/dist/src/local-first/index.d.ts.map +1 -1
  94. package/dist/src/local-first/index.js +0 -1
  95. package/package.json +1 -1
  96. package/src/Assert.test.ts +2 -5
  97. package/src/Bytes.test.ts +27 -0
  98. package/src/Bytes.ts +58 -2
  99. package/src/Config.test.ts +2 -6
  100. package/src/Config.ts +133 -133
  101. package/src/Console.ts +62 -7
  102. package/src/Crypto.ts +76 -4
  103. package/src/Eq.test.ts +2 -3
  104. package/src/Error.test.ts +76 -3
  105. package/src/Error.ts +71 -0
  106. package/src/Fs.ts +92 -18
  107. package/src/Identicon.ts +2 -2
  108. package/src/LeakDetector.ts +22 -3
  109. package/src/LockManager.ts +8 -0
  110. package/src/Object.test.ts +27 -12
  111. package/src/Object.ts +5 -0
  112. package/src/Platform.ts +50 -8
  113. package/src/Random.ts +25 -2
  114. package/src/Resource.test.ts +837 -0
  115. package/src/Resource.ts +235 -15
  116. package/src/Schedule.test.ts +50 -12
  117. package/src/Schedule.ts +24 -14
  118. package/src/Sqlite.ts +137 -17
  119. package/src/Task.test.ts +189 -8
  120. package/src/Task.ts +56 -17
  121. package/src/Test.ts +9 -0
  122. package/src/Time.ts +106 -9
  123. package/src/Type.test.ts +946 -1028
  124. package/src/Type.ts +4195 -3136
  125. package/src/Types.test.ts +4 -14
  126. package/src/WebSocket.ts +313 -40
  127. package/src/Worker.ts +90 -8
  128. package/src/index.ts +20 -6
  129. package/src/local-first/Db.ts +644 -339
  130. package/src/local-first/Evolu.test.ts +994 -22
  131. package/src/local-first/Evolu.ts +625 -232
  132. package/src/local-first/Owner.ts +13 -30
  133. package/src/local-first/Protocol.test.ts +634 -10
  134. package/src/local-first/Protocol.ts +255 -109
  135. package/src/local-first/Query.ts +8 -15
  136. package/src/local-first/Relay.ts +4 -2
  137. package/src/local-first/Schema.test.ts +143 -0
  138. package/src/local-first/Schema.ts +376 -26
  139. package/src/local-first/Shared.test.ts +7731 -559
  140. package/src/local-first/Shared.ts +2036 -267
  141. package/src/local-first/Storage.ts +224 -36
  142. package/src/local-first/Timestamp.test.ts +344 -70
  143. package/src/local-first/Timestamp.ts +434 -118
  144. package/src/local-first/index.ts +0 -1
  145. package/dist/src/local-first/Error.d.ts +0 -12
  146. package/dist/src/local-first/Error.d.ts.map +0 -1
  147. package/dist/src/local-first/Error.js +0 -6
  148. package/dist/src/local-first/LocalAuth.d.ts +0 -150
  149. package/dist/src/local-first/LocalAuth.d.ts.map +0 -1
  150. package/dist/src/local-first/LocalAuth.js +0 -179
  151. package/src/local-first/Error.ts +0 -17
  152. package/src/local-first/LocalAuth.ts +0 -457
package/src/Sqlite.ts CHANGED
@@ -40,6 +40,8 @@ import {
40
40
  * API is synchronous because it provides
41
41
  * {@link https://github.com/WiseLibs/better-sqlite3/issues/262 | better concurrency}
42
42
  * for SQLite.
43
+ *
44
+ * @group Core
43
45
  */
44
46
  export interface Sqlite extends AsyncDisposable {
45
47
  readonly exec: <R extends SqliteRow = SqliteRow>(
@@ -67,26 +69,48 @@ export interface Sqlite extends AsyncDisposable {
67
69
  readonly export: () => Uint8Array<ArrayBuffer>;
68
70
  }
69
71
 
72
+ /**
73
+ * Dependency wrapper for {@link Sqlite}.
74
+ *
75
+ * @group Core
76
+ */
70
77
  export interface SqliteDep {
71
78
  readonly sqlite: Sqlite;
72
79
  }
73
80
 
81
+ /**
82
+ * Runs a callback inside a SQLite transaction.
83
+ *
84
+ * @group Core
85
+ */
74
86
  export interface SqliteTransaction {
75
87
  <T, E>(callback: () => Result<T, E>): Result<T, E>;
76
88
  (callback: () => void): void;
77
89
  }
78
90
 
79
- /** Represents a SQL query to be executed on a {@link Sqlite} database. */
91
+ /**
92
+ * Represents a SQL query to be executed on a {@link Sqlite} database.
93
+ *
94
+ * @group Queries
95
+ */
80
96
  export interface SqliteQuery {
81
97
  readonly sql: SafeSql;
82
98
  readonly parameters: SqliteQueryParameters;
83
99
  readonly options?: SqliteQueryOptions;
84
100
  }
85
101
 
86
- /** Serialized {@link SqliteQuery} used as a stable string key. */
102
+ /**
103
+ * Serialized {@link SqliteQuery} used as a stable string key.
104
+ *
105
+ * @group Queries
106
+ */
87
107
  export type SqliteQueryString = string & Brand<"SqliteQueryString">;
88
108
 
89
- /** A sanitized SQL string for {@link SqliteQuery}. */
109
+ /**
110
+ * A sanitized SQL string for {@link SqliteQuery}.
111
+ *
112
+ * @group Queries
113
+ */
90
114
  export type SafeSql = string & Brand<"SafeSql">;
91
115
 
92
116
  /**
@@ -99,6 +123,8 @@ export type SafeSql = string & Brand<"SafeSql">;
99
123
  *
100
124
  * Note that Evolu can't support Int64 because expo-sqlite (and some others) do
101
125
  * not support it.
126
+ *
127
+ * @group Values
102
128
  */
103
129
  export const SqliteValue = /*#__PURE__*/ union(
104
130
  FiniteNumber,
@@ -108,7 +134,11 @@ export const SqliteValue = /*#__PURE__*/ union(
108
134
  );
109
135
  export type SqliteValue = typeof SqliteValue.Output;
110
136
 
111
- /** Parameters of a {@link SqliteQuery}. */
137
+ /**
138
+ * Parameters of a {@link SqliteQuery}.
139
+ *
140
+ * @group Queries
141
+ */
112
142
  export const SqliteQueryParameters = /*#__PURE__*/ array(SqliteValue);
113
143
  export type SqliteQueryParameters = typeof SqliteQueryParameters.Output;
114
144
 
@@ -118,14 +148,24 @@ export type SqliteQueryParameters = typeof SqliteQueryParameters.Output;
118
148
  *
119
149
  * It differs from {@link SqliteValue} only by using `number` instead of
120
150
  * {@link FiniteNumber}.
151
+ *
152
+ * @group Values
121
153
  */
122
154
  export type SqliteValueInput = typeof SqliteValue.Input;
123
155
 
124
- /** Equality comparison for {@link SqliteValueInput}. */
156
+ /**
157
+ * Equality comparison for {@link SqliteValueInput}.
158
+ *
159
+ * @group Values
160
+ */
125
161
  export const eqSqliteValue: Eq<SqliteValueInput> = (x, y) =>
126
162
  Uint8Array.is(x) && Uint8Array.is(y) ? eqUint8Array(x, y) : x === y;
127
163
 
128
- /** Options for configuring {@link SqliteQuery} execution behavior. */
164
+ /**
165
+ * Options for configuring {@link SqliteQuery} execution behavior.
166
+ *
167
+ * @group Queries
168
+ */
129
169
  export interface SqliteQueryOptions {
130
170
  /**
131
171
  * If set to `true`, logs the time taken to execute the SQL query. Useful for
@@ -152,7 +192,11 @@ export interface SqliteQueryOptions {
152
192
  readonly prepare?: boolean;
153
193
  }
154
194
 
155
- /** Converts a {@link SqliteQuery} into a stable {@link SqliteQueryString}. */
195
+ /**
196
+ * Converts a {@link SqliteQuery} into a stable {@link SqliteQueryString}.
197
+ *
198
+ * @group Queries
199
+ */
156
200
  export const sqliteQueryToSqliteQueryString = (
157
201
  query: SqliteQuery,
158
202
  ): SqliteQueryString => {
@@ -169,7 +213,11 @@ export const sqliteQueryToSqliteQueryString = (
169
213
  return JSON.stringify([query.sql, params, options]) as SqliteQueryString;
170
214
  };
171
215
 
172
- /** Converts a {@link SqliteQueryString} back into a {@link SqliteQuery}. */
216
+ /**
217
+ * Converts a {@link SqliteQueryString} back into a {@link SqliteQuery}.
218
+ *
219
+ * @group Queries
220
+ */
173
221
  export const sqliteQueryStringToSqliteQuery = (
174
222
  query: SqliteQueryString,
175
223
  ): SqliteQuery => {
@@ -196,15 +244,22 @@ export const sqliteQueryStringToSqliteQuery = (
196
244
  };
197
245
  };
198
246
 
199
- /** Result of executing a SQLite query. */
247
+ /**
248
+ * Result of executing a SQLite query.
249
+ *
250
+ * @group Queries
251
+ */
200
252
  export interface SqliteExecResult<R extends SqliteRow = SqliteRow> {
201
253
  readonly rows: ReadonlyArray<R>;
254
+ /** The number of rows an insert, update, or delete statement changed. */
202
255
  readonly changes: number;
203
256
  }
204
257
 
205
258
  /**
206
259
  * A row returned from a {@link Sqlite} query, mapping column names to
207
260
  * {@link SqliteValueInput}.
261
+ *
262
+ * @group Values
208
263
  */
209
264
  export type SqliteRow = Record<string, SqliteValueInput>;
210
265
 
@@ -212,6 +267,8 @@ export type SqliteRow = Record<string, SqliteValueInput>;
212
267
  * SQLite driver interface.
213
268
  *
214
269
  * Platform-specific drivers must implement this interface.
270
+ *
271
+ * @group Core
215
272
  */
216
273
  export interface SqliteDriver extends Disposable {
217
274
  readonly exec: (query: SqliteQuery) => SqliteExecResult;
@@ -228,12 +285,21 @@ export interface SqliteDriver extends Disposable {
228
285
  readonly export: () => Uint8Array<ArrayBuffer>;
229
286
  }
230
287
 
231
- /** Creates a {@link SqliteDriver}. */
288
+ /**
289
+ * Creates a {@link SqliteDriver}.
290
+ *
291
+ * @group Core
292
+ */
232
293
  export type CreateSqliteDriver = (
233
294
  name: Name,
234
295
  options?: SqliteDriverOptions,
235
296
  ) => Task<SqliteDriver>;
236
297
 
298
+ /**
299
+ * Dependency wrapper for {@link CreateSqliteDriver}.
300
+ *
301
+ * @group Core
302
+ */
237
303
  export interface CreateSqliteDriverDep {
238
304
  createSqliteDriver: CreateSqliteDriver;
239
305
  }
@@ -243,6 +309,8 @@ export interface CreateSqliteDriverDep {
243
309
  *
244
310
  * Three mutually exclusive modes: in-memory (for testing), encrypted persistent
245
311
  * (OPFS/file with encryption key), or persistent (default when omitted).
312
+ *
313
+ * @group Core
246
314
  */
247
315
  export type SqliteDriverOptions =
248
316
  | { readonly mode: "memory" }
@@ -253,6 +321,8 @@ export type SqliteDriverOptions =
253
321
  *
254
322
  * The driver is created via {@link CreateSqliteDriver} and wrapped with logging,
255
323
  * error handling, and transaction helpers.
324
+ *
325
+ * @group Core
256
326
  */
257
327
  export const createSqlite =
258
328
  (
@@ -330,7 +400,11 @@ export const createSqlite =
330
400
  );
331
401
  };
332
402
 
333
- /** Creates a test setup with a in-memory {@link Sqlite}. */
403
+ /**
404
+ * Creates a test setup with a in-memory {@link Sqlite}.
405
+ *
406
+ * @group Testing
407
+ */
334
408
  export const testSetupSqlite = async (
335
409
  deps: CreateSqliteDriverDep,
336
410
  ): Promise<
@@ -381,6 +455,8 @@ const drawSqliteQueryPlan = (rows: Array<SqliteQueryPlanRow>): string =>
381
455
  *
382
456
  * Statements are created on first access and reused for subsequent calls with
383
457
  * the same SQL. Disposing the cache finalizes all cached statements.
458
+ *
459
+ * @group Core
384
460
  */
385
461
  export interface PreparedStatements<P> extends Disposable {
386
462
  readonly get: <T extends boolean>(
@@ -392,6 +468,8 @@ export interface PreparedStatements<P> extends Disposable {
392
468
  /**
393
469
  * Creates a {@link PreparedStatements} cache backed by the given factory and
394
470
  * dispose function.
471
+ *
472
+ * @group Core
395
473
  */
396
474
  export const createPreparedStatementsCache = <P>(
397
475
  factory: (sql: SafeSql) => P,
@@ -428,7 +506,11 @@ export const createPreparedStatementsCache = <P>(
428
506
  );
429
507
  };
430
508
 
431
- /** A double-quoted SQL identifier for safe column or table name interpolation. */
509
+ /**
510
+ * A double-quoted SQL identifier for safe column or table name interpolation.
511
+ *
512
+ * @group Queries
513
+ */
432
514
  export interface SqlIdentifier extends Typed<"SqlIdentifier"> {
433
515
  readonly sql: SafeSql;
434
516
  }
@@ -437,12 +519,18 @@ export interface SqlIdentifier extends Typed<"SqlIdentifier"> {
437
519
  * An unescaped SQL fragment inserted verbatim into a query.
438
520
  *
439
521
  * **Warning**: Use only with trusted, constant strings to avoid SQL injection.
522
+ *
523
+ * @group Queries
440
524
  */
441
525
  export interface RawSql extends Typed<"RawSql"> {
442
526
  readonly sql: string;
443
527
  }
444
528
 
445
- /** A parameter accepted by the {@link sql} tagged template. */
529
+ /**
530
+ * A parameter accepted by the {@link sql} tagged template.
531
+ *
532
+ * @group Queries
533
+ */
446
534
  export type SqlTemplateParam = SqliteValueInput | SqlIdentifier | RawSql;
447
535
 
448
536
  /**
@@ -488,6 +576,8 @@ export type SqlTemplateParam = SqliteValueInput | SqlIdentifier | RawSql;
488
576
  * Use `prettier-plugin-sql-cst` for SQL formatting. Like Prettier for
489
577
  * JavaScript, this plugin formats SQL expressions differently depending on
490
578
  * their length.
579
+ *
580
+ * @group Queries
491
581
  */
492
582
  export const sql = (
493
583
  strings: TemplateStringsArray,
@@ -504,7 +594,9 @@ export const sql = (
504
594
  sql += param.sql;
505
595
  } else {
506
596
  sql += "?";
507
- values.push(SqliteValue.orThrow(param));
597
+ values.push(
598
+ typeof param === "number" ? FiniteNumber.orThrow(param) : param,
599
+ );
508
600
  }
509
601
  }
510
602
  }
@@ -535,14 +627,22 @@ sql.prepared = (
535
627
  return { ...query, options: { prepare: true } };
536
628
  };
537
629
 
538
- /** Index metadata stored in `sqlite_master` for a {@link Sqlite} database. */
630
+ /**
631
+ * Index metadata stored in `sqlite_master` for a {@link Sqlite} database.
632
+ *
633
+ * @group Schema
634
+ */
539
635
  export const SqliteIndex: ObjectType<{
540
636
  readonly name: typeof String;
541
637
  readonly sql: typeof String;
542
638
  }> = /*#__PURE__*/ object({ name: String, sql: String });
543
639
  export interface SqliteIndex extends InferType<typeof SqliteIndex> {}
544
640
 
545
- /** {@link Eq} instance for {@link SqliteIndex}. */
641
+ /**
642
+ * {@link Eq} instance for {@link SqliteIndex}.
643
+ *
644
+ * @group Schema
645
+ */
546
646
  export const eqSqliteIndex: Eq<SqliteIndex> = /*#__PURE__*/ createEqObject({
547
647
  name: eqString,
548
648
  sql: eqString,
@@ -552,6 +652,8 @@ export const eqSqliteIndex: Eq<SqliteIndex> = /*#__PURE__*/ createEqObject({
552
652
  * Full schema metadata for a {@link Sqlite} database.
553
653
  *
554
654
  * Includes table-column mappings and user-visible indexes.
655
+ *
656
+ * @group Schema
555
657
  */
556
658
  export const SqliteSchema: ObjectType<{
557
659
  readonly tables: RecordType<typeof String, SetType<typeof String>>;
@@ -562,7 +664,11 @@ export const SqliteSchema: ObjectType<{
562
664
  });
563
665
  export interface SqliteSchema extends InferType<typeof SqliteSchema> {}
564
666
 
565
- /** Get the current SQLite schema by reading SQLite metadata. */
667
+ /**
668
+ * Get the current SQLite schema by reading SQLite metadata.
669
+ *
670
+ * @group Schema
671
+ */
566
672
  export const getSqliteSchema =
567
673
  (deps: SqliteDep) =>
568
674
  ({
@@ -627,6 +733,8 @@ export const getSqliteSchema =
627
733
  /**
628
734
  * Returns {@link SqliteSchema} and full {@link SqliteRow} table contents for
629
735
  * inspection and testing.
736
+ *
737
+ * @group Schema
630
738
  */
631
739
  export interface SqliteSnapshot {
632
740
  readonly schema: SqliteSchema;
@@ -641,6 +749,8 @@ export interface SqliteSnapshot {
641
749
  *
642
750
  * The snapshot includes current {@link SqliteSchema} and all rows from every
643
751
  * discovered table. Table order follows `schema.tables` iteration order.
752
+ *
753
+ * @group Schema
644
754
  */
645
755
  export const getSqliteSnapshot = (deps: SqliteDep): SqliteSnapshot => {
646
756
  const schema = getSqliteSchema(deps)();
@@ -671,6 +781,8 @@ export const getSqliteSnapshot = (deps: SqliteDep): SqliteSnapshot => {
671
781
  * readability.
672
782
  * - Use {@link booleanToSqliteBoolean} and {@link sqliteBooleanToBoolean} for
673
783
  * converting between JavaScript booleans and SQLite boolean values.
784
+ *
785
+ * @group Values
674
786
  */
675
787
  export const SqliteBoolean = /*#__PURE__*/ union(0, 1);
676
788
  export type SqliteBoolean = typeof SqliteBoolean.Output;
@@ -679,6 +791,8 @@ export type SqliteBoolean = typeof SqliteBoolean.Output;
679
791
  * Represents the {@link SqliteBoolean} value for `true`.
680
792
  *
681
793
  * See {@link SqliteBoolean}.
794
+ *
795
+ * @group Values
682
796
  */
683
797
  export const sqliteTrue = 1;
684
798
 
@@ -686,6 +800,8 @@ export const sqliteTrue = 1;
686
800
  * Represents the {@link SqliteBoolean} value for `false`.
687
801
  *
688
802
  * See {@link SqliteBoolean}.
803
+ *
804
+ * @group Values
689
805
  */
690
806
  export const sqliteFalse = 0;
691
807
 
@@ -699,6 +815,8 @@ export const sqliteFalse = 0;
699
815
  *
700
816
  * assertEqual(booleanToSqliteBoolean(true), 1);
701
817
  * ```
818
+ *
819
+ * @group Values
702
820
  */
703
821
  export const booleanToSqliteBoolean = (value: boolean): SqliteBoolean =>
704
822
  value ? sqliteTrue : sqliteFalse;
@@ -713,6 +831,8 @@ export const booleanToSqliteBoolean = (value: boolean): SqliteBoolean =>
713
831
  *
714
832
  * assertTrue(sqliteBooleanToBoolean(1));
715
833
  * ```
834
+ *
835
+ * @group Values
716
836
  */
717
837
  export const sqliteBooleanToBoolean = (value: SqliteBoolean): boolean =>
718
838
  value === sqliteTrue;
package/src/Task.test.ts CHANGED
@@ -521,16 +521,10 @@ describe("Run", () => {
521
521
  const userFiber = run(loadUser);
522
522
 
523
523
  assertType<typeof userFiber, Fiber<string, never>>();
524
- const compileTimeAssertions = () => {
524
+ void (() => {
525
525
  // oxlint-disable-next-line typescript/no-floating-promises -- Verifies that a Fiber must be handled or explicitly discarded with void.
526
526
  run(loadUser);
527
- };
528
- assertType<
529
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
530
- ? true
531
- : false,
532
- true
533
- >();
527
+ });
534
528
  assertNotUndefined(childRun);
535
529
  assertFalse(Object.is(childRun, run));
536
530
  assertSame(userFiber.run, childRun);
@@ -1673,6 +1667,124 @@ describe("Run", () => {
1673
1667
  });
1674
1668
 
1675
1669
  describe("state", () => {
1670
+ for (const action of ["abort", "dispose", "panic"] as const) {
1671
+ it(`publishes ancestor shutdown before descendant callbacks on ${action}`, async () => {
1672
+ await using run = testCreateRun();
1673
+ await using owner = run.create();
1674
+ const continueTask = Promise.withResolvers<void>();
1675
+ let statesDuringAbort: Array<ReturnType<Run["getState"]>> = [];
1676
+ let snapshotsDuringAbort: Array<RunSnapshot> = [];
1677
+ let signalsDuringAbort: Array<boolean> = [];
1678
+ let rootStateDuringAbort: ReturnType<Run["getState"]> | undefined;
1679
+ using _onAbort = run.onAbort(() => {
1680
+ rootStateDuringAbort = run.getState();
1681
+ });
1682
+ const fiber = owner(async (childRun) => {
1683
+ using _onAbort = childRun.onAbort(() => {
1684
+ const runs = [run, owner, childRun];
1685
+ statesDuringAbort = runs.map((run) => run.getState());
1686
+ snapshotsDuringAbort = runs.map((run) => run.snapshot());
1687
+ signalsDuringAbort = runs.map((run) => run.signal.aborted);
1688
+ });
1689
+ await continueTask.promise;
1690
+ return ok();
1691
+ });
1692
+
1693
+ try {
1694
+ if (action === "abort") run.abort(testAbortReason);
1695
+ else if (action === "dispose") run[Symbol.dispose]();
1696
+ else run.panic(new Error("shutdown"));
1697
+
1698
+ const abortError: unknown = run.signal.reason;
1699
+ assertType(AbortError, abortError);
1700
+ assertLength(statesDuringAbort, 3);
1701
+ assertLength(snapshotsDuringAbort, 3);
1702
+ for (const [index, state] of statesDuringAbort.entries()) {
1703
+ assertSame(state.type, "Aborted");
1704
+ assertSame(state.abort.request, abortError.reason);
1705
+ assertSame(
1706
+ state.abort.observed,
1707
+ index === 2 ? abortError.reason : null,
1708
+ );
1709
+ assertSame(snapshotsDuringAbort[index]?.state, state);
1710
+ }
1711
+ assertEqual(signalsDuringAbort, [false, false, true]);
1712
+ assertNotUndefined(rootStateDuringAbort);
1713
+ assertSame(rootStateDuringAbort.type, "Aborted");
1714
+ assertSame(rootStateDuringAbort.abort.request, abortError.reason);
1715
+ assertSame(rootStateDuringAbort.abort.observed, abortError.reason);
1716
+ } finally {
1717
+ continueTask.resolve();
1718
+ assertOk(await fiber, undefined);
1719
+ }
1720
+ });
1721
+ }
1722
+
1723
+ it("publishes masked disposal without replacing the earlier abort request", async () => {
1724
+ await using run = testCreateRun();
1725
+ const continueTask = Promise.withResolvers<void>();
1726
+ let stateDuringAbort: ReturnType<Run["getState"]> | undefined;
1727
+ const fiber = run.abortable(
1728
+ unabortable(async (run) => {
1729
+ // Keep the callback through normal Task finalization.
1730
+ run.onAbort(() => {
1731
+ stateDuringAbort = run.getState();
1732
+ });
1733
+ await continueTask.promise;
1734
+ return ok();
1735
+ }),
1736
+ );
1737
+
1738
+ try {
1739
+ fiber.abort(testAbortReason);
1740
+ assertSame(stateDuringAbort, undefined);
1741
+ assertEqual(fiber.run.getState(), {
1742
+ type: "Aborted",
1743
+ abort: { request: testAbortReason, observed: null },
1744
+ });
1745
+ } finally {
1746
+ continueTask.resolve();
1747
+ }
1748
+
1749
+ assertOk(await fiber, undefined);
1750
+ assertEqual(stateDuringAbort, {
1751
+ type: "Aborted",
1752
+ abort: { request: testAbortReason, observed: runDisposedAbortReason },
1753
+ });
1754
+ });
1755
+
1756
+ it("preserves the state published by reentrant disposal during propagation", async () => {
1757
+ await using run = testCreateRun();
1758
+ await using owner = run.create();
1759
+ const continueTask = Promise.withResolvers<void>();
1760
+ let stateDuringAbort: ReturnType<Run["getState"]> | undefined;
1761
+ using _onAbort = owner.onAbort(() => {
1762
+ stateDuringAbort = owner.getState();
1763
+ });
1764
+ const fiber = owner(async (run) => {
1765
+ using _onAbort = run.onAbort(() => {
1766
+ owner[Symbol.dispose]();
1767
+ });
1768
+ await continueTask.promise;
1769
+ return ok();
1770
+ });
1771
+
1772
+ try {
1773
+ run.abort(testAbortReason);
1774
+ assertEqual(stateDuringAbort, {
1775
+ type: "Aborted",
1776
+ abort: { request: testAbortReason, observed: runDisposedAbortReason },
1777
+ });
1778
+ assertSame(owner.getState(), stateDuringAbort);
1779
+ const abortError: unknown = owner.signal.reason;
1780
+ assertType(AbortError, abortError);
1781
+ assertSame(abortError.reason, runDisposedAbortReason);
1782
+ } finally {
1783
+ continueTask.resolve();
1784
+ assertOk(await fiber, undefined);
1785
+ }
1786
+ });
1787
+
1676
1788
  it("new Run starts in Running state", async () => {
1677
1789
  await using run = createRun();
1678
1790
 
@@ -1967,6 +2079,75 @@ describe("Run", () => {
1967
2079
  });
1968
2080
 
1969
2081
  describe("event reporting", () => {
2082
+ it("emits one abort state event when a descendant disposes its owner", async () => {
2083
+ await using run = testCreateRun({
2084
+ runConfig: { eventsEnabled: createRef(true) },
2085
+ });
2086
+ await using owner = run.create();
2087
+ const states: Array<ReturnType<Run["getState"]>> = [];
2088
+ owner.onEvent = (event) => {
2089
+ if (event.id === owner.id && event.data.type === "StateChanged")
2090
+ states.push(event.data.state);
2091
+ };
2092
+ const continueTask = Promise.withResolvers<void>();
2093
+ const fiber = owner(async (childRun) => {
2094
+ using _onAbort = childRun.onAbort(() => {
2095
+ owner[Symbol.dispose]();
2096
+ });
2097
+ await continueTask.promise;
2098
+ return ok();
2099
+ });
2100
+
2101
+ try {
2102
+ run.abort(testAbortReason);
2103
+ assertLength(states, 1);
2104
+ assertSame(states[0], owner.getState());
2105
+ } finally {
2106
+ continueTask.resolve();
2107
+ assertOk(await fiber, undefined);
2108
+ }
2109
+
2110
+ await owner[Symbol.asyncDispose]();
2111
+ assertEqual(
2112
+ states.map((state) => state.type),
2113
+ ["Aborted", "Settled"],
2114
+ );
2115
+ assertSame(states[1], owner.getState());
2116
+ });
2117
+
2118
+ it("emits abort state after local callbacks when a callback disposes the Run", async () => {
2119
+ await using run = testCreateRun({
2120
+ runConfig: { eventsEnabled: createRef(true) },
2121
+ });
2122
+ await using owner = run.create();
2123
+ const events: Array<string> = [];
2124
+ owner.onEvent = (event) => {
2125
+ if (
2126
+ event.id === owner.id &&
2127
+ event.data.type === "StateChanged" &&
2128
+ event.data.state.type === "Aborted"
2129
+ )
2130
+ events.push("StateChanged");
2131
+ };
2132
+ using _first = owner.onAbort(() => {
2133
+ events.push("first callback starts");
2134
+ owner[Symbol.dispose]();
2135
+ events.push("first callback ends");
2136
+ });
2137
+ using _second = owner.onAbort(() => {
2138
+ events.push("second callback");
2139
+ });
2140
+
2141
+ run.abort(testAbortReason);
2142
+
2143
+ assertEqual(events, [
2144
+ "first callback starts",
2145
+ "first callback ends",
2146
+ "second callback",
2147
+ "StateChanged",
2148
+ ]);
2149
+ });
2150
+
1970
2151
  it("emits Run events only while eventsEnabled is true", async () => {
1971
2152
  const eventsEnabled = createRef(false);
1972
2153
  await using run = testCreateRun({ runConfig: { eventsEnabled } });