@powersync/web 0.0.0-dev-20250207081035 → 0.0.0-dev-20250220093908
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 +40 -31
- package/dist/index.umd.js.map +1 -1
- package/dist/worker/SharedSyncImplementation.umd.js +85 -84
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
- package/dist/worker/WASQLiteDB.umd.js +59 -57
- package/dist/worker/WASQLiteDB.umd.js.map +1 -1
- package/lib/package.json +2 -2
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.js +1 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.d.ts +1 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.js +4 -2
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +5 -2
- package/lib/src/db/adapters/web-sql-flags.d.ts +10 -0
- package/lib/src/db/adapters/web-sql-flags.js +1 -0
- package/lib/src/db/sync/SharedWebStreamingSyncImplementation.js +3 -3
- package/lib/src/worker/sync/SharedSyncImplementation.js +27 -27
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
package/lib/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powersync/web",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "A Web SDK for JourneyApps PowerSync",
|
|
5
5
|
"main": "lib/src/index.js",
|
|
6
6
|
"types": "lib/src/index.d.ts",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"license": "Apache-2.0",
|
|
62
62
|
"peerDependencies": {
|
|
63
63
|
"@journeyapps/wa-sqlite": "^1.2.0",
|
|
64
|
-
"@powersync/common": "workspace:^1.
|
|
64
|
+
"@powersync/common": "workspace:^1.24.0"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"@powersync/common": "workspace:*",
|
|
@@ -184,6 +184,7 @@ export class WASqliteConnection extends BaseObserver {
|
|
|
184
184
|
await this.openDB();
|
|
185
185
|
this.registerBroadcastListeners();
|
|
186
186
|
await this.executeSingleStatement(`PRAGMA temp_store = ${this.options.temporaryStorage};`);
|
|
187
|
+
await this.executeSingleStatement(`PRAGMA cache_size = -${this.options.cacheSizeKb};`);
|
|
187
188
|
await this.executeEncryptionPragma();
|
|
188
189
|
this.sqliteAPI.update_hook(this.dbP, (updateType, dbName, tableName) => {
|
|
189
190
|
if (!tableName) {
|
|
@@ -17,6 +17,7 @@ export interface WASQLiteDBAdapterOptions extends Omit<PowerSyncOpenFactoryOptio
|
|
|
17
17
|
worker?: string | URL | ((options: ResolvedWebSQLOpenOptions) => Worker | SharedWorker);
|
|
18
18
|
vfs?: WASQLiteVFS;
|
|
19
19
|
temporaryStorage?: TemporaryStorageOption;
|
|
20
|
+
cacheSizeKb?: number;
|
|
20
21
|
/**
|
|
21
22
|
* Encryption key for the database.
|
|
22
23
|
* If set, the database will be encrypted using multiple-ciphers.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Comlink from 'comlink';
|
|
2
2
|
import { resolveWebPowerSyncFlags } from '../../PowerSyncDatabase';
|
|
3
3
|
import { LockedAsyncDatabaseAdapter } from '../LockedAsyncDatabaseAdapter';
|
|
4
|
-
import { TemporaryStorageOption } from '../web-sql-flags';
|
|
4
|
+
import { DEFAULT_CACHE_SIZE_KB, TemporaryStorageOption } from '../web-sql-flags';
|
|
5
5
|
import { WorkerWrappedAsyncDatabaseConnection } from '../WorkerWrappedAsyncDatabaseConnection';
|
|
6
6
|
import { WASQLiteOpenFactory } from './WASQLiteOpenFactory';
|
|
7
7
|
/**
|
|
@@ -12,7 +12,7 @@ export class WASQLiteDBAdapter extends LockedAsyncDatabaseAdapter {
|
|
|
12
12
|
super({
|
|
13
13
|
name: options.dbFilename,
|
|
14
14
|
openConnection: async () => {
|
|
15
|
-
const { workerPort, temporaryStorage } = options;
|
|
15
|
+
const { workerPort, temporaryStorage, cacheSizeKb } = options;
|
|
16
16
|
if (workerPort) {
|
|
17
17
|
const remote = Comlink.wrap(workerPort);
|
|
18
18
|
return new WorkerWrappedAsyncDatabaseConnection({
|
|
@@ -21,6 +21,7 @@ export class WASQLiteDBAdapter extends LockedAsyncDatabaseAdapter {
|
|
|
21
21
|
baseConnection: await remote({
|
|
22
22
|
...options,
|
|
23
23
|
temporaryStorage: temporaryStorage ?? TemporaryStorageOption.MEMORY,
|
|
24
|
+
cacheSizeKb: cacheSizeKb ?? DEFAULT_CACHE_SIZE_KB,
|
|
24
25
|
flags: resolveWebPowerSyncFlags(options.flags),
|
|
25
26
|
encryptionKey: options.encryptionKey
|
|
26
27
|
})
|
|
@@ -32,6 +33,7 @@ export class WASQLiteDBAdapter extends LockedAsyncDatabaseAdapter {
|
|
|
32
33
|
debugMode: options.debugMode,
|
|
33
34
|
flags: options.flags,
|
|
34
35
|
temporaryStorage,
|
|
36
|
+
cacheSizeKb,
|
|
35
37
|
logger: options.logger,
|
|
36
38
|
vfs: options.vfs,
|
|
37
39
|
encryptionKey: options.encryptionKey,
|
|
@@ -2,7 +2,7 @@ import * as Comlink from 'comlink';
|
|
|
2
2
|
import { openWorkerDatabasePort, resolveWorkerDatabasePortFactory } from '../../../worker/db/open-worker-database';
|
|
3
3
|
import { AbstractWebSQLOpenFactory } from '../AbstractWebSQLOpenFactory';
|
|
4
4
|
import { LockedAsyncDatabaseAdapter } from '../LockedAsyncDatabaseAdapter';
|
|
5
|
-
import { TemporaryStorageOption } from '../web-sql-flags';
|
|
5
|
+
import { DEFAULT_CACHE_SIZE_KB, TemporaryStorageOption } from '../web-sql-flags';
|
|
6
6
|
import { WorkerWrappedAsyncDatabaseConnection } from '../WorkerWrappedAsyncDatabaseConnection';
|
|
7
7
|
import { WASqliteConnection, WASQLiteVFS } from './WASQLiteConnection';
|
|
8
8
|
/**
|
|
@@ -27,7 +27,7 @@ export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
|
|
|
27
27
|
}
|
|
28
28
|
async openConnection() {
|
|
29
29
|
const { enableMultiTabs, useWebWorker } = this.resolvedFlags;
|
|
30
|
-
const { vfs = WASQLiteVFS.IDBBatchAtomicVFS, temporaryStorage = TemporaryStorageOption.MEMORY, encryptionKey } = this.waOptions;
|
|
30
|
+
const { vfs = WASQLiteVFS.IDBBatchAtomicVFS, temporaryStorage = TemporaryStorageOption.MEMORY, cacheSizeKb = DEFAULT_CACHE_SIZE_KB, encryptionKey } = this.waOptions;
|
|
31
31
|
if (!enableMultiTabs) {
|
|
32
32
|
this.logger.warn('Multiple tabs are not enabled in this browser');
|
|
33
33
|
}
|
|
@@ -37,6 +37,7 @@ export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
|
|
|
37
37
|
? resolveWorkerDatabasePortFactory(() => optionsDbWorker({
|
|
38
38
|
...this.options,
|
|
39
39
|
temporaryStorage,
|
|
40
|
+
cacheSizeKb,
|
|
40
41
|
flags: this.resolvedFlags,
|
|
41
42
|
encryptionKey
|
|
42
43
|
}))
|
|
@@ -48,6 +49,7 @@ export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
|
|
|
48
49
|
dbFilename: this.options.dbFilename,
|
|
49
50
|
vfs,
|
|
50
51
|
temporaryStorage,
|
|
52
|
+
cacheSizeKb,
|
|
51
53
|
flags: this.resolvedFlags,
|
|
52
54
|
encryptionKey: encryptionKey
|
|
53
55
|
}),
|
|
@@ -70,6 +72,7 @@ export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
|
|
|
70
72
|
debugMode: this.options.debugMode,
|
|
71
73
|
vfs,
|
|
72
74
|
temporaryStorage,
|
|
75
|
+
cacheSizeKb,
|
|
73
76
|
flags: this.resolvedFlags,
|
|
74
77
|
encryptionKey: encryptionKey
|
|
75
78
|
});
|
|
@@ -39,6 +39,7 @@ export interface ResolvedWebSQLOpenOptions extends SQLOpenOptions {
|
|
|
39
39
|
* Setting this to `FILESYSTEM` can cause issues with larger queries or datasets.
|
|
40
40
|
*/
|
|
41
41
|
temporaryStorage: TemporaryStorageOption;
|
|
42
|
+
cacheSizeKb: number;
|
|
42
43
|
/**
|
|
43
44
|
* Encryption key for the database.
|
|
44
45
|
* If set, the database will be encrypted using ChaCha20.
|
|
@@ -49,6 +50,7 @@ export declare enum TemporaryStorageOption {
|
|
|
49
50
|
MEMORY = "memory",
|
|
50
51
|
FILESYSTEM = "file"
|
|
51
52
|
}
|
|
53
|
+
export declare const DEFAULT_CACHE_SIZE_KB: number;
|
|
52
54
|
/**
|
|
53
55
|
* Options for opening a Web SQL connection
|
|
54
56
|
*/
|
|
@@ -65,8 +67,16 @@ export interface WebSQLOpenFactoryOptions extends SQLOpenOptions {
|
|
|
65
67
|
/**
|
|
66
68
|
* Where to store SQLite temporary files. Defaults to 'MEMORY'.
|
|
67
69
|
* Setting this to `FILESYSTEM` can cause issues with larger queries or datasets.
|
|
70
|
+
*
|
|
71
|
+
* For details, see: https://www.sqlite.org/pragma.html#pragma_temp_store
|
|
68
72
|
*/
|
|
69
73
|
temporaryStorage?: TemporaryStorageOption;
|
|
74
|
+
/**
|
|
75
|
+
* Maximum SQLite cache size. Defaults to 50MB.
|
|
76
|
+
*
|
|
77
|
+
* For details, see: https://www.sqlite.org/pragma.html#pragma_cache_size
|
|
78
|
+
*/
|
|
79
|
+
cacheSizeKb?: number;
|
|
70
80
|
/**
|
|
71
81
|
* Encryption key for the database.
|
|
72
82
|
* If set, the database will be encrypted using ChaCha20.
|
|
@@ -3,6 +3,7 @@ export var TemporaryStorageOption;
|
|
|
3
3
|
TemporaryStorageOption["MEMORY"] = "memory";
|
|
4
4
|
TemporaryStorageOption["FILESYSTEM"] = "file";
|
|
5
5
|
})(TemporaryStorageOption || (TemporaryStorageOption = {}));
|
|
6
|
+
export const DEFAULT_CACHE_SIZE_KB = 50 * 1024;
|
|
6
7
|
export function isServerSide() {
|
|
7
8
|
return typeof window == 'undefined';
|
|
8
9
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Comlink from 'comlink';
|
|
2
2
|
import { AbstractSharedSyncClientProvider } from '../../worker/sync/AbstractSharedSyncClientProvider';
|
|
3
3
|
import { SharedSyncClientEvent } from '../../worker/sync/SharedSyncImplementation';
|
|
4
|
-
import { resolveWebSQLFlags, TemporaryStorageOption } from '../adapters/web-sql-flags';
|
|
4
|
+
import { DEFAULT_CACHE_SIZE_KB, resolveWebSQLFlags, TemporaryStorageOption } from '../adapters/web-sql-flags';
|
|
5
5
|
import { WebStreamingSyncImplementation } from './WebStreamingSyncImplementation';
|
|
6
6
|
/**
|
|
7
7
|
* The shared worker will trigger methods on this side of the message port
|
|
@@ -86,10 +86,10 @@ export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplem
|
|
|
86
86
|
* This worker will manage all syncing operations remotely.
|
|
87
87
|
*/
|
|
88
88
|
const resolvedWorkerOptions = {
|
|
89
|
-
...options,
|
|
90
89
|
dbFilename: this.options.identifier,
|
|
91
|
-
// TODO
|
|
92
90
|
temporaryStorage: TemporaryStorageOption.MEMORY,
|
|
91
|
+
cacheSizeKb: DEFAULT_CACHE_SIZE_KB,
|
|
92
|
+
...options,
|
|
93
93
|
flags: resolveWebSQLFlags(options.flags)
|
|
94
94
|
};
|
|
95
95
|
const syncWorker = options.sync?.worker;
|
|
@@ -102,6 +102,9 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
102
102
|
await this.waitForReady();
|
|
103
103
|
// This effectively queues connect and disconnect calls. Ensuring multiple tabs' requests are synchronized
|
|
104
104
|
return getNavigatorLocks().request('shared-sync-connect', async () => {
|
|
105
|
+
if (!this.dbAdapter) {
|
|
106
|
+
await this.openInternalDB();
|
|
107
|
+
}
|
|
105
108
|
this.syncStreamClient = this.generateStreamingImplementation();
|
|
106
109
|
this.lastConnectOptions = options;
|
|
107
110
|
this.syncStreamClient.registerListener({
|
|
@@ -125,10 +128,7 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
125
128
|
* Adds a new client tab's message port to the list of connected ports
|
|
126
129
|
*/
|
|
127
130
|
addPort(port) {
|
|
128
|
-
const portProvider = {
|
|
129
|
-
port,
|
|
130
|
-
clientProvider: Comlink.wrap(port)
|
|
131
|
-
};
|
|
131
|
+
const portProvider = { port, clientProvider: Comlink.wrap(port) };
|
|
132
132
|
this.ports.push(portProvider);
|
|
133
133
|
// Give the newly connected client the latest status
|
|
134
134
|
const status = this.syncStreamClient?.syncStatus;
|
|
@@ -147,11 +147,7 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
147
147
|
return;
|
|
148
148
|
}
|
|
149
149
|
const trackedPort = this.ports[index];
|
|
150
|
-
|
|
151
|
-
trackedPort.db.close();
|
|
152
|
-
}
|
|
153
|
-
// Release proxy
|
|
154
|
-
trackedPort.clientProvider[Comlink.releaseProxy]();
|
|
150
|
+
// Remove from the list of active ports
|
|
155
151
|
this.ports.splice(index, 1);
|
|
156
152
|
/**
|
|
157
153
|
* The port might currently be in use. Any active functions might
|
|
@@ -162,12 +158,22 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
162
158
|
abortController.controller.abort(new AbortOperation('Closing pending requests after client port is removed'));
|
|
163
159
|
}
|
|
164
160
|
});
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
161
|
+
const shouldReconnect = !!this.syncStreamClient;
|
|
162
|
+
if (this.dbAdapter && this.dbAdapter == trackedPort.db) {
|
|
163
|
+
if (shouldReconnect) {
|
|
164
|
+
await this.disconnect();
|
|
165
|
+
}
|
|
166
|
+
// Clearing the adapter will result in a new one being opened in connect
|
|
167
|
+
this.dbAdapter = null;
|
|
168
|
+
if (shouldReconnect) {
|
|
169
|
+
await this.connect(this.lastConnectOptions);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (trackedPort.db) {
|
|
173
|
+
trackedPort.db.close();
|
|
170
174
|
}
|
|
175
|
+
// Release proxy
|
|
176
|
+
trackedPort.clientProvider[Comlink.releaseProxy]();
|
|
171
177
|
}
|
|
172
178
|
triggerCrudUpload() {
|
|
173
179
|
this.waitForReady().then(() => this.syncStreamClient?.triggerCrudUpload());
|
|
@@ -195,10 +201,7 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
195
201
|
const lastPort = this.ports[this.ports.length - 1];
|
|
196
202
|
return new Promise(async (resolve, reject) => {
|
|
197
203
|
const abortController = new AbortController();
|
|
198
|
-
this.fetchCredentialsController = {
|
|
199
|
-
controller: abortController,
|
|
200
|
-
activePort: lastPort
|
|
201
|
-
};
|
|
204
|
+
this.fetchCredentialsController = { controller: abortController, activePort: lastPort };
|
|
202
205
|
abortController.signal.onabort = reject;
|
|
203
206
|
try {
|
|
204
207
|
console.log('calling the last port client provider for credentials');
|
|
@@ -217,10 +220,7 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
217
220
|
const lastPort = this.ports[this.ports.length - 1];
|
|
218
221
|
return new Promise(async (resolve, reject) => {
|
|
219
222
|
const abortController = new AbortController();
|
|
220
|
-
this.uploadDataController = {
|
|
221
|
-
controller: abortController,
|
|
222
|
-
activePort: lastPort
|
|
223
|
-
};
|
|
223
|
+
this.uploadDataController = { controller: abortController, activePort: lastPort };
|
|
224
224
|
// Resolving will make it retry
|
|
225
225
|
abortController.signal.onabort = () => resolve();
|
|
226
226
|
try {
|
|
@@ -241,6 +241,10 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
241
241
|
}
|
|
242
242
|
async openInternalDB() {
|
|
243
243
|
const lastClient = this.ports[this.ports.length - 1];
|
|
244
|
+
if (!lastClient) {
|
|
245
|
+
// Should not really happen in practice
|
|
246
|
+
throw new Error(`Could not open DB connection since no client is connected.`);
|
|
247
|
+
}
|
|
244
248
|
const workerPort = await lastClient.clientProvider.getDBWorkerPort();
|
|
245
249
|
const remote = Comlink.wrap(workerPort);
|
|
246
250
|
const identifier = this.syncParams.dbParams.dbFilename;
|
|
@@ -248,11 +252,7 @@ export class SharedSyncImplementation extends BaseObserver {
|
|
|
248
252
|
const locked = new LockedAsyncDatabaseAdapter({
|
|
249
253
|
name: identifier,
|
|
250
254
|
openConnection: async () => {
|
|
251
|
-
return new WorkerWrappedAsyncDatabaseConnection({
|
|
252
|
-
remote,
|
|
253
|
-
baseConnection: db,
|
|
254
|
-
identifier
|
|
255
|
-
});
|
|
255
|
+
return new WorkerWrappedAsyncDatabaseConnection({ remote, baseConnection: db, identifier });
|
|
256
256
|
},
|
|
257
257
|
logger: this.logger
|
|
258
258
|
});
|