@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.
- package/dist/bundle.cjs +922 -772
- package/dist/bundle.cjs.map +1 -1
- package/dist/bundle.mjs +922 -772
- package/dist/bundle.mjs.map +1 -1
- package/dist/bundle.node.cjs +923 -619
- package/dist/bundle.node.cjs.map +1 -1
- package/dist/bundle.node.mjs +923 -619
- package/dist/bundle.node.mjs.map +1 -1
- package/dist/index.d.cts +749 -205
- package/lib/attachments/AttachmentContext.d.ts +7 -6
- package/lib/attachments/AttachmentContext.js +2 -1
- package/lib/attachments/AttachmentContext.js.map +1 -1
- package/lib/attachments/AttachmentErrorHandler.d.ts +6 -6
- package/lib/attachments/AttachmentQueue.d.ts +82 -33
- package/lib/attachments/AttachmentQueue.js +16 -18
- package/lib/attachments/AttachmentQueue.js.map +1 -1
- package/lib/attachments/LocalStorageAdapter.d.ts +14 -8
- package/lib/attachments/LocalStorageAdapter.js +3 -0
- package/lib/attachments/LocalStorageAdapter.js.map +1 -1
- package/lib/attachments/RemoteStorageAdapter.d.ts +4 -4
- package/lib/attachments/Schema.d.ts +12 -4
- package/lib/attachments/Schema.js +8 -3
- package/lib/attachments/Schema.js.map +1 -1
- package/lib/attachments/WatchedAttachmentItem.d.ts +3 -1
- package/lib/client/AbstractPowerSyncDatabase.d.ts +110 -60
- package/lib/client/AbstractPowerSyncDatabase.js +77 -74
- package/lib/client/AbstractPowerSyncDatabase.js.map +1 -1
- package/lib/client/AbstractPowerSyncOpenFactory.d.ts +6 -0
- package/lib/client/AbstractPowerSyncOpenFactory.js +3 -0
- package/lib/client/AbstractPowerSyncOpenFactory.js.map +1 -1
- package/lib/client/ConnectionManager.d.ts +4 -1
- package/lib/client/ConnectionManager.js +1 -1
- package/lib/client/ConnectionManager.js.map +1 -1
- package/lib/client/Query.d.ts +9 -0
- package/lib/client/SQLOpenFactory.d.ts +12 -0
- package/lib/client/SQLOpenFactory.js +6 -0
- package/lib/client/SQLOpenFactory.js.map +1 -1
- package/lib/client/compilableQueryWatch.d.ts +6 -0
- package/lib/client/compilableQueryWatch.js +3 -0
- package/lib/client/compilableQueryWatch.js.map +1 -1
- package/lib/client/connection/PowerSyncBackendConnector.d.ts +3 -0
- package/lib/client/connection/PowerSyncCredentials.d.ts +3 -0
- package/lib/client/constants.d.ts +3 -0
- package/lib/client/constants.js +3 -0
- package/lib/client/constants.js.map +1 -1
- package/lib/client/runOnSchemaChange.d.ts +3 -0
- package/lib/client/runOnSchemaChange.js +3 -0
- package/lib/client/runOnSchemaChange.js.map +1 -1
- package/lib/client/sync/bucket/BucketStorageAdapter.d.ts +12 -0
- package/lib/client/sync/bucket/BucketStorageAdapter.js +6 -0
- package/lib/client/sync/bucket/BucketStorageAdapter.js.map +1 -1
- package/lib/client/sync/bucket/CrudBatch.d.ts +2 -0
- package/lib/client/sync/bucket/CrudBatch.js +2 -0
- package/lib/client/sync/bucket/CrudBatch.js.map +1 -1
- package/lib/client/sync/bucket/CrudEntry.d.ts +9 -0
- package/lib/client/sync/bucket/CrudEntry.js +4 -0
- package/lib/client/sync/bucket/CrudEntry.js.map +1 -1
- package/lib/client/sync/bucket/CrudTransaction.d.ts +3 -0
- package/lib/client/sync/bucket/CrudTransaction.js +3 -0
- package/lib/client/sync/bucket/CrudTransaction.js.map +1 -1
- package/lib/client/sync/bucket/SqliteBucketStorage.d.ts +3 -0
- package/lib/client/sync/bucket/SqliteBucketStorage.js +3 -0
- package/lib/client/sync/bucket/SqliteBucketStorage.js.map +1 -1
- package/lib/client/sync/stream/AbstractRemote.d.ts +30 -1
- package/lib/client/sync/stream/AbstractRemote.js +59 -27
- package/lib/client/sync/stream/AbstractRemote.js.map +1 -1
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.d.ts +55 -5
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +32 -4
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js.map +1 -1
- package/lib/client/sync/stream/JsonValue.d.ts +3 -0
- package/lib/client/sync/stream/WebsocketClientTransport.js +2 -1
- package/lib/client/sync/stream/WebsocketClientTransport.js.map +1 -1
- package/lib/client/sync/sync-streams.d.ts +22 -7
- package/lib/client/triggers/TriggerManager.d.ts +19 -18
- package/lib/client/triggers/TriggerManager.js +2 -1
- package/lib/client/triggers/TriggerManager.js.map +1 -1
- package/lib/client/triggers/TriggerManagerImpl.d.ts +1 -1
- package/lib/client/triggers/TriggerManagerImpl.js +3 -3
- package/lib/client/triggers/TriggerManagerImpl.js.map +1 -1
- package/lib/client/triggers/sanitizeSQL.d.ts +4 -0
- package/lib/client/triggers/sanitizeSQL.js +4 -0
- package/lib/client/triggers/sanitizeSQL.js.map +1 -1
- package/lib/client/watched/GetAllQuery.d.ts +4 -0
- package/lib/client/watched/GetAllQuery.js +2 -0
- package/lib/client/watched/GetAllQuery.js.map +1 -1
- package/lib/client/watched/WatchedQuery.d.ts +24 -2
- package/lib/client/watched/WatchedQuery.js +9 -0
- package/lib/client/watched/WatchedQuery.js.map +1 -1
- package/lib/client/watched/processors/AbstractQueryProcessor.d.ts +1 -1
- package/lib/client/watched/processors/AbstractQueryProcessor.js.map +1 -1
- package/lib/client/watched/processors/DifferentialQueryProcessor.d.ts +20 -0
- package/lib/client/watched/processors/DifferentialQueryProcessor.js +4 -0
- package/lib/client/watched/processors/DifferentialQueryProcessor.js.map +1 -1
- package/lib/client/watched/processors/OnChangeQueryProcessor.d.ts +4 -0
- package/lib/client/watched/processors/OnChangeQueryProcessor.js.map +1 -1
- package/lib/client/watched/processors/comparators.d.ts +8 -0
- package/lib/client/watched/processors/comparators.js +4 -0
- package/lib/client/watched/processors/comparators.js.map +1 -1
- package/lib/db/ConnectionClosedError.d.ts +2 -0
- package/lib/db/ConnectionClosedError.js +2 -0
- package/lib/db/ConnectionClosedError.js.map +1 -1
- package/lib/db/DBAdapter.d.ts +56 -6
- package/lib/db/DBAdapter.js +15 -3
- package/lib/db/DBAdapter.js.map +1 -1
- package/lib/db/crud/SyncProgress.d.ts +6 -1
- package/lib/db/crud/SyncProgress.js +2 -0
- package/lib/db/crud/SyncProgress.js.map +1 -1
- package/lib/db/crud/SyncStatus.d.ts +36 -38
- package/lib/db/crud/SyncStatus.js +19 -14
- package/lib/db/crud/SyncStatus.js.map +1 -1
- package/lib/db/crud/UploadQueueStatus.d.ts +3 -0
- package/lib/db/crud/UploadQueueStatus.js +3 -0
- package/lib/db/crud/UploadQueueStatus.js.map +1 -1
- package/lib/db/schema/Column.d.ts +28 -0
- package/lib/db/schema/Column.js +16 -3
- package/lib/db/schema/Column.js.map +1 -1
- package/lib/db/schema/Index.d.ts +9 -0
- package/lib/db/schema/Index.js +6 -0
- package/lib/db/schema/Index.js.map +1 -1
- package/lib/db/schema/IndexedColumn.d.ts +9 -0
- package/lib/db/schema/IndexedColumn.js +6 -0
- package/lib/db/schema/IndexedColumn.js.map +1 -1
- package/lib/db/schema/RawTable.d.ts +7 -1
- package/lib/db/schema/Schema.d.ts +6 -1
- package/lib/db/schema/Schema.js +3 -1
- package/lib/db/schema/Schema.js.map +1 -1
- package/lib/db/schema/Table.d.ts +27 -3
- package/lib/db/schema/Table.js +9 -0
- package/lib/db/schema/Table.js.map +1 -1
- package/lib/db/schema/TableV2.d.ts +2 -0
- package/lib/db/schema/TableV2.js +2 -0
- package/lib/db/schema/TableV2.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/types/types.d.ts +6 -0
- package/lib/utils/AbortOperation.d.ts +2 -0
- package/lib/utils/AbortOperation.js +2 -0
- package/lib/utils/AbortOperation.js.map +1 -1
- package/lib/utils/BaseObserver.d.ts +12 -0
- package/lib/utils/BaseObserver.js +3 -0
- package/lib/utils/BaseObserver.js.map +1 -1
- package/lib/utils/ControlledExecutor.d.ts +6 -0
- package/lib/utils/ControlledExecutor.js +3 -0
- package/lib/utils/ControlledExecutor.js.map +1 -1
- package/lib/utils/Logger.d.ts +9 -0
- package/lib/utils/Logger.js +6 -0
- package/lib/utils/Logger.js.map +1 -1
- package/lib/utils/async.d.ts +26 -0
- package/lib/utils/async.js +114 -27
- package/lib/utils/async.js.map +1 -1
- package/lib/utils/compatibility.d.ts +8 -0
- package/lib/utils/compatibility.js +9 -0
- package/lib/utils/compatibility.js.map +1 -0
- package/lib/utils/mutex.d.ts +8 -0
- package/lib/utils/mutex.js +3 -0
- package/lib/utils/mutex.js.map +1 -1
- package/lib/utils/parseQuery.d.ts +6 -0
- package/lib/utils/parseQuery.js +3 -0
- package/lib/utils/parseQuery.js.map +1 -1
- package/lib/utils/stream_transform.d.ts +3 -1
- package/lib/utils/stream_transform.js.map +1 -1
- package/package.json +3 -3
- package/src/attachments/AttachmentContext.ts +7 -6
- package/src/attachments/AttachmentErrorHandler.ts +6 -6
- package/src/attachments/AttachmentQueue.ts +93 -35
- package/src/attachments/LocalStorageAdapter.ts +14 -8
- package/src/attachments/README.md +2 -0
- package/src/attachments/RemoteStorageAdapter.ts +4 -4
- package/src/attachments/Schema.ts +12 -4
- package/src/attachments/WatchedAttachmentItem.ts +3 -1
- package/src/client/AbstractPowerSyncDatabase.ts +135 -91
- package/src/client/AbstractPowerSyncOpenFactory.ts +6 -0
- package/src/client/ConnectionManager.ts +4 -1
- package/src/client/Query.ts +9 -0
- package/src/client/SQLOpenFactory.ts +12 -0
- package/src/client/compilableQueryWatch.ts +6 -0
- package/src/client/connection/PowerSyncBackendConnector.ts +3 -0
- package/src/client/connection/PowerSyncCredentials.ts +3 -0
- package/src/client/constants.ts +3 -0
- package/src/client/runOnSchemaChange.ts +3 -0
- package/src/client/sync/bucket/BucketStorageAdapter.ts +12 -0
- package/src/client/sync/bucket/CrudBatch.ts +2 -0
- package/src/client/sync/bucket/CrudEntry.ts +9 -0
- package/src/client/sync/bucket/CrudTransaction.ts +3 -0
- package/src/client/sync/bucket/SqliteBucketStorage.ts +3 -0
- package/src/client/sync/stream/AbstractRemote.ts +76 -34
- package/src/client/sync/stream/AbstractStreamingSyncImplementation.ts +55 -5
- package/src/client/sync/stream/JsonValue.ts +3 -0
- package/src/client/sync/stream/WebsocketClientTransport.ts +3 -1
- package/src/client/sync/sync-streams.ts +22 -9
- package/src/client/triggers/TriggerManager.ts +19 -18
- package/src/client/triggers/TriggerManagerImpl.ts +5 -5
- package/src/client/triggers/sanitizeSQL.ts +5 -0
- package/src/client/watched/GetAllQuery.ts +5 -1
- package/src/client/watched/WatchedQuery.ts +24 -2
- package/src/client/watched/processors/AbstractQueryProcessor.ts +6 -6
- package/src/client/watched/processors/DifferentialQueryProcessor.ts +28 -5
- package/src/client/watched/processors/OnChangeQueryProcessor.ts +9 -3
- package/src/client/watched/processors/comparators.ts +8 -0
- package/src/db/ConnectionClosedError.ts +2 -0
- package/src/db/DBAdapter.ts +58 -6
- package/src/db/crud/SyncProgress.ts +6 -1
- package/src/db/crud/SyncStatus.ts +40 -21
- package/src/db/crud/UploadQueueStatus.ts +3 -0
- package/src/db/schema/Column.ts +28 -3
- package/src/db/schema/Index.ts +9 -0
- package/src/db/schema/IndexedColumn.ts +9 -0
- package/src/db/schema/RawTable.ts +7 -1
- package/src/db/schema/Schema.ts +8 -3
- package/src/db/schema/Table.ts +30 -5
- package/src/db/schema/TableV2.ts +2 -0
- package/src/index.ts +1 -1
- package/src/types/types.ts +6 -0
- package/src/utils/AbortOperation.ts +2 -0
- package/src/utils/BaseObserver.ts +12 -0
- package/src/utils/ControlledExecutor.ts +6 -0
- package/src/utils/Logger.ts +9 -0
- package/src/utils/async.ts +136 -28
- package/src/utils/compatibility.ts +9 -0
- package/src/utils/mutex.ts +12 -0
- package/src/utils/parseQuery.ts +6 -0
- package/src/utils/stream_transform.ts +3 -1
package/dist/bundle.node.cjs
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var eventIterator = require('event-iterator');
|
|
4
3
|
var node_buffer = require('node:buffer');
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @see https://www.sqlite.org/lang_expr.html#castexpr
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
7
9
|
exports.ColumnType = void 0;
|
|
8
10
|
(function (ColumnType) {
|
|
9
11
|
ColumnType["TEXT"] = "TEXT";
|
|
@@ -19,14 +21,24 @@ const integer = {
|
|
|
19
21
|
const real = {
|
|
20
22
|
type: exports.ColumnType.REAL
|
|
21
23
|
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
/**
|
|
25
|
+
* powersync-sqlite-core limits the number of column per table to 1999, due to internal SQLite limits.
|
|
26
|
+
* In earlier versions this was limited to 63.
|
|
27
|
+
*
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
24
30
|
const MAX_AMOUNT_OF_COLUMNS = 1999;
|
|
31
|
+
/**
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
25
34
|
const column = {
|
|
26
35
|
text,
|
|
27
36
|
integer,
|
|
28
37
|
real
|
|
29
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* @public
|
|
41
|
+
*/
|
|
30
42
|
class Column {
|
|
31
43
|
options;
|
|
32
44
|
constructor(options) {
|
|
@@ -46,9 +58,15 @@ class Column {
|
|
|
46
58
|
}
|
|
47
59
|
}
|
|
48
60
|
|
|
61
|
+
/**
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
49
64
|
const DEFAULT_INDEX_COLUMN_OPTIONS = {
|
|
50
65
|
ascending: true
|
|
51
66
|
};
|
|
67
|
+
/**
|
|
68
|
+
* @public
|
|
69
|
+
*/
|
|
52
70
|
class IndexedColumn {
|
|
53
71
|
options;
|
|
54
72
|
static createAscending(column) {
|
|
@@ -75,9 +93,15 @@ class IndexedColumn {
|
|
|
75
93
|
}
|
|
76
94
|
}
|
|
77
95
|
|
|
96
|
+
/**
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
78
99
|
const DEFAULT_INDEX_OPTIONS = {
|
|
79
100
|
columns: []
|
|
80
101
|
};
|
|
102
|
+
/**
|
|
103
|
+
* @public
|
|
104
|
+
*/
|
|
81
105
|
class Index {
|
|
82
106
|
options;
|
|
83
107
|
static createAscending(options, columnNames) {
|
|
@@ -119,6 +143,9 @@ function encodeTableOptions(options) {
|
|
|
119
143
|
};
|
|
120
144
|
}
|
|
121
145
|
|
|
146
|
+
/**
|
|
147
|
+
* @internal
|
|
148
|
+
*/
|
|
122
149
|
const DEFAULT_TABLE_OPTIONS = {
|
|
123
150
|
indexes: [],
|
|
124
151
|
insertOnly: false,
|
|
@@ -127,7 +154,13 @@ const DEFAULT_TABLE_OPTIONS = {
|
|
|
127
154
|
trackMetadata: false,
|
|
128
155
|
ignoreEmptyUpdates: false
|
|
129
156
|
};
|
|
157
|
+
/**
|
|
158
|
+
* @internal
|
|
159
|
+
*/
|
|
130
160
|
const InvalidSQLCharacters = /["'%,.#\s[\]]/;
|
|
161
|
+
/**
|
|
162
|
+
* @public
|
|
163
|
+
*/
|
|
131
164
|
class Table {
|
|
132
165
|
options;
|
|
133
166
|
_mappedColumns;
|
|
@@ -318,6 +351,11 @@ class Table {
|
|
|
318
351
|
}
|
|
319
352
|
}
|
|
320
353
|
|
|
354
|
+
/**
|
|
355
|
+
* The default name of the local table storing attachment data.
|
|
356
|
+
*
|
|
357
|
+
* @alpha
|
|
358
|
+
*/
|
|
321
359
|
const ATTACHMENT_TABLE = 'attachments';
|
|
322
360
|
/**
|
|
323
361
|
* Maps a database row to an AttachmentRecord.
|
|
@@ -325,7 +363,7 @@ const ATTACHMENT_TABLE = 'attachments';
|
|
|
325
363
|
* @param row - The database row object
|
|
326
364
|
* @returns The corresponding AttachmentRecord
|
|
327
365
|
*
|
|
328
|
-
* @
|
|
366
|
+
* @alpha
|
|
329
367
|
*/
|
|
330
368
|
function attachmentFromSql(row) {
|
|
331
369
|
return {
|
|
@@ -343,7 +381,7 @@ function attachmentFromSql(row) {
|
|
|
343
381
|
/**
|
|
344
382
|
* AttachmentState represents the current synchronization state of an attachment.
|
|
345
383
|
*
|
|
346
|
-
* @
|
|
384
|
+
* @alpha
|
|
347
385
|
*/
|
|
348
386
|
exports.AttachmentState = void 0;
|
|
349
387
|
(function (AttachmentState) {
|
|
@@ -356,7 +394,7 @@ exports.AttachmentState = void 0;
|
|
|
356
394
|
/**
|
|
357
395
|
* AttachmentTable defines the schema for the attachment queue table.
|
|
358
396
|
*
|
|
359
|
-
* @
|
|
397
|
+
* @alpha
|
|
360
398
|
*/
|
|
361
399
|
class AttachmentTable extends Table {
|
|
362
400
|
constructor(options) {
|
|
@@ -384,7 +422,8 @@ class AttachmentTable extends Table {
|
|
|
384
422
|
* Provides methods to query, insert, update, and delete attachment records with
|
|
385
423
|
* proper transaction management through PowerSync.
|
|
386
424
|
*
|
|
387
|
-
* @
|
|
425
|
+
* @experimental
|
|
426
|
+
* @alpha
|
|
388
427
|
*/
|
|
389
428
|
class AttachmentContext {
|
|
390
429
|
/** PowerSync database instance for executing queries */
|
|
@@ -606,6 +645,9 @@ class AttachmentContext {
|
|
|
606
645
|
}
|
|
607
646
|
}
|
|
608
647
|
|
|
648
|
+
/**
|
|
649
|
+
* @public
|
|
650
|
+
*/
|
|
609
651
|
exports.WatchedQueryListenerEvent = void 0;
|
|
610
652
|
(function (WatchedQueryListenerEvent) {
|
|
611
653
|
WatchedQueryListenerEvent["ON_DATA"] = "onData";
|
|
@@ -614,176 +656,18 @@ exports.WatchedQueryListenerEvent = void 0;
|
|
|
614
656
|
WatchedQueryListenerEvent["SETTINGS_WILL_UPDATE"] = "settingsWillUpdate";
|
|
615
657
|
WatchedQueryListenerEvent["CLOSED"] = "closed";
|
|
616
658
|
})(exports.WatchedQueryListenerEvent || (exports.WatchedQueryListenerEvent = {}));
|
|
659
|
+
/**
|
|
660
|
+
* @internal
|
|
661
|
+
*/
|
|
617
662
|
const DEFAULT_WATCH_THROTTLE_MS = 30;
|
|
663
|
+
/**
|
|
664
|
+
* @internal
|
|
665
|
+
*/
|
|
618
666
|
const DEFAULT_WATCH_QUERY_OPTIONS = {
|
|
619
667
|
throttleMs: DEFAULT_WATCH_THROTTLE_MS,
|
|
620
668
|
reportFetching: true
|
|
621
669
|
};
|
|
622
670
|
|
|
623
|
-
/**
|
|
624
|
-
* Orchestrates attachment synchronization between local and remote storage.
|
|
625
|
-
* Handles uploads, downloads, deletions, and state transitions.
|
|
626
|
-
*
|
|
627
|
-
* @internal
|
|
628
|
-
*/
|
|
629
|
-
class SyncingService {
|
|
630
|
-
attachmentService;
|
|
631
|
-
localStorage;
|
|
632
|
-
remoteStorage;
|
|
633
|
-
logger;
|
|
634
|
-
errorHandler;
|
|
635
|
-
constructor(attachmentService, localStorage, remoteStorage, logger, errorHandler) {
|
|
636
|
-
this.attachmentService = attachmentService;
|
|
637
|
-
this.localStorage = localStorage;
|
|
638
|
-
this.remoteStorage = remoteStorage;
|
|
639
|
-
this.logger = logger;
|
|
640
|
-
this.errorHandler = errorHandler;
|
|
641
|
-
}
|
|
642
|
-
/**
|
|
643
|
-
* Processes attachments based on their state (upload, download, or delete).
|
|
644
|
-
* All updates are saved in a single batch after processing.
|
|
645
|
-
*
|
|
646
|
-
* @param attachments - Array of attachment records to process
|
|
647
|
-
* @param context - Attachment context for database operations
|
|
648
|
-
* @returns Promise that resolves when all attachments have been processed and saved
|
|
649
|
-
*/
|
|
650
|
-
async processAttachments(attachments, context) {
|
|
651
|
-
const updatedAttachments = [];
|
|
652
|
-
for (const attachment of attachments) {
|
|
653
|
-
switch (attachment.state) {
|
|
654
|
-
case exports.AttachmentState.QUEUED_UPLOAD:
|
|
655
|
-
const uploaded = await this.uploadAttachment(attachment);
|
|
656
|
-
updatedAttachments.push(uploaded);
|
|
657
|
-
break;
|
|
658
|
-
case exports.AttachmentState.QUEUED_DOWNLOAD:
|
|
659
|
-
const downloaded = await this.downloadAttachment(attachment);
|
|
660
|
-
updatedAttachments.push(downloaded);
|
|
661
|
-
break;
|
|
662
|
-
case exports.AttachmentState.QUEUED_DELETE:
|
|
663
|
-
const deleted = await this.deleteAttachment(attachment, context);
|
|
664
|
-
updatedAttachments.push(deleted);
|
|
665
|
-
break;
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
await context.saveAttachments(updatedAttachments);
|
|
669
|
-
}
|
|
670
|
-
/**
|
|
671
|
-
* Uploads an attachment from local storage to remote storage.
|
|
672
|
-
* On success, marks as SYNCED. On failure, defers to error handler or archives.
|
|
673
|
-
*
|
|
674
|
-
* @param attachment - The attachment record to upload
|
|
675
|
-
* @returns Updated attachment record with new state
|
|
676
|
-
* @throws Error if the attachment has no localUri
|
|
677
|
-
*/
|
|
678
|
-
async uploadAttachment(attachment) {
|
|
679
|
-
this.logger.info(`Uploading attachment ${attachment.filename}`);
|
|
680
|
-
try {
|
|
681
|
-
if (attachment.localUri == null) {
|
|
682
|
-
throw new Error(`No localUri for attachment ${attachment.id}`);
|
|
683
|
-
}
|
|
684
|
-
const fileBlob = await this.localStorage.readFile(attachment.localUri);
|
|
685
|
-
await this.remoteStorage.uploadFile(fileBlob, attachment);
|
|
686
|
-
return {
|
|
687
|
-
...attachment,
|
|
688
|
-
state: exports.AttachmentState.SYNCED,
|
|
689
|
-
hasSynced: true
|
|
690
|
-
};
|
|
691
|
-
}
|
|
692
|
-
catch (error) {
|
|
693
|
-
const shouldRetry = (await this.errorHandler?.onUploadError(attachment, error)) ?? true;
|
|
694
|
-
if (!shouldRetry) {
|
|
695
|
-
return {
|
|
696
|
-
...attachment,
|
|
697
|
-
state: exports.AttachmentState.ARCHIVED
|
|
698
|
-
};
|
|
699
|
-
}
|
|
700
|
-
return attachment;
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
/**
|
|
704
|
-
* Downloads an attachment from remote storage to local storage.
|
|
705
|
-
* Retrieves the file, converts to base64, and saves locally.
|
|
706
|
-
* On success, marks as SYNCED. On failure, defers to error handler or archives.
|
|
707
|
-
*
|
|
708
|
-
* @param attachment - The attachment record to download
|
|
709
|
-
* @returns Updated attachment record with local URI and new state
|
|
710
|
-
*/
|
|
711
|
-
async downloadAttachment(attachment) {
|
|
712
|
-
this.logger.info(`Downloading attachment ${attachment.filename}`);
|
|
713
|
-
try {
|
|
714
|
-
const fileData = await this.remoteStorage.downloadFile(attachment);
|
|
715
|
-
const localUri = this.localStorage.getLocalUri(attachment.filename);
|
|
716
|
-
await this.localStorage.saveFile(localUri, fileData);
|
|
717
|
-
return {
|
|
718
|
-
...attachment,
|
|
719
|
-
state: exports.AttachmentState.SYNCED,
|
|
720
|
-
localUri: localUri,
|
|
721
|
-
hasSynced: true
|
|
722
|
-
};
|
|
723
|
-
}
|
|
724
|
-
catch (error) {
|
|
725
|
-
const shouldRetry = (await this.errorHandler?.onDownloadError(attachment, error)) ?? true;
|
|
726
|
-
if (!shouldRetry) {
|
|
727
|
-
return {
|
|
728
|
-
...attachment,
|
|
729
|
-
state: exports.AttachmentState.ARCHIVED
|
|
730
|
-
};
|
|
731
|
-
}
|
|
732
|
-
return attachment;
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
/**
|
|
736
|
-
* Deletes an attachment from both remote and local storage.
|
|
737
|
-
* Removes the remote file, local file (if exists), and the attachment record.
|
|
738
|
-
* On failure, defers to error handler or archives.
|
|
739
|
-
*
|
|
740
|
-
* @param attachment - The attachment record to delete
|
|
741
|
-
* @param context - Attachment context for database operations
|
|
742
|
-
* @returns Updated attachment record
|
|
743
|
-
*/
|
|
744
|
-
async deleteAttachment(attachment, context) {
|
|
745
|
-
try {
|
|
746
|
-
await this.remoteStorage.deleteFile(attachment);
|
|
747
|
-
if (attachment.localUri) {
|
|
748
|
-
await this.localStorage.deleteFile(attachment.localUri);
|
|
749
|
-
}
|
|
750
|
-
await context.deleteAttachment(attachment.id);
|
|
751
|
-
return {
|
|
752
|
-
...attachment,
|
|
753
|
-
state: exports.AttachmentState.ARCHIVED
|
|
754
|
-
};
|
|
755
|
-
}
|
|
756
|
-
catch (error) {
|
|
757
|
-
const shouldRetry = (await this.errorHandler?.onDeleteError(attachment, error)) ?? true;
|
|
758
|
-
if (!shouldRetry) {
|
|
759
|
-
return {
|
|
760
|
-
...attachment,
|
|
761
|
-
state: exports.AttachmentState.ARCHIVED
|
|
762
|
-
};
|
|
763
|
-
}
|
|
764
|
-
return attachment;
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
/**
|
|
768
|
-
* Performs cleanup of archived attachments by removing their local files and records.
|
|
769
|
-
* Errors during local file deletion are logged but do not prevent record deletion.
|
|
770
|
-
*/
|
|
771
|
-
async deleteArchivedAttachments(context) {
|
|
772
|
-
return await context.deleteArchivedAttachments(async (archivedAttachments) => {
|
|
773
|
-
for (const attachment of archivedAttachments) {
|
|
774
|
-
if (attachment.localUri) {
|
|
775
|
-
try {
|
|
776
|
-
await this.localStorage.deleteFile(attachment.localUri);
|
|
777
|
-
}
|
|
778
|
-
catch (error) {
|
|
779
|
-
this.logger.error('Error deleting local file for archived attachment', error);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
|
|
787
671
|
/**
|
|
788
672
|
* A simple fixed-capacity queue implementation.
|
|
789
673
|
*
|
|
@@ -969,6 +853,9 @@ class Mutex {
|
|
|
969
853
|
}
|
|
970
854
|
}
|
|
971
855
|
}
|
|
856
|
+
/**
|
|
857
|
+
* @internal
|
|
858
|
+
*/
|
|
972
859
|
function timeoutSignal(timeout) {
|
|
973
860
|
if (timeout == null)
|
|
974
861
|
return;
|
|
@@ -1031,6 +918,170 @@ class AttachmentService {
|
|
|
1031
918
|
}
|
|
1032
919
|
}
|
|
1033
920
|
|
|
921
|
+
/**
|
|
922
|
+
* Orchestrates attachment synchronization between local and remote storage.
|
|
923
|
+
* Handles uploads, downloads, deletions, and state transitions.
|
|
924
|
+
*
|
|
925
|
+
* @internal
|
|
926
|
+
*/
|
|
927
|
+
class SyncingService {
|
|
928
|
+
attachmentService;
|
|
929
|
+
localStorage;
|
|
930
|
+
remoteStorage;
|
|
931
|
+
logger;
|
|
932
|
+
errorHandler;
|
|
933
|
+
constructor(attachmentService, localStorage, remoteStorage, logger, errorHandler) {
|
|
934
|
+
this.attachmentService = attachmentService;
|
|
935
|
+
this.localStorage = localStorage;
|
|
936
|
+
this.remoteStorage = remoteStorage;
|
|
937
|
+
this.logger = logger;
|
|
938
|
+
this.errorHandler = errorHandler;
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Processes attachments based on their state (upload, download, or delete).
|
|
942
|
+
* All updates are saved in a single batch after processing.
|
|
943
|
+
*
|
|
944
|
+
* @param attachments - Array of attachment records to process
|
|
945
|
+
* @param context - Attachment context for database operations
|
|
946
|
+
* @returns Promise that resolves when all attachments have been processed and saved
|
|
947
|
+
*/
|
|
948
|
+
async processAttachments(attachments, context) {
|
|
949
|
+
const updatedAttachments = [];
|
|
950
|
+
for (const attachment of attachments) {
|
|
951
|
+
switch (attachment.state) {
|
|
952
|
+
case exports.AttachmentState.QUEUED_UPLOAD:
|
|
953
|
+
const uploaded = await this.uploadAttachment(attachment);
|
|
954
|
+
updatedAttachments.push(uploaded);
|
|
955
|
+
break;
|
|
956
|
+
case exports.AttachmentState.QUEUED_DOWNLOAD:
|
|
957
|
+
const downloaded = await this.downloadAttachment(attachment);
|
|
958
|
+
updatedAttachments.push(downloaded);
|
|
959
|
+
break;
|
|
960
|
+
case exports.AttachmentState.QUEUED_DELETE:
|
|
961
|
+
const deleted = await this.deleteAttachment(attachment, context);
|
|
962
|
+
updatedAttachments.push(deleted);
|
|
963
|
+
break;
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
await context.saveAttachments(updatedAttachments);
|
|
967
|
+
}
|
|
968
|
+
/**
|
|
969
|
+
* Uploads an attachment from local storage to remote storage.
|
|
970
|
+
* On success, marks as SYNCED. On failure, defers to error handler or archives.
|
|
971
|
+
*
|
|
972
|
+
* @param attachment - The attachment record to upload
|
|
973
|
+
* @returns Updated attachment record with new state
|
|
974
|
+
* @throws Error if the attachment has no localUri
|
|
975
|
+
*/
|
|
976
|
+
async uploadAttachment(attachment) {
|
|
977
|
+
this.logger.info(`Uploading attachment ${attachment.filename}`);
|
|
978
|
+
try {
|
|
979
|
+
if (attachment.localUri == null) {
|
|
980
|
+
throw new Error(`No localUri for attachment ${attachment.id}`);
|
|
981
|
+
}
|
|
982
|
+
const fileBlob = await this.localStorage.readFile(attachment.localUri);
|
|
983
|
+
await this.remoteStorage.uploadFile(fileBlob, attachment);
|
|
984
|
+
return {
|
|
985
|
+
...attachment,
|
|
986
|
+
state: exports.AttachmentState.SYNCED,
|
|
987
|
+
hasSynced: true
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
catch (error) {
|
|
991
|
+
const shouldRetry = (await this.errorHandler?.onUploadError(attachment, error)) ?? true;
|
|
992
|
+
if (!shouldRetry) {
|
|
993
|
+
return {
|
|
994
|
+
...attachment,
|
|
995
|
+
state: exports.AttachmentState.ARCHIVED
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
return attachment;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Downloads an attachment from remote storage to local storage.
|
|
1003
|
+
* Retrieves the file, converts to base64, and saves locally.
|
|
1004
|
+
* On success, marks as SYNCED. On failure, defers to error handler or archives.
|
|
1005
|
+
*
|
|
1006
|
+
* @param attachment - The attachment record to download
|
|
1007
|
+
* @returns Updated attachment record with local URI and new state
|
|
1008
|
+
*/
|
|
1009
|
+
async downloadAttachment(attachment) {
|
|
1010
|
+
this.logger.info(`Downloading attachment ${attachment.filename}`);
|
|
1011
|
+
try {
|
|
1012
|
+
const fileData = await this.remoteStorage.downloadFile(attachment);
|
|
1013
|
+
const localUri = this.localStorage.getLocalUri(attachment.filename);
|
|
1014
|
+
await this.localStorage.saveFile(localUri, fileData);
|
|
1015
|
+
return {
|
|
1016
|
+
...attachment,
|
|
1017
|
+
state: exports.AttachmentState.SYNCED,
|
|
1018
|
+
localUri: localUri,
|
|
1019
|
+
hasSynced: true
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
catch (error) {
|
|
1023
|
+
const shouldRetry = (await this.errorHandler?.onDownloadError(attachment, error)) ?? true;
|
|
1024
|
+
if (!shouldRetry) {
|
|
1025
|
+
return {
|
|
1026
|
+
...attachment,
|
|
1027
|
+
state: exports.AttachmentState.ARCHIVED
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
return attachment;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Deletes an attachment from both remote and local storage.
|
|
1035
|
+
* Removes the remote file, local file (if exists), and the attachment record.
|
|
1036
|
+
* On failure, defers to error handler or archives.
|
|
1037
|
+
*
|
|
1038
|
+
* @param attachment - The attachment record to delete
|
|
1039
|
+
* @param context - Attachment context for database operations
|
|
1040
|
+
* @returns Updated attachment record
|
|
1041
|
+
*/
|
|
1042
|
+
async deleteAttachment(attachment, context) {
|
|
1043
|
+
try {
|
|
1044
|
+
await this.remoteStorage.deleteFile(attachment);
|
|
1045
|
+
if (attachment.localUri) {
|
|
1046
|
+
await this.localStorage.deleteFile(attachment.localUri);
|
|
1047
|
+
}
|
|
1048
|
+
await context.deleteAttachment(attachment.id);
|
|
1049
|
+
return {
|
|
1050
|
+
...attachment,
|
|
1051
|
+
state: exports.AttachmentState.ARCHIVED
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
catch (error) {
|
|
1055
|
+
const shouldRetry = (await this.errorHandler?.onDeleteError(attachment, error)) ?? true;
|
|
1056
|
+
if (!shouldRetry) {
|
|
1057
|
+
return {
|
|
1058
|
+
...attachment,
|
|
1059
|
+
state: exports.AttachmentState.ARCHIVED
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
return attachment;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
/**
|
|
1066
|
+
* Performs cleanup of archived attachments by removing their local files and records.
|
|
1067
|
+
* Errors during local file deletion are logged but do not prevent record deletion.
|
|
1068
|
+
*/
|
|
1069
|
+
async deleteArchivedAttachments(context) {
|
|
1070
|
+
return await context.deleteArchivedAttachments(async (archivedAttachments) => {
|
|
1071
|
+
for (const attachment of archivedAttachments) {
|
|
1072
|
+
if (attachment.localUri) {
|
|
1073
|
+
try {
|
|
1074
|
+
await this.localStorage.deleteFile(attachment.localUri);
|
|
1075
|
+
}
|
|
1076
|
+
catch (error) {
|
|
1077
|
+
this.logger.error('Error deleting local file for archived attachment', error);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1034
1085
|
/**
|
|
1035
1086
|
* AttachmentQueue manages the lifecycle and synchronization of attachments
|
|
1036
1087
|
* between local and remote storage.
|
|
@@ -1087,16 +1138,6 @@ class AttachmentQueue {
|
|
|
1087
1138
|
* Creates a new AttachmentQueue instance.
|
|
1088
1139
|
*
|
|
1089
1140
|
* @param options - Configuration options
|
|
1090
|
-
* @param options.db - PowerSync database instance
|
|
1091
|
-
* @param options.remoteStorage - Remote storage adapter for upload/download operations
|
|
1092
|
-
* @param options.localStorage - Local storage adapter for file persistence
|
|
1093
|
-
* @param options.watchAttachments - Callback for monitoring attachment changes in your data model
|
|
1094
|
-
* @param options.tableName - Name of the table to store attachment records. Default: 'ps_attachment_queue'
|
|
1095
|
-
* @param options.logger - Logger instance. Defaults to db.logger
|
|
1096
|
-
* @param options.syncIntervalMs - Periodic polling interval in milliseconds for retrying failed uploads/downloads. Default: 30000
|
|
1097
|
-
* @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
|
|
1098
|
-
* @param options.downloadAttachments - Whether to automatically download remote attachments. Default: true
|
|
1099
|
-
* @param options.archivedCacheLimit - Maximum archived attachments before cleanup. Default: 100
|
|
1100
1141
|
*/
|
|
1101
1142
|
constructor({ db, localStorage, remoteStorage, watchAttachments, logger, tableName = ATTACHMENT_TABLE, syncIntervalMs = 30 * 1000, syncThrottleDuration = DEFAULT_WATCH_THROTTLE_MS, downloadAttachments = true, archivedCacheLimit = 100, errorHandler }) {
|
|
1102
1143
|
this.db = db;
|
|
@@ -1185,6 +1226,7 @@ class AttachmentQueue {
|
|
|
1185
1226
|
state: exports.AttachmentState.QUEUED_DOWNLOAD,
|
|
1186
1227
|
hasSynced: false,
|
|
1187
1228
|
metaData: watchedAttachment.metaData,
|
|
1229
|
+
mediaType: watchedAttachment.mediaType,
|
|
1188
1230
|
timestamp: new Date().getTime()
|
|
1189
1231
|
});
|
|
1190
1232
|
continue;
|
|
@@ -1272,17 +1314,24 @@ class AttachmentQueue {
|
|
|
1272
1314
|
this.statusListenerDispose = undefined;
|
|
1273
1315
|
}
|
|
1274
1316
|
}
|
|
1317
|
+
/**
|
|
1318
|
+
* Provides an {@link AttachmentContext} to a callback.
|
|
1319
|
+
*
|
|
1320
|
+
* The callback runs while the attachment queue mutex is held. Do not call
|
|
1321
|
+
* other {@link AttachmentQueue} methods from within the callback, as they may
|
|
1322
|
+
* attempt to acquire the same mutex and block indefinitely.
|
|
1323
|
+
*/
|
|
1324
|
+
withAttachmentContext(callback) {
|
|
1325
|
+
/**
|
|
1326
|
+
* AttachmentService is internal and private in this class.
|
|
1327
|
+
* We only need to expose its locking and context functionality for extending classes.
|
|
1328
|
+
*/
|
|
1329
|
+
return this.attachmentService.withContext(callback);
|
|
1330
|
+
}
|
|
1275
1331
|
/**
|
|
1276
1332
|
* Saves a file to local storage and queues it for upload to remote storage.
|
|
1277
1333
|
*
|
|
1278
1334
|
* @param options - File save options
|
|
1279
|
-
* @param options.data - The file data as ArrayBuffer, Blob, or base64 string
|
|
1280
|
-
* @param options.fileExtension - File extension (e.g., 'jpg', 'pdf')
|
|
1281
|
-
* @param options.mediaType - MIME type of the file (e.g., 'image/jpeg')
|
|
1282
|
-
* @param options.metaData - Optional metadata to associate with the attachment
|
|
1283
|
-
* @param options.id - Optional custom ID. If not provided, a UUID will be generated
|
|
1284
|
-
* @param options.updateHook - Optional callback to execute additional database operations
|
|
1285
|
-
* within the same transaction as the attachment creation
|
|
1286
1335
|
* @returns Promise resolving to the created attachment record
|
|
1287
1336
|
*/
|
|
1288
1337
|
async saveFile({ data, fileExtension, mediaType, metaData, id, updateHook }) {
|
|
@@ -1395,6 +1444,9 @@ class AttachmentQueue {
|
|
|
1395
1444
|
}
|
|
1396
1445
|
}
|
|
1397
1446
|
|
|
1447
|
+
/**
|
|
1448
|
+
* @alpha
|
|
1449
|
+
*/
|
|
1398
1450
|
exports.EncodingType = void 0;
|
|
1399
1451
|
(function (EncodingType) {
|
|
1400
1452
|
EncodingType["UTF8"] = "utf8";
|
|
@@ -1703,7 +1755,9 @@ var Logger = /*@__PURE__*/getDefaultExportFromCjs(loggerExports);
|
|
|
1703
1755
|
* different SQLite DB implementations.
|
|
1704
1756
|
*/
|
|
1705
1757
|
/**
|
|
1706
|
-
* Implements {@link DBGetUtils} on a {@link
|
|
1758
|
+
* Implements {@link DBGetUtils} on a {@link SqlExecutor}.
|
|
1759
|
+
*
|
|
1760
|
+
* @internal
|
|
1707
1761
|
*/
|
|
1708
1762
|
function DBGetUtilsDefaultMixin(Base) {
|
|
1709
1763
|
return class extends Base {
|
|
@@ -1747,6 +1801,8 @@ function DBGetUtilsDefaultMixin(Base) {
|
|
|
1747
1801
|
}
|
|
1748
1802
|
/**
|
|
1749
1803
|
* Update table operation numbers from SQLite
|
|
1804
|
+
*
|
|
1805
|
+
* @public
|
|
1750
1806
|
*/
|
|
1751
1807
|
exports.RowUpdateType = void 0;
|
|
1752
1808
|
(function (RowUpdateType) {
|
|
@@ -1755,8 +1811,10 @@ exports.RowUpdateType = void 0;
|
|
|
1755
1811
|
RowUpdateType[RowUpdateType["SQLITE_UPDATE"] = 23] = "SQLITE_UPDATE";
|
|
1756
1812
|
})(exports.RowUpdateType || (exports.RowUpdateType = {}));
|
|
1757
1813
|
/**
|
|
1758
|
-
* A mixin to implement {@link DBAdapter} by delegating to {@link ConnectionPool
|
|
1759
|
-
* {@link ConnectionPool
|
|
1814
|
+
* A mixin to implement {@link DBAdapter} by delegating to {@link ConnectionPool#readLock} and
|
|
1815
|
+
* {@link ConnectionPool#writeLock}.
|
|
1816
|
+
*
|
|
1817
|
+
* @internal
|
|
1760
1818
|
*/
|
|
1761
1819
|
function DBAdapterDefaultMixin(Base) {
|
|
1762
1820
|
return class extends Base {
|
|
@@ -1844,9 +1902,15 @@ class TransactionImplementation extends DBGetUtilsDefaultMixin(BaseTransaction)
|
|
|
1844
1902
|
}
|
|
1845
1903
|
}
|
|
1846
1904
|
}
|
|
1905
|
+
/**
|
|
1906
|
+
* @internal
|
|
1907
|
+
*/
|
|
1847
1908
|
function isBatchedUpdateNotification(update) {
|
|
1848
1909
|
return 'tables' in update;
|
|
1849
1910
|
}
|
|
1911
|
+
/**
|
|
1912
|
+
* @internal
|
|
1913
|
+
*/
|
|
1850
1914
|
function extractTableUpdates(update) {
|
|
1851
1915
|
return isBatchedUpdateNotification(update) ? update.tables : [update.table];
|
|
1852
1916
|
}
|
|
@@ -1874,6 +1938,8 @@ const FULL_SYNC_PRIORITY = 2147483647;
|
|
|
1874
1938
|
*
|
|
1875
1939
|
* Also note that data is downloaded in bulk, which means that individual counters are unlikely
|
|
1876
1940
|
* to be updated one-by-one.
|
|
1941
|
+
*
|
|
1942
|
+
* @public
|
|
1877
1943
|
*/
|
|
1878
1944
|
class SyncProgress {
|
|
1879
1945
|
internal;
|
|
@@ -1912,6 +1978,9 @@ class SyncProgress {
|
|
|
1912
1978
|
}
|
|
1913
1979
|
}
|
|
1914
1980
|
|
|
1981
|
+
/**
|
|
1982
|
+
* @public
|
|
1983
|
+
*/
|
|
1915
1984
|
class SyncStatus {
|
|
1916
1985
|
options;
|
|
1917
1986
|
constructor(options) {
|
|
@@ -1922,6 +1991,8 @@ class SyncStatus {
|
|
|
1922
1991
|
* implementation).
|
|
1923
1992
|
*
|
|
1924
1993
|
* This information is only available after a connection has been requested.
|
|
1994
|
+
*
|
|
1995
|
+
* @deprecated This always returns the Rust client (the only option).
|
|
1925
1996
|
*/
|
|
1926
1997
|
get clientImplementation() {
|
|
1927
1998
|
return this.options.clientImplementation;
|
|
@@ -1929,7 +2000,7 @@ class SyncStatus {
|
|
|
1929
2000
|
/**
|
|
1930
2001
|
* Indicates if the client is currently connected to the PowerSync service.
|
|
1931
2002
|
*
|
|
1932
|
-
* @returns
|
|
2003
|
+
* @returns True if connected, false otherwise. Defaults to false if not specified.
|
|
1933
2004
|
*/
|
|
1934
2005
|
get connected() {
|
|
1935
2006
|
return this.options.connected ?? false;
|
|
@@ -1937,7 +2008,7 @@ class SyncStatus {
|
|
|
1937
2008
|
/**
|
|
1938
2009
|
* Indicates if the client is in the process of establishing a connection to the PowerSync service.
|
|
1939
2010
|
*
|
|
1940
|
-
* @returns
|
|
2011
|
+
* @returns True if connecting, false otherwise. Defaults to false if not specified.
|
|
1941
2012
|
*/
|
|
1942
2013
|
get connecting() {
|
|
1943
2014
|
return this.options.connecting ?? false;
|
|
@@ -1946,7 +2017,7 @@ class SyncStatus {
|
|
|
1946
2017
|
* Time that a last sync has fully completed, if any.
|
|
1947
2018
|
* This timestamp is reset to null after a restart of the PowerSync service.
|
|
1948
2019
|
*
|
|
1949
|
-
* @returns
|
|
2020
|
+
* @returns The timestamp of the last successful sync, or undefined if no sync has completed.
|
|
1950
2021
|
*/
|
|
1951
2022
|
get lastSyncedAt() {
|
|
1952
2023
|
return this.options.lastSyncedAt;
|
|
@@ -1954,7 +2025,7 @@ class SyncStatus {
|
|
|
1954
2025
|
/**
|
|
1955
2026
|
* Indicates whether there has been at least one full sync completed since initialization.
|
|
1956
2027
|
*
|
|
1957
|
-
* @returns
|
|
2028
|
+
* @returns True if at least one sync has completed, false if no sync has completed,
|
|
1958
2029
|
* or undefined when the state is still being loaded from the database.
|
|
1959
2030
|
*/
|
|
1960
2031
|
get hasSynced() {
|
|
@@ -1963,10 +2034,10 @@ class SyncStatus {
|
|
|
1963
2034
|
/**
|
|
1964
2035
|
* Provides the current data flow status regarding uploads and downloads.
|
|
1965
2036
|
*
|
|
1966
|
-
* @returns
|
|
2037
|
+
* @returns An object containing:
|
|
1967
2038
|
* - downloading: True if actively downloading changes (only when connected is also true)
|
|
1968
2039
|
* - uploading: True if actively uploading changes
|
|
1969
|
-
* Defaults to {downloading: false, uploading: false} if not specified.
|
|
2040
|
+
* Defaults to `{downloading: false, uploading: false}` if not specified.
|
|
1970
2041
|
*/
|
|
1971
2042
|
get dataFlowStatus() {
|
|
1972
2043
|
return (this.options.dataFlow ?? {
|
|
@@ -1991,7 +2062,7 @@ class SyncStatus {
|
|
|
1991
2062
|
return this.options.dataFlow?.internalStreamSubscriptions?.map((core) => new SyncStreamStatusView(this, core));
|
|
1992
2063
|
}
|
|
1993
2064
|
/**
|
|
1994
|
-
* If the `stream` appears in {@link syncStreams}, returns the current status for that stream.
|
|
2065
|
+
* If the `stream` appears in {@link SyncStatus.syncStreams}, returns the current status for that stream.
|
|
1995
2066
|
*/
|
|
1996
2067
|
forStream(stream) {
|
|
1997
2068
|
const asJson = JSON.stringify(stream.parameters);
|
|
@@ -2001,7 +2072,7 @@ class SyncStatus {
|
|
|
2001
2072
|
/**
|
|
2002
2073
|
* Provides sync status information for all bucket priorities, sorted by priority (highest first).
|
|
2003
2074
|
*
|
|
2004
|
-
* @returns
|
|
2075
|
+
* @returns An array of status entries for different sync priority levels,
|
|
2005
2076
|
* sorted with highest priorities (lower numbers) first.
|
|
2006
2077
|
*/
|
|
2007
2078
|
get priorityStatusEntries() {
|
|
@@ -2036,8 +2107,8 @@ class SyncStatus {
|
|
|
2036
2107
|
* For example, if PowerSync just finished synchronizing buckets in priority level 3, calling this method
|
|
2037
2108
|
* with a priority of 1 may return information for priority level 3.
|
|
2038
2109
|
*
|
|
2039
|
-
* @param
|
|
2040
|
-
* @returns
|
|
2110
|
+
* @param priority - The bucket priority for which the status should be reported
|
|
2111
|
+
* @returns Status information for the requested priority level or the next higher level with available status
|
|
2041
2112
|
*/
|
|
2042
2113
|
statusForPriority(priority) {
|
|
2043
2114
|
// priorityStatusEntries are sorted by ascending priorities (so higher numbers to lower numbers).
|
|
@@ -2058,8 +2129,8 @@ class SyncStatus {
|
|
|
2058
2129
|
* Compares this SyncStatus instance with another to determine if they are equal.
|
|
2059
2130
|
* Equality is determined by comparing the serialized JSON representation of both instances.
|
|
2060
2131
|
*
|
|
2061
|
-
* @param
|
|
2062
|
-
* @returns
|
|
2132
|
+
* @param status - The SyncStatus instance to compare against
|
|
2133
|
+
* @returns True if the instances are considered equal, false otherwise
|
|
2063
2134
|
*/
|
|
2064
2135
|
isEqual(status) {
|
|
2065
2136
|
/**
|
|
@@ -2082,7 +2153,7 @@ class SyncStatus {
|
|
|
2082
2153
|
* Creates a human-readable string representation of the current sync status.
|
|
2083
2154
|
* Includes information about connection state, sync completion, and data flow.
|
|
2084
2155
|
*
|
|
2085
|
-
* @returns
|
|
2156
|
+
* @returns A string representation of the sync status
|
|
2086
2157
|
*/
|
|
2087
2158
|
getMessage() {
|
|
2088
2159
|
const dataFlow = this.dataFlowStatus;
|
|
@@ -2091,7 +2162,7 @@ class SyncStatus {
|
|
|
2091
2162
|
/**
|
|
2092
2163
|
* Serializes the SyncStatus instance to a plain object.
|
|
2093
2164
|
*
|
|
2094
|
-
* @returns
|
|
2165
|
+
* @returns A plain object representation of the sync status
|
|
2095
2166
|
*/
|
|
2096
2167
|
toJSON() {
|
|
2097
2168
|
return {
|
|
@@ -2157,6 +2228,9 @@ class SyncStreamStatusView {
|
|
|
2157
2228
|
}
|
|
2158
2229
|
}
|
|
2159
2230
|
|
|
2231
|
+
/**
|
|
2232
|
+
* @public
|
|
2233
|
+
*/
|
|
2160
2234
|
class UploadQueueStats {
|
|
2161
2235
|
count;
|
|
2162
2236
|
size;
|
|
@@ -2182,6 +2256,9 @@ class UploadQueueStats {
|
|
|
2182
2256
|
}
|
|
2183
2257
|
}
|
|
2184
2258
|
|
|
2259
|
+
/**
|
|
2260
|
+
* @internal
|
|
2261
|
+
*/
|
|
2185
2262
|
class BaseObserver {
|
|
2186
2263
|
listeners = new Set();
|
|
2187
2264
|
constructor() { }
|
|
@@ -2209,6 +2286,9 @@ class BaseObserver {
|
|
|
2209
2286
|
}
|
|
2210
2287
|
}
|
|
2211
2288
|
|
|
2289
|
+
/**
|
|
2290
|
+
* @internal
|
|
2291
|
+
*/
|
|
2212
2292
|
class ControlledExecutor {
|
|
2213
2293
|
task;
|
|
2214
2294
|
/**
|
|
@@ -2260,6 +2340,210 @@ class ControlledExecutor {
|
|
|
2260
2340
|
}
|
|
2261
2341
|
}
|
|
2262
2342
|
|
|
2343
|
+
/**
|
|
2344
|
+
* Some JavaScript engines, in particular older versions of React Native, don't support Symbol.asyncIterator.
|
|
2345
|
+
*
|
|
2346
|
+
* 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).
|
|
2347
|
+
* This definition is compatible with that polyfill, so transpiled apps can use async iterables created by the PowerSync
|
|
2348
|
+
* SDK.
|
|
2349
|
+
*/
|
|
2350
|
+
const symbolAsyncIterator = Symbol.asyncIterator ?? Symbol.for('Symbol.asyncIterator');
|
|
2351
|
+
|
|
2352
|
+
const doneResult = { done: true, value: undefined };
|
|
2353
|
+
function valueResult(value) {
|
|
2354
|
+
return { done: false, value };
|
|
2355
|
+
}
|
|
2356
|
+
/**
|
|
2357
|
+
* Expands a source async iterator by allowing to inject events asynchronously.
|
|
2358
|
+
*
|
|
2359
|
+
* The resulting iterator will emit all events from its source. Additionally though, events can be injected. These
|
|
2360
|
+
* events are dropped once the main iterator completes, but are otherwise forwarded.
|
|
2361
|
+
*
|
|
2362
|
+
* The iterator completes when its source completes, and it supports backpressure by only calling `next()` on the source
|
|
2363
|
+
* in response to a `next()` call from downstream if no pending injected events can be dispatched.
|
|
2364
|
+
*/
|
|
2365
|
+
function injectable(source) {
|
|
2366
|
+
let sourceIsDone = false;
|
|
2367
|
+
let waiter = undefined; // An active, waiting next() call.
|
|
2368
|
+
// A pending upstream event that couldn't be dispatched because inject() has been called before it was resolved.
|
|
2369
|
+
let pendingSourceEvent = null;
|
|
2370
|
+
let sourceFetchInFlight = false;
|
|
2371
|
+
let pendingInjectedEvents = [];
|
|
2372
|
+
const consumeWaiter = () => {
|
|
2373
|
+
const pending = waiter;
|
|
2374
|
+
waiter = undefined;
|
|
2375
|
+
return pending;
|
|
2376
|
+
};
|
|
2377
|
+
const fetchFromSource = () => {
|
|
2378
|
+
const resolveWaiter = (propagate) => {
|
|
2379
|
+
sourceFetchInFlight = false;
|
|
2380
|
+
const active = consumeWaiter();
|
|
2381
|
+
if (active) {
|
|
2382
|
+
propagate(active);
|
|
2383
|
+
}
|
|
2384
|
+
else {
|
|
2385
|
+
pendingSourceEvent = propagate;
|
|
2386
|
+
}
|
|
2387
|
+
};
|
|
2388
|
+
sourceFetchInFlight = true;
|
|
2389
|
+
const nextFromSource = source.next();
|
|
2390
|
+
nextFromSource.then((value) => {
|
|
2391
|
+
sourceIsDone = value.done == true;
|
|
2392
|
+
resolveWaiter((w) => w.resolve(value));
|
|
2393
|
+
}, (error) => {
|
|
2394
|
+
resolveWaiter((w) => w.reject(error));
|
|
2395
|
+
});
|
|
2396
|
+
};
|
|
2397
|
+
return {
|
|
2398
|
+
next: () => {
|
|
2399
|
+
return new Promise((resolve, reject) => {
|
|
2400
|
+
// First priority: Dispatch ready upstream events.
|
|
2401
|
+
if (sourceIsDone) {
|
|
2402
|
+
return resolve(doneResult);
|
|
2403
|
+
}
|
|
2404
|
+
if (pendingSourceEvent) {
|
|
2405
|
+
pendingSourceEvent({ resolve, reject });
|
|
2406
|
+
pendingSourceEvent = null;
|
|
2407
|
+
return;
|
|
2408
|
+
}
|
|
2409
|
+
// Second priority: Dispatch injected events
|
|
2410
|
+
if (pendingInjectedEvents.length) {
|
|
2411
|
+
return resolve(valueResult(pendingInjectedEvents.shift()));
|
|
2412
|
+
}
|
|
2413
|
+
// Nothing pending? Fetch from source
|
|
2414
|
+
waiter = { resolve, reject };
|
|
2415
|
+
if (!sourceFetchInFlight) {
|
|
2416
|
+
fetchFromSource();
|
|
2417
|
+
}
|
|
2418
|
+
});
|
|
2419
|
+
},
|
|
2420
|
+
inject: (event) => {
|
|
2421
|
+
const pending = consumeWaiter();
|
|
2422
|
+
if (pending != null) {
|
|
2423
|
+
pending.resolve(valueResult(event));
|
|
2424
|
+
}
|
|
2425
|
+
else {
|
|
2426
|
+
pendingInjectedEvents.push(event);
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
};
|
|
2430
|
+
}
|
|
2431
|
+
/**
|
|
2432
|
+
* Splits a byte stream at line endings, emitting each line as a string.
|
|
2433
|
+
*/
|
|
2434
|
+
function extractJsonLines(source, decoder) {
|
|
2435
|
+
let buffer = '';
|
|
2436
|
+
const pendingLines = [];
|
|
2437
|
+
let isFinalEvent = false;
|
|
2438
|
+
return {
|
|
2439
|
+
next: async () => {
|
|
2440
|
+
while (true) {
|
|
2441
|
+
if (isFinalEvent) {
|
|
2442
|
+
return doneResult;
|
|
2443
|
+
}
|
|
2444
|
+
{
|
|
2445
|
+
const first = pendingLines.shift();
|
|
2446
|
+
if (first) {
|
|
2447
|
+
return { done: false, value: first };
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
const { done, value } = await source.next();
|
|
2451
|
+
if (done) {
|
|
2452
|
+
const remaining = buffer.trim();
|
|
2453
|
+
if (remaining.length != 0) {
|
|
2454
|
+
isFinalEvent = true;
|
|
2455
|
+
return { done: false, value: remaining };
|
|
2456
|
+
}
|
|
2457
|
+
return doneResult;
|
|
2458
|
+
}
|
|
2459
|
+
const data = decoder.decode(value, { stream: true });
|
|
2460
|
+
buffer += data;
|
|
2461
|
+
const lines = buffer.split('\n');
|
|
2462
|
+
for (let i = 0; i < lines.length - 1; i++) {
|
|
2463
|
+
const l = lines[i].trim();
|
|
2464
|
+
if (l.length > 0) {
|
|
2465
|
+
pendingLines.push(l);
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
buffer = lines[lines.length - 1];
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
};
|
|
2472
|
+
}
|
|
2473
|
+
/**
|
|
2474
|
+
* Splits a concatenated stream of BSON objects by emitting individual objects.
|
|
2475
|
+
*/
|
|
2476
|
+
function extractBsonObjects(source) {
|
|
2477
|
+
// Fully read but not emitted yet.
|
|
2478
|
+
const completedObjects = [];
|
|
2479
|
+
// Whether source has returned { done: true }. We do the same once completed objects have been emitted.
|
|
2480
|
+
let isDone = false;
|
|
2481
|
+
const lengthBuffer = new DataView(new ArrayBuffer(4));
|
|
2482
|
+
let objectBody = null;
|
|
2483
|
+
// If we're parsing the length field, a number between 1 and 4 (inclusive) describing remaining bytes in the header.
|
|
2484
|
+
// If we're consuming a document, the bytes remaining.
|
|
2485
|
+
let remainingLength = 4;
|
|
2486
|
+
return {
|
|
2487
|
+
async next() {
|
|
2488
|
+
while (true) {
|
|
2489
|
+
// Before fetching new data from upstream, return completed objects.
|
|
2490
|
+
if (completedObjects.length) {
|
|
2491
|
+
return valueResult(completedObjects.shift());
|
|
2492
|
+
}
|
|
2493
|
+
if (isDone) {
|
|
2494
|
+
return doneResult;
|
|
2495
|
+
}
|
|
2496
|
+
const upstreamEvent = await source.next();
|
|
2497
|
+
if (upstreamEvent.done) {
|
|
2498
|
+
isDone = true;
|
|
2499
|
+
if (objectBody || remainingLength != 4) {
|
|
2500
|
+
throw new Error('illegal end of stream in BSON object');
|
|
2501
|
+
}
|
|
2502
|
+
return doneResult;
|
|
2503
|
+
}
|
|
2504
|
+
const chunk = upstreamEvent.value;
|
|
2505
|
+
for (let i = 0; i < chunk.length;) {
|
|
2506
|
+
const availableInData = chunk.length - i;
|
|
2507
|
+
if (objectBody) {
|
|
2508
|
+
// We're in the middle of reading a BSON document.
|
|
2509
|
+
const bytesToRead = Math.min(availableInData, remainingLength);
|
|
2510
|
+
const copySource = new Uint8Array(chunk.buffer, chunk.byteOffset + i, bytesToRead);
|
|
2511
|
+
objectBody.set(copySource, objectBody.length - remainingLength);
|
|
2512
|
+
i += bytesToRead;
|
|
2513
|
+
remainingLength -= bytesToRead;
|
|
2514
|
+
if (remainingLength == 0) {
|
|
2515
|
+
completedObjects.push(objectBody);
|
|
2516
|
+
// Prepare to read another document, starting with its length
|
|
2517
|
+
objectBody = null;
|
|
2518
|
+
remainingLength = 4;
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
else {
|
|
2522
|
+
// Copy up to 4 bytes into lengthBuffer, depending on how many we still need.
|
|
2523
|
+
const bytesToRead = Math.min(availableInData, remainingLength);
|
|
2524
|
+
for (let j = 0; j < bytesToRead; j++) {
|
|
2525
|
+
lengthBuffer.setUint8(4 - remainingLength + j, chunk[i + j]);
|
|
2526
|
+
}
|
|
2527
|
+
i += bytesToRead;
|
|
2528
|
+
remainingLength -= bytesToRead;
|
|
2529
|
+
if (remainingLength == 0) {
|
|
2530
|
+
// Transition from reading length header to reading document. Subtracting 4 because the length of the
|
|
2531
|
+
// header is included in length.
|
|
2532
|
+
const length = lengthBuffer.getInt32(0, true /* little endian */);
|
|
2533
|
+
remainingLength = length - 4;
|
|
2534
|
+
if (remainingLength < 1) {
|
|
2535
|
+
throw new Error(`invalid length for bson: ${length}`);
|
|
2536
|
+
}
|
|
2537
|
+
objectBody = new Uint8Array(length);
|
|
2538
|
+
new DataView(objectBody.buffer).setInt32(0, length, true);
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
};
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2263
2547
|
/**
|
|
2264
2548
|
* Throttle a function to be called at most once every "wait" milliseconds,
|
|
2265
2549
|
* on the trailing edge.
|
|
@@ -2279,45 +2563,128 @@ function throttleTrailing(func, wait) {
|
|
|
2279
2563
|
};
|
|
2280
2564
|
}
|
|
2281
2565
|
function asyncNotifier() {
|
|
2282
|
-
|
|
2283
|
-
let hasPendingNotification = false;
|
|
2566
|
+
const queue = new EventQueue();
|
|
2284
2567
|
return {
|
|
2285
2568
|
notify() {
|
|
2286
|
-
if (
|
|
2287
|
-
waitingConsumer();
|
|
2288
|
-
waitingConsumer = null;
|
|
2289
|
-
}
|
|
2569
|
+
if (queue.countOutstandingEvents > 0) ;
|
|
2290
2570
|
else {
|
|
2291
|
-
|
|
2571
|
+
queue.notify();
|
|
2292
2572
|
}
|
|
2293
2573
|
},
|
|
2294
2574
|
waitForNotification(signal) {
|
|
2295
|
-
return
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2575
|
+
return queue.waitForEvent(signal);
|
|
2576
|
+
}
|
|
2577
|
+
};
|
|
2578
|
+
}
|
|
2579
|
+
class EventQueue {
|
|
2580
|
+
options;
|
|
2581
|
+
waitingConsumer;
|
|
2582
|
+
outstandingEvents;
|
|
2583
|
+
constructor(options = {}) {
|
|
2584
|
+
this.options = options;
|
|
2585
|
+
this.outstandingEvents = [];
|
|
2586
|
+
}
|
|
2587
|
+
/**
|
|
2588
|
+
* The amount of buffered events not yet dispatched to listeners.
|
|
2589
|
+
*/
|
|
2590
|
+
get countOutstandingEvents() {
|
|
2591
|
+
return this.outstandingEvents.length;
|
|
2592
|
+
}
|
|
2593
|
+
notifyInner(dispatch) {
|
|
2594
|
+
const existing = this.waitingConsumer;
|
|
2595
|
+
this.waitingConsumer = undefined;
|
|
2596
|
+
const dispatchAndNotifyListeners = (waiter) => {
|
|
2597
|
+
dispatch(waiter);
|
|
2598
|
+
this.options.eventDelivered?.();
|
|
2599
|
+
};
|
|
2600
|
+
if (existing) {
|
|
2601
|
+
dispatchAndNotifyListeners(existing);
|
|
2602
|
+
}
|
|
2603
|
+
else {
|
|
2604
|
+
this.outstandingEvents.push(dispatchAndNotifyListeners);
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
notify(value) {
|
|
2608
|
+
this.notifyInner((l) => l.resolve(value));
|
|
2609
|
+
}
|
|
2610
|
+
notifyError(error) {
|
|
2611
|
+
this.notifyInner((l) => l.reject(error));
|
|
2612
|
+
}
|
|
2613
|
+
waitForEvent(signal) {
|
|
2614
|
+
return new Promise((resolve, reject) => {
|
|
2615
|
+
if (this.waitingConsumer != null) {
|
|
2616
|
+
throw new Error('Illegal call to waitForEvent, already has a waiter.');
|
|
2617
|
+
}
|
|
2618
|
+
const complete = () => {
|
|
2619
|
+
signal?.removeEventListener('abort', onAbort);
|
|
2620
|
+
};
|
|
2621
|
+
const onAbort = () => {
|
|
2622
|
+
complete();
|
|
2623
|
+
this.waitingConsumer = undefined;
|
|
2624
|
+
resolve(undefined);
|
|
2625
|
+
};
|
|
2626
|
+
const waiter = {
|
|
2627
|
+
resolve: (value) => {
|
|
2628
|
+
complete();
|
|
2629
|
+
resolve(value);
|
|
2630
|
+
},
|
|
2631
|
+
reject: (error) => {
|
|
2632
|
+
complete();
|
|
2633
|
+
reject(error);
|
|
2301
2634
|
}
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2635
|
+
};
|
|
2636
|
+
if (signal.aborted) {
|
|
2637
|
+
resolve(undefined);
|
|
2638
|
+
}
|
|
2639
|
+
else if (this.countOutstandingEvents > 0) {
|
|
2640
|
+
const [event] = this.outstandingEvents.splice(0, 1);
|
|
2641
|
+
event(waiter);
|
|
2642
|
+
}
|
|
2643
|
+
else {
|
|
2644
|
+
this.waitingConsumer = waiter;
|
|
2645
|
+
signal.addEventListener('abort', onAbort);
|
|
2646
|
+
}
|
|
2647
|
+
});
|
|
2648
|
+
}
|
|
2649
|
+
/**
|
|
2650
|
+
* Creates an async iterable backed by event queues.
|
|
2651
|
+
*
|
|
2652
|
+
* @param run A function invoked for every new listener. It receives a queue backing the async iterator.
|
|
2653
|
+
* @param abort An additional abort signal. The `run` callback will also be aborted when `AsyncIterator.return` is
|
|
2654
|
+
* called.
|
|
2655
|
+
* @returns An object conforming to the async iterable protocol.
|
|
2656
|
+
*/
|
|
2657
|
+
static queueBasedAsyncIterable(run, abort) {
|
|
2658
|
+
return {
|
|
2659
|
+
[symbolAsyncIterator]: () => {
|
|
2660
|
+
const queue = new EventQueue();
|
|
2661
|
+
const controller = new AbortController();
|
|
2662
|
+
function dispose() {
|
|
2663
|
+
controller.abort();
|
|
2664
|
+
abort?.removeEventListener('abort', dispose);
|
|
2305
2665
|
}
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
resolve();
|
|
2666
|
+
if (abort) {
|
|
2667
|
+
if (abort.aborted) {
|
|
2668
|
+
controller.abort();
|
|
2310
2669
|
}
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
resolve();
|
|
2670
|
+
else {
|
|
2671
|
+
abort.addEventListener('abort', dispose);
|
|
2314
2672
|
}
|
|
2315
|
-
waitingConsumer = complete;
|
|
2316
|
-
signal.addEventListener('abort', onAbort);
|
|
2317
2673
|
}
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2674
|
+
run(queue, controller.signal);
|
|
2675
|
+
return {
|
|
2676
|
+
async next() {
|
|
2677
|
+
const event = await queue.waitForEvent(controller.signal);
|
|
2678
|
+
return event == null ? doneResult : valueResult(event);
|
|
2679
|
+
},
|
|
2680
|
+
async return() {
|
|
2681
|
+
dispose();
|
|
2682
|
+
return doneResult;
|
|
2683
|
+
}
|
|
2684
|
+
};
|
|
2685
|
+
}
|
|
2686
|
+
};
|
|
2687
|
+
}
|
|
2321
2688
|
}
|
|
2322
2689
|
|
|
2323
2690
|
/**
|
|
@@ -2476,7 +2843,7 @@ class ConnectionManager extends BaseObserver {
|
|
|
2476
2843
|
/**
|
|
2477
2844
|
* Close the sync connection.
|
|
2478
2845
|
*
|
|
2479
|
-
* Use {@link connect} to connect again.
|
|
2846
|
+
* Use {@link ConnectionManager.connect} to connect again.
|
|
2480
2847
|
*/
|
|
2481
2848
|
async disconnect() {
|
|
2482
2849
|
// This will help abort pending connects
|
|
@@ -2616,6 +2983,8 @@ const _finalizer = 'FinalizationRegistry' in globalThis
|
|
|
2616
2983
|
/**
|
|
2617
2984
|
* An efficient comparator for {@link WatchedQuery} created with {@link Query#watch}. This has the ability to determine if a query
|
|
2618
2985
|
* result has changes without necessarily processing all items in the result.
|
|
2986
|
+
*
|
|
2987
|
+
* @public
|
|
2619
2988
|
*/
|
|
2620
2989
|
class ArrayComparator {
|
|
2621
2990
|
options;
|
|
@@ -2643,6 +3012,8 @@ class ArrayComparator {
|
|
|
2643
3012
|
}
|
|
2644
3013
|
/**
|
|
2645
3014
|
* Watched query comparator that always reports changed result sets.
|
|
3015
|
+
*
|
|
3016
|
+
* @public
|
|
2646
3017
|
*/
|
|
2647
3018
|
const FalsyComparator = {
|
|
2648
3019
|
checkEquality: () => false // Default comparator that always returns false
|
|
@@ -2850,6 +3221,8 @@ class AbstractQueryProcessor extends MetaBaseObserver {
|
|
|
2850
3221
|
/**
|
|
2851
3222
|
* An empty differential result set.
|
|
2852
3223
|
* This is used as the initial state for differential incrementally watched queries.
|
|
3224
|
+
*
|
|
3225
|
+
* @internal
|
|
2853
3226
|
*/
|
|
2854
3227
|
const EMPTY_DIFFERENTIAL = {
|
|
2855
3228
|
added: [],
|
|
@@ -2862,6 +3235,8 @@ const EMPTY_DIFFERENTIAL = {
|
|
|
2862
3235
|
* Default implementation of the {@link DifferentialWatchedQueryComparator} for watched queries.
|
|
2863
3236
|
* It keys items by their `id` property if available, alternatively it uses JSON stringification
|
|
2864
3237
|
* of the entire item for the key and comparison.
|
|
3238
|
+
*
|
|
3239
|
+
* @internal
|
|
2865
3240
|
*/
|
|
2866
3241
|
const DEFAULT_ROW_COMPARATOR = {
|
|
2867
3242
|
keyBy: (item) => {
|
|
@@ -3142,6 +3517,8 @@ class CustomQuery {
|
|
|
3142
3517
|
|
|
3143
3518
|
/**
|
|
3144
3519
|
* Tests if the input is a {@link SQLOpenOptions}
|
|
3520
|
+
*
|
|
3521
|
+
* @internal
|
|
3145
3522
|
*/
|
|
3146
3523
|
const isSQLOpenOptions = (test) => {
|
|
3147
3524
|
// typeof null is `object`, but you cannot use the `in` operator on `null.
|
|
@@ -3149,17 +3526,24 @@ const isSQLOpenOptions = (test) => {
|
|
|
3149
3526
|
};
|
|
3150
3527
|
/**
|
|
3151
3528
|
* Tests if input is a {@link SQLOpenFactory}
|
|
3529
|
+
*
|
|
3530
|
+
* @internal
|
|
3152
3531
|
*/
|
|
3153
3532
|
const isSQLOpenFactory = (test) => {
|
|
3154
3533
|
return typeof test?.openDB == 'function';
|
|
3155
3534
|
};
|
|
3156
3535
|
/**
|
|
3157
3536
|
* Tests if input is a {@link DBAdapter}
|
|
3537
|
+
*
|
|
3538
|
+
* @internal
|
|
3158
3539
|
*/
|
|
3159
3540
|
const isDBAdapter = (test) => {
|
|
3160
3541
|
return typeof test?.writeTransaction == 'function';
|
|
3161
3542
|
};
|
|
3162
3543
|
|
|
3544
|
+
/**
|
|
3545
|
+
* @internal
|
|
3546
|
+
*/
|
|
3163
3547
|
exports.PSInternalTable = void 0;
|
|
3164
3548
|
(function (PSInternalTable) {
|
|
3165
3549
|
PSInternalTable["DATA"] = "ps_data";
|
|
@@ -3168,6 +3552,9 @@ exports.PSInternalTable = void 0;
|
|
|
3168
3552
|
PSInternalTable["OPLOG"] = "ps_oplog";
|
|
3169
3553
|
PSInternalTable["UNTYPED"] = "ps_untyped";
|
|
3170
3554
|
})(exports.PSInternalTable || (exports.PSInternalTable = {}));
|
|
3555
|
+
/**
|
|
3556
|
+
* @internal
|
|
3557
|
+
*/
|
|
3171
3558
|
exports.PowerSyncControlCommand = void 0;
|
|
3172
3559
|
(function (PowerSyncControlCommand) {
|
|
3173
3560
|
PowerSyncControlCommand["PROCESS_TEXT_LINE"] = "line_text";
|
|
@@ -3185,6 +3572,8 @@ exports.PowerSyncControlCommand = void 0;
|
|
|
3185
3572
|
|
|
3186
3573
|
/**
|
|
3187
3574
|
* A batch of client-side changes.
|
|
3575
|
+
*
|
|
3576
|
+
* @public
|
|
3188
3577
|
*/
|
|
3189
3578
|
class CrudBatch {
|
|
3190
3579
|
crud;
|
|
@@ -3211,6 +3600,8 @@ class CrudBatch {
|
|
|
3211
3600
|
|
|
3212
3601
|
/**
|
|
3213
3602
|
* Type of local change.
|
|
3603
|
+
*
|
|
3604
|
+
* @public
|
|
3214
3605
|
*/
|
|
3215
3606
|
exports.UpdateType = void 0;
|
|
3216
3607
|
(function (UpdateType) {
|
|
@@ -3223,6 +3614,8 @@ exports.UpdateType = void 0;
|
|
|
3223
3614
|
})(exports.UpdateType || (exports.UpdateType = {}));
|
|
3224
3615
|
/**
|
|
3225
3616
|
* A single client-side change.
|
|
3617
|
+
*
|
|
3618
|
+
* @public
|
|
3226
3619
|
*/
|
|
3227
3620
|
class CrudEntry {
|
|
3228
3621
|
/**
|
|
@@ -3319,6 +3712,9 @@ class CrudEntry {
|
|
|
3319
3712
|
}
|
|
3320
3713
|
}
|
|
3321
3714
|
|
|
3715
|
+
/**
|
|
3716
|
+
* @public
|
|
3717
|
+
*/
|
|
3322
3718
|
class CrudTransaction extends CrudBatch {
|
|
3323
3719
|
crud;
|
|
3324
3720
|
complete;
|
|
@@ -3347,6 +3743,8 @@ class CrudTransaction extends CrudBatch {
|
|
|
3347
3743
|
* Calls to Abortcontroller.abort(reason: any) will result in the
|
|
3348
3744
|
* `reason` being thrown. This is not necessarily an error,
|
|
3349
3745
|
* but extends error for better logging purposes.
|
|
3746
|
+
*
|
|
3747
|
+
* @internal
|
|
3350
3748
|
*/
|
|
3351
3749
|
class AbortOperation extends Error {
|
|
3352
3750
|
reason;
|
|
@@ -8146,7 +8544,7 @@ function requireDist () {
|
|
|
8146
8544
|
|
|
8147
8545
|
var distExports = requireDist();
|
|
8148
8546
|
|
|
8149
|
-
var version = "1.
|
|
8547
|
+
var version = "1.55.0";
|
|
8150
8548
|
var PACKAGE = {
|
|
8151
8549
|
version: version};
|
|
8152
8550
|
|
|
@@ -8222,289 +8620,95 @@ function requireWebsocketDuplexConnection () {
|
|
|
8222
8620
|
get: function () {
|
|
8223
8621
|
return this.done ? 0 : 1;
|
|
8224
8622
|
},
|
|
8225
|
-
enumerable: false,
|
|
8226
|
-
configurable: true
|
|
8227
|
-
});
|
|
8228
|
-
WebsocketDuplexConnection.prototype.close = function (error) {
|
|
8229
|
-
if (this.done) {
|
|
8230
|
-
_super.prototype.close.call(this, error);
|
|
8231
|
-
return;
|
|
8232
|
-
}
|
|
8233
|
-
this.websocket.removeEventListener("close", this.handleClosed);
|
|
8234
|
-
this.websocket.removeEventListener("error", this.handleError);
|
|
8235
|
-
this.websocket.removeEventListener("message", this.handleMessage);
|
|
8236
|
-
this.websocket.close();
|
|
8237
|
-
delete this.websocket;
|
|
8238
|
-
_super.prototype.close.call(this, error);
|
|
8239
|
-
};
|
|
8240
|
-
WebsocketDuplexConnection.prototype.send = function (frame) {
|
|
8241
|
-
if (this.done) {
|
|
8242
|
-
return;
|
|
8243
|
-
}
|
|
8244
|
-
var buffer = (0, rsocket_core_1.serializeFrame)(frame);
|
|
8245
|
-
this.websocket.send(buffer);
|
|
8246
|
-
};
|
|
8247
|
-
return WebsocketDuplexConnection;
|
|
8248
|
-
}(rsocket_core_1.Deferred));
|
|
8249
|
-
WebsocketDuplexConnection.WebsocketDuplexConnection = WebsocketDuplexConnection$1;
|
|
8250
|
-
|
|
8251
|
-
return WebsocketDuplexConnection;
|
|
8252
|
-
}
|
|
8253
|
-
|
|
8254
|
-
var WebsocketDuplexConnectionExports = requireWebsocketDuplexConnection();
|
|
8255
|
-
|
|
8256
|
-
/**
|
|
8257
|
-
* Adapted from rsocket-websocket-client
|
|
8258
|
-
* https://github.com/rsocket/rsocket-js/blob/e224cf379e747c4f1ddc4f2fa111854626cc8575/packages/rsocket-websocket-client/src/WebsocketClientTransport.ts#L17
|
|
8259
|
-
* This adds additional error handling for React Native iOS.
|
|
8260
|
-
* This particularly adds a close listener to handle cases where the WebSocket
|
|
8261
|
-
* connection closes immediately after opening without emitting an error.
|
|
8262
|
-
*/
|
|
8263
|
-
class WebsocketClientTransport {
|
|
8264
|
-
url;
|
|
8265
|
-
factory;
|
|
8266
|
-
constructor(options) {
|
|
8267
|
-
this.url = options.url;
|
|
8268
|
-
this.factory = options.wsCreator ?? ((url) => new WebSocket(url));
|
|
8269
|
-
}
|
|
8270
|
-
connect(multiplexerDemultiplexerFactory) {
|
|
8271
|
-
return new Promise((resolve, reject) => {
|
|
8272
|
-
const websocket = this.factory(this.url);
|
|
8273
|
-
websocket.binaryType = 'arraybuffer';
|
|
8274
|
-
let removeListeners;
|
|
8275
|
-
const openListener = () => {
|
|
8276
|
-
removeListeners();
|
|
8277
|
-
resolve(new WebsocketDuplexConnectionExports.WebsocketDuplexConnection(websocket, new distExports.Deserializer(), multiplexerDemultiplexerFactory));
|
|
8278
|
-
};
|
|
8279
|
-
const errorListener = (ev) => {
|
|
8280
|
-
removeListeners();
|
|
8281
|
-
// We add a default error in that case.
|
|
8282
|
-
if (ev.error != null) {
|
|
8283
|
-
// undici typically provides an error object
|
|
8284
|
-
reject(ev.error);
|
|
8285
|
-
}
|
|
8286
|
-
else if (ev.message != null) {
|
|
8287
|
-
// React Native typically does not provide an error object, but does provide a message
|
|
8288
|
-
reject(new Error(`Failed to create websocket connection: ${ev.message}`));
|
|
8289
|
-
}
|
|
8290
|
-
else {
|
|
8291
|
-
// Browsers often provide no details at all
|
|
8292
|
-
reject(new Error(`Failed to create websocket connection to ${this.url}`));
|
|
8293
|
-
}
|
|
8294
|
-
};
|
|
8295
|
-
/**
|
|
8296
|
-
* In some cases, such as React Native iOS, the WebSocket connection may close immediately after opening
|
|
8297
|
-
* without and error. In such cases, we need to handle the close event to reject the promise.
|
|
8298
|
-
*/
|
|
8299
|
-
const closeListener = () => {
|
|
8300
|
-
removeListeners();
|
|
8301
|
-
reject(new Error('WebSocket connection closed while opening'));
|
|
8302
|
-
};
|
|
8303
|
-
removeListeners = () => {
|
|
8304
|
-
websocket.removeEventListener('open', openListener);
|
|
8305
|
-
websocket.removeEventListener('error', errorListener);
|
|
8306
|
-
websocket.removeEventListener('close', closeListener);
|
|
8307
|
-
};
|
|
8308
|
-
websocket.addEventListener('open', openListener);
|
|
8309
|
-
websocket.addEventListener('error', errorListener);
|
|
8310
|
-
websocket.addEventListener('close', closeListener);
|
|
8311
|
-
});
|
|
8312
|
-
}
|
|
8313
|
-
}
|
|
8314
|
-
|
|
8315
|
-
const doneResult = { done: true, value: undefined };
|
|
8316
|
-
function valueResult(value) {
|
|
8317
|
-
return { done: false, value };
|
|
8318
|
-
}
|
|
8319
|
-
/**
|
|
8320
|
-
* Expands a source async iterator by allowing to inject events asynchronously.
|
|
8321
|
-
*
|
|
8322
|
-
* The resulting iterator will emit all events from its source. Additionally though, events can be injected. These
|
|
8323
|
-
* events are dropped once the main iterator completes, but are otherwise forwarded.
|
|
8324
|
-
*
|
|
8325
|
-
* The iterator completes when its source completes, and it supports backpressure by only calling `next()` on the source
|
|
8326
|
-
* in response to a `next()` call from downstream if no pending injected events can be dispatched.
|
|
8327
|
-
*/
|
|
8328
|
-
function injectable(source) {
|
|
8329
|
-
let sourceIsDone = false;
|
|
8330
|
-
let waiter = undefined; // An active, waiting next() call.
|
|
8331
|
-
// A pending upstream event that couldn't be dispatched because inject() has been called before it was resolved.
|
|
8332
|
-
let pendingSourceEvent = null;
|
|
8333
|
-
let sourceFetchInFlight = false;
|
|
8334
|
-
let pendingInjectedEvents = [];
|
|
8335
|
-
const consumeWaiter = () => {
|
|
8336
|
-
const pending = waiter;
|
|
8337
|
-
waiter = undefined;
|
|
8338
|
-
return pending;
|
|
8339
|
-
};
|
|
8340
|
-
const fetchFromSource = () => {
|
|
8341
|
-
const resolveWaiter = (propagate) => {
|
|
8342
|
-
sourceFetchInFlight = false;
|
|
8343
|
-
const active = consumeWaiter();
|
|
8344
|
-
if (active) {
|
|
8345
|
-
propagate(active);
|
|
8346
|
-
}
|
|
8347
|
-
else {
|
|
8348
|
-
pendingSourceEvent = propagate;
|
|
8349
|
-
}
|
|
8350
|
-
};
|
|
8351
|
-
sourceFetchInFlight = true;
|
|
8352
|
-
const nextFromSource = source.next();
|
|
8353
|
-
nextFromSource.then((value) => {
|
|
8354
|
-
sourceIsDone = value.done == true;
|
|
8355
|
-
resolveWaiter((w) => w.resolve(value));
|
|
8356
|
-
}, (error) => {
|
|
8357
|
-
resolveWaiter((w) => w.reject(error));
|
|
8358
|
-
});
|
|
8359
|
-
};
|
|
8360
|
-
return {
|
|
8361
|
-
next: () => {
|
|
8362
|
-
return new Promise((resolve, reject) => {
|
|
8363
|
-
// First priority: Dispatch ready upstream events.
|
|
8364
|
-
if (sourceIsDone) {
|
|
8365
|
-
return resolve(doneResult);
|
|
8366
|
-
}
|
|
8367
|
-
if (pendingSourceEvent) {
|
|
8368
|
-
pendingSourceEvent({ resolve, reject });
|
|
8369
|
-
pendingSourceEvent = null;
|
|
8370
|
-
return;
|
|
8371
|
-
}
|
|
8372
|
-
// Second priority: Dispatch injected events
|
|
8373
|
-
if (pendingInjectedEvents.length) {
|
|
8374
|
-
return resolve(valueResult(pendingInjectedEvents.shift()));
|
|
8375
|
-
}
|
|
8376
|
-
// Nothing pending? Fetch from source
|
|
8377
|
-
waiter = { resolve, reject };
|
|
8378
|
-
if (!sourceFetchInFlight) {
|
|
8379
|
-
fetchFromSource();
|
|
8380
|
-
}
|
|
8381
|
-
});
|
|
8382
|
-
},
|
|
8383
|
-
inject: (event) => {
|
|
8384
|
-
const pending = consumeWaiter();
|
|
8385
|
-
if (pending != null) {
|
|
8386
|
-
pending.resolve(valueResult(event));
|
|
8387
|
-
}
|
|
8388
|
-
else {
|
|
8389
|
-
pendingInjectedEvents.push(event);
|
|
8390
|
-
}
|
|
8391
|
-
}
|
|
8392
|
-
};
|
|
8393
|
-
}
|
|
8394
|
-
/**
|
|
8395
|
-
* Splits a byte stream at line endings, emitting each line as a string.
|
|
8396
|
-
*/
|
|
8397
|
-
function extractJsonLines(source, decoder) {
|
|
8398
|
-
let buffer = '';
|
|
8399
|
-
const pendingLines = [];
|
|
8400
|
-
let isFinalEvent = false;
|
|
8401
|
-
return {
|
|
8402
|
-
next: async () => {
|
|
8403
|
-
while (true) {
|
|
8404
|
-
if (isFinalEvent) {
|
|
8405
|
-
return doneResult;
|
|
8406
|
-
}
|
|
8407
|
-
{
|
|
8408
|
-
const first = pendingLines.shift();
|
|
8409
|
-
if (first) {
|
|
8410
|
-
return { done: false, value: first };
|
|
8411
|
-
}
|
|
8412
|
-
}
|
|
8413
|
-
const { done, value } = await source.next();
|
|
8414
|
-
if (done) {
|
|
8415
|
-
const remaining = buffer.trim();
|
|
8416
|
-
if (remaining.length != 0) {
|
|
8417
|
-
isFinalEvent = true;
|
|
8418
|
-
return { done: false, value: remaining };
|
|
8419
|
-
}
|
|
8420
|
-
return doneResult;
|
|
8421
|
-
}
|
|
8422
|
-
const data = decoder.decode(value, { stream: true });
|
|
8423
|
-
buffer += data;
|
|
8424
|
-
const lines = buffer.split('\n');
|
|
8425
|
-
for (let i = 0; i < lines.length - 1; i++) {
|
|
8426
|
-
const l = lines[i].trim();
|
|
8427
|
-
if (l.length > 0) {
|
|
8428
|
-
pendingLines.push(l);
|
|
8429
|
-
}
|
|
8430
|
-
}
|
|
8431
|
-
buffer = lines[lines.length - 1];
|
|
8432
|
-
}
|
|
8433
|
-
}
|
|
8434
|
-
};
|
|
8623
|
+
enumerable: false,
|
|
8624
|
+
configurable: true
|
|
8625
|
+
});
|
|
8626
|
+
WebsocketDuplexConnection.prototype.close = function (error) {
|
|
8627
|
+
if (this.done) {
|
|
8628
|
+
_super.prototype.close.call(this, error);
|
|
8629
|
+
return;
|
|
8630
|
+
}
|
|
8631
|
+
this.websocket.removeEventListener("close", this.handleClosed);
|
|
8632
|
+
this.websocket.removeEventListener("error", this.handleError);
|
|
8633
|
+
this.websocket.removeEventListener("message", this.handleMessage);
|
|
8634
|
+
this.websocket.close();
|
|
8635
|
+
delete this.websocket;
|
|
8636
|
+
_super.prototype.close.call(this, error);
|
|
8637
|
+
};
|
|
8638
|
+
WebsocketDuplexConnection.prototype.send = function (frame) {
|
|
8639
|
+
if (this.done) {
|
|
8640
|
+
return;
|
|
8641
|
+
}
|
|
8642
|
+
var buffer = (0, rsocket_core_1.serializeFrame)(frame);
|
|
8643
|
+
this.websocket.send(buffer);
|
|
8644
|
+
};
|
|
8645
|
+
return WebsocketDuplexConnection;
|
|
8646
|
+
}(rsocket_core_1.Deferred));
|
|
8647
|
+
WebsocketDuplexConnection.WebsocketDuplexConnection = WebsocketDuplexConnection$1;
|
|
8648
|
+
|
|
8649
|
+
return WebsocketDuplexConnection;
|
|
8435
8650
|
}
|
|
8651
|
+
|
|
8652
|
+
var WebsocketDuplexConnectionExports = requireWebsocketDuplexConnection();
|
|
8653
|
+
|
|
8436
8654
|
/**
|
|
8437
|
-
*
|
|
8655
|
+
* Adapted from rsocket-websocket-client
|
|
8656
|
+
* https://github.com/rsocket/rsocket-js/blob/e224cf379e747c4f1ddc4f2fa111854626cc8575/packages/rsocket-websocket-client/src/WebsocketClientTransport.ts#L17
|
|
8657
|
+
* This adds additional error handling for React Native iOS.
|
|
8658
|
+
* This particularly adds a close listener to handle cases where the WebSocket
|
|
8659
|
+
* connection closes immediately after opening without emitting an error.
|
|
8438
8660
|
*/
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
|
|
8457
|
-
|
|
8661
|
+
class WebsocketClientTransport {
|
|
8662
|
+
url;
|
|
8663
|
+
factory;
|
|
8664
|
+
constructor(options) {
|
|
8665
|
+
this.url = options.url;
|
|
8666
|
+
this.factory = options.wsCreator ?? ((url) => new WebSocket(url));
|
|
8667
|
+
}
|
|
8668
|
+
connect(multiplexerDemultiplexerFactory) {
|
|
8669
|
+
return new Promise((resolve, reject) => {
|
|
8670
|
+
const websocket = this.factory(this.url);
|
|
8671
|
+
websocket.binaryType = 'arraybuffer';
|
|
8672
|
+
let removeListeners;
|
|
8673
|
+
const openListener = () => {
|
|
8674
|
+
removeListeners();
|
|
8675
|
+
resolve(new WebsocketDuplexConnectionExports.WebsocketDuplexConnection(websocket, new distExports.Deserializer(), multiplexerDemultiplexerFactory));
|
|
8676
|
+
};
|
|
8677
|
+
const errorListener = (event) => {
|
|
8678
|
+
const ev = event;
|
|
8679
|
+
removeListeners();
|
|
8680
|
+
// We add a default error in that case.
|
|
8681
|
+
if (ev.error != null) {
|
|
8682
|
+
// undici typically provides an error object
|
|
8683
|
+
reject(ev.error);
|
|
8458
8684
|
}
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
if (objectBody || remainingLength != 4) {
|
|
8463
|
-
throw new Error('illegal end of stream in BSON object');
|
|
8464
|
-
}
|
|
8465
|
-
return doneResult;
|
|
8685
|
+
else if (ev.message != null) {
|
|
8686
|
+
// React Native typically does not provide an error object, but does provide a message
|
|
8687
|
+
reject(new Error(`Failed to create websocket connection: ${ev.message}`));
|
|
8466
8688
|
}
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
if (objectBody) {
|
|
8471
|
-
// We're in the middle of reading a BSON document.
|
|
8472
|
-
const bytesToRead = Math.min(availableInData, remainingLength);
|
|
8473
|
-
const copySource = new Uint8Array(chunk.buffer, chunk.byteOffset + i, bytesToRead);
|
|
8474
|
-
objectBody.set(copySource, objectBody.length - remainingLength);
|
|
8475
|
-
i += bytesToRead;
|
|
8476
|
-
remainingLength -= bytesToRead;
|
|
8477
|
-
if (remainingLength == 0) {
|
|
8478
|
-
completedObjects.push(objectBody);
|
|
8479
|
-
// Prepare to read another document, starting with its length
|
|
8480
|
-
objectBody = null;
|
|
8481
|
-
remainingLength = 4;
|
|
8482
|
-
}
|
|
8483
|
-
}
|
|
8484
|
-
else {
|
|
8485
|
-
// Copy up to 4 bytes into lengthBuffer, depending on how many we still need.
|
|
8486
|
-
const bytesToRead = Math.min(availableInData, remainingLength);
|
|
8487
|
-
for (let j = 0; j < bytesToRead; j++) {
|
|
8488
|
-
lengthBuffer.setUint8(4 - remainingLength + j, chunk[i + j]);
|
|
8489
|
-
}
|
|
8490
|
-
i += bytesToRead;
|
|
8491
|
-
remainingLength -= bytesToRead;
|
|
8492
|
-
if (remainingLength == 0) {
|
|
8493
|
-
// Transition from reading length header to reading document. Subtracting 4 because the length of the
|
|
8494
|
-
// header is included in length.
|
|
8495
|
-
const length = lengthBuffer.getInt32(0, true /* little endian */);
|
|
8496
|
-
remainingLength = length - 4;
|
|
8497
|
-
if (remainingLength < 1) {
|
|
8498
|
-
throw new Error(`invalid length for bson: ${length}`);
|
|
8499
|
-
}
|
|
8500
|
-
objectBody = new Uint8Array(length);
|
|
8501
|
-
new DataView(objectBody.buffer).setInt32(0, length, true);
|
|
8502
|
-
}
|
|
8503
|
-
}
|
|
8689
|
+
else {
|
|
8690
|
+
// Browsers often provide no details at all
|
|
8691
|
+
reject(new Error(`Failed to create websocket connection to ${this.url}`));
|
|
8504
8692
|
}
|
|
8505
|
-
}
|
|
8506
|
-
|
|
8507
|
-
|
|
8693
|
+
};
|
|
8694
|
+
/**
|
|
8695
|
+
* In some cases, such as React Native iOS, the WebSocket connection may close immediately after opening
|
|
8696
|
+
* without and error. In such cases, we need to handle the close event to reject the promise.
|
|
8697
|
+
*/
|
|
8698
|
+
const closeListener = () => {
|
|
8699
|
+
removeListeners();
|
|
8700
|
+
reject(new Error('WebSocket connection closed while opening'));
|
|
8701
|
+
};
|
|
8702
|
+
removeListeners = () => {
|
|
8703
|
+
websocket.removeEventListener('open', openListener);
|
|
8704
|
+
websocket.removeEventListener('error', errorListener);
|
|
8705
|
+
websocket.removeEventListener('close', closeListener);
|
|
8706
|
+
};
|
|
8707
|
+
websocket.addEventListener('open', openListener);
|
|
8708
|
+
websocket.addEventListener('error', errorListener);
|
|
8709
|
+
websocket.addEventListener('close', closeListener);
|
|
8710
|
+
});
|
|
8711
|
+
}
|
|
8508
8712
|
}
|
|
8509
8713
|
|
|
8510
8714
|
const POWERSYNC_TRAILING_SLASH_MATCH = /\/+$/;
|
|
@@ -8519,7 +8723,13 @@ const SOCKET_TIMEOUT_MS = 30_000;
|
|
|
8519
8723
|
// If there is a backlog of messages (for example on slow connections), keepalive messages could be delayed
|
|
8520
8724
|
// significantly. Therefore this is longer than the socket timeout.
|
|
8521
8725
|
const KEEP_ALIVE_LIFETIME_MS = 90_000;
|
|
8726
|
+
/**
|
|
8727
|
+
* @internal
|
|
8728
|
+
*/
|
|
8522
8729
|
const DEFAULT_REMOTE_LOGGER = Logger.get('PowerSyncRemote');
|
|
8730
|
+
/**
|
|
8731
|
+
* @public
|
|
8732
|
+
*/
|
|
8523
8733
|
exports.FetchStrategy = void 0;
|
|
8524
8734
|
(function (FetchStrategy) {
|
|
8525
8735
|
/**
|
|
@@ -8538,12 +8748,17 @@ exports.FetchStrategy = void 0;
|
|
|
8538
8748
|
* The class wrapper is used to distinguish the fetchImplementation
|
|
8539
8749
|
* option in [AbstractRemoteOptions] from the general fetch method
|
|
8540
8750
|
* which is typeof "function"
|
|
8751
|
+
*
|
|
8752
|
+
* @internal
|
|
8541
8753
|
*/
|
|
8542
8754
|
class FetchImplementationProvider {
|
|
8543
8755
|
getFetch() {
|
|
8544
8756
|
throw new Error('Unspecified fetch implementation');
|
|
8545
8757
|
}
|
|
8546
8758
|
}
|
|
8759
|
+
/**
|
|
8760
|
+
* @internal
|
|
8761
|
+
*/
|
|
8547
8762
|
const DEFAULT_REMOTE_OPTIONS = {
|
|
8548
8763
|
socketUrlTransformer: (url) => url.replace(/^https?:\/\//, function (match) {
|
|
8549
8764
|
return match === 'https://' ? 'wss://' : 'ws://';
|
|
@@ -8551,6 +8766,9 @@ const DEFAULT_REMOTE_OPTIONS = {
|
|
|
8551
8766
|
fetchImplementation: new FetchImplementationProvider(),
|
|
8552
8767
|
fetchOptions: {}
|
|
8553
8768
|
};
|
|
8769
|
+
/**
|
|
8770
|
+
* @internal
|
|
8771
|
+
*/
|
|
8554
8772
|
class AbstractRemote {
|
|
8555
8773
|
connector;
|
|
8556
8774
|
logger;
|
|
@@ -8711,8 +8929,19 @@ class AbstractRemote {
|
|
|
8711
8929
|
let pendingSocket = null;
|
|
8712
8930
|
let keepAliveTimeout;
|
|
8713
8931
|
let rsocket = null;
|
|
8714
|
-
let
|
|
8932
|
+
let paused = false;
|
|
8933
|
+
const queue = new EventQueue({
|
|
8934
|
+
eventDelivered: () => {
|
|
8935
|
+
if (queue.countOutstandingEvents <= SYNC_QUEUE_REQUEST_LOW_WATER) {
|
|
8936
|
+
paused = false;
|
|
8937
|
+
requestMore();
|
|
8938
|
+
}
|
|
8939
|
+
}
|
|
8940
|
+
});
|
|
8715
8941
|
let didClose = false;
|
|
8942
|
+
let connectionEstablished = false;
|
|
8943
|
+
let pendingEventsCount = syncQueueRequestSize;
|
|
8944
|
+
let res = null;
|
|
8716
8945
|
const abortRequest = () => {
|
|
8717
8946
|
if (didClose) {
|
|
8718
8947
|
return;
|
|
@@ -8725,10 +8954,23 @@ class AbstractRemote {
|
|
|
8725
8954
|
if (rsocket) {
|
|
8726
8955
|
rsocket.close();
|
|
8727
8956
|
}
|
|
8728
|
-
|
|
8729
|
-
|
|
8730
|
-
|
|
8957
|
+
// Send a bogus event to the queue to ensure a pending listener gets woken up. We check for didClose and would
|
|
8958
|
+
// return a doneEvent.
|
|
8959
|
+
queue.notify(null);
|
|
8731
8960
|
};
|
|
8961
|
+
function push(event) {
|
|
8962
|
+
queue.notify(event);
|
|
8963
|
+
if (queue.countOutstandingEvents >= SYNC_QUEUE_REQUEST_HIGH_WATER) {
|
|
8964
|
+
paused = true;
|
|
8965
|
+
}
|
|
8966
|
+
}
|
|
8967
|
+
function requestMore() {
|
|
8968
|
+
const delta = syncQueueRequestSize - pendingEventsCount;
|
|
8969
|
+
if (!paused && delta > 0) {
|
|
8970
|
+
res?.request(delta);
|
|
8971
|
+
pendingEventsCount = syncQueueRequestSize;
|
|
8972
|
+
}
|
|
8973
|
+
}
|
|
8732
8974
|
// Handle upstream abort
|
|
8733
8975
|
if (options.abortSignal.aborted) {
|
|
8734
8976
|
throw new AbortOperation('Connection request aborted');
|
|
@@ -8783,25 +9025,19 @@ class AbstractRemote {
|
|
|
8783
9025
|
// Helps to prevent double close scenarios
|
|
8784
9026
|
rsocket.onClose(() => (rsocket = null));
|
|
8785
9027
|
return await new Promise((resolve, reject) => {
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
|
|
8791
|
-
|
|
8792
|
-
|
|
8793
|
-
|
|
8794
|
-
|
|
9028
|
+
const queueAsIterator = {
|
|
9029
|
+
next: async () => {
|
|
9030
|
+
if (didClose)
|
|
9031
|
+
return doneResult;
|
|
9032
|
+
const notification = await queue.waitForEvent(options.abortSignal);
|
|
9033
|
+
if (didClose) {
|
|
9034
|
+
return doneResult;
|
|
9035
|
+
}
|
|
9036
|
+
else {
|
|
9037
|
+
return valueResult(notification);
|
|
9038
|
+
}
|
|
8795
9039
|
}
|
|
8796
|
-
}
|
|
8797
|
-
const events = new eventIterator.EventIterator((q) => {
|
|
8798
|
-
queue = q;
|
|
8799
|
-
q.on('highWater', () => (paused = true));
|
|
8800
|
-
q.on('lowWater', () => {
|
|
8801
|
-
paused = false;
|
|
8802
|
-
requestMore();
|
|
8803
|
-
});
|
|
8804
|
-
}, { highWaterMark: SYNC_QUEUE_REQUEST_HIGH_WATER, lowWaterMark: SYNC_QUEUE_REQUEST_LOW_WATER })[Symbol.asyncIterator]();
|
|
9040
|
+
};
|
|
8805
9041
|
res = rsocket.requestStream({
|
|
8806
9042
|
data: toBuffer(options.data),
|
|
8807
9043
|
metadata: toBuffer({
|
|
@@ -8837,11 +9073,11 @@ class AbstractRemote {
|
|
|
8837
9073
|
// The connection is active
|
|
8838
9074
|
if (!connectionEstablished) {
|
|
8839
9075
|
connectionEstablished = true;
|
|
8840
|
-
resolve(
|
|
9076
|
+
resolve(queueAsIterator);
|
|
8841
9077
|
}
|
|
8842
9078
|
const { data } = payload;
|
|
8843
9079
|
if (data) {
|
|
8844
|
-
|
|
9080
|
+
push(data);
|
|
8845
9081
|
}
|
|
8846
9082
|
// Less events are now pending
|
|
8847
9083
|
pendingEventsCount--;
|
|
@@ -8960,7 +9196,7 @@ class AbstractRemote {
|
|
|
8960
9196
|
* Posts a `/sync/stream` request.
|
|
8961
9197
|
*
|
|
8962
9198
|
* Depending on the `Content-Type` of the response, this returns strings for sync lines or encoded BSON documents as
|
|
8963
|
-
*
|
|
9199
|
+
* `Uint8Array`s.
|
|
8964
9200
|
*/
|
|
8965
9201
|
async fetchStream(options) {
|
|
8966
9202
|
const { isBson, stream } = await this.fetchStreamRaw(options);
|
|
@@ -9002,16 +9238,26 @@ function isInterruptingInstruction(instruction) {
|
|
|
9002
9238
|
return 'EstablishSyncStream' in instruction || 'CloseSyncStream' in instruction;
|
|
9003
9239
|
}
|
|
9004
9240
|
|
|
9241
|
+
/**
|
|
9242
|
+
* @internal
|
|
9243
|
+
*/
|
|
9005
9244
|
exports.LockType = void 0;
|
|
9006
9245
|
(function (LockType) {
|
|
9007
9246
|
LockType["CRUD"] = "crud";
|
|
9008
9247
|
LockType["SYNC"] = "sync";
|
|
9009
9248
|
})(exports.LockType || (exports.LockType = {}));
|
|
9249
|
+
/**
|
|
9250
|
+
* @public
|
|
9251
|
+
*/
|
|
9010
9252
|
exports.SyncStreamConnectionMethod = void 0;
|
|
9011
9253
|
(function (SyncStreamConnectionMethod) {
|
|
9012
9254
|
SyncStreamConnectionMethod["HTTP"] = "http";
|
|
9013
9255
|
SyncStreamConnectionMethod["WEB_SOCKET"] = "web-socket";
|
|
9014
9256
|
})(exports.SyncStreamConnectionMethod || (exports.SyncStreamConnectionMethod = {}));
|
|
9257
|
+
/**
|
|
9258
|
+
* @deprecated Deprecated since {@link SyncClientImplementation.RUST} is the only option.
|
|
9259
|
+
* @public
|
|
9260
|
+
*/
|
|
9015
9261
|
exports.SyncClientImplementation = void 0;
|
|
9016
9262
|
(function (SyncClientImplementation) {
|
|
9017
9263
|
/**
|
|
@@ -9023,8 +9269,8 @@ exports.SyncClientImplementation = void 0;
|
|
|
9023
9269
|
* ## Compatibility warning
|
|
9024
9270
|
*
|
|
9025
9271
|
* The Rust sync client stores sync data in a format that is slightly different than the one used
|
|
9026
|
-
* by the old JavaScript client. When adopting the {@link RUST} client on existing databases,
|
|
9027
|
-
* migrate the format automatically.
|
|
9272
|
+
* by the old JavaScript client. When adopting the {@link SyncClientImplementation.RUST} client on existing databases,
|
|
9273
|
+
* the PowerSync SDK will migrate the format automatically.
|
|
9028
9274
|
*
|
|
9029
9275
|
* SDK versions supporting both the JavaScript and the Rust client support both formats with the JavaScript client
|
|
9030
9276
|
* implementaiton. However, downgrading to an SDK version that only supports the JavaScript client would not be
|
|
@@ -9034,14 +9280,29 @@ exports.SyncClientImplementation = void 0;
|
|
|
9034
9280
|
})(exports.SyncClientImplementation || (exports.SyncClientImplementation = {}));
|
|
9035
9281
|
/**
|
|
9036
9282
|
* The default {@link SyncClientImplementation} to use, {@link SyncClientImplementation.RUST}.
|
|
9283
|
+
*
|
|
9284
|
+
* @deprecated Deprecated since {@link SyncClientImplementation.RUST} is the only option.
|
|
9285
|
+
* @public
|
|
9037
9286
|
*/
|
|
9038
9287
|
const DEFAULT_SYNC_CLIENT_IMPLEMENTATION = exports.SyncClientImplementation.RUST;
|
|
9288
|
+
/**
|
|
9289
|
+
* @internal
|
|
9290
|
+
*/
|
|
9039
9291
|
const DEFAULT_CRUD_UPLOAD_THROTTLE_MS = 1000;
|
|
9292
|
+
/**
|
|
9293
|
+
* @internal
|
|
9294
|
+
*/
|
|
9040
9295
|
const DEFAULT_RETRY_DELAY_MS = 5000;
|
|
9296
|
+
/**
|
|
9297
|
+
* @internal
|
|
9298
|
+
*/
|
|
9041
9299
|
const DEFAULT_STREAMING_SYNC_OPTIONS = {
|
|
9042
9300
|
retryDelayMs: DEFAULT_RETRY_DELAY_MS,
|
|
9043
9301
|
crudUploadThrottleMs: DEFAULT_CRUD_UPLOAD_THROTTLE_MS
|
|
9044
9302
|
};
|
|
9303
|
+
/**
|
|
9304
|
+
* @internal
|
|
9305
|
+
*/
|
|
9045
9306
|
const DEFAULT_STREAM_CONNECTION_OPTIONS = {
|
|
9046
9307
|
appMetadata: {},
|
|
9047
9308
|
connectionMethod: exports.SyncStreamConnectionMethod.WEB_SOCKET,
|
|
@@ -9051,6 +9312,9 @@ const DEFAULT_STREAM_CONNECTION_OPTIONS = {
|
|
|
9051
9312
|
serializedSchema: undefined,
|
|
9052
9313
|
includeDefaultStreams: true
|
|
9053
9314
|
};
|
|
9315
|
+
/**
|
|
9316
|
+
* @internal
|
|
9317
|
+
*/
|
|
9054
9318
|
class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
9055
9319
|
options;
|
|
9056
9320
|
abortController;
|
|
@@ -9374,7 +9638,7 @@ The next upload iteration will be delayed.`);
|
|
|
9374
9638
|
this.handleActiveStreamsChange?.();
|
|
9375
9639
|
}
|
|
9376
9640
|
/**
|
|
9377
|
-
* Older versions of the JS SDK used to encode subkeys as JSON in
|
|
9641
|
+
* Older versions of the JS SDK used to encode subkeys as JSON in `OplogEntry.toJSON`.
|
|
9378
9642
|
* Because subkeys are always strings, this leads to quotes being added around them in `ps_oplog`.
|
|
9379
9643
|
* While this is not a problem as long as it's done consistently, it causes issues when a database
|
|
9380
9644
|
* created by the JS SDK is used with other SDKs, or (more likely) when the new Rust sync client
|
|
@@ -9384,7 +9648,7 @@ The next upload iteration will be delayed.`);
|
|
|
9384
9648
|
* migration is only triggered when necessary (for now). The function returns whether the new format
|
|
9385
9649
|
* should be used, so that the JS SDK is able to write to updated databases.
|
|
9386
9650
|
*
|
|
9387
|
-
* @param requireFixedKeyFormat Whether we require the new format or also support the old one.
|
|
9651
|
+
* @param requireFixedKeyFormat - Whether we require the new format or also support the old one.
|
|
9388
9652
|
* The Rust client requires the new subkey format.
|
|
9389
9653
|
* @returns Whether the database is now using the new, fixed subkey format.
|
|
9390
9654
|
*/
|
|
@@ -9691,7 +9955,8 @@ const MEMORY_TRIGGER_CLAIM_MANAGER = {
|
|
|
9691
9955
|
|
|
9692
9956
|
/**
|
|
9693
9957
|
* SQLite operations to track changes for with {@link TriggerManager}
|
|
9694
|
-
*
|
|
9958
|
+
*
|
|
9959
|
+
* @experimental @alpha
|
|
9695
9960
|
*/
|
|
9696
9961
|
exports.DiffTriggerOperation = void 0;
|
|
9697
9962
|
(function (DiffTriggerOperation) {
|
|
@@ -9753,8 +10018,8 @@ class TriggerManagerImpl {
|
|
|
9753
10018
|
get db() {
|
|
9754
10019
|
return this.options.db;
|
|
9755
10020
|
}
|
|
9756
|
-
async getUUID() {
|
|
9757
|
-
const { id: uuid } = await this.db.get(/* sql */ `
|
|
10021
|
+
async getUUID(ctx) {
|
|
10022
|
+
const { id: uuid } = await (ctx ?? this.db).get(/* sql */ `
|
|
9758
10023
|
SELECT
|
|
9759
10024
|
uuid () as id
|
|
9760
10025
|
`);
|
|
@@ -9867,7 +10132,7 @@ class TriggerManagerImpl {
|
|
|
9867
10132
|
const replicatedColumns = columns ?? sourceDefinition.columns.map((col) => col.name);
|
|
9868
10133
|
const internalSource = sourceDefinition.internalName;
|
|
9869
10134
|
const triggerIds = [];
|
|
9870
|
-
const id = await this.getUUID();
|
|
10135
|
+
const id = await this.getUUID(setupContext);
|
|
9871
10136
|
const releaseStorageClaim = useStorage ? await this.options.claimManager.obtainClaim(id) : null;
|
|
9872
10137
|
/**
|
|
9873
10138
|
* We default to replicating all columns if no columns array is provided.
|
|
@@ -10107,18 +10372,29 @@ const POWERSYNC_TABLE_MATCH = /(^ps_data__|^ps_data_local__)/;
|
|
|
10107
10372
|
const DEFAULT_DISCONNECT_CLEAR_OPTIONS = {
|
|
10108
10373
|
clearLocal: true
|
|
10109
10374
|
};
|
|
10375
|
+
/**
|
|
10376
|
+
* @internal
|
|
10377
|
+
*/
|
|
10110
10378
|
const DEFAULT_POWERSYNC_CLOSE_OPTIONS = {
|
|
10111
10379
|
disconnect: true
|
|
10112
10380
|
};
|
|
10381
|
+
/**
|
|
10382
|
+
* @internal
|
|
10383
|
+
*/
|
|
10113
10384
|
const DEFAULT_POWERSYNC_DB_OPTIONS = {
|
|
10114
10385
|
retryDelayMs: 5000,
|
|
10115
10386
|
crudUploadThrottleMs: DEFAULT_CRUD_UPLOAD_THROTTLE_MS
|
|
10116
10387
|
};
|
|
10388
|
+
/**
|
|
10389
|
+
* @internal
|
|
10390
|
+
*/
|
|
10117
10391
|
const DEFAULT_CRUD_BATCH_LIMIT = 100;
|
|
10118
10392
|
/**
|
|
10119
10393
|
* Requesting nested or recursive locks can block the application in some circumstances.
|
|
10120
10394
|
* This default lock timeout will act as a failsafe to throw an error if a lock cannot
|
|
10121
10395
|
* be obtained.
|
|
10396
|
+
*
|
|
10397
|
+
* @internal
|
|
10122
10398
|
*/
|
|
10123
10399
|
const DEFAULT_LOCK_TIMEOUT_MS = 120_000; // 2 mins
|
|
10124
10400
|
/**
|
|
@@ -10128,6 +10404,9 @@ const DEFAULT_LOCK_TIMEOUT_MS = 120_000; // 2 mins
|
|
|
10128
10404
|
const isPowerSyncDatabaseOptionsWithSettings = (test) => {
|
|
10129
10405
|
return typeof test == 'object' && isSQLOpenOptions(test.database);
|
|
10130
10406
|
};
|
|
10407
|
+
/**
|
|
10408
|
+
* @public
|
|
10409
|
+
*/
|
|
10131
10410
|
class AbstractPowerSyncDatabase extends BaseObserver {
|
|
10132
10411
|
options;
|
|
10133
10412
|
/**
|
|
@@ -10285,7 +10564,7 @@ class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
10285
10564
|
/**
|
|
10286
10565
|
* Wait for the first sync operation to complete.
|
|
10287
10566
|
*
|
|
10288
|
-
* @param request Either an abort signal (after which the promise will complete regardless of
|
|
10567
|
+
* @param request - Either an abort signal (after which the promise will complete regardless of
|
|
10289
10568
|
* whether a full sync was completed) or an object providing an abort signal and a priority target.
|
|
10290
10569
|
* When a priority target is set, the promise may complete when all buckets with the given (or higher)
|
|
10291
10570
|
* priorities have been synchronized. This can be earlier than a complete sync.
|
|
@@ -10440,7 +10719,7 @@ class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
10440
10719
|
/**
|
|
10441
10720
|
* Close the sync connection.
|
|
10442
10721
|
*
|
|
10443
|
-
* Use {@link connect} to connect again.
|
|
10722
|
+
* Use {@link AbstractPowerSyncDatabase.connect} to connect again.
|
|
10444
10723
|
*/
|
|
10445
10724
|
async disconnect() {
|
|
10446
10725
|
return this.connectionManager.disconnect();
|
|
@@ -10467,8 +10746,8 @@ class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
10467
10746
|
/**
|
|
10468
10747
|
* Create a sync stream to query its status or to subscribe to it.
|
|
10469
10748
|
*
|
|
10470
|
-
* @param name The name of the stream to subscribe to.
|
|
10471
|
-
* @param params Optional parameters for the stream subscription.
|
|
10749
|
+
* @param name - The name of the stream to subscribe to.
|
|
10750
|
+
* @param params - Optional parameters for the stream subscription.
|
|
10472
10751
|
* @returns A {@link SyncStream} instance that can be subscribed to.
|
|
10473
10752
|
* @experimental Sync streams are currently in alpha.
|
|
10474
10753
|
*/
|
|
@@ -10526,14 +10805,14 @@ class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
10526
10805
|
* Once the data have been successfully uploaded, call {@link CrudBatch.complete} before
|
|
10527
10806
|
* requesting the next batch.
|
|
10528
10807
|
*
|
|
10529
|
-
* Use
|
|
10808
|
+
* Use the `limit` parameter to specify the maximum number of updates to return in a single
|
|
10530
10809
|
* batch.
|
|
10531
10810
|
*
|
|
10532
10811
|
* This method does include transaction ids in the result, but does not group
|
|
10533
10812
|
* data by transaction. One batch may contain data from multiple transactions,
|
|
10534
10813
|
* and a single transaction may be split over multiple batches.
|
|
10535
10814
|
*
|
|
10536
|
-
* @param limit Maximum number of CRUD entries to include in the batch
|
|
10815
|
+
* @param limit - Maximum number of CRUD entries to include in the batch
|
|
10537
10816
|
* @returns A batch of CRUD operations to upload, or null if there are none
|
|
10538
10817
|
*/
|
|
10539
10818
|
async getCrudBatch(limit = DEFAULT_CRUD_BATCH_LIMIT) {
|
|
@@ -10560,13 +10839,13 @@ class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
10560
10839
|
* Once the data have been successfully uploaded, call {@link CrudTransaction.complete} before
|
|
10561
10840
|
* requesting the next transaction.
|
|
10562
10841
|
*
|
|
10563
|
-
* Unlike {@link getCrudBatch}, this only returns data from a single transaction at a time.
|
|
10842
|
+
* Unlike {@link AbstractPowerSyncDatabase.getCrudBatch}, this only returns data from a single transaction at a time.
|
|
10564
10843
|
* All data for the transaction is loaded into memory.
|
|
10565
10844
|
*
|
|
10566
10845
|
* @returns A transaction of CRUD operations to upload, or null if there are none
|
|
10567
10846
|
*/
|
|
10568
10847
|
async getNextCrudTransaction() {
|
|
10569
|
-
const iterator = this.getCrudTransactions()[
|
|
10848
|
+
const iterator = this.getCrudTransactions()[symbolAsyncIterator]();
|
|
10570
10849
|
return (await iterator.next()).value;
|
|
10571
10850
|
}
|
|
10572
10851
|
/**
|
|
@@ -10575,7 +10854,7 @@ class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
10575
10854
|
* This is typically used from the {@link PowerSyncBackendConnector.uploadData} callback. Each entry emitted by the
|
|
10576
10855
|
* returned iterator is a full transaction containing all local writes made while that transaction was active.
|
|
10577
10856
|
*
|
|
10578
|
-
* Unlike {@link getNextCrudTransaction}, which always returns the oldest transaction that hasn't been
|
|
10857
|
+
* Unlike {@link AbstractPowerSyncDatabase.getNextCrudTransaction}, which always returns the oldest transaction that hasn't been
|
|
10579
10858
|
* {@link CrudTransaction.complete}d yet, this iterator can be used to receive multiple transactions. Calling
|
|
10580
10859
|
* {@link CrudTransaction.complete} will mark that and all prior transactions emitted by the iterator as completed.
|
|
10581
10860
|
*
|
|
@@ -10602,7 +10881,7 @@ class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
10602
10881
|
*/
|
|
10603
10882
|
getCrudTransactions() {
|
|
10604
10883
|
return {
|
|
10605
|
-
[
|
|
10884
|
+
[symbolAsyncIterator]: () => {
|
|
10606
10885
|
let lastCrudItemId = -1;
|
|
10607
10886
|
const sql = `
|
|
10608
10887
|
WITH RECURSIVE crud_entries AS (
|
|
@@ -10669,8 +10948,8 @@ SELECT * FROM crud_entries;
|
|
|
10669
10948
|
* the returned result's `rowsAffected` may be `0` for successful `UPDATE` and `DELETE` statements.
|
|
10670
10949
|
* Use a `RETURNING` clause and inspect `result.rows` when you need to confirm which rows changed.
|
|
10671
10950
|
*
|
|
10672
|
-
* @param sql The SQL query to execute
|
|
10673
|
-
* @param parameters Optional array of parameters to bind to the query
|
|
10951
|
+
* @param sql - The SQL query to execute
|
|
10952
|
+
* @param parameters - Optional array of parameters to bind to the query
|
|
10674
10953
|
* @returns The query result as an object with structured key-value pairs
|
|
10675
10954
|
*/
|
|
10676
10955
|
async execute(sql, parameters) {
|
|
@@ -10680,8 +10959,8 @@ SELECT * FROM crud_entries;
|
|
|
10680
10959
|
* Execute a SQL write (INSERT/UPDATE/DELETE) query directly on the database without any PowerSync processing.
|
|
10681
10960
|
* This bypasses certain PowerSync abstractions and is useful for accessing the raw database results.
|
|
10682
10961
|
*
|
|
10683
|
-
* @param sql The SQL query to execute
|
|
10684
|
-
* @param parameters Optional array of parameters to bind to the query
|
|
10962
|
+
* @param sql - The SQL query to execute
|
|
10963
|
+
* @param parameters - Optional array of parameters to bind to the query
|
|
10685
10964
|
* @returns The raw query result from the underlying database as a nested array of raw values, where each row is
|
|
10686
10965
|
* represented as an array of column values without field names.
|
|
10687
10966
|
*/
|
|
@@ -10694,8 +10973,8 @@ SELECT * FROM crud_entries;
|
|
|
10694
10973
|
* and optionally return results.
|
|
10695
10974
|
* This is faster than executing separately with each parameter set.
|
|
10696
10975
|
*
|
|
10697
|
-
* @param sql The SQL query to execute
|
|
10698
|
-
* @param parameters Optional 2D array of parameter sets, where each inner array is a set of parameters for one execution
|
|
10976
|
+
* @param sql - The SQL query to execute
|
|
10977
|
+
* @param parameters - Optional 2D array of parameter sets, where each inner array is a set of parameters for one execution
|
|
10699
10978
|
* @returns The query result
|
|
10700
10979
|
*/
|
|
10701
10980
|
async executeBatch(sql, parameters) {
|
|
@@ -10705,8 +10984,8 @@ SELECT * FROM crud_entries;
|
|
|
10705
10984
|
/**
|
|
10706
10985
|
* Execute a read-only query and return results.
|
|
10707
10986
|
*
|
|
10708
|
-
* @param sql The SQL query to execute
|
|
10709
|
-
* @param parameters Optional array of parameters to bind to the query
|
|
10987
|
+
* @param sql - The SQL query to execute
|
|
10988
|
+
* @param parameters - Optional array of parameters to bind to the query
|
|
10710
10989
|
* @returns An array of results
|
|
10711
10990
|
*/
|
|
10712
10991
|
async getAll(sql, parameters) {
|
|
@@ -10716,8 +10995,8 @@ SELECT * FROM crud_entries;
|
|
|
10716
10995
|
/**
|
|
10717
10996
|
* Execute a read-only query and return the first result, or null if the ResultSet is empty.
|
|
10718
10997
|
*
|
|
10719
|
-
* @param sql The SQL query to execute
|
|
10720
|
-
* @param parameters Optional array of parameters to bind to the query
|
|
10998
|
+
* @param sql - The SQL query to execute
|
|
10999
|
+
* @param parameters - Optional array of parameters to bind to the query
|
|
10721
11000
|
* @returns The first result if found, or null if no results are returned
|
|
10722
11001
|
*/
|
|
10723
11002
|
async getOptional(sql, parameters) {
|
|
@@ -10727,8 +11006,8 @@ SELECT * FROM crud_entries;
|
|
|
10727
11006
|
/**
|
|
10728
11007
|
* Execute a read-only query and return the first result, error if the ResultSet is empty.
|
|
10729
11008
|
*
|
|
10730
|
-
* @param sql The SQL query to execute
|
|
10731
|
-
* @param parameters Optional array of parameters to bind to the query
|
|
11009
|
+
* @param sql - The SQL query to execute
|
|
11010
|
+
* @param parameters - Optional array of parameters to bind to the query
|
|
10732
11011
|
* @returns The first result matching the query
|
|
10733
11012
|
* @throws Error if no rows are returned
|
|
10734
11013
|
*/
|
|
@@ -10738,7 +11017,7 @@ SELECT * FROM crud_entries;
|
|
|
10738
11017
|
}
|
|
10739
11018
|
/**
|
|
10740
11019
|
* Takes a read lock, without starting a transaction.
|
|
10741
|
-
* In most cases, {@link readTransaction} should be used instead.
|
|
11020
|
+
* In most cases, {@link AbstractPowerSyncDatabase.readTransaction} should be used instead.
|
|
10742
11021
|
*/
|
|
10743
11022
|
async readLock(callback) {
|
|
10744
11023
|
await this.waitForReady();
|
|
@@ -10746,7 +11025,7 @@ SELECT * FROM crud_entries;
|
|
|
10746
11025
|
}
|
|
10747
11026
|
/**
|
|
10748
11027
|
* Takes a global lock, without starting a transaction.
|
|
10749
|
-
* In most cases, {@link writeTransaction} should be used instead.
|
|
11028
|
+
* In most cases, {@link AbstractPowerSyncDatabase.writeTransaction} should be used instead.
|
|
10750
11029
|
*/
|
|
10751
11030
|
async writeLock(callback) {
|
|
10752
11031
|
await this.waitForReady();
|
|
@@ -10757,8 +11036,8 @@ SELECT * FROM crud_entries;
|
|
|
10757
11036
|
* Read transactions can run concurrently to a write transaction.
|
|
10758
11037
|
* Changes from any write transaction are not visible to read transactions started before it.
|
|
10759
11038
|
*
|
|
10760
|
-
* @param callback Function to execute within the transaction
|
|
10761
|
-
* @param lockTimeout Time in milliseconds to wait for a lock before throwing an error
|
|
11039
|
+
* @param callback - Function to execute within the transaction
|
|
11040
|
+
* @param lockTimeout - Time in milliseconds to wait for a lock before throwing an error
|
|
10762
11041
|
* @returns The result of the callback
|
|
10763
11042
|
* @throws Error if the lock cannot be obtained within the timeout period
|
|
10764
11043
|
*/
|
|
@@ -10775,8 +11054,8 @@ SELECT * FROM crud_entries;
|
|
|
10775
11054
|
* This takes a global lock - only one write transaction can execute against the database at a time.
|
|
10776
11055
|
* Statements within the transaction must be done on the provided {@link Transaction} interface.
|
|
10777
11056
|
*
|
|
10778
|
-
* @param callback Function to execute within the transaction
|
|
10779
|
-
* @param lockTimeout Time in milliseconds to wait for a lock before throwing an error
|
|
11057
|
+
* @param callback - Function to execute within the transaction
|
|
11058
|
+
* @param lockTimeout - Time in milliseconds to wait for a lock before throwing an error
|
|
10780
11059
|
* @returns The result of the callback
|
|
10781
11060
|
* @throws Error if the lock cannot be obtained within the timeout period
|
|
10782
11061
|
*/
|
|
@@ -10853,15 +11132,15 @@ SELECT * FROM crud_entries;
|
|
|
10853
11132
|
}
|
|
10854
11133
|
/**
|
|
10855
11134
|
* Execute a read query every time the source tables are modified.
|
|
10856
|
-
* Use {@link
|
|
11135
|
+
* Use {@link SQLOnChangeOptions.throttleMs} to specify the minimum interval between queries.
|
|
10857
11136
|
* Source tables are automatically detected using `EXPLAIN QUERY PLAN`.
|
|
10858
11137
|
*
|
|
10859
11138
|
* Note that the `onChange` callback member of the handler is required.
|
|
10860
11139
|
*
|
|
10861
|
-
* @param sql The SQL query to execute
|
|
10862
|
-
* @param parameters Optional array of parameters to bind to the query
|
|
10863
|
-
* @param handler Callbacks for handling results and errors
|
|
10864
|
-
* @param options Options for configuring watch behavior
|
|
11140
|
+
* @param sql - The SQL query to execute
|
|
11141
|
+
* @param parameters - Optional array of parameters to bind to the query
|
|
11142
|
+
* @param handler - Callbacks for handling results and errors
|
|
11143
|
+
* @param options - Options for configuring watch behavior
|
|
10865
11144
|
*/
|
|
10866
11145
|
watchWithCallback(sql, parameters, handler, options) {
|
|
10867
11146
|
const { onResult, onError = (e) => this.logger.error(e) } = handler ?? {};
|
|
@@ -10874,7 +11153,7 @@ SELECT * FROM crud_entries;
|
|
|
10874
11153
|
const watchedQuery = new OnChangeQueryProcessor({
|
|
10875
11154
|
db: this,
|
|
10876
11155
|
comparator,
|
|
10877
|
-
placeholderData: null,
|
|
11156
|
+
placeholderData: null, // FIXME
|
|
10878
11157
|
watchOptions: {
|
|
10879
11158
|
query: {
|
|
10880
11159
|
compile: () => ({
|
|
@@ -10907,38 +11186,35 @@ SELECT * FROM crud_entries;
|
|
|
10907
11186
|
}
|
|
10908
11187
|
/**
|
|
10909
11188
|
* Execute a read query every time the source tables are modified.
|
|
10910
|
-
* Use {@link
|
|
11189
|
+
* Use {@link SQLOnChangeOptions.throttleMs} to specify the minimum interval between queries.
|
|
10911
11190
|
* Source tables are automatically detected using `EXPLAIN QUERY PLAN`.
|
|
10912
11191
|
*
|
|
10913
|
-
* @param sql The SQL query to execute
|
|
10914
|
-
* @param parameters Optional array of parameters to bind to the query
|
|
10915
|
-
* @param options Options for configuring watch behavior
|
|
11192
|
+
* @param sql - The SQL query to execute
|
|
11193
|
+
* @param parameters - Optional array of parameters to bind to the query
|
|
11194
|
+
* @param options - Options for configuring watch behavior
|
|
10916
11195
|
* @returns An AsyncIterable that yields QueryResults whenever the data changes
|
|
10917
11196
|
*/
|
|
10918
11197
|
watchWithAsyncGenerator(sql, parameters, options) {
|
|
10919
|
-
return
|
|
11198
|
+
return EventQueue.queueBasedAsyncIterable((queue, abort) => {
|
|
10920
11199
|
const handler = {
|
|
10921
11200
|
onResult: (result) => {
|
|
10922
|
-
|
|
11201
|
+
queue.notify(result);
|
|
10923
11202
|
},
|
|
10924
11203
|
onError: (error) => {
|
|
10925
|
-
|
|
11204
|
+
queue.notifyError(error);
|
|
10926
11205
|
}
|
|
10927
11206
|
};
|
|
10928
|
-
this.watchWithCallback(sql, parameters, handler, options);
|
|
10929
|
-
|
|
10930
|
-
eventOptions.stop();
|
|
10931
|
-
});
|
|
10932
|
-
});
|
|
11207
|
+
this.watchWithCallback(sql, parameters, handler, { ...options, signal: abort });
|
|
11208
|
+
}, options?.signal);
|
|
10933
11209
|
}
|
|
10934
11210
|
/**
|
|
10935
11211
|
* Resolves the list of tables that are used in a SQL query.
|
|
10936
11212
|
* If tables are specified in the options, those are used directly.
|
|
10937
11213
|
* Otherwise, analyzes the query using EXPLAIN to determine which tables are accessed.
|
|
10938
11214
|
*
|
|
10939
|
-
* @param sql The SQL query to analyze
|
|
10940
|
-
* @param parameters Optional parameters for the SQL query
|
|
10941
|
-
* @param options Optional watch options that may contain explicit table list
|
|
11215
|
+
* @param sql - The SQL query to analyze
|
|
11216
|
+
* @param parameters - Optional parameters for the SQL query
|
|
11217
|
+
* @param options - Optional watch options that may contain explicit table list
|
|
10942
11218
|
* @returns Array of table names that the query depends on
|
|
10943
11219
|
*/
|
|
10944
11220
|
async resolveTables(sql, parameters, options) {
|
|
@@ -10967,13 +11243,13 @@ SELECT * FROM crud_entries;
|
|
|
10967
11243
|
/**
|
|
10968
11244
|
* Invoke the provided callback on any changes to any of the specified tables.
|
|
10969
11245
|
*
|
|
10970
|
-
* This is preferred over {@link watchWithCallback} when multiple queries need to be performed
|
|
11246
|
+
* This is preferred over {@link AbstractPowerSyncDatabase.watchWithCallback} when multiple queries need to be performed
|
|
10971
11247
|
* together when data is changed.
|
|
10972
11248
|
*
|
|
10973
11249
|
* Note that the `onChange` callback member of the handler is required.
|
|
10974
11250
|
*
|
|
10975
|
-
* @param handler Callbacks for handling change events and errors
|
|
10976
|
-
* @param options Options for configuring watch behavior
|
|
11251
|
+
* @param handler - Callbacks for handling change events and errors
|
|
11252
|
+
* @param options - Options for configuring watch behavior
|
|
10977
11253
|
* @returns A dispose function to stop watching for changes
|
|
10978
11254
|
*/
|
|
10979
11255
|
onChangeWithCallback(handler, options) {
|
|
@@ -11016,31 +11292,26 @@ SELECT * FROM crud_entries;
|
|
|
11016
11292
|
/**
|
|
11017
11293
|
* Create a Stream of changes to any of the specified tables.
|
|
11018
11294
|
*
|
|
11019
|
-
* This is preferred over {@link watchWithAsyncGenerator} when multiple queries need to be
|
|
11020
|
-
* together when data is changed.
|
|
11021
|
-
*
|
|
11022
|
-
* Note: do not declare this as `async *onChange` as it will not work in React Native.
|
|
11295
|
+
* This is preferred over {@link AbstractPowerSyncDatabase.watchWithAsyncGenerator} when multiple queries need to be
|
|
11296
|
+
* performed together when data is changed.
|
|
11023
11297
|
*
|
|
11024
|
-
* @param options Options for configuring watch behavior
|
|
11298
|
+
* @param options - Options for configuring watch behavior
|
|
11025
11299
|
* @returns An AsyncIterable that yields change events whenever the specified tables change
|
|
11026
11300
|
*/
|
|
11301
|
+
// Note: do not declare this as `async *onChange` as it will not work in React Native.
|
|
11027
11302
|
onChangeWithAsyncGenerator(options) {
|
|
11028
|
-
|
|
11029
|
-
|
|
11030
|
-
const dispose = this.onChangeWithCallback({
|
|
11303
|
+
return EventQueue.queueBasedAsyncIterable((queue, abort) => {
|
|
11304
|
+
this.onChangeWithCallback({
|
|
11031
11305
|
onChange: (event) => {
|
|
11032
|
-
|
|
11306
|
+
queue.notify(event);
|
|
11033
11307
|
},
|
|
11034
11308
|
onError: (error) => {
|
|
11035
|
-
|
|
11309
|
+
queue.notifyError(error);
|
|
11036
11310
|
}
|
|
11037
|
-
}, options);
|
|
11038
|
-
|
|
11039
|
-
|
|
11040
|
-
|
|
11041
|
-
});
|
|
11042
|
-
return () => dispose();
|
|
11043
|
-
});
|
|
11311
|
+
}, { ...options, signal: abort });
|
|
11312
|
+
// Note: We don't have to track the dispose function returned by onChangeWithCallback, it cleans up
|
|
11313
|
+
// after the abort signal completes.
|
|
11314
|
+
}, options?.signal);
|
|
11044
11315
|
}
|
|
11045
11316
|
handleTableChanges(changedTables, watchedTables, onDetectedChanges) {
|
|
11046
11317
|
if (changedTables.size > 0) {
|
|
@@ -11059,15 +11330,15 @@ SELECT * FROM crud_entries;
|
|
|
11059
11330
|
changedTables.add(table);
|
|
11060
11331
|
}
|
|
11061
11332
|
}
|
|
11062
|
-
/**
|
|
11063
|
-
* @ignore
|
|
11064
|
-
*/
|
|
11065
11333
|
async executeReadOnly(sql, params) {
|
|
11066
11334
|
await this.waitForReady();
|
|
11067
11335
|
return this.database.readLock((tx) => tx.execute(sql, params));
|
|
11068
11336
|
}
|
|
11069
11337
|
}
|
|
11070
11338
|
|
|
11339
|
+
/**
|
|
11340
|
+
* @internal
|
|
11341
|
+
*/
|
|
11071
11342
|
class AbstractPowerSyncDatabaseOpenFactory {
|
|
11072
11343
|
options;
|
|
11073
11344
|
constructor(options) {
|
|
@@ -11092,6 +11363,9 @@ class AbstractPowerSyncDatabaseOpenFactory {
|
|
|
11092
11363
|
}
|
|
11093
11364
|
}
|
|
11094
11365
|
|
|
11366
|
+
/**
|
|
11367
|
+
* @internal
|
|
11368
|
+
*/
|
|
11095
11369
|
function runOnSchemaChange(callback, db, options) {
|
|
11096
11370
|
const triggerWatchedQuery = () => {
|
|
11097
11371
|
const abortController = new AbortController();
|
|
@@ -11116,6 +11390,9 @@ function runOnSchemaChange(callback, db, options) {
|
|
|
11116
11390
|
triggerWatchedQuery();
|
|
11117
11391
|
}
|
|
11118
11392
|
|
|
11393
|
+
/**
|
|
11394
|
+
* @public
|
|
11395
|
+
*/
|
|
11119
11396
|
function compilableQueryWatch(db, query, handler, options) {
|
|
11120
11397
|
const { onResult, onError = (e) => { } } = handler ?? {};
|
|
11121
11398
|
if (!onResult) {
|
|
@@ -11153,8 +11430,14 @@ function compilableQueryWatch(db, query, handler, options) {
|
|
|
11153
11430
|
runOnSchemaChange(watchQuery, db, options);
|
|
11154
11431
|
}
|
|
11155
11432
|
|
|
11433
|
+
/**
|
|
11434
|
+
* @internal
|
|
11435
|
+
*/
|
|
11156
11436
|
const MAX_OP_ID = '9223372036854775807';
|
|
11157
11437
|
|
|
11438
|
+
/**
|
|
11439
|
+
* @internal
|
|
11440
|
+
*/
|
|
11158
11441
|
class SqliteBucketStorage extends BaseObserver {
|
|
11159
11442
|
db;
|
|
11160
11443
|
logger;
|
|
@@ -11315,6 +11598,8 @@ class SqliteBucketStorage extends BaseObserver {
|
|
|
11315
11598
|
* Thrown when an underlying database connection is closed.
|
|
11316
11599
|
* This is particularly relevant when worker connections are marked as closed while
|
|
11317
11600
|
* operations are still in progress.
|
|
11601
|
+
*
|
|
11602
|
+
* @internal
|
|
11318
11603
|
*/
|
|
11319
11604
|
class ConnectionClosedError extends Error {
|
|
11320
11605
|
static NAME = 'ConnectionClosedError';
|
|
@@ -11334,6 +11619,8 @@ class ConnectionClosedError extends Error {
|
|
|
11334
11619
|
|
|
11335
11620
|
/**
|
|
11336
11621
|
* A schema is a collection of tables. It is used to define the structure of a database.
|
|
11622
|
+
*
|
|
11623
|
+
* @public
|
|
11337
11624
|
*/
|
|
11338
11625
|
class Schema {
|
|
11339
11626
|
/*
|
|
@@ -11370,7 +11657,7 @@ class Schema {
|
|
|
11370
11657
|
* Since raw tables are not backed by JSON, running complex queries on them may be more efficient. Further, they allow
|
|
11371
11658
|
* using client-side table and column constraints.
|
|
11372
11659
|
*
|
|
11373
|
-
* @param tables An object of (table name, raw table definition) entries.
|
|
11660
|
+
* @param tables - An object of (table name, raw table definition) entries.
|
|
11374
11661
|
*/
|
|
11375
11662
|
withRawTables(tables) {
|
|
11376
11663
|
for (const [name, rawTableDefinition] of Object.entries(tables)) {
|
|
@@ -11416,6 +11703,8 @@ class Schema {
|
|
|
11416
11703
|
Generate a new table from the columns and indexes
|
|
11417
11704
|
@deprecated You should use {@link Table} instead as it now allows TableV2 syntax.
|
|
11418
11705
|
This will be removed in the next major release.
|
|
11706
|
+
|
|
11707
|
+
@public
|
|
11419
11708
|
*/
|
|
11420
11709
|
class TableV2 extends Table {
|
|
11421
11710
|
}
|
|
@@ -11426,6 +11715,8 @@ function sanitizeString(input) {
|
|
|
11426
11715
|
/**
|
|
11427
11716
|
* Helper function for sanitizing UUID input strings.
|
|
11428
11717
|
* Typically used with {@link sanitizeSQL}.
|
|
11718
|
+
*
|
|
11719
|
+
* @alpha
|
|
11429
11720
|
*/
|
|
11430
11721
|
function sanitizeUUID(uuid) {
|
|
11431
11722
|
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;
|
|
@@ -11462,6 +11753,8 @@ function sanitizeUUID(uuid) {
|
|
|
11462
11753
|
* // Incorrect:
|
|
11463
11754
|
* sanitizeSQL`New.id = '${myID}'` // Produces double quotes: New.id = ''O''Reilly''
|
|
11464
11755
|
* ```
|
|
11756
|
+
*
|
|
11757
|
+
* @alpha
|
|
11465
11758
|
*/
|
|
11466
11759
|
function sanitizeSQL(strings, ...values) {
|
|
11467
11760
|
let result = '';
|
|
@@ -11491,6 +11784,8 @@ function sanitizeSQL(strings, ...values) {
|
|
|
11491
11784
|
|
|
11492
11785
|
/**
|
|
11493
11786
|
* Performs a {@link AbstractPowerSyncDatabase.getAll} operation for a watched query.
|
|
11787
|
+
*
|
|
11788
|
+
* @public
|
|
11494
11789
|
*/
|
|
11495
11790
|
class GetAllQuery {
|
|
11496
11791
|
options;
|
|
@@ -11515,6 +11810,9 @@ class GetAllQuery {
|
|
|
11515
11810
|
}
|
|
11516
11811
|
|
|
11517
11812
|
const TypedLogger = Logger;
|
|
11813
|
+
/**
|
|
11814
|
+
* @public
|
|
11815
|
+
*/
|
|
11518
11816
|
const LogLevel = {
|
|
11519
11817
|
TRACE: TypedLogger.TRACE,
|
|
11520
11818
|
DEBUG: TypedLogger.DEBUG,
|
|
@@ -11531,6 +11829,7 @@ const LogLevel = {
|
|
|
11531
11829
|
* across all loggers created with `createLogger`. Adjusting settings on this
|
|
11532
11830
|
* base logger affects all loggers derived from it unless explicitly overridden.
|
|
11533
11831
|
*
|
|
11832
|
+
* @public
|
|
11534
11833
|
*/
|
|
11535
11834
|
function createBaseLogger() {
|
|
11536
11835
|
return Logger;
|
|
@@ -11541,6 +11840,8 @@ function createBaseLogger() {
|
|
|
11541
11840
|
* Named loggers allow specific modules or areas of your application to have
|
|
11542
11841
|
* their own logging levels and behaviors. These loggers inherit configuration
|
|
11543
11842
|
* from the base logger by default but can override settings independently.
|
|
11843
|
+
*
|
|
11844
|
+
* @public
|
|
11544
11845
|
*/
|
|
11545
11846
|
function createLogger(name, options = {}) {
|
|
11546
11847
|
const logger = Logger.get(name);
|
|
@@ -11550,6 +11851,9 @@ function createLogger(name, options = {}) {
|
|
|
11550
11851
|
return logger;
|
|
11551
11852
|
}
|
|
11552
11853
|
|
|
11854
|
+
/**
|
|
11855
|
+
* @internal
|
|
11856
|
+
*/
|
|
11553
11857
|
const parseQuery = (query, parameters) => {
|
|
11554
11858
|
let sqlStatement;
|
|
11555
11859
|
if (typeof query == 'string') {
|