@powersync/web 0.0.0-dev-20250127153955 → 0.0.0-dev-20250210155038
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 +47 -5
- package/dist/index.umd.js.map +1 -1
- package/dist/worker/SharedSyncImplementation.umd.js +71 -39
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
- package/dist/worker/WASQLiteDB.umd.js +41 -39
- package/dist/worker/WASQLiteDB.umd.js.map +1 -1
- package/lib/package.json +4 -8
- package/lib/src/db/PowerSyncDatabase.d.ts +2 -2
- package/lib/src/db/PowerSyncDatabase.js +4 -2
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.d.ts +2 -0
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.js +31 -0
- 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/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -9
package/lib/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powersync/web",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.1",
|
|
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.23.0"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"@powersync/common": "workspace:*",
|
|
@@ -74,20 +74,16 @@
|
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"@journeyapps/wa-sqlite": "^1.2.0",
|
|
76
76
|
"@types/uuid": "^9.0.6",
|
|
77
|
-
"@vitest/browser": "^2.1.4",
|
|
78
77
|
"crypto-browserify": "^3.12.0",
|
|
79
78
|
"p-defer": "^4.0.1",
|
|
80
79
|
"source-map-loader": "^5.0.0",
|
|
81
80
|
"stream-browserify": "^3.0.0",
|
|
82
81
|
"terser-webpack-plugin": "^5.3.9",
|
|
83
|
-
"typescript": "^5.5.3",
|
|
84
82
|
"uuid": "^9.0.1",
|
|
85
|
-
"vite": "^
|
|
86
|
-
"vite-plugin-top-level-await": "^1.4.
|
|
83
|
+
"vite": "^6.1.0",
|
|
84
|
+
"vite-plugin-top-level-await": "^1.4.4",
|
|
87
85
|
"vite-plugin-wasm": "^3.3.0",
|
|
88
|
-
"vitest": "^2.1.4",
|
|
89
86
|
"vm-browserify": "^1.1.2",
|
|
90
|
-
"webdriverio": "^8.40.6",
|
|
91
87
|
"webpack": "^5.90.1",
|
|
92
88
|
"webpack-cli": "^5.1.4",
|
|
93
89
|
"webpack-node-externals": "^3.0.0"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type BucketStorageAdapter, type PowerSyncBackendConnector, type PowerSyncCloseOptions, type PowerSyncConnectionOptions, AbstractPowerSyncDatabase, DBAdapter, PowerSyncDatabaseOptions, PowerSyncDatabaseOptionsWithDBAdapter, PowerSyncDatabaseOptionsWithOpenFactory, PowerSyncDatabaseOptionsWithSettings, StreamingSyncImplementation } from '@powersync/common';
|
|
1
|
+
import { type BucketStorageAdapter, type PowerSyncBackendConnector, type PowerSyncCloseOptions, type PowerSyncConnectionOptions, type RequiredAdditionalConnectionOptions, AbstractPowerSyncDatabase, DBAdapter, PowerSyncDatabaseOptions, PowerSyncDatabaseOptionsWithDBAdapter, PowerSyncDatabaseOptionsWithOpenFactory, PowerSyncDatabaseOptionsWithSettings, StreamingSyncImplementation } from '@powersync/common';
|
|
2
2
|
import { Mutex } from 'async-mutex';
|
|
3
3
|
import { ResolvedWebSQLOpenOptions, WebSQLFlags } from './adapters/web-sql-flags';
|
|
4
4
|
export interface WebPowerSyncFlags extends WebSQLFlags {
|
|
@@ -72,6 +72,6 @@ export declare class PowerSyncDatabase extends AbstractPowerSyncDatabase {
|
|
|
72
72
|
connect(connector: PowerSyncBackendConnector, options?: PowerSyncConnectionOptions): Promise<void>;
|
|
73
73
|
protected generateBucketStorageAdapter(): BucketStorageAdapter;
|
|
74
74
|
protected runExclusive<T>(cb: () => Promise<T>): Promise<any>;
|
|
75
|
-
protected generateSyncStreamImplementation(connector: PowerSyncBackendConnector): StreamingSyncImplementation;
|
|
75
|
+
protected generateSyncStreamImplementation(connector: PowerSyncBackendConnector, options: RequiredAdditionalConnectionOptions): StreamingSyncImplementation;
|
|
76
76
|
}
|
|
77
77
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AbstractPowerSyncDatabase, DEFAULT_POWERSYNC_CLOSE_OPTIONS, isDBAdapter, isSQLOpenFactory, SqliteBucketStorage } from '@powersync/common';
|
|
1
|
+
import { AbstractPowerSyncDatabase, DEFAULT_POWERSYNC_CLOSE_OPTIONS, isDBAdapter, isSQLOpenFactory, SqliteBucketStorage, } from '@powersync/common';
|
|
2
2
|
import { Mutex } from 'async-mutex';
|
|
3
3
|
import { getNavigatorLocks } from '../shared/navigator';
|
|
4
4
|
import { WASQLiteOpenFactory } from './adapters/wa-sqlite/WASQLiteOpenFactory';
|
|
@@ -101,10 +101,12 @@ export class PowerSyncDatabase extends AbstractPowerSyncDatabase {
|
|
|
101
101
|
}
|
|
102
102
|
return getNavigatorLocks().request(`lock-${this.database.name}`, cb);
|
|
103
103
|
}
|
|
104
|
-
generateSyncStreamImplementation(connector) {
|
|
104
|
+
generateSyncStreamImplementation(connector, options) {
|
|
105
105
|
const remote = new WebRemote(connector);
|
|
106
106
|
const syncOptions = {
|
|
107
107
|
...this.options,
|
|
108
|
+
retryDelayMs: options.retryDelayMs,
|
|
109
|
+
crudUploadThrottleMs: options.crudUploadThrottleMs,
|
|
108
110
|
flags: this.resolvedFlags,
|
|
109
111
|
adapter: this.bucketStorageAdapter,
|
|
110
112
|
remote,
|
|
@@ -20,6 +20,8 @@ export type WrappedWorkerConnectionOptions<Config extends ResolvedWebSQLOpenOpti
|
|
|
20
20
|
*/
|
|
21
21
|
export declare class WorkerWrappedAsyncDatabaseConnection<Config extends ResolvedWebSQLOpenOptions = ResolvedWebSQLOpenOptions> implements AsyncDatabaseConnection {
|
|
22
22
|
protected options: WrappedWorkerConnectionOptions<Config>;
|
|
23
|
+
protected releaseSharedConnectionLock: (() => void) | null;
|
|
24
|
+
protected lockAbortController: AbortController;
|
|
23
25
|
constructor(options: WrappedWorkerConnectionOptions<Config>);
|
|
24
26
|
protected get baseConnection(): AsyncDatabaseConnection<ResolvedWebSQLOpenOptions>;
|
|
25
27
|
init(): Promise<void>;
|
|
@@ -5,8 +5,12 @@ import * as Comlink from 'comlink';
|
|
|
5
5
|
*/
|
|
6
6
|
export class WorkerWrappedAsyncDatabaseConnection {
|
|
7
7
|
options;
|
|
8
|
+
releaseSharedConnectionLock;
|
|
9
|
+
lockAbortController;
|
|
8
10
|
constructor(options) {
|
|
9
11
|
this.options = options;
|
|
12
|
+
this.releaseSharedConnectionLock = null;
|
|
13
|
+
this.lockAbortController = new AbortController();
|
|
10
14
|
}
|
|
11
15
|
get baseConnection() {
|
|
12
16
|
return this.options.baseConnection;
|
|
@@ -19,6 +23,30 @@ export class WorkerWrappedAsyncDatabaseConnection {
|
|
|
19
23
|
*/
|
|
20
24
|
async shareConnection() {
|
|
21
25
|
const { identifier, remote } = this.options;
|
|
26
|
+
/**
|
|
27
|
+
* Hold a navigator lock in order to avoid features such as Chrome's frozen tabs,
|
|
28
|
+
* or Edge's sleeping tabs from pausing the thread for this connection.
|
|
29
|
+
* This promise resolves once a lock is obtained.
|
|
30
|
+
* This lock will be held as long as this connection is open.
|
|
31
|
+
* The `shareConnection` method should not be called on multiple tabs concurrently.
|
|
32
|
+
*/
|
|
33
|
+
await new Promise((lockObtained) => navigator.locks
|
|
34
|
+
.request(`shared-connection-${this.options.identifier}`, {
|
|
35
|
+
signal: this.lockAbortController.signal
|
|
36
|
+
}, async () => {
|
|
37
|
+
lockObtained();
|
|
38
|
+
// Free the lock when the connection is already closed.
|
|
39
|
+
if (this.lockAbortController.signal.aborted) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Hold the lock while the shared connection is in use.
|
|
43
|
+
await new Promise((releaseLock) => {
|
|
44
|
+
// We can use the resolver to free the lock
|
|
45
|
+
this.releaseSharedConnectionLock = releaseLock;
|
|
46
|
+
});
|
|
47
|
+
})
|
|
48
|
+
// We aren't concerned with errors here
|
|
49
|
+
.catch(() => { }));
|
|
22
50
|
const newPort = await remote[Comlink.createEndpoint]();
|
|
23
51
|
return { port: newPort, identifier };
|
|
24
52
|
}
|
|
@@ -30,6 +58,9 @@ export class WorkerWrappedAsyncDatabaseConnection {
|
|
|
30
58
|
return this.baseConnection.registerOnTableChange(Comlink.proxy(callback));
|
|
31
59
|
}
|
|
32
60
|
async close() {
|
|
61
|
+
// Abort any pending lock requests.
|
|
62
|
+
this.lockAbortController.abort();
|
|
63
|
+
this.releaseSharedConnectionLock?.();
|
|
33
64
|
await this.baseConnection.close();
|
|
34
65
|
this.options.remote[Comlink.releaseProxy]();
|
|
35
66
|
this.options.onClose?.();
|
|
@@ -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;
|