@powersync/web 2.1.1 → 2.3.0
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/README.md +1 -1
- package/dist/index.react_native_web.js +224 -121
- package/dist/index.react_native_web.js.map +1 -1
- package/dist/worker/AccessHandlePoolVFS-BPUHfZME.js.map +1 -1
- package/dist/worker/FacadeVFS-d1ZDvud7.js.map +1 -1
- package/dist/worker/IDBBatchAtomicVFS-DbkDb777.js.map +1 -1
- package/dist/worker/MemoryVFS-DVJL5F8j.js.map +1 -1
- package/dist/worker/OPFSCoopSyncVFS-BgTiWPfa.js.map +1 -1
- package/dist/worker/OPFSWriteAheadVFS-Rt5CGCZP.js +2 -0
- package/dist/worker/OPFSWriteAheadVFS-Rt5CGCZP.js.map +1 -0
- package/dist/worker/mc-wa-sqlite-DDFgWP93.js.map +1 -1
- package/dist/worker/mc-wa-sqlite-async-lGclTjKJ.js.map +1 -1
- package/dist/worker/wa-sqlite-B0tZMM0j.js.map +1 -1
- package/dist/worker/wa-sqlite-async-CM6BmfRh.js.map +1 -1
- package/dist/worker/worker.js +1 -1
- package/dist/worker/worker.js.map +1 -1
- package/lib/db/PowerSyncDatabase.d.ts +1 -2
- package/lib/db/PowerSyncDatabase.js +19 -24
- package/lib/db/PowerSyncDatabase.js.map +1 -1
- package/lib/db/adapters/AsyncWebAdapter.js +4 -55
- package/lib/db/adapters/AsyncWebAdapter.js.map +1 -1
- package/lib/db/adapters/acquireFromPool.d.ts +7 -0
- package/lib/db/adapters/acquireFromPool.js +60 -0
- package/lib/db/adapters/acquireFromPool.js.map +1 -0
- package/lib/db/adapters/memory-pool/client.d.ts +70 -0
- package/lib/db/adapters/memory-pool/client.js +269 -0
- package/lib/db/adapters/memory-pool/client.js.map +1 -0
- package/lib/db/adapters/memory-pool/shared.d.ts +51 -0
- package/lib/db/adapters/memory-pool/shared.js +16 -0
- package/lib/db/adapters/memory-pool/shared.js.map +1 -0
- package/lib/db/adapters/memory-pool/vfs.d.ts +19 -0
- package/lib/db/adapters/memory-pool/vfs.js +247 -0
- package/lib/db/adapters/memory-pool/vfs.js.map +1 -0
- package/lib/db/adapters/memory-pool/worker.d.ts +1 -0
- package/lib/db/adapters/memory-pool/worker.js +45 -0
- package/lib/db/adapters/memory-pool/worker.js.map +1 -0
- package/lib/db/adapters/options.d.ts +7 -0
- package/lib/db/adapters/options.js.map +1 -1
- package/lib/db/adapters/wa-sqlite/RawSqliteConnection.d.ts +8 -0
- package/lib/db/adapters/wa-sqlite/RawSqliteConnection.js +56 -5
- package/lib/db/adapters/wa-sqlite/RawSqliteConnection.js.map +1 -1
- package/lib/db/adapters/wa-sqlite/StatementCache.d.ts +16 -0
- package/lib/db/adapters/wa-sqlite/StatementCache.js +44 -0
- package/lib/db/adapters/wa-sqlite/StatementCache.js.map +1 -0
- package/lib/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +7 -4
- package/lib/db/adapters/wa-sqlite/WASQLiteOpenFactory.js.map +1 -1
- package/lib/db/sync/SSRWebStreamingSyncImplementation.d.ts +1 -8
- package/lib/db/sync/SSRWebStreamingSyncImplementation.js +3 -12
- package/lib/db/sync/SSRWebStreamingSyncImplementation.js.map +1 -1
- package/lib/db/sync/SharedWebStreamingSyncImplementation.d.ts +2 -1
- package/lib/db/sync/SharedWebStreamingSyncImplementation.js +6 -4
- package/lib/db/sync/SharedWebStreamingSyncImplementation.js.map +1 -1
- package/lib/worker/db/MultiDatabaseServer.d.ts +1 -2
- package/lib/worker/db/MultiDatabaseServer.js +28 -17
- package/lib/worker/db/MultiDatabaseServer.js.map +1 -1
- package/lib/worker/sync/AbstractSharedSyncClientProvider.d.ts +1 -0
- package/lib/worker/sync/AbstractSharedSyncClientProvider.js.map +1 -1
- package/lib/worker/sync/SharedSyncImplementation.d.ts +3 -11
- package/lib/worker/sync/SharedSyncImplementation.js +32 -64
- package/lib/worker/sync/SharedSyncImplementation.js.map +1 -1
- package/lib/worker/sync/WorkerClient.d.ts +1 -1
- package/lib/worker/sync/WorkerClient.js +3 -3
- package/lib/worker/sync/WorkerClient.js.map +1 -1
- package/package.json +15 -8
- package/src/db/PowerSyncDatabase.ts +20 -24
- package/src/db/adapters/AsyncWebAdapter.ts +13 -61
- package/src/db/adapters/acquireFromPool.ts +73 -0
- package/src/db/adapters/memory-pool/client.ts +367 -0
- package/src/db/adapters/memory-pool/shared.ts +79 -0
- package/src/db/adapters/memory-pool/vfs.ts +293 -0
- package/src/db/adapters/memory-pool/worker.ts +53 -0
- package/src/db/adapters/options.ts +8 -0
- package/src/db/adapters/wa-sqlite/RawSqliteConnection.ts +71 -6
- package/src/db/adapters/wa-sqlite/StatementCache.ts +50 -0
- package/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.ts +17 -5
- package/src/db/sync/SSRWebStreamingSyncImplementation.ts +4 -14
- package/src/db/sync/SharedWebStreamingSyncImplementation.ts +8 -5
- package/src/worker/db/MultiDatabaseServer.ts +29 -21
- package/src/worker/sync/AbstractSharedSyncClientProvider.ts +1 -0
- package/src/worker/sync/SharedSyncImplementation.ts +41 -76
- package/src/worker/sync/WorkerClient.ts +4 -4
- package/dist/worker/OPFSWriteAheadVFS-BzodSqNq.js +0 -2
- package/dist/worker/OPFSWriteAheadVFS-BzodSqNq.js.map +0 -1
|
@@ -5,6 +5,7 @@ import { getNavigatorLocks } from '../../shared/navigator.js';
|
|
|
5
5
|
import { RawSqliteConnection, RawWaSqliteDatabaseOptions } from '../../db/adapters/wa-sqlite/RawSqliteConnection.js';
|
|
6
6
|
import { ConcurrentSqliteConnection } from '../../db/adapters/wa-sqlite/ConcurrentConnection.js';
|
|
7
7
|
import { WASQLiteVFS } from '../../db/adapters/wa-sqlite/vfs.js';
|
|
8
|
+
import { Mutex } from '@powersync/shared-internals';
|
|
8
9
|
|
|
9
10
|
const OPEN_DB_LOCK = 'open-wasqlite-db';
|
|
10
11
|
|
|
@@ -18,7 +19,8 @@ export interface ConnectToMultiDatabaseServerOptions {
|
|
|
18
19
|
* Shared state to manage multiple database connections hosted by a worker.
|
|
19
20
|
*/
|
|
20
21
|
export class MultiDatabaseServer {
|
|
21
|
-
|
|
22
|
+
readonly #activeDatabases = new Map<string, DatabaseServer>();
|
|
23
|
+
readonly #localOpenLock = new Mutex();
|
|
22
24
|
|
|
23
25
|
constructor(readonly logger: PowerSyncLogger) {}
|
|
24
26
|
|
|
@@ -38,7 +40,7 @@ export class MultiDatabaseServer {
|
|
|
38
40
|
|
|
39
41
|
async connectToExisting(name: string, lockName: string): Promise<ClientConnectionView> {
|
|
40
42
|
return getNavigatorLocks().request(OPEN_DB_LOCK, async () => {
|
|
41
|
-
const server = this
|
|
43
|
+
const server = this.#activeDatabases.get(name);
|
|
42
44
|
if (server == null) {
|
|
43
45
|
throw new Error(`connectToExisting(${name}) failed because the worker doesn't own a database with that name.`);
|
|
44
46
|
}
|
|
@@ -55,7 +57,7 @@ export class MultiDatabaseServer {
|
|
|
55
57
|
|
|
56
58
|
for (let count = 0; count < maxAttempts - 1; count++) {
|
|
57
59
|
try {
|
|
58
|
-
server = await this
|
|
60
|
+
server = await this.#databaseOpenAttempt(logger, options);
|
|
59
61
|
} catch (error) {
|
|
60
62
|
this.logger.log({
|
|
61
63
|
level: LogLevels.warn,
|
|
@@ -67,24 +69,22 @@ export class MultiDatabaseServer {
|
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
// Final attempt if we haven't been able to open the server - rethrow errors if we still can't open.
|
|
70
|
-
server ??= await this
|
|
72
|
+
server ??= await this.#databaseOpenAttempt(logger, options);
|
|
71
73
|
return server.connect(lockName);
|
|
72
74
|
}
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
76
|
+
async #databaseOpenAttempt(logger: PowerSyncLogger, options: RawWaSqliteDatabaseOptions): Promise<DatabaseServer> {
|
|
77
|
+
const { filename, readonly, vfs } = options;
|
|
78
|
+
// We don't need navigator locks for shared workers because all queries run in this shared worker exclusively.
|
|
79
|
+
// For read-only connections, we use a VFS that supports concurrent reads (so a single lock on the connection is
|
|
80
|
+
// fine). In-memory databases either run in a shared worker or aren't shared across tabs at all, so the internal
|
|
81
|
+
// lock is enough.
|
|
82
|
+
const needsNavigatorLocks = !(isSharedWorker || readonly || vfs == WASQLiteVFS.InMemoryVfs);
|
|
83
|
+
const activeDatabases = this.#activeDatabases;
|
|
84
|
+
|
|
85
|
+
async function openDatabase() {
|
|
86
|
+
let server: DatabaseServer | undefined = activeDatabases.get(filename);
|
|
82
87
|
if (server == null) {
|
|
83
|
-
// We don't need navigator locks for shared workers because all queries run in this shared worker exclusively.
|
|
84
|
-
// For read-only connections, we use a VFS that supports concurrent reads (so a single lock on the connection is
|
|
85
|
-
// fine). In-memory databases either run in a shared worker or aren't shared across tabs at all, so the internal
|
|
86
|
-
// lock is enough.
|
|
87
|
-
const needsNavigatorLocks = !(isSharedWorker || readonly || vfs == WASQLiteVFS.InMemoryVfs);
|
|
88
88
|
const connection = new RawSqliteConnection(options);
|
|
89
89
|
const withSafeConcurrency = new ConcurrentSqliteConnection(connection, needsNavigatorLocks);
|
|
90
90
|
|
|
@@ -101,21 +101,29 @@ export class MultiDatabaseServer {
|
|
|
101
101
|
}
|
|
102
102
|
returnLease();
|
|
103
103
|
|
|
104
|
-
const onClose = () =>
|
|
104
|
+
const onClose = () => activeDatabases.delete(filename);
|
|
105
105
|
server = new DatabaseServer({
|
|
106
106
|
inner: withSafeConcurrency,
|
|
107
107
|
logger,
|
|
108
108
|
onClose
|
|
109
109
|
});
|
|
110
|
-
|
|
110
|
+
activeDatabases.set(filename, server);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
return server;
|
|
114
|
-
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (needsNavigatorLocks) {
|
|
117
|
+
return getNavigatorLocks().request(OPEN_DB_LOCK, openDatabase);
|
|
118
|
+
} else {
|
|
119
|
+
// Even if we don't need navigator locks, this avoids a race between the activeDatabases.get() call, the async
|
|
120
|
+
// open logic and the final activeDatabases.set() step.
|
|
121
|
+
return this.#localOpenLock.runExclusive(openDatabase);
|
|
122
|
+
}
|
|
115
123
|
}
|
|
116
124
|
|
|
117
125
|
closeAll() {
|
|
118
|
-
const existingDatabases = [...this
|
|
126
|
+
const existingDatabases = [...this.#activeDatabases.values()];
|
|
119
127
|
return Promise.all(
|
|
120
128
|
existingDatabases.map((db) => {
|
|
121
129
|
db.forceClose();
|
|
@@ -8,6 +8,7 @@ export abstract class AbstractSharedSyncClientProvider {
|
|
|
8
8
|
abstract fetchCredentials(): Promise<PowerSyncCredentials | null>;
|
|
9
9
|
abstract invalidateCredentials(): void;
|
|
10
10
|
abstract uploadCrud(): Promise<void>;
|
|
11
|
+
abstract postCheckpointRequest(clientId: string, requestId: string): Promise<string | null>;
|
|
11
12
|
abstract statusChanged(status: SyncStatusJson): void;
|
|
12
13
|
abstract getDBWorkerPort(): Promise<MessagePort>;
|
|
13
14
|
|
|
@@ -60,7 +60,7 @@ export type ManualSharedSyncPayload = {
|
|
|
60
60
|
export type SharedSyncInitOptions = {
|
|
61
61
|
streamOptions: Omit<
|
|
62
62
|
WebStreamingSyncImplementationOptions,
|
|
63
|
-
'adapter' | 'uploadCrud' | 'remote' | 'subscriptions' | 'logger'
|
|
63
|
+
'adapter' | 'uploadCrud' | 'postCheckpointRequest' | 'remote' | 'subscriptions' | 'logger'
|
|
64
64
|
>;
|
|
65
65
|
dbParams: ResolvedWebSQLOpenOptions;
|
|
66
66
|
enableBroadcastLogs: boolean;
|
|
@@ -85,14 +85,6 @@ export type WrappedSyncPort = {
|
|
|
85
85
|
isClosing: boolean;
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
-
/**
|
|
89
|
-
* @internal
|
|
90
|
-
*/
|
|
91
|
-
export type RemoteOperationAbortController = {
|
|
92
|
-
controller: AbortController;
|
|
93
|
-
activePort: WrappedSyncPort;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
88
|
/**
|
|
97
89
|
* HACK: The shared implementation wraps and provides its own
|
|
98
90
|
* PowerSyncBackendConnector when generating the streaming sync implementation.
|
|
@@ -110,9 +102,6 @@ export class SharedSyncImplementation extends BaseObserver<SharedSyncImplementat
|
|
|
110
102
|
protected isInitialized: Promise<void>;
|
|
111
103
|
protected statusListener?: () => void;
|
|
112
104
|
|
|
113
|
-
protected fetchCredentialsController?: RemoteOperationAbortController;
|
|
114
|
-
protected uploadDataController?: RemoteOperationAbortController;
|
|
115
|
-
|
|
116
105
|
protected syncParams: SharedSyncInitOptions | null;
|
|
117
106
|
protected lastConnectOptions: ResolvedSyncOptions | undefined;
|
|
118
107
|
protected portMutex: Mutex;
|
|
@@ -334,18 +323,6 @@ export class SharedSyncImplementation extends BaseObserver<SharedSyncImplementat
|
|
|
334
323
|
// Remove from the list of active ports
|
|
335
324
|
this.ports.splice(index, 1);
|
|
336
325
|
|
|
337
|
-
/**
|
|
338
|
-
* The port might currently be in use. Any active functions might
|
|
339
|
-
* not resolve. Abort them here.
|
|
340
|
-
*/
|
|
341
|
-
[this.fetchCredentialsController, this.uploadDataController].forEach((abortController) => {
|
|
342
|
-
if (abortController?.activePort == port) {
|
|
343
|
-
abortController!.controller.abort(
|
|
344
|
-
new AbortOperation('Closing pending requests after client port is removed')
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
});
|
|
348
|
-
|
|
349
326
|
// Close the worker wrapped database connection, we can't accurately rely on this connection
|
|
350
327
|
for (const closeListener of trackedPort.closeListeners) {
|
|
351
328
|
await closeListener();
|
|
@@ -363,10 +340,8 @@ export class SharedSyncImplementation extends BaseObserver<SharedSyncImplementat
|
|
|
363
340
|
});
|
|
364
341
|
}
|
|
365
342
|
|
|
366
|
-
|
|
367
|
-
return this.withSyncImplementation(
|
|
368
|
-
return sync.getWriteCheckpoint();
|
|
369
|
-
});
|
|
343
|
+
requestCheckpoint() {
|
|
344
|
+
return this.withSyncImplementation((sync) => sync.requestCheckpoint());
|
|
370
345
|
}
|
|
371
346
|
|
|
372
347
|
protected async withSyncImplementation<T>(callback: (sync: StreamingSyncImplementation) => Promise<T>): Promise<T> {
|
|
@@ -411,58 +386,27 @@ export class SharedSyncImplementation extends BaseObserver<SharedSyncImplementat
|
|
|
411
386
|
this.logger.log({ level: LogLevels.error, message: 'error invalidating credentials', error });
|
|
412
387
|
}
|
|
413
388
|
},
|
|
414
|
-
fetchCredentials:
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
activePort: lastPort
|
|
424
|
-
};
|
|
425
|
-
|
|
426
|
-
abortController.signal.onabort = reject;
|
|
427
|
-
try {
|
|
428
|
-
this.logger.log({
|
|
429
|
-
level: LogLevels.info,
|
|
430
|
-
message: 'calling the last port client provider for credentials'
|
|
431
|
-
});
|
|
432
|
-
resolve(await lastPort.clientProvider.fetchCredentials());
|
|
433
|
-
} catch (ex) {
|
|
434
|
-
reject(ex);
|
|
435
|
-
} finally {
|
|
436
|
-
this.fetchCredentialsController = undefined;
|
|
437
|
-
}
|
|
438
|
-
});
|
|
389
|
+
fetchCredentials: () => {
|
|
390
|
+
return this.#useConnector((port) => {
|
|
391
|
+
this.logger.log({
|
|
392
|
+
level: LogLevels.info,
|
|
393
|
+
message: 'calling the last port client provider for credentials'
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
return port.clientProvider.fetchCredentials();
|
|
397
|
+
}, 'fetchCredentials');
|
|
439
398
|
}
|
|
440
399
|
},
|
|
441
400
|
this.logger
|
|
442
401
|
),
|
|
443
|
-
uploadCrud:
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
this.uploadDataController = {
|
|
452
|
-
controller: abortController,
|
|
453
|
-
activePort: lastPort
|
|
454
|
-
};
|
|
455
|
-
|
|
456
|
-
// Resolving will make it retry
|
|
457
|
-
abortController.signal.onabort = () => resolve();
|
|
458
|
-
try {
|
|
459
|
-
resolve(await lastPort.clientProvider.uploadCrud());
|
|
460
|
-
} catch (ex) {
|
|
461
|
-
reject(ex);
|
|
462
|
-
} finally {
|
|
463
|
-
this.uploadDataController = undefined;
|
|
464
|
-
}
|
|
465
|
-
});
|
|
402
|
+
uploadCrud: () => {
|
|
403
|
+
return this.#useConnector((port) => port.clientProvider.uploadCrud(), 'uploadCrud');
|
|
404
|
+
},
|
|
405
|
+
postCheckpointRequest: (clientId, requestId) => {
|
|
406
|
+
return this.#useConnector(
|
|
407
|
+
(port) => port.clientProvider.postCheckpointRequest(clientId, requestId),
|
|
408
|
+
'postCheckpointRequest'
|
|
409
|
+
);
|
|
466
410
|
},
|
|
467
411
|
...syncParams.streamOptions,
|
|
468
412
|
subscriptions: this.subscriptions,
|
|
@@ -471,6 +415,27 @@ export class SharedSyncImplementation extends BaseObserver<SharedSyncImplementat
|
|
|
471
415
|
});
|
|
472
416
|
}
|
|
473
417
|
|
|
418
|
+
async #useConnector<T>(inner: (port: WrappedSyncPort) => Promise<T>, debugContext: string): Promise<T> {
|
|
419
|
+
const lastPort = await this.getLastWrappedPort();
|
|
420
|
+
if (!lastPort) {
|
|
421
|
+
throw new Error(`No client port found for ${debugContext}`);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return new Promise((resolve, reject) => {
|
|
425
|
+
function portClosed() {
|
|
426
|
+
reject(new Error(`Tab closed while handling ${debugContext}`));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
lastPort.closeListeners.push(portClosed);
|
|
430
|
+
|
|
431
|
+
inner(lastPort)
|
|
432
|
+
.then(resolve, reject)
|
|
433
|
+
.finally(() => {
|
|
434
|
+
lastPort.closeListeners.splice(lastPort.closeListeners.indexOf(portClosed), 1);
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
|
|
474
439
|
/**
|
|
475
440
|
* Requests a random client to share its database connection with us.
|
|
476
441
|
*/
|
|
@@ -78,10 +78,6 @@ export class WorkerClient {
|
|
|
78
78
|
return this.sync.setParams(params);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
getWriteCheckpoint() {
|
|
82
|
-
return this.sync.getWriteCheckpoint();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
81
|
connect(options: ResolvedSyncOptions, schema: any) {
|
|
86
82
|
return this.sync.connect(options, schema);
|
|
87
83
|
}
|
|
@@ -92,6 +88,10 @@ export class WorkerClient {
|
|
|
92
88
|
}
|
|
93
89
|
}
|
|
94
90
|
|
|
91
|
+
requestCheckpoint(): Promise<bigint> {
|
|
92
|
+
return this.sync.requestCheckpoint();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
95
|
disconnect() {
|
|
96
96
|
return this.sync.disconnect();
|
|
97
97
|
}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{F as e}from"./FacadeVFS-d1ZDvud7.js";import{r as t,f as s,e as a,I as i,H as r,j as n,S as o,k as l,l as c,m as h,n as d,o as u,p as g,q as w,t as p,u as f,v as m,w as y,i as k,g as b,a as x,b as I,J as T,A as v,x as L,y as F,z as H,B as S,D as P,d as z,F as A,E}from"./worker.js";class U{#e;#t=null;#s=Promise.resolve(null);#a=!1;constructor(e){this.#e=e}get name(){return this.#e}get mode(){return this.#t}close(){this.release()}async acquire(e,t=-1){if(this.#a)throw new Error("Lock is already being acquired");this.#a=!0;try{if(this.#t)throw new Error(`Lock ${this.#e} is already acquired`);return this.#s=new Promise((s,a)=>{const i={mode:e,ifAvailable:0===t};t>0&&(i.signal=AbortSignal.timeout(t)),navigator.locks.request(this.#e,i,t=>null===t?s(null):(this.#t=e,new Promise(e=>{s(e)}))).catch(e=>a(e))}),this.#s.then(e=>!!e)}finally{this.#a=!1}}release(){this.#s.then(e=>e?.(),()=>{}),this.#t=null}}class O extends U{#i;#r=!1;#n=!1;constructor(e){super(e),this.#i=new BroadcastChannel(e),this.#i.onmessage=e=>{this.#r?this.#n=!0:this.release()}}close(){super.close(),this.#i.onmessage=null,this.#i.close()}async acquire(e,t=-1){this.#r=!0;try{if(e===this.mode)return!0;if(this.mode)super.release();else if(await super.acquire(e,0))return!0;const s=super.acquire(e,t);return this.#i.postMessage({}),await s}catch(e){throw this.release(),e}}acquireIfHeld(e){return e===this.mode&&(this.#r=!0,!0)}release(){super.release(),this.#r=!1,this.#n=!1}releaseLazy(){this.#r=!1,this.#n&&this.release()}}const C=931071620,$=32,R=32;class _{log=null;options={autoCheckpoint:1,backstopInterval:3e4,journalSizeLimit:1e3};#o;#l;#c;#h;#d;#u;#g=0;#w=null;#p=0;#f;#m=null;#y=null;#k=new Map;#b=new Map;#x=new Map;#I=0;#T;#v;#L=0;#F=new AbortController;constructor(e,t,s,a={}){this.#o=e,this.#l=t,this.#c=s,this.options=Object.assign(this.options,a),this.#f=(async()=>{await this.#H(),this.#T=new BroadcastChannel(`${e}#wa`),this.#T.onmessage=e=>{this.#S(e)};const t=this.#c.map(e=>this.#P(e)).filter(e=>e).sort((e,t)=>e.nextTxId-t.nextTxId)[0]??this.#z(Math.floor(4294967295*Math.random()));this.#d=t,this.#h=this.#c[1&t.salt1],this.#u=$,this.#g=t.nextTxId-1;for(const e of this.#A())this.#E(e);this.#H(),this.#L=performance.now(),this.#U()})()}ready(){return this.#f}close(){this.#F.abort(),this.#T.onmessage=null,clearTimeout(this.#v),this.#y?.release(),this.#T.close()}isolateForRead(){if(null!==this.#m)throw new Error("Already in isolated state");this.#m="read",clearTimeout(this.#v),this.#v=null}isolateForWrite(){if(null!==this.#m)throw new Error("Already in isolated state");this.#m="write",clearTimeout(this.#v),this.#v=null,this.#O({readToCurrent:!0})}rejoin(){"read"===this.#m&&this.#O({autoCheckpoint:!0}),this.#m=null,this.#U()}read(e){const t=this.#w?.pages.get(e)??this.#k.get(e);return t?t.pageData?(this.log?.(`%cread page at ${e} from WAL ${1&t.waSalt1}:${t.waOffset} (cached)`,"background-color: gold;"),t.pageData):(this.log?.(`%cread page at ${e} from WAL ${1&t.waSalt1}:${t.waOffset}`,"background-color: gold;"),this.#C(t)):null}write(e,t,s){if("write"!==this.#m)throw new Error("Not in write isolated state");if(!this.#w){const e=this.options.journalSizeLimit>0?this.options.journalSizeLimit:1e3;this.#I>=e&&this.#$()&&(this.log?.(`%cchange WAL file at ${this.#I} pages`,"background-color: lightskyblue;"),this.#R()),this.#_(),s.dstPageSize!==t.byteLength&&(this.#w.newPageSize=s.dstPageSize)}if(this.#w.newPageSize){const s=R+this.#w.newPageSize;if(t.byteLength>this.#w.newPageSize)for(let s=0;s<t.byteLength;s+=this.#w.newPageSize){const a=t.slice(s,s+this.#w.newPageSize),i=this.#q(e+s,a);this.log?.(`%cwrite page at ${e+s} to WAL ${1&this.#d.salt1}:${i}`,"background-color: lightskyblue;")}else{const a=e%this.#w.newPageSize,i=this.#u+(e-a)/this.#w.newPageSize*s+R+a;this.#h.write(t.subarray(),{at:i}),this.log?.(`%cwrite page at ${e} to WAL ${1&this.#d.salt1}:${i}`,"background-color: lightskyblue;")}}else{const s=this.#q(e,t.slice());this.log?.(`%cwrite page at ${e} to WAL ${1&this.#d.salt1}:${s}`,"background-color: lightskyblue;")}}truncate(e){if(this.#w)for(const t of this.#w.pages.keys())t>=e&&this.#w.pages.delete(t)}getFileSize(){return this.#w?.dbFileSize??this.#p}commit(){const e=this.#w;if(e.newPageSize&&0===e.pages.size){let t=1;for(let s=0;s<t;s++){const a=new Uint8Array(e.newPageSize),i=this.#u+s*(R+e.newPageSize)+R;if(this.#h.read(a,{at:i}),0===s){t=new DataView(a.buffer).getUint32(28)}this.#q(s*e.newPageSize,a)}}const t=this.#w.pages.get(0)?.pageData;if(!t)return void this.rollback();{const e=new DataView(t.buffer,t.byteOffset,t.byteLength).getUint32(28);this.#w.dbFileSize=e*t.byteLength}this.#B(),this.#E(e),this.#H();const s={type:"tx",tx:e};this.#T.postMessage(s),this.#j(),this.#L=performance.now()}rollback(){this.#D()}sync(e){"strict"===e.durability&&this.#M()}async checkpoint(e={isPassive:!0}){const t={ifAvailable:e.isPassive};await navigator.locks.request(`${this.#o}#ckpt`,t,async t=>{if(!t)return;if(this.#F.signal.aborted)return;let s=this.#N()-1;if(e.isPassive){if(!this.#b.has(s))return;if((await this.#W()).reduce((e,t)=>Math.min(e,t.maxTxId),this.#g)<s)return}else await this.#V(e=>e.maxTxId>=this.#g),s=this.#g;this.log?.(`%ccheckpoint through txId ${s}`,"background-color: lightgreen;"),this.#G(),e.isPassive||this.#M();const a=new Set;let i=this.#l.getSize();for(let e=this.#b.get(s);e;e=this.#b.get(e.id-1)){e.id===s&&i!==e.dbFileSize&&(i=e.dbFileSize,this.#l.truncate(i));for(const[t,s]of e.pages)if(t<i&&!a.has(t)){const i=s.pageData??this.#C(s);if(this.#l.write(i,{at:t})!==i.byteLength)throw new Error("Checkpoint write failed");a.add(t),this.log?.(`%ccheckpoint wrote txId ${e.id} page at ${t} to database`,"background-color: lightgreen;")}if(e.newPageSize)break}this.log?.("%ccheckpoint flush database file","background-color: lightgreen;"),this.#l.flush(),this.#T.postMessage({type:"ckpt",ckptId:s}),this.#J(s),this.log?.("%ccheckpoint waiting for connection updates","background-color: lightgreen;"),await this.#V(e=>e.minTxId>s),this.#K(),this.log?.("%ccheckpoint complete","background-color: lightgreen;")})}getWriteAheadSize(){return this.#I}isTransactionPending(){return!!this.#w}setBackstopInterval(e){this.options.backstopInterval=e,e>0&&this.#m&&this.#U()}#E(e){this.#b.set(e.id,e),this.#I+=e.pages.size;for(const[t,s]of e.pages)this.#k.set(t,s);this.#p=e.dbFileSize}#O(e={}){let t=!1;for(;this.#x.size;){const e=this.#g+1;let s;this.#x.has(e)?(s=this.#x.get(e),this.#x.delete(s.id),this.#Q(s)):s=this.#X(),this.#E(s),t=!0}if(e.readToCurrent)for(const e of this.#A())this.#E(e),t=!0;t&&(this.#H(),e.autoCheckpoint&&this.#j()),(e.readToCurrent||t)&&(this.#L=performance.now())}#j(){this.options.autoCheckpoint>0&&this.checkpoint({isPassive:!0})}#J(e){this.log?.(`%capply checkpoint through txId ${e}`,"background-color: lightgreen;");for(let t=this.#b.get(e);t;t=this.#b.get(t.id-1)){for(const[e,s]of t.pages.entries()){this.#k.get(e)===s&&(this.log?.(`%cremove txId ${t.id} page at offset ${e}`,"background-color: lightgreen;"),this.#k.delete(e))}this.#b.delete(t.id),this.#I-=t.pages.size}this.#H()}#S(e){if("tx"===e.data.type){const t=e.data.tx;t.id>this.#g&&(this.#x.set(t.id,t),null===this.#m&&this.#O({autoCheckpoint:!0}))}else if("ckpt"===e.data.type){const t=e.data.ckptId;this.#J(t)}}#U(){if(this.options.backstopInterval<=0)return;if(this.#m)throw new Error("Backstop was invoked in an isolated state");if(performance.now()>=this.#L+this.options.backstopInterval){const e=this.#g;this.#O({readToCurrent:!0}),this.#g>e&&this.log?.(`%cbackstop txId ${e} -> ${this.#g}`,"background-color: lightyellow;"),this.#L=performance.now()}const e=this.#L+this.options.backstopInterval-performance.now();clearTimeout(this.#v),this.#v=self.setTimeout(()=>{this.#U()},e)}async#H(){const e=this.#y,t=this.#Y();if(e?.name!==t&&(this.#y=new U(t),await this.#y.acquire("shared").then(()=>{e?.release()}),this.log)){const{minTxId:e,maxTxId:s}=this.#Z(t);this.log?.(`%ctxId to ${e}:${s}`,"background-color: pink;")}}async#W(){const{held:e}=await navigator.locks.query();return e.map(e=>this.#Z(e.name)).filter(e=>null!==e)}#Y(){const e=this.#g,t=this.#b.keys().next().value??e+1;return`${this.#o}-txId<${t.toString(36)}:${e.toString(36)}>`}#Z(e){const t=e.match(/^(.*)-txId<([0-9a-z]+):([0-9a-z]+)>$/);return t?.[1]===this.#o?{name:t[1],minTxId:parseInt(t[2],36),maxTxId:parseInt(t[3],36),encoded:e}:null}async#V(e){let t=[];do{t.length>0&&await Promise.all(t.map(e=>navigator.locks.request(e,async()=>{}))),t=(await this.#W()).filter(t=>!e(t)).map(e=>e.encoded)}while(t.length>0)}#C(e){const t=this.#c[1&e.waSalt1],s=new Uint8Array(e.pageSize),a=t.read(s,{at:e.waOffset});if(a!==e.pageSize)throw new Error(`Short WAL read: expected ${e.pageSize} bytes, got ${a}`);return s}*#A(){for(;;){const e=this.#X();if(!e)break;yield e}}#X(){const e={id:0,pages:new Map,dbFileSize:0,waSalt1:0,waOffsetEnd:0};let t=this.#u;for(;;){const s=this.#ee(t);if(!s)return null;if(0===s.frameType)e.pages.set(s.pageOffset,{pageSize:s.pageData.byteLength,waOffset:t+R,waSalt1:this.#d.salt1});else{if(1===s.frameType)return this.#g+=1,this.#u=t+s.byteLength,e.id=this.#g,e.dbFileSize=s.dbFileSize,e.waSalt1=this.#d.salt1,e.newPageSize=1&s.flags?e.pages.get(0).pageSize:null,e.waOffsetEnd=this.#u,e;if(2===s.frameType){this.#te(s.fileHeader),t=this.#u;continue}}t+=s.byteLength}}#Q(e){if(e.waSalt1!==this.#d.salt1&&!this.#te(null))throw new Error("invalid WAL file");this.#g=e.id,this.#u=e.waOffsetEnd}#_(e={}){return this.#w={id:this.#g+1,pages:new Map,dbFileSize:this.#p,waSalt1:this.#d.salt1,waOffsetEnd:this.#u},this.#w}#q(e,t){const s=new DataView(new ArrayBuffer(R));s.setUint8(0,0),s.setUint16(2,65536===t.byteLength?1:t.byteLength),s.setBigUint64(8,BigInt(e)),s.setUint32(16,this.#d.salt1),s.setUint32(20,this.#d.salt2);const a=new q;a.update(new Uint8Array(s.buffer,0,24)),a.update(t),s.setUint32(24,a.s0),s.setUint32(28,a.s1);const i=this.#h.write(s,{at:this.#w.waOffsetEnd})+this.#h.write(t,{at:this.#w.waOffsetEnd+R});if(i!==s.byteLength+t.byteLength)throw new Error("write failed");const r={pageSize:t.byteLength,waOffset:this.#w.waOffsetEnd+R,waSalt1:this.#d.salt1,pageData:0===e?t:void 0};return this.#w.pages.set(e,r),this.#w.waOffsetEnd+=i,r.waOffset}#B(){const e=new DataView(new ArrayBuffer(R));e.setUint8(0,1),e.setUint8(1,this.#w.newPageSize?1:0),e.setBigUint64(8,BigInt(this.#w.dbFileSize)),e.setUint32(16,this.#d.salt1),e.setUint32(20,this.#d.salt2);const t=new q;t.update(new Uint8Array(e.buffer,0,24)),e.setUint32(24,t.s0),e.setUint32(28,t.s1);const s=this.#h.write(e,{at:this.#w.waOffsetEnd});if(s!==e.byteLength)throw new Error("write failed");this.#w.waOffsetEnd+=s;const a=this.#w;return this.#w=null,this.#u=a.waOffsetEnd,this.#g=a.id,a}#D(){this.#w=null,this.#h.truncate(this.#u)}#R(){const e=new DataView(new ArrayBuffer(R));e.setUint8(0,2),e.setUint32(16,this.#d.salt1),e.setUint32(20,this.#d.salt2);const t=new q;t.update(new Uint8Array(e.buffer,0,24)),e.setUint32(24,t.s0),e.setUint32(28,t.s1);if(this.#h.write(e,{at:this.#u})!==e.byteLength)throw new Error("write failed");this.#d=this.#z(),this.#h=this.#se(),this.#u=$}#N(){return this.#d.nextTxId}#M(){this.#h.flush()}#G(){this.#se().flush()}#$(){if(this.#b.has(this.#d.nextTxId-1))return!1;const e=this.#se();return e.getSize()<$||null===this.#P(e)}#K(){this.#se().truncate(0)}#te(e){const t=this.#se();return e||(e=this.#P(t),e?.salt1===this.#d.salt1+1>>>0)?(this.#h=t,this.#d=e,this.#u=$,e):null}#se(){return this.#h!==this.#c[0]?this.#c[0]:this.#c[1]}#P(e){const t=new DataView(new ArrayBuffer($));if(e.read(t,{at:0})!==t.byteLength)return null;if(t.getUint32(0)!==C)return null;const s=new q;return s.update(new Uint8Array(t.buffer,0,24)),s.matches(t.getUint32(24),t.getUint32(28))?{nextTxId:Number(t.getBigUint64(8)),salt1:t.getUint32(16),salt2:t.getUint32(20)}:null}#ee(e){const t=new DataView(new ArrayBuffer(R));if(this.#h.read(t,{at:e})!==t.byteLength)return null;const s=t.getUint32(16),a=t.getUint32(20);if(s!==this.#d.salt1||a!==this.#d.salt2)return null;const i=1===(r=t.getUint16(2))?65536:r;var r;let n;if(i){n=new Uint8Array(i);if(this.#h.read(n,{at:e+R})!==i)return null}const o=new q;if(o.update(new Uint8Array(t.buffer,0,24)),n&&o.update(n),!o.matches(t.getUint32(24),t.getUint32(28)))return null;const l=t.getUint8(0);if(0===l)return{frameType:l,byteLength:R+i,pageOffset:Number(t.getBigUint64(8)),pageData:n};if(1===l)return{frameType:l,byteLength:R,flags:t.getUint8(1),dbFileSize:Number(t.getBigUint64(8))};if(2===l){const e=this.#P(this.#se());return e?.salt1!==this.#d.salt1+1>>>0?null:{frameType:l,byteLength:R,fileHeader:e}}throw new Error(`Invalid frame type: ${l}`)}#z(e=this.#d.salt1){const t=this.#g+1,s=e+1>>>0,a=Math.floor(4294967295*Math.random())>>>0,i=new DataView(new ArrayBuffer($));i.setUint32(0,C),i.setBigUint64(8,BigInt(t)),i.setUint32(16,s),i.setUint32(20,a);const r=new q;r.update(new Uint8Array(i.buffer,0,24)),i.setUint32(24,r.s0),i.setUint32(28,r.s1);if(this.#c[1&s].write(i,{at:0})!==i.byteLength)throw new Error("write failed");return{nextTxId:t,salt1:s,salt2:a}}}class q{s0=0;s1=0;update(e){if(e.byteLength%8!=0)throw new Error("Data must be a multiple of 8 bytes");const t=ArrayBuffer.isView(e)?new Uint32Array(e.buffer,e.byteOffset,e.byteLength/4):new Uint32Array(e);for(let e=0;e<t.length;e+=2)this.s0=this.s0+t[e]+this.s1>>>0,this.s1=this.s1+t[e+1]+this.s0>>>0}matches(e,t){return this.s0===e&&this.s1===t}}const B=new FinalizationRegistry(e=>e());class j extends e{lastError=null;log=null;mapIdToFile=new Map;mapPathToFile=new Map;boundTempFiles=new Map;unboundTempFiles=new Set;options={nTmpFiles:6};_ready;static async create(e,t,s){const a=new j(e,t);return Object.assign(a.options,s),await a.isReady(),a}constructor(e,t){super(e,t),this._ready=(async()=>{let e=await navigator.storage.getDirectory();e=await e.getDirectoryHandle(".wa-sqlite",{create:!0});for await(const t of e.keys())t.startsWith(".session-")&&await navigator.locks.request(t,{ifAvailable:!0},async s=>{if(s)try{await e.removeEntry(t,{recursive:!0})}catch(e){}});const t=`.session-${Math.random().toString(16).slice(2)}`;await new Promise(e=>{navigator.locks.request(t,()=>(e(),new Promise(e=>{B.register(this,e)})))}),e=await e.getDirectoryHandle(t,{create:!0});for(let t=0;t<this.options.nTmpFiles;t++){const s=await e.getFileHandle(t.toString(),{create:!0}),a=await s.createSyncAccessHandle();B.register(this,()=>a.close()),this.unboundTempFiles.add(a)}})()}isReady(){return Promise.all([super.isReady(),this._ready]).then(()=>!0)}jOpen(e,c,h,d){try{null===e&&(e=Math.random().toString(16).slice(2));const l=this.mapPathToFile.get(e)??{zName:e,flags:h,retryResult:null};if(this.mapPathToFile.set(e,l),h&t){if(null===l.retryResult)return this._module.retryOps.push(this.#ae(e,h,c,d)),s;if(l.retryResult instanceof Error){const e=l.retryResult;throw l.retryResult=null,e}l.accessHandle=l.retryResult.accessHandle,l.waHandles=l.retryResult.waHandles,l.writeAhead=l.retryResult.writeAhead,l.retryResult=null,l.lockState=a,l.lockingMode="normal",l.readLock=new O(`${e}#read`),l.writeLock=new O(`${e}#write`),l.useLazyLock="readwrite",l.timeout=-1,l.synchronous=1,l.writeHint=null,l.pageSize=null,l.overwrite=!1}else{if(h&(i|r))throw new Error("WAL and super-journal files are not supported");if(l.accessHandle);else{if(!(h&n))throw new Error("file not found");l.accessHandle=this.#ie(e)}}return this.mapIdToFile.set(c,l),d.setInt32(0,h,!0),o}catch(t){return console.error(t.stack),this.lastError=t,this.mapPathToFile.delete(e),l}}jDelete(e,t){try{if(!this.boundTempFiles.has(e))throw new Error(`unexpected file deletion: ${e}`);{const t=this.mapPathToFile.get(e);this.#re(t)}return o}catch(e){return console.error(e.stack),this.lastError=e,c}}jAccess(e,t,s){try{const t=this.mapPathToFile.get(e);return s.setInt32(0,t?1:0,!0),o}catch(e){return console.error(e.stack),this.lastError=e,h}}jClose(e){try{const s=this.mapIdToFile.get(e);return s?.flags&t?(s.writeAhead.close(),s.accessHandle.close(),s.waHandles.forEach(e=>e.close()),this.mapPathToFile.delete(s?.zName),s.readLock.close(),s.writeLock.close()):s?.flags&d&&this.#re(s),this.mapIdToFile.delete(e),o}catch(e){return console.error(e.stack),this.lastError=e,u}}jRead(e,s,a){try{const i=this.mapIdToFile.get(e);let r=null;if(i.flags&t){const e=a<100?a:0,t=i.writeAhead.read(a-e);if(t){const a=t.subarray(e,e+s.byteLength);s.set(a),r=a.byteLength}}return null===r&&(r=i.accessHandle.read(s.subarray(),{at:a})),r<s.byteLength?(s.fill(0,r),g):o}catch(e){return console.error(e.stack),this.lastError=e,w}}jWrite(e,s,a){try{const i=this.mapIdToFile.get(e);if(i.flags&t){const e=i.overwrite&&i.pageSize!==s.byteLength;return i.writeAhead.write(a,s,{dstPageSize:e?i.pageSize:null}),o}return i.accessHandle.write(s.subarray(),{at:a}),o}catch(e){return console.error(e.stack),this.lastError=e,p}}jTruncate(e,s){try{const a=this.mapIdToFile.get(e);return a.flags&t?(a.writeAhead.truncate(s),o):(a.accessHandle.truncate(s),o)}catch(e){return console.error(e.stack),this.lastError=e,f}}jSync(e,s){try{const s=this.mapIdToFile.get(e);if(s.flags&t){const e=s.synchronous>1?"strict":"relaxed";s.writeAhead.sync({durability:e})}return o}catch(e){return console.error(e.stack),this.lastError=e,m}}jFileSize(e,s){try{const a=this.mapIdToFile.get(e);let i;return i=a.flags&t&&a.writeAhead.getFileSize()||a.accessHandle.getSize(),s.setBigInt64(0,BigInt(i),!0),o}catch(e){return console.error(e.stack),this.lastError=e,y}}jLock(e,t){try{const i=this.mapIdToFile.get(e);if(i.lockState===a&&t===k){if(null===i.retryResult){if("exclusive"===i.lockingMode)return i.retryResult={},this._module.retryOps.push(this.#ne(i)),s;if(i.writeHint){if(!i.writeLock.acquireIfHeld("exclusive"))return i.retryResult={},this._module.retryOps.push(this.#ne(i)),s;i.writeAhead.isolateForWrite()}else{if(!i.readLock.acquireIfHeld("shared"))return i.retryResult={},this._module.retryOps.push(this.#oe(i)),s;i.writeAhead.isolateForRead()}}else if(i.retryResult instanceof Error){const e=i.retryResult;throw i.retryResult=null,e}i.retryResult=null}else if(t>=b&&!i.writeLock.mode)throw new Error("Write transaction cannot use BEGIN DEFERRED");return i.lockState=t,o}catch(e){return"TimeoutError"===e.name?s:(console.error(e.stack),this.lastError=e,x)}}jUnlock(e,t){try{const s=this.mapIdToFile.get(e);if(!s.retryResult&&t===a){switch(s.writeAhead.rejoin(),s.useLazyLock){case"none":s.writeLock.release(),s.readLock.release();break;case"read":s.writeLock.release(),s.readLock.releaseLazy();break;case"write":s.writeLock.releaseLazy(),s.readLock.release();break;case"readwrite":s.writeLock.releaseLazy(),s.readLock.releaseLazy()}s.writeHint=null}s.lockState=t}catch(e){return console.error(e.stack),this.lastError=e,I}}jCheckReservedLock(e,t){return console.assert(!1,"unexpected"),t.setInt32(0,0,!0),o}jFileControl(e,s,a){try{const i=this.mapIdToFile.get(e);switch(s){case S:const e=this._module.UTF8ToString(a.getUint32(4,!0)),s=a.getUint32(8,!0),r=s?this._module.UTF8ToString(s):null;switch(this.log?.(`PRAGMA ${e} ${r}`),e.toLowerCase()){case"experimental_pragma_20251114":switch(r){case"1":i.writeHint="reserved";break;case"2":i.writeHint="exclusive";break;default:throw new Error(`unexpected write hint value: ${r}`)}break;case"backstop_interval":if(null!==r){const e=parseInt(r);i.writeAhead.setBackstopInterval(e)}else{const e=i.writeAhead.options.backstopInterval.toString(),t=this._module._sqlite3_malloc64(e.length+1);this._module.stringToUTF8(e,t,e.length+1),a.setUint32(0,t,!0)}return o;case"busy_timeout":if(null!==r)i.timeout=parseInt(r);else{const e=i.timeout.toString(),t=this._module._sqlite3_malloc64(e.length+1);this._module.stringToUTF8(e,t,e.length+1),a.setUint32(0,t,!0)}return o;case"journal_size_limit":if(null!==r){const e=parseInt(r);i.writeAhead.options.journalSizeLimit=e}break;case"locking_mode":switch(r?.toLowerCase()){case"normal":i.lockingMode="normal";break;case"exclusive":i.lockingMode="exclusive"}break;case"page_size":if(null!==r){const e=parseInt(r);(1===e||e>=512&&e<=32768&&!(e&e-1))&&(i.pageSize=1===e?65536:e)}break;case"synchronous":if(null!==r)switch(r.toLowerCase()){case"off":case"0":i.synchronous=0;break;case"normal":case"1":i.synchronous=1;break;case"full":case"2":i.synchronous=2;break;case"extra":case"3":i.synchronous=3;break;default:throw new Error(`unexpected synchronous value: ${r}`)}break;case"vfs_trace":return null!==r&&(this.log=0!==parseInt(r)?console.debug:null,i.writeAhead.log=this.log),o;case"wal_autocheckpoint":null!==r&&(i.writeAhead.options.autoCheckpoint=parseInt(r));break;case"wal_checkpoint":const e=(r??"passive").toLowerCase();switch(e){case"passive":this._module.pendingOps.push(this.#le(i,e));break;case"full":case"restart":case"truncate":if(i.writeAhead.isTransactionPending())throw new Error("invalid while a transaction is in progress");this._module.pendingOps.push(this.#le(i,e));break;case"noop":break;default:throw new Error(`unexpected wal_checkpoint mode: ${r}`)}{const e=i.writeAhead.getWriteAheadSize().toString(),t=this._module._sqlite3_malloc64(e.length+1);this._module.stringToUTF8(e,t,e.length+1),a.setUint32(0,t,!0)}return o;case"lazy_lock":if(null!==r){const e=r.toLowerCase();switch(e){case"read":case"write":case"readwrite":case"none":i.useLazyLock=e;break;default:throw new Error(`unexpected value for lazy_lock: ${r}`)}}{const e=i.useLazyLock,t=this._module._sqlite3_malloc64(e.length+1);this._module.stringToUTF8(e,t,e.length+1),a.setUint32(0,t,!0)}return o}break;case H:case F:if(i.flags&t)return o;break;case L:if(i.flags&t)return i.writeAhead.rollback(),o;break;case v:i.flags&t&&i.writeAhead.commit();break;case T:i.overwrite=!0}}catch(e){return console.error(e.stack),this.lastError=e,P}return z}jDeviceCharacteristics(e){return A|E}jGetLastError(e){if(this.lastError){console.error(this.lastError);const t=e.subarray(0,e.byteLength-1),{written:s}=(new TextEncoder).encodeInto(this.lastError.message,t);e[s]=0}return o}#ie(e){if(0===this.unboundTempFiles.size)throw new Error("no temporary files available");const t=this.unboundTempFiles.values().next().value;return this.unboundTempFiles.delete(t),this.boundTempFiles.set(e,t),t}#re(e){e.accessHandle.truncate(0),this.mapPathToFile.delete(e.zName),this.unboundTempFiles.add(e.accessHandle),this.boundTempFiles.delete(e.zName)}#ce(e,t){return`${e}-wa${t}`}async#le(e,t){const i=[];try{"passive"!==t&&e.lockState===a&&(await e.writeLock.acquire("exclusive"),i.push(()=>e.writeLock.release()),e.writeAhead.isolateForWrite(),i.push(()=>e.writeAhead.rejoin())),await e.writeAhead.checkpoint({isPassive:"passive"===t})}catch(e){throw"AbortError"===e.name&&(e.code=s),e}finally{for(;i.length;)i.pop()()}}async#oe(e){const t=[];try{await e.readLock.acquire("shared",e.timeout),t.push(()=>e.readLock.release()),e.writeAhead.isolateForRead(),e.retryResult={}}catch(s){for(;t.length;)t.pop()();e.retryResult=s}}async#ne(e){const t=[];try{"exclusive"===e.lockingMode&&(await e.readLock.acquire("exclusive",e.timeout),t.push(()=>e.readLock.release())),await e.writeLock.acquire("exclusive",e.timeout),t.push(()=>e.writeLock.release()),e.writeAhead.isolateForWrite(),e.retryResult={}}catch(s){for(;t.length;)t.pop()();e.retryResult=s}}async#ae(e,t,s,a){const i=[],r=this.mapPathToFile.get(e);try{await navigator.locks.request(`${e}#ckpt`,async s=>{const a=e.split("/").filter(e=>e),o=a.pop();let l=await navigator.storage.getDirectory();const c=!!(t&n);for(const e of a)l=await l.getDirectoryHandle(e,{create:c});const h=c&&await async function(){try{return await l.getFileHandle(o),!1}catch(e){if("NotFoundError"===e.name)return!0;throw e}}();async function d(e,t){const s=await l.getFileHandle(e,t),a=await s.createSyncAccessHandle({mode:"readwrite-unsafe"});return i.push(()=>{a.close(),h&&l.removeEntry(e)}),a}const u=await d(o,{create:c}),g=await Promise.all([0,1].map(async e=>{const t=this.#ce(o,e),s=await d(t,{create:!0});return h&&s.truncate(0),s})),w=new _(e,u,g);await w.ready(),r.retryResult={accessHandle:u,waHandles:g,writeAhead:w}})}catch(e){for(;i.length;)i.pop()();r.retryResult=e}}}export{j as OPFSWriteAheadVFS};
|
|
2
|
-
//# sourceMappingURL=OPFSWriteAheadVFS-BzodSqNq.js.map
|