@powersync/web 1.36.0 → 1.37.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/index.umd.js +1127 -1235
- package/dist/index.umd.js.map +1 -1
- package/dist/worker/SharedSyncImplementation.umd.js +481 -3111
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
- package/dist/worker/WASQLiteDB.umd.js +688 -836
- package/dist/worker/WASQLiteDB.umd.js.map +1 -1
- package/lib/package.json +2 -3
- package/lib/src/db/PowerSyncDatabase.d.ts +1 -2
- package/lib/src/db/PowerSyncDatabase.js +3 -4
- package/lib/src/db/adapters/AsyncWebAdapter.d.ts +40 -0
- package/lib/src/db/adapters/AsyncWebAdapter.js +69 -0
- package/lib/src/db/adapters/SSRDBAdapter.d.ts +1 -2
- package/lib/src/db/adapters/SSRDBAdapter.js +5 -6
- package/lib/src/db/adapters/wa-sqlite/ConcurrentConnection.d.ts +56 -0
- package/lib/src/db/adapters/wa-sqlite/ConcurrentConnection.js +121 -0
- package/lib/src/db/adapters/wa-sqlite/DatabaseClient.d.ts +54 -0
- package/lib/src/db/adapters/wa-sqlite/DatabaseClient.js +227 -0
- package/lib/src/db/adapters/wa-sqlite/DatabaseServer.d.ts +47 -0
- package/lib/src/db/adapters/wa-sqlite/DatabaseServer.js +146 -0
- package/lib/src/db/adapters/wa-sqlite/RawSqliteConnection.d.ts +46 -0
- package/lib/src/db/adapters/wa-sqlite/RawSqliteConnection.js +147 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.d.ts +14 -6
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +66 -39
- package/lib/src/db/adapters/wa-sqlite/vfs.d.ts +61 -0
- package/lib/src/db/adapters/wa-sqlite/vfs.js +91 -0
- package/lib/src/db/adapters/web-sql-flags.d.ts +5 -0
- package/lib/src/db/sync/SSRWebStreamingSyncImplementation.d.ts +1 -2
- package/lib/src/db/sync/SSRWebStreamingSyncImplementation.js +2 -3
- package/lib/src/db/sync/SharedWebStreamingSyncImplementation.js +4 -19
- package/lib/src/index.d.ts +1 -4
- package/lib/src/index.js +1 -4
- package/lib/src/shared/tab_close_signal.d.ts +11 -0
- package/lib/src/shared/tab_close_signal.js +26 -0
- package/lib/src/worker/db/MultiDatabaseServer.d.ts +17 -0
- package/lib/src/worker/db/MultiDatabaseServer.js +86 -0
- package/lib/src/worker/db/WASQLiteDB.worker.js +9 -48
- package/lib/src/worker/db/open-worker-database.d.ts +3 -3
- package/lib/src/worker/db/open-worker-database.js +1 -1
- package/lib/src/worker/sync/SharedSyncImplementation.d.ts +5 -6
- package/lib/src/worker/sync/SharedSyncImplementation.js +92 -54
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -4
- package/src/db/PowerSyncDatabase.ts +3 -3
- package/src/db/adapters/AsyncWebAdapter.ts +91 -0
- package/src/db/adapters/SSRDBAdapter.ts +7 -7
- package/src/db/adapters/wa-sqlite/ConcurrentConnection.ts +137 -0
- package/src/db/adapters/wa-sqlite/DatabaseClient.ts +325 -0
- package/src/db/adapters/wa-sqlite/DatabaseServer.ts +201 -0
- package/src/db/adapters/wa-sqlite/RawSqliteConnection.ts +191 -0
- package/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.ts +87 -43
- package/src/db/adapters/wa-sqlite/vfs.ts +112 -0
- package/src/db/adapters/web-sql-flags.ts +6 -0
- package/src/db/sync/SSRWebStreamingSyncImplementation.ts +2 -3
- package/src/db/sync/SharedWebStreamingSyncImplementation.ts +4 -20
- package/src/index.ts +1 -4
- package/src/shared/tab_close_signal.ts +28 -0
- package/src/worker/db/MultiDatabaseServer.ts +104 -0
- package/src/worker/db/WASQLiteDB.worker.ts +10 -57
- package/src/worker/db/open-worker-database.ts +3 -3
- package/src/worker/sync/SharedSyncImplementation.ts +118 -58
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-89f0ba.index.umd.js +0 -1881
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-89f0ba.index.umd.js.map +0 -1
- package/dist/_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapps_wa-sqlite_src_example-97ebe9.index.umd.js +0 -555
- package/dist/_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapps_wa-sqlite_src_example-97ebe9.index.umd.js.map +0 -1
- package/lib/src/db/adapters/AbstractWebSQLOpenFactory.d.ts +0 -17
- package/lib/src/db/adapters/AbstractWebSQLOpenFactory.js +0 -33
- package/lib/src/db/adapters/AsyncDatabaseConnection.d.ts +0 -49
- package/lib/src/db/adapters/AsyncDatabaseConnection.js +0 -1
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.d.ts +0 -109
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.js +0 -404
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.d.ts +0 -59
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.js +0 -147
- package/lib/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.d.ts +0 -12
- package/lib/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.js +0 -19
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.d.ts +0 -155
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.js +0 -401
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.d.ts +0 -32
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.js +0 -49
- package/lib/src/worker/db/SharedWASQLiteConnection.d.ts +0 -42
- package/lib/src/worker/db/SharedWASQLiteConnection.js +0 -90
- package/lib/src/worker/db/WorkerWASQLiteConnection.d.ts +0 -9
- package/lib/src/worker/db/WorkerWASQLiteConnection.js +0 -12
- package/src/db/adapters/AbstractWebSQLOpenFactory.ts +0 -48
- package/src/db/adapters/AsyncDatabaseConnection.ts +0 -55
- package/src/db/adapters/LockedAsyncDatabaseAdapter.ts +0 -489
- package/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.ts +0 -201
- package/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.ts +0 -23
- package/src/db/adapters/wa-sqlite/WASQLiteConnection.ts +0 -497
- package/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.ts +0 -86
- package/src/worker/db/SharedWASQLiteConnection.ts +0 -131
- package/src/worker/db/WorkerWASQLiteConnection.ts +0 -14
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { AbortOperation, BaseObserver, ConnectionManager, SqliteBucketStorage, SyncStatus, createLogger } from '@powersync/common';
|
|
2
|
-
import { Mutex } from 'async-mutex';
|
|
1
|
+
import { AbortOperation, BaseObserver, ConnectionManager, DBAdapterDefaultMixin, SqliteBucketStorage, SyncStatus, createLogger, Mutex } from '@powersync/common';
|
|
3
2
|
import * as Comlink from 'comlink';
|
|
4
3
|
import { WebRemote } from '../../db/sync/WebRemote.js';
|
|
5
4
|
import { WebStreamingSyncImplementation } from '../../db/sync/WebStreamingSyncImplementation.js';
|
|
6
|
-
import { LockedAsyncDatabaseAdapter } from '../../db/adapters/LockedAsyncDatabaseAdapter.js';
|
|
7
|
-
import { WorkerWrappedAsyncDatabaseConnection } from '../../db/adapters/WorkerWrappedAsyncDatabaseConnection.js';
|
|
8
5
|
import { BroadcastLogger } from './BroadcastLogger.js';
|
|
6
|
+
import { DatabaseClient } from '../../db/adapters/wa-sqlite/DatabaseClient.js';
|
|
7
|
+
import { generateTabCloseSignal } from '../../shared/tab_close_signal.js';
|
|
9
8
|
/**
|
|
10
9
|
* @internal
|
|
11
10
|
* Manual message events for shared sync clients
|
|
@@ -43,7 +42,7 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
43
42
|
connectionManager;
|
|
44
43
|
syncStatus;
|
|
45
44
|
broadCastLogger;
|
|
46
|
-
|
|
45
|
+
database = this.generateReconnectableDatabase();
|
|
47
46
|
constructor() {
|
|
48
47
|
super();
|
|
49
48
|
this.ports = [];
|
|
@@ -59,8 +58,6 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
59
58
|
}
|
|
60
59
|
});
|
|
61
60
|
});
|
|
62
|
-
// Should be configured once we get params
|
|
63
|
-
this.distributedDB = null;
|
|
64
61
|
this.syncStatus = new SyncStatus({});
|
|
65
62
|
this.broadCastLogger = new BroadcastLogger(this.ports);
|
|
66
63
|
this.connectionManager = new ConnectionManager({
|
|
@@ -160,38 +157,8 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
160
157
|
if (params.streamOptions?.flags?.broadcastLogs) {
|
|
161
158
|
this.logger = this.broadCastLogger;
|
|
162
159
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
openConnection: async () => {
|
|
166
|
-
// Gets a connection from the clients when a new connection is requested.
|
|
167
|
-
const db = await this.openInternalDB();
|
|
168
|
-
db.registerListener({
|
|
169
|
-
closing: () => {
|
|
170
|
-
lockedAdapter.reOpenInternalDB();
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
|
-
return db;
|
|
174
|
-
},
|
|
175
|
-
logger: this.logger,
|
|
176
|
-
reOpenOnConnectionClosed: true
|
|
177
|
-
});
|
|
178
|
-
this.distributedDB = lockedAdapter;
|
|
179
|
-
await lockedAdapter.init();
|
|
180
|
-
lockedAdapter.registerListener({
|
|
181
|
-
databaseReOpened: () => {
|
|
182
|
-
// We may have missed some table updates while the database was closed.
|
|
183
|
-
// We can poke the crud in case we missed any updates.
|
|
184
|
-
this.connectionManager.syncStreamImplementation?.triggerCrudUpload();
|
|
185
|
-
/**
|
|
186
|
-
* FIXME or IMPROVE ME
|
|
187
|
-
* The Rust client implementation stores sync state on the connection level.
|
|
188
|
-
* Reopening the database causes a state machine error which should cause the
|
|
189
|
-
* StreamingSyncImplementation to reconnect. It would be nicer if we could trigger
|
|
190
|
-
* this reconnect earlier.
|
|
191
|
-
* This reconnect is not required for IndexedDB.
|
|
192
|
-
*/
|
|
193
|
-
}
|
|
194
|
-
});
|
|
160
|
+
// Ensure we have a usable database connection, the reconnectable database will connect lazily on first use.
|
|
161
|
+
await this.database.readLock(async () => { });
|
|
195
162
|
self.onerror = (event) => {
|
|
196
163
|
// Share any uncaught events on the broadcast logger
|
|
197
164
|
this.logger.error('Uncaught exception in PowerSync shared sync worker', event);
|
|
@@ -308,7 +275,7 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
308
275
|
const syncParams = this.syncParams;
|
|
309
276
|
// Create a new StreamingSyncImplementation for each connect call. This is usually done is all SDKs.
|
|
310
277
|
return new WebStreamingSyncImplementation({
|
|
311
|
-
adapter: new SqliteBucketStorage(this.
|
|
278
|
+
adapter: new SqliteBucketStorage(this.database, this.logger),
|
|
312
279
|
remote: new WebRemote({
|
|
313
280
|
invalidateCredentials: async () => {
|
|
314
281
|
const lastPort = await this.getLastWrappedPort();
|
|
@@ -379,9 +346,9 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
379
346
|
});
|
|
380
347
|
}
|
|
381
348
|
/**
|
|
382
|
-
*
|
|
349
|
+
* Requests a random client to share its database connection with us.
|
|
383
350
|
*/
|
|
384
|
-
async openInternalDB() {
|
|
351
|
+
async openInternalDB(handleClosed) {
|
|
385
352
|
const client = await this.getRandomWrappedPort();
|
|
386
353
|
if (!client) {
|
|
387
354
|
// Should not really happen in practice
|
|
@@ -417,6 +384,7 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
417
384
|
});
|
|
418
385
|
const remote = Comlink.wrap(workerPort);
|
|
419
386
|
const identifier = this.syncParams.dbParams.dbFilename;
|
|
387
|
+
const clientLockName = await generateTabCloseSignal();
|
|
420
388
|
/**
|
|
421
389
|
* The open could fail if the tab is closed while we're busy opening the database.
|
|
422
390
|
* This operation is typically executed inside an exclusive portMutex lock.
|
|
@@ -424,7 +392,16 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
424
392
|
* We can't rely on the closeListeners to abort the operation if the tab is closed.
|
|
425
393
|
*/
|
|
426
394
|
const db = await withAbort({
|
|
427
|
-
action: () =>
|
|
395
|
+
action: async () => {
|
|
396
|
+
const clientView = await remote.connectToExisting({ identifier, lockName: clientLockName });
|
|
397
|
+
return new DatabaseClient({
|
|
398
|
+
connection: clientView,
|
|
399
|
+
source: remote,
|
|
400
|
+
// It's possible for this worker to outlive the client hosting the database for us. We need to be prepared for
|
|
401
|
+
// that and ensure pending requests are aborted when the tab is closed.
|
|
402
|
+
remoteCanCloseUnexpectedly: true
|
|
403
|
+
}, this.syncParams.dbParams);
|
|
404
|
+
},
|
|
428
405
|
signal: abortController.signal,
|
|
429
406
|
cleanupOnAbort: (db) => {
|
|
430
407
|
db.close();
|
|
@@ -434,25 +411,86 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
434
411
|
removeCloseListener();
|
|
435
412
|
});
|
|
436
413
|
clearTimeout(timeout);
|
|
437
|
-
const wrapped = new WorkerWrappedAsyncDatabaseConnection({
|
|
438
|
-
remote,
|
|
439
|
-
baseConnection: db,
|
|
440
|
-
identifier,
|
|
441
|
-
// It's possible for this worker to outlive the client hosting the database for us. We need to be prepared for
|
|
442
|
-
// that and ensure pending requests are aborted when the tab is closed.
|
|
443
|
-
remoteCanCloseUnexpectedly: true
|
|
444
|
-
});
|
|
445
414
|
client.closeListeners.push(async () => {
|
|
446
415
|
this.logger.info('Aborting open connection because associated tab closed.');
|
|
416
|
+
handleClosed(db);
|
|
447
417
|
/**
|
|
448
418
|
* Don't await this close operation. It might never resolve if the tab is closed.
|
|
449
419
|
* We mark the remote as closed first, this will reject any pending requests.
|
|
450
420
|
* We then call close. The close operation is configured to fire-and-forget, the main promise will reject immediately.
|
|
451
421
|
*/
|
|
452
|
-
|
|
453
|
-
|
|
422
|
+
db.markRemoteClosed();
|
|
423
|
+
db.close().catch((ex) => this.logger.warn('error closing database connection', ex));
|
|
454
424
|
});
|
|
455
|
-
return
|
|
425
|
+
return db;
|
|
426
|
+
}
|
|
427
|
+
generateReconnectableDatabase() {
|
|
428
|
+
const syncParams = this.syncParams;
|
|
429
|
+
const sharedSync = this;
|
|
430
|
+
class ReconnectPool extends BaseObserver {
|
|
431
|
+
connectionState = null;
|
|
432
|
+
get name() {
|
|
433
|
+
return syncParams?.dbParams.dbFilename;
|
|
434
|
+
}
|
|
435
|
+
async connect() {
|
|
436
|
+
if (this.connectionState == null) {
|
|
437
|
+
const handleClosed = this.handleClientClosed.bind(this);
|
|
438
|
+
this.connectionState = (async () => {
|
|
439
|
+
try {
|
|
440
|
+
const db = await sharedSync.openInternalDB(handleClosed);
|
|
441
|
+
db.registerListener({
|
|
442
|
+
tablesUpdated: (notification) => {
|
|
443
|
+
this.iterateListeners((l) => l.tablesUpdated?.(notification));
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
this.connectionState = db;
|
|
447
|
+
return db;
|
|
448
|
+
}
|
|
449
|
+
catch (e) {
|
|
450
|
+
// Allow reconnecting when the database is used again.
|
|
451
|
+
this.connectionState = null;
|
|
452
|
+
throw e;
|
|
453
|
+
}
|
|
454
|
+
})();
|
|
455
|
+
}
|
|
456
|
+
return await this.connectionState;
|
|
457
|
+
}
|
|
458
|
+
async close() {
|
|
459
|
+
if (this.connectionState != null) {
|
|
460
|
+
await (await this.connectionState).close();
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
handleClientClosed(client) {
|
|
464
|
+
if (client === this.connectionState) {
|
|
465
|
+
this.connectionState = null;
|
|
466
|
+
// We may have missed some table updates while the database was closed.
|
|
467
|
+
// We can poke the crud in case we missed any updates.
|
|
468
|
+
const impl = sharedSync.connectionManager.syncStreamImplementation;
|
|
469
|
+
impl?.triggerCrudUpload();
|
|
470
|
+
/**
|
|
471
|
+
* FIXME or IMPROVE ME
|
|
472
|
+
* The Rust client implementation stores sync state on the connection level.
|
|
473
|
+
* Reopening the database causes a state machine error which should cause the
|
|
474
|
+
* StreamingSyncImplementation to reconnect. It would be nicer if we could trigger
|
|
475
|
+
* this reconnect earlier.
|
|
476
|
+
* This reconnect is not required for IndexedDB.
|
|
477
|
+
*/
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
async readLock(fn, options) {
|
|
481
|
+
const db = await this.connect();
|
|
482
|
+
return db.readLock(fn, options);
|
|
483
|
+
}
|
|
484
|
+
async writeLock(fn, options) {
|
|
485
|
+
const db = await this.connect();
|
|
486
|
+
return db.writeLock(fn, options);
|
|
487
|
+
}
|
|
488
|
+
async refreshSchema() {
|
|
489
|
+
// Not used by sync client.
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
const Adapter = DBAdapterDefaultMixin(ReconnectPool);
|
|
493
|
+
return new Adapter();
|
|
456
494
|
}
|
|
457
495
|
/**
|
|
458
496
|
* A method to update the all shared statuses for each
|