@powersync/web 0.0.0-dev-20251120085122 → 0.0.0-dev-20251127205344

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 (28) hide show
  1. package/dist/index.umd.js +63 -41
  2. package/dist/index.umd.js.map +1 -1
  3. package/dist/worker/SharedSyncImplementation.umd.js +14914 -10959
  4. package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
  5. package/dist/worker/WASQLiteDB.umd.js +12708 -10895
  6. package/dist/worker/WASQLiteDB.umd.js.map +1 -1
  7. package/lib/package.json +2 -2
  8. package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.d.ts +1 -0
  9. package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.js +11 -2
  10. package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.js +1 -1
  11. package/lib/src/db/sync/SharedWebStreamingSyncImplementation.d.ts +1 -1
  12. package/lib/src/db/sync/SharedWebStreamingSyncImplementation.js +15 -13
  13. package/lib/src/worker/db/SharedWASQLiteConnection.js +1 -0
  14. package/lib/src/worker/sync/SharedSyncImplementation.js +22 -12
  15. package/lib/src/worker/sync/WorkerClient.d.ts +1 -1
  16. package/lib/src/worker/sync/WorkerClient.js +2 -2
  17. package/lib/tsconfig.tsbuildinfo +1 -1
  18. package/package.json +3 -3
  19. package/src/db/adapters/LockedAsyncDatabaseAdapter.ts +12 -2
  20. package/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.ts +1 -1
  21. package/src/db/sync/SharedWebStreamingSyncImplementation.ts +18 -16
  22. package/src/worker/db/SharedWASQLiteConnection.ts +1 -0
  23. package/src/worker/sync/SharedSyncImplementation.ts +24 -14
  24. package/src/worker/sync/WorkerClient.ts +5 -4
  25. package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3460.index.umd.js +0 -355
  26. package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3460.index.umd.js.map +0 -1
  27. package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3461.index.umd.js +0 -355
  28. package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3461.index.umd.js.map +0 -1
package/dist/index.umd.js CHANGED
@@ -38700,6 +38700,8 @@ __webpack_require__.r(__webpack_exports__);
38700
38700
  /* harmony import */ var _powersync_common__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_powersync_common__WEBPACK_IMPORTED_MODULE_0__);
38701
38701
  /* harmony import */ var _shared_navigator__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../..//shared/navigator */ "./lib/src/shared/navigator.js");
38702
38702
  /* harmony import */ var _WorkerWrappedAsyncDatabaseConnection__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./WorkerWrappedAsyncDatabaseConnection */ "./lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.js");
38703
+ /* harmony import */ var _wa_sqlite_WASQLiteConnection__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./wa-sqlite/WASQLiteConnection */ "./lib/src/db/adapters/wa-sqlite/WASQLiteConnection.js");
38704
+
38703
38705
 
38704
38706
 
38705
38707
 
@@ -38719,6 +38721,7 @@ class LockedAsyncDatabaseAdapter extends _powersync_common__WEBPACK_IMPORTED_MOD
38719
38721
  _disposeTableChangeListener = null;
38720
38722
  _config = null;
38721
38723
  pendingAbortControllers;
38724
+ requiresHolds;
38722
38725
  closing;
38723
38726
  closed;
38724
38727
  constructor(options) {
@@ -38729,6 +38732,7 @@ class LockedAsyncDatabaseAdapter extends _powersync_common__WEBPACK_IMPORTED_MOD
38729
38732
  this.pendingAbortControllers = new Set();
38730
38733
  this.closed = false;
38731
38734
  this.closing = false;
38735
+ this.requiresHolds = null;
38732
38736
  // Set the name if provided. We can query for the name if not available yet
38733
38737
  this.debugMode = options.debugMode ?? false;
38734
38738
  if (this.debugMode) {
@@ -38773,6 +38777,10 @@ class LockedAsyncDatabaseAdapter extends _powersync_common__WEBPACK_IMPORTED_MOD
38773
38777
  this._config = await this._db.getConfig();
38774
38778
  await this.registerOnChangeListener(this._db);
38775
38779
  this.iterateListeners((cb) => cb.initialized?.());
38780
+ /**
38781
+ * This is only required for the long-lived shared IndexedDB connections.
38782
+ */
38783
+ this.requiresHolds = this._config.vfs == _wa_sqlite_WASQLiteConnection__WEBPACK_IMPORTED_MODULE_3__.WASQLiteVFS.IDBBatchAtomicVFS;
38776
38784
  }
38777
38785
  getConfiguration() {
38778
38786
  if (!this._config) {
@@ -38867,12 +38875,14 @@ class LockedAsyncDatabaseAdapter extends _powersync_common__WEBPACK_IMPORTED_MOD
38867
38875
  if (timoutId) {
38868
38876
  clearTimeout(timoutId);
38869
38877
  }
38870
- const holdId = await this.baseDB.markHold();
38878
+ const holdId = this.requiresHolds ? await this.baseDB.markHold() : null;
38871
38879
  try {
38872
38880
  return await callback();
38873
38881
  }
38874
38882
  finally {
38875
- await this.baseDB.releaseHold(holdId);
38883
+ if (holdId) {
38884
+ await this.baseDB.releaseHold(holdId);
38885
+ }
38876
38886
  }
38877
38887
  });
38878
38888
  }
@@ -39132,7 +39142,7 @@ class WorkerWrappedAsyncDatabaseConnection {
39132
39142
  return this.withRemote(() => this.baseConnection.releaseHold(holdId));
39133
39143
  }
39134
39144
  isAutoCommit() {
39135
- return this.baseConnection.isAutoCommit();
39145
+ return this.withRemote(() => this.baseConnection.isAutoCommit());
39136
39146
  }
39137
39147
  withRemote(workerPromise) {
39138
39148
  const controller = this.notifyRemoteClosed;
@@ -40036,11 +40046,11 @@ __webpack_require__.r(__webpack_exports__);
40036
40046
  /* harmony export */ });
40037
40047
  /* harmony import */ var comlink__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! comlink */ "comlink");
40038
40048
  /* harmony import */ var comlink__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(comlink__WEBPACK_IMPORTED_MODULE_0__);
40039
- /* harmony import */ var _worker_sync_AbstractSharedSyncClientProvider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../worker/sync/AbstractSharedSyncClientProvider */ "./lib/src/worker/sync/AbstractSharedSyncClientProvider.js");
40040
- /* harmony import */ var _worker_sync_SharedSyncImplementation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../worker/sync/SharedSyncImplementation */ "./lib/src/worker/sync/SharedSyncImplementation.js");
40041
- /* harmony import */ var _adapters_web_sql_flags__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../adapters/web-sql-flags */ "./lib/src/db/adapters/web-sql-flags.js");
40042
- /* harmony import */ var _WebStreamingSyncImplementation__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./WebStreamingSyncImplementation */ "./lib/src/db/sync/WebStreamingSyncImplementation.js");
40043
- /* harmony import */ var _shared_navigator__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../shared/navigator */ "./lib/src/shared/navigator.js");
40049
+ /* harmony import */ var _shared_navigator__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../shared/navigator */ "./lib/src/shared/navigator.js");
40050
+ /* harmony import */ var _worker_sync_AbstractSharedSyncClientProvider__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../worker/sync/AbstractSharedSyncClientProvider */ "./lib/src/worker/sync/AbstractSharedSyncClientProvider.js");
40051
+ /* harmony import */ var _worker_sync_SharedSyncImplementation__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../worker/sync/SharedSyncImplementation */ "./lib/src/worker/sync/SharedSyncImplementation.js");
40052
+ /* harmony import */ var _adapters_web_sql_flags__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../adapters/web-sql-flags */ "./lib/src/db/adapters/web-sql-flags.js");
40053
+ /* harmony import */ var _WebStreamingSyncImplementation__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./WebStreamingSyncImplementation */ "./lib/src/db/sync/WebStreamingSyncImplementation.js");
40044
40054
 
40045
40055
 
40046
40056
 
@@ -40051,7 +40061,7 @@ __webpack_require__.r(__webpack_exports__);
40051
40061
  * The shared worker will trigger methods on this side of the message port
40052
40062
  * via this client provider.
40053
40063
  */
40054
- class SharedSyncClientProvider extends _worker_sync_AbstractSharedSyncClientProvider__WEBPACK_IMPORTED_MODULE_1__.AbstractSharedSyncClientProvider {
40064
+ class SharedSyncClientProvider extends _worker_sync_AbstractSharedSyncClientProvider__WEBPACK_IMPORTED_MODULE_2__.AbstractSharedSyncClientProvider {
40055
40065
  options;
40056
40066
  statusChanged;
40057
40067
  webDB;
@@ -40122,7 +40132,7 @@ class SharedSyncClientProvider extends _worker_sync_AbstractSharedSyncClientProv
40122
40132
  /**
40123
40133
  * The local part of the sync implementation on the web, which talks to a sync implementation hosted in a shared worker.
40124
40134
  */
40125
- class SharedWebStreamingSyncImplementation extends _WebStreamingSyncImplementation__WEBPACK_IMPORTED_MODULE_4__.WebStreamingSyncImplementation {
40135
+ class SharedWebStreamingSyncImplementation extends _WebStreamingSyncImplementation__WEBPACK_IMPORTED_MODULE_5__.WebStreamingSyncImplementation {
40126
40136
  syncManager;
40127
40137
  clientProvider;
40128
40138
  messagePort;
@@ -40138,10 +40148,10 @@ class SharedWebStreamingSyncImplementation extends _WebStreamingSyncImplementati
40138
40148
  */
40139
40149
  const resolvedWorkerOptions = {
40140
40150
  dbFilename: this.options.identifier,
40141
- temporaryStorage: _adapters_web_sql_flags__WEBPACK_IMPORTED_MODULE_3__.TemporaryStorageOption.MEMORY,
40142
- cacheSizeKb: _adapters_web_sql_flags__WEBPACK_IMPORTED_MODULE_3__.DEFAULT_CACHE_SIZE_KB,
40151
+ temporaryStorage: _adapters_web_sql_flags__WEBPACK_IMPORTED_MODULE_4__.TemporaryStorageOption.MEMORY,
40152
+ cacheSizeKb: _adapters_web_sql_flags__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_CACHE_SIZE_KB,
40143
40153
  ...options,
40144
- flags: (0,_adapters_web_sql_flags__WEBPACK_IMPORTED_MODULE_3__.resolveWebSQLFlags)(options.flags)
40154
+ flags: (0,_adapters_web_sql_flags__WEBPACK_IMPORTED_MODULE_4__.resolveWebSQLFlags)(options.flags)
40145
40155
  };
40146
40156
  const syncWorker = options.sync?.worker;
40147
40157
  if (syncWorker) {
@@ -40156,7 +40166,7 @@ class SharedWebStreamingSyncImplementation extends _WebStreamingSyncImplementati
40156
40166
  }
40157
40167
  }
40158
40168
  else {
40159
- this.messagePort = new SharedWorker(new URL(/* worker import */ __webpack_require__.p + __webpack_require__.u("lib_src_worker_db_WASQLiteDB_worker_js-lib_src_worker_sync_SharedSyncImplementation_worker_js"), __webpack_require__.b), {
40169
+ this.messagePort = new SharedWorker(new URL(/* worker import */ __webpack_require__.p + __webpack_require__.u("lib_src_worker_sync_SharedSyncImplementation_worker_js-_journeyapps_wa-sqlite-_journeyapps_wa-4748cf"), __webpack_require__.b), {
40160
40170
  /* @vite-ignore */
40161
40171
  name: `shared-sync-${this.webOptions.identifier}`,
40162
40172
  type: undefined
@@ -40173,6 +40183,19 @@ class SharedWebStreamingSyncImplementation extends _WebStreamingSyncImplementati
40173
40183
  */
40174
40184
  const { crudUploadThrottleMs, identifier, retryDelayMs } = this.options;
40175
40185
  const flags = { ...this.webOptions.flags, workers: undefined };
40186
+ // Request a random lock until this client is disposed. The name of the lock is sent to the shared worker, which
40187
+ // will also attempt to acquire it. Since the lock is returned when the tab is closed, this allows the share worker
40188
+ // to free resources associated with this tab.
40189
+ // We take hold of this lock as soon-as-possible in order to cater for potentially closed tabs.
40190
+ (0,_shared_navigator__WEBPACK_IMPORTED_MODULE_1__.getNavigatorLocks)().request(`tab-close-signal-${crypto.randomUUID()}`, async (lock) => {
40191
+ if (!this.abortOnClose.signal.aborted) {
40192
+ // Awaiting here ensures the worker is waiting for the lock
40193
+ await this.syncManager.addLockBasedCloseSignal(lock.name);
40194
+ await new Promise((r) => {
40195
+ this.abortOnClose.signal.onabort = () => r();
40196
+ });
40197
+ }
40198
+ });
40176
40199
  this.isInitialized = this.syncManager.setParams({
40177
40200
  dbParams: this.dbAdapter.getConfiguration(),
40178
40201
  streamOptions: {
@@ -40194,17 +40217,6 @@ class SharedWebStreamingSyncImplementation extends _WebStreamingSyncImplementati
40194
40217
  * This performs bi-directional method calling.
40195
40218
  */
40196
40219
  comlink__WEBPACK_IMPORTED_MODULE_0__.expose(this.clientProvider, this.messagePort);
40197
- // Request a random lock until this client is disposed. The name of the lock is sent to the shared worker, which
40198
- // will also attempt to acquire it. Since the lock is returned when the tab is closed, this allows the share worker
40199
- // to free resources associated with this tab.
40200
- (0,_shared_navigator__WEBPACK_IMPORTED_MODULE_5__.getNavigatorLocks)().request(`tab-close-signal-${crypto.randomUUID()}`, async (lock) => {
40201
- if (!this.abortOnClose.signal.aborted) {
40202
- this.syncManager.addLockBasedCloseSignal(lock.name);
40203
- await new Promise((r) => {
40204
- this.abortOnClose.signal.onabort = () => r();
40205
- });
40206
- }
40207
- });
40208
40220
  }
40209
40221
  /**
40210
40222
  * Starts the sync process, this effectively acts as a call to
@@ -40232,13 +40244,13 @@ class SharedWebStreamingSyncImplementation extends _WebStreamingSyncImplementati
40232
40244
  // Listen for the close acknowledgment from the worker
40233
40245
  this.messagePort.addEventListener('message', (event) => {
40234
40246
  const payload = event.data;
40235
- if (payload?.event === _worker_sync_SharedSyncImplementation__WEBPACK_IMPORTED_MODULE_2__.SharedSyncClientEvent.CLOSE_ACK) {
40247
+ if (payload?.event === _worker_sync_SharedSyncImplementation__WEBPACK_IMPORTED_MODULE_3__.SharedSyncClientEvent.CLOSE_ACK) {
40236
40248
  resolve();
40237
40249
  }
40238
40250
  });
40239
40251
  // Signal the shared worker that this client is closing its connection to the worker
40240
40252
  const closeMessagePayload = {
40241
- event: _worker_sync_SharedSyncImplementation__WEBPACK_IMPORTED_MODULE_2__.SharedSyncClientEvent.CLOSE_CLIENT,
40253
+ event: _worker_sync_SharedSyncImplementation__WEBPACK_IMPORTED_MODULE_3__.SharedSyncClientEvent.CLOSE_CLIENT,
40242
40254
  data: {}
40243
40255
  };
40244
40256
  this.messagePort.postMessage(closeMessagePayload);
@@ -40507,12 +40519,12 @@ function openWorkerDatabasePort(workerIdentifier, multipleTabs = true, worker =
40507
40519
  * (in the case of Android)
40508
40520
  */
40509
40521
  return !needsDedicated && multipleTabs
40510
- ? new SharedWorker(new URL(/* worker import */ __webpack_require__.p + __webpack_require__.u("_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3460"), __webpack_require__.b), {
40522
+ ? new SharedWorker(new URL(/* worker import */ __webpack_require__.p + __webpack_require__.u("lib_src_worker_db_WASQLiteDB_worker_js-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVF-1dc7800"), __webpack_require__.b), {
40511
40523
  /* @vite-ignore */
40512
40524
  name: `shared-DB-worker-${workerIdentifier}`,
40513
40525
  type: undefined
40514
40526
  }).port
40515
- : new Worker(new URL(/* worker import */ __webpack_require__.p + __webpack_require__.u("_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3461"), __webpack_require__.b), {
40527
+ : new Worker(new URL(/* worker import */ __webpack_require__.p + __webpack_require__.u("lib_src_worker_db_WASQLiteDB_worker_js-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVF-1dc7801"), __webpack_require__.b), {
40516
40528
  /* @vite-ignore */
40517
40529
  name: `DB-worker-${workerIdentifier}`,
40518
40530
  type: undefined
@@ -40945,6 +40957,20 @@ class SharedSyncImplementation extends _powersync_common__WEBPACK_IMPORTED_MODUL
40945
40957
  }
40946
40958
  });
40947
40959
  const shouldReconnect = !!this.connectionManager.syncStreamImplementation && this.ports.length > 0;
40960
+ /**
40961
+ * If the current database adapter is the one that is being closed, we need to disconnect from the backend.
40962
+ * We can disconnect in the portMutex lock. This ensures the disconnect is not affected by potential other
40963
+ * connect operations coming from other tabs.
40964
+ */
40965
+ if (this.dbAdapter && this.dbAdapter == trackedPort.db) {
40966
+ this.logger.debug(`Disconnecting due to closed database: should reconnect: ${shouldReconnect}`);
40967
+ this.dbAdapter = null;
40968
+ // Unconditionally close the connection because the database it's writing to has just been closed.
40969
+ // The connection has been closed previously, this might throw. We should be able to ignore it.
40970
+ await this.connectionManager
40971
+ .disconnect()
40972
+ .catch((ex) => this.logger.warn('Error while disconnecting. Will attempt to reconnect.', ex));
40973
+ }
40948
40974
  return {
40949
40975
  shouldReconnect,
40950
40976
  trackedPort
@@ -40957,17 +40983,8 @@ class SharedSyncImplementation extends _powersync_common__WEBPACK_IMPORTED_MODUL
40957
40983
  for (const closeListener of trackedPort.closeListeners) {
40958
40984
  await closeListener();
40959
40985
  }
40960
- if (this.dbAdapter && this.dbAdapter == trackedPort.db) {
40961
- // Unconditionally close the connection because the database it's writing to has just been closed.
40962
- // The connection has been closed previously, this might throw. We should be able to ignore it.
40963
- await this.connectionManager
40964
- .disconnect()
40965
- .catch((ex) => this.logger.warn('Error while disconnecting. Will attempt to reconnect.', ex));
40966
- // Clearing the adapter will result in a new one being opened in connect
40967
- this.dbAdapter = null;
40968
- if (shouldReconnect) {
40969
- await this.connectionManager.connect(CONNECTOR_PLACEHOLDER, this.lastConnectOptions ?? {});
40970
- }
40986
+ if (shouldReconnect) {
40987
+ await this.connectionManager.connect(CONNECTOR_PLACEHOLDER, this.lastConnectOptions ?? {});
40971
40988
  }
40972
40989
  // Re-index subscriptions, the subscriptions of the removed port would no longer be considered.
40973
40990
  this.collectActiveSubscriptions();
@@ -41093,7 +41110,12 @@ class SharedSyncImplementation extends _powersync_common__WEBPACK_IMPORTED_MODUL
41093
41110
  });
41094
41111
  lastClient.closeListeners.push(async () => {
41095
41112
  this.logger.info('Aborting open connection because associated tab closed.');
41096
- await wrapped.close().catch((ex) => this.logger.warn('error closing database connection', ex));
41113
+ /**
41114
+ * Don't await this close operation. It might never resolve if the tab is closed.
41115
+ * We run the close operation first, before marking the remote as closed. This gives the database some chance
41116
+ * to close the connection.
41117
+ */
41118
+ wrapped.close().catch((ex) => this.logger.warn('error closing database connection', ex));
41097
41119
  wrapped.markRemoteClosed();
41098
41120
  });
41099
41121
  return wrapped;