@powersync/web 0.0.0-dev-20251203144301 → 0.0.0-dev-20251209082930

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 (42) hide show
  1. package/dist/0b19af1befc07ce338dd.wasm +0 -0
  2. package/dist/2632c3bda9473da74fd5.wasm +0 -0
  3. package/dist/64f5351ba3784bfe2f3e.wasm +0 -0
  4. package/dist/9318ca94aac4d0fe0135.wasm +0 -0
  5. package/dist/index.umd.js +180 -2433
  6. package/dist/index.umd.js.map +1 -1
  7. package/dist/worker/SharedSyncImplementation.umd.js +106 -1896
  8. package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
  9. package/dist/worker/WASQLiteDB.umd.js +23 -1812
  10. package/dist/worker/WASQLiteDB.umd.js.map +1 -1
  11. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite-async_mjs.umd.js +16 -3
  12. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite-async_mjs.umd.js.map +1 -1
  13. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite_mjs.umd.js +16 -3
  14. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite_mjs.umd.js.map +1 -1
  15. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite-async_mjs.umd.js +16 -3
  16. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite-async_mjs.umd.js.map +1 -1
  17. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js +16 -3
  18. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js.map +1 -1
  19. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js.umd.js +1203 -0
  20. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js.umd.js.map +1 -1
  21. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_IDBBatchAtomicVFS_js.umd.js +1203 -0
  22. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_IDBBatchAtomicVFS_js.umd.js.map +1 -1
  23. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_OPFSCoopSyncVFS_js.umd.js +1820 -0
  24. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_OPFSCoopSyncVFS_js.umd.js.map +1 -0
  25. package/lib/package.json +2 -2
  26. package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.js +13 -6
  27. package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.js +12 -3
  28. package/lib/src/worker/db/WASQLiteDB.worker.js +1 -0
  29. package/lib/src/worker/sync/SharedSyncImplementation.js +71 -78
  30. package/lib/tsconfig.tsbuildinfo +1 -1
  31. package/package.json +5 -5
  32. package/src/db/adapters/LockedAsyncDatabaseAdapter.ts +14 -6
  33. package/src/db/adapters/wa-sqlite/WASQLiteConnection.ts +12 -3
  34. package/src/worker/db/WASQLiteDB.worker.ts +1 -0
  35. package/src/worker/sync/SharedSyncImplementation.ts +75 -81
  36. package/dist/1807036ae51c10ee4d23.wasm +0 -0
  37. package/dist/307d8ce2280e3bae09d5.wasm +0 -0
  38. package/dist/cd8b9e8f4c87bf81c169.wasm +0 -0
  39. package/dist/e797080f5ed0b5324166.wasm +0 -0
  40. package/lib/src/worker/db/opfs.d.ts +0 -96
  41. package/lib/src/worker/db/opfs.js +0 -582
  42. package/src/worker/db/opfs.ts +0 -623
@@ -20,6 +20,7 @@ const OPEN_DB_LOCK = 'open-wasqlite-db';
20
20
  let nextClientId = 1;
21
21
 
22
22
  const openDBShared = async (options: WorkerDBOpenerOptions): Promise<AsyncDatabaseConnection> => {
23
+ // Prevent multiple simultaneous opens from causing race conditions
23
24
  return getNavigatorLocks().request(OPEN_DB_LOCK, async () => {
24
25
  const clientId = nextClientId++;
25
26
  const { dbFilename, logLevel } = options;
@@ -190,7 +190,8 @@ export class SharedSyncImplementation extends BaseObserver<SharedSyncImplementat
190
190
  */
191
191
  protected async getRandomWrappedPort(): Promise<WrappedSyncPort | undefined> {
192
192
  return await this.portMutex.runExclusive(() => {
193
- return this.ports[Math.floor(Math.random() * this.ports.length)];
193
+ const nonClosingPorts = this.ports.filter((p) => !p.isClosing);
194
+ return nonClosingPorts[Math.floor(Math.random() * nonClosingPorts.length)];
194
195
  });
195
196
  }
196
197
 
@@ -495,94 +496,87 @@ export class SharedSyncImplementation extends BaseObserver<SharedSyncImplementat
495
496
  * Opens a worker wrapped database connection. Using the last connected client port.
496
497
  */
497
498
  protected async openInternalDB() {
498
- while (true) {
499
- try {
500
- const client = await this.getRandomWrappedPort();
501
- if (!client) {
502
- // Should not really happen in practice
503
- throw new Error(`Could not open DB connection since no client is connected.`);
504
- }
499
+ const client = await this.getRandomWrappedPort();
500
+ if (!client) {
501
+ // Should not really happen in practice
502
+ throw new Error(`Could not open DB connection since no client is connected.`);
503
+ }
505
504
 
506
- // Fail-safe timeout for opening a database connection.
507
- const timeout = setTimeout(() => {
508
- abortController.abort();
509
- }, 10_000);
510
-
511
- /**
512
- * Handle cases where the client might close while opening a connection.
513
- */
514
- const abortController = new AbortController();
515
- const closeListener = () => {
516
- abortController.abort();
517
- };
505
+ // Fail-safe timeout for opening a database connection.
506
+ const timeout = setTimeout(() => {
507
+ abortController.abort();
508
+ }, 10_000);
509
+
510
+ /**
511
+ * Handle cases where the client might close while opening a connection.
512
+ */
513
+ const abortController = new AbortController();
514
+ const closeListener = () => {
515
+ abortController.abort();
516
+ };
518
517
 
519
- const removeCloseListener = () => {
520
- const index = client.closeListeners.indexOf(closeListener);
521
- if (index >= 0) {
522
- client.closeListeners.splice(index, 1);
523
- }
524
- };
518
+ const removeCloseListener = () => {
519
+ const index = client.closeListeners.indexOf(closeListener);
520
+ if (index >= 0) {
521
+ client.closeListeners.splice(index, 1);
522
+ }
523
+ };
525
524
 
526
- client.closeListeners.push(closeListener);
525
+ client.closeListeners.push(closeListener);
527
526
 
528
- const workerPort = await withAbort({
529
- action: () => client.clientProvider.getDBWorkerPort(),
530
- signal: abortController.signal,
531
- cleanupOnAbort: (port) => {
532
- port.close();
533
- }
534
- }).catch((ex) => {
535
- removeCloseListener();
536
- throw ex;
537
- });
527
+ const workerPort = await withAbort({
528
+ action: () => client.clientProvider.getDBWorkerPort(),
529
+ signal: abortController.signal,
530
+ cleanupOnAbort: (port) => {
531
+ port.close();
532
+ }
533
+ }).catch((ex) => {
534
+ removeCloseListener();
535
+ throw ex;
536
+ });
538
537
 
539
- const remote = Comlink.wrap<OpenAsyncDatabaseConnection>(workerPort);
540
- const identifier = this.syncParams!.dbParams.dbFilename;
541
-
542
- /**
543
- * The open could fail if the tab is closed while we're busy opening the database.
544
- * This operation is typically executed inside an exclusive portMutex lock.
545
- * We typically execute the closeListeners using the portMutex in a different context.
546
- * We can't rely on the closeListeners to abort the operation if the tab is closed.
547
- */
548
- const db = await withAbort({
549
- action: () => remote(this.syncParams!.dbParams),
550
- signal: abortController.signal,
551
- cleanupOnAbort: (db) => {
552
- db.close();
553
- }
554
- }).finally(() => {
555
- // We can remove the close listener here since we no longer need it past this point.
556
- removeCloseListener();
557
- });
538
+ const remote = Comlink.wrap<OpenAsyncDatabaseConnection>(workerPort);
539
+ const identifier = this.syncParams!.dbParams.dbFilename;
540
+
541
+ /**
542
+ * The open could fail if the tab is closed while we're busy opening the database.
543
+ * This operation is typically executed inside an exclusive portMutex lock.
544
+ * We typically execute the closeListeners using the portMutex in a different context.
545
+ * We can't rely on the closeListeners to abort the operation if the tab is closed.
546
+ */
547
+ const db = await withAbort({
548
+ action: () => remote(this.syncParams!.dbParams),
549
+ signal: abortController.signal,
550
+ cleanupOnAbort: (db) => {
551
+ db.close();
552
+ }
553
+ }).finally(() => {
554
+ // We can remove the close listener here since we no longer need it past this point.
555
+ removeCloseListener();
556
+ });
558
557
 
559
- clearTimeout(timeout);
558
+ clearTimeout(timeout);
560
559
 
561
- const wrapped = new WorkerWrappedAsyncDatabaseConnection({
562
- remote,
563
- baseConnection: db,
564
- identifier,
565
- // It's possible for this worker to outlive the client hosting the database for us. We need to be prepared for
566
- // that and ensure pending requests are aborted when the tab is closed.
567
- remoteCanCloseUnexpectedly: true
568
- });
569
- client.closeListeners.push(async () => {
570
- this.logger.info('Aborting open connection because associated tab closed.');
571
- /**
572
- * Don't await this close operation. It might never resolve if the tab is closed.
573
- * We mark the remote as closed first, this will reject any pending requests.
574
- * We then call close. The close operation is configured to fire-and-forget, the main promise will reject immediately.
575
- */
576
- wrapped.markRemoteClosed();
577
- wrapped.close().catch((ex) => this.logger.warn('error closing database connection', ex));
578
- });
560
+ const wrapped = new WorkerWrappedAsyncDatabaseConnection({
561
+ remote,
562
+ baseConnection: db,
563
+ identifier,
564
+ // It's possible for this worker to outlive the client hosting the database for us. We need to be prepared for
565
+ // that and ensure pending requests are aborted when the tab is closed.
566
+ remoteCanCloseUnexpectedly: true
567
+ });
568
+ client.closeListeners.push(async () => {
569
+ this.logger.info('Aborting open connection because associated tab closed.');
570
+ /**
571
+ * Don't await this close operation. It might never resolve if the tab is closed.
572
+ * We mark the remote as closed first, this will reject any pending requests.
573
+ * We then call close. The close operation is configured to fire-and-forget, the main promise will reject immediately.
574
+ */
575
+ wrapped.markRemoteClosed();
576
+ wrapped.close().catch((ex) => this.logger.warn('error closing database connection', ex));
577
+ });
579
578
 
580
- return wrapped;
581
- } catch (ex) {
582
- this.logger.warn('Error opening internal DB', ex);
583
- await new Promise((resolve) => setTimeout(resolve, 1000));
584
- }
585
- }
579
+ return wrapped;
586
580
  }
587
581
 
588
582
  /**
Binary file
Binary file
Binary file
Binary file
@@ -1,96 +0,0 @@
1
- import { FacadeVFS } from '@journeyapps/wa-sqlite/src/FacadeVFS.js';
2
- export declare class OPFSCoopSyncVFS extends FacadeVFS {
3
- #private;
4
- /** @type {Map<number, File>} */ mapIdToFile: Map<any, any>;
5
- lastError: null;
6
- log: null;
7
- /** @type {Map<string, PersistentFile>} */ persistentFiles: Map<any, any>;
8
- /** @type {Map<string, FileSystemSyncAccessHandle>} */ boundAccessHandles: Map<any, any>;
9
- /** @type {Set<FileSystemSyncAccessHandle>} */ unboundAccessHandles: Set<unknown>;
10
- /** @type {Set<string>} */ accessiblePaths: Set<unknown>;
11
- releaser: null;
12
- static create(name: any, module: any): Promise<OPFSCoopSyncVFS>;
13
- constructor(name: any, module: any);
14
- /**
15
- * @param {string?} zName
16
- * @param {number} fileId
17
- * @param {number} flags
18
- * @param {DataView} pOutFlags
19
- * @returns {number}
20
- */
21
- jOpen(zName: any, fileId: any, flags: any, pOutFlags: any): 0 | 5 | 14;
22
- /**
23
- * @param {string} zName
24
- * @param {number} syncDir
25
- * @returns {number}
26
- */
27
- jDelete(zName: any, syncDir: any): 0 | 2570;
28
- /**
29
- * @param {string} zName
30
- * @param {number} flags
31
- * @param {DataView} pResOut
32
- * @returns {number}
33
- */
34
- jAccess(zName: any, flags: any, pResOut: any): 0 | 3338;
35
- /**
36
- * @param {number} fileId
37
- * @returns {number}
38
- */
39
- jClose(fileId: any): 0 | 4106;
40
- /**
41
- * @param {number} fileId
42
- * @param {Uint8Array} pData
43
- * @param {number} iOffset
44
- * @returns {number}
45
- */
46
- jRead(fileId: any, pData: any, iOffset: any): 0 | 522 | 266;
47
- /**
48
- * @param {number} fileId
49
- * @param {Uint8Array} pData
50
- * @param {number} iOffset
51
- * @returns {number}
52
- */
53
- jWrite(fileId: any, pData: any, iOffset: any): 0 | 778;
54
- /**
55
- * @param {number} fileId
56
- * @param {number} iSize
57
- * @returns {number}
58
- */
59
- jTruncate(fileId: any, iSize: any): 0 | 1546;
60
- /**
61
- * @param {number} fileId
62
- * @param {number} flags
63
- * @returns {number}
64
- */
65
- jSync(fileId: any, flags: any): 0 | 1034;
66
- /**
67
- * @param {number} fileId
68
- * @param {DataView} pSize64
69
- * @returns {number}
70
- */
71
- jFileSize(fileId: any, pSize64: any): 0 | 1802;
72
- /**
73
- * @param {number} fileId
74
- * @param {number} lockType
75
- * @returns {number}
76
- */
77
- jLock(fileId: any, lockType: any): 0 | 5;
78
- /**
79
- * @param {number} fileId
80
- * @param {number} lockType
81
- * @returns {number}
82
- */
83
- jUnlock(fileId: any, lockType: any): 0;
84
- /**
85
- * @param {number} fileId
86
- * @param {number} op
87
- * @param {DataView} pArg
88
- * @returns {number|Promise<number>}
89
- */
90
- jFileControl(fileId: any, op: any, pArg: any): 10 | 12;
91
- /**
92
- * @param {Uint8Array} zBuf
93
- * @returns
94
- */
95
- jGetLastError(zBuf: any): 0;
96
- }