@powersync/common 1.53.2 → 1.55.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 (221) hide show
  1. package/dist/bundle.cjs +922 -772
  2. package/dist/bundle.cjs.map +1 -1
  3. package/dist/bundle.mjs +922 -772
  4. package/dist/bundle.mjs.map +1 -1
  5. package/dist/bundle.node.cjs +923 -619
  6. package/dist/bundle.node.cjs.map +1 -1
  7. package/dist/bundle.node.mjs +923 -619
  8. package/dist/bundle.node.mjs.map +1 -1
  9. package/dist/index.d.cts +749 -205
  10. package/lib/attachments/AttachmentContext.d.ts +7 -6
  11. package/lib/attachments/AttachmentContext.js +2 -1
  12. package/lib/attachments/AttachmentContext.js.map +1 -1
  13. package/lib/attachments/AttachmentErrorHandler.d.ts +6 -6
  14. package/lib/attachments/AttachmentQueue.d.ts +82 -33
  15. package/lib/attachments/AttachmentQueue.js +16 -18
  16. package/lib/attachments/AttachmentQueue.js.map +1 -1
  17. package/lib/attachments/LocalStorageAdapter.d.ts +14 -8
  18. package/lib/attachments/LocalStorageAdapter.js +3 -0
  19. package/lib/attachments/LocalStorageAdapter.js.map +1 -1
  20. package/lib/attachments/RemoteStorageAdapter.d.ts +4 -4
  21. package/lib/attachments/Schema.d.ts +12 -4
  22. package/lib/attachments/Schema.js +8 -3
  23. package/lib/attachments/Schema.js.map +1 -1
  24. package/lib/attachments/WatchedAttachmentItem.d.ts +3 -1
  25. package/lib/client/AbstractPowerSyncDatabase.d.ts +110 -60
  26. package/lib/client/AbstractPowerSyncDatabase.js +77 -74
  27. package/lib/client/AbstractPowerSyncDatabase.js.map +1 -1
  28. package/lib/client/AbstractPowerSyncOpenFactory.d.ts +6 -0
  29. package/lib/client/AbstractPowerSyncOpenFactory.js +3 -0
  30. package/lib/client/AbstractPowerSyncOpenFactory.js.map +1 -1
  31. package/lib/client/ConnectionManager.d.ts +4 -1
  32. package/lib/client/ConnectionManager.js +1 -1
  33. package/lib/client/ConnectionManager.js.map +1 -1
  34. package/lib/client/Query.d.ts +9 -0
  35. package/lib/client/SQLOpenFactory.d.ts +12 -0
  36. package/lib/client/SQLOpenFactory.js +6 -0
  37. package/lib/client/SQLOpenFactory.js.map +1 -1
  38. package/lib/client/compilableQueryWatch.d.ts +6 -0
  39. package/lib/client/compilableQueryWatch.js +3 -0
  40. package/lib/client/compilableQueryWatch.js.map +1 -1
  41. package/lib/client/connection/PowerSyncBackendConnector.d.ts +3 -0
  42. package/lib/client/connection/PowerSyncCredentials.d.ts +3 -0
  43. package/lib/client/constants.d.ts +3 -0
  44. package/lib/client/constants.js +3 -0
  45. package/lib/client/constants.js.map +1 -1
  46. package/lib/client/runOnSchemaChange.d.ts +3 -0
  47. package/lib/client/runOnSchemaChange.js +3 -0
  48. package/lib/client/runOnSchemaChange.js.map +1 -1
  49. package/lib/client/sync/bucket/BucketStorageAdapter.d.ts +12 -0
  50. package/lib/client/sync/bucket/BucketStorageAdapter.js +6 -0
  51. package/lib/client/sync/bucket/BucketStorageAdapter.js.map +1 -1
  52. package/lib/client/sync/bucket/CrudBatch.d.ts +2 -0
  53. package/lib/client/sync/bucket/CrudBatch.js +2 -0
  54. package/lib/client/sync/bucket/CrudBatch.js.map +1 -1
  55. package/lib/client/sync/bucket/CrudEntry.d.ts +9 -0
  56. package/lib/client/sync/bucket/CrudEntry.js +4 -0
  57. package/lib/client/sync/bucket/CrudEntry.js.map +1 -1
  58. package/lib/client/sync/bucket/CrudTransaction.d.ts +3 -0
  59. package/lib/client/sync/bucket/CrudTransaction.js +3 -0
  60. package/lib/client/sync/bucket/CrudTransaction.js.map +1 -1
  61. package/lib/client/sync/bucket/SqliteBucketStorage.d.ts +3 -0
  62. package/lib/client/sync/bucket/SqliteBucketStorage.js +3 -0
  63. package/lib/client/sync/bucket/SqliteBucketStorage.js.map +1 -1
  64. package/lib/client/sync/stream/AbstractRemote.d.ts +30 -1
  65. package/lib/client/sync/stream/AbstractRemote.js +59 -27
  66. package/lib/client/sync/stream/AbstractRemote.js.map +1 -1
  67. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.d.ts +55 -5
  68. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +32 -4
  69. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js.map +1 -1
  70. package/lib/client/sync/stream/JsonValue.d.ts +3 -0
  71. package/lib/client/sync/stream/WebsocketClientTransport.js +2 -1
  72. package/lib/client/sync/stream/WebsocketClientTransport.js.map +1 -1
  73. package/lib/client/sync/sync-streams.d.ts +22 -7
  74. package/lib/client/triggers/TriggerManager.d.ts +19 -18
  75. package/lib/client/triggers/TriggerManager.js +2 -1
  76. package/lib/client/triggers/TriggerManager.js.map +1 -1
  77. package/lib/client/triggers/TriggerManagerImpl.d.ts +1 -1
  78. package/lib/client/triggers/TriggerManagerImpl.js +3 -3
  79. package/lib/client/triggers/TriggerManagerImpl.js.map +1 -1
  80. package/lib/client/triggers/sanitizeSQL.d.ts +4 -0
  81. package/lib/client/triggers/sanitizeSQL.js +4 -0
  82. package/lib/client/triggers/sanitizeSQL.js.map +1 -1
  83. package/lib/client/watched/GetAllQuery.d.ts +4 -0
  84. package/lib/client/watched/GetAllQuery.js +2 -0
  85. package/lib/client/watched/GetAllQuery.js.map +1 -1
  86. package/lib/client/watched/WatchedQuery.d.ts +24 -2
  87. package/lib/client/watched/WatchedQuery.js +9 -0
  88. package/lib/client/watched/WatchedQuery.js.map +1 -1
  89. package/lib/client/watched/processors/AbstractQueryProcessor.d.ts +1 -1
  90. package/lib/client/watched/processors/AbstractQueryProcessor.js.map +1 -1
  91. package/lib/client/watched/processors/DifferentialQueryProcessor.d.ts +20 -0
  92. package/lib/client/watched/processors/DifferentialQueryProcessor.js +4 -0
  93. package/lib/client/watched/processors/DifferentialQueryProcessor.js.map +1 -1
  94. package/lib/client/watched/processors/OnChangeQueryProcessor.d.ts +4 -0
  95. package/lib/client/watched/processors/OnChangeQueryProcessor.js.map +1 -1
  96. package/lib/client/watched/processors/comparators.d.ts +8 -0
  97. package/lib/client/watched/processors/comparators.js +4 -0
  98. package/lib/client/watched/processors/comparators.js.map +1 -1
  99. package/lib/db/ConnectionClosedError.d.ts +2 -0
  100. package/lib/db/ConnectionClosedError.js +2 -0
  101. package/lib/db/ConnectionClosedError.js.map +1 -1
  102. package/lib/db/DBAdapter.d.ts +56 -6
  103. package/lib/db/DBAdapter.js +15 -3
  104. package/lib/db/DBAdapter.js.map +1 -1
  105. package/lib/db/crud/SyncProgress.d.ts +6 -1
  106. package/lib/db/crud/SyncProgress.js +2 -0
  107. package/lib/db/crud/SyncProgress.js.map +1 -1
  108. package/lib/db/crud/SyncStatus.d.ts +36 -38
  109. package/lib/db/crud/SyncStatus.js +19 -14
  110. package/lib/db/crud/SyncStatus.js.map +1 -1
  111. package/lib/db/crud/UploadQueueStatus.d.ts +3 -0
  112. package/lib/db/crud/UploadQueueStatus.js +3 -0
  113. package/lib/db/crud/UploadQueueStatus.js.map +1 -1
  114. package/lib/db/schema/Column.d.ts +28 -0
  115. package/lib/db/schema/Column.js +16 -3
  116. package/lib/db/schema/Column.js.map +1 -1
  117. package/lib/db/schema/Index.d.ts +9 -0
  118. package/lib/db/schema/Index.js +6 -0
  119. package/lib/db/schema/Index.js.map +1 -1
  120. package/lib/db/schema/IndexedColumn.d.ts +9 -0
  121. package/lib/db/schema/IndexedColumn.js +6 -0
  122. package/lib/db/schema/IndexedColumn.js.map +1 -1
  123. package/lib/db/schema/RawTable.d.ts +7 -1
  124. package/lib/db/schema/Schema.d.ts +6 -1
  125. package/lib/db/schema/Schema.js +3 -1
  126. package/lib/db/schema/Schema.js.map +1 -1
  127. package/lib/db/schema/Table.d.ts +27 -3
  128. package/lib/db/schema/Table.js +9 -0
  129. package/lib/db/schema/Table.js.map +1 -1
  130. package/lib/db/schema/TableV2.d.ts +2 -0
  131. package/lib/db/schema/TableV2.js +2 -0
  132. package/lib/db/schema/TableV2.js.map +1 -1
  133. package/lib/index.d.ts +1 -1
  134. package/lib/types/types.d.ts +6 -0
  135. package/lib/utils/AbortOperation.d.ts +2 -0
  136. package/lib/utils/AbortOperation.js +2 -0
  137. package/lib/utils/AbortOperation.js.map +1 -1
  138. package/lib/utils/BaseObserver.d.ts +12 -0
  139. package/lib/utils/BaseObserver.js +3 -0
  140. package/lib/utils/BaseObserver.js.map +1 -1
  141. package/lib/utils/ControlledExecutor.d.ts +6 -0
  142. package/lib/utils/ControlledExecutor.js +3 -0
  143. package/lib/utils/ControlledExecutor.js.map +1 -1
  144. package/lib/utils/Logger.d.ts +9 -0
  145. package/lib/utils/Logger.js +6 -0
  146. package/lib/utils/Logger.js.map +1 -1
  147. package/lib/utils/async.d.ts +26 -0
  148. package/lib/utils/async.js +114 -27
  149. package/lib/utils/async.js.map +1 -1
  150. package/lib/utils/compatibility.d.ts +8 -0
  151. package/lib/utils/compatibility.js +9 -0
  152. package/lib/utils/compatibility.js.map +1 -0
  153. package/lib/utils/mutex.d.ts +8 -0
  154. package/lib/utils/mutex.js +3 -0
  155. package/lib/utils/mutex.js.map +1 -1
  156. package/lib/utils/parseQuery.d.ts +6 -0
  157. package/lib/utils/parseQuery.js +3 -0
  158. package/lib/utils/parseQuery.js.map +1 -1
  159. package/lib/utils/stream_transform.d.ts +3 -1
  160. package/lib/utils/stream_transform.js.map +1 -1
  161. package/package.json +3 -3
  162. package/src/attachments/AttachmentContext.ts +7 -6
  163. package/src/attachments/AttachmentErrorHandler.ts +6 -6
  164. package/src/attachments/AttachmentQueue.ts +93 -35
  165. package/src/attachments/LocalStorageAdapter.ts +14 -8
  166. package/src/attachments/README.md +2 -0
  167. package/src/attachments/RemoteStorageAdapter.ts +4 -4
  168. package/src/attachments/Schema.ts +12 -4
  169. package/src/attachments/WatchedAttachmentItem.ts +3 -1
  170. package/src/client/AbstractPowerSyncDatabase.ts +135 -91
  171. package/src/client/AbstractPowerSyncOpenFactory.ts +6 -0
  172. package/src/client/ConnectionManager.ts +4 -1
  173. package/src/client/Query.ts +9 -0
  174. package/src/client/SQLOpenFactory.ts +12 -0
  175. package/src/client/compilableQueryWatch.ts +6 -0
  176. package/src/client/connection/PowerSyncBackendConnector.ts +3 -0
  177. package/src/client/connection/PowerSyncCredentials.ts +3 -0
  178. package/src/client/constants.ts +3 -0
  179. package/src/client/runOnSchemaChange.ts +3 -0
  180. package/src/client/sync/bucket/BucketStorageAdapter.ts +12 -0
  181. package/src/client/sync/bucket/CrudBatch.ts +2 -0
  182. package/src/client/sync/bucket/CrudEntry.ts +9 -0
  183. package/src/client/sync/bucket/CrudTransaction.ts +3 -0
  184. package/src/client/sync/bucket/SqliteBucketStorage.ts +3 -0
  185. package/src/client/sync/stream/AbstractRemote.ts +76 -34
  186. package/src/client/sync/stream/AbstractStreamingSyncImplementation.ts +55 -5
  187. package/src/client/sync/stream/JsonValue.ts +3 -0
  188. package/src/client/sync/stream/WebsocketClientTransport.ts +3 -1
  189. package/src/client/sync/sync-streams.ts +22 -9
  190. package/src/client/triggers/TriggerManager.ts +19 -18
  191. package/src/client/triggers/TriggerManagerImpl.ts +5 -5
  192. package/src/client/triggers/sanitizeSQL.ts +5 -0
  193. package/src/client/watched/GetAllQuery.ts +5 -1
  194. package/src/client/watched/WatchedQuery.ts +24 -2
  195. package/src/client/watched/processors/AbstractQueryProcessor.ts +6 -6
  196. package/src/client/watched/processors/DifferentialQueryProcessor.ts +28 -5
  197. package/src/client/watched/processors/OnChangeQueryProcessor.ts +9 -3
  198. package/src/client/watched/processors/comparators.ts +8 -0
  199. package/src/db/ConnectionClosedError.ts +2 -0
  200. package/src/db/DBAdapter.ts +58 -6
  201. package/src/db/crud/SyncProgress.ts +6 -1
  202. package/src/db/crud/SyncStatus.ts +40 -21
  203. package/src/db/crud/UploadQueueStatus.ts +3 -0
  204. package/src/db/schema/Column.ts +28 -3
  205. package/src/db/schema/Index.ts +9 -0
  206. package/src/db/schema/IndexedColumn.ts +9 -0
  207. package/src/db/schema/RawTable.ts +7 -1
  208. package/src/db/schema/Schema.ts +8 -3
  209. package/src/db/schema/Table.ts +30 -5
  210. package/src/db/schema/TableV2.ts +2 -0
  211. package/src/index.ts +1 -1
  212. package/src/types/types.ts +6 -0
  213. package/src/utils/AbortOperation.ts +2 -0
  214. package/src/utils/BaseObserver.ts +12 -0
  215. package/src/utils/ControlledExecutor.ts +6 -0
  216. package/src/utils/Logger.ts +9 -0
  217. package/src/utils/async.ts +136 -28
  218. package/src/utils/compatibility.ts +9 -0
  219. package/src/utils/mutex.ts +12 -0
  220. package/src/utils/parseQuery.ts +6 -0
  221. package/src/utils/stream_transform.ts +3 -1
package/dist/bundle.cjs CHANGED
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
- // https://www.sqlite.org/lang_expr.html#castexpr
3
+ /**
4
+ * @see https://www.sqlite.org/lang_expr.html#castexpr
5
+ * @public
6
+ */
4
7
  exports.ColumnType = void 0;
5
8
  (function (ColumnType) {
6
9
  ColumnType["TEXT"] = "TEXT";
@@ -16,14 +19,24 @@ const integer = {
16
19
  const real = {
17
20
  type: exports.ColumnType.REAL
18
21
  };
19
- // powersync-sqlite-core limits the number of column per table to 1999, due to internal SQLite limits.
20
- // In earlier versions this was limited to 63.
22
+ /**
23
+ * powersync-sqlite-core limits the number of column per table to 1999, due to internal SQLite limits.
24
+ * In earlier versions this was limited to 63.
25
+ *
26
+ * @internal
27
+ */
21
28
  const MAX_AMOUNT_OF_COLUMNS = 1999;
29
+ /**
30
+ * @public
31
+ */
22
32
  const column = {
23
33
  text,
24
34
  integer,
25
35
  real
26
36
  };
37
+ /**
38
+ * @public
39
+ */
27
40
  class Column {
28
41
  options;
29
42
  constructor(options) {
@@ -43,9 +56,15 @@ class Column {
43
56
  }
44
57
  }
45
58
 
59
+ /**
60
+ * @internal
61
+ */
46
62
  const DEFAULT_INDEX_COLUMN_OPTIONS = {
47
63
  ascending: true
48
64
  };
65
+ /**
66
+ * @public
67
+ */
49
68
  class IndexedColumn {
50
69
  options;
51
70
  static createAscending(column) {
@@ -72,9 +91,15 @@ class IndexedColumn {
72
91
  }
73
92
  }
74
93
 
94
+ /**
95
+ * @internal
96
+ */
75
97
  const DEFAULT_INDEX_OPTIONS = {
76
98
  columns: []
77
99
  };
100
+ /**
101
+ * @public
102
+ */
78
103
  class Index {
79
104
  options;
80
105
  static createAscending(options, columnNames) {
@@ -116,6 +141,9 @@ function encodeTableOptions(options) {
116
141
  };
117
142
  }
118
143
 
144
+ /**
145
+ * @internal
146
+ */
119
147
  const DEFAULT_TABLE_OPTIONS = {
120
148
  indexes: [],
121
149
  insertOnly: false,
@@ -124,7 +152,13 @@ const DEFAULT_TABLE_OPTIONS = {
124
152
  trackMetadata: false,
125
153
  ignoreEmptyUpdates: false
126
154
  };
155
+ /**
156
+ * @internal
157
+ */
127
158
  const InvalidSQLCharacters = /["'%,.#\s[\]]/;
159
+ /**
160
+ * @public
161
+ */
128
162
  class Table {
129
163
  options;
130
164
  _mappedColumns;
@@ -315,6 +349,11 @@ class Table {
315
349
  }
316
350
  }
317
351
 
352
+ /**
353
+ * The default name of the local table storing attachment data.
354
+ *
355
+ * @alpha
356
+ */
318
357
  const ATTACHMENT_TABLE = 'attachments';
319
358
  /**
320
359
  * Maps a database row to an AttachmentRecord.
@@ -322,7 +361,7 @@ const ATTACHMENT_TABLE = 'attachments';
322
361
  * @param row - The database row object
323
362
  * @returns The corresponding AttachmentRecord
324
363
  *
325
- * @experimental
364
+ * @alpha
326
365
  */
327
366
  function attachmentFromSql(row) {
328
367
  return {
@@ -340,7 +379,7 @@ function attachmentFromSql(row) {
340
379
  /**
341
380
  * AttachmentState represents the current synchronization state of an attachment.
342
381
  *
343
- * @experimental
382
+ * @alpha
344
383
  */
345
384
  exports.AttachmentState = void 0;
346
385
  (function (AttachmentState) {
@@ -353,7 +392,7 @@ exports.AttachmentState = void 0;
353
392
  /**
354
393
  * AttachmentTable defines the schema for the attachment queue table.
355
394
  *
356
- * @internal
395
+ * @alpha
357
396
  */
358
397
  class AttachmentTable extends Table {
359
398
  constructor(options) {
@@ -381,7 +420,8 @@ class AttachmentTable extends Table {
381
420
  * Provides methods to query, insert, update, and delete attachment records with
382
421
  * proper transaction management through PowerSync.
383
422
  *
384
- * @internal
423
+ * @experimental
424
+ * @alpha
385
425
  */
386
426
  class AttachmentContext {
387
427
  /** PowerSync database instance for executing queries */
@@ -603,6 +643,9 @@ class AttachmentContext {
603
643
  }
604
644
  }
605
645
 
646
+ /**
647
+ * @public
648
+ */
606
649
  exports.WatchedQueryListenerEvent = void 0;
607
650
  (function (WatchedQueryListenerEvent) {
608
651
  WatchedQueryListenerEvent["ON_DATA"] = "onData";
@@ -611,176 +654,18 @@ exports.WatchedQueryListenerEvent = void 0;
611
654
  WatchedQueryListenerEvent["SETTINGS_WILL_UPDATE"] = "settingsWillUpdate";
612
655
  WatchedQueryListenerEvent["CLOSED"] = "closed";
613
656
  })(exports.WatchedQueryListenerEvent || (exports.WatchedQueryListenerEvent = {}));
657
+ /**
658
+ * @internal
659
+ */
614
660
  const DEFAULT_WATCH_THROTTLE_MS = 30;
661
+ /**
662
+ * @internal
663
+ */
615
664
  const DEFAULT_WATCH_QUERY_OPTIONS = {
616
665
  throttleMs: DEFAULT_WATCH_THROTTLE_MS,
617
666
  reportFetching: true
618
667
  };
619
668
 
620
- /**
621
- * Orchestrates attachment synchronization between local and remote storage.
622
- * Handles uploads, downloads, deletions, and state transitions.
623
- *
624
- * @internal
625
- */
626
- class SyncingService {
627
- attachmentService;
628
- localStorage;
629
- remoteStorage;
630
- logger;
631
- errorHandler;
632
- constructor(attachmentService, localStorage, remoteStorage, logger, errorHandler) {
633
- this.attachmentService = attachmentService;
634
- this.localStorage = localStorage;
635
- this.remoteStorage = remoteStorage;
636
- this.logger = logger;
637
- this.errorHandler = errorHandler;
638
- }
639
- /**
640
- * Processes attachments based on their state (upload, download, or delete).
641
- * All updates are saved in a single batch after processing.
642
- *
643
- * @param attachments - Array of attachment records to process
644
- * @param context - Attachment context for database operations
645
- * @returns Promise that resolves when all attachments have been processed and saved
646
- */
647
- async processAttachments(attachments, context) {
648
- const updatedAttachments = [];
649
- for (const attachment of attachments) {
650
- switch (attachment.state) {
651
- case exports.AttachmentState.QUEUED_UPLOAD:
652
- const uploaded = await this.uploadAttachment(attachment);
653
- updatedAttachments.push(uploaded);
654
- break;
655
- case exports.AttachmentState.QUEUED_DOWNLOAD:
656
- const downloaded = await this.downloadAttachment(attachment);
657
- updatedAttachments.push(downloaded);
658
- break;
659
- case exports.AttachmentState.QUEUED_DELETE:
660
- const deleted = await this.deleteAttachment(attachment, context);
661
- updatedAttachments.push(deleted);
662
- break;
663
- }
664
- }
665
- await context.saveAttachments(updatedAttachments);
666
- }
667
- /**
668
- * Uploads an attachment from local storage to remote storage.
669
- * On success, marks as SYNCED. On failure, defers to error handler or archives.
670
- *
671
- * @param attachment - The attachment record to upload
672
- * @returns Updated attachment record with new state
673
- * @throws Error if the attachment has no localUri
674
- */
675
- async uploadAttachment(attachment) {
676
- this.logger.info(`Uploading attachment ${attachment.filename}`);
677
- try {
678
- if (attachment.localUri == null) {
679
- throw new Error(`No localUri for attachment ${attachment.id}`);
680
- }
681
- const fileBlob = await this.localStorage.readFile(attachment.localUri);
682
- await this.remoteStorage.uploadFile(fileBlob, attachment);
683
- return {
684
- ...attachment,
685
- state: exports.AttachmentState.SYNCED,
686
- hasSynced: true
687
- };
688
- }
689
- catch (error) {
690
- const shouldRetry = (await this.errorHandler?.onUploadError(attachment, error)) ?? true;
691
- if (!shouldRetry) {
692
- return {
693
- ...attachment,
694
- state: exports.AttachmentState.ARCHIVED
695
- };
696
- }
697
- return attachment;
698
- }
699
- }
700
- /**
701
- * Downloads an attachment from remote storage to local storage.
702
- * Retrieves the file, converts to base64, and saves locally.
703
- * On success, marks as SYNCED. On failure, defers to error handler or archives.
704
- *
705
- * @param attachment - The attachment record to download
706
- * @returns Updated attachment record with local URI and new state
707
- */
708
- async downloadAttachment(attachment) {
709
- this.logger.info(`Downloading attachment ${attachment.filename}`);
710
- try {
711
- const fileData = await this.remoteStorage.downloadFile(attachment);
712
- const localUri = this.localStorage.getLocalUri(attachment.filename);
713
- await this.localStorage.saveFile(localUri, fileData);
714
- return {
715
- ...attachment,
716
- state: exports.AttachmentState.SYNCED,
717
- localUri: localUri,
718
- hasSynced: true
719
- };
720
- }
721
- catch (error) {
722
- const shouldRetry = (await this.errorHandler?.onDownloadError(attachment, error)) ?? true;
723
- if (!shouldRetry) {
724
- return {
725
- ...attachment,
726
- state: exports.AttachmentState.ARCHIVED
727
- };
728
- }
729
- return attachment;
730
- }
731
- }
732
- /**
733
- * Deletes an attachment from both remote and local storage.
734
- * Removes the remote file, local file (if exists), and the attachment record.
735
- * On failure, defers to error handler or archives.
736
- *
737
- * @param attachment - The attachment record to delete
738
- * @param context - Attachment context for database operations
739
- * @returns Updated attachment record
740
- */
741
- async deleteAttachment(attachment, context) {
742
- try {
743
- await this.remoteStorage.deleteFile(attachment);
744
- if (attachment.localUri) {
745
- await this.localStorage.deleteFile(attachment.localUri);
746
- }
747
- await context.deleteAttachment(attachment.id);
748
- return {
749
- ...attachment,
750
- state: exports.AttachmentState.ARCHIVED
751
- };
752
- }
753
- catch (error) {
754
- const shouldRetry = (await this.errorHandler?.onDeleteError(attachment, error)) ?? true;
755
- if (!shouldRetry) {
756
- return {
757
- ...attachment,
758
- state: exports.AttachmentState.ARCHIVED
759
- };
760
- }
761
- return attachment;
762
- }
763
- }
764
- /**
765
- * Performs cleanup of archived attachments by removing their local files and records.
766
- * Errors during local file deletion are logged but do not prevent record deletion.
767
- */
768
- async deleteArchivedAttachments(context) {
769
- return await context.deleteArchivedAttachments(async (archivedAttachments) => {
770
- for (const attachment of archivedAttachments) {
771
- if (attachment.localUri) {
772
- try {
773
- await this.localStorage.deleteFile(attachment.localUri);
774
- }
775
- catch (error) {
776
- this.logger.error('Error deleting local file for archived attachment', error);
777
- }
778
- }
779
- }
780
- });
781
- }
782
- }
783
-
784
669
  /**
785
670
  * A simple fixed-capacity queue implementation.
786
671
  *
@@ -966,6 +851,9 @@ class Mutex {
966
851
  }
967
852
  }
968
853
  }
854
+ /**
855
+ * @internal
856
+ */
969
857
  function timeoutSignal(timeout) {
970
858
  if (timeout == null)
971
859
  return;
@@ -1028,6 +916,170 @@ class AttachmentService {
1028
916
  }
1029
917
  }
1030
918
 
919
+ /**
920
+ * Orchestrates attachment synchronization between local and remote storage.
921
+ * Handles uploads, downloads, deletions, and state transitions.
922
+ *
923
+ * @internal
924
+ */
925
+ class SyncingService {
926
+ attachmentService;
927
+ localStorage;
928
+ remoteStorage;
929
+ logger;
930
+ errorHandler;
931
+ constructor(attachmentService, localStorage, remoteStorage, logger, errorHandler) {
932
+ this.attachmentService = attachmentService;
933
+ this.localStorage = localStorage;
934
+ this.remoteStorage = remoteStorage;
935
+ this.logger = logger;
936
+ this.errorHandler = errorHandler;
937
+ }
938
+ /**
939
+ * Processes attachments based on their state (upload, download, or delete).
940
+ * All updates are saved in a single batch after processing.
941
+ *
942
+ * @param attachments - Array of attachment records to process
943
+ * @param context - Attachment context for database operations
944
+ * @returns Promise that resolves when all attachments have been processed and saved
945
+ */
946
+ async processAttachments(attachments, context) {
947
+ const updatedAttachments = [];
948
+ for (const attachment of attachments) {
949
+ switch (attachment.state) {
950
+ case exports.AttachmentState.QUEUED_UPLOAD:
951
+ const uploaded = await this.uploadAttachment(attachment);
952
+ updatedAttachments.push(uploaded);
953
+ break;
954
+ case exports.AttachmentState.QUEUED_DOWNLOAD:
955
+ const downloaded = await this.downloadAttachment(attachment);
956
+ updatedAttachments.push(downloaded);
957
+ break;
958
+ case exports.AttachmentState.QUEUED_DELETE:
959
+ const deleted = await this.deleteAttachment(attachment, context);
960
+ updatedAttachments.push(deleted);
961
+ break;
962
+ }
963
+ }
964
+ await context.saveAttachments(updatedAttachments);
965
+ }
966
+ /**
967
+ * Uploads an attachment from local storage to remote storage.
968
+ * On success, marks as SYNCED. On failure, defers to error handler or archives.
969
+ *
970
+ * @param attachment - The attachment record to upload
971
+ * @returns Updated attachment record with new state
972
+ * @throws Error if the attachment has no localUri
973
+ */
974
+ async uploadAttachment(attachment) {
975
+ this.logger.info(`Uploading attachment ${attachment.filename}`);
976
+ try {
977
+ if (attachment.localUri == null) {
978
+ throw new Error(`No localUri for attachment ${attachment.id}`);
979
+ }
980
+ const fileBlob = await this.localStorage.readFile(attachment.localUri);
981
+ await this.remoteStorage.uploadFile(fileBlob, attachment);
982
+ return {
983
+ ...attachment,
984
+ state: exports.AttachmentState.SYNCED,
985
+ hasSynced: true
986
+ };
987
+ }
988
+ catch (error) {
989
+ const shouldRetry = (await this.errorHandler?.onUploadError(attachment, error)) ?? true;
990
+ if (!shouldRetry) {
991
+ return {
992
+ ...attachment,
993
+ state: exports.AttachmentState.ARCHIVED
994
+ };
995
+ }
996
+ return attachment;
997
+ }
998
+ }
999
+ /**
1000
+ * Downloads an attachment from remote storage to local storage.
1001
+ * Retrieves the file, converts to base64, and saves locally.
1002
+ * On success, marks as SYNCED. On failure, defers to error handler or archives.
1003
+ *
1004
+ * @param attachment - The attachment record to download
1005
+ * @returns Updated attachment record with local URI and new state
1006
+ */
1007
+ async downloadAttachment(attachment) {
1008
+ this.logger.info(`Downloading attachment ${attachment.filename}`);
1009
+ try {
1010
+ const fileData = await this.remoteStorage.downloadFile(attachment);
1011
+ const localUri = this.localStorage.getLocalUri(attachment.filename);
1012
+ await this.localStorage.saveFile(localUri, fileData);
1013
+ return {
1014
+ ...attachment,
1015
+ state: exports.AttachmentState.SYNCED,
1016
+ localUri: localUri,
1017
+ hasSynced: true
1018
+ };
1019
+ }
1020
+ catch (error) {
1021
+ const shouldRetry = (await this.errorHandler?.onDownloadError(attachment, error)) ?? true;
1022
+ if (!shouldRetry) {
1023
+ return {
1024
+ ...attachment,
1025
+ state: exports.AttachmentState.ARCHIVED
1026
+ };
1027
+ }
1028
+ return attachment;
1029
+ }
1030
+ }
1031
+ /**
1032
+ * Deletes an attachment from both remote and local storage.
1033
+ * Removes the remote file, local file (if exists), and the attachment record.
1034
+ * On failure, defers to error handler or archives.
1035
+ *
1036
+ * @param attachment - The attachment record to delete
1037
+ * @param context - Attachment context for database operations
1038
+ * @returns Updated attachment record
1039
+ */
1040
+ async deleteAttachment(attachment, context) {
1041
+ try {
1042
+ await this.remoteStorage.deleteFile(attachment);
1043
+ if (attachment.localUri) {
1044
+ await this.localStorage.deleteFile(attachment.localUri);
1045
+ }
1046
+ await context.deleteAttachment(attachment.id);
1047
+ return {
1048
+ ...attachment,
1049
+ state: exports.AttachmentState.ARCHIVED
1050
+ };
1051
+ }
1052
+ catch (error) {
1053
+ const shouldRetry = (await this.errorHandler?.onDeleteError(attachment, error)) ?? true;
1054
+ if (!shouldRetry) {
1055
+ return {
1056
+ ...attachment,
1057
+ state: exports.AttachmentState.ARCHIVED
1058
+ };
1059
+ }
1060
+ return attachment;
1061
+ }
1062
+ }
1063
+ /**
1064
+ * Performs cleanup of archived attachments by removing their local files and records.
1065
+ * Errors during local file deletion are logged but do not prevent record deletion.
1066
+ */
1067
+ async deleteArchivedAttachments(context) {
1068
+ return await context.deleteArchivedAttachments(async (archivedAttachments) => {
1069
+ for (const attachment of archivedAttachments) {
1070
+ if (attachment.localUri) {
1071
+ try {
1072
+ await this.localStorage.deleteFile(attachment.localUri);
1073
+ }
1074
+ catch (error) {
1075
+ this.logger.error('Error deleting local file for archived attachment', error);
1076
+ }
1077
+ }
1078
+ }
1079
+ });
1080
+ }
1081
+ }
1082
+
1031
1083
  /**
1032
1084
  * AttachmentQueue manages the lifecycle and synchronization of attachments
1033
1085
  * between local and remote storage.
@@ -1084,16 +1136,6 @@ class AttachmentQueue {
1084
1136
  * Creates a new AttachmentQueue instance.
1085
1137
  *
1086
1138
  * @param options - Configuration options
1087
- * @param options.db - PowerSync database instance
1088
- * @param options.remoteStorage - Remote storage adapter for upload/download operations
1089
- * @param options.localStorage - Local storage adapter for file persistence
1090
- * @param options.watchAttachments - Callback for monitoring attachment changes in your data model
1091
- * @param options.tableName - Name of the table to store attachment records. Default: 'ps_attachment_queue'
1092
- * @param options.logger - Logger instance. Defaults to db.logger
1093
- * @param options.syncIntervalMs - Periodic polling interval in milliseconds for retrying failed uploads/downloads. Default: 30000
1094
- * @param options.syncThrottleDuration - Throttle duration in milliseconds for the reactive watch query that detects attachment changes. Prevents rapid-fire syncs during bulk changes. Default: 30
1095
- * @param options.downloadAttachments - Whether to automatically download remote attachments. Default: true
1096
- * @param options.archivedCacheLimit - Maximum archived attachments before cleanup. Default: 100
1097
1139
  */
1098
1140
  constructor({ db, localStorage, remoteStorage, watchAttachments, logger, tableName = ATTACHMENT_TABLE, syncIntervalMs = 30 * 1000, syncThrottleDuration = DEFAULT_WATCH_THROTTLE_MS, downloadAttachments = true, archivedCacheLimit = 100, errorHandler }) {
1099
1141
  this.db = db;
@@ -1182,6 +1224,7 @@ class AttachmentQueue {
1182
1224
  state: exports.AttachmentState.QUEUED_DOWNLOAD,
1183
1225
  hasSynced: false,
1184
1226
  metaData: watchedAttachment.metaData,
1227
+ mediaType: watchedAttachment.mediaType,
1185
1228
  timestamp: new Date().getTime()
1186
1229
  });
1187
1230
  continue;
@@ -1269,17 +1312,24 @@ class AttachmentQueue {
1269
1312
  this.statusListenerDispose = undefined;
1270
1313
  }
1271
1314
  }
1315
+ /**
1316
+ * Provides an {@link AttachmentContext} to a callback.
1317
+ *
1318
+ * The callback runs while the attachment queue mutex is held. Do not call
1319
+ * other {@link AttachmentQueue} methods from within the callback, as they may
1320
+ * attempt to acquire the same mutex and block indefinitely.
1321
+ */
1322
+ withAttachmentContext(callback) {
1323
+ /**
1324
+ * AttachmentService is internal and private in this class.
1325
+ * We only need to expose its locking and context functionality for extending classes.
1326
+ */
1327
+ return this.attachmentService.withContext(callback);
1328
+ }
1272
1329
  /**
1273
1330
  * Saves a file to local storage and queues it for upload to remote storage.
1274
1331
  *
1275
1332
  * @param options - File save options
1276
- * @param options.data - The file data as ArrayBuffer, Blob, or base64 string
1277
- * @param options.fileExtension - File extension (e.g., 'jpg', 'pdf')
1278
- * @param options.mediaType - MIME type of the file (e.g., 'image/jpeg')
1279
- * @param options.metaData - Optional metadata to associate with the attachment
1280
- * @param options.id - Optional custom ID. If not provided, a UUID will be generated
1281
- * @param options.updateHook - Optional callback to execute additional database operations
1282
- * within the same transaction as the attachment creation
1283
1333
  * @returns Promise resolving to the created attachment record
1284
1334
  */
1285
1335
  async saveFile({ data, fileExtension, mediaType, metaData, id, updateHook }) {
@@ -1392,171 +1442,19 @@ class AttachmentQueue {
1392
1442
  }
1393
1443
  }
1394
1444
 
1445
+ /**
1446
+ * @alpha
1447
+ */
1395
1448
  exports.EncodingType = void 0;
1396
1449
  (function (EncodingType) {
1397
1450
  EncodingType["UTF8"] = "utf8";
1398
1451
  EncodingType["Base64"] = "base64";
1399
1452
  })(exports.EncodingType || (exports.EncodingType = {}));
1400
1453
 
1401
- const symbolAsyncIterator = Symbol.asyncIterator ?? Symbol.for('Symbol.asyncIterator');
1402
-
1403
1454
  function getDefaultExportFromCjs (x) {
1404
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
1405
- }
1406
-
1407
- var dom = {};
1408
-
1409
- var eventIterator = {};
1410
-
1411
- var hasRequiredEventIterator;
1412
-
1413
- function requireEventIterator () {
1414
- if (hasRequiredEventIterator) return eventIterator;
1415
- hasRequiredEventIterator = 1;
1416
- Object.defineProperty(eventIterator, "__esModule", { value: true });
1417
- class EventQueue {
1418
- constructor() {
1419
- this.pullQueue = [];
1420
- this.pushQueue = [];
1421
- this.eventHandlers = {};
1422
- this.isPaused = false;
1423
- this.isStopped = false;
1424
- }
1425
- push(value) {
1426
- if (this.isStopped)
1427
- return;
1428
- const resolution = { value, done: false };
1429
- if (this.pullQueue.length) {
1430
- const placeholder = this.pullQueue.shift();
1431
- if (placeholder)
1432
- placeholder.resolve(resolution);
1433
- }
1434
- else {
1435
- this.pushQueue.push(Promise.resolve(resolution));
1436
- if (this.highWaterMark !== undefined &&
1437
- this.pushQueue.length >= this.highWaterMark &&
1438
- !this.isPaused) {
1439
- this.isPaused = true;
1440
- if (this.eventHandlers.highWater) {
1441
- this.eventHandlers.highWater();
1442
- }
1443
- else if (console) {
1444
- console.warn(`EventIterator queue reached ${this.pushQueue.length} items`);
1445
- }
1446
- }
1447
- }
1448
- }
1449
- stop() {
1450
- if (this.isStopped)
1451
- return;
1452
- this.isStopped = true;
1453
- this.remove();
1454
- for (const placeholder of this.pullQueue) {
1455
- placeholder.resolve({ value: undefined, done: true });
1456
- }
1457
- this.pullQueue.length = 0;
1458
- }
1459
- fail(error) {
1460
- if (this.isStopped)
1461
- return;
1462
- this.isStopped = true;
1463
- this.remove();
1464
- if (this.pullQueue.length) {
1465
- for (const placeholder of this.pullQueue) {
1466
- placeholder.reject(error);
1467
- }
1468
- this.pullQueue.length = 0;
1469
- }
1470
- else {
1471
- const rejection = Promise.reject(error);
1472
- /* Attach error handler to avoid leaking an unhandled promise rejection. */
1473
- rejection.catch(() => { });
1474
- this.pushQueue.push(rejection);
1475
- }
1476
- }
1477
- remove() {
1478
- Promise.resolve().then(() => {
1479
- if (this.removeCallback)
1480
- this.removeCallback();
1481
- });
1482
- }
1483
- [symbolAsyncIterator]() {
1484
- return {
1485
- next: (value) => {
1486
- const result = this.pushQueue.shift();
1487
- if (result) {
1488
- if (this.lowWaterMark !== undefined &&
1489
- this.pushQueue.length <= this.lowWaterMark &&
1490
- this.isPaused) {
1491
- this.isPaused = false;
1492
- if (this.eventHandlers.lowWater) {
1493
- this.eventHandlers.lowWater();
1494
- }
1495
- }
1496
- return result;
1497
- }
1498
- else if (this.isStopped) {
1499
- return Promise.resolve({ value: undefined, done: true });
1500
- }
1501
- else {
1502
- return new Promise((resolve, reject) => {
1503
- this.pullQueue.push({ resolve, reject });
1504
- });
1505
- }
1506
- },
1507
- return: () => {
1508
- this.isStopped = true;
1509
- this.pushQueue.length = 0;
1510
- this.remove();
1511
- return Promise.resolve({ value: undefined, done: true });
1512
- },
1513
- };
1514
- }
1515
- }
1516
- class EventIterator {
1517
- constructor(listen, { highWaterMark = 100, lowWaterMark = 1 } = {}) {
1518
- const queue = new EventQueue();
1519
- queue.highWaterMark = highWaterMark;
1520
- queue.lowWaterMark = lowWaterMark;
1521
- queue.removeCallback =
1522
- listen({
1523
- push: value => queue.push(value),
1524
- stop: () => queue.stop(),
1525
- fail: error => queue.fail(error),
1526
- on: (event, fn) => {
1527
- queue.eventHandlers[event] = fn;
1528
- },
1529
- }) || (() => { });
1530
- this[symbolAsyncIterator] = () => queue[symbolAsyncIterator]();
1531
- Object.freeze(this);
1532
- }
1533
- }
1534
- eventIterator.EventIterator = EventIterator;
1535
- eventIterator.default = EventIterator;
1536
- return eventIterator;
1537
- }
1538
-
1539
- var hasRequiredDom;
1540
-
1541
- function requireDom () {
1542
- if (hasRequiredDom) return dom;
1543
- hasRequiredDom = 1;
1544
- Object.defineProperty(dom, "__esModule", { value: true });
1545
- const event_iterator_1 = requireEventIterator();
1546
- dom.EventIterator = event_iterator_1.EventIterator;
1547
- function subscribe(event, options, evOptions) {
1548
- return new event_iterator_1.EventIterator(({ push }) => {
1549
- this.addEventListener(event, push, options);
1550
- return () => this.removeEventListener(event, push, options);
1551
- }, evOptions);
1552
- }
1553
- dom.subscribe = subscribe;
1554
- dom.default = event_iterator_1.EventIterator;
1555
- return dom;
1455
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
1556
1456
  }
1557
1457
 
1558
- var domExports = requireDom();
1559
-
1560
1458
  var logger$1 = {exports: {}};
1561
1459
 
1562
1460
  /*!
@@ -1855,7 +1753,9 @@ var Logger = /*@__PURE__*/getDefaultExportFromCjs(loggerExports);
1855
1753
  * different SQLite DB implementations.
1856
1754
  */
1857
1755
  /**
1858
- * Implements {@link DBGetUtils} on a {@link SqlRunner}.
1756
+ * Implements {@link DBGetUtils} on a {@link SqlExecutor}.
1757
+ *
1758
+ * @internal
1859
1759
  */
1860
1760
  function DBGetUtilsDefaultMixin(Base) {
1861
1761
  return class extends Base {
@@ -1899,6 +1799,8 @@ function DBGetUtilsDefaultMixin(Base) {
1899
1799
  }
1900
1800
  /**
1901
1801
  * Update table operation numbers from SQLite
1802
+ *
1803
+ * @public
1902
1804
  */
1903
1805
  exports.RowUpdateType = void 0;
1904
1806
  (function (RowUpdateType) {
@@ -1907,8 +1809,10 @@ exports.RowUpdateType = void 0;
1907
1809
  RowUpdateType[RowUpdateType["SQLITE_UPDATE"] = 23] = "SQLITE_UPDATE";
1908
1810
  })(exports.RowUpdateType || (exports.RowUpdateType = {}));
1909
1811
  /**
1910
- * A mixin to implement {@link DBAdapter} by delegating to {@link ConnectionPool.readLock} and
1911
- * {@link ConnectionPool.writeLock}.
1812
+ * A mixin to implement {@link DBAdapter} by delegating to {@link ConnectionPool#readLock} and
1813
+ * {@link ConnectionPool#writeLock}.
1814
+ *
1815
+ * @internal
1912
1816
  */
1913
1817
  function DBAdapterDefaultMixin(Base) {
1914
1818
  return class extends Base {
@@ -1996,9 +1900,15 @@ class TransactionImplementation extends DBGetUtilsDefaultMixin(BaseTransaction)
1996
1900
  }
1997
1901
  }
1998
1902
  }
1903
+ /**
1904
+ * @internal
1905
+ */
1999
1906
  function isBatchedUpdateNotification(update) {
2000
1907
  return 'tables' in update;
2001
1908
  }
1909
+ /**
1910
+ * @internal
1911
+ */
2002
1912
  function extractTableUpdates(update) {
2003
1913
  return isBatchedUpdateNotification(update) ? update.tables : [update.table];
2004
1914
  }
@@ -2026,6 +1936,8 @@ const FULL_SYNC_PRIORITY = 2147483647;
2026
1936
  *
2027
1937
  * Also note that data is downloaded in bulk, which means that individual counters are unlikely
2028
1938
  * to be updated one-by-one.
1939
+ *
1940
+ * @public
2029
1941
  */
2030
1942
  class SyncProgress {
2031
1943
  internal;
@@ -2064,6 +1976,9 @@ class SyncProgress {
2064
1976
  }
2065
1977
  }
2066
1978
 
1979
+ /**
1980
+ * @public
1981
+ */
2067
1982
  class SyncStatus {
2068
1983
  options;
2069
1984
  constructor(options) {
@@ -2074,6 +1989,8 @@ class SyncStatus {
2074
1989
  * implementation).
2075
1990
  *
2076
1991
  * This information is only available after a connection has been requested.
1992
+ *
1993
+ * @deprecated This always returns the Rust client (the only option).
2077
1994
  */
2078
1995
  get clientImplementation() {
2079
1996
  return this.options.clientImplementation;
@@ -2081,7 +1998,7 @@ class SyncStatus {
2081
1998
  /**
2082
1999
  * Indicates if the client is currently connected to the PowerSync service.
2083
2000
  *
2084
- * @returns {boolean} True if connected, false otherwise. Defaults to false if not specified.
2001
+ * @returns True if connected, false otherwise. Defaults to false if not specified.
2085
2002
  */
2086
2003
  get connected() {
2087
2004
  return this.options.connected ?? false;
@@ -2089,7 +2006,7 @@ class SyncStatus {
2089
2006
  /**
2090
2007
  * Indicates if the client is in the process of establishing a connection to the PowerSync service.
2091
2008
  *
2092
- * @returns {boolean} True if connecting, false otherwise. Defaults to false if not specified.
2009
+ * @returns True if connecting, false otherwise. Defaults to false if not specified.
2093
2010
  */
2094
2011
  get connecting() {
2095
2012
  return this.options.connecting ?? false;
@@ -2098,7 +2015,7 @@ class SyncStatus {
2098
2015
  * Time that a last sync has fully completed, if any.
2099
2016
  * This timestamp is reset to null after a restart of the PowerSync service.
2100
2017
  *
2101
- * @returns {Date | undefined} The timestamp of the last successful sync, or undefined if no sync has completed.
2018
+ * @returns The timestamp of the last successful sync, or undefined if no sync has completed.
2102
2019
  */
2103
2020
  get lastSyncedAt() {
2104
2021
  return this.options.lastSyncedAt;
@@ -2106,7 +2023,7 @@ class SyncStatus {
2106
2023
  /**
2107
2024
  * Indicates whether there has been at least one full sync completed since initialization.
2108
2025
  *
2109
- * @returns {boolean | undefined} True if at least one sync has completed, false if no sync has completed,
2026
+ * @returns True if at least one sync has completed, false if no sync has completed,
2110
2027
  * or undefined when the state is still being loaded from the database.
2111
2028
  */
2112
2029
  get hasSynced() {
@@ -2115,10 +2032,10 @@ class SyncStatus {
2115
2032
  /**
2116
2033
  * Provides the current data flow status regarding uploads and downloads.
2117
2034
  *
2118
- * @returns {SyncDataFlowStatus} An object containing:
2035
+ * @returns An object containing:
2119
2036
  * - downloading: True if actively downloading changes (only when connected is also true)
2120
2037
  * - uploading: True if actively uploading changes
2121
- * Defaults to {downloading: false, uploading: false} if not specified.
2038
+ * Defaults to `{downloading: false, uploading: false}` if not specified.
2122
2039
  */
2123
2040
  get dataFlowStatus() {
2124
2041
  return (this.options.dataFlow ?? {
@@ -2143,7 +2060,7 @@ class SyncStatus {
2143
2060
  return this.options.dataFlow?.internalStreamSubscriptions?.map((core) => new SyncStreamStatusView(this, core));
2144
2061
  }
2145
2062
  /**
2146
- * If the `stream` appears in {@link syncStreams}, returns the current status for that stream.
2063
+ * If the `stream` appears in {@link SyncStatus.syncStreams}, returns the current status for that stream.
2147
2064
  */
2148
2065
  forStream(stream) {
2149
2066
  const asJson = JSON.stringify(stream.parameters);
@@ -2153,7 +2070,7 @@ class SyncStatus {
2153
2070
  /**
2154
2071
  * Provides sync status information for all bucket priorities, sorted by priority (highest first).
2155
2072
  *
2156
- * @returns {SyncPriorityStatus[]} An array of status entries for different sync priority levels,
2073
+ * @returns An array of status entries for different sync priority levels,
2157
2074
  * sorted with highest priorities (lower numbers) first.
2158
2075
  */
2159
2076
  get priorityStatusEntries() {
@@ -2188,8 +2105,8 @@ class SyncStatus {
2188
2105
  * For example, if PowerSync just finished synchronizing buckets in priority level 3, calling this method
2189
2106
  * with a priority of 1 may return information for priority level 3.
2190
2107
  *
2191
- * @param {number} priority The bucket priority for which the status should be reported
2192
- * @returns {SyncPriorityStatus} Status information for the requested priority level or the next higher level with available status
2108
+ * @param priority - The bucket priority for which the status should be reported
2109
+ * @returns Status information for the requested priority level or the next higher level with available status
2193
2110
  */
2194
2111
  statusForPriority(priority) {
2195
2112
  // priorityStatusEntries are sorted by ascending priorities (so higher numbers to lower numbers).
@@ -2210,8 +2127,8 @@ class SyncStatus {
2210
2127
  * Compares this SyncStatus instance with another to determine if they are equal.
2211
2128
  * Equality is determined by comparing the serialized JSON representation of both instances.
2212
2129
  *
2213
- * @param {SyncStatus} status The SyncStatus instance to compare against
2214
- * @returns {boolean} True if the instances are considered equal, false otherwise
2130
+ * @param status - The SyncStatus instance to compare against
2131
+ * @returns True if the instances are considered equal, false otherwise
2215
2132
  */
2216
2133
  isEqual(status) {
2217
2134
  /**
@@ -2234,7 +2151,7 @@ class SyncStatus {
2234
2151
  * Creates a human-readable string representation of the current sync status.
2235
2152
  * Includes information about connection state, sync completion, and data flow.
2236
2153
  *
2237
- * @returns {string} A string representation of the sync status
2154
+ * @returns A string representation of the sync status
2238
2155
  */
2239
2156
  getMessage() {
2240
2157
  const dataFlow = this.dataFlowStatus;
@@ -2243,7 +2160,7 @@ class SyncStatus {
2243
2160
  /**
2244
2161
  * Serializes the SyncStatus instance to a plain object.
2245
2162
  *
2246
- * @returns {SyncStatusOptions} A plain object representation of the sync status
2163
+ * @returns A plain object representation of the sync status
2247
2164
  */
2248
2165
  toJSON() {
2249
2166
  return {
@@ -2309,6 +2226,9 @@ class SyncStreamStatusView {
2309
2226
  }
2310
2227
  }
2311
2228
 
2229
+ /**
2230
+ * @public
2231
+ */
2312
2232
  class UploadQueueStats {
2313
2233
  count;
2314
2234
  size;
@@ -2334,6 +2254,9 @@ class UploadQueueStats {
2334
2254
  }
2335
2255
  }
2336
2256
 
2257
+ /**
2258
+ * @internal
2259
+ */
2337
2260
  class BaseObserver {
2338
2261
  listeners = new Set();
2339
2262
  constructor() { }
@@ -2361,6 +2284,9 @@ class BaseObserver {
2361
2284
  }
2362
2285
  }
2363
2286
 
2287
+ /**
2288
+ * @internal
2289
+ */
2364
2290
  class ControlledExecutor {
2365
2291
  task;
2366
2292
  /**
@@ -2412,6 +2338,210 @@ class ControlledExecutor {
2412
2338
  }
2413
2339
  }
2414
2340
 
2341
+ /**
2342
+ * Some JavaScript engines, in particular older versions of React Native, don't support Symbol.asyncIterator.
2343
+ *
2344
+ * For those, users relying on async generators typically lower them with a transpiler and [this polyfill](https://github.com/Azure/azure-sdk-for-js/blob/%40azure/core-asynciterator-polyfill_1.0.2/sdk/core/core-asynciterator-polyfill/src/index.ts#L4-L6).
2345
+ * This definition is compatible with that polyfill, so transpiled apps can use async iterables created by the PowerSync
2346
+ * SDK.
2347
+ */
2348
+ const symbolAsyncIterator = Symbol.asyncIterator ?? Symbol.for('Symbol.asyncIterator');
2349
+
2350
+ const doneResult = { done: true, value: undefined };
2351
+ function valueResult(value) {
2352
+ return { done: false, value };
2353
+ }
2354
+ /**
2355
+ * Expands a source async iterator by allowing to inject events asynchronously.
2356
+ *
2357
+ * The resulting iterator will emit all events from its source. Additionally though, events can be injected. These
2358
+ * events are dropped once the main iterator completes, but are otherwise forwarded.
2359
+ *
2360
+ * The iterator completes when its source completes, and it supports backpressure by only calling `next()` on the source
2361
+ * in response to a `next()` call from downstream if no pending injected events can be dispatched.
2362
+ */
2363
+ function injectable(source) {
2364
+ let sourceIsDone = false;
2365
+ let waiter = undefined; // An active, waiting next() call.
2366
+ // A pending upstream event that couldn't be dispatched because inject() has been called before it was resolved.
2367
+ let pendingSourceEvent = null;
2368
+ let sourceFetchInFlight = false;
2369
+ let pendingInjectedEvents = [];
2370
+ const consumeWaiter = () => {
2371
+ const pending = waiter;
2372
+ waiter = undefined;
2373
+ return pending;
2374
+ };
2375
+ const fetchFromSource = () => {
2376
+ const resolveWaiter = (propagate) => {
2377
+ sourceFetchInFlight = false;
2378
+ const active = consumeWaiter();
2379
+ if (active) {
2380
+ propagate(active);
2381
+ }
2382
+ else {
2383
+ pendingSourceEvent = propagate;
2384
+ }
2385
+ };
2386
+ sourceFetchInFlight = true;
2387
+ const nextFromSource = source.next();
2388
+ nextFromSource.then((value) => {
2389
+ sourceIsDone = value.done == true;
2390
+ resolveWaiter((w) => w.resolve(value));
2391
+ }, (error) => {
2392
+ resolveWaiter((w) => w.reject(error));
2393
+ });
2394
+ };
2395
+ return {
2396
+ next: () => {
2397
+ return new Promise((resolve, reject) => {
2398
+ // First priority: Dispatch ready upstream events.
2399
+ if (sourceIsDone) {
2400
+ return resolve(doneResult);
2401
+ }
2402
+ if (pendingSourceEvent) {
2403
+ pendingSourceEvent({ resolve, reject });
2404
+ pendingSourceEvent = null;
2405
+ return;
2406
+ }
2407
+ // Second priority: Dispatch injected events
2408
+ if (pendingInjectedEvents.length) {
2409
+ return resolve(valueResult(pendingInjectedEvents.shift()));
2410
+ }
2411
+ // Nothing pending? Fetch from source
2412
+ waiter = { resolve, reject };
2413
+ if (!sourceFetchInFlight) {
2414
+ fetchFromSource();
2415
+ }
2416
+ });
2417
+ },
2418
+ inject: (event) => {
2419
+ const pending = consumeWaiter();
2420
+ if (pending != null) {
2421
+ pending.resolve(valueResult(event));
2422
+ }
2423
+ else {
2424
+ pendingInjectedEvents.push(event);
2425
+ }
2426
+ }
2427
+ };
2428
+ }
2429
+ /**
2430
+ * Splits a byte stream at line endings, emitting each line as a string.
2431
+ */
2432
+ function extractJsonLines(source, decoder) {
2433
+ let buffer = '';
2434
+ const pendingLines = [];
2435
+ let isFinalEvent = false;
2436
+ return {
2437
+ next: async () => {
2438
+ while (true) {
2439
+ if (isFinalEvent) {
2440
+ return doneResult;
2441
+ }
2442
+ {
2443
+ const first = pendingLines.shift();
2444
+ if (first) {
2445
+ return { done: false, value: first };
2446
+ }
2447
+ }
2448
+ const { done, value } = await source.next();
2449
+ if (done) {
2450
+ const remaining = buffer.trim();
2451
+ if (remaining.length != 0) {
2452
+ isFinalEvent = true;
2453
+ return { done: false, value: remaining };
2454
+ }
2455
+ return doneResult;
2456
+ }
2457
+ const data = decoder.decode(value, { stream: true });
2458
+ buffer += data;
2459
+ const lines = buffer.split('\n');
2460
+ for (let i = 0; i < lines.length - 1; i++) {
2461
+ const l = lines[i].trim();
2462
+ if (l.length > 0) {
2463
+ pendingLines.push(l);
2464
+ }
2465
+ }
2466
+ buffer = lines[lines.length - 1];
2467
+ }
2468
+ }
2469
+ };
2470
+ }
2471
+ /**
2472
+ * Splits a concatenated stream of BSON objects by emitting individual objects.
2473
+ */
2474
+ function extractBsonObjects(source) {
2475
+ // Fully read but not emitted yet.
2476
+ const completedObjects = [];
2477
+ // Whether source has returned { done: true }. We do the same once completed objects have been emitted.
2478
+ let isDone = false;
2479
+ const lengthBuffer = new DataView(new ArrayBuffer(4));
2480
+ let objectBody = null;
2481
+ // If we're parsing the length field, a number between 1 and 4 (inclusive) describing remaining bytes in the header.
2482
+ // If we're consuming a document, the bytes remaining.
2483
+ let remainingLength = 4;
2484
+ return {
2485
+ async next() {
2486
+ while (true) {
2487
+ // Before fetching new data from upstream, return completed objects.
2488
+ if (completedObjects.length) {
2489
+ return valueResult(completedObjects.shift());
2490
+ }
2491
+ if (isDone) {
2492
+ return doneResult;
2493
+ }
2494
+ const upstreamEvent = await source.next();
2495
+ if (upstreamEvent.done) {
2496
+ isDone = true;
2497
+ if (objectBody || remainingLength != 4) {
2498
+ throw new Error('illegal end of stream in BSON object');
2499
+ }
2500
+ return doneResult;
2501
+ }
2502
+ const chunk = upstreamEvent.value;
2503
+ for (let i = 0; i < chunk.length;) {
2504
+ const availableInData = chunk.length - i;
2505
+ if (objectBody) {
2506
+ // We're in the middle of reading a BSON document.
2507
+ const bytesToRead = Math.min(availableInData, remainingLength);
2508
+ const copySource = new Uint8Array(chunk.buffer, chunk.byteOffset + i, bytesToRead);
2509
+ objectBody.set(copySource, objectBody.length - remainingLength);
2510
+ i += bytesToRead;
2511
+ remainingLength -= bytesToRead;
2512
+ if (remainingLength == 0) {
2513
+ completedObjects.push(objectBody);
2514
+ // Prepare to read another document, starting with its length
2515
+ objectBody = null;
2516
+ remainingLength = 4;
2517
+ }
2518
+ }
2519
+ else {
2520
+ // Copy up to 4 bytes into lengthBuffer, depending on how many we still need.
2521
+ const bytesToRead = Math.min(availableInData, remainingLength);
2522
+ for (let j = 0; j < bytesToRead; j++) {
2523
+ lengthBuffer.setUint8(4 - remainingLength + j, chunk[i + j]);
2524
+ }
2525
+ i += bytesToRead;
2526
+ remainingLength -= bytesToRead;
2527
+ if (remainingLength == 0) {
2528
+ // Transition from reading length header to reading document. Subtracting 4 because the length of the
2529
+ // header is included in length.
2530
+ const length = lengthBuffer.getInt32(0, true /* little endian */);
2531
+ remainingLength = length - 4;
2532
+ if (remainingLength < 1) {
2533
+ throw new Error(`invalid length for bson: ${length}`);
2534
+ }
2535
+ objectBody = new Uint8Array(length);
2536
+ new DataView(objectBody.buffer).setInt32(0, length, true);
2537
+ }
2538
+ }
2539
+ }
2540
+ }
2541
+ }
2542
+ };
2543
+ }
2544
+
2415
2545
  /**
2416
2546
  * Throttle a function to be called at most once every "wait" milliseconds,
2417
2547
  * on the trailing edge.
@@ -2431,45 +2561,128 @@ function throttleTrailing(func, wait) {
2431
2561
  };
2432
2562
  }
2433
2563
  function asyncNotifier() {
2434
- let waitingConsumer = null;
2435
- let hasPendingNotification = false;
2564
+ const queue = new EventQueue();
2436
2565
  return {
2437
2566
  notify() {
2438
- if (waitingConsumer != null) {
2439
- waitingConsumer();
2440
- waitingConsumer = null;
2441
- }
2567
+ if (queue.countOutstandingEvents > 0) ;
2442
2568
  else {
2443
- hasPendingNotification = true;
2569
+ queue.notify();
2444
2570
  }
2445
2571
  },
2446
2572
  waitForNotification(signal) {
2447
- return new Promise((resolve) => {
2448
- if (waitingConsumer != null) {
2449
- throw new Error('Illegal call to waitForNotification, already has a waiter.');
2450
- }
2451
- if (signal.aborted) {
2452
- resolve();
2573
+ return queue.waitForEvent(signal);
2574
+ }
2575
+ };
2576
+ }
2577
+ class EventQueue {
2578
+ options;
2579
+ waitingConsumer;
2580
+ outstandingEvents;
2581
+ constructor(options = {}) {
2582
+ this.options = options;
2583
+ this.outstandingEvents = [];
2584
+ }
2585
+ /**
2586
+ * The amount of buffered events not yet dispatched to listeners.
2587
+ */
2588
+ get countOutstandingEvents() {
2589
+ return this.outstandingEvents.length;
2590
+ }
2591
+ notifyInner(dispatch) {
2592
+ const existing = this.waitingConsumer;
2593
+ this.waitingConsumer = undefined;
2594
+ const dispatchAndNotifyListeners = (waiter) => {
2595
+ dispatch(waiter);
2596
+ this.options.eventDelivered?.();
2597
+ };
2598
+ if (existing) {
2599
+ dispatchAndNotifyListeners(existing);
2600
+ }
2601
+ else {
2602
+ this.outstandingEvents.push(dispatchAndNotifyListeners);
2603
+ }
2604
+ }
2605
+ notify(value) {
2606
+ this.notifyInner((l) => l.resolve(value));
2607
+ }
2608
+ notifyError(error) {
2609
+ this.notifyInner((l) => l.reject(error));
2610
+ }
2611
+ waitForEvent(signal) {
2612
+ return new Promise((resolve, reject) => {
2613
+ if (this.waitingConsumer != null) {
2614
+ throw new Error('Illegal call to waitForEvent, already has a waiter.');
2615
+ }
2616
+ const complete = () => {
2617
+ signal?.removeEventListener('abort', onAbort);
2618
+ };
2619
+ const onAbort = () => {
2620
+ complete();
2621
+ this.waitingConsumer = undefined;
2622
+ resolve(undefined);
2623
+ };
2624
+ const waiter = {
2625
+ resolve: (value) => {
2626
+ complete();
2627
+ resolve(value);
2628
+ },
2629
+ reject: (error) => {
2630
+ complete();
2631
+ reject(error);
2453
2632
  }
2454
- else if (hasPendingNotification) {
2455
- resolve();
2456
- hasPendingNotification = false;
2633
+ };
2634
+ if (signal.aborted) {
2635
+ resolve(undefined);
2636
+ }
2637
+ else if (this.countOutstandingEvents > 0) {
2638
+ const [event] = this.outstandingEvents.splice(0, 1);
2639
+ event(waiter);
2640
+ }
2641
+ else {
2642
+ this.waitingConsumer = waiter;
2643
+ signal.addEventListener('abort', onAbort);
2644
+ }
2645
+ });
2646
+ }
2647
+ /**
2648
+ * Creates an async iterable backed by event queues.
2649
+ *
2650
+ * @param run A function invoked for every new listener. It receives a queue backing the async iterator.
2651
+ * @param abort An additional abort signal. The `run` callback will also be aborted when `AsyncIterator.return` is
2652
+ * called.
2653
+ * @returns An object conforming to the async iterable protocol.
2654
+ */
2655
+ static queueBasedAsyncIterable(run, abort) {
2656
+ return {
2657
+ [symbolAsyncIterator]: () => {
2658
+ const queue = new EventQueue();
2659
+ const controller = new AbortController();
2660
+ function dispose() {
2661
+ controller.abort();
2662
+ abort?.removeEventListener('abort', dispose);
2457
2663
  }
2458
- else {
2459
- function complete() {
2460
- signal.removeEventListener('abort', onAbort);
2461
- resolve();
2664
+ if (abort) {
2665
+ if (abort.aborted) {
2666
+ controller.abort();
2462
2667
  }
2463
- function onAbort() {
2464
- waitingConsumer = null;
2465
- resolve();
2668
+ else {
2669
+ abort.addEventListener('abort', dispose);
2466
2670
  }
2467
- waitingConsumer = complete;
2468
- signal.addEventListener('abort', onAbort);
2469
2671
  }
2470
- });
2471
- }
2472
- };
2672
+ run(queue, controller.signal);
2673
+ return {
2674
+ async next() {
2675
+ const event = await queue.waitForEvent(controller.signal);
2676
+ return event == null ? doneResult : valueResult(event);
2677
+ },
2678
+ async return() {
2679
+ dispose();
2680
+ return doneResult;
2681
+ }
2682
+ };
2683
+ }
2684
+ };
2685
+ }
2473
2686
  }
2474
2687
 
2475
2688
  /**
@@ -2628,7 +2841,7 @@ class ConnectionManager extends BaseObserver {
2628
2841
  /**
2629
2842
  * Close the sync connection.
2630
2843
  *
2631
- * Use {@link connect} to connect again.
2844
+ * Use {@link ConnectionManager.connect} to connect again.
2632
2845
  */
2633
2846
  async disconnect() {
2634
2847
  // This will help abort pending connects
@@ -2768,6 +2981,8 @@ const _finalizer = 'FinalizationRegistry' in globalThis
2768
2981
  /**
2769
2982
  * An efficient comparator for {@link WatchedQuery} created with {@link Query#watch}. This has the ability to determine if a query
2770
2983
  * result has changes without necessarily processing all items in the result.
2984
+ *
2985
+ * @public
2771
2986
  */
2772
2987
  class ArrayComparator {
2773
2988
  options;
@@ -2795,6 +3010,8 @@ class ArrayComparator {
2795
3010
  }
2796
3011
  /**
2797
3012
  * Watched query comparator that always reports changed result sets.
3013
+ *
3014
+ * @public
2798
3015
  */
2799
3016
  const FalsyComparator = {
2800
3017
  checkEquality: () => false // Default comparator that always returns false
@@ -3002,6 +3219,8 @@ class AbstractQueryProcessor extends MetaBaseObserver {
3002
3219
  /**
3003
3220
  * An empty differential result set.
3004
3221
  * This is used as the initial state for differential incrementally watched queries.
3222
+ *
3223
+ * @internal
3005
3224
  */
3006
3225
  const EMPTY_DIFFERENTIAL = {
3007
3226
  added: [],
@@ -3014,6 +3233,8 @@ const EMPTY_DIFFERENTIAL = {
3014
3233
  * Default implementation of the {@link DifferentialWatchedQueryComparator} for watched queries.
3015
3234
  * It keys items by their `id` property if available, alternatively it uses JSON stringification
3016
3235
  * of the entire item for the key and comparison.
3236
+ *
3237
+ * @internal
3017
3238
  */
3018
3239
  const DEFAULT_ROW_COMPARATOR = {
3019
3240
  keyBy: (item) => {
@@ -3294,6 +3515,8 @@ class CustomQuery {
3294
3515
 
3295
3516
  /**
3296
3517
  * Tests if the input is a {@link SQLOpenOptions}
3518
+ *
3519
+ * @internal
3297
3520
  */
3298
3521
  const isSQLOpenOptions = (test) => {
3299
3522
  // typeof null is `object`, but you cannot use the `in` operator on `null.
@@ -3301,17 +3524,24 @@ const isSQLOpenOptions = (test) => {
3301
3524
  };
3302
3525
  /**
3303
3526
  * Tests if input is a {@link SQLOpenFactory}
3527
+ *
3528
+ * @internal
3304
3529
  */
3305
3530
  const isSQLOpenFactory = (test) => {
3306
3531
  return typeof test?.openDB == 'function';
3307
3532
  };
3308
3533
  /**
3309
3534
  * Tests if input is a {@link DBAdapter}
3535
+ *
3536
+ * @internal
3310
3537
  */
3311
3538
  const isDBAdapter = (test) => {
3312
3539
  return typeof test?.writeTransaction == 'function';
3313
3540
  };
3314
3541
 
3542
+ /**
3543
+ * @internal
3544
+ */
3315
3545
  exports.PSInternalTable = void 0;
3316
3546
  (function (PSInternalTable) {
3317
3547
  PSInternalTable["DATA"] = "ps_data";
@@ -3320,6 +3550,9 @@ exports.PSInternalTable = void 0;
3320
3550
  PSInternalTable["OPLOG"] = "ps_oplog";
3321
3551
  PSInternalTable["UNTYPED"] = "ps_untyped";
3322
3552
  })(exports.PSInternalTable || (exports.PSInternalTable = {}));
3553
+ /**
3554
+ * @internal
3555
+ */
3323
3556
  exports.PowerSyncControlCommand = void 0;
3324
3557
  (function (PowerSyncControlCommand) {
3325
3558
  PowerSyncControlCommand["PROCESS_TEXT_LINE"] = "line_text";
@@ -3337,6 +3570,8 @@ exports.PowerSyncControlCommand = void 0;
3337
3570
 
3338
3571
  /**
3339
3572
  * A batch of client-side changes.
3573
+ *
3574
+ * @public
3340
3575
  */
3341
3576
  class CrudBatch {
3342
3577
  crud;
@@ -3363,6 +3598,8 @@ class CrudBatch {
3363
3598
 
3364
3599
  /**
3365
3600
  * Type of local change.
3601
+ *
3602
+ * @public
3366
3603
  */
3367
3604
  exports.UpdateType = void 0;
3368
3605
  (function (UpdateType) {
@@ -3375,6 +3612,8 @@ exports.UpdateType = void 0;
3375
3612
  })(exports.UpdateType || (exports.UpdateType = {}));
3376
3613
  /**
3377
3614
  * A single client-side change.
3615
+ *
3616
+ * @public
3378
3617
  */
3379
3618
  class CrudEntry {
3380
3619
  /**
@@ -3471,6 +3710,9 @@ class CrudEntry {
3471
3710
  }
3472
3711
  }
3473
3712
 
3713
+ /**
3714
+ * @public
3715
+ */
3474
3716
  class CrudTransaction extends CrudBatch {
3475
3717
  crud;
3476
3718
  complete;
@@ -3499,6 +3741,8 @@ class CrudTransaction extends CrudBatch {
3499
3741
  * Calls to Abortcontroller.abort(reason: any) will result in the
3500
3742
  * `reason` being thrown. This is not necessarily an error,
3501
3743
  * but extends error for better logging purposes.
3744
+ *
3745
+ * @internal
3502
3746
  */
3503
3747
  class AbortOperation extends Error {
3504
3748
  reason;
@@ -10669,7 +10913,7 @@ function requireDist () {
10669
10913
 
10670
10914
  var distExports = requireDist();
10671
10915
 
10672
- var version = "1.53.2";
10916
+ var version = "1.55.0";
10673
10917
  var PACKAGE = {
10674
10918
  version: version};
10675
10919
 
@@ -10745,289 +10989,95 @@ function requireWebsocketDuplexConnection () {
10745
10989
  get: function () {
10746
10990
  return this.done ? 0 : 1;
10747
10991
  },
10748
- enumerable: false,
10749
- configurable: true
10750
- });
10751
- WebsocketDuplexConnection.prototype.close = function (error) {
10752
- if (this.done) {
10753
- _super.prototype.close.call(this, error);
10754
- return;
10755
- }
10756
- this.websocket.removeEventListener("close", this.handleClosed);
10757
- this.websocket.removeEventListener("error", this.handleError);
10758
- this.websocket.removeEventListener("message", this.handleMessage);
10759
- this.websocket.close();
10760
- delete this.websocket;
10761
- _super.prototype.close.call(this, error);
10762
- };
10763
- WebsocketDuplexConnection.prototype.send = function (frame) {
10764
- if (this.done) {
10765
- return;
10766
- }
10767
- var buffer = (0, rsocket_core_1.serializeFrame)(frame);
10768
- this.websocket.send(buffer);
10769
- };
10770
- return WebsocketDuplexConnection;
10771
- }(rsocket_core_1.Deferred));
10772
- WebsocketDuplexConnection.WebsocketDuplexConnection = WebsocketDuplexConnection$1;
10773
-
10774
- return WebsocketDuplexConnection;
10775
- }
10776
-
10777
- var WebsocketDuplexConnectionExports = requireWebsocketDuplexConnection();
10778
-
10779
- /**
10780
- * Adapted from rsocket-websocket-client
10781
- * https://github.com/rsocket/rsocket-js/blob/e224cf379e747c4f1ddc4f2fa111854626cc8575/packages/rsocket-websocket-client/src/WebsocketClientTransport.ts#L17
10782
- * This adds additional error handling for React Native iOS.
10783
- * This particularly adds a close listener to handle cases where the WebSocket
10784
- * connection closes immediately after opening without emitting an error.
10785
- */
10786
- class WebsocketClientTransport {
10787
- url;
10788
- factory;
10789
- constructor(options) {
10790
- this.url = options.url;
10791
- this.factory = options.wsCreator ?? ((url) => new WebSocket(url));
10792
- }
10793
- connect(multiplexerDemultiplexerFactory) {
10794
- return new Promise((resolve, reject) => {
10795
- const websocket = this.factory(this.url);
10796
- websocket.binaryType = 'arraybuffer';
10797
- let removeListeners;
10798
- const openListener = () => {
10799
- removeListeners();
10800
- resolve(new WebsocketDuplexConnectionExports.WebsocketDuplexConnection(websocket, new distExports.Deserializer(), multiplexerDemultiplexerFactory));
10801
- };
10802
- const errorListener = (ev) => {
10803
- removeListeners();
10804
- // We add a default error in that case.
10805
- if (ev.error != null) {
10806
- // undici typically provides an error object
10807
- reject(ev.error);
10808
- }
10809
- else if (ev.message != null) {
10810
- // React Native typically does not provide an error object, but does provide a message
10811
- reject(new Error(`Failed to create websocket connection: ${ev.message}`));
10812
- }
10813
- else {
10814
- // Browsers often provide no details at all
10815
- reject(new Error(`Failed to create websocket connection to ${this.url}`));
10816
- }
10817
- };
10818
- /**
10819
- * In some cases, such as React Native iOS, the WebSocket connection may close immediately after opening
10820
- * without and error. In such cases, we need to handle the close event to reject the promise.
10821
- */
10822
- const closeListener = () => {
10823
- removeListeners();
10824
- reject(new Error('WebSocket connection closed while opening'));
10825
- };
10826
- removeListeners = () => {
10827
- websocket.removeEventListener('open', openListener);
10828
- websocket.removeEventListener('error', errorListener);
10829
- websocket.removeEventListener('close', closeListener);
10830
- };
10831
- websocket.addEventListener('open', openListener);
10832
- websocket.addEventListener('error', errorListener);
10833
- websocket.addEventListener('close', closeListener);
10834
- });
10835
- }
10836
- }
10837
-
10838
- const doneResult = { done: true, value: undefined };
10839
- function valueResult(value) {
10840
- return { done: false, value };
10841
- }
10842
- /**
10843
- * Expands a source async iterator by allowing to inject events asynchronously.
10844
- *
10845
- * The resulting iterator will emit all events from its source. Additionally though, events can be injected. These
10846
- * events are dropped once the main iterator completes, but are otherwise forwarded.
10847
- *
10848
- * The iterator completes when its source completes, and it supports backpressure by only calling `next()` on the source
10849
- * in response to a `next()` call from downstream if no pending injected events can be dispatched.
10850
- */
10851
- function injectable(source) {
10852
- let sourceIsDone = false;
10853
- let waiter = undefined; // An active, waiting next() call.
10854
- // A pending upstream event that couldn't be dispatched because inject() has been called before it was resolved.
10855
- let pendingSourceEvent = null;
10856
- let sourceFetchInFlight = false;
10857
- let pendingInjectedEvents = [];
10858
- const consumeWaiter = () => {
10859
- const pending = waiter;
10860
- waiter = undefined;
10861
- return pending;
10862
- };
10863
- const fetchFromSource = () => {
10864
- const resolveWaiter = (propagate) => {
10865
- sourceFetchInFlight = false;
10866
- const active = consumeWaiter();
10867
- if (active) {
10868
- propagate(active);
10869
- }
10870
- else {
10871
- pendingSourceEvent = propagate;
10872
- }
10873
- };
10874
- sourceFetchInFlight = true;
10875
- const nextFromSource = source.next();
10876
- nextFromSource.then((value) => {
10877
- sourceIsDone = value.done == true;
10878
- resolveWaiter((w) => w.resolve(value));
10879
- }, (error) => {
10880
- resolveWaiter((w) => w.reject(error));
10881
- });
10882
- };
10883
- return {
10884
- next: () => {
10885
- return new Promise((resolve, reject) => {
10886
- // First priority: Dispatch ready upstream events.
10887
- if (sourceIsDone) {
10888
- return resolve(doneResult);
10889
- }
10890
- if (pendingSourceEvent) {
10891
- pendingSourceEvent({ resolve, reject });
10892
- pendingSourceEvent = null;
10893
- return;
10894
- }
10895
- // Second priority: Dispatch injected events
10896
- if (pendingInjectedEvents.length) {
10897
- return resolve(valueResult(pendingInjectedEvents.shift()));
10898
- }
10899
- // Nothing pending? Fetch from source
10900
- waiter = { resolve, reject };
10901
- if (!sourceFetchInFlight) {
10902
- fetchFromSource();
10903
- }
10904
- });
10905
- },
10906
- inject: (event) => {
10907
- const pending = consumeWaiter();
10908
- if (pending != null) {
10909
- pending.resolve(valueResult(event));
10910
- }
10911
- else {
10912
- pendingInjectedEvents.push(event);
10913
- }
10914
- }
10915
- };
10916
- }
10917
- /**
10918
- * Splits a byte stream at line endings, emitting each line as a string.
10919
- */
10920
- function extractJsonLines(source, decoder) {
10921
- let buffer = '';
10922
- const pendingLines = [];
10923
- let isFinalEvent = false;
10924
- return {
10925
- next: async () => {
10926
- while (true) {
10927
- if (isFinalEvent) {
10928
- return doneResult;
10929
- }
10930
- {
10931
- const first = pendingLines.shift();
10932
- if (first) {
10933
- return { done: false, value: first };
10934
- }
10935
- }
10936
- const { done, value } = await source.next();
10937
- if (done) {
10938
- const remaining = buffer.trim();
10939
- if (remaining.length != 0) {
10940
- isFinalEvent = true;
10941
- return { done: false, value: remaining };
10942
- }
10943
- return doneResult;
10944
- }
10945
- const data = decoder.decode(value, { stream: true });
10946
- buffer += data;
10947
- const lines = buffer.split('\n');
10948
- for (let i = 0; i < lines.length - 1; i++) {
10949
- const l = lines[i].trim();
10950
- if (l.length > 0) {
10951
- pendingLines.push(l);
10952
- }
10953
- }
10954
- buffer = lines[lines.length - 1];
10955
- }
10956
- }
10957
- };
10992
+ enumerable: false,
10993
+ configurable: true
10994
+ });
10995
+ WebsocketDuplexConnection.prototype.close = function (error) {
10996
+ if (this.done) {
10997
+ _super.prototype.close.call(this, error);
10998
+ return;
10999
+ }
11000
+ this.websocket.removeEventListener("close", this.handleClosed);
11001
+ this.websocket.removeEventListener("error", this.handleError);
11002
+ this.websocket.removeEventListener("message", this.handleMessage);
11003
+ this.websocket.close();
11004
+ delete this.websocket;
11005
+ _super.prototype.close.call(this, error);
11006
+ };
11007
+ WebsocketDuplexConnection.prototype.send = function (frame) {
11008
+ if (this.done) {
11009
+ return;
11010
+ }
11011
+ var buffer = (0, rsocket_core_1.serializeFrame)(frame);
11012
+ this.websocket.send(buffer);
11013
+ };
11014
+ return WebsocketDuplexConnection;
11015
+ }(rsocket_core_1.Deferred));
11016
+ WebsocketDuplexConnection.WebsocketDuplexConnection = WebsocketDuplexConnection$1;
11017
+
11018
+ return WebsocketDuplexConnection;
10958
11019
  }
11020
+
11021
+ var WebsocketDuplexConnectionExports = requireWebsocketDuplexConnection();
11022
+
10959
11023
  /**
10960
- * Splits a concatenated stream of BSON objects by emitting individual objects.
11024
+ * Adapted from rsocket-websocket-client
11025
+ * https://github.com/rsocket/rsocket-js/blob/e224cf379e747c4f1ddc4f2fa111854626cc8575/packages/rsocket-websocket-client/src/WebsocketClientTransport.ts#L17
11026
+ * This adds additional error handling for React Native iOS.
11027
+ * This particularly adds a close listener to handle cases where the WebSocket
11028
+ * connection closes immediately after opening without emitting an error.
10961
11029
  */
10962
- function extractBsonObjects(source) {
10963
- // Fully read but not emitted yet.
10964
- const completedObjects = [];
10965
- // Whether source has returned { done: true }. We do the same once completed objects have been emitted.
10966
- let isDone = false;
10967
- const lengthBuffer = new DataView(new ArrayBuffer(4));
10968
- let objectBody = null;
10969
- // If we're parsing the length field, a number between 1 and 4 (inclusive) describing remaining bytes in the header.
10970
- // If we're consuming a document, the bytes remaining.
10971
- let remainingLength = 4;
10972
- return {
10973
- async next() {
10974
- while (true) {
10975
- // Before fetching new data from upstream, return completed objects.
10976
- if (completedObjects.length) {
10977
- return valueResult(completedObjects.shift());
10978
- }
10979
- if (isDone) {
10980
- return doneResult;
11030
+ class WebsocketClientTransport {
11031
+ url;
11032
+ factory;
11033
+ constructor(options) {
11034
+ this.url = options.url;
11035
+ this.factory = options.wsCreator ?? ((url) => new WebSocket(url));
11036
+ }
11037
+ connect(multiplexerDemultiplexerFactory) {
11038
+ return new Promise((resolve, reject) => {
11039
+ const websocket = this.factory(this.url);
11040
+ websocket.binaryType = 'arraybuffer';
11041
+ let removeListeners;
11042
+ const openListener = () => {
11043
+ removeListeners();
11044
+ resolve(new WebsocketDuplexConnectionExports.WebsocketDuplexConnection(websocket, new distExports.Deserializer(), multiplexerDemultiplexerFactory));
11045
+ };
11046
+ const errorListener = (event) => {
11047
+ const ev = event;
11048
+ removeListeners();
11049
+ // We add a default error in that case.
11050
+ if (ev.error != null) {
11051
+ // undici typically provides an error object
11052
+ reject(ev.error);
10981
11053
  }
10982
- const upstreamEvent = await source.next();
10983
- if (upstreamEvent.done) {
10984
- isDone = true;
10985
- if (objectBody || remainingLength != 4) {
10986
- throw new Error('illegal end of stream in BSON object');
10987
- }
10988
- return doneResult;
11054
+ else if (ev.message != null) {
11055
+ // React Native typically does not provide an error object, but does provide a message
11056
+ reject(new Error(`Failed to create websocket connection: ${ev.message}`));
10989
11057
  }
10990
- const chunk = upstreamEvent.value;
10991
- for (let i = 0; i < chunk.length;) {
10992
- const availableInData = chunk.length - i;
10993
- if (objectBody) {
10994
- // We're in the middle of reading a BSON document.
10995
- const bytesToRead = Math.min(availableInData, remainingLength);
10996
- const copySource = new Uint8Array(chunk.buffer, chunk.byteOffset + i, bytesToRead);
10997
- objectBody.set(copySource, objectBody.length - remainingLength);
10998
- i += bytesToRead;
10999
- remainingLength -= bytesToRead;
11000
- if (remainingLength == 0) {
11001
- completedObjects.push(objectBody);
11002
- // Prepare to read another document, starting with its length
11003
- objectBody = null;
11004
- remainingLength = 4;
11005
- }
11006
- }
11007
- else {
11008
- // Copy up to 4 bytes into lengthBuffer, depending on how many we still need.
11009
- const bytesToRead = Math.min(availableInData, remainingLength);
11010
- for (let j = 0; j < bytesToRead; j++) {
11011
- lengthBuffer.setUint8(4 - remainingLength + j, chunk[i + j]);
11012
- }
11013
- i += bytesToRead;
11014
- remainingLength -= bytesToRead;
11015
- if (remainingLength == 0) {
11016
- // Transition from reading length header to reading document. Subtracting 4 because the length of the
11017
- // header is included in length.
11018
- const length = lengthBuffer.getInt32(0, true /* little endian */);
11019
- remainingLength = length - 4;
11020
- if (remainingLength < 1) {
11021
- throw new Error(`invalid length for bson: ${length}`);
11022
- }
11023
- objectBody = new Uint8Array(length);
11024
- new DataView(objectBody.buffer).setInt32(0, length, true);
11025
- }
11026
- }
11058
+ else {
11059
+ // Browsers often provide no details at all
11060
+ reject(new Error(`Failed to create websocket connection to ${this.url}`));
11027
11061
  }
11028
- }
11029
- }
11030
- };
11062
+ };
11063
+ /**
11064
+ * In some cases, such as React Native iOS, the WebSocket connection may close immediately after opening
11065
+ * without and error. In such cases, we need to handle the close event to reject the promise.
11066
+ */
11067
+ const closeListener = () => {
11068
+ removeListeners();
11069
+ reject(new Error('WebSocket connection closed while opening'));
11070
+ };
11071
+ removeListeners = () => {
11072
+ websocket.removeEventListener('open', openListener);
11073
+ websocket.removeEventListener('error', errorListener);
11074
+ websocket.removeEventListener('close', closeListener);
11075
+ };
11076
+ websocket.addEventListener('open', openListener);
11077
+ websocket.addEventListener('error', errorListener);
11078
+ websocket.addEventListener('close', closeListener);
11079
+ });
11080
+ }
11031
11081
  }
11032
11082
 
11033
11083
  const POWERSYNC_TRAILING_SLASH_MATCH = /\/+$/;
@@ -11042,7 +11092,13 @@ const SOCKET_TIMEOUT_MS = 30_000;
11042
11092
  // If there is a backlog of messages (for example on slow connections), keepalive messages could be delayed
11043
11093
  // significantly. Therefore this is longer than the socket timeout.
11044
11094
  const KEEP_ALIVE_LIFETIME_MS = 90_000;
11095
+ /**
11096
+ * @internal
11097
+ */
11045
11098
  const DEFAULT_REMOTE_LOGGER = Logger.get('PowerSyncRemote');
11099
+ /**
11100
+ * @public
11101
+ */
11046
11102
  exports.FetchStrategy = void 0;
11047
11103
  (function (FetchStrategy) {
11048
11104
  /**
@@ -11061,12 +11117,17 @@ exports.FetchStrategy = void 0;
11061
11117
  * The class wrapper is used to distinguish the fetchImplementation
11062
11118
  * option in [AbstractRemoteOptions] from the general fetch method
11063
11119
  * which is typeof "function"
11120
+ *
11121
+ * @internal
11064
11122
  */
11065
11123
  class FetchImplementationProvider {
11066
11124
  getFetch() {
11067
11125
  throw new Error('Unspecified fetch implementation');
11068
11126
  }
11069
11127
  }
11128
+ /**
11129
+ * @internal
11130
+ */
11070
11131
  const DEFAULT_REMOTE_OPTIONS = {
11071
11132
  socketUrlTransformer: (url) => url.replace(/^https?:\/\//, function (match) {
11072
11133
  return match === 'https://' ? 'wss://' : 'ws://';
@@ -11074,6 +11135,9 @@ const DEFAULT_REMOTE_OPTIONS = {
11074
11135
  fetchImplementation: new FetchImplementationProvider(),
11075
11136
  fetchOptions: {}
11076
11137
  };
11138
+ /**
11139
+ * @internal
11140
+ */
11077
11141
  class AbstractRemote {
11078
11142
  connector;
11079
11143
  logger;
@@ -11234,8 +11298,19 @@ class AbstractRemote {
11234
11298
  let pendingSocket = null;
11235
11299
  let keepAliveTimeout;
11236
11300
  let rsocket = null;
11237
- let queue = null;
11301
+ let paused = false;
11302
+ const queue = new EventQueue({
11303
+ eventDelivered: () => {
11304
+ if (queue.countOutstandingEvents <= SYNC_QUEUE_REQUEST_LOW_WATER) {
11305
+ paused = false;
11306
+ requestMore();
11307
+ }
11308
+ }
11309
+ });
11238
11310
  let didClose = false;
11311
+ let connectionEstablished = false;
11312
+ let pendingEventsCount = syncQueueRequestSize;
11313
+ let res = null;
11239
11314
  const abortRequest = () => {
11240
11315
  if (didClose) {
11241
11316
  return;
@@ -11248,10 +11323,23 @@ class AbstractRemote {
11248
11323
  if (rsocket) {
11249
11324
  rsocket.close();
11250
11325
  }
11251
- if (queue) {
11252
- queue.stop();
11253
- }
11326
+ // Send a bogus event to the queue to ensure a pending listener gets woken up. We check for didClose and would
11327
+ // return a doneEvent.
11328
+ queue.notify(null);
11254
11329
  };
11330
+ function push(event) {
11331
+ queue.notify(event);
11332
+ if (queue.countOutstandingEvents >= SYNC_QUEUE_REQUEST_HIGH_WATER) {
11333
+ paused = true;
11334
+ }
11335
+ }
11336
+ function requestMore() {
11337
+ const delta = syncQueueRequestSize - pendingEventsCount;
11338
+ if (!paused && delta > 0) {
11339
+ res?.request(delta);
11340
+ pendingEventsCount = syncQueueRequestSize;
11341
+ }
11342
+ }
11255
11343
  // Handle upstream abort
11256
11344
  if (options.abortSignal.aborted) {
11257
11345
  throw new AbortOperation('Connection request aborted');
@@ -11306,25 +11394,19 @@ class AbstractRemote {
11306
11394
  // Helps to prevent double close scenarios
11307
11395
  rsocket.onClose(() => (rsocket = null));
11308
11396
  return await new Promise((resolve, reject) => {
11309
- let connectionEstablished = false;
11310
- let pendingEventsCount = syncQueueRequestSize;
11311
- let paused = false;
11312
- let res = null;
11313
- function requestMore() {
11314
- const delta = syncQueueRequestSize - pendingEventsCount;
11315
- if (!paused && delta > 0) {
11316
- res?.request(delta);
11317
- pendingEventsCount = syncQueueRequestSize;
11397
+ const queueAsIterator = {
11398
+ next: async () => {
11399
+ if (didClose)
11400
+ return doneResult;
11401
+ const notification = await queue.waitForEvent(options.abortSignal);
11402
+ if (didClose) {
11403
+ return doneResult;
11404
+ }
11405
+ else {
11406
+ return valueResult(notification);
11407
+ }
11318
11408
  }
11319
- }
11320
- const events = new domExports.EventIterator((q) => {
11321
- queue = q;
11322
- q.on('highWater', () => (paused = true));
11323
- q.on('lowWater', () => {
11324
- paused = false;
11325
- requestMore();
11326
- });
11327
- }, { highWaterMark: SYNC_QUEUE_REQUEST_HIGH_WATER, lowWaterMark: SYNC_QUEUE_REQUEST_LOW_WATER })[symbolAsyncIterator]();
11409
+ };
11328
11410
  res = rsocket.requestStream({
11329
11411
  data: toBuffer(options.data),
11330
11412
  metadata: toBuffer({
@@ -11360,11 +11442,11 @@ class AbstractRemote {
11360
11442
  // The connection is active
11361
11443
  if (!connectionEstablished) {
11362
11444
  connectionEstablished = true;
11363
- resolve(events);
11445
+ resolve(queueAsIterator);
11364
11446
  }
11365
11447
  const { data } = payload;
11366
11448
  if (data) {
11367
- queue.push(data);
11449
+ push(data);
11368
11450
  }
11369
11451
  // Less events are now pending
11370
11452
  pendingEventsCount--;
@@ -11483,7 +11565,7 @@ class AbstractRemote {
11483
11565
  * Posts a `/sync/stream` request.
11484
11566
  *
11485
11567
  * Depending on the `Content-Type` of the response, this returns strings for sync lines or encoded BSON documents as
11486
- * {@link Uint8Array}s.
11568
+ * `Uint8Array`s.
11487
11569
  */
11488
11570
  async fetchStream(options) {
11489
11571
  const { isBson, stream } = await this.fetchStreamRaw(options);
@@ -11525,16 +11607,26 @@ function isInterruptingInstruction(instruction) {
11525
11607
  return 'EstablishSyncStream' in instruction || 'CloseSyncStream' in instruction;
11526
11608
  }
11527
11609
 
11610
+ /**
11611
+ * @internal
11612
+ */
11528
11613
  exports.LockType = void 0;
11529
11614
  (function (LockType) {
11530
11615
  LockType["CRUD"] = "crud";
11531
11616
  LockType["SYNC"] = "sync";
11532
11617
  })(exports.LockType || (exports.LockType = {}));
11618
+ /**
11619
+ * @public
11620
+ */
11533
11621
  exports.SyncStreamConnectionMethod = void 0;
11534
11622
  (function (SyncStreamConnectionMethod) {
11535
11623
  SyncStreamConnectionMethod["HTTP"] = "http";
11536
11624
  SyncStreamConnectionMethod["WEB_SOCKET"] = "web-socket";
11537
11625
  })(exports.SyncStreamConnectionMethod || (exports.SyncStreamConnectionMethod = {}));
11626
+ /**
11627
+ * @deprecated Deprecated since {@link SyncClientImplementation.RUST} is the only option.
11628
+ * @public
11629
+ */
11538
11630
  exports.SyncClientImplementation = void 0;
11539
11631
  (function (SyncClientImplementation) {
11540
11632
  /**
@@ -11546,8 +11638,8 @@ exports.SyncClientImplementation = void 0;
11546
11638
  * ## Compatibility warning
11547
11639
  *
11548
11640
  * The Rust sync client stores sync data in a format that is slightly different than the one used
11549
- * by the old JavaScript client. When adopting the {@link RUST} client on existing databases, the PowerSync SDK will
11550
- * migrate the format automatically.
11641
+ * by the old JavaScript client. When adopting the {@link SyncClientImplementation.RUST} client on existing databases,
11642
+ * the PowerSync SDK will migrate the format automatically.
11551
11643
  *
11552
11644
  * SDK versions supporting both the JavaScript and the Rust client support both formats with the JavaScript client
11553
11645
  * implementaiton. However, downgrading to an SDK version that only supports the JavaScript client would not be
@@ -11557,14 +11649,29 @@ exports.SyncClientImplementation = void 0;
11557
11649
  })(exports.SyncClientImplementation || (exports.SyncClientImplementation = {}));
11558
11650
  /**
11559
11651
  * The default {@link SyncClientImplementation} to use, {@link SyncClientImplementation.RUST}.
11652
+ *
11653
+ * @deprecated Deprecated since {@link SyncClientImplementation.RUST} is the only option.
11654
+ * @public
11560
11655
  */
11561
11656
  const DEFAULT_SYNC_CLIENT_IMPLEMENTATION = exports.SyncClientImplementation.RUST;
11657
+ /**
11658
+ * @internal
11659
+ */
11562
11660
  const DEFAULT_CRUD_UPLOAD_THROTTLE_MS = 1000;
11661
+ /**
11662
+ * @internal
11663
+ */
11563
11664
  const DEFAULT_RETRY_DELAY_MS = 5000;
11665
+ /**
11666
+ * @internal
11667
+ */
11564
11668
  const DEFAULT_STREAMING_SYNC_OPTIONS = {
11565
11669
  retryDelayMs: DEFAULT_RETRY_DELAY_MS,
11566
11670
  crudUploadThrottleMs: DEFAULT_CRUD_UPLOAD_THROTTLE_MS
11567
11671
  };
11672
+ /**
11673
+ * @internal
11674
+ */
11568
11675
  const DEFAULT_STREAM_CONNECTION_OPTIONS = {
11569
11676
  appMetadata: {},
11570
11677
  connectionMethod: exports.SyncStreamConnectionMethod.WEB_SOCKET,
@@ -11574,6 +11681,9 @@ const DEFAULT_STREAM_CONNECTION_OPTIONS = {
11574
11681
  serializedSchema: undefined,
11575
11682
  includeDefaultStreams: true
11576
11683
  };
11684
+ /**
11685
+ * @internal
11686
+ */
11577
11687
  class AbstractStreamingSyncImplementation extends BaseObserver {
11578
11688
  options;
11579
11689
  abortController;
@@ -11897,7 +12007,7 @@ The next upload iteration will be delayed.`);
11897
12007
  this.handleActiveStreamsChange?.();
11898
12008
  }
11899
12009
  /**
11900
- * Older versions of the JS SDK used to encode subkeys as JSON in {@link OplogEntry.toJSON}.
12010
+ * Older versions of the JS SDK used to encode subkeys as JSON in `OplogEntry.toJSON`.
11901
12011
  * Because subkeys are always strings, this leads to quotes being added around them in `ps_oplog`.
11902
12012
  * While this is not a problem as long as it's done consistently, it causes issues when a database
11903
12013
  * created by the JS SDK is used with other SDKs, or (more likely) when the new Rust sync client
@@ -11907,7 +12017,7 @@ The next upload iteration will be delayed.`);
11907
12017
  * migration is only triggered when necessary (for now). The function returns whether the new format
11908
12018
  * should be used, so that the JS SDK is able to write to updated databases.
11909
12019
  *
11910
- * @param requireFixedKeyFormat Whether we require the new format or also support the old one.
12020
+ * @param requireFixedKeyFormat - Whether we require the new format or also support the old one.
11911
12021
  * The Rust client requires the new subkey format.
11912
12022
  * @returns Whether the database is now using the new, fixed subkey format.
11913
12023
  */
@@ -12214,7 +12324,8 @@ const MEMORY_TRIGGER_CLAIM_MANAGER = {
12214
12324
 
12215
12325
  /**
12216
12326
  * SQLite operations to track changes for with {@link TriggerManager}
12217
- * @experimental
12327
+ *
12328
+ * @experimental @alpha
12218
12329
  */
12219
12330
  exports.DiffTriggerOperation = void 0;
12220
12331
  (function (DiffTriggerOperation) {
@@ -12276,8 +12387,8 @@ class TriggerManagerImpl {
12276
12387
  get db() {
12277
12388
  return this.options.db;
12278
12389
  }
12279
- async getUUID() {
12280
- const { id: uuid } = await this.db.get(/* sql */ `
12390
+ async getUUID(ctx) {
12391
+ const { id: uuid } = await (ctx ?? this.db).get(/* sql */ `
12281
12392
  SELECT
12282
12393
  uuid () as id
12283
12394
  `);
@@ -12390,7 +12501,7 @@ class TriggerManagerImpl {
12390
12501
  const replicatedColumns = columns ?? sourceDefinition.columns.map((col) => col.name);
12391
12502
  const internalSource = sourceDefinition.internalName;
12392
12503
  const triggerIds = [];
12393
- const id = await this.getUUID();
12504
+ const id = await this.getUUID(setupContext);
12394
12505
  const releaseStorageClaim = useStorage ? await this.options.claimManager.obtainClaim(id) : null;
12395
12506
  /**
12396
12507
  * We default to replicating all columns if no columns array is provided.
@@ -12630,18 +12741,29 @@ const POWERSYNC_TABLE_MATCH = /(^ps_data__|^ps_data_local__)/;
12630
12741
  const DEFAULT_DISCONNECT_CLEAR_OPTIONS = {
12631
12742
  clearLocal: true
12632
12743
  };
12744
+ /**
12745
+ * @internal
12746
+ */
12633
12747
  const DEFAULT_POWERSYNC_CLOSE_OPTIONS = {
12634
12748
  disconnect: true
12635
12749
  };
12750
+ /**
12751
+ * @internal
12752
+ */
12636
12753
  const DEFAULT_POWERSYNC_DB_OPTIONS = {
12637
12754
  retryDelayMs: 5000,
12638
12755
  crudUploadThrottleMs: DEFAULT_CRUD_UPLOAD_THROTTLE_MS
12639
12756
  };
12757
+ /**
12758
+ * @internal
12759
+ */
12640
12760
  const DEFAULT_CRUD_BATCH_LIMIT = 100;
12641
12761
  /**
12642
12762
  * Requesting nested or recursive locks can block the application in some circumstances.
12643
12763
  * This default lock timeout will act as a failsafe to throw an error if a lock cannot
12644
12764
  * be obtained.
12765
+ *
12766
+ * @internal
12645
12767
  */
12646
12768
  const DEFAULT_LOCK_TIMEOUT_MS = 120_000; // 2 mins
12647
12769
  /**
@@ -12651,6 +12773,9 @@ const DEFAULT_LOCK_TIMEOUT_MS = 120_000; // 2 mins
12651
12773
  const isPowerSyncDatabaseOptionsWithSettings = (test) => {
12652
12774
  return typeof test == 'object' && isSQLOpenOptions(test.database);
12653
12775
  };
12776
+ /**
12777
+ * @public
12778
+ */
12654
12779
  class AbstractPowerSyncDatabase extends BaseObserver {
12655
12780
  options;
12656
12781
  /**
@@ -12808,7 +12933,7 @@ class AbstractPowerSyncDatabase extends BaseObserver {
12808
12933
  /**
12809
12934
  * Wait for the first sync operation to complete.
12810
12935
  *
12811
- * @param request Either an abort signal (after which the promise will complete regardless of
12936
+ * @param request - Either an abort signal (after which the promise will complete regardless of
12812
12937
  * whether a full sync was completed) or an object providing an abort signal and a priority target.
12813
12938
  * When a priority target is set, the promise may complete when all buckets with the given (or higher)
12814
12939
  * priorities have been synchronized. This can be earlier than a complete sync.
@@ -12963,7 +13088,7 @@ class AbstractPowerSyncDatabase extends BaseObserver {
12963
13088
  /**
12964
13089
  * Close the sync connection.
12965
13090
  *
12966
- * Use {@link connect} to connect again.
13091
+ * Use {@link AbstractPowerSyncDatabase.connect} to connect again.
12967
13092
  */
12968
13093
  async disconnect() {
12969
13094
  return this.connectionManager.disconnect();
@@ -12990,8 +13115,8 @@ class AbstractPowerSyncDatabase extends BaseObserver {
12990
13115
  /**
12991
13116
  * Create a sync stream to query its status or to subscribe to it.
12992
13117
  *
12993
- * @param name The name of the stream to subscribe to.
12994
- * @param params Optional parameters for the stream subscription.
13118
+ * @param name - The name of the stream to subscribe to.
13119
+ * @param params - Optional parameters for the stream subscription.
12995
13120
  * @returns A {@link SyncStream} instance that can be subscribed to.
12996
13121
  * @experimental Sync streams are currently in alpha.
12997
13122
  */
@@ -13049,14 +13174,14 @@ class AbstractPowerSyncDatabase extends BaseObserver {
13049
13174
  * Once the data have been successfully uploaded, call {@link CrudBatch.complete} before
13050
13175
  * requesting the next batch.
13051
13176
  *
13052
- * Use {@link limit} to specify the maximum number of updates to return in a single
13177
+ * Use the `limit` parameter to specify the maximum number of updates to return in a single
13053
13178
  * batch.
13054
13179
  *
13055
13180
  * This method does include transaction ids in the result, but does not group
13056
13181
  * data by transaction. One batch may contain data from multiple transactions,
13057
13182
  * and a single transaction may be split over multiple batches.
13058
13183
  *
13059
- * @param limit Maximum number of CRUD entries to include in the batch
13184
+ * @param limit - Maximum number of CRUD entries to include in the batch
13060
13185
  * @returns A batch of CRUD operations to upload, or null if there are none
13061
13186
  */
13062
13187
  async getCrudBatch(limit = DEFAULT_CRUD_BATCH_LIMIT) {
@@ -13083,7 +13208,7 @@ class AbstractPowerSyncDatabase extends BaseObserver {
13083
13208
  * Once the data have been successfully uploaded, call {@link CrudTransaction.complete} before
13084
13209
  * requesting the next transaction.
13085
13210
  *
13086
- * Unlike {@link getCrudBatch}, this only returns data from a single transaction at a time.
13211
+ * Unlike {@link AbstractPowerSyncDatabase.getCrudBatch}, this only returns data from a single transaction at a time.
13087
13212
  * All data for the transaction is loaded into memory.
13088
13213
  *
13089
13214
  * @returns A transaction of CRUD operations to upload, or null if there are none
@@ -13098,7 +13223,7 @@ class AbstractPowerSyncDatabase extends BaseObserver {
13098
13223
  * This is typically used from the {@link PowerSyncBackendConnector.uploadData} callback. Each entry emitted by the
13099
13224
  * returned iterator is a full transaction containing all local writes made while that transaction was active.
13100
13225
  *
13101
- * Unlike {@link getNextCrudTransaction}, which always returns the oldest transaction that hasn't been
13226
+ * Unlike {@link AbstractPowerSyncDatabase.getNextCrudTransaction}, which always returns the oldest transaction that hasn't been
13102
13227
  * {@link CrudTransaction.complete}d yet, this iterator can be used to receive multiple transactions. Calling
13103
13228
  * {@link CrudTransaction.complete} will mark that and all prior transactions emitted by the iterator as completed.
13104
13229
  *
@@ -13192,8 +13317,8 @@ SELECT * FROM crud_entries;
13192
13317
  * the returned result's `rowsAffected` may be `0` for successful `UPDATE` and `DELETE` statements.
13193
13318
  * Use a `RETURNING` clause and inspect `result.rows` when you need to confirm which rows changed.
13194
13319
  *
13195
- * @param sql The SQL query to execute
13196
- * @param parameters Optional array of parameters to bind to the query
13320
+ * @param sql - The SQL query to execute
13321
+ * @param parameters - Optional array of parameters to bind to the query
13197
13322
  * @returns The query result as an object with structured key-value pairs
13198
13323
  */
13199
13324
  async execute(sql, parameters) {
@@ -13203,8 +13328,8 @@ SELECT * FROM crud_entries;
13203
13328
  * Execute a SQL write (INSERT/UPDATE/DELETE) query directly on the database without any PowerSync processing.
13204
13329
  * This bypasses certain PowerSync abstractions and is useful for accessing the raw database results.
13205
13330
  *
13206
- * @param sql The SQL query to execute
13207
- * @param parameters Optional array of parameters to bind to the query
13331
+ * @param sql - The SQL query to execute
13332
+ * @param parameters - Optional array of parameters to bind to the query
13208
13333
  * @returns The raw query result from the underlying database as a nested array of raw values, where each row is
13209
13334
  * represented as an array of column values without field names.
13210
13335
  */
@@ -13217,8 +13342,8 @@ SELECT * FROM crud_entries;
13217
13342
  * and optionally return results.
13218
13343
  * This is faster than executing separately with each parameter set.
13219
13344
  *
13220
- * @param sql The SQL query to execute
13221
- * @param parameters Optional 2D array of parameter sets, where each inner array is a set of parameters for one execution
13345
+ * @param sql - The SQL query to execute
13346
+ * @param parameters - Optional 2D array of parameter sets, where each inner array is a set of parameters for one execution
13222
13347
  * @returns The query result
13223
13348
  */
13224
13349
  async executeBatch(sql, parameters) {
@@ -13228,8 +13353,8 @@ SELECT * FROM crud_entries;
13228
13353
  /**
13229
13354
  * Execute a read-only query and return results.
13230
13355
  *
13231
- * @param sql The SQL query to execute
13232
- * @param parameters Optional array of parameters to bind to the query
13356
+ * @param sql - The SQL query to execute
13357
+ * @param parameters - Optional array of parameters to bind to the query
13233
13358
  * @returns An array of results
13234
13359
  */
13235
13360
  async getAll(sql, parameters) {
@@ -13239,8 +13364,8 @@ SELECT * FROM crud_entries;
13239
13364
  /**
13240
13365
  * Execute a read-only query and return the first result, or null if the ResultSet is empty.
13241
13366
  *
13242
- * @param sql The SQL query to execute
13243
- * @param parameters Optional array of parameters to bind to the query
13367
+ * @param sql - The SQL query to execute
13368
+ * @param parameters - Optional array of parameters to bind to the query
13244
13369
  * @returns The first result if found, or null if no results are returned
13245
13370
  */
13246
13371
  async getOptional(sql, parameters) {
@@ -13250,8 +13375,8 @@ SELECT * FROM crud_entries;
13250
13375
  /**
13251
13376
  * Execute a read-only query and return the first result, error if the ResultSet is empty.
13252
13377
  *
13253
- * @param sql The SQL query to execute
13254
- * @param parameters Optional array of parameters to bind to the query
13378
+ * @param sql - The SQL query to execute
13379
+ * @param parameters - Optional array of parameters to bind to the query
13255
13380
  * @returns The first result matching the query
13256
13381
  * @throws Error if no rows are returned
13257
13382
  */
@@ -13261,7 +13386,7 @@ SELECT * FROM crud_entries;
13261
13386
  }
13262
13387
  /**
13263
13388
  * Takes a read lock, without starting a transaction.
13264
- * In most cases, {@link readTransaction} should be used instead.
13389
+ * In most cases, {@link AbstractPowerSyncDatabase.readTransaction} should be used instead.
13265
13390
  */
13266
13391
  async readLock(callback) {
13267
13392
  await this.waitForReady();
@@ -13269,7 +13394,7 @@ SELECT * FROM crud_entries;
13269
13394
  }
13270
13395
  /**
13271
13396
  * Takes a global lock, without starting a transaction.
13272
- * In most cases, {@link writeTransaction} should be used instead.
13397
+ * In most cases, {@link AbstractPowerSyncDatabase.writeTransaction} should be used instead.
13273
13398
  */
13274
13399
  async writeLock(callback) {
13275
13400
  await this.waitForReady();
@@ -13280,8 +13405,8 @@ SELECT * FROM crud_entries;
13280
13405
  * Read transactions can run concurrently to a write transaction.
13281
13406
  * Changes from any write transaction are not visible to read transactions started before it.
13282
13407
  *
13283
- * @param callback Function to execute within the transaction
13284
- * @param lockTimeout Time in milliseconds to wait for a lock before throwing an error
13408
+ * @param callback - Function to execute within the transaction
13409
+ * @param lockTimeout - Time in milliseconds to wait for a lock before throwing an error
13285
13410
  * @returns The result of the callback
13286
13411
  * @throws Error if the lock cannot be obtained within the timeout period
13287
13412
  */
@@ -13298,8 +13423,8 @@ SELECT * FROM crud_entries;
13298
13423
  * This takes a global lock - only one write transaction can execute against the database at a time.
13299
13424
  * Statements within the transaction must be done on the provided {@link Transaction} interface.
13300
13425
  *
13301
- * @param callback Function to execute within the transaction
13302
- * @param lockTimeout Time in milliseconds to wait for a lock before throwing an error
13426
+ * @param callback - Function to execute within the transaction
13427
+ * @param lockTimeout - Time in milliseconds to wait for a lock before throwing an error
13303
13428
  * @returns The result of the callback
13304
13429
  * @throws Error if the lock cannot be obtained within the timeout period
13305
13430
  */
@@ -13376,15 +13501,15 @@ SELECT * FROM crud_entries;
13376
13501
  }
13377
13502
  /**
13378
13503
  * Execute a read query every time the source tables are modified.
13379
- * Use {@link SQLWatchOptions.throttleMs} to specify the minimum interval between queries.
13504
+ * Use {@link SQLOnChangeOptions.throttleMs} to specify the minimum interval between queries.
13380
13505
  * Source tables are automatically detected using `EXPLAIN QUERY PLAN`.
13381
13506
  *
13382
13507
  * Note that the `onChange` callback member of the handler is required.
13383
13508
  *
13384
- * @param sql The SQL query to execute
13385
- * @param parameters Optional array of parameters to bind to the query
13386
- * @param handler Callbacks for handling results and errors
13387
- * @param options Options for configuring watch behavior
13509
+ * @param sql - The SQL query to execute
13510
+ * @param parameters - Optional array of parameters to bind to the query
13511
+ * @param handler - Callbacks for handling results and errors
13512
+ * @param options - Options for configuring watch behavior
13388
13513
  */
13389
13514
  watchWithCallback(sql, parameters, handler, options) {
13390
13515
  const { onResult, onError = (e) => this.logger.error(e) } = handler ?? {};
@@ -13397,7 +13522,7 @@ SELECT * FROM crud_entries;
13397
13522
  const watchedQuery = new OnChangeQueryProcessor({
13398
13523
  db: this,
13399
13524
  comparator,
13400
- placeholderData: null,
13525
+ placeholderData: null, // FIXME
13401
13526
  watchOptions: {
13402
13527
  query: {
13403
13528
  compile: () => ({
@@ -13430,38 +13555,35 @@ SELECT * FROM crud_entries;
13430
13555
  }
13431
13556
  /**
13432
13557
  * Execute a read query every time the source tables are modified.
13433
- * Use {@link SQLWatchOptions.throttleMs} to specify the minimum interval between queries.
13558
+ * Use {@link SQLOnChangeOptions.throttleMs} to specify the minimum interval between queries.
13434
13559
  * Source tables are automatically detected using `EXPLAIN QUERY PLAN`.
13435
13560
  *
13436
- * @param sql The SQL query to execute
13437
- * @param parameters Optional array of parameters to bind to the query
13438
- * @param options Options for configuring watch behavior
13561
+ * @param sql - The SQL query to execute
13562
+ * @param parameters - Optional array of parameters to bind to the query
13563
+ * @param options - Options for configuring watch behavior
13439
13564
  * @returns An AsyncIterable that yields QueryResults whenever the data changes
13440
13565
  */
13441
13566
  watchWithAsyncGenerator(sql, parameters, options) {
13442
- return new domExports.EventIterator((eventOptions) => {
13567
+ return EventQueue.queueBasedAsyncIterable((queue, abort) => {
13443
13568
  const handler = {
13444
13569
  onResult: (result) => {
13445
- eventOptions.push(result);
13570
+ queue.notify(result);
13446
13571
  },
13447
13572
  onError: (error) => {
13448
- eventOptions.fail(error);
13573
+ queue.notifyError(error);
13449
13574
  }
13450
13575
  };
13451
- this.watchWithCallback(sql, parameters, handler, options);
13452
- options?.signal?.addEventListener('abort', () => {
13453
- eventOptions.stop();
13454
- });
13455
- });
13576
+ this.watchWithCallback(sql, parameters, handler, { ...options, signal: abort });
13577
+ }, options?.signal);
13456
13578
  }
13457
13579
  /**
13458
13580
  * Resolves the list of tables that are used in a SQL query.
13459
13581
  * If tables are specified in the options, those are used directly.
13460
13582
  * Otherwise, analyzes the query using EXPLAIN to determine which tables are accessed.
13461
13583
  *
13462
- * @param sql The SQL query to analyze
13463
- * @param parameters Optional parameters for the SQL query
13464
- * @param options Optional watch options that may contain explicit table list
13584
+ * @param sql - The SQL query to analyze
13585
+ * @param parameters - Optional parameters for the SQL query
13586
+ * @param options - Optional watch options that may contain explicit table list
13465
13587
  * @returns Array of table names that the query depends on
13466
13588
  */
13467
13589
  async resolveTables(sql, parameters, options) {
@@ -13490,13 +13612,13 @@ SELECT * FROM crud_entries;
13490
13612
  /**
13491
13613
  * Invoke the provided callback on any changes to any of the specified tables.
13492
13614
  *
13493
- * This is preferred over {@link watchWithCallback} when multiple queries need to be performed
13615
+ * This is preferred over {@link AbstractPowerSyncDatabase.watchWithCallback} when multiple queries need to be performed
13494
13616
  * together when data is changed.
13495
13617
  *
13496
13618
  * Note that the `onChange` callback member of the handler is required.
13497
13619
  *
13498
- * @param handler Callbacks for handling change events and errors
13499
- * @param options Options for configuring watch behavior
13620
+ * @param handler - Callbacks for handling change events and errors
13621
+ * @param options - Options for configuring watch behavior
13500
13622
  * @returns A dispose function to stop watching for changes
13501
13623
  */
13502
13624
  onChangeWithCallback(handler, options) {
@@ -13539,31 +13661,26 @@ SELECT * FROM crud_entries;
13539
13661
  /**
13540
13662
  * Create a Stream of changes to any of the specified tables.
13541
13663
  *
13542
- * This is preferred over {@link watchWithAsyncGenerator} when multiple queries need to be performed
13543
- * together when data is changed.
13544
- *
13545
- * Note: do not declare this as `async *onChange` as it will not work in React Native.
13664
+ * This is preferred over {@link AbstractPowerSyncDatabase.watchWithAsyncGenerator} when multiple queries need to be
13665
+ * performed together when data is changed.
13546
13666
  *
13547
- * @param options Options for configuring watch behavior
13667
+ * @param options - Options for configuring watch behavior
13548
13668
  * @returns An AsyncIterable that yields change events whenever the specified tables change
13549
13669
  */
13670
+ // Note: do not declare this as `async *onChange` as it will not work in React Native.
13550
13671
  onChangeWithAsyncGenerator(options) {
13551
- const resolvedOptions = options ?? {};
13552
- return new domExports.EventIterator((eventOptions) => {
13553
- const dispose = this.onChangeWithCallback({
13672
+ return EventQueue.queueBasedAsyncIterable((queue, abort) => {
13673
+ this.onChangeWithCallback({
13554
13674
  onChange: (event) => {
13555
- eventOptions.push(event);
13675
+ queue.notify(event);
13556
13676
  },
13557
13677
  onError: (error) => {
13558
- eventOptions.fail(error);
13678
+ queue.notifyError(error);
13559
13679
  }
13560
- }, options);
13561
- resolvedOptions.signal?.addEventListener('abort', () => {
13562
- eventOptions.stop();
13563
- // Maybe fail?
13564
- });
13565
- return () => dispose();
13566
- });
13680
+ }, { ...options, signal: abort });
13681
+ // Note: We don't have to track the dispose function returned by onChangeWithCallback, it cleans up
13682
+ // after the abort signal completes.
13683
+ }, options?.signal);
13567
13684
  }
13568
13685
  handleTableChanges(changedTables, watchedTables, onDetectedChanges) {
13569
13686
  if (changedTables.size > 0) {
@@ -13582,15 +13699,15 @@ SELECT * FROM crud_entries;
13582
13699
  changedTables.add(table);
13583
13700
  }
13584
13701
  }
13585
- /**
13586
- * @ignore
13587
- */
13588
13702
  async executeReadOnly(sql, params) {
13589
13703
  await this.waitForReady();
13590
13704
  return this.database.readLock((tx) => tx.execute(sql, params));
13591
13705
  }
13592
13706
  }
13593
13707
 
13708
+ /**
13709
+ * @internal
13710
+ */
13594
13711
  class AbstractPowerSyncDatabaseOpenFactory {
13595
13712
  options;
13596
13713
  constructor(options) {
@@ -13615,6 +13732,9 @@ class AbstractPowerSyncDatabaseOpenFactory {
13615
13732
  }
13616
13733
  }
13617
13734
 
13735
+ /**
13736
+ * @internal
13737
+ */
13618
13738
  function runOnSchemaChange(callback, db, options) {
13619
13739
  const triggerWatchedQuery = () => {
13620
13740
  const abortController = new AbortController();
@@ -13639,6 +13759,9 @@ function runOnSchemaChange(callback, db, options) {
13639
13759
  triggerWatchedQuery();
13640
13760
  }
13641
13761
 
13762
+ /**
13763
+ * @public
13764
+ */
13642
13765
  function compilableQueryWatch(db, query, handler, options) {
13643
13766
  const { onResult, onError = (e) => { } } = handler ?? {};
13644
13767
  if (!onResult) {
@@ -13676,8 +13799,14 @@ function compilableQueryWatch(db, query, handler, options) {
13676
13799
  runOnSchemaChange(watchQuery, db, options);
13677
13800
  }
13678
13801
 
13802
+ /**
13803
+ * @internal
13804
+ */
13679
13805
  const MAX_OP_ID = '9223372036854775807';
13680
13806
 
13807
+ /**
13808
+ * @internal
13809
+ */
13681
13810
  class SqliteBucketStorage extends BaseObserver {
13682
13811
  db;
13683
13812
  logger;
@@ -13838,6 +13967,8 @@ class SqliteBucketStorage extends BaseObserver {
13838
13967
  * Thrown when an underlying database connection is closed.
13839
13968
  * This is particularly relevant when worker connections are marked as closed while
13840
13969
  * operations are still in progress.
13970
+ *
13971
+ * @internal
13841
13972
  */
13842
13973
  class ConnectionClosedError extends Error {
13843
13974
  static NAME = 'ConnectionClosedError';
@@ -13857,6 +13988,8 @@ class ConnectionClosedError extends Error {
13857
13988
 
13858
13989
  /**
13859
13990
  * A schema is a collection of tables. It is used to define the structure of a database.
13991
+ *
13992
+ * @public
13860
13993
  */
13861
13994
  class Schema {
13862
13995
  /*
@@ -13893,7 +14026,7 @@ class Schema {
13893
14026
  * Since raw tables are not backed by JSON, running complex queries on them may be more efficient. Further, they allow
13894
14027
  * using client-side table and column constraints.
13895
14028
  *
13896
- * @param tables An object of (table name, raw table definition) entries.
14029
+ * @param tables - An object of (table name, raw table definition) entries.
13897
14030
  */
13898
14031
  withRawTables(tables) {
13899
14032
  for (const [name, rawTableDefinition] of Object.entries(tables)) {
@@ -13939,6 +14072,8 @@ class Schema {
13939
14072
  Generate a new table from the columns and indexes
13940
14073
  @deprecated You should use {@link Table} instead as it now allows TableV2 syntax.
13941
14074
  This will be removed in the next major release.
14075
+
14076
+ @public
13942
14077
  */
13943
14078
  class TableV2 extends Table {
13944
14079
  }
@@ -13949,6 +14084,8 @@ function sanitizeString(input) {
13949
14084
  /**
13950
14085
  * Helper function for sanitizing UUID input strings.
13951
14086
  * Typically used with {@link sanitizeSQL}.
14087
+ *
14088
+ * @alpha
13952
14089
  */
13953
14090
  function sanitizeUUID(uuid) {
13954
14091
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
@@ -13985,6 +14122,8 @@ function sanitizeUUID(uuid) {
13985
14122
  * // Incorrect:
13986
14123
  * sanitizeSQL`New.id = '${myID}'` // Produces double quotes: New.id = ''O''Reilly''
13987
14124
  * ```
14125
+ *
14126
+ * @alpha
13988
14127
  */
13989
14128
  function sanitizeSQL(strings, ...values) {
13990
14129
  let result = '';
@@ -14014,6 +14153,8 @@ function sanitizeSQL(strings, ...values) {
14014
14153
 
14015
14154
  /**
14016
14155
  * Performs a {@link AbstractPowerSyncDatabase.getAll} operation for a watched query.
14156
+ *
14157
+ * @public
14017
14158
  */
14018
14159
  class GetAllQuery {
14019
14160
  options;
@@ -14038,6 +14179,9 @@ class GetAllQuery {
14038
14179
  }
14039
14180
 
14040
14181
  const TypedLogger = Logger;
14182
+ /**
14183
+ * @public
14184
+ */
14041
14185
  const LogLevel = {
14042
14186
  TRACE: TypedLogger.TRACE,
14043
14187
  DEBUG: TypedLogger.DEBUG,
@@ -14054,6 +14198,7 @@ const LogLevel = {
14054
14198
  * across all loggers created with `createLogger`. Adjusting settings on this
14055
14199
  * base logger affects all loggers derived from it unless explicitly overridden.
14056
14200
  *
14201
+ * @public
14057
14202
  */
14058
14203
  function createBaseLogger() {
14059
14204
  return Logger;
@@ -14064,6 +14209,8 @@ function createBaseLogger() {
14064
14209
  * Named loggers allow specific modules or areas of your application to have
14065
14210
  * their own logging levels and behaviors. These loggers inherit configuration
14066
14211
  * from the base logger by default but can override settings independently.
14212
+ *
14213
+ * @public
14067
14214
  */
14068
14215
  function createLogger(name, options = {}) {
14069
14216
  const logger = Logger.get(name);
@@ -14073,6 +14220,9 @@ function createLogger(name, options = {}) {
14073
14220
  return logger;
14074
14221
  }
14075
14222
 
14223
+ /**
14224
+ * @internal
14225
+ */
14076
14226
  const parseQuery = (query, parameters) => {
14077
14227
  let sqlStatement;
14078
14228
  if (typeof query == 'string') {