@powersync/web 0.0.0-dev-20240723112746 → 0.0.0-dev-20240726145618
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/README.md +25 -1
- package/lib/src/db/PowerSyncDatabase.d.ts +2 -2
- package/lib/src/db/PowerSyncDatabase.js +28 -32
- package/lib/src/db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.js +1 -7
- package/lib/src/db/adapters/AbstractWebSQLOpenFactory.js +0 -2
- package/lib/src/db/adapters/SSRDBAdapter.js +48 -28
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.d.ts +1 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.js +136 -100
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +1 -4
- package/lib/src/db/adapters/web-sql-flags.js +3 -6
- package/lib/src/db/sync/SSRWebStreamingSyncImplementation.js +0 -2
- package/lib/src/db/sync/SharedWebStreamingSyncImplementation.js +95 -66
- package/lib/src/db/sync/WebRemote.d.ts +1 -5
- package/lib/src/db/sync/WebRemote.js +21 -29
- package/lib/src/shared/open-db.js +184 -153
- package/lib/src/worker/db/SharedWASQLiteDB.worker.js +23 -15
- package/lib/src/worker/db/WASQLiteDB.worker.js +10 -1
- package/lib/src/worker/sync/BroadcastLogger.js +19 -16
- package/lib/src/worker/sync/SharedSyncImplementation.js +115 -96
- package/lib/src/worker/sync/SharedSyncImplementation.worker.js +5 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -13
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
1
10
|
import * as Comlink from 'comlink';
|
|
2
11
|
import Logger from 'js-logger';
|
|
3
12
|
import { BaseObserver, SqliteBucketStorage, SyncStatus, AbortOperation } from '@powersync/common';
|
|
@@ -21,14 +30,6 @@ export var SharedSyncClientEvent;
|
|
|
21
30
|
* Shared sync implementation which runs inside a shared webworker
|
|
22
31
|
*/
|
|
23
32
|
export class SharedSyncImplementation extends BaseObserver {
|
|
24
|
-
ports;
|
|
25
|
-
syncStreamClient;
|
|
26
|
-
isInitialized;
|
|
27
|
-
statusListener;
|
|
28
|
-
fetchCredentialsController;
|
|
29
|
-
uploadDataController;
|
|
30
|
-
syncStatus;
|
|
31
|
-
broadCastLogger;
|
|
32
33
|
constructor() {
|
|
33
34
|
super();
|
|
34
35
|
this.ports = [];
|
|
@@ -36,104 +37,111 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
36
37
|
const callback = this.registerListener({
|
|
37
38
|
initialized: () => {
|
|
38
39
|
resolve();
|
|
39
|
-
callback
|
|
40
|
+
callback === null || callback === void 0 ? void 0 : callback();
|
|
40
41
|
}
|
|
41
42
|
});
|
|
42
43
|
});
|
|
43
44
|
this.syncStatus = new SyncStatus({});
|
|
44
45
|
this.broadCastLogger = new BroadcastLogger(this.ports);
|
|
45
46
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
waitForStatus(status) {
|
|
48
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
yield this.waitForReady();
|
|
50
|
+
return this.syncStreamClient.waitForStatus(status);
|
|
51
|
+
});
|
|
49
52
|
}
|
|
50
53
|
get lastSyncedAt() {
|
|
51
|
-
|
|
54
|
+
var _a;
|
|
55
|
+
return (_a = this.syncStreamClient) === null || _a === void 0 ? void 0 : _a.lastSyncedAt;
|
|
52
56
|
}
|
|
53
57
|
get isConnected() {
|
|
54
|
-
|
|
58
|
+
var _a, _b;
|
|
59
|
+
return (_b = (_a = this.syncStreamClient) === null || _a === void 0 ? void 0 : _a.isConnected) !== null && _b !== void 0 ? _b : false;
|
|
55
60
|
}
|
|
56
|
-
|
|
57
|
-
return this
|
|
61
|
+
waitForReady() {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
return this.isInitialized;
|
|
64
|
+
});
|
|
58
65
|
}
|
|
59
66
|
/**
|
|
60
67
|
* Configures the DBAdapter connection and a streaming sync client.
|
|
61
68
|
*/
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
69
|
+
init(dbWorkerPort, params) {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
var _a, _b;
|
|
72
|
+
if (this.syncStreamClient) {
|
|
73
|
+
// Cannot modify already existing sync implementation
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const logger = ((_b = (_a = params.streamOptions) === null || _a === void 0 ? void 0 : _a.flags) === null || _b === void 0 ? void 0 : _b.broadcastLogs) ? this.broadCastLogger : Logger.get('shared-sync');
|
|
77
|
+
self.onerror = (event) => {
|
|
78
|
+
// Share any uncaught events on the broadcast logger
|
|
79
|
+
logger.error('Uncaught exception in PowerSync shared sync worker', event);
|
|
80
|
+
};
|
|
81
|
+
this.syncStreamClient = new WebStreamingSyncImplementation(Object.assign(Object.assign({ adapter: new SqliteBucketStorage(new WASQLiteDBAdapter({
|
|
82
|
+
dbFilename: params.dbName,
|
|
83
|
+
workerPort: dbWorkerPort,
|
|
84
|
+
flags: { enableMultiTabs: true, useWebWorker: true },
|
|
85
|
+
logger
|
|
86
|
+
}), new Mutex(), logger), remote: new WebRemote({
|
|
87
|
+
fetchCredentials: () => __awaiter(this, void 0, void 0, function* () {
|
|
88
|
+
const lastPort = this.ports[this.ports.length - 1];
|
|
89
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
90
|
+
const abortController = new AbortController();
|
|
91
|
+
this.fetchCredentialsController = {
|
|
92
|
+
controller: abortController,
|
|
93
|
+
activePort: lastPort
|
|
94
|
+
};
|
|
95
|
+
abortController.signal.onabort = reject;
|
|
96
|
+
try {
|
|
97
|
+
resolve(yield lastPort.clientProvider.fetchCredentials());
|
|
98
|
+
}
|
|
99
|
+
catch (ex) {
|
|
100
|
+
reject(ex);
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
this.fetchCredentialsController = undefined;
|
|
104
|
+
}
|
|
105
|
+
}));
|
|
106
|
+
})
|
|
107
|
+
}), uploadCrud: () => __awaiter(this, void 0, void 0, function* () {
|
|
81
108
|
const lastPort = this.ports[this.ports.length - 1];
|
|
82
|
-
return new Promise(
|
|
109
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
83
110
|
const abortController = new AbortController();
|
|
84
|
-
this.
|
|
111
|
+
this.uploadDataController = {
|
|
85
112
|
controller: abortController,
|
|
86
113
|
activePort: lastPort
|
|
87
114
|
};
|
|
88
|
-
|
|
115
|
+
// Resolving will make it retry
|
|
116
|
+
abortController.signal.onabort = () => resolve();
|
|
89
117
|
try {
|
|
90
|
-
resolve(
|
|
118
|
+
resolve(yield lastPort.clientProvider.uploadCrud());
|
|
91
119
|
}
|
|
92
120
|
catch (ex) {
|
|
93
121
|
reject(ex);
|
|
94
122
|
}
|
|
95
123
|
finally {
|
|
96
|
-
this.
|
|
124
|
+
this.uploadDataController = undefined;
|
|
97
125
|
}
|
|
98
|
-
});
|
|
126
|
+
}));
|
|
127
|
+
}) }, params.streamOptions), {
|
|
128
|
+
// Logger cannot be transferred just yet
|
|
129
|
+
logger }));
|
|
130
|
+
this.syncStreamClient.registerListener({
|
|
131
|
+
statusChanged: (status) => {
|
|
132
|
+
this.updateAllStatuses(status.toJSON());
|
|
99
133
|
}
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
const lastPort = this.ports[this.ports.length - 1];
|
|
103
|
-
return new Promise(async (resolve, reject) => {
|
|
104
|
-
const abortController = new AbortController();
|
|
105
|
-
this.uploadDataController = {
|
|
106
|
-
controller: abortController,
|
|
107
|
-
activePort: lastPort
|
|
108
|
-
};
|
|
109
|
-
// Resolving will make it retry
|
|
110
|
-
abortController.signal.onabort = () => resolve();
|
|
111
|
-
try {
|
|
112
|
-
resolve(await lastPort.clientProvider.uploadCrud());
|
|
113
|
-
}
|
|
114
|
-
catch (ex) {
|
|
115
|
-
reject(ex);
|
|
116
|
-
}
|
|
117
|
-
finally {
|
|
118
|
-
this.uploadDataController = undefined;
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
},
|
|
122
|
-
...params.streamOptions,
|
|
123
|
-
// Logger cannot be transferred just yet
|
|
124
|
-
logger
|
|
125
|
-
});
|
|
126
|
-
this.syncStreamClient.registerListener({
|
|
127
|
-
statusChanged: (status) => {
|
|
128
|
-
this.updateAllStatuses(status.toJSON());
|
|
129
|
-
}
|
|
134
|
+
});
|
|
135
|
+
this.iterateListeners((l) => { var _a; return (_a = l.initialized) === null || _a === void 0 ? void 0 : _a.call(l); });
|
|
130
136
|
});
|
|
131
|
-
this.iterateListeners((l) => l.initialized?.());
|
|
132
137
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
138
|
+
dispose() {
|
|
139
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
140
|
+
var _a, _b;
|
|
141
|
+
yield this.waitForReady();
|
|
142
|
+
(_a = this.statusListener) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
143
|
+
return (_b = this.syncStreamClient) === null || _b === void 0 ? void 0 : _b.dispose();
|
|
144
|
+
});
|
|
137
145
|
}
|
|
138
146
|
/**
|
|
139
147
|
* Connects to the PowerSync backend instance.
|
|
@@ -141,27 +149,32 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
141
149
|
* The connection will simply be reconnected whenever a new tab
|
|
142
150
|
* connects.
|
|
143
151
|
*/
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
152
|
+
connect(options) {
|
|
153
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
154
|
+
yield this.waitForReady();
|
|
155
|
+
// This effectively queues connect and disconnect calls. Ensuring multiple tabs' requests are synchronized
|
|
156
|
+
return navigator.locks.request('shared-sync-connect', () => { var _a; return (_a = this.syncStreamClient) === null || _a === void 0 ? void 0 : _a.connect(options); });
|
|
157
|
+
});
|
|
148
158
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
159
|
+
disconnect() {
|
|
160
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
161
|
+
yield this.waitForReady();
|
|
162
|
+
// This effectively queues connect and disconnect calls. Ensuring multiple tabs' requests are synchronized
|
|
163
|
+
return navigator.locks.request('shared-sync-connect', () => { var _a; return (_a = this.syncStreamClient) === null || _a === void 0 ? void 0 : _a.disconnect(); });
|
|
164
|
+
});
|
|
153
165
|
}
|
|
154
166
|
/**
|
|
155
167
|
* Adds a new client tab's message port to the list of connected ports
|
|
156
168
|
*/
|
|
157
169
|
addPort(port) {
|
|
170
|
+
var _a;
|
|
158
171
|
const portProvider = {
|
|
159
172
|
port,
|
|
160
173
|
clientProvider: Comlink.wrap(port)
|
|
161
174
|
};
|
|
162
175
|
this.ports.push(portProvider);
|
|
163
176
|
// Give the newly connected client the latest status
|
|
164
|
-
const status = this.syncStreamClient
|
|
177
|
+
const status = (_a = this.syncStreamClient) === null || _a === void 0 ? void 0 : _a.syncStatus;
|
|
165
178
|
if (status) {
|
|
166
179
|
portProvider.clientProvider.statusChanged(status.toJSON());
|
|
167
180
|
}
|
|
@@ -185,25 +198,31 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
185
198
|
* not resolve. Abort them here.
|
|
186
199
|
*/
|
|
187
200
|
[this.fetchCredentialsController, this.uploadDataController].forEach((abortController) => {
|
|
188
|
-
if (abortController
|
|
201
|
+
if ((abortController === null || abortController === void 0 ? void 0 : abortController.activePort.port) == port) {
|
|
189
202
|
abortController.controller.abort(new AbortOperation('Closing pending requests after client port is removed'));
|
|
190
203
|
}
|
|
191
204
|
});
|
|
192
205
|
}
|
|
193
206
|
triggerCrudUpload() {
|
|
194
|
-
this.waitForReady().then(() => this.syncStreamClient
|
|
207
|
+
this.waitForReady().then(() => { var _a; return (_a = this.syncStreamClient) === null || _a === void 0 ? void 0 : _a.triggerCrudUpload(); });
|
|
195
208
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
209
|
+
obtainLock(lockOptions) {
|
|
210
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
211
|
+
yield this.waitForReady();
|
|
212
|
+
return this.syncStreamClient.obtainLock(lockOptions);
|
|
213
|
+
});
|
|
199
214
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
215
|
+
hasCompletedSync() {
|
|
216
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
217
|
+
yield this.waitForReady();
|
|
218
|
+
return this.syncStreamClient.hasCompletedSync();
|
|
219
|
+
});
|
|
203
220
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
221
|
+
getWriteCheckpoint() {
|
|
222
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
223
|
+
yield this.waitForReady();
|
|
224
|
+
return this.syncStreamClient.getWriteCheckpoint();
|
|
225
|
+
});
|
|
207
226
|
}
|
|
208
227
|
/**
|
|
209
228
|
* A method to update the all shared statuses for each
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import * as Comlink from 'comlink';
|
|
2
2
|
import { SharedSyncImplementation, SharedSyncClientEvent } from './SharedSyncImplementation';
|
|
3
3
|
import Logger from 'js-logger';
|
|
4
|
+
import { Buffer } from 'buffer';
|
|
5
|
+
if (typeof self.Buffer == 'undefined') {
|
|
6
|
+
self.Buffer = Buffer;
|
|
7
|
+
}
|
|
4
8
|
const _self = self;
|
|
5
9
|
Logger.useDefaults();
|
|
6
10
|
const sharedSyncImplementation = new SharedSyncImplementation();
|
|
@@ -12,7 +16,7 @@ _self.onconnect = function (event) {
|
|
|
12
16
|
*/
|
|
13
17
|
port.addEventListener('message', (event) => {
|
|
14
18
|
const payload = event.data;
|
|
15
|
-
if (payload
|
|
19
|
+
if ((payload === null || payload === void 0 ? void 0 : payload.event) == SharedSyncClientEvent.CLOSE_CLIENT) {
|
|
16
20
|
console.log('closing shared for port', port);
|
|
17
21
|
sharedSyncImplementation.removePort(port);
|
|
18
22
|
}
|