@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.
Files changed (83) hide show
  1. package/README.md +1 -1
  2. package/dist/index.react_native_web.js +224 -121
  3. package/dist/index.react_native_web.js.map +1 -1
  4. package/dist/worker/AccessHandlePoolVFS-BPUHfZME.js.map +1 -1
  5. package/dist/worker/FacadeVFS-d1ZDvud7.js.map +1 -1
  6. package/dist/worker/IDBBatchAtomicVFS-DbkDb777.js.map +1 -1
  7. package/dist/worker/MemoryVFS-DVJL5F8j.js.map +1 -1
  8. package/dist/worker/OPFSCoopSyncVFS-BgTiWPfa.js.map +1 -1
  9. package/dist/worker/OPFSWriteAheadVFS-Rt5CGCZP.js +2 -0
  10. package/dist/worker/OPFSWriteAheadVFS-Rt5CGCZP.js.map +1 -0
  11. package/dist/worker/mc-wa-sqlite-DDFgWP93.js.map +1 -1
  12. package/dist/worker/mc-wa-sqlite-async-lGclTjKJ.js.map +1 -1
  13. package/dist/worker/wa-sqlite-B0tZMM0j.js.map +1 -1
  14. package/dist/worker/wa-sqlite-async-CM6BmfRh.js.map +1 -1
  15. package/dist/worker/worker.js +1 -1
  16. package/dist/worker/worker.js.map +1 -1
  17. package/lib/db/PowerSyncDatabase.d.ts +1 -2
  18. package/lib/db/PowerSyncDatabase.js +19 -24
  19. package/lib/db/PowerSyncDatabase.js.map +1 -1
  20. package/lib/db/adapters/AsyncWebAdapter.js +4 -55
  21. package/lib/db/adapters/AsyncWebAdapter.js.map +1 -1
  22. package/lib/db/adapters/acquireFromPool.d.ts +7 -0
  23. package/lib/db/adapters/acquireFromPool.js +60 -0
  24. package/lib/db/adapters/acquireFromPool.js.map +1 -0
  25. package/lib/db/adapters/memory-pool/client.d.ts +70 -0
  26. package/lib/db/adapters/memory-pool/client.js +269 -0
  27. package/lib/db/adapters/memory-pool/client.js.map +1 -0
  28. package/lib/db/adapters/memory-pool/shared.d.ts +51 -0
  29. package/lib/db/adapters/memory-pool/shared.js +16 -0
  30. package/lib/db/adapters/memory-pool/shared.js.map +1 -0
  31. package/lib/db/adapters/memory-pool/vfs.d.ts +19 -0
  32. package/lib/db/adapters/memory-pool/vfs.js +247 -0
  33. package/lib/db/adapters/memory-pool/vfs.js.map +1 -0
  34. package/lib/db/adapters/memory-pool/worker.d.ts +1 -0
  35. package/lib/db/adapters/memory-pool/worker.js +45 -0
  36. package/lib/db/adapters/memory-pool/worker.js.map +1 -0
  37. package/lib/db/adapters/options.d.ts +7 -0
  38. package/lib/db/adapters/options.js.map +1 -1
  39. package/lib/db/adapters/wa-sqlite/RawSqliteConnection.d.ts +8 -0
  40. package/lib/db/adapters/wa-sqlite/RawSqliteConnection.js +56 -5
  41. package/lib/db/adapters/wa-sqlite/RawSqliteConnection.js.map +1 -1
  42. package/lib/db/adapters/wa-sqlite/StatementCache.d.ts +16 -0
  43. package/lib/db/adapters/wa-sqlite/StatementCache.js +44 -0
  44. package/lib/db/adapters/wa-sqlite/StatementCache.js.map +1 -0
  45. package/lib/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +7 -4
  46. package/lib/db/adapters/wa-sqlite/WASQLiteOpenFactory.js.map +1 -1
  47. package/lib/db/sync/SSRWebStreamingSyncImplementation.d.ts +1 -8
  48. package/lib/db/sync/SSRWebStreamingSyncImplementation.js +3 -12
  49. package/lib/db/sync/SSRWebStreamingSyncImplementation.js.map +1 -1
  50. package/lib/db/sync/SharedWebStreamingSyncImplementation.d.ts +2 -1
  51. package/lib/db/sync/SharedWebStreamingSyncImplementation.js +6 -4
  52. package/lib/db/sync/SharedWebStreamingSyncImplementation.js.map +1 -1
  53. package/lib/worker/db/MultiDatabaseServer.d.ts +1 -2
  54. package/lib/worker/db/MultiDatabaseServer.js +28 -17
  55. package/lib/worker/db/MultiDatabaseServer.js.map +1 -1
  56. package/lib/worker/sync/AbstractSharedSyncClientProvider.d.ts +1 -0
  57. package/lib/worker/sync/AbstractSharedSyncClientProvider.js.map +1 -1
  58. package/lib/worker/sync/SharedSyncImplementation.d.ts +3 -11
  59. package/lib/worker/sync/SharedSyncImplementation.js +32 -64
  60. package/lib/worker/sync/SharedSyncImplementation.js.map +1 -1
  61. package/lib/worker/sync/WorkerClient.d.ts +1 -1
  62. package/lib/worker/sync/WorkerClient.js +3 -3
  63. package/lib/worker/sync/WorkerClient.js.map +1 -1
  64. package/package.json +15 -8
  65. package/src/db/PowerSyncDatabase.ts +20 -24
  66. package/src/db/adapters/AsyncWebAdapter.ts +13 -61
  67. package/src/db/adapters/acquireFromPool.ts +73 -0
  68. package/src/db/adapters/memory-pool/client.ts +367 -0
  69. package/src/db/adapters/memory-pool/shared.ts +79 -0
  70. package/src/db/adapters/memory-pool/vfs.ts +293 -0
  71. package/src/db/adapters/memory-pool/worker.ts +53 -0
  72. package/src/db/adapters/options.ts +8 -0
  73. package/src/db/adapters/wa-sqlite/RawSqliteConnection.ts +71 -6
  74. package/src/db/adapters/wa-sqlite/StatementCache.ts +50 -0
  75. package/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.ts +17 -5
  76. package/src/db/sync/SSRWebStreamingSyncImplementation.ts +4 -14
  77. package/src/db/sync/SharedWebStreamingSyncImplementation.ts +8 -5
  78. package/src/worker/db/MultiDatabaseServer.ts +29 -21
  79. package/src/worker/sync/AbstractSharedSyncClientProvider.ts +1 -0
  80. package/src/worker/sync/SharedSyncImplementation.ts +41 -76
  81. package/src/worker/sync/WorkerClient.ts +4 -4
  82. package/dist/worker/OPFSWriteAheadVFS-BzodSqNq.js +0 -2
  83. 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
- private activeDatabases = new Map<string, DatabaseServer>();
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.activeDatabases.get(name);
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.databaseOpenAttempt(logger, options);
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.databaseOpenAttempt(logger, options);
72
+ server ??= await this.#databaseOpenAttempt(logger, options);
71
73
  return server.connect(lockName);
72
74
  }
73
75
 
74
- private async databaseOpenAttempt(
75
- logger: PowerSyncLogger,
76
- options: RawWaSqliteDatabaseOptions
77
- ): Promise<DatabaseServer> {
78
- return getNavigatorLocks().request(OPEN_DB_LOCK, async () => {
79
- const { filename, readonly, vfs } = options;
80
-
81
- let server: DatabaseServer | undefined = this.activeDatabases.get(filename);
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 = () => this.activeDatabases.delete(filename);
104
+ const onClose = () => activeDatabases.delete(filename);
105
105
  server = new DatabaseServer({
106
106
  inner: withSafeConcurrency,
107
107
  logger,
108
108
  onClose
109
109
  });
110
- this.activeDatabases.set(filename, server);
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.activeDatabases.values()];
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
- async getWriteCheckpoint(): Promise<string> {
367
- return this.withSyncImplementation(async (sync) => {
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: async () => {
415
- const lastPort = await this.getLastWrappedPort();
416
- if (!lastPort) {
417
- throw new Error('No client port found to fetch credentials');
418
- }
419
- return new Promise(async (resolve, reject) => {
420
- const abortController = new AbortController();
421
- this.fetchCredentialsController = {
422
- controller: abortController,
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: async () => {
444
- const lastPort = await this.getLastWrappedPort();
445
- if (!lastPort) {
446
- throw new Error('No client port found to upload crud');
447
- }
448
-
449
- return new Promise(async (resolve, reject) => {
450
- const abortController = new AbortController();
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