indexeddbshim 17.2.0 → 17.2.2

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.
@@ -1,4 +1,4 @@
1
- /*! indexeddbshim - v17.2.0 - 8/18/2026 */
1
+ /*! indexeddbshim - v17.2.2 - 8/18/2026 */
2
2
 
3
3
  (function (factory) {
4
4
  typeof define === 'function' && define.amd ? define(factory) :
@@ -4917,6 +4917,17 @@
4917
4917
  IDBTransaction.prototype.__callTransFinishedCb = function (err, cb) {
4918
4918
  var me = this;
4919
4919
  if (me.__transFinishedCb === IDBTransaction.prototype.__transFinishedCb) {
4920
+ // Standard (3-argument) `transaction()` implementations (browser WebSQL,
4921
+ // `cordova-plugin-sqlite-2`, etc.) never invoke the non-standard 4th
4922
+ // callback that installs the real `__transFinishedCb`, so waiting for
4923
+ // it here would defer forever. Detect that via arity and, if it's not
4924
+ // supported, just call the default (the driver auto-commits on its own).
4925
+ var dbConn = me.db && me.db.__db;
4926
+ var supportsNonstandardTransCb = Boolean(dbConn && typeof dbConn.transaction === 'function' && dbConn.transaction.length >= 4);
4927
+ if (!supportsNonstandardTransCb) {
4928
+ me.__transFinishedCb(err, cb);
4929
+ return;
4930
+ }
4920
4931
  setTimeout(function () {
4921
4932
  me.__callTransFinishedCb(err, cb);
4922
4933
  }, 0);
@@ -9858,6 +9869,56 @@
9858
9869
  return websqlDBCache[name] && websqlDBCache[name][getLatestCachedWebSQLVersion(name)];
9859
9870
  }
9860
9871
 
9872
+ /**
9873
+ * A cached WebSQL connection (e.g., from a prior `open()`) can keep the
9874
+ * underlying SQLite file handle open even after `IDBDatabase#close()`
9875
+ * (which only flags the connection for closing without releasing the
9876
+ * handle, to allow instance reuse). On Windows, deleting a file while a
9877
+ * handle to it is still open fails with `EBUSY`, so any cached connections
9878
+ * for `name` must be actually closed (and evicted, since they're no longer
9879
+ * usable) before attempting to remove the file.
9880
+ * @param {string} name
9881
+ * @param {() => void} cb
9882
+ * @returns {void}
9883
+ */
9884
+ function closeCachedWebSQLConnections(name, cb) {
9885
+ if (!Object.hasOwn(websqlDBCache, name)) {
9886
+ cb();
9887
+ return;
9888
+ }
9889
+ var dbs = Object.values(websqlDBCache[name]);
9890
+ delete websqlDBCache[name];
9891
+ var remaining = dbs.length;
9892
+ if (remaining === 0) {
9893
+ cb();
9894
+ return;
9895
+ }
9896
+ dbs.forEach(function (db) {
9897
+ var sqliteDB = db._db && db._db._db;
9898
+ if (!sqliteDB || !sqliteDB.close) {
9899
+ remaining--;
9900
+ if (remaining === 0) {
9901
+ cb();
9902
+ }
9903
+ return;
9904
+ }
9905
+ sqliteDB.close(
9906
+ /**
9907
+ * @param {Error} err
9908
+ * @returns {void}
9909
+ */
9910
+ function (err) {
9911
+ if (err) {
9912
+ console.warn('Error closing database connection prior to file removal: ' + err);
9913
+ }
9914
+ remaining--;
9915
+ if (remaining === 0) {
9916
+ cb();
9917
+ }
9918
+ });
9919
+ });
9920
+ }
9921
+
9861
9922
  /**
9862
9923
  * @param {OpenDatabase} __openDatabase
9863
9924
  * @param {string} name
@@ -9895,16 +9956,18 @@
9895
9956
  return;
9896
9957
  }
9897
9958
  if (fs && CFG.deleteDatabaseFiles !== false) {
9898
- fs.unlink(path.join(CFG.databaseBasePath || '', escapedDatabaseName), function (err) {
9899
- if (err && err.code !== 'ENOENT') {
9900
- // Ignore if file is already deleted
9901
- dbError({
9902
- code: 0,
9903
- message: 'Error removing database file: ' + escapedDatabaseName + ' ' + err
9904
- });
9905
- return;
9906
- }
9907
- databaseDeleted();
9959
+ closeCachedWebSQLConnections(name, function () {
9960
+ fs.unlink(path.join(CFG.databaseBasePath || '', escapedDatabaseName), function (err) {
9961
+ if (err && err.code !== 'ENOENT') {
9962
+ // Ignore if file is already deleted
9963
+ dbError({
9964
+ code: 0,
9965
+ message: 'Error removing database file: ' + escapedDatabaseName + ' ' + err
9966
+ });
9967
+ return;
9968
+ }
9969
+ databaseDeleted();
9970
+ });
9908
9971
  });
9909
9972
  return;
9910
9973
  }
@@ -10433,9 +10496,17 @@
10433
10496
  * @returns {boolean}
10434
10497
  */
10435
10498
  function dbError(tx, err) {
10436
- if (calledDBError || err === true) {
10499
+ if (calledDBError) {
10437
10500
  return false;
10438
10501
  }
10502
+ // Must be set synchronously (not inside the `sysdbFinishedCbDelete` callback below) to
10503
+ // guard against reentrancy: `sysdbFinishedCbDelete` -> `rollback`/`commit` -> websql-configurable's
10504
+ // `done()` -> `currentTask.errorCallback(er)`, which is this very `dbError`, calling back into
10505
+ // us before the first invocation has finished. Without this, a second rollback/commit gets
10506
+ // issued on the shared `sysdb` connection after it has already moved on to the next queued
10507
+ // transaction, corrupting that connection's task queue (see issue with unrelated `open()` calls
10508
+ // failing/crashing after a `deleteDatabase` file-removal error).
10509
+ calledDBError = true;
10439
10510
  var er = webSQLErrback(/** @type {SQLError} */err || tx);
10440
10511
  sysdbFinishedCbDelete(true, function () {
10441
10512
  req.__done = true;
@@ -10447,7 +10518,6 @@
10447
10518
  cancelable: true
10448
10519
  });
10449
10520
  req.dispatchEvent(e);
10450
- calledDBError = true;
10451
10521
  });
10452
10522
  return false;
10453
10523
  }