@powersync/web 0.0.0-dev-20251119150914 → 0.0.0-dev-20251126195153
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 +36 -11
- package/dist/index.umd.js.map +1 -1
- package/dist/worker/SharedSyncImplementation.umd.js +14863 -10910
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
- package/dist/worker/WASQLiteDB.umd.js +12733 -10923
- package/dist/worker/WASQLiteDB.umd.js.map +1 -1
- package/lib/package.json +2 -2
- package/lib/src/db/adapters/AsyncDatabaseConnection.d.ts +5 -0
- 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.d.ts +1 -0
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.js +7 -2
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.d.ts +5 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.js +7 -0
- package/lib/src/worker/db/SharedWASQLiteConnection.d.ts +4 -3
- package/lib/src/worker/db/SharedWASQLiteConnection.js +15 -11
- package/lib/src/worker/db/WASQLiteDB.worker.js +2 -2
- package/lib/src/worker/db/WorkerWASQLiteConnection.d.ts +3 -3
- package/lib/src/worker/db/WorkerWASQLiteConnection.js +2 -14
- package/lib/src/worker/sync/SharedSyncImplementation.d.ts +2 -2
- package/lib/src/worker/sync/SharedSyncImplementation.js +7 -4
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/db/adapters/AsyncDatabaseConnection.ts +5 -0
- package/src/db/adapters/LockedAsyncDatabaseAdapter.ts +12 -2
- package/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.ts +8 -2
- package/src/db/adapters/wa-sqlite/WASQLiteConnection.ts +8 -0
- package/src/worker/db/SharedWASQLiteConnection.ts +19 -14
- package/src/worker/db/WASQLiteDB.worker.ts +2 -2
- package/src/worker/db/WorkerWASQLiteConnection.ts +3 -18
- package/src/worker/sync/SharedSyncImplementation.ts +15 -12
- 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:*",
|
|
@@ -32,6 +32,11 @@ export interface AsyncDatabaseConnection<Config extends ResolvedWebSQLOpenOption
|
|
|
32
32
|
* @param holdId The hold ID to release.
|
|
33
33
|
*/
|
|
34
34
|
releaseHold(holdId: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Checks if the database connection is in autocommit mode.
|
|
37
|
+
* @returns true if in autocommit mode, false if in a transaction
|
|
38
|
+
*/
|
|
39
|
+
isAutoCommit(): Promise<boolean>;
|
|
35
40
|
execute(sql: string, params?: any[]): Promise<ProxiedQueryResult>;
|
|
36
41
|
executeRaw(sql: string, params?: any[]): Promise<any[][]>;
|
|
37
42
|
executeBatch(sql: string, params?: any[]): Promise<ProxiedQueryResult>;
|
|
@@ -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
|
}
|
|
@@ -36,6 +36,7 @@ export declare class WorkerWrappedAsyncDatabaseConnection<Config extends Resolve
|
|
|
36
36
|
markRemoteClosed(): void;
|
|
37
37
|
markHold(): Promise<string>;
|
|
38
38
|
releaseHold(holdId: string): Promise<void>;
|
|
39
|
+
isAutoCommit(): Promise<boolean>;
|
|
39
40
|
private withRemote;
|
|
40
41
|
/**
|
|
41
42
|
* Get a MessagePort which can be used to share the internals of this connection.
|
|
@@ -32,10 +32,13 @@ export class WorkerWrappedAsyncDatabaseConnection {
|
|
|
32
32
|
this.notifyRemoteClosed.abort();
|
|
33
33
|
}
|
|
34
34
|
markHold() {
|
|
35
|
-
return this.baseConnection.markHold();
|
|
35
|
+
return this.withRemote(() => this.baseConnection.markHold());
|
|
36
36
|
}
|
|
37
37
|
releaseHold(holdId) {
|
|
38
|
-
return this.baseConnection.releaseHold(holdId);
|
|
38
|
+
return this.withRemote(() => this.baseConnection.releaseHold(holdId));
|
|
39
|
+
}
|
|
40
|
+
isAutoCommit() {
|
|
41
|
+
return this.withRemote(() => this.baseConnection.isAutoCommit());
|
|
39
42
|
}
|
|
40
43
|
withRemote(workerPromise) {
|
|
41
44
|
const controller = this.notifyRemoteClosed;
|
|
@@ -43,6 +46,8 @@ export class WorkerWrappedAsyncDatabaseConnection {
|
|
|
43
46
|
return new Promise((resolve, reject) => {
|
|
44
47
|
if (controller.signal.aborted) {
|
|
45
48
|
reject(new Error('Called operation on closed remote'));
|
|
49
|
+
// Don't run the operation if we're going to reject
|
|
50
|
+
return;
|
|
46
51
|
}
|
|
47
52
|
function handleAbort() {
|
|
48
53
|
reject(new Error('Remote peer closed with request in flight'));
|
|
@@ -112,6 +112,11 @@ export declare class WASqliteConnection extends BaseObserver<WASQLiteConnectionL
|
|
|
112
112
|
get currentHoldId(): string | null;
|
|
113
113
|
protected get sqliteAPI(): SQLiteAPI;
|
|
114
114
|
protected get dbP(): number;
|
|
115
|
+
/**
|
|
116
|
+
* Checks if the database connection is in autocommit mode.
|
|
117
|
+
* @returns true if in autocommit mode, false if in a transaction
|
|
118
|
+
*/
|
|
119
|
+
isAutoCommit(): Promise<boolean>;
|
|
115
120
|
markHold(): Promise<string>;
|
|
116
121
|
releaseHold(holdId: string): Promise<void>;
|
|
117
122
|
protected openDB(): Promise<number>;
|
|
@@ -140,6 +140,13 @@ export class WASqliteConnection extends BaseObserver {
|
|
|
140
140
|
}
|
|
141
141
|
return this._dbP;
|
|
142
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Checks if the database connection is in autocommit mode.
|
|
145
|
+
* @returns true if in autocommit mode, false if in a transaction
|
|
146
|
+
*/
|
|
147
|
+
async isAutoCommit() {
|
|
148
|
+
return this.sqliteAPI.get_autocommit(this.dbP) != 0;
|
|
149
|
+
}
|
|
143
150
|
async markHold() {
|
|
144
151
|
const previousHoldId = this._holdId;
|
|
145
152
|
this._holdId = `${++this._holdCounter}`;
|
|
@@ -20,13 +20,14 @@ export declare class SharedWASQLiteConnection implements AsyncDatabaseConnection
|
|
|
20
20
|
protected isClosing: boolean;
|
|
21
21
|
protected activeHoldId: string | null;
|
|
22
22
|
constructor(options: SharedWASQLiteConnectionOptions);
|
|
23
|
-
init(): Promise<void>;
|
|
24
|
-
markHold(): Promise<string>;
|
|
25
|
-
releaseHold(id: string): Promise<void>;
|
|
26
23
|
protected get logger(): ILogger;
|
|
27
24
|
protected get dbEntry(): SharedDBWorkerConnection;
|
|
28
25
|
protected get connection(): AsyncDatabaseConnection<ResolvedWebSQLOpenOptions>;
|
|
29
26
|
protected get clientIds(): Set<number>;
|
|
27
|
+
init(): Promise<void>;
|
|
28
|
+
markHold(): Promise<string>;
|
|
29
|
+
releaseHold(id: string): Promise<void>;
|
|
30
|
+
isAutoCommit(): Promise<boolean>;
|
|
30
31
|
/**
|
|
31
32
|
* Handles closing of a shared connection.
|
|
32
33
|
* The connection is only closed if there are no active clients using it.
|
|
@@ -10,6 +10,18 @@ export class SharedWASQLiteConnection {
|
|
|
10
10
|
this.isClosing = false;
|
|
11
11
|
this.activeHoldId = null;
|
|
12
12
|
}
|
|
13
|
+
get logger() {
|
|
14
|
+
return this.options.logger;
|
|
15
|
+
}
|
|
16
|
+
get dbEntry() {
|
|
17
|
+
return this.options.dbMap.get(this.options.dbFilename);
|
|
18
|
+
}
|
|
19
|
+
get connection() {
|
|
20
|
+
return this.dbEntry.db;
|
|
21
|
+
}
|
|
22
|
+
get clientIds() {
|
|
23
|
+
return this.dbEntry.clientIds;
|
|
24
|
+
}
|
|
13
25
|
async init() {
|
|
14
26
|
// No-op since the connection is already initialized when it was created
|
|
15
27
|
}
|
|
@@ -25,17 +37,8 @@ export class SharedWASQLiteConnection {
|
|
|
25
37
|
this.activeHoldId = null;
|
|
26
38
|
}
|
|
27
39
|
}
|
|
28
|
-
|
|
29
|
-
return this.
|
|
30
|
-
}
|
|
31
|
-
get dbEntry() {
|
|
32
|
-
return this.options.dbMap.get(this.options.dbFilename);
|
|
33
|
-
}
|
|
34
|
-
get connection() {
|
|
35
|
-
return this.dbEntry.db;
|
|
36
|
-
}
|
|
37
|
-
get clientIds() {
|
|
38
|
-
return this.dbEntry.clientIds;
|
|
40
|
+
async isAutoCommit() {
|
|
41
|
+
return this.connection.isAutoCommit();
|
|
39
42
|
}
|
|
40
43
|
/**
|
|
41
44
|
* Handles closing of a shared connection.
|
|
@@ -58,6 +61,7 @@ export class SharedWASQLiteConnection {
|
|
|
58
61
|
const connection = this.connection;
|
|
59
62
|
dbMap.delete(dbFilename);
|
|
60
63
|
await connection.close();
|
|
64
|
+
return;
|
|
61
65
|
}
|
|
62
66
|
logger.debug(`Connection to ${dbFilename} not closed yet due to active clients.`);
|
|
63
67
|
return;
|
|
@@ -6,7 +6,7 @@ import { createBaseLogger, createLogger } from '@powersync/common';
|
|
|
6
6
|
import * as Comlink from 'comlink';
|
|
7
7
|
import { getNavigatorLocks } from '../../shared/navigator';
|
|
8
8
|
import { SharedWASQLiteConnection } from './SharedWASQLiteConnection';
|
|
9
|
-
import { WorkerWASQLiteConnection
|
|
9
|
+
import { WorkerWASQLiteConnection } from './WorkerWASQLiteConnection';
|
|
10
10
|
const baseLogger = createBaseLogger();
|
|
11
11
|
baseLogger.useDefaults();
|
|
12
12
|
const logger = createLogger('db-worker');
|
|
@@ -46,7 +46,7 @@ const openDBShared = async (options) => {
|
|
|
46
46
|
clientId,
|
|
47
47
|
logger
|
|
48
48
|
});
|
|
49
|
-
return
|
|
49
|
+
return Comlink.proxy(sharedConnection);
|
|
50
50
|
});
|
|
51
51
|
};
|
|
52
52
|
// Check if we're in a SharedWorker context
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OnTableChangeCallback } from '../../db/adapters/AsyncDatabaseConnection';
|
|
2
2
|
import { WASqliteConnection } from '../../db/adapters/wa-sqlite/WASQLiteConnection';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* A Small proxy wrapper around the WASqliteConnection.
|
|
5
|
+
* This ensures that certain return types are properly proxied.
|
|
5
6
|
*/
|
|
6
|
-
export declare function proxyWASQLiteConnection(connection: AsyncDatabaseConnection): AsyncDatabaseConnection;
|
|
7
7
|
export declare class WorkerWASQLiteConnection extends WASqliteConnection {
|
|
8
8
|
registerOnTableChange(callback: OnTableChangeCallback): Promise<() => void>;
|
|
9
9
|
}
|
|
@@ -1,21 +1,9 @@
|
|
|
1
1
|
import * as Comlink from 'comlink';
|
|
2
2
|
import { WASqliteConnection } from '../../db/adapters/wa-sqlite/WASQLiteConnection';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* A Small proxy wrapper around the WASqliteConnection.
|
|
5
|
+
* This ensures that certain return types are properly proxied.
|
|
5
6
|
*/
|
|
6
|
-
export function proxyWASQLiteConnection(connection) {
|
|
7
|
-
return Comlink.proxy({
|
|
8
|
-
init: Comlink.proxy(() => connection.init()),
|
|
9
|
-
close: Comlink.proxy(() => connection.close()),
|
|
10
|
-
markHold: Comlink.proxy(() => connection.markHold()),
|
|
11
|
-
releaseHold: Comlink.proxy((holdId) => connection.releaseHold(holdId)),
|
|
12
|
-
execute: Comlink.proxy((sql, params) => connection.execute(sql, params)),
|
|
13
|
-
executeRaw: Comlink.proxy((sql, params) => connection.executeRaw(sql, params)),
|
|
14
|
-
executeBatch: Comlink.proxy((sql, params) => connection.executeBatch(sql, params)),
|
|
15
|
-
registerOnTableChange: Comlink.proxy((callback) => connection.registerOnTableChange(callback)),
|
|
16
|
-
getConfig: Comlink.proxy(() => connection.getConfig())
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
7
|
export class WorkerWASQLiteConnection extends WASqliteConnection {
|
|
20
8
|
async registerOnTableChange(callback) {
|
|
21
9
|
// Proxy the callback remove function
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ILogger, type ILogLevel, type PowerSyncConnectionOptions, type StreamingSyncImplementation, type StreamingSyncImplementationListener, type SyncStatusOptions
|
|
1
|
+
import { BaseObserver, ConnectionManager, DBAdapter, SubscribedStream, SyncStatus, type ILogger, type ILogLevel, type PowerSyncConnectionOptions, type StreamingSyncImplementation, type StreamingSyncImplementationListener, type SyncStatusOptions } from '@powersync/common';
|
|
2
2
|
import { Mutex } from 'async-mutex';
|
|
3
3
|
import * as Comlink from 'comlink';
|
|
4
4
|
import { WebStreamingSyncImplementation, WebStreamingSyncImplementationOptions } from '../../db/sync/WebStreamingSyncImplementation';
|
|
@@ -44,7 +44,7 @@ export type WrappedSyncPort = {
|
|
|
44
44
|
clientProvider: Comlink.Remote<AbstractSharedSyncClientProvider>;
|
|
45
45
|
db?: DBAdapter;
|
|
46
46
|
currentSubscriptions: SubscribedStream[];
|
|
47
|
-
closeListeners: (() => void)[];
|
|
47
|
+
closeListeners: (() => void | Promise<void>)[];
|
|
48
48
|
};
|
|
49
49
|
/**
|
|
50
50
|
* @internal
|
|
@@ -228,11 +228,14 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
228
228
|
return () => { };
|
|
229
229
|
}
|
|
230
230
|
for (const closeListener of trackedPort.closeListeners) {
|
|
231
|
-
closeListener();
|
|
231
|
+
await closeListener();
|
|
232
232
|
}
|
|
233
233
|
if (this.dbAdapter && this.dbAdapter == trackedPort.db) {
|
|
234
234
|
// Unconditionally close the connection because the database it's writing to has just been closed.
|
|
235
|
-
|
|
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));
|
|
236
239
|
// Clearing the adapter will result in a new one being opened in connect
|
|
237
240
|
this.dbAdapter = null;
|
|
238
241
|
if (shouldReconnect) {
|
|
@@ -361,9 +364,9 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
361
364
|
// that and ensure pending requests are aborted when the tab is closed.
|
|
362
365
|
remoteCanCloseUnexpectedly: true
|
|
363
366
|
});
|
|
364
|
-
lastClient.closeListeners.push(() => {
|
|
367
|
+
lastClient.closeListeners.push(async () => {
|
|
365
368
|
this.logger.info('Aborting open connection because associated tab closed.');
|
|
366
|
-
wrapped.close();
|
|
369
|
+
wrapped.close().catch((ex) => this.logger.warn('error closing database connection', ex));
|
|
367
370
|
wrapped.markRemoteClosed();
|
|
368
371
|
});
|
|
369
372
|
return wrapped;
|