@powersync/web 0.0.0-dev-20251120085122 → 0.0.0-dev-20251127205344
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 +63 -41
- package/dist/index.umd.js.map +1 -1
- package/dist/worker/SharedSyncImplementation.umd.js +14914 -10959
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
- package/dist/worker/WASQLiteDB.umd.js +12708 -10895
- package/dist/worker/WASQLiteDB.umd.js.map +1 -1
- package/lib/package.json +2 -2
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.d.ts +1 -0
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.js +11 -2
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.js +1 -1
- package/lib/src/db/sync/SharedWebStreamingSyncImplementation.d.ts +1 -1
- package/lib/src/db/sync/SharedWebStreamingSyncImplementation.js +15 -13
- package/lib/src/worker/db/SharedWASQLiteConnection.js +1 -0
- package/lib/src/worker/sync/SharedSyncImplementation.js +22 -12
- package/lib/src/worker/sync/WorkerClient.d.ts +1 -1
- package/lib/src/worker/sync/WorkerClient.js +2 -2
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/db/adapters/LockedAsyncDatabaseAdapter.ts +12 -2
- package/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.ts +1 -1
- package/src/db/sync/SharedWebStreamingSyncImplementation.ts +18 -16
- package/src/worker/db/SharedWASQLiteConnection.ts +1 -0
- package/src/worker/sync/SharedSyncImplementation.ts +24 -14
- package/src/worker/sync/WorkerClient.ts +5 -4
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3460.index.umd.js +0 -355
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3460.index.umd.js.map +0 -1
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3461.index.umd.js +0 -355
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3461.index.umd.js.map +0 -1
package/lib/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powersync/web",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.1",
|
|
4
4
|
"description": "PowerSync web SDK. Sync Postgres, MongoDB or MySQL with SQLite in your web app",
|
|
5
5
|
"main": "lib/src/index.js",
|
|
6
6
|
"types": "lib/src/index.d.ts",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"license": "Apache-2.0",
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"@journeyapps/wa-sqlite": "^1.3.2",
|
|
65
|
-
"@powersync/common": "workspace:^1.
|
|
65
|
+
"@powersync/common": "workspace:^1.43.1"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@powersync/common": "workspace:*",
|
|
@@ -30,6 +30,7 @@ export declare class LockedAsyncDatabaseAdapter extends BaseObserver<LockedAsync
|
|
|
30
30
|
protected _disposeTableChangeListener: (() => void) | null;
|
|
31
31
|
private _config;
|
|
32
32
|
protected pendingAbortControllers: Set<AbortController>;
|
|
33
|
+
protected requiresHolds: boolean | null;
|
|
33
34
|
closing: boolean;
|
|
34
35
|
closed: boolean;
|
|
35
36
|
constructor(options: LockedAsyncDatabaseAdapterOptions);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BaseObserver, createLogger } from '@powersync/common';
|
|
2
2
|
import { getNavigatorLocks } from '../..//shared/navigator';
|
|
3
3
|
import { WorkerWrappedAsyncDatabaseConnection } from './WorkerWrappedAsyncDatabaseConnection';
|
|
4
|
+
import { WASQLiteVFS } from './wa-sqlite/WASQLiteConnection';
|
|
4
5
|
/**
|
|
5
6
|
* @internal
|
|
6
7
|
* Wraps a {@link AsyncDatabaseConnection} and provides exclusive locking functions in
|
|
@@ -17,6 +18,7 @@ export class LockedAsyncDatabaseAdapter extends BaseObserver {
|
|
|
17
18
|
_disposeTableChangeListener = null;
|
|
18
19
|
_config = null;
|
|
19
20
|
pendingAbortControllers;
|
|
21
|
+
requiresHolds;
|
|
20
22
|
closing;
|
|
21
23
|
closed;
|
|
22
24
|
constructor(options) {
|
|
@@ -27,6 +29,7 @@ export class LockedAsyncDatabaseAdapter extends BaseObserver {
|
|
|
27
29
|
this.pendingAbortControllers = new Set();
|
|
28
30
|
this.closed = false;
|
|
29
31
|
this.closing = false;
|
|
32
|
+
this.requiresHolds = null;
|
|
30
33
|
// Set the name if provided. We can query for the name if not available yet
|
|
31
34
|
this.debugMode = options.debugMode ?? false;
|
|
32
35
|
if (this.debugMode) {
|
|
@@ -71,6 +74,10 @@ export class LockedAsyncDatabaseAdapter extends BaseObserver {
|
|
|
71
74
|
this._config = await this._db.getConfig();
|
|
72
75
|
await this.registerOnChangeListener(this._db);
|
|
73
76
|
this.iterateListeners((cb) => cb.initialized?.());
|
|
77
|
+
/**
|
|
78
|
+
* This is only required for the long-lived shared IndexedDB connections.
|
|
79
|
+
*/
|
|
80
|
+
this.requiresHolds = this._config.vfs == WASQLiteVFS.IDBBatchAtomicVFS;
|
|
74
81
|
}
|
|
75
82
|
getConfiguration() {
|
|
76
83
|
if (!this._config) {
|
|
@@ -165,12 +172,14 @@ export class LockedAsyncDatabaseAdapter extends BaseObserver {
|
|
|
165
172
|
if (timoutId) {
|
|
166
173
|
clearTimeout(timoutId);
|
|
167
174
|
}
|
|
168
|
-
const holdId = await this.baseDB.markHold();
|
|
175
|
+
const holdId = this.requiresHolds ? await this.baseDB.markHold() : null;
|
|
169
176
|
try {
|
|
170
177
|
return await callback();
|
|
171
178
|
}
|
|
172
179
|
finally {
|
|
173
|
-
|
|
180
|
+
if (holdId) {
|
|
181
|
+
await this.baseDB.releaseHold(holdId);
|
|
182
|
+
}
|
|
174
183
|
}
|
|
175
184
|
});
|
|
176
185
|
}
|
|
@@ -38,7 +38,7 @@ export class WorkerWrappedAsyncDatabaseConnection {
|
|
|
38
38
|
return this.withRemote(() => this.baseConnection.releaseHold(holdId));
|
|
39
39
|
}
|
|
40
40
|
isAutoCommit() {
|
|
41
|
-
return this.baseConnection.isAutoCommit();
|
|
41
|
+
return this.withRemote(() => this.baseConnection.isAutoCommit());
|
|
42
42
|
}
|
|
43
43
|
withRemote(workerPromise) {
|
|
44
44
|
const controller = this.notifyRemoteClosed;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { PowerSyncConnectionOptions, PowerSyncCredentials, SubscribedStream, SyncStatusOptions } from '@powersync/common';
|
|
2
2
|
import * as Comlink from 'comlink';
|
|
3
3
|
import { AbstractSharedSyncClientProvider } from '../../worker/sync/AbstractSharedSyncClientProvider';
|
|
4
|
+
import { WorkerClient } from '../../worker/sync/WorkerClient';
|
|
4
5
|
import { WebDBAdapter } from '../adapters/WebDBAdapter';
|
|
5
6
|
import { WebStreamingSyncImplementation, WebStreamingSyncImplementationOptions } from './WebStreamingSyncImplementation';
|
|
6
|
-
import { WorkerClient } from '../../worker/sync/WorkerClient';
|
|
7
7
|
/**
|
|
8
8
|
* The shared worker will trigger methods on this side of the message port
|
|
9
9
|
* via this client provider.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as Comlink from 'comlink';
|
|
2
|
+
import { getNavigatorLocks } from '../../shared/navigator';
|
|
2
3
|
import { AbstractSharedSyncClientProvider } from '../../worker/sync/AbstractSharedSyncClientProvider';
|
|
3
4
|
import { SharedSyncClientEvent } from '../../worker/sync/SharedSyncImplementation';
|
|
4
|
-
import { DEFAULT_CACHE_SIZE_KB,
|
|
5
|
+
import { DEFAULT_CACHE_SIZE_KB, TemporaryStorageOption, resolveWebSQLFlags } from '../adapters/web-sql-flags';
|
|
5
6
|
import { WebStreamingSyncImplementation } from './WebStreamingSyncImplementation';
|
|
6
|
-
import { getNavigatorLocks } from '../../shared/navigator';
|
|
7
7
|
/**
|
|
8
8
|
* The shared worker will trigger methods on this side of the message port
|
|
9
9
|
* via this client provider.
|
|
@@ -130,6 +130,19 @@ export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplem
|
|
|
130
130
|
*/
|
|
131
131
|
const { crudUploadThrottleMs, identifier, retryDelayMs } = this.options;
|
|
132
132
|
const flags = { ...this.webOptions.flags, workers: undefined };
|
|
133
|
+
// Request a random lock until this client is disposed. The name of the lock is sent to the shared worker, which
|
|
134
|
+
// will also attempt to acquire it. Since the lock is returned when the tab is closed, this allows the share worker
|
|
135
|
+
// to free resources associated with this tab.
|
|
136
|
+
// We take hold of this lock as soon-as-possible in order to cater for potentially closed tabs.
|
|
137
|
+
getNavigatorLocks().request(`tab-close-signal-${crypto.randomUUID()}`, async (lock) => {
|
|
138
|
+
if (!this.abortOnClose.signal.aborted) {
|
|
139
|
+
// Awaiting here ensures the worker is waiting for the lock
|
|
140
|
+
await this.syncManager.addLockBasedCloseSignal(lock.name);
|
|
141
|
+
await new Promise((r) => {
|
|
142
|
+
this.abortOnClose.signal.onabort = () => r();
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
133
146
|
this.isInitialized = this.syncManager.setParams({
|
|
134
147
|
dbParams: this.dbAdapter.getConfiguration(),
|
|
135
148
|
streamOptions: {
|
|
@@ -151,17 +164,6 @@ export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplem
|
|
|
151
164
|
* This performs bi-directional method calling.
|
|
152
165
|
*/
|
|
153
166
|
Comlink.expose(this.clientProvider, this.messagePort);
|
|
154
|
-
// Request a random lock until this client is disposed. The name of the lock is sent to the shared worker, which
|
|
155
|
-
// will also attempt to acquire it. Since the lock is returned when the tab is closed, this allows the share worker
|
|
156
|
-
// to free resources associated with this tab.
|
|
157
|
-
getNavigatorLocks().request(`tab-close-signal-${crypto.randomUUID()}`, async (lock) => {
|
|
158
|
-
if (!this.abortOnClose.signal.aborted) {
|
|
159
|
-
this.syncManager.addLockBasedCloseSignal(lock.name);
|
|
160
|
-
await new Promise((r) => {
|
|
161
|
-
this.abortOnClose.signal.onabort = () => r();
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
167
|
}
|
|
166
168
|
/**
|
|
167
169
|
* Starts the sync process, this effectively acts as a call to
|
|
@@ -218,6 +218,20 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
218
218
|
}
|
|
219
219
|
});
|
|
220
220
|
const shouldReconnect = !!this.connectionManager.syncStreamImplementation && this.ports.length > 0;
|
|
221
|
+
/**
|
|
222
|
+
* If the current database adapter is the one that is being closed, we need to disconnect from the backend.
|
|
223
|
+
* We can disconnect in the portMutex lock. This ensures the disconnect is not affected by potential other
|
|
224
|
+
* connect operations coming from other tabs.
|
|
225
|
+
*/
|
|
226
|
+
if (this.dbAdapter && this.dbAdapter == trackedPort.db) {
|
|
227
|
+
this.logger.debug(`Disconnecting due to closed database: should reconnect: ${shouldReconnect}`);
|
|
228
|
+
this.dbAdapter = null;
|
|
229
|
+
// Unconditionally close the connection because the database it's writing to has just been closed.
|
|
230
|
+
// The connection has been closed previously, this might throw. We should be able to ignore it.
|
|
231
|
+
await this.connectionManager
|
|
232
|
+
.disconnect()
|
|
233
|
+
.catch((ex) => this.logger.warn('Error while disconnecting. Will attempt to reconnect.', ex));
|
|
234
|
+
}
|
|
221
235
|
return {
|
|
222
236
|
shouldReconnect,
|
|
223
237
|
trackedPort
|
|
@@ -230,17 +244,8 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
230
244
|
for (const closeListener of trackedPort.closeListeners) {
|
|
231
245
|
await closeListener();
|
|
232
246
|
}
|
|
233
|
-
if (
|
|
234
|
-
|
|
235
|
-
// The connection has been closed previously, this might throw. We should be able to ignore it.
|
|
236
|
-
await this.connectionManager
|
|
237
|
-
.disconnect()
|
|
238
|
-
.catch((ex) => this.logger.warn('Error while disconnecting. Will attempt to reconnect.', ex));
|
|
239
|
-
// Clearing the adapter will result in a new one being opened in connect
|
|
240
|
-
this.dbAdapter = null;
|
|
241
|
-
if (shouldReconnect) {
|
|
242
|
-
await this.connectionManager.connect(CONNECTOR_PLACEHOLDER, this.lastConnectOptions ?? {});
|
|
243
|
-
}
|
|
247
|
+
if (shouldReconnect) {
|
|
248
|
+
await this.connectionManager.connect(CONNECTOR_PLACEHOLDER, this.lastConnectOptions ?? {});
|
|
244
249
|
}
|
|
245
250
|
// Re-index subscriptions, the subscriptions of the removed port would no longer be considered.
|
|
246
251
|
this.collectActiveSubscriptions();
|
|
@@ -366,7 +371,12 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
366
371
|
});
|
|
367
372
|
lastClient.closeListeners.push(async () => {
|
|
368
373
|
this.logger.info('Aborting open connection because associated tab closed.');
|
|
369
|
-
|
|
374
|
+
/**
|
|
375
|
+
* Don't await this close operation. It might never resolve if the tab is closed.
|
|
376
|
+
* We run the close operation first, before marking the remote as closed. This gives the database some chance
|
|
377
|
+
* to close the connection.
|
|
378
|
+
*/
|
|
379
|
+
wrapped.close().catch((ex) => this.logger.warn('error closing database connection', ex));
|
|
370
380
|
wrapped.markRemoteClosed();
|
|
371
381
|
});
|
|
372
382
|
return wrapped;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { SharedSyncImplementation, SharedSyncInitOptions } from './SharedSyncImplementation';
|
|
2
1
|
import { ILogLevel, PowerSyncConnectionOptions, SubscribedStream, SyncStatusOptions } from '@powersync/common';
|
|
2
|
+
import { SharedSyncImplementation, SharedSyncInitOptions } from './SharedSyncImplementation';
|
|
3
3
|
/**
|
|
4
4
|
* A client to the shared sync worker.
|
|
5
5
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Comlink from 'comlink';
|
|
2
|
-
import { SharedSyncClientEvent } from './SharedSyncImplementation';
|
|
3
2
|
import { getNavigatorLocks } from '../../shared/navigator';
|
|
3
|
+
import { SharedSyncClientEvent } from './SharedSyncImplementation';
|
|
4
4
|
/**
|
|
5
5
|
* A client to the shared sync worker.
|
|
6
6
|
*
|
|
@@ -14,6 +14,7 @@ export class WorkerClient {
|
|
|
14
14
|
constructor(sync, port) {
|
|
15
15
|
this.sync = sync;
|
|
16
16
|
this.port = port;
|
|
17
|
+
Comlink.expose(this, this.port);
|
|
17
18
|
}
|
|
18
19
|
async initialize() {
|
|
19
20
|
/**
|
|
@@ -27,7 +28,6 @@ export class WorkerClient {
|
|
|
27
28
|
}
|
|
28
29
|
});
|
|
29
30
|
this.resolvedPort = await this.sync.addPort(this.port);
|
|
30
|
-
Comlink.expose(this, this.port);
|
|
31
31
|
}
|
|
32
32
|
async removePort() {
|
|
33
33
|
if (this.resolvedPort) {
|