@powersync/web 0.0.0-dev-20260202162549 → 0.0.0-dev-20260202163643
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/0b19af1befc07ce338dd.wasm +0 -0
- package/dist/2632c3bda9473da74fd5.wasm +0 -0
- package/dist/64f5351ba3784bfe2f3e.wasm +0 -0
- package/dist/9318ca94aac4d0fe0135.wasm +0 -0
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-89f0ba.index.umd.js +1878 -0
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-89f0ba.index.umd.js.map +1 -0
- package/dist/_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapps_wa-sqlite_src_example-2530150.index.umd.js +555 -0
- package/dist/_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapps_wa-sqlite_src_example-2530150.index.umd.js.map +1 -0
- package/dist/_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapps_wa-sqlite_src_example-2530151.index.umd.js +555 -0
- package/dist/_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapps_wa-sqlite_src_example-2530151.index.umd.js.map +1 -0
- package/dist/index.umd.js +8253 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/worker/SharedSyncImplementation.umd.js +19059 -0
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -0
- package/dist/worker/WASQLiteDB.umd.js +17736 -0
- package/dist/worker/WASQLiteDB.umd.js.map +1 -0
- package/dist/worker/node_modules_pnpm_bson_6_10_4_node_modules_bson_lib_bson_mjs.umd.js +4646 -0
- package/dist/worker/node_modules_pnpm_bson_6_10_4_node_modules_bson_lib_bson_mjs.umd.js.map +1 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-3a94cf.umd.js +44 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-3a94cf.umd.js.map +1 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-868779.umd.js +44 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-868779.umd.js.map +1 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_dist_wa-sqli-f60d0d.umd.js +44 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_dist_wa-sqli-f60d0d.umd.js.map +1 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js +44 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js.map +1 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_src_examples-0d2437.umd.js +2478 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_src_examples-0d2437.umd.js.map +1 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_src_examples-1d4e74.umd.js +1820 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_src_examples-1d4e74.umd.js.map +1 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_src_examples-3622cf.umd.js +1681 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_4_1_node_modules_journeyapps_wa-sqlite_src_examples-3622cf.umd.js.map +1 -0
- package/lib/package.json +95 -0
- package/lib/src/attachments/IndexDBFileSystemAdapter.d.ts +25 -0
- package/lib/src/attachments/IndexDBFileSystemAdapter.js +104 -0
- package/lib/src/db/NavigatorTriggerClaimManager.d.ts +6 -0
- package/lib/src/db/NavigatorTriggerClaimManager.js +20 -0
- package/lib/src/db/PowerSyncDatabase.d.ts +79 -0
- package/lib/src/db/PowerSyncDatabase.js +166 -0
- package/lib/src/db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.d.ts +23 -0
- package/lib/src/db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.js +26 -0
- package/lib/src/db/adapters/AbstractWebSQLOpenFactory.d.ts +17 -0
- package/lib/src/db/adapters/AbstractWebSQLOpenFactory.js +33 -0
- package/lib/src/db/adapters/AsyncDatabaseConnection.d.ts +49 -0
- package/lib/src/db/adapters/AsyncDatabaseConnection.js +1 -0
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.d.ts +109 -0
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.js +401 -0
- package/lib/src/db/adapters/SSRDBAdapter.d.ts +31 -0
- package/lib/src/db/adapters/SSRDBAdapter.js +69 -0
- package/lib/src/db/adapters/WebDBAdapter.d.ts +20 -0
- package/lib/src/db/adapters/WebDBAdapter.js +1 -0
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.d.ts +59 -0
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.js +147 -0
- package/lib/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.d.ts +12 -0
- package/lib/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.js +19 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.d.ts +155 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.js +401 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.d.ts +32 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.js +49 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.d.ts +23 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +96 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLitePowerSyncDatabaseOpenFactory.d.ts +15 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLitePowerSyncDatabaseOpenFactory.js +21 -0
- package/lib/src/db/adapters/web-sql-flags.d.ts +87 -0
- package/lib/src/db/adapters/web-sql-flags.js +36 -0
- package/lib/src/db/sync/SSRWebStreamingSyncImplementation.d.ts +48 -0
- package/lib/src/db/sync/SSRWebStreamingSyncImplementation.js +65 -0
- package/lib/src/db/sync/SharedWebStreamingSyncImplementation.d.ts +57 -0
- package/lib/src/db/sync/SharedWebStreamingSyncImplementation.js +237 -0
- package/lib/src/db/sync/WebRemote.d.ts +9 -0
- package/lib/src/db/sync/WebRemote.js +44 -0
- package/lib/src/db/sync/WebStreamingSyncImplementation.d.ts +13 -0
- package/lib/src/db/sync/WebStreamingSyncImplementation.js +18 -0
- package/lib/src/db/sync/userAgent.d.ts +17 -0
- package/lib/src/db/sync/userAgent.js +64 -0
- package/lib/src/index.d.ts +14 -0
- package/lib/src/index.js +14 -0
- package/lib/src/shared/navigator.d.ts +1 -0
- package/lib/src/shared/navigator.js +6 -0
- package/lib/src/worker/db/SharedWASQLiteConnection.d.ts +42 -0
- package/lib/src/worker/db/SharedWASQLiteConnection.js +90 -0
- package/lib/src/worker/db/WASQLiteDB.worker.d.ts +4 -0
- package/lib/src/worker/db/WASQLiteDB.worker.js +69 -0
- package/lib/src/worker/db/WorkerWASQLiteConnection.d.ts +9 -0
- package/lib/src/worker/db/WorkerWASQLiteConnection.js +12 -0
- package/lib/src/worker/db/open-worker-database.d.ts +14 -0
- package/lib/src/worker/db/open-worker-database.js +52 -0
- package/lib/src/worker/sync/AbstractSharedSyncClientProvider.d.ts +19 -0
- package/lib/src/worker/sync/AbstractSharedSyncClientProvider.js +5 -0
- package/lib/src/worker/sync/BroadcastLogger.d.ts +47 -0
- package/lib/src/worker/sync/BroadcastLogger.js +128 -0
- package/lib/src/worker/sync/SharedSyncImplementation.d.ts +137 -0
- package/lib/src/worker/sync/SharedSyncImplementation.js +495 -0
- package/lib/src/worker/sync/SharedSyncImplementation.worker.d.ts +1 -0
- package/lib/src/worker/sync/SharedSyncImplementation.worker.js +11 -0
- package/lib/src/worker/sync/WorkerClient.d.ts +31 -0
- package/lib/src/worker/sync/WorkerClient.js +84 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { type ILogger, SQLOpenOptions } from '@powersync/common';
|
|
2
|
+
/**
|
|
3
|
+
* Common settings used when creating SQL connections on web.
|
|
4
|
+
*/
|
|
5
|
+
export interface WebSQLFlags {
|
|
6
|
+
/**
|
|
7
|
+
* Broadcast logs from shared workers, such as the shared sync worker,
|
|
8
|
+
* to individual tabs. This defaults to true.
|
|
9
|
+
*/
|
|
10
|
+
broadcastLogs?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* SQLite operations are currently not supported in SSR mode.
|
|
13
|
+
* A warning will be logged if attempting to use SQLite in SSR.
|
|
14
|
+
* Setting this to `true` will disabled the warning above.
|
|
15
|
+
*/
|
|
16
|
+
disableSSRWarning?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Enables multi tab support
|
|
19
|
+
*/
|
|
20
|
+
enableMultiTabs?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The SQLite connection is often executed through a web worker
|
|
23
|
+
* in order to offload computation. This can be used to manually
|
|
24
|
+
* disable the use of web workers in environments where web workers
|
|
25
|
+
* might be unstable.
|
|
26
|
+
*/
|
|
27
|
+
useWebWorker?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Open in SSR placeholder mode. DB operations and Sync operations will be a No-op
|
|
30
|
+
*/
|
|
31
|
+
ssrMode?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export type ResolvedWebSQLFlags = Required<WebSQLFlags>;
|
|
34
|
+
export interface ResolvedWebSQLOpenOptions extends SQLOpenOptions {
|
|
35
|
+
flags: ResolvedWebSQLFlags;
|
|
36
|
+
/**
|
|
37
|
+
* Where to store SQLite temporary files. Defaults to 'MEMORY'.
|
|
38
|
+
* Setting this to `FILESYSTEM` can cause issues with larger queries or datasets.
|
|
39
|
+
*/
|
|
40
|
+
temporaryStorage: TemporaryStorageOption;
|
|
41
|
+
cacheSizeKb: number;
|
|
42
|
+
/**
|
|
43
|
+
* Encryption key for the database.
|
|
44
|
+
* If set, the database will be encrypted using ChaCha20.
|
|
45
|
+
*/
|
|
46
|
+
encryptionKey?: string;
|
|
47
|
+
}
|
|
48
|
+
export declare enum TemporaryStorageOption {
|
|
49
|
+
MEMORY = "memory",
|
|
50
|
+
FILESYSTEM = "file"
|
|
51
|
+
}
|
|
52
|
+
export declare const DEFAULT_CACHE_SIZE_KB: number;
|
|
53
|
+
/**
|
|
54
|
+
* Options for opening a Web SQL connection
|
|
55
|
+
*/
|
|
56
|
+
export interface WebSQLOpenFactoryOptions extends SQLOpenOptions {
|
|
57
|
+
flags?: WebSQLFlags;
|
|
58
|
+
/**
|
|
59
|
+
* Allows you to override the default wasqlite db worker.
|
|
60
|
+
*
|
|
61
|
+
* You can either provide a path to the worker script
|
|
62
|
+
* or a factory method that returns a worker.
|
|
63
|
+
*/
|
|
64
|
+
worker?: string | URL | ((options: ResolvedWebSQLOpenOptions) => Worker | SharedWorker);
|
|
65
|
+
logger?: ILogger;
|
|
66
|
+
/**
|
|
67
|
+
* Where to store SQLite temporary files. Defaults to 'MEMORY'.
|
|
68
|
+
* Setting this to `FILESYSTEM` can cause issues with larger queries or datasets.
|
|
69
|
+
*
|
|
70
|
+
* For details, see: https://www.sqlite.org/pragma.html#pragma_temp_store
|
|
71
|
+
*/
|
|
72
|
+
temporaryStorage?: TemporaryStorageOption;
|
|
73
|
+
/**
|
|
74
|
+
* Maximum SQLite cache size. Defaults to 50MB.
|
|
75
|
+
*
|
|
76
|
+
* For details, see: https://www.sqlite.org/pragma.html#pragma_cache_size
|
|
77
|
+
*/
|
|
78
|
+
cacheSizeKb?: number;
|
|
79
|
+
/**
|
|
80
|
+
* Encryption key for the database.
|
|
81
|
+
* If set, the database will be encrypted using ChaCha20.
|
|
82
|
+
*/
|
|
83
|
+
encryptionKey?: string;
|
|
84
|
+
}
|
|
85
|
+
export declare function isServerSide(): boolean;
|
|
86
|
+
export declare const DEFAULT_WEB_SQL_FLAGS: ResolvedWebSQLFlags;
|
|
87
|
+
export declare function resolveWebSQLFlags(flags?: WebSQLFlags): ResolvedWebSQLFlags;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export var TemporaryStorageOption;
|
|
2
|
+
(function (TemporaryStorageOption) {
|
|
3
|
+
TemporaryStorageOption["MEMORY"] = "memory";
|
|
4
|
+
TemporaryStorageOption["FILESYSTEM"] = "file";
|
|
5
|
+
})(TemporaryStorageOption || (TemporaryStorageOption = {}));
|
|
6
|
+
export const DEFAULT_CACHE_SIZE_KB = 50 * 1024;
|
|
7
|
+
export function isServerSide() {
|
|
8
|
+
return typeof window == 'undefined';
|
|
9
|
+
}
|
|
10
|
+
export const DEFAULT_WEB_SQL_FLAGS = {
|
|
11
|
+
broadcastLogs: true,
|
|
12
|
+
disableSSRWarning: false,
|
|
13
|
+
ssrMode: isServerSide(),
|
|
14
|
+
/**
|
|
15
|
+
* Multiple tabs are by default not supported on Android, iOS and Safari.
|
|
16
|
+
* Other platforms will have multiple tabs enabled by default.
|
|
17
|
+
*/
|
|
18
|
+
enableMultiTabs: typeof globalThis.navigator !== 'undefined' && // For SSR purposes
|
|
19
|
+
typeof SharedWorker !== 'undefined' &&
|
|
20
|
+
!navigator.userAgent.match(/(Android|iPhone|iPod|iPad)/i) &&
|
|
21
|
+
!window.safari,
|
|
22
|
+
useWebWorker: true
|
|
23
|
+
};
|
|
24
|
+
export function resolveWebSQLFlags(flags) {
|
|
25
|
+
const resolvedFlags = {
|
|
26
|
+
...DEFAULT_WEB_SQL_FLAGS,
|
|
27
|
+
...(flags ?? {})
|
|
28
|
+
};
|
|
29
|
+
if (typeof flags?.enableMultiTabs != 'undefined') {
|
|
30
|
+
resolvedFlags.enableMultiTabs = flags.enableMultiTabs;
|
|
31
|
+
}
|
|
32
|
+
if (flags?.useWebWorker === false) {
|
|
33
|
+
resolvedFlags.enableMultiTabs = false;
|
|
34
|
+
}
|
|
35
|
+
return resolvedFlags;
|
|
36
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { AbstractStreamingSyncImplementationOptions, BaseObserver, LockOptions, PowerSyncConnectionOptions, StreamingSyncImplementation, SyncStatus, SyncStatusOptions } from '@powersync/common';
|
|
2
|
+
import { Mutex } from 'async-mutex';
|
|
3
|
+
export declare class SSRStreamingSyncImplementation extends BaseObserver implements StreamingSyncImplementation {
|
|
4
|
+
syncMutex: Mutex;
|
|
5
|
+
crudMutex: Mutex;
|
|
6
|
+
isConnected: boolean;
|
|
7
|
+
lastSyncedAt?: Date | undefined;
|
|
8
|
+
syncStatus: SyncStatus;
|
|
9
|
+
constructor(options: AbstractStreamingSyncImplementationOptions);
|
|
10
|
+
obtainLock<T>(lockOptions: LockOptions<T>): Promise<T>;
|
|
11
|
+
/**
|
|
12
|
+
* This is a no-op in SSR mode
|
|
13
|
+
*/
|
|
14
|
+
connect(options?: PowerSyncConnectionOptions): Promise<void>;
|
|
15
|
+
dispose(): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* This is a no-op in SSR mode
|
|
18
|
+
*/
|
|
19
|
+
disconnect(): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* This SSR Mode implementation is immediately ready.
|
|
22
|
+
*/
|
|
23
|
+
waitForReady(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* This will never resolve in SSR Mode.
|
|
26
|
+
*/
|
|
27
|
+
waitForStatus(status: SyncStatusOptions): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* This will never resolve in SSR Mode.
|
|
30
|
+
*/
|
|
31
|
+
waitUntilStatusMatches(_predicate: (status: SyncStatus) => boolean): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Returns a placeholder checkpoint. This should not be used.
|
|
34
|
+
*/
|
|
35
|
+
getWriteCheckpoint(): Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* The SSR mode adapter will never complete syncing.
|
|
38
|
+
*/
|
|
39
|
+
hasCompletedSync(): Promise<boolean>;
|
|
40
|
+
/**
|
|
41
|
+
* This is a no-op in SSR mode.
|
|
42
|
+
*/
|
|
43
|
+
triggerCrudUpload(): void;
|
|
44
|
+
/**
|
|
45
|
+
* No-op in SSR mode.
|
|
46
|
+
*/
|
|
47
|
+
updateSubscriptions(): void;
|
|
48
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { BaseObserver, LockType, SyncStatus } from '@powersync/common';
|
|
2
|
+
import { Mutex } from 'async-mutex';
|
|
3
|
+
export class SSRStreamingSyncImplementation extends BaseObserver {
|
|
4
|
+
syncMutex;
|
|
5
|
+
crudMutex;
|
|
6
|
+
isConnected;
|
|
7
|
+
lastSyncedAt;
|
|
8
|
+
syncStatus;
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super();
|
|
11
|
+
this.syncMutex = new Mutex();
|
|
12
|
+
this.crudMutex = new Mutex();
|
|
13
|
+
this.syncStatus = new SyncStatus({});
|
|
14
|
+
this.isConnected = false;
|
|
15
|
+
}
|
|
16
|
+
obtainLock(lockOptions) {
|
|
17
|
+
const mutex = lockOptions.type == LockType.CRUD ? this.crudMutex : this.syncMutex;
|
|
18
|
+
return mutex.runExclusive(lockOptions.callback);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* This is a no-op in SSR mode
|
|
22
|
+
*/
|
|
23
|
+
async connect(options) { }
|
|
24
|
+
async dispose() { }
|
|
25
|
+
/**
|
|
26
|
+
* This is a no-op in SSR mode
|
|
27
|
+
*/
|
|
28
|
+
async disconnect() { }
|
|
29
|
+
/**
|
|
30
|
+
* This SSR Mode implementation is immediately ready.
|
|
31
|
+
*/
|
|
32
|
+
async waitForReady() { }
|
|
33
|
+
/**
|
|
34
|
+
* This will never resolve in SSR Mode.
|
|
35
|
+
*/
|
|
36
|
+
async waitForStatus(status) {
|
|
37
|
+
return this.waitUntilStatusMatches(() => false);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* This will never resolve in SSR Mode.
|
|
41
|
+
*/
|
|
42
|
+
waitUntilStatusMatches(_predicate) {
|
|
43
|
+
return new Promise(() => { });
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Returns a placeholder checkpoint. This should not be used.
|
|
47
|
+
*/
|
|
48
|
+
async getWriteCheckpoint() {
|
|
49
|
+
return '1';
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The SSR mode adapter will never complete syncing.
|
|
53
|
+
*/
|
|
54
|
+
async hasCompletedSync() {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* This is a no-op in SSR mode.
|
|
59
|
+
*/
|
|
60
|
+
triggerCrudUpload() { }
|
|
61
|
+
/**
|
|
62
|
+
* No-op in SSR mode.
|
|
63
|
+
*/
|
|
64
|
+
updateSubscriptions() { }
|
|
65
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { PowerSyncConnectionOptions, PowerSyncCredentials, SubscribedStream, SyncStatusOptions } from '@powersync/common';
|
|
2
|
+
import * as Comlink from 'comlink';
|
|
3
|
+
import { AbstractSharedSyncClientProvider } from '../../worker/sync/AbstractSharedSyncClientProvider.js';
|
|
4
|
+
import { WorkerClient } from '../../worker/sync/WorkerClient.js';
|
|
5
|
+
import { WebDBAdapter } from '../adapters/WebDBAdapter.js';
|
|
6
|
+
import { WebStreamingSyncImplementation, WebStreamingSyncImplementationOptions } from './WebStreamingSyncImplementation.js';
|
|
7
|
+
/**
|
|
8
|
+
* The shared worker will trigger methods on this side of the message port
|
|
9
|
+
* via this client provider.
|
|
10
|
+
*/
|
|
11
|
+
declare class SharedSyncClientProvider extends AbstractSharedSyncClientProvider {
|
|
12
|
+
protected options: WebStreamingSyncImplementationOptions;
|
|
13
|
+
statusChanged: (status: SyncStatusOptions) => void;
|
|
14
|
+
protected webDB: WebDBAdapter;
|
|
15
|
+
constructor(options: WebStreamingSyncImplementationOptions, statusChanged: (status: SyncStatusOptions) => void, webDB: WebDBAdapter);
|
|
16
|
+
getDBWorkerPort(): Promise<MessagePort>;
|
|
17
|
+
invalidateCredentials(): void;
|
|
18
|
+
fetchCredentials(): Promise<PowerSyncCredentials | null>;
|
|
19
|
+
uploadCrud(): Promise<void>;
|
|
20
|
+
get logger(): import("@powersync/common").ILogger | undefined;
|
|
21
|
+
trace(...x: any[]): void;
|
|
22
|
+
debug(...x: any[]): void;
|
|
23
|
+
info(...x: any[]): void;
|
|
24
|
+
log(...x: any[]): void;
|
|
25
|
+
warn(...x: any[]): void;
|
|
26
|
+
error(...x: any[]): void;
|
|
27
|
+
time(label: string): void;
|
|
28
|
+
timeEnd(label: string): void;
|
|
29
|
+
}
|
|
30
|
+
export interface SharedWebStreamingSyncImplementationOptions extends WebStreamingSyncImplementationOptions {
|
|
31
|
+
db: WebDBAdapter;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The local part of the sync implementation on the web, which talks to a sync implementation hosted in a shared worker.
|
|
35
|
+
*/
|
|
36
|
+
export declare class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplementation {
|
|
37
|
+
protected syncManager: Comlink.Remote<WorkerClient>;
|
|
38
|
+
protected clientProvider: SharedSyncClientProvider;
|
|
39
|
+
protected messagePort: MessagePort;
|
|
40
|
+
protected isInitialized: Promise<void>;
|
|
41
|
+
protected dbAdapter: WebDBAdapter;
|
|
42
|
+
private abortOnClose;
|
|
43
|
+
constructor(options: SharedWebStreamingSyncImplementationOptions);
|
|
44
|
+
protected _init(): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Starts the sync process, this effectively acts as a call to
|
|
47
|
+
* `connect` if not yet connected.
|
|
48
|
+
*/
|
|
49
|
+
connect(options?: PowerSyncConnectionOptions): Promise<void>;
|
|
50
|
+
disconnect(): Promise<void>;
|
|
51
|
+
getWriteCheckpoint(): Promise<string>;
|
|
52
|
+
hasCompletedSync(): Promise<boolean>;
|
|
53
|
+
dispose(): Promise<void>;
|
|
54
|
+
waitForReady(): Promise<void>;
|
|
55
|
+
updateSubscriptions(subscriptions: SubscribedStream[]): void;
|
|
56
|
+
}
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import * as Comlink from 'comlink';
|
|
2
|
+
import { getNavigatorLocks } from '../../shared/navigator.js';
|
|
3
|
+
import { AbstractSharedSyncClientProvider } from '../../worker/sync/AbstractSharedSyncClientProvider.js';
|
|
4
|
+
import { SharedSyncClientEvent } from '../../worker/sync/SharedSyncImplementation.js';
|
|
5
|
+
import { DEFAULT_CACHE_SIZE_KB, TemporaryStorageOption, resolveWebSQLFlags } from '../adapters/web-sql-flags.js';
|
|
6
|
+
import { WebStreamingSyncImplementation } from './WebStreamingSyncImplementation.js';
|
|
7
|
+
/**
|
|
8
|
+
* The shared worker will trigger methods on this side of the message port
|
|
9
|
+
* via this client provider.
|
|
10
|
+
*/
|
|
11
|
+
class SharedSyncClientProvider extends AbstractSharedSyncClientProvider {
|
|
12
|
+
options;
|
|
13
|
+
statusChanged;
|
|
14
|
+
webDB;
|
|
15
|
+
constructor(options, statusChanged, webDB) {
|
|
16
|
+
super();
|
|
17
|
+
this.options = options;
|
|
18
|
+
this.statusChanged = statusChanged;
|
|
19
|
+
this.webDB = webDB;
|
|
20
|
+
}
|
|
21
|
+
async getDBWorkerPort() {
|
|
22
|
+
const { port } = await this.webDB.shareConnection();
|
|
23
|
+
return Comlink.transfer(port, [port]);
|
|
24
|
+
}
|
|
25
|
+
invalidateCredentials() {
|
|
26
|
+
this.options.remote.invalidateCredentials();
|
|
27
|
+
}
|
|
28
|
+
async fetchCredentials() {
|
|
29
|
+
const credentials = await this.options.remote.getCredentials();
|
|
30
|
+
if (credentials == null) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The credentials need to be serializable.
|
|
35
|
+
* Users might extend [PowerSyncCredentials] to contain
|
|
36
|
+
* items which are not serializable.
|
|
37
|
+
* This returns only the essential fields.
|
|
38
|
+
*/
|
|
39
|
+
return {
|
|
40
|
+
endpoint: credentials.endpoint,
|
|
41
|
+
token: credentials.token
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async uploadCrud() {
|
|
45
|
+
/**
|
|
46
|
+
* Don't return anything here, just incase something which is not
|
|
47
|
+
* serializable is returned from the `uploadCrud` function.
|
|
48
|
+
*/
|
|
49
|
+
await this.options.uploadCrud();
|
|
50
|
+
}
|
|
51
|
+
get logger() {
|
|
52
|
+
return this.options.logger;
|
|
53
|
+
}
|
|
54
|
+
trace(...x) {
|
|
55
|
+
this.logger?.trace(...x);
|
|
56
|
+
}
|
|
57
|
+
debug(...x) {
|
|
58
|
+
this.logger?.debug(...x);
|
|
59
|
+
}
|
|
60
|
+
info(...x) {
|
|
61
|
+
this.logger?.info(...x);
|
|
62
|
+
}
|
|
63
|
+
log(...x) {
|
|
64
|
+
this.logger?.log(...x);
|
|
65
|
+
}
|
|
66
|
+
warn(...x) {
|
|
67
|
+
this.logger?.warn(...x);
|
|
68
|
+
}
|
|
69
|
+
error(...x) {
|
|
70
|
+
this.logger?.error(...x);
|
|
71
|
+
}
|
|
72
|
+
time(label) {
|
|
73
|
+
this.logger?.time(label);
|
|
74
|
+
}
|
|
75
|
+
timeEnd(label) {
|
|
76
|
+
this.logger?.timeEnd(label);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The local part of the sync implementation on the web, which talks to a sync implementation hosted in a shared worker.
|
|
81
|
+
*/
|
|
82
|
+
export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplementation {
|
|
83
|
+
syncManager;
|
|
84
|
+
clientProvider;
|
|
85
|
+
messagePort;
|
|
86
|
+
isInitialized;
|
|
87
|
+
dbAdapter;
|
|
88
|
+
abortOnClose = new AbortController();
|
|
89
|
+
constructor(options) {
|
|
90
|
+
super(options);
|
|
91
|
+
this.dbAdapter = options.db;
|
|
92
|
+
/**
|
|
93
|
+
* Configure or connect to the shared sync worker.
|
|
94
|
+
* This worker will manage all syncing operations remotely.
|
|
95
|
+
*/
|
|
96
|
+
const resolvedWorkerOptions = {
|
|
97
|
+
dbFilename: this.options.identifier,
|
|
98
|
+
temporaryStorage: TemporaryStorageOption.MEMORY,
|
|
99
|
+
cacheSizeKb: DEFAULT_CACHE_SIZE_KB,
|
|
100
|
+
...options,
|
|
101
|
+
flags: resolveWebSQLFlags(options.flags)
|
|
102
|
+
};
|
|
103
|
+
const syncWorker = options.sync?.worker;
|
|
104
|
+
if (syncWorker) {
|
|
105
|
+
if (typeof syncWorker === 'function') {
|
|
106
|
+
this.messagePort = syncWorker(resolvedWorkerOptions).port;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
this.messagePort = new SharedWorker(`${syncWorker}`, {
|
|
110
|
+
/* @vite-ignore */
|
|
111
|
+
name: `shared-sync-${this.webOptions.identifier}`
|
|
112
|
+
}).port;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
this.messagePort = new SharedWorker(new URL('../../worker/sync/SharedSyncImplementation.worker.js', import.meta.url), {
|
|
117
|
+
/* @vite-ignore */
|
|
118
|
+
name: `shared-sync-${this.webOptions.identifier}`,
|
|
119
|
+
type: 'module'
|
|
120
|
+
}).port;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Pass along any sync status updates to this listener
|
|
124
|
+
*/
|
|
125
|
+
this.clientProvider = new SharedSyncClientProvider(this.webOptions, (status) => {
|
|
126
|
+
this.updateSyncStatus(status);
|
|
127
|
+
}, options.db);
|
|
128
|
+
this.syncManager = Comlink.wrap(this.messagePort);
|
|
129
|
+
/**
|
|
130
|
+
* The sync worker will call this client provider when it needs
|
|
131
|
+
* to fetch credentials or upload data.
|
|
132
|
+
* This performs bi-directional method calling.
|
|
133
|
+
*/
|
|
134
|
+
Comlink.expose(this.clientProvider, this.messagePort);
|
|
135
|
+
this.syncManager.setLogLevel(this.logger.getLevel());
|
|
136
|
+
this.triggerCrudUpload = this.syncManager.triggerCrudUpload;
|
|
137
|
+
/**
|
|
138
|
+
* Opens MessagePort to the existing shared DB worker.
|
|
139
|
+
* The sync worker cannot initiate connections directly to the
|
|
140
|
+
* DB worker, but a port to the DB worker can be transferred to the
|
|
141
|
+
* sync worker.
|
|
142
|
+
*/
|
|
143
|
+
this.isInitialized = this._init();
|
|
144
|
+
}
|
|
145
|
+
async _init() {
|
|
146
|
+
/**
|
|
147
|
+
* The general flow of initialization is:
|
|
148
|
+
* - The client requests a unique navigator lock.
|
|
149
|
+
* - Once the lock is acquired, we register the lock with the shared worker.
|
|
150
|
+
* - The shared worker can then request the same lock. The client has been closed if the shared worker can acquire the lock.
|
|
151
|
+
* - Once the shared worker knows the client's lock, we can guarentee that the shared worker will detect if the client has been closed.
|
|
152
|
+
* - This makes the client safe for the shared worker to use.
|
|
153
|
+
* - The client is only added to the SharedSyncImplementation once the lock has been registered.
|
|
154
|
+
* This ensures we don't ever keep track of dead clients (tabs that closed before the lock was registered).
|
|
155
|
+
* - The client side lock is held until the client is disposed.
|
|
156
|
+
* - We resolve the top-level promise after the lock has been registered with the shared worker.
|
|
157
|
+
* - The client sends the params to the shared worker after locks have been registered.
|
|
158
|
+
*/
|
|
159
|
+
await new Promise((resolve) => {
|
|
160
|
+
// Request a random lock until this client is disposed. The name of the lock is sent to the shared worker, which
|
|
161
|
+
// will also attempt to acquire it. Since the lock is returned when the tab is closed, this allows the share worker
|
|
162
|
+
// to free resources associated with this tab.
|
|
163
|
+
// We take hold of this lock as soon-as-possible in order to cater for potentially closed tabs.
|
|
164
|
+
getNavigatorLocks().request(`tab-close-signal-${crypto.randomUUID()}`, async (lock) => {
|
|
165
|
+
if (this.abortOnClose.signal.aborted) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// Awaiting here ensures the worker is waiting for the lock
|
|
169
|
+
await this.syncManager.addLockBasedCloseSignal(lock.name);
|
|
170
|
+
// The lock has been registered, we can continue with the initialization
|
|
171
|
+
resolve();
|
|
172
|
+
await new Promise((r) => {
|
|
173
|
+
this.abortOnClose.signal.onabort = () => r();
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
const { crudUploadThrottleMs, identifier, retryDelayMs } = this.options;
|
|
178
|
+
const flags = { ...this.webOptions.flags, workers: undefined };
|
|
179
|
+
await this.syncManager.setParams({
|
|
180
|
+
dbParams: this.dbAdapter.getConfiguration(),
|
|
181
|
+
streamOptions: {
|
|
182
|
+
crudUploadThrottleMs,
|
|
183
|
+
identifier,
|
|
184
|
+
retryDelayMs,
|
|
185
|
+
flags: flags
|
|
186
|
+
}
|
|
187
|
+
}, this.options.subscriptions);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Starts the sync process, this effectively acts as a call to
|
|
191
|
+
* `connect` if not yet connected.
|
|
192
|
+
*/
|
|
193
|
+
async connect(options) {
|
|
194
|
+
await this.waitForReady();
|
|
195
|
+
return this.syncManager.connect(options);
|
|
196
|
+
}
|
|
197
|
+
async disconnect() {
|
|
198
|
+
await this.waitForReady();
|
|
199
|
+
return this.syncManager.disconnect();
|
|
200
|
+
}
|
|
201
|
+
async getWriteCheckpoint() {
|
|
202
|
+
await this.waitForReady();
|
|
203
|
+
return this.syncManager.getWriteCheckpoint();
|
|
204
|
+
}
|
|
205
|
+
async hasCompletedSync() {
|
|
206
|
+
return this.syncManager.hasCompletedSync();
|
|
207
|
+
}
|
|
208
|
+
async dispose() {
|
|
209
|
+
await this.waitForReady();
|
|
210
|
+
await new Promise((resolve) => {
|
|
211
|
+
// Listen for the close acknowledgment from the worker
|
|
212
|
+
this.messagePort.addEventListener('message', (event) => {
|
|
213
|
+
const payload = event.data;
|
|
214
|
+
if (payload?.event === SharedSyncClientEvent.CLOSE_ACK) {
|
|
215
|
+
resolve();
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
// Signal the shared worker that this client is closing its connection to the worker
|
|
219
|
+
const closeMessagePayload = {
|
|
220
|
+
event: SharedSyncClientEvent.CLOSE_CLIENT,
|
|
221
|
+
data: {}
|
|
222
|
+
};
|
|
223
|
+
this.messagePort.postMessage(closeMessagePayload);
|
|
224
|
+
});
|
|
225
|
+
await super.dispose();
|
|
226
|
+
this.abortOnClose.abort();
|
|
227
|
+
// Release the proxy
|
|
228
|
+
this.syncManager[Comlink.releaseProxy]();
|
|
229
|
+
this.messagePort.close();
|
|
230
|
+
}
|
|
231
|
+
async waitForReady() {
|
|
232
|
+
return this.isInitialized;
|
|
233
|
+
}
|
|
234
|
+
updateSubscriptions(subscriptions) {
|
|
235
|
+
this.syncManager.updateSubscriptions(subscriptions);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AbstractRemote, AbstractRemoteOptions, BSONImplementation, ILogger, RemoteConnector } from '@powersync/common';
|
|
2
|
+
export declare class WebRemote extends AbstractRemote {
|
|
3
|
+
protected connector: RemoteConnector;
|
|
4
|
+
protected logger: ILogger;
|
|
5
|
+
private _bson;
|
|
6
|
+
constructor(connector: RemoteConnector, logger?: ILogger, options?: Partial<AbstractRemoteOptions>);
|
|
7
|
+
getUserAgent(): string;
|
|
8
|
+
getBSON(): Promise<BSONImplementation>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { AbstractRemote, DEFAULT_REMOTE_LOGGER, FetchImplementationProvider } from '@powersync/common';
|
|
2
|
+
import { getUserAgentInfo } from './userAgent.js';
|
|
3
|
+
/*
|
|
4
|
+
* Depends on browser's implementation of global fetch.
|
|
5
|
+
*/
|
|
6
|
+
class WebFetchProvider extends FetchImplementationProvider {
|
|
7
|
+
getFetch() {
|
|
8
|
+
return fetch.bind(globalThis);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class WebRemote extends AbstractRemote {
|
|
12
|
+
connector;
|
|
13
|
+
logger;
|
|
14
|
+
_bson;
|
|
15
|
+
constructor(connector, logger = DEFAULT_REMOTE_LOGGER, options) {
|
|
16
|
+
super(connector, logger, {
|
|
17
|
+
...(options ?? {}),
|
|
18
|
+
fetchImplementation: options?.fetchImplementation ?? new WebFetchProvider()
|
|
19
|
+
});
|
|
20
|
+
this.connector = connector;
|
|
21
|
+
this.logger = logger;
|
|
22
|
+
}
|
|
23
|
+
getUserAgent() {
|
|
24
|
+
let ua = [super.getUserAgent(), `powersync-web`];
|
|
25
|
+
try {
|
|
26
|
+
ua.push(...getUserAgentInfo());
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
this.logger.warn('Failed to get user agent info', e);
|
|
30
|
+
}
|
|
31
|
+
return ua.join(' ');
|
|
32
|
+
}
|
|
33
|
+
async getBSON() {
|
|
34
|
+
if (this._bson) {
|
|
35
|
+
return this._bson;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Dynamic import to be used only when needed.
|
|
39
|
+
*/
|
|
40
|
+
const { BSON } = await import('bson');
|
|
41
|
+
this._bson = BSON;
|
|
42
|
+
return this._bson;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AbstractStreamingSyncImplementation, AbstractStreamingSyncImplementationOptions, LockOptions } from '@powersync/common';
|
|
2
|
+
import { ResolvedWebSQLOpenOptions, WebSQLFlags } from '../adapters/web-sql-flags.js';
|
|
3
|
+
export interface WebStreamingSyncImplementationOptions extends AbstractStreamingSyncImplementationOptions {
|
|
4
|
+
flags?: WebSQLFlags;
|
|
5
|
+
sync?: {
|
|
6
|
+
worker?: string | URL | ((options: ResolvedWebSQLOpenOptions) => SharedWorker);
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export declare class WebStreamingSyncImplementation extends AbstractStreamingSyncImplementation {
|
|
10
|
+
constructor(options: WebStreamingSyncImplementationOptions);
|
|
11
|
+
get webOptions(): WebStreamingSyncImplementationOptions;
|
|
12
|
+
obtainLock<T>(lockOptions: LockOptions<T>): Promise<T>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AbstractStreamingSyncImplementation, LockType } from '@powersync/common';
|
|
2
|
+
import { getNavigatorLocks } from '../../shared/navigator.js';
|
|
3
|
+
export class WebStreamingSyncImplementation extends AbstractStreamingSyncImplementation {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
// Super will store and provide default values for options
|
|
6
|
+
super(options);
|
|
7
|
+
}
|
|
8
|
+
get webOptions() {
|
|
9
|
+
return this.options;
|
|
10
|
+
}
|
|
11
|
+
async obtainLock(lockOptions) {
|
|
12
|
+
const identifier = `streaming-sync-${lockOptions.type}-${this.webOptions.identifier}`;
|
|
13
|
+
if (lockOptions.type == LockType.SYNC) {
|
|
14
|
+
this.logger.debug('requesting lock for ', identifier);
|
|
15
|
+
}
|
|
16
|
+
return getNavigatorLocks().request(identifier, { signal: lockOptions.signal }, lockOptions.callback);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface NavigatorInfo {
|
|
2
|
+
userAgent: string;
|
|
3
|
+
userAgentData?: {
|
|
4
|
+
brands?: {
|
|
5
|
+
brand: string;
|
|
6
|
+
version: string;
|
|
7
|
+
}[];
|
|
8
|
+
platform?: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Get a minimal representation of browser, version and operating system.
|
|
13
|
+
*
|
|
14
|
+
* The goal is to get enough environemnt info to reproduce issues, but no
|
|
15
|
+
* more.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getUserAgentInfo(nav?: NavigatorInfo): string[];
|