@powersync/web 1.38.5 → 1.38.6
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/worker/SharedSyncImplementation.umd.js +98 -38
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
- package/dist/worker/WASQLiteDB.umd.js +97 -37
- package/dist/worker/WASQLiteDB.umd.js.map +1 -1
- package/lib/package.json +2 -2
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -1641,6 +1641,7 @@ class WorkerClient {
|
|
|
1641
1641
|
__webpack_require__.r(__webpack_exports__);
|
|
1642
1642
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
1643
1643
|
/* harmony export */ ATTACHMENT_TABLE: () => (/* binding */ ATTACHMENT_TABLE),
|
|
1644
|
+
/* harmony export */ ATTACHMENT_TABLE_COLUMNS: () => (/* binding */ ATTACHMENT_TABLE_COLUMNS),
|
|
1644
1645
|
/* harmony export */ AbortOperation: () => (/* binding */ AbortOperation),
|
|
1645
1646
|
/* harmony export */ AbstractPowerSyncDatabase: () => (/* binding */ AbstractPowerSyncDatabase),
|
|
1646
1647
|
/* harmony export */ AbstractPowerSyncDatabaseOpenFactory: () => (/* binding */ AbstractPowerSyncDatabaseOpenFactory),
|
|
@@ -2122,6 +2123,19 @@ var AttachmentState;
|
|
|
2122
2123
|
AttachmentState[AttachmentState["SYNCED"] = 3] = "SYNCED";
|
|
2123
2124
|
AttachmentState[AttachmentState["ARCHIVED"] = 4] = "ARCHIVED"; // Attachment has been orphaned, i.e. the associated record has been deleted
|
|
2124
2125
|
})(AttachmentState || (AttachmentState = {}));
|
|
2126
|
+
/**
|
|
2127
|
+
* @alpha
|
|
2128
|
+
*/
|
|
2129
|
+
const ATTACHMENT_TABLE_COLUMNS = {
|
|
2130
|
+
filename: column.text,
|
|
2131
|
+
local_uri: column.text,
|
|
2132
|
+
timestamp: column.integer,
|
|
2133
|
+
size: column.integer,
|
|
2134
|
+
media_type: column.text,
|
|
2135
|
+
state: column.integer, // Corresponds to AttachmentState
|
|
2136
|
+
has_synced: column.integer,
|
|
2137
|
+
meta_data: column.text
|
|
2138
|
+
};
|
|
2125
2139
|
/**
|
|
2126
2140
|
* AttachmentTable defines the schema for the attachment queue table.
|
|
2127
2141
|
*
|
|
@@ -2129,16 +2143,7 @@ var AttachmentState;
|
|
|
2129
2143
|
*/
|
|
2130
2144
|
class AttachmentTable extends Table {
|
|
2131
2145
|
constructor(options) {
|
|
2132
|
-
super({
|
|
2133
|
-
filename: column.text,
|
|
2134
|
-
local_uri: column.text,
|
|
2135
|
-
timestamp: column.integer,
|
|
2136
|
-
size: column.integer,
|
|
2137
|
-
media_type: column.text,
|
|
2138
|
-
state: column.integer, // Corresponds to AttachmentState
|
|
2139
|
-
has_synced: column.integer,
|
|
2140
|
-
meta_data: column.text
|
|
2141
|
-
}, {
|
|
2146
|
+
super(ATTACHMENT_TABLE_COLUMNS, {
|
|
2142
2147
|
...options,
|
|
2143
2148
|
viewName: options?.viewName ?? ATTACHMENT_TABLE,
|
|
2144
2149
|
localOnly: true,
|
|
@@ -2670,31 +2675,51 @@ class SyncingService {
|
|
|
2670
2675
|
}
|
|
2671
2676
|
/**
|
|
2672
2677
|
* Processes attachments based on their state (upload, download, or delete).
|
|
2673
|
-
*
|
|
2678
|
+
*
|
|
2679
|
+
* Each attachment's I/O runs outside the attachment-service mutex, and the row's
|
|
2680
|
+
* state transition is persisted immediately after it completes. This keeps the
|
|
2681
|
+
* mutex available to concurrent `saveFile` / `deleteFile` / watched-attachment
|
|
2682
|
+
* processing while a batch is in flight, and means consumer queries against the
|
|
2683
|
+
* attachments queue see incremental progress instead of one atomic commit at the
|
|
2684
|
+
* end of the batch.
|
|
2674
2685
|
*
|
|
2675
2686
|
* @param attachments - Array of attachment records to process
|
|
2676
|
-
* @param
|
|
2677
|
-
*
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2687
|
+
* @param options - Optional controls. Pass `signal` (an `AbortSignal`) to interrupt
|
|
2688
|
+
* the batch: it is checked between attachments and, once aborted, the
|
|
2689
|
+
* loop exits early — letting `stopSync` stop a running batch within
|
|
2690
|
+
* one attachment's processing time.
|
|
2691
|
+
*/
|
|
2692
|
+
async processAttachments(attachments, options) {
|
|
2693
|
+
const signal = options?.signal;
|
|
2694
|
+
this.logger.info(`Starting processAttachments with ${attachments.length} attachments`);
|
|
2681
2695
|
for (const attachment of attachments) {
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2696
|
+
if (signal?.aborted) {
|
|
2697
|
+
this.logger.info('Sync cancelled; stopping iteration early');
|
|
2698
|
+
return;
|
|
2699
|
+
}
|
|
2700
|
+
try {
|
|
2701
|
+
let updated;
|
|
2702
|
+
switch (attachment.state) {
|
|
2703
|
+
case AttachmentState.QUEUED_UPLOAD:
|
|
2704
|
+
updated = await this.uploadAttachment(attachment);
|
|
2705
|
+
break;
|
|
2706
|
+
case AttachmentState.QUEUED_DOWNLOAD:
|
|
2707
|
+
updated = await this.downloadAttachment(attachment);
|
|
2708
|
+
break;
|
|
2709
|
+
case AttachmentState.QUEUED_DELETE:
|
|
2710
|
+
// `deleteAttachment` needs a context (it removes the row in a
|
|
2711
|
+
// transaction); briefly re-acquire the mutex for just this row.
|
|
2712
|
+
updated = await this.attachmentService.withContext((ctx) => this.deleteAttachment(attachment, ctx));
|
|
2713
|
+
break;
|
|
2714
|
+
default:
|
|
2715
|
+
continue;
|
|
2716
|
+
}
|
|
2717
|
+
await this.attachmentService.withContext((ctx) => ctx.saveAttachments([updated]));
|
|
2718
|
+
}
|
|
2719
|
+
catch (error) {
|
|
2720
|
+
this.logger.warn(`Error during sync for ${attachment.id}`, error);
|
|
2695
2721
|
}
|
|
2696
2722
|
}
|
|
2697
|
-
await context.saveAttachments(updatedAttachments);
|
|
2698
2723
|
}
|
|
2699
2724
|
/**
|
|
2700
2725
|
* Uploads an attachment from local storage to remote storage.
|
|
@@ -2865,6 +2890,19 @@ class AttachmentQueue {
|
|
|
2865
2890
|
statusListenerDispose;
|
|
2866
2891
|
watchActiveAttachments;
|
|
2867
2892
|
watchAttachmentsAbortController;
|
|
2893
|
+
/**
|
|
2894
|
+
* Serializes concurrent `syncStorage()` triggers (periodic timer, watch-onDiff,
|
|
2895
|
+
* status-changed). Held across the whole batch, but only contended by other
|
|
2896
|
+
* sync triggers — foreground `saveFile` / `deleteFile` / watched-attachment
|
|
2897
|
+
* processing don't take this lock and proceed in parallel via the
|
|
2898
|
+
* `AttachmentService` mutex, which is acquired only briefly per row.
|
|
2899
|
+
*/
|
|
2900
|
+
syncLoopMutex = new Mutex();
|
|
2901
|
+
/**
|
|
2902
|
+
* Aborted by `stopSync()` to interrupt an in-flight batch within one
|
|
2903
|
+
* attachment's processing time. Polled between rows by `SyncingService`.
|
|
2904
|
+
*/
|
|
2905
|
+
syncAbortController;
|
|
2868
2906
|
/**
|
|
2869
2907
|
* Creates a new AttachmentQueue instance.
|
|
2870
2908
|
*
|
|
@@ -2904,6 +2942,7 @@ class AttachmentQueue {
|
|
|
2904
2942
|
*/
|
|
2905
2943
|
async startSync() {
|
|
2906
2944
|
await this.stopSync();
|
|
2945
|
+
this.syncAbortController = new AbortController();
|
|
2907
2946
|
this.watchActiveAttachments = this.attachmentService.watchActiveAttachments({
|
|
2908
2947
|
throttleMs: this.syncThrottleDuration
|
|
2909
2948
|
});
|
|
@@ -3018,23 +3057,44 @@ class AttachmentQueue {
|
|
|
3018
3057
|
*
|
|
3019
3058
|
* This is called automatically at regular intervals when sync is started,
|
|
3020
3059
|
* but can also be called manually to trigger an immediate sync.
|
|
3060
|
+
*
|
|
3061
|
+
* Concurrent invocations are serialized via `syncLoopMutex`.
|
|
3021
3062
|
*/
|
|
3022
3063
|
async syncStorage() {
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
await this.
|
|
3028
|
-
|
|
3064
|
+
const signal = this.syncAbortController?.signal;
|
|
3065
|
+
if (signal?.aborted)
|
|
3066
|
+
return;
|
|
3067
|
+
try {
|
|
3068
|
+
await this.syncLoopMutex.runExclusive(async () => {
|
|
3069
|
+
const activeAttachments = await this.attachmentService.withContext((ctx) => ctx.getActiveAttachments());
|
|
3070
|
+
await this.localStorage.initialize();
|
|
3071
|
+
await this.syncingService.processAttachments(activeAttachments, { signal });
|
|
3072
|
+
if (signal?.aborted)
|
|
3073
|
+
return;
|
|
3074
|
+
await this.attachmentService.withContext((ctx) => this.syncingService.deleteArchivedAttachments(ctx));
|
|
3075
|
+
}, signal);
|
|
3076
|
+
}
|
|
3077
|
+
catch (error) {
|
|
3078
|
+
// A queued batch's acquire rejects when `stopSync` aborts — expected, not an error.
|
|
3079
|
+
if (signal?.aborted)
|
|
3080
|
+
return;
|
|
3081
|
+
throw error;
|
|
3082
|
+
}
|
|
3029
3083
|
}
|
|
3030
3084
|
/**
|
|
3031
3085
|
* Stops the attachment synchronization process.
|
|
3032
3086
|
*
|
|
3033
|
-
* Clears the periodic sync timer
|
|
3087
|
+
* Clears the periodic sync timer, closes all active attachment watchers, and
|
|
3088
|
+
* aborts any in-flight `syncStorage()` call so it exits within one
|
|
3089
|
+
* attachment's processing time instead of running the batch to completion.
|
|
3034
3090
|
*/
|
|
3035
3091
|
async stopSync() {
|
|
3036
3092
|
clearInterval(this.periodicSyncTimer);
|
|
3037
3093
|
this.periodicSyncTimer = undefined;
|
|
3094
|
+
if (this.syncAbortController) {
|
|
3095
|
+
this.syncAbortController.abort();
|
|
3096
|
+
this.syncAbortController = undefined;
|
|
3097
|
+
}
|
|
3038
3098
|
if (this.watchActiveAttachments)
|
|
3039
3099
|
await this.watchActiveAttachments.close();
|
|
3040
3100
|
if (this.watchAttachmentsAbortController) {
|
|
@@ -12649,7 +12709,7 @@ function requireDist () {
|
|
|
12649
12709
|
|
|
12650
12710
|
var distExports = requireDist();
|
|
12651
12711
|
|
|
12652
|
-
var version = "1.
|
|
12712
|
+
var version = "1.57.0";
|
|
12653
12713
|
var PACKAGE = {
|
|
12654
12714
|
version: version};
|
|
12655
12715
|
|