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 (global, factory) {
4
4
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
@@ -4925,6 +4925,17 @@
4925
4925
  IDBTransaction.prototype.__callTransFinishedCb = function (err, cb) {
4926
4926
  var me = this;
4927
4927
  if (me.__transFinishedCb === IDBTransaction.prototype.__transFinishedCb) {
4928
+ // Standard (3-argument) `transaction()` implementations (browser WebSQL,
4929
+ // `cordova-plugin-sqlite-2`, etc.) never invoke the non-standard 4th
4930
+ // callback that installs the real `__transFinishedCb`, so waiting for
4931
+ // it here would defer forever. Detect that via arity and, if it's not
4932
+ // supported, just call the default (the driver auto-commits on its own).
4933
+ var dbConn = me.db && me.db.__db;
4934
+ var supportsNonstandardTransCb = Boolean(dbConn && typeof dbConn.transaction === 'function' && dbConn.transaction.length >= 4);
4935
+ if (!supportsNonstandardTransCb) {
4936
+ me.__transFinishedCb(err, cb);
4937
+ return;
4938
+ }
4928
4939
  setTimeout(function () {
4929
4940
  me.__callTransFinishedCb(err, cb);
4930
4941
  }, 0);
@@ -9866,6 +9877,56 @@
9866
9877
  return websqlDBCache[name] && websqlDBCache[name][getLatestCachedWebSQLVersion(name)];
9867
9878
  }
9868
9879
 
9880
+ /**
9881
+ * A cached WebSQL connection (e.g., from a prior `open()`) can keep the
9882
+ * underlying SQLite file handle open even after `IDBDatabase#close()`
9883
+ * (which only flags the connection for closing without releasing the
9884
+ * handle, to allow instance reuse). On Windows, deleting a file while a
9885
+ * handle to it is still open fails with `EBUSY`, so any cached connections
9886
+ * for `name` must be actually closed (and evicted, since they're no longer
9887
+ * usable) before attempting to remove the file.
9888
+ * @param {string} name
9889
+ * @param {() => void} cb
9890
+ * @returns {void}
9891
+ */
9892
+ function closeCachedWebSQLConnections(name, cb) {
9893
+ if (!Object.hasOwn(websqlDBCache, name)) {
9894
+ cb();
9895
+ return;
9896
+ }
9897
+ var dbs = Object.values(websqlDBCache[name]);
9898
+ delete websqlDBCache[name];
9899
+ var remaining = dbs.length;
9900
+ if (remaining === 0) {
9901
+ cb();
9902
+ return;
9903
+ }
9904
+ dbs.forEach(function (db) {
9905
+ var sqliteDB = db._db && db._db._db;
9906
+ if (!sqliteDB || !sqliteDB.close) {
9907
+ remaining--;
9908
+ if (remaining === 0) {
9909
+ cb();
9910
+ }
9911
+ return;
9912
+ }
9913
+ sqliteDB.close(
9914
+ /**
9915
+ * @param {Error} err
9916
+ * @returns {void}
9917
+ */
9918
+ function (err) {
9919
+ if (err) {
9920
+ console.warn('Error closing database connection prior to file removal: ' + err);
9921
+ }
9922
+ remaining--;
9923
+ if (remaining === 0) {
9924
+ cb();
9925
+ }
9926
+ });
9927
+ });
9928
+ }
9929
+
9869
9930
  /**
9870
9931
  * @param {OpenDatabase} __openDatabase
9871
9932
  * @param {string} name
@@ -9903,16 +9964,18 @@
9903
9964
  return;
9904
9965
  }
9905
9966
  if (fs && CFG.deleteDatabaseFiles !== false) {
9906
- fs.unlink(path.join(CFG.databaseBasePath || '', escapedDatabaseName), function (err) {
9907
- if (err && err.code !== 'ENOENT') {
9908
- // Ignore if file is already deleted
9909
- dbError({
9910
- code: 0,
9911
- message: 'Error removing database file: ' + escapedDatabaseName + ' ' + err
9912
- });
9913
- return;
9914
- }
9915
- databaseDeleted();
9967
+ closeCachedWebSQLConnections(name, function () {
9968
+ fs.unlink(path.join(CFG.databaseBasePath || '', escapedDatabaseName), function (err) {
9969
+ if (err && err.code !== 'ENOENT') {
9970
+ // Ignore if file is already deleted
9971
+ dbError({
9972
+ code: 0,
9973
+ message: 'Error removing database file: ' + escapedDatabaseName + ' ' + err
9974
+ });
9975
+ return;
9976
+ }
9977
+ databaseDeleted();
9978
+ });
9916
9979
  });
9917
9980
  return;
9918
9981
  }
@@ -10441,9 +10504,17 @@
10441
10504
  * @returns {boolean}
10442
10505
  */
10443
10506
  function dbError(tx, err) {
10444
- if (calledDBError || err === true) {
10507
+ if (calledDBError) {
10445
10508
  return false;
10446
10509
  }
10510
+ // Must be set synchronously (not inside the `sysdbFinishedCbDelete` callback below) to
10511
+ // guard against reentrancy: `sysdbFinishedCbDelete` -> `rollback`/`commit` -> websql-configurable's
10512
+ // `done()` -> `currentTask.errorCallback(er)`, which is this very `dbError`, calling back into
10513
+ // us before the first invocation has finished. Without this, a second rollback/commit gets
10514
+ // issued on the shared `sysdb` connection after it has already moved on to the next queued
10515
+ // transaction, corrupting that connection's task queue (see issue with unrelated `open()` calls
10516
+ // failing/crashing after a `deleteDatabase` file-removal error).
10517
+ calledDBError = true;
10447
10518
  var er = webSQLErrback(/** @type {SQLError} */err || tx);
10448
10519
  sysdbFinishedCbDelete(true, function () {
10449
10520
  req.__done = true;
@@ -10455,7 +10526,6 @@
10455
10526
  cancelable: true
10456
10527
  });
10457
10528
  req.dispatchEvent(e);
10458
- calledDBError = true;
10459
10529
  });
10460
10530
  return false;
10461
10531
  }