@powersync/web 0.0.0-dev-20260311103504 → 0.0.0-dev-20260503073249
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/2075a31bb151adbb9767.wasm +0 -0
- package/dist/3322bc84de986b63c2cd.wasm +0 -0
- package/dist/8e97452e297be23b5e50.wasm +0 -0
- package/dist/fbc178b70d530e8ce02b.wasm +0 -0
- package/dist/index.umd.js +5341 -1279
- package/dist/index.umd.js.map +1 -1
- package/dist/worker/SharedSyncImplementation.umd.js +1113 -3526
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
- package/dist/worker/WASQLiteDB.umd.js +1397 -1332
- package/dist/worker/WASQLiteDB.umd.js.map +1 -1
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-9af0a7.umd.js +31 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-9af0a7.umd.js.map +1 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-bbf5a9.umd.js +31 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-bbf5a9.umd.js.map +1 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqli-c26e0f.umd.js +31 -0
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqli-cc5fcc.umd.js.map → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqli-c26e0f.umd.js.map} +1 -1
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js +31 -0
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js.map → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js.map} +1 -1
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-2fb422.umd.js +3562 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-2fb422.umd.js.map +1 -0
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_src_examples-0df390.umd.js → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-96fb23.umd.js} +16 -16
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_src_examples-0df390.umd.js.map → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-96fb23.umd.js.map} +1 -1
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_src_examples-151024.umd.js → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-c89911.umd.js} +12 -12
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_src_examples-151024.umd.js.map → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-c89911.umd.js.map} +1 -1
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_src_examples-c01ef0.umd.js → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-ec4eb1.umd.js} +14 -14
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_src_examples-c01ef0.umd.js.map → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-ec4eb1.umd.js.map} +1 -1
- package/lib/package.json +4 -5
- package/lib/src/db/PowerSyncDatabase.d.ts +2 -3
- package/lib/src/db/PowerSyncDatabase.js +3 -12
- package/lib/src/db/adapters/AsyncWebAdapter.d.ts +50 -0
- package/lib/src/db/adapters/AsyncWebAdapter.js +163 -0
- package/lib/src/db/adapters/SSRDBAdapter.d.ts +1 -2
- package/lib/src/db/adapters/SSRDBAdapter.js +5 -6
- package/lib/src/db/adapters/wa-sqlite/ConcurrentConnection.d.ts +56 -0
- package/lib/src/db/adapters/wa-sqlite/ConcurrentConnection.js +121 -0
- package/lib/src/db/adapters/wa-sqlite/DatabaseClient.d.ts +54 -0
- package/lib/src/db/adapters/wa-sqlite/DatabaseClient.js +227 -0
- package/lib/src/db/adapters/wa-sqlite/DatabaseServer.d.ts +47 -0
- package/lib/src/db/adapters/wa-sqlite/DatabaseServer.js +145 -0
- package/lib/src/db/adapters/wa-sqlite/RawSqliteConnection.d.ts +46 -0
- package/lib/src/db/adapters/wa-sqlite/RawSqliteConnection.js +147 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.d.ts +28 -6
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +104 -55
- package/lib/src/db/adapters/wa-sqlite/vfs.d.ts +50 -0
- package/lib/src/db/adapters/wa-sqlite/vfs.js +76 -0
- package/lib/src/db/adapters/web-sql-flags.d.ts +5 -0
- package/lib/src/db/sync/SSRWebStreamingSyncImplementation.d.ts +5 -2
- package/lib/src/db/sync/SSRWebStreamingSyncImplementation.js +6 -3
- package/lib/src/db/sync/SharedWebStreamingSyncImplementation.js +4 -19
- package/lib/src/index.d.ts +1 -4
- package/lib/src/index.js +1 -4
- package/lib/src/shared/tab_close_signal.d.ts +11 -0
- package/lib/src/shared/tab_close_signal.js +26 -0
- package/lib/src/worker/db/MultiDatabaseServer.d.ts +17 -0
- package/lib/src/worker/db/MultiDatabaseServer.js +89 -0
- package/lib/src/worker/db/WASQLiteDB.worker.js +9 -48
- package/lib/src/worker/db/open-worker-database.d.ts +3 -3
- package/lib/src/worker/db/open-worker-database.js +2 -2
- package/lib/src/worker/sync/SharedSyncImplementation.d.ts +5 -6
- package/lib/src/worker/sync/SharedSyncImplementation.js +88 -54
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -6
- package/src/db/PowerSyncDatabase.ts +4 -12
- package/src/db/adapters/AsyncWebAdapter.ts +207 -0
- package/src/db/adapters/SSRDBAdapter.ts +7 -7
- package/src/db/adapters/wa-sqlite/ConcurrentConnection.ts +137 -0
- package/src/db/adapters/wa-sqlite/DatabaseClient.ts +325 -0
- package/src/db/adapters/wa-sqlite/DatabaseServer.ts +203 -0
- package/src/db/adapters/wa-sqlite/RawSqliteConnection.ts +194 -0
- package/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.ts +152 -63
- package/src/db/adapters/wa-sqlite/vfs.ts +96 -0
- package/src/db/adapters/web-sql-flags.ts +6 -0
- package/src/db/sync/SSRWebStreamingSyncImplementation.ts +7 -3
- package/src/db/sync/SharedWebStreamingSyncImplementation.ts +4 -20
- package/src/index.ts +1 -4
- package/src/shared/tab_close_signal.ts +28 -0
- package/src/worker/db/MultiDatabaseServer.ts +107 -0
- package/src/worker/db/WASQLiteDB.worker.ts +10 -57
- package/src/worker/db/open-worker-database.ts +4 -4
- package/src/worker/sync/SharedSyncImplementation.ts +114 -58
- package/dist/26d61ca9f5694d064635.wasm +0 -0
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-89f0ba.index.umd.js +0 -1878
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-89f0ba.index.umd.js.map +0 -1
- package/dist/_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapps_wa-sqlite_src_example-97ebe9.index.umd.js +0 -555
- package/dist/_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapps_wa-sqlite_src_example-97ebe9.index.umd.js.map +0 -1
- package/dist/b4c6283dc473b6b3fd24.wasm +0 -0
- package/dist/c78985091a0b22aaef03.wasm +0 -0
- package/dist/ca59e199e1138b553fad.wasm +0 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-b9c070.umd.js +0 -31
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-b9c070.umd.js.map +0 -1
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-c99c07.umd.js +0 -31
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-c99c07.umd.js.map +0 -1
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqli-cc5fcc.umd.js +0 -31
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js +0 -31
- package/lib/src/db/adapters/AbstractWebSQLOpenFactory.d.ts +0 -17
- package/lib/src/db/adapters/AbstractWebSQLOpenFactory.js +0 -33
- package/lib/src/db/adapters/AsyncDatabaseConnection.d.ts +0 -49
- package/lib/src/db/adapters/AsyncDatabaseConnection.js +0 -1
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.d.ts +0 -109
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.js +0 -401
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.d.ts +0 -59
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.js +0 -147
- package/lib/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.d.ts +0 -12
- package/lib/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.js +0 -19
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.d.ts +0 -155
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.js +0 -401
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.d.ts +0 -32
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.js +0 -49
- package/lib/src/worker/db/SharedWASQLiteConnection.d.ts +0 -42
- package/lib/src/worker/db/SharedWASQLiteConnection.js +0 -90
- package/lib/src/worker/db/WorkerWASQLiteConnection.d.ts +0 -9
- package/lib/src/worker/db/WorkerWASQLiteConnection.js +0 -12
- package/src/db/adapters/AbstractWebSQLOpenFactory.ts +0 -48
- package/src/db/adapters/AsyncDatabaseConnection.ts +0 -55
- package/src/db/adapters/LockedAsyncDatabaseAdapter.ts +0 -490
- package/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.ts +0 -201
- package/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.ts +0 -23
- package/src/db/adapters/wa-sqlite/WASQLiteConnection.ts +0 -497
- package/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.ts +0 -86
- package/src/worker/db/SharedWASQLiteConnection.ts +0 -131
- package/src/worker/db/WorkerWASQLiteConnection.ts +0 -14
|
@@ -1,29 +1,48 @@
|
|
|
1
|
+
import { createLogger } from '@powersync/common';
|
|
1
2
|
import * as Comlink from 'comlink';
|
|
2
3
|
import { openWorkerDatabasePort, resolveWorkerDatabasePortFactory } from '../../../worker/db/open-worker-database.js';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
4
|
+
import { DEFAULT_CACHE_SIZE_KB, isServerSide, resolveWebSQLFlags, TemporaryStorageOption } from '../web-sql-flags.js';
|
|
5
|
+
import { SSRDBAdapter } from '../SSRDBAdapter.js';
|
|
6
|
+
import { vfsRequiresDedicatedWorkers, WASQLiteVFS } from './vfs.js';
|
|
7
|
+
import { MultiDatabaseServer } from '../../../worker/db/MultiDatabaseServer.js';
|
|
8
|
+
import { DatabaseClient } from './DatabaseClient.js';
|
|
9
|
+
import { generateTabCloseSignal } from '../../../shared/tab_close_signal.js';
|
|
10
|
+
import { AsyncDbAdapter } from '../AsyncWebAdapter.js';
|
|
8
11
|
/**
|
|
9
12
|
* Opens a SQLite connection using WA-SQLite.
|
|
10
13
|
*/
|
|
11
|
-
export class WASQLiteOpenFactory
|
|
14
|
+
export class WASQLiteOpenFactory {
|
|
15
|
+
options;
|
|
16
|
+
resolvedFlags;
|
|
17
|
+
logger;
|
|
12
18
|
constructor(options) {
|
|
13
|
-
|
|
19
|
+
this.options = options;
|
|
14
20
|
assertValidWASQLiteOpenFactoryOptions(options);
|
|
21
|
+
this.resolvedFlags = resolveWebSQLFlags(options.flags);
|
|
22
|
+
this.logger = options.logger ?? createLogger(`WASQLiteOpenFactory - ${this.options.dbFilename}`);
|
|
15
23
|
}
|
|
16
24
|
get waOptions() {
|
|
17
25
|
// Cast to extended type
|
|
18
26
|
return this.options;
|
|
19
27
|
}
|
|
20
28
|
openAdapter() {
|
|
21
|
-
return new
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
return new AsyncDbAdapter(this.openConnection(), this.options.dbFilename);
|
|
30
|
+
}
|
|
31
|
+
openDB() {
|
|
32
|
+
const { resolvedFlags: { disableSSRWarning, enableMultiTabs, ssrMode = isServerSide() } } = this;
|
|
33
|
+
if (ssrMode) {
|
|
34
|
+
if (!disableSSRWarning) {
|
|
35
|
+
this.logger.warn(`
|
|
36
|
+
Running PowerSync in SSR mode.
|
|
37
|
+
Only empty query results will be returned.
|
|
38
|
+
Disable this warning by setting 'disableSSRWarning: true' in options.`);
|
|
39
|
+
}
|
|
40
|
+
return new SSRDBAdapter();
|
|
41
|
+
}
|
|
42
|
+
if (!enableMultiTabs) {
|
|
43
|
+
this.logger.warn('Multiple tab support is not enabled. Using this site across multiple tabs may not function correctly.');
|
|
44
|
+
}
|
|
45
|
+
return this.openAdapter();
|
|
27
46
|
}
|
|
28
47
|
async openConnection() {
|
|
29
48
|
const { enableMultiTabs, useWebWorker } = this.resolvedFlags;
|
|
@@ -31,55 +50,85 @@ export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
|
|
|
31
50
|
if (!enableMultiTabs) {
|
|
32
51
|
this.logger.warn('Multiple tabs are not enabled in this browser');
|
|
33
52
|
}
|
|
53
|
+
const resolveOptions = (isReadOnly) => ({
|
|
54
|
+
dbFilename: this.options.dbFilename,
|
|
55
|
+
dbLocation: this.options.dbLocation,
|
|
56
|
+
debugMode: this.options.debugMode,
|
|
57
|
+
vfs,
|
|
58
|
+
temporaryStorage,
|
|
59
|
+
cacheSizeKb,
|
|
60
|
+
flags: this.resolvedFlags,
|
|
61
|
+
encryptionKey: encryptionKey,
|
|
62
|
+
isReadOnly
|
|
63
|
+
});
|
|
64
|
+
let client;
|
|
65
|
+
let additionalReaders = [];
|
|
66
|
+
let requiresPersistentTriggers = vfsRequiresDedicatedWorkers(vfs);
|
|
34
67
|
if (useWebWorker) {
|
|
35
68
|
const optionsDbWorker = this.options.worker;
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
const openDatabaseWorker = async (resolvedOptions) => {
|
|
70
|
+
const workerPort = typeof optionsDbWorker == 'function'
|
|
71
|
+
? resolveWorkerDatabasePortFactory(() => optionsDbWorker({
|
|
72
|
+
...this.options,
|
|
73
|
+
temporaryStorage,
|
|
74
|
+
cacheSizeKb,
|
|
75
|
+
flags: this.resolvedFlags,
|
|
76
|
+
encryptionKey
|
|
77
|
+
}))
|
|
78
|
+
: openWorkerDatabasePort(this.options.dbFilename, enableMultiTabs, optionsDbWorker, this.waOptions.vfs);
|
|
79
|
+
const source = Comlink.wrap(workerPort);
|
|
80
|
+
const closeSignal = new AbortController();
|
|
81
|
+
const connection = await source.connect({
|
|
82
|
+
...resolvedOptions,
|
|
83
|
+
logLevel: this.logger.getLevel(),
|
|
84
|
+
lockName: await generateTabCloseSignal(closeSignal.signal)
|
|
85
|
+
});
|
|
86
|
+
const clientOptions = {
|
|
87
|
+
connection,
|
|
88
|
+
source,
|
|
89
|
+
// This tab owns the worker, so we're guaranteed to outlive it.
|
|
90
|
+
remoteCanCloseUnexpectedly: false,
|
|
91
|
+
onClose: () => {
|
|
92
|
+
closeSignal.abort();
|
|
93
|
+
if (workerPort instanceof Worker) {
|
|
94
|
+
workerPort.terminate();
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
workerPort.close();
|
|
98
|
+
}
|
|
66
99
|
}
|
|
100
|
+
};
|
|
101
|
+
return new DatabaseClient(clientOptions, {
|
|
102
|
+
...resolvedOptions,
|
|
103
|
+
requiresPersistentTriggers
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
client = await openDatabaseWorker(resolveOptions(false));
|
|
107
|
+
if (vfs == WASQLiteVFS.OPFSWriteAheadVFS) {
|
|
108
|
+
// This VFS supports concurrent reads, so we can open additional workers to host read-only connections for
|
|
109
|
+
// concurrent reads / writes.
|
|
110
|
+
const additionalReadersCount = this.options.additionalReaders ?? 1;
|
|
111
|
+
for (let i = 0; i < additionalReadersCount; i++) {
|
|
112
|
+
const reader = await openDatabaseWorker(resolveOptions(true));
|
|
113
|
+
additionalReaders.push(reader);
|
|
67
114
|
}
|
|
68
|
-
}
|
|
115
|
+
}
|
|
69
116
|
}
|
|
70
117
|
else {
|
|
71
|
-
// Don't use a web worker
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
flags: this.resolvedFlags,
|
|
80
|
-
encryptionKey: encryptionKey
|
|
118
|
+
// Don't use a web worker. Instead, open the MultiDatabaseServer a worker would use locally.
|
|
119
|
+
const localServer = new MultiDatabaseServer(this.logger);
|
|
120
|
+
requiresPersistentTriggers = true;
|
|
121
|
+
const resolvedOptions = resolveOptions(false);
|
|
122
|
+
const connection = await localServer.openConnectionLocally(resolvedOptions);
|
|
123
|
+
client = new DatabaseClient({ connection, source: null, remoteCanCloseUnexpectedly: false }, {
|
|
124
|
+
...resolvedOptions,
|
|
125
|
+
requiresPersistentTriggers
|
|
81
126
|
});
|
|
82
127
|
}
|
|
128
|
+
return {
|
|
129
|
+
writer: client,
|
|
130
|
+
additionalReaders
|
|
131
|
+
};
|
|
83
132
|
}
|
|
84
133
|
}
|
|
85
134
|
/**
|
|
@@ -89,7 +138,7 @@ function assertValidWASQLiteOpenFactoryOptions(options) {
|
|
|
89
138
|
// The OPFS VFS only works in dedicated web workers.
|
|
90
139
|
if ('vfs' in options && 'flags' in options) {
|
|
91
140
|
const { vfs, flags = {} } = options;
|
|
92
|
-
if (vfs
|
|
141
|
+
if (vfs && vfsRequiresDedicatedWorkers(vfs) && 'useWebWorker' in flags && !flags.useWebWorker) {
|
|
93
142
|
throw new Error(`Invalid configuration: The 'useWebWorker' flag must be true when using an OPFS-based VFS (${vfs}).`);
|
|
94
143
|
}
|
|
95
144
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type * as SQLite from '@journeyapps/wa-sqlite';
|
|
2
|
+
/**
|
|
3
|
+
* List of currently tested virtual filesystems
|
|
4
|
+
*/
|
|
5
|
+
export declare enum WASQLiteVFS {
|
|
6
|
+
IDBBatchAtomicVFS = "IDBBatchAtomicVFS",
|
|
7
|
+
OPFSCoopSyncVFS = "OPFSCoopSyncVFS",
|
|
8
|
+
AccessHandlePoolVFS = "AccessHandlePoolVFS",
|
|
9
|
+
OPFSWriteAheadVFS = "OPFSWriteAheadVFS"
|
|
10
|
+
}
|
|
11
|
+
export declare function vfsRequiresDedicatedWorkers(vfs: WASQLiteVFS): vfs is WASQLiteVFS.OPFSCoopSyncVFS | WASQLiteVFS.AccessHandlePoolVFS | WASQLiteVFS.OPFSWriteAheadVFS;
|
|
12
|
+
/**
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export type WASQLiteModuleFactoryOptions = {
|
|
16
|
+
dbFileName: string;
|
|
17
|
+
encryptionKey?: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export type SQLiteModule = Parameters<typeof SQLite.Factory>[0];
|
|
23
|
+
/**
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export type WASQLiteModuleFactory = (options: WASQLiteModuleFactoryOptions) => Promise<{
|
|
27
|
+
module: SQLiteModule;
|
|
28
|
+
vfs: SQLiteVFS;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
export declare const DEFAULT_MODULE_FACTORIES: {
|
|
34
|
+
IDBBatchAtomicVFS: (options: WASQLiteModuleFactoryOptions) => Promise<{
|
|
35
|
+
module: any;
|
|
36
|
+
vfs: any;
|
|
37
|
+
}>;
|
|
38
|
+
AccessHandlePoolVFS: (options: WASQLiteModuleFactoryOptions) => Promise<{
|
|
39
|
+
module: any;
|
|
40
|
+
vfs: any;
|
|
41
|
+
}>;
|
|
42
|
+
OPFSCoopSyncVFS: (options: WASQLiteModuleFactoryOptions) => Promise<{
|
|
43
|
+
module: any;
|
|
44
|
+
vfs: any;
|
|
45
|
+
}>;
|
|
46
|
+
OPFSWriteAheadVFS: (options: WASQLiteModuleFactoryOptions) => Promise<{
|
|
47
|
+
module: any;
|
|
48
|
+
vfs: any;
|
|
49
|
+
}>;
|
|
50
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List of currently tested virtual filesystems
|
|
3
|
+
*/
|
|
4
|
+
export var WASQLiteVFS;
|
|
5
|
+
(function (WASQLiteVFS) {
|
|
6
|
+
WASQLiteVFS["IDBBatchAtomicVFS"] = "IDBBatchAtomicVFS";
|
|
7
|
+
WASQLiteVFS["OPFSCoopSyncVFS"] = "OPFSCoopSyncVFS";
|
|
8
|
+
WASQLiteVFS["AccessHandlePoolVFS"] = "AccessHandlePoolVFS";
|
|
9
|
+
WASQLiteVFS["OPFSWriteAheadVFS"] = "OPFSWriteAheadVFS";
|
|
10
|
+
})(WASQLiteVFS || (WASQLiteVFS = {}));
|
|
11
|
+
export function vfsRequiresDedicatedWorkers(vfs) {
|
|
12
|
+
return vfs != WASQLiteVFS.IDBBatchAtomicVFS;
|
|
13
|
+
}
|
|
14
|
+
async function asyncModuleFactory(encryptionKey) {
|
|
15
|
+
if (encryptionKey) {
|
|
16
|
+
const { default: factory } = await import('@journeyapps/wa-sqlite/dist/mc-wa-sqlite-async.mjs');
|
|
17
|
+
return factory();
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const { default: factory } = await import('@journeyapps/wa-sqlite/dist/wa-sqlite-async.mjs');
|
|
21
|
+
return factory();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function syncModuleFactory(encryptionKey) {
|
|
25
|
+
if (encryptionKey) {
|
|
26
|
+
const { default: factory } = await import('@journeyapps/wa-sqlite/dist/mc-wa-sqlite.mjs');
|
|
27
|
+
return factory();
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const { default: factory } = await import('@journeyapps/wa-sqlite/dist/wa-sqlite.mjs');
|
|
31
|
+
return factory();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
export const DEFAULT_MODULE_FACTORIES = {
|
|
38
|
+
[WASQLiteVFS.IDBBatchAtomicVFS]: async (options) => {
|
|
39
|
+
const module = await asyncModuleFactory(options.encryptionKey);
|
|
40
|
+
const { IDBBatchAtomicVFS } = await import('@journeyapps/wa-sqlite/src/examples/IDBBatchAtomicVFS.js');
|
|
41
|
+
return {
|
|
42
|
+
module,
|
|
43
|
+
// @ts-expect-error The types for this static method are missing upstream
|
|
44
|
+
vfs: await IDBBatchAtomicVFS.create(options.dbFileName, module, { lockPolicy: 'exclusive' })
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
[WASQLiteVFS.AccessHandlePoolVFS]: async (options) => {
|
|
48
|
+
const module = await syncModuleFactory(options.encryptionKey);
|
|
49
|
+
// @ts-expect-error The types for this static method are missing upstream
|
|
50
|
+
const { AccessHandlePoolVFS } = await import('@journeyapps/wa-sqlite/src/examples/AccessHandlePoolVFS.js');
|
|
51
|
+
return {
|
|
52
|
+
module,
|
|
53
|
+
vfs: await AccessHandlePoolVFS.create(options.dbFileName, module)
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
[WASQLiteVFS.OPFSCoopSyncVFS]: async (options) => {
|
|
57
|
+
const module = await syncModuleFactory(options.encryptionKey);
|
|
58
|
+
// @ts-expect-error The types for this static method are missing upstream
|
|
59
|
+
const { OPFSCoopSyncVFS } = await import('@journeyapps/wa-sqlite/src/examples/OPFSCoopSyncVFS.js');
|
|
60
|
+
const vfs = await OPFSCoopSyncVFS.create(options.dbFileName, module);
|
|
61
|
+
return {
|
|
62
|
+
module,
|
|
63
|
+
vfs
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
[WASQLiteVFS.OPFSWriteAheadVFS]: async (options) => {
|
|
67
|
+
const module = await syncModuleFactory(options.encryptionKey);
|
|
68
|
+
// @ts-expect-error The types for this static method are missing upstream
|
|
69
|
+
const { OPFSWriteAheadVFS } = await import('@journeyapps/wa-sqlite/src/examples/OPFSWriteAheadVFS.js');
|
|
70
|
+
const vfs = await OPFSWriteAheadVFS.create(options.dbFileName, module, {});
|
|
71
|
+
return {
|
|
72
|
+
module,
|
|
73
|
+
vfs
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
};
|
|
@@ -62,6 +62,11 @@ export interface WebSQLOpenFactoryOptions extends SQLOpenOptions {
|
|
|
62
62
|
* or a factory method that returns a worker.
|
|
63
63
|
*/
|
|
64
64
|
worker?: string | URL | ((options: ResolvedWebSQLOpenOptions) => Worker | SharedWorker);
|
|
65
|
+
/**
|
|
66
|
+
* Use an existing port to an initialized worker.
|
|
67
|
+
* A worker will be initialized if none is provided
|
|
68
|
+
*/
|
|
69
|
+
workerPort?: MessagePort;
|
|
65
70
|
logger?: ILogger;
|
|
66
71
|
/**
|
|
67
72
|
* Where to store SQLite temporary files. Defaults to 'MEMORY'.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { AbstractStreamingSyncImplementationOptions, BaseObserver, LockOptions, PowerSyncConnectionOptions, StreamingSyncImplementation, SyncStatus, SyncStatusOptions } from '@powersync/common';
|
|
2
|
-
import { Mutex } from 'async-mutex';
|
|
1
|
+
import { AbstractStreamingSyncImplementationOptions, BaseObserver, LockOptions, Mutex, PowerSyncConnectionOptions, StreamingSyncImplementation, SyncStatus, SyncStatusOptions } from '@powersync/common';
|
|
3
2
|
export declare class SSRStreamingSyncImplementation extends BaseObserver implements StreamingSyncImplementation {
|
|
4
3
|
syncMutex: Mutex;
|
|
5
4
|
crudMutex: Mutex;
|
|
@@ -45,4 +44,8 @@ export declare class SSRStreamingSyncImplementation extends BaseObserver impleme
|
|
|
45
44
|
* No-op in SSR mode.
|
|
46
45
|
*/
|
|
47
46
|
updateSubscriptions(): void;
|
|
47
|
+
/**
|
|
48
|
+
* No-op in SSR mode.
|
|
49
|
+
*/
|
|
50
|
+
markConnectionMayHaveChanged(): void;
|
|
48
51
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { BaseObserver, LockType, SyncStatus } from '@powersync/common';
|
|
2
|
-
import { Mutex } from 'async-mutex';
|
|
1
|
+
import { BaseObserver, LockType, Mutex, SyncStatus } from '@powersync/common';
|
|
3
2
|
export class SSRStreamingSyncImplementation extends BaseObserver {
|
|
4
3
|
syncMutex;
|
|
5
4
|
crudMutex;
|
|
@@ -15,7 +14,7 @@ export class SSRStreamingSyncImplementation extends BaseObserver {
|
|
|
15
14
|
}
|
|
16
15
|
obtainLock(lockOptions) {
|
|
17
16
|
const mutex = lockOptions.type == LockType.CRUD ? this.crudMutex : this.syncMutex;
|
|
18
|
-
return mutex.runExclusive(lockOptions.callback);
|
|
17
|
+
return mutex.runExclusive(lockOptions.callback, lockOptions.signal);
|
|
19
18
|
}
|
|
20
19
|
/**
|
|
21
20
|
* This is a no-op in SSR mode
|
|
@@ -62,4 +61,8 @@ export class SSRStreamingSyncImplementation extends BaseObserver {
|
|
|
62
61
|
* No-op in SSR mode.
|
|
63
62
|
*/
|
|
64
63
|
updateSubscriptions() { }
|
|
64
|
+
/**
|
|
65
|
+
* No-op in SSR mode.
|
|
66
|
+
*/
|
|
67
|
+
markConnectionMayHaveChanged() { }
|
|
65
68
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as Comlink from 'comlink';
|
|
2
|
-
import { getNavigatorLocks } from '../../shared/navigator.js';
|
|
3
2
|
import { AbstractSharedSyncClientProvider } from '../../worker/sync/AbstractSharedSyncClientProvider.js';
|
|
4
3
|
import { SharedSyncClientEvent } from '../../worker/sync/SharedSyncImplementation.js';
|
|
5
4
|
import { DEFAULT_CACHE_SIZE_KB, TemporaryStorageOption, resolveWebSQLFlags } from '../adapters/web-sql-flags.js';
|
|
6
5
|
import { WebStreamingSyncImplementation } from './WebStreamingSyncImplementation.js';
|
|
6
|
+
import { generateTabCloseSignal } from '../../shared/tab_close_signal.js';
|
|
7
7
|
/**
|
|
8
8
|
* The shared worker will trigger methods on this side of the message port
|
|
9
9
|
* via this client provider.
|
|
@@ -156,24 +156,9 @@ export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplem
|
|
|
156
156
|
* - We resolve the top-level promise after the lock has been registered with the shared worker.
|
|
157
157
|
* - The client sends the params to the shared worker after locks have been registered.
|
|
158
158
|
*/
|
|
159
|
-
await
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
});
|
|
159
|
+
const closeSignal = await generateTabCloseSignal(this.abortOnClose.signal);
|
|
160
|
+
// Awaiting here ensures the worker is waiting for the lock
|
|
161
|
+
await this.syncManager.addLockBasedCloseSignal(closeSignal);
|
|
177
162
|
const { crudUploadThrottleMs, identifier, retryDelayMs } = this.options;
|
|
178
163
|
const flags = { ...this.webOptions.flags, workers: undefined };
|
|
179
164
|
await this.syncManager.setParams({
|
package/lib/src/index.d.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
export * from '@powersync/common';
|
|
2
2
|
export * from './attachments/IndexDBFileSystemAdapter.js';
|
|
3
3
|
export * from './db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.js';
|
|
4
|
-
export
|
|
5
|
-
export * from './db/adapters/AsyncDatabaseConnection.js';
|
|
6
|
-
export * from './db/adapters/wa-sqlite/WASQLiteConnection.js';
|
|
7
|
-
export * from './db/adapters/wa-sqlite/WASQLiteDBAdapter.js';
|
|
4
|
+
export { WASQLiteVFS } from './db/adapters/wa-sqlite/vfs.js';
|
|
8
5
|
export * from './db/adapters/wa-sqlite/WASQLiteOpenFactory.js';
|
|
9
6
|
export * from './db/adapters/wa-sqlite/WASQLitePowerSyncDatabaseOpenFactory.js';
|
|
10
7
|
export * from './db/adapters/web-sql-flags.js';
|
package/lib/src/index.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
export * from '@powersync/common';
|
|
2
2
|
export * from './attachments/IndexDBFileSystemAdapter.js';
|
|
3
3
|
export * from './db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.js';
|
|
4
|
-
export
|
|
5
|
-
export * from './db/adapters/AsyncDatabaseConnection.js';
|
|
6
|
-
export * from './db/adapters/wa-sqlite/WASQLiteConnection.js';
|
|
7
|
-
export * from './db/adapters/wa-sqlite/WASQLiteDBAdapter.js';
|
|
4
|
+
export { WASQLiteVFS } from './db/adapters/wa-sqlite/vfs.js';
|
|
8
5
|
export * from './db/adapters/wa-sqlite/WASQLiteOpenFactory.js';
|
|
9
6
|
export * from './db/adapters/wa-sqlite/WASQLitePowerSyncDatabaseOpenFactory.js';
|
|
10
7
|
export * from './db/adapters/web-sql-flags.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Requests a random lock that will be released once the optional signal is aborted (or, if no signal is given, when the
|
|
3
|
+
* tab is closed).
|
|
4
|
+
*
|
|
5
|
+
* This allows sending the name of the lock to another context (e.g. a shared worker), which will also attempt to
|
|
6
|
+
* acquire it. Since the lock is returned when the tab is closed, this allows the shared worker to free resources
|
|
7
|
+
* assocatiated with this tab.
|
|
8
|
+
*
|
|
9
|
+
* We take hold of this lock as soon-as-possible in order to cater for potentially closed tabs.
|
|
10
|
+
*/
|
|
11
|
+
export declare function generateTabCloseSignal(abort?: AbortSignal): Promise<string>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { getNavigatorLocks } from './navigator.js';
|
|
2
|
+
/**
|
|
3
|
+
* Requests a random lock that will be released once the optional signal is aborted (or, if no signal is given, when the
|
|
4
|
+
* tab is closed).
|
|
5
|
+
*
|
|
6
|
+
* This allows sending the name of the lock to another context (e.g. a shared worker), which will also attempt to
|
|
7
|
+
* acquire it. Since the lock is returned when the tab is closed, this allows the shared worker to free resources
|
|
8
|
+
* assocatiated with this tab.
|
|
9
|
+
*
|
|
10
|
+
* We take hold of this lock as soon-as-possible in order to cater for potentially closed tabs.
|
|
11
|
+
*/
|
|
12
|
+
export function generateTabCloseSignal(abort) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
const options = { signal: abort };
|
|
15
|
+
getNavigatorLocks()
|
|
16
|
+
.request(`tab-close-signal-${crypto.randomUUID()}`, options, (lock) => {
|
|
17
|
+
resolve(lock.name);
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
if (abort) {
|
|
20
|
+
abort.addEventListener('abort', () => resolve());
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
})
|
|
24
|
+
.catch(reject);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ILogger } from '@powersync/common';
|
|
2
|
+
import { ClientConnectionView } from '../../db/adapters/wa-sqlite/DatabaseServer.js';
|
|
3
|
+
import { ResolvedWASQLiteOpenFactoryOptions, WorkerDBOpenerOptions } from '../../db/adapters/wa-sqlite/WASQLiteOpenFactory.js';
|
|
4
|
+
/**
|
|
5
|
+
* Shared state to manage multiple database connections hosted by a worker.
|
|
6
|
+
*/
|
|
7
|
+
export declare class MultiDatabaseServer {
|
|
8
|
+
readonly logger: ILogger;
|
|
9
|
+
private activeDatabases;
|
|
10
|
+
constructor(logger: ILogger);
|
|
11
|
+
handleConnection(options: WorkerDBOpenerOptions): Promise<ClientConnectionView>;
|
|
12
|
+
connectToExisting(name: string, lockName: string): Promise<ClientConnectionView>;
|
|
13
|
+
openConnectionLocally(options: ResolvedWASQLiteOpenFactoryOptions, lockName?: string): Promise<ClientConnectionView>;
|
|
14
|
+
private databaseOpenAttempt;
|
|
15
|
+
closeAll(): Promise<void[]>;
|
|
16
|
+
}
|
|
17
|
+
export declare const isSharedWorker: boolean;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as Comlink from 'comlink';
|
|
2
|
+
import { DatabaseServer } from '../../db/adapters/wa-sqlite/DatabaseServer.js';
|
|
3
|
+
import { getNavigatorLocks } from '../../shared/navigator.js';
|
|
4
|
+
import { RawSqliteConnection } from '../../db/adapters/wa-sqlite/RawSqliteConnection.js';
|
|
5
|
+
import { ConcurrentSqliteConnection } from '../../db/adapters/wa-sqlite/ConcurrentConnection.js';
|
|
6
|
+
const OPEN_DB_LOCK = 'open-wasqlite-db';
|
|
7
|
+
/**
|
|
8
|
+
* Shared state to manage multiple database connections hosted by a worker.
|
|
9
|
+
*/
|
|
10
|
+
export class MultiDatabaseServer {
|
|
11
|
+
logger;
|
|
12
|
+
activeDatabases = new Map();
|
|
13
|
+
constructor(logger) {
|
|
14
|
+
this.logger = logger;
|
|
15
|
+
}
|
|
16
|
+
async handleConnection(options) {
|
|
17
|
+
this.logger.setLevel(options.logLevel);
|
|
18
|
+
return Comlink.proxy(await this.openConnectionLocally(options, options.lockName));
|
|
19
|
+
}
|
|
20
|
+
async connectToExisting(name, lockName) {
|
|
21
|
+
return getNavigatorLocks().request(OPEN_DB_LOCK, async () => {
|
|
22
|
+
const server = this.activeDatabases.get(name);
|
|
23
|
+
if (server == null) {
|
|
24
|
+
throw new Error(`connectToExisting(${name}) failed because the worker doesn't own a database with that name.`);
|
|
25
|
+
}
|
|
26
|
+
return Comlink.proxy(await server.connect(lockName));
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async openConnectionLocally(options, lockName) {
|
|
30
|
+
// Especially on Firefox, we're sometimes seeing "NoModificationAllowedError"s when opening OPFS databases we can
|
|
31
|
+
// work around by retrying.
|
|
32
|
+
const maxAttempts = 3;
|
|
33
|
+
let server;
|
|
34
|
+
for (let count = 0; count < maxAttempts - 1; count++) {
|
|
35
|
+
try {
|
|
36
|
+
server = await this.databaseOpenAttempt(options);
|
|
37
|
+
}
|
|
38
|
+
catch (ex) {
|
|
39
|
+
this.logger.warn(`Attempt ${count + 1} of ${maxAttempts} to open database failed, retrying in 1 second...`, ex);
|
|
40
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Final attempt if we haven't been able to open the server - rethrow errors if we still can't open.
|
|
44
|
+
server ??= await this.databaseOpenAttempt(options);
|
|
45
|
+
return server.connect(lockName);
|
|
46
|
+
}
|
|
47
|
+
async databaseOpenAttempt(options) {
|
|
48
|
+
return getNavigatorLocks().request(OPEN_DB_LOCK, async () => {
|
|
49
|
+
const { dbFilename } = options;
|
|
50
|
+
let server = this.activeDatabases.get(dbFilename);
|
|
51
|
+
if (server == null) {
|
|
52
|
+
// We don't need navigator locks for shared workers because all queries run in this shared worker exclusively.
|
|
53
|
+
// For read-only connections, we use a VFS that supports concurrent reads (so a single lock on the connection is
|
|
54
|
+
// fine).
|
|
55
|
+
const needsNavigatorLocks = !(isSharedWorker || options.isReadOnly);
|
|
56
|
+
const connection = new RawSqliteConnection(options);
|
|
57
|
+
const withSafeConcurrency = new ConcurrentSqliteConnection(connection, needsNavigatorLocks);
|
|
58
|
+
// Initializing the RawSqliteConnection will run some pragmas that might write to the database file, so we want
|
|
59
|
+
// to do that in an exclusive lock. Note that OPEN_DB_LOCK is not enough for that, as another tab might have
|
|
60
|
+
// already created a connection (and is thus outside of OPEN_DB_LOCK) while currently writing to it.
|
|
61
|
+
const returnLease = await withSafeConcurrency.acquireMutex();
|
|
62
|
+
try {
|
|
63
|
+
await connection.init();
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
returnLease();
|
|
67
|
+
await connection.close();
|
|
68
|
+
throw e;
|
|
69
|
+
}
|
|
70
|
+
returnLease();
|
|
71
|
+
const onClose = () => this.activeDatabases.delete(dbFilename);
|
|
72
|
+
server = new DatabaseServer({
|
|
73
|
+
inner: withSafeConcurrency,
|
|
74
|
+
logger: this.logger,
|
|
75
|
+
onClose
|
|
76
|
+
});
|
|
77
|
+
this.activeDatabases.set(dbFilename, server);
|
|
78
|
+
}
|
|
79
|
+
return server;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
closeAll() {
|
|
83
|
+
const existingDatabases = [...this.activeDatabases.values()];
|
|
84
|
+
return Promise.all(existingDatabases.map((db) => {
|
|
85
|
+
db.forceClose();
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export const isSharedWorker = 'SharedWorkerGlobalScope' in globalThis;
|