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