indexeddbshim 19.0.4 → 19.0.6

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 (60) hide show
  1. package/badges/coverage-badge.svg +1 -1
  2. package/badges/tests-badge.svg +1 -1
  3. package/dist/CFG.d.ts +1 -1
  4. package/dist/CFG.d.ts.map +1 -1
  5. package/dist/DOMException.d.ts.map +1 -1
  6. package/dist/IDBCursor.d.ts.map +1 -1
  7. package/dist/IDBDatabase.d.ts.map +1 -1
  8. package/dist/IDBFactory.d.ts +1 -2
  9. package/dist/IDBFactory.d.ts.map +1 -1
  10. package/dist/IDBIndex.d.ts +2 -6
  11. package/dist/IDBIndex.d.ts.map +1 -1
  12. package/dist/IDBKeyRange.d.ts.map +1 -1
  13. package/dist/IDBObjectStore.d.ts.map +1 -1
  14. package/dist/IDBRecord.d.ts.map +1 -1
  15. package/dist/IDBRequest.d.ts.map +1 -1
  16. package/dist/IDBTransaction.d.ts.map +1 -1
  17. package/dist/Key.d.ts.map +1 -1
  18. package/dist/Sca.d.ts.map +1 -1
  19. package/dist/indexeddbshim-Key.js +40 -28
  20. package/dist/indexeddbshim-Key.js.map +1 -1
  21. package/dist/indexeddbshim-Key.min.js +2 -2
  22. package/dist/indexeddbshim-Key.min.js.map +1 -1
  23. package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs +525 -225
  24. package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
  25. package/dist/indexeddbshim-UnicodeIdentifiers.js +553 -252
  26. package/dist/indexeddbshim-UnicodeIdentifiers.js.map +1 -1
  27. package/dist/indexeddbshim-UnicodeIdentifiers.min.js +3 -3
  28. package/dist/indexeddbshim-UnicodeIdentifiers.min.js.map +1 -1
  29. package/dist/indexeddbshim-node.cjs +525 -225
  30. package/dist/indexeddbshim-node.cjs.map +1 -1
  31. package/dist/indexeddbshim-noninvasive.js +553 -252
  32. package/dist/indexeddbshim-noninvasive.js.map +1 -1
  33. package/dist/indexeddbshim-noninvasive.min.js +3 -3
  34. package/dist/indexeddbshim-noninvasive.min.js.map +1 -1
  35. package/dist/indexeddbshim.js +553 -252
  36. package/dist/indexeddbshim.js.map +1 -1
  37. package/dist/indexeddbshim.min.js +3 -3
  38. package/dist/indexeddbshim.min.js.map +1 -1
  39. package/dist/nodeWebSQL.d.ts.map +1 -1
  40. package/dist/setGlobalVars.d.ts +1 -1
  41. package/dist/setGlobalVars.d.ts.map +1 -1
  42. package/dist/util.d.ts.map +1 -1
  43. package/package.json +22 -17
  44. package/src/CFG.js +18 -4
  45. package/src/DOMException.js +6 -0
  46. package/src/DOMStringList.js +3 -0
  47. package/src/IDBCursor.js +36 -3
  48. package/src/IDBDatabase.js +26 -10
  49. package/src/IDBFactory.js +105 -5
  50. package/src/IDBIndex.js +49 -32
  51. package/src/IDBKeyRange.js +8 -7
  52. package/src/IDBObjectStore.js +25 -2
  53. package/src/IDBRecord.js +2 -0
  54. package/src/IDBRequest.js +7 -4
  55. package/src/IDBTransaction.js +111 -34
  56. package/src/Key.js +17 -16
  57. package/src/Sca.js +9 -4
  58. package/src/nodeWebSQL.js +1 -0
  59. package/src/setGlobalVars.js +86 -77
  60. package/src/util.js +5 -6
@@ -1,4 +1,4 @@
1
- /*! indexeddbshim - v19.0.4 - 9/17/2026 */
1
+ /*! indexeddbshim - v19.0.6 - 9/22/2026 */
2
2
 
3
3
  (function (global, factory) {
4
4
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
@@ -481,6 +481,7 @@
481
481
  var ShimDOMException$1 = typeof DOMException === 'undefined'
482
482
  // Todo: Better polyfill (if even needed here)
483
483
  /* eslint-disable no-shadow -- Polyfill */
484
+ /* c8 ignore start -- Only reachable when the global `DOMException` is absent, which it never is in this project's test environment (Node always provides it) */
484
485
  // eslint-disable-next-line @stylistic/operator-linebreak -- TS/JSDoc needs
485
486
  ?
486
487
  /**
@@ -498,9 +499,10 @@
498
499
  configurable: true
499
500
  });
500
501
  return err;
501
- } : DOMException;
502
+ }
503
+ /* c8 ignore stop */ : DOMException;
502
504
 
503
- /** @type {WeakMap<object, any>} */
505
+ /** @type {WeakMap<object, EventWithProps>} */
504
506
  var ev = new WeakMap();
505
507
  /** @type {WeakMap<object, EventWithProps>} */
506
508
  var evCfg = new WeakMap();
@@ -546,11 +548,12 @@
546
548
  obj[prop] = {
547
549
  configurable: true,
548
550
  get: function get() {
549
- return Object.hasOwn(_evCfg, prop) ? _evCfg[prop] : Reflect.has(_ev, prop) ? _ev[prop] : ['bubbles', 'cancelable', 'composed'].includes(prop) ? false : undefined;
551
+ return Object.hasOwn(_evCfg, prop) ? _evCfg[prop] : Reflect.has(_ev, prop) ? _ev[prop] : ['bubbles', 'cancelable', 'composed'].includes(prop) ? false
552
+ /* c8 ignore next -- Every prop this is ever called with ('type'/'bubbles'/'cancelable'/'timeStamp'/'composed'/'detail') always ends up set on `_evCfg` or `_ev` by the time it's read, so this is unreachable */ : undefined;
550
553
  }
551
554
  };
552
555
  return obj;
553
- }, /** @type {{[key: string]: any}} */{}));
556
+ }, /** @type {PropertyDescriptorMap} */{}));
554
557
  }
555
558
 
556
559
  /**
@@ -573,8 +576,9 @@
573
576
  throw new TypeError('Illegal invocation');
574
577
  }
575
578
  var _evCfg = getEvCfg(this);
576
- var _ev = ev.get(this);
577
- return Boolean(Object.hasOwn(_evCfg, 'isTrusted') ? _evCfg.isTrusted : Reflect.has(_ev, 'isTrusted') && _ev.isTrusted);
579
+ var _ev = /** @type {EventWithProps} */ /** @type {EventWithProps} */ev.get(this);
580
+ return Boolean(Object.hasOwn(_evCfg, 'isTrusted')
581
+ /* c8 ignore next -- Nothing currently sets `_evCfg.isTrusted` (see the commented-out assignment above); kept for when/if it's revived */ ? _evCfg.isTrusted : Reflect.has(_ev, 'isTrusted') && _ev.isTrusted);
578
582
  }
579
583
 
580
584
  /**
@@ -725,15 +729,15 @@
725
729
  // this untyped alias, rather than `ShimEvent.prototype` directly, keeps
726
730
  // that dynamic-augmentation pattern working without a `@ts-expect-error`
727
731
  // on every single line below.
728
- /** @type {any} */
729
- var ShimEventProto = ShimEvent.prototype;
732
+
733
+ var ShimEventProto = /** @type {Record<PropertyKey, unknown>} */ /** @type {unknown} */ShimEvent.prototype;
730
734
 
731
735
  /** @this {EventWithProps} */
732
736
  ShimEventProto.preventDefault = function preventDefault() {
733
737
  if (!(this instanceof ShimEvent)) {
734
738
  throw new TypeError('Illegal invocation');
735
739
  }
736
- var _ev = ev.get(this);
740
+ var _ev = /** @type {EventWithProps} */ /** @type {EventWithProps} */ev.get(this);
737
741
  var _evCfg = getEvCfg(this);
738
742
  if (this.cancelable && !_evCfg._passive) {
739
743
  _evCfg.defaultPrevented = true;
@@ -931,13 +935,12 @@
931
935
  return _createClass(CustomEvent);
932
936
  }(Event);
933
937
  var ShimCustomEvent = CustomEvent;
934
- /** @type {any} */
935
- var ShimCustomEventProto = ShimCustomEvent.prototype;
938
+ var ShimCustomEventProto = /** @type {Record<PropertyKey, unknown>} */ /** @type {unknown} */ShimCustomEvent.prototype;
936
939
  /**
937
940
  * @param {string} type
938
941
  * @param {boolean} [bubbles]
939
942
  * @param {boolean} [cancelable]
940
- * @param {any} [detail]
943
+ * @param {unknown} [detail]
941
944
  * @this {EventWithProps}
942
945
  */
943
946
  ShimCustomEventProto.initCustomEvent = function initCustomEvent(type) {
@@ -949,6 +952,10 @@
949
952
  throw new TypeError('Illegal invocation');
950
953
  }
951
954
  var _evCfg = getEvCfg(this);
955
+ if (_evCfg._dispatched) {
956
+ return;
957
+ }
958
+
952
959
  // @ts-expect-error `detail` isn't part of `EventInit`, only used internally here
953
960
  // eslint-disable-next-line prefer-rest-params -- Keep signature
954
961
  initEventInternal(this, type, {
@@ -956,16 +963,13 @@
956
963
  cancelable: cancelable,
957
964
  detail: detail
958
965
  }, arguments[4]);
959
- if (_evCfg._dispatched) {
960
- return;
961
- }
962
966
  if (detail !== undefined) {
963
967
  _evCfg.detail = detail;
964
968
  }
965
969
  // `initCustomEvent` deliberately excluded -- see the matching comment
966
970
  // in `initEventInternal` for `initEvent`, above; the same reasoning
967
971
  // applies here.
968
- definePassthroughProps(this, ['detail'], _evCfg, ev.get(this));
972
+ definePassthroughProps(this, ['detail'], _evCfg, /** @type {EventWithProps} */ev.get(this));
969
973
  };
970
974
  // @ts-expect-error Not part of the class body itself
971
975
  ShimCustomEvent[Symbol.toStringTag] = 'Function';
@@ -1372,7 +1376,7 @@
1372
1376
  /** @type {string[]} */
1373
1377
  this._extraProperties.forEach(function (prop) {
1374
1378
  if (Reflect.has(e, prop)) {
1375
- /** @type {{[key: string]: any}} */eventCopy[prop] = /** @type {{[key: string]: any}} */e[prop]; // Todo: Put internal to `ShimEvent`?
1379
+ /** @type {PropertyDescriptorMap} */eventCopy[prop] = /** @type {PropertyDescriptorMap} */e[prop]; // Todo: Put internal to `ShimEvent`?
1376
1380
  }
1377
1381
  });
1378
1382
  }
@@ -1451,6 +1455,7 @@
1451
1455
  if (child) {
1452
1456
  child._defaultSync = this._defaultSync;
1453
1457
  }
1458
+ /* c8 ignore next -- `cfg._children` always has exactly as many entries as remaining capturing-phase steps (built from the same walk that starts this phase), so `child` is never falsy here; the `|| this` fallback is defensive only */
1454
1459
  return (child || this)._dispatchEvent(eventCopy, false);
1455
1460
  }
1456
1461
  case phases.AT_TARGET:
@@ -1748,7 +1753,7 @@
1748
1753
  * databaseNameLengthLimit: number|false,
1749
1754
  * escapeNFDForDatabaseNames: boolean,
1750
1755
  * addSQLiteExtension: boolean,
1751
- * memoryDatabase: string,
1756
+ * memoryDatabase: string|null|undefined,
1752
1757
  * deleteDatabaseFiles: boolean,
1753
1758
  * databaseBasePath: string,
1754
1759
  * sysDatabaseBasePath: string,
@@ -1891,13 +1896,27 @@
1891
1896
  // Various types of in-memory databases that can auto-delete
1892
1897
  ['memoryDatabase',
1893
1898
  /**
1894
- * @param {string} val
1899
+ * `null`/`undefined` are accepted (and left unvalidated against the
1900
+ * regex below) specifically so this can be reset back to its
1901
+ * unset/disabled state after being set: unlike other `CFG`
1902
+ * boolean-ish switches (e.g. `sqlMemoryQuota`, which is checked
1903
+ * with a falsy `if (CFG.sqlMemoryQuota)`), `memoryDatabase`'s own
1904
+ * usage sites check `typeof CFG.memoryDatabase === 'string'`, so
1905
+ * even the empty string counts as "on" (it's a distinct, valid
1906
+ * in-memory mode of its own -- an unnamed private temporary
1907
+ * database -- not an "off" state). Without this, once set to any
1908
+ * string there would be no value passable back through this same
1909
+ * validator that turns `useMemoryDatabase` false again.
1910
+ * @param {string|null|undefined} val
1895
1911
  * @throws {TypeError}
1896
1912
  * @returns {void}
1897
1913
  */
1898
1914
  function (val) {
1915
+ if (val === null || val === undefined) {
1916
+ return;
1917
+ }
1899
1918
  if (!/^(?::memory:|file::memory:(\?(?:[\0-"\$-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?(#(?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?)?$/.test(/** @type {string} */val)) {
1900
- throw new TypeError('`memoryDatabase` must be the empty string, ":memory:", or a ' + '"file::memory:[?queryString][#hash] URL".');
1919
+ throw new TypeError('`memoryDatabase` must be `null`/`undefined` (to reset it to disabled), the empty string, ' + '":memory:", or a "file::memory:[?queryString][#hash] URL".');
1901
1920
  }
1902
1921
  }],
1903
1922
  // NODE-SPECIFIC CONFIG
@@ -1951,10 +1970,7 @@
1951
1970
  return arg.replaceAll(/((?:[\uD800-\uDBFF](?![\uDC00-\uDFFF])))(?!(?:(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))|(^|(?:[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))((?:(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))/g, function (_, unmatchedHighSurrogate, precedingLow, unmatchedLowSurrogate) {
1952
1971
  // Could add a corresponding surrogate for compatibility with `node-sqlite3`: https://bugs.python.org/issue12569 and https://stackoverflow.com/a/6701665/271577
1953
1972
  // but Chrome having problems
1954
- if (unmatchedHighSurrogate) {
1955
- return '^2' + unmatchedHighSurrogate.codePointAt().toString(16).padStart(4, '0');
1956
- }
1957
- return (precedingLow || '') + '^3' + unmatchedLowSurrogate.codePointAt().toString(16).padStart(4, '0');
1973
+ return unmatchedHighSurrogate ? '^2' + unmatchedHighSurrogate.codePointAt().toString(16).padStart(4, '0') : (precedingLow || '') + '^3' + unmatchedLowSurrogate.codePointAt().toString(16).padStart(4, '0');
1958
1974
  });
1959
1975
  }
1960
1976
 
@@ -2621,7 +2637,8 @@
2621
2637
  function createNativeDOMException(name, message) {
2622
2638
  // @ts-expect-error It's ok
2623
2639
  // eslint-disable-next-line new-cap -- Ok
2624
- return new DOMException.prototype.constructor(message, name || 'DOMException');
2640
+ return new DOMException.prototype.constructor(message, /* c8 ignore next -- Defensive fallback; every call site in this codebase always supplies a `name` */
2641
+ name || 'DOMException');
2625
2642
  }
2626
2643
 
2627
2644
  // From web-platform-tests testharness.js name_code_map (though not in new spec)
@@ -2785,8 +2802,10 @@
2785
2802
  */
2786
2803
  get: function get() {
2787
2804
  if (!(this instanceof DOMException ||
2805
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
2788
2806
  // @ts-ignore Just checking; needed under some TS versions
2789
2807
  this instanceof DummyDOMException ||
2808
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
2790
2809
  // @ts-ignore Just checking; needed under some TS versions
2791
2810
  this instanceof Error)) {
2792
2811
  throw new TypeError('Illegal invocation');
@@ -2845,6 +2864,7 @@
2845
2864
  value: DOMException
2846
2865
  });
2847
2866
 
2867
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
2848
2868
  // @ts-ignore We don't need all its properties; needed under some TS versions
2849
2869
  return DOMException;
2850
2870
  }
@@ -2857,6 +2877,7 @@
2857
2877
  * @returns {Error}
2858
2878
  */
2859
2879
  function createNonNativeDOMException(name, message) {
2880
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
2860
2881
  // @ts-ignore It's ok; needed under some TS versions
2861
2882
  return new ShimNonNativeDOMException(message, name);
2862
2883
  }
@@ -2879,6 +2900,8 @@
2879
2900
  return;
2880
2901
  }
2881
2902
  var msg = error && _typeof(error) === 'object' && error.message ? error.message : (/** @type {string} */error);
2903
+
2904
+ /* c8 ignore next -- Defensive fallback for an environment lacking `console.error` */
2882
2905
  var method = typeof console.error === 'function' ? 'error' : 'log';
2883
2906
  console[method](name + ': ' + message + '. ' + (msg || ''));
2884
2907
  if (console.trace) {
@@ -3064,8 +3087,10 @@
3064
3087
  */
3065
3088
  IDBRequest.__super = function IDBRequest() {
3066
3089
  var _this = this;
3090
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
3067
3091
  // @ts-ignore It's ok
3068
3092
  this[Symbol.toStringTag] = 'IDBRequest';
3093
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
3069
3094
  // @ts-ignore Part of `ShimEventTarget`
3070
3095
  this.__setOptions({
3071
3096
  legacyOutputDidListenersThrowFlag: true // Event hook for IndexedB
@@ -3123,10 +3148,7 @@
3123
3148
  * @returns {import('./IDBTransaction.js').IDBTransactionFull|null|undefined}
3124
3149
  */
3125
3150
  IDBRequest.prototype.__getParent = function () {
3126
- if (this.toString() === '[object IDBOpenDBRequest]') {
3127
- return null;
3128
- }
3129
- return this.__transaction;
3151
+ return this.toString() === '[object IDBOpenDBRequest]' ? null : this.__transaction;
3130
3152
  };
3131
3153
 
3132
3154
  /* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
@@ -3185,8 +3207,10 @@
3185
3207
  function IDBOpenDBRequest() {
3186
3208
  IDBRequest.__super.call(this);
3187
3209
 
3210
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
3188
3211
  // @ts-ignore It's ok
3189
3212
  this[Symbol.toStringTag] = 'IDBOpenDBRequest';
3213
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
3190
3214
  // @ts-ignore It's ok
3191
3215
  this.__setOptions({
3192
3216
  legacyOutputDidListenersThrowFlag: true,
@@ -4197,8 +4221,14 @@
4197
4221
  }
4198
4222
  if (!multiEntry || !fullKeys && keys.every(function (k) {
4199
4223
  return cmp(/** @type {Key} */k, /** @type {Key} */key.value) !== 0;
4200
- }) || fullKeys && keys.every(function (k) {
4201
- return cmp(/** @type {Key} */k, /** @type {Key} */ /** @type {unknown} */key) !== 0;
4224
+ }) ||
4225
+ // `keys` holds full `{type, value}` objects here (see
4226
+ // `safePush` below), so -- like the sibling branch
4227
+ // above -- `cmp` (which expects raw `Value`s, not
4228
+ // decoded key objects) must compare their `.value`s,
4229
+ // not the wrapper objects themselves.
4230
+ fullKeys && keys.every(function (k) {
4231
+ return cmp(/** @type {Key} */ /** @type {KeyValueObject} */k.value, /** @type {Key} */key.value) !== 0;
4202
4232
  })) {
4203
4233
  safePush(keys, fullKeys ? key : key.value);
4204
4234
  }
@@ -4223,12 +4253,9 @@
4223
4253
  {
4224
4254
  var date = /** @type {Date} */input;
4225
4255
  if (!Number.isNaN(date.getTime())) {
4226
- return fullKeys ? {
4227
- type: type,
4228
- value: date.getTime()
4229
- } : {
4256
+ return {
4230
4257
  type: type,
4231
- value: new Date(date)
4258
+ value: fullKeys ? date.getTime() : new Date(date)
4232
4259
  };
4233
4260
  }
4234
4261
  return {
@@ -4316,10 +4343,7 @@
4316
4343
  if (r.failure) {
4317
4344
  return r;
4318
4345
  }
4319
- if (!multiEntry) {
4320
- return convertValueToKeyValueDecoded(r.value, null, false, fullKeys);
4321
- }
4322
- return convertValueToMultiEntryKeyDecoded(r.value, fullKeys);
4346
+ return !multiEntry ? convertValueToKeyValueDecoded(r.value, null, false, fullKeys) : convertValueToMultiEntryKeyDecoded(r.value, fullKeys);
4323
4347
  }
4324
4348
 
4325
4349
  /**
@@ -4500,10 +4524,7 @@
4500
4524
  */
4501
4525
  function isMultiEntryMatch(encodedEntry, encodedKey) {
4502
4526
  var keyType = encodedCharToKeyType[encodedKey.slice(0, 1)];
4503
- if (keyType === 'array') {
4504
- return encodedKey.indexOf(encodedEntry) > 1;
4505
- }
4506
- return encodedKey === encodedEntry;
4527
+ return keyType === 'array' ? encodedKey.indexOf(encodedEntry) > 1 : encodedKey === encodedEntry;
4507
4528
  }
4508
4529
 
4509
4530
  /**
@@ -4621,10 +4642,7 @@
4621
4642
  * @returns {undefined|ValueType}
4622
4643
  */
4623
4644
  function _decode(key, inArray) {
4624
- if (typeof key !== 'string') {
4625
- return undefined;
4626
- }
4627
- return types[encodedCharToKeyType[key.slice(0, 1)]].decode(key, inArray);
4645
+ return typeof key !== 'string' ? undefined : types[encodedCharToKeyType[key.slice(0, 1)]].decode(key, inArray);
4628
4646
  }
4629
4647
 
4630
4648
  /**
@@ -5030,10 +5048,11 @@
5030
5048
  if (hasLower && hasUpper) {
5031
5049
  sql.push('AND');
5032
5050
  }
5033
- if (hasUpper) {
5034
- sql.push(quotedKeyColumnName, range.upperOpen ? '<' : '<=', '?');
5035
- sqlValues.push(escapeSQLiteStatement(/** @type {string} */encodedUpperKey));
5051
+ if (!hasUpper) {
5052
+ return;
5036
5053
  }
5054
+ sql.push(quotedKeyColumnName, range.upperOpen ? '<' : '<=', '?');
5055
+ sqlValues.push(escapeSQLiteStatement(/** @type {string} */encodedUpperKey));
5037
5056
  }
5038
5057
 
5039
5058
  /**
@@ -5046,10 +5065,7 @@
5046
5065
  if (instanceOf(value, IDBKeyRange)) {
5047
5066
  // We still need to validate IDBKeyRange-like objects (the above check is based on loose duck-typing)
5048
5067
  var range = /** @type {IDBKeyRangeFull} */value;
5049
- if (range.toString() !== '[object IDBKeyRange]') {
5050
- return IDBKeyRange.__createInstance(range.lower, range.upper, range.lowerOpen, range.upperOpen);
5051
- }
5052
- return range;
5068
+ return range.toString() !== '[object IDBKeyRange]' ? IDBKeyRange.__createInstance(range.lower, range.upper, range.lowerOpen, range.upperOpen) : range;
5053
5069
  }
5054
5070
  if (isNullish(value)) {
5055
5071
  if (nullDisallowed) {
@@ -5094,9 +5110,11 @@
5094
5110
  if (testObject.test) {
5095
5111
  cleanInterface = true;
5096
5112
  }
5113
+ /* c8 ignore start -- Defensive fallback for an engine with a broken `Object.defineProperty` */
5097
5114
  } catch (err) {
5098
5115
  // Object.defineProperty does not work as intended.
5099
5116
  }
5117
+ /* c8 ignore stop -- Defensive fallback for an engine with a broken `Object.defineProperty` */
5100
5118
  }
5101
5119
 
5102
5120
  /**
@@ -5297,6 +5315,7 @@
5297
5315
  this._length = 0;
5298
5316
  };
5299
5317
  DOMStringList.prototype = DOMStringListAlias.prototype;
5318
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
5300
5319
  // @ts-ignore It's ok; needed under some TS versions
5301
5320
  return /** @type {DOMStringListFull} */new DOMStringList();
5302
5321
  }
@@ -5596,12 +5615,14 @@
5596
5615
  */
5597
5616
  IDBTransaction.prototype.__executeRequests = function () {
5598
5617
  var me = this;
5618
+ /* c8 ignore start -- Dead code: `__executeRequests` has exactly one caller (a single `setTimeout` scheduled once per transaction), so `me.__running` can never already be `true` when this function starts. */
5599
5619
  if (me.__running) {
5600
5620
  if (CFG.DEBUG) {
5601
5621
  console.log('Looks like the request set is already running', me.mode);
5602
5622
  }
5603
5623
  return;
5604
5624
  }
5625
+ /* c8 ignore stop -- see comment above */
5605
5626
 
5606
5627
  // The synchronous script that created this transaction (and
5607
5628
  // synchronously queued whatever requests it wanted to) has now
@@ -5621,6 +5642,10 @@
5621
5642
  var q,
5622
5643
  i = -1;
5623
5644
 
5645
+ // On a standard driver, `keepAliveAndWait` issues a SQL query, which
5646
+ // is a macrotask. Otherwise it issues ten microtasks.
5647
+ var keepAliveAttempts = isStandardDriver ? 1 : 10;
5648
+
5624
5649
  /**
5625
5650
  * A continuation that must still be able to observe the
5626
5651
  * transaction as safe to extend (e.g., re-checking whether an
@@ -5647,6 +5672,7 @@
5647
5672
  queueMicrotask(cb);
5648
5673
  return;
5649
5674
  }
5675
+ /* c8 ignore start -- Browser-only path: in every automated test environment (Node's websql-configurable/better-sqlite3 driver, and the fake/mock drivers modeled after it) `__usesStandardDriver()` is always `false` (they support the 4-arg `nonstandardTransCb` signature), so `isStandardDriver` is never `true` and this branch is never reached. Only a real standard (3-arg) WebSQL driver, as found in an actual browser, would exercise it. */
5650
5676
  try {
5651
5677
  tx.executeSql('SELECT 1', [], function () {
5652
5678
  cb();
@@ -5656,10 +5682,11 @@
5656
5682
  });
5657
5683
  } catch (err) {
5658
5684
  // The driver has already finalized the transaction (or otherwise
5659
- // rejected the call) -- nothing left to hold open, so fall back
5660
- // to a plain microtask hop for the continuation itself.
5661
- queueMicrotask(cb);
5685
+ // rejected the call) -- nothing left to hold open. We explicitly
5686
+ // abort the transaction here.
5687
+ me.__abortTransaction(/** @type {Error|DOMException} */err);
5662
5688
  }
5689
+ /* c8 ignore stop -- see comment above */
5663
5690
  }
5664
5691
 
5665
5692
  /**
@@ -5672,21 +5699,26 @@
5672
5699
  * @returns {void}
5673
5700
  */
5674
5701
  function success(result, req) {
5702
+ /* c8 ignore start -- Defensive: only reached if the transaction was independently errored/finished by a concurrent path (e.g. a driver-level failure or explicit `abort()`) racing with this request's own in-flight SQL success callback; not reliably reproducible without directly manipulating the SQL driver's callback timing. */
5675
5703
  if (me.__errored || me.__requestsFinished) {
5676
5704
  // We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
5677
5705
  return;
5678
5706
  }
5707
+ /* c8 ignore stop -- see comment above */
5679
5708
  if (req) {
5680
5709
  q.req = req; // Need to do this in case of cursors
5681
5710
  }
5711
+ /* c8 ignore start -- Dead code: `launchQueuedOp` only ever passes `success` as a callback in the branch where `q.req` is already truthy, and a falsy `req` param here leaves `q.req` unchanged, so `q.req` can't be falsy at this point. */
5682
5712
  if (!q.req) {
5683
- // TS guard
5684
5713
  return;
5685
5714
  }
5715
+ /* c8 ignore stop -- see comment above */
5716
+ /* c8 ignore start -- Defensive: only reached if the SQL driver invoked this request's success callback more than once for the same queued op; not reliably reproducible without directly manipulating the SQL driver. */
5686
5717
  if (q.req.__done) {
5687
5718
  // Avoid continuing with aborted requests
5688
5719
  return;
5689
5720
  }
5721
+ /* c8 ignore stop -- see comment above */
5690
5722
  q.req.__done = true;
5691
5723
  q.req.__result = result;
5692
5724
  q.req.__error = null;
@@ -5703,6 +5735,7 @@
5703
5735
  // is what actually resets `__handlerActive`, once it's
5704
5736
  // confirmed (across its own bounded microtask wait) that no
5705
5737
  // such continuation queued anything.
5738
+ /* c8 ignore start -- Deliberately not tested: throwing from a request's `onsuccess` handler to exercise this branch would surface as an uncaught error through this test suite's `window.onerror` shim, which (per `retention-spec.js`'s `assertLater` comment) can trigger unbounded recursion here; not safe to trigger directly. */
5706
5739
  if (e.__legacyOutputDidListenersThrowError) {
5707
5740
  logError('Error', 'An error occurred in a success handler attached to request chain', e.__legacyOutputDidListenersThrowError); // We do nothing else with this error as per spec
5708
5741
  if (!me.__committed) {
@@ -5712,6 +5745,7 @@
5712
5745
  return;
5713
5746
  }
5714
5747
  }
5748
+ /* c8 ignore stop -- see comment above */
5715
5749
  runContinuationSafely(advanceAfterDispatch);
5716
5750
  }
5717
5751
 
@@ -5723,15 +5757,19 @@
5723
5757
  * @returns {void}
5724
5758
  */
5725
5759
  function error() {
5760
+ /* c8 ignore start -- Defensive: only reached if the transaction was independently errored/finished by a concurrent path racing with this request's own in-flight SQL error callback; not reliably reproducible without directly manipulating the SQL driver's callback timing. */
5726
5761
  if (me.__errored || me.__requestsFinished) {
5727
5762
  // We've already called "onerror", "onabort", or thrown within
5728
5763
  // the transaction, so don't do it again.
5729
5764
  return;
5730
5765
  }
5766
+ /* c8 ignore stop -- see comment above */
5767
+ /* c8 ignore start -- Defensive: only reached if the SQL driver invoked this request's error callback more than once, or after its success callback already ran; not reliably reproducible without directly manipulating the SQL driver. */
5731
5768
  if (q.req && q.req.__done) {
5732
5769
  // Avoid continuing with aborted requests
5733
5770
  return;
5734
5771
  }
5772
+ /* c8 ignore stop -- see comment above */
5735
5773
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
5736
5774
  args[_key] = arguments[_key];
5737
5775
  }
@@ -5756,10 +5794,11 @@
5756
5794
  }
5757
5795
  });
5758
5796
  q.req.addDefaultEventListener('error', function () {
5797
+ /* c8 ignore start -- Defensive: this default listener is skipped entirely by `eventtargeter` whenever the event was `preventDefault()`-ed (the only case in which the shared `q` variable above could have already advanced to a different, non-request queue entry by the time a default listener runs); not reachable via the public API under normal (synchronous) dispatch. */
5759
5798
  if (!q.req) {
5760
- // TS guard
5761
5799
  return;
5762
5800
  }
5801
+ /* c8 ignore stop -- see comment above */
5763
5802
  me.__abortTransaction(q.req.__error);
5764
5803
  });
5765
5804
  me.__active = true;
@@ -5771,16 +5810,19 @@
5771
5810
  q.req.dispatchEvent(e);
5772
5811
  // Do not set __active or __handlerActive flags to false yet --
5773
5812
  // see the matching comment in `success`, above.
5774
- if (e.__legacyOutputDidListenersThrowError) {
5775
- logError('Error', 'An error occurred in an error handler attached to request chain', e.__legacyOutputDidListenersThrowError); // We do nothing else with this error as per spec
5776
- e.preventDefault(); // Prevent 'error' default as steps indicate we should abort with `AbortError` even without cancellation
5777
- if (me.__committed) {
5778
- // An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
5779
- runContinuationSafely(advanceAfterDispatch);
5780
- return;
5781
- }
5782
- me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after error).'));
5813
+ /* c8 ignore start -- Deliberately not tested: throwing from a request's `onerror` handler to exercise this branch would surface as an uncaught error through this test suite's `window.onerror` shim, which (per `retention-spec.js`'s `assertLater` comment) can trigger unbounded recursion here; not safe to trigger directly. */
5814
+ if (!e.__legacyOutputDidListenersThrowError) {
5815
+ return;
5783
5816
  }
5817
+ logError('Error', 'An error occurred in an error handler attached to request chain', e.__legacyOutputDidListenersThrowError); // We do nothing else with this error as per spec
5818
+ e.preventDefault(); // Prevent 'error' default as steps indicate we should abort with `AbortError` even without cancellation
5819
+ if (me.__committed) {
5820
+ // An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
5821
+ runContinuationSafely(advanceAfterDispatch);
5822
+ return;
5823
+ }
5824
+ me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after error).'));
5825
+ /* c8 ignore stop -- see comment above */
5784
5826
  }
5785
5827
 
5786
5828
  /**
@@ -5804,10 +5846,12 @@
5804
5846
  // (not reset here).
5805
5847
  return true;
5806
5848
  }
5849
+ /* c8 ignore start -- Defensive: reaching this queue entry via the normal advancement path after it was independently marked `__done` (e.g. by `__abortTransaction`'s own separate, async per-request error dispatch) requires a narrow race between that async cleanup and this synchronous advancement; not reliably reproducible without directly manipulating that timing. */
5807
5850
  if (q.req.__done) {
5808
5851
  // Avoid continuing with aborted requests
5809
5852
  return false;
5810
5853
  }
5854
+ /* c8 ignore stop -- see comment above */
5811
5855
  // We're now handing off to (possibly async) work for
5812
5856
  // this request, so the transaction is no longer active
5813
5857
  // until its own `success`/`error` dispatch (below)
@@ -5832,18 +5876,22 @@
5832
5876
  return;
5833
5877
  }
5834
5878
  q.op(tx, q.args, success, error, executeNextRequest);
5879
+ /* c8 ignore start -- Defensive: `q.op` (the SQL driver callback) is expected to report failures via its own `error`/`failure` callback argument rather than throwing synchronously; not reliably reproducible without directly forcing the driver to throw. */
5835
5880
  } catch (e) {
5836
5881
  error(/** @type {Error} */e);
5837
5882
  }
5883
+ /* c8 ignore stop -- see comment above */
5838
5884
  }
5839
5885
 
5840
5886
  /**
5841
5887
  * @returns {void}
5842
5888
  */
5843
5889
  function runQueuedRequest() {
5890
+ /* c8 ignore start -- Defensive: only reached if `prepareNextRequest` returns `false` (see its own ignore comment above for why that's not reliably reproducible). */
5844
5891
  if (!prepareNextRequest()) {
5845
5892
  return;
5846
5893
  }
5894
+ /* c8 ignore stop -- see comment above */
5847
5895
  launchQueuedOp();
5848
5896
  }
5849
5897
 
@@ -5865,16 +5913,20 @@
5865
5913
  * consumer of that same handler (e.g. one that resolves a
5866
5914
  * promise from within `onsuccess` and only attaches `oncomplete`
5867
5915
  * afterward) ever gets a turn to run, so it can miss `complete`
5868
- * entirely. `readonly` requests don't hold a real SQL
5869
- * transaction open, though, so there's no file-lock/connection
5870
- * collision risk in waiting the same bounded amount here.
5916
+ * afterward) ever gets a turn to run, so it can miss `complete`
5917
+ * entirely. On a non-standard driver, `readonly` requests don't hold
5918
+ * a real SQL transaction open, so there's no file-lock/connection
5919
+ * collision risk. On a standard driver, the wait now issues real SQL
5920
+ * inside the read transaction, so this does carry a slight risk.
5871
5921
  * @param {number} attemptsLeft
5872
5922
  * @returns {void}
5873
5923
  */
5874
5924
  function checkQueueEntry(attemptsLeft) {
5925
+ /* c8 ignore start -- Defensive: only reached if the transaction is independently errored/finished (e.g. an explicit `abort()`) during this function's keep-alive polling wait; not reliably reproducible without a contrived timing race. */
5875
5926
  if (me.__errored || me.__requestsFinished) {
5876
5927
  return;
5877
5928
  }
5929
+ /* c8 ignore stop -- see comment above */
5878
5930
  if (i < me.__requests.length) {
5879
5931
  runQueuedRequest();
5880
5932
  return;
@@ -5896,13 +5948,15 @@
5896
5948
  * @returns {void}
5897
5949
  */
5898
5950
  function executeNextRequest() {
5951
+ /* c8 ignore start -- Defensive: only reached if the transaction was independently errored/finished by a concurrent path racing with this continuation; not reliably reproducible without a contrived timing race. */
5899
5952
  if (me.__errored || me.__requestsFinished) {
5900
5953
  // We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
5901
5954
  return;
5902
5955
  }
5956
+ /* c8 ignore stop -- see comment above */
5903
5957
  i++;
5904
5958
  if (i >= me.__requests.length) {
5905
- checkQueueEntry(10);
5959
+ checkQueueEntry(keepAliveAttempts);
5906
5960
  return;
5907
5961
  }
5908
5962
  runQueuedRequest();
@@ -5934,31 +5988,34 @@
5934
5988
  * @returns {void}
5935
5989
  */
5936
5990
  function advanceAfterDispatch() {
5991
+ /* c8 ignore start -- Defensive: only reached if the transaction was independently errored/finished by a concurrent path racing with this continuation; not reliably reproducible without a contrived timing race. */
5937
5992
  if (me.__errored || me.__requestsFinished) {
5938
5993
  return;
5939
5994
  }
5995
+ /* c8 ignore stop -- see comment above */
5940
5996
  i++;
5941
5997
  if (i >= me.__requests.length) {
5942
- checkQueueEntry(10);
5998
+ checkQueueEntry(keepAliveAttempts);
5943
5999
  return;
5944
6000
  }
5945
6001
  keepAliveAndWait(function () {
5946
- if (me.__errored || me.__requestsFinished) {
5947
- return;
5948
- }
5949
- if (!prepareNextRequest()) {
6002
+ /* c8 ignore start -- Defensive: only reached if the transaction was independently errored/finished (or the next request's preparation failed) by a concurrent path racing with this continuation; not reliably reproducible without a contrived timing race. */
6003
+ if (me.__errored || me.__requestsFinished || !prepareNextRequest()) {
5950
6004
  return;
5951
6005
  }
6006
+ /* c8 ignore stop -- see comment above */
5952
6007
  launchQueuedOp();
5953
6008
  });
5954
6009
  }
5955
6010
  executeNextRequest();
5956
6011
  }, function webSQLError(webSQLErr) {
6012
+ /* c8 ignore start -- Dead code: the underlying websql-configurable driver's `_onTransactionComplete` always passes either `null` or a genuine `Error`/`DOMException` as this callback's argument, never the literal value `true`, under any driver used by the test suite. */
5957
6013
  // @ts-expect-error It's ok
5958
6014
  if (webSQLErr === true) {
5959
6015
  // Not a genuine SQL error
5960
6016
  return;
5961
6017
  }
6018
+ /* c8 ignore stop -- see comment above */
5962
6019
  var err = webSQLErrback(/** @type {Error & {code?: number}} */webSQLErr);
5963
6020
  me.__abortTransaction(err);
5964
6021
  }, function () {
@@ -5969,18 +6026,25 @@
5969
6026
  // Node
5970
6027
  return;
5971
6028
  }
6029
+ /* c8 ignore start -- Defensive: reaching this callback before `requestsFinished` has already set `__transactionEndCallback` (or finished) would require the underlying driver's own "queue empty" signal to race ahead of this codebase's own request-completion tracking; not observed (nor reliably reproducible) in this test suite, where the latter always wins. */
5972
6030
  if (!me.__transactionEndCallback && !me.__requestsFinished) {
5973
6031
  me.__transactionFinished = true;
5974
6032
  return;
5975
6033
  }
5976
- if (me.__transactionEndCallback && !me.__completed && !me.__transFinishedCbFired) {
5977
- me.__transFinishedCbFired = true;
5978
- me.__transFinishedCb(me.__errored, me.__transactionEndCallback);
6034
+ /* c8 ignore stop -- see comment above */
6035
+ /* c8 ignore start -- Dead code in practice: by the time this callback runs, `requestsFinished` has always already set `__transactionEndCallback` (per the guard above), and `__completed`/`__transFinishedCbFired` are always already set true by `requestsFinished`'s own `__callTransFinishedCb` call, so this guard always returns early and the fall-through body below is never reached; not reliably reproducible without a contrived timing race. */
6036
+ if (!me.__transactionEndCallback || me.__completed || me.__transFinishedCbFired) {
6037
+ return;
5979
6038
  }
6039
+ me.__transFinishedCbFired = true;
6040
+ me.__transFinishedCb(me.__errored, me.__transactionEndCallback);
6041
+ /* c8 ignore stop -- see comment above */
5980
6042
  }, function (currentTask, err, done, rollback, commit) {
6043
+ /* c8 ignore start -- Defensive: `err` here would mean the underlying WebSQL/SQLite driver reported a genuine unhandled SQL error bubbling out of this transaction's own executed statements -- every `executeSql` error callback in this codebase already handles/reports its own errors (returning `false`), so this is not reliably reproducible without mocking the SQL layer. */
5981
6044
  if (err) {
5982
6045
  return true;
5983
6046
  }
6047
+ /* c8 ignore stop -- see comment above */
5984
6048
  // `readonly` transactions never hold a real SQL transaction open
5985
6049
  // (see `WebSQLTransaction`'s constructor skipping `BEGIN;` for
5986
6050
  // them), so there's no commit/rollback round trip to defer --
@@ -6029,6 +6093,7 @@
6029
6093
  */
6030
6094
  function complete() {
6031
6095
  me.__completed = true;
6096
+ /* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
6032
6097
  if (CFG.DEBUG) {
6033
6098
  console.log('Transaction completed');
6034
6099
  }
@@ -6038,6 +6103,7 @@
6038
6103
  me.dispatchEvent(evt);
6039
6104
  me.__internal = false;
6040
6105
  me.dispatchEvent(createEvent('__complete'));
6106
+ /* c8 ignore start -- Deliberately not tested: throwing from an `oncomplete`/`__complete` handler to exercise this branch would surface as an uncaught error through this test suite's `window.onerror` shim, which (per `retention-spec.js`'s `assertLater` comment) can trigger unbounded recursion here; not safe to trigger directly. */
6041
6107
  } catch (e) {
6042
6108
  me.__internal = false;
6043
6109
  // An error occurred in the "oncomplete" handler.
@@ -6045,6 +6111,7 @@
6045
6111
  // (this may seem odd/bad, but it's how all native IndexedDB implementations work)
6046
6112
  me.__errored = true;
6047
6113
  throw e;
6114
+ /* c8 ignore stop -- see comment above */
6048
6115
  } finally {
6049
6116
  activeTransactions.delete(me);
6050
6117
  me.__storeHandles = {};
@@ -6052,10 +6119,12 @@
6052
6119
  }
6053
6120
  }
6054
6121
  if (me.mode === 'readwrite' || me.mode === 'readonly') {
6122
+ /* c8 ignore start -- Dead code in practice: `__transactionFinished` is only ever set by the driver-queue-idle-races-ahead scenario described above (also `c8 ignore`d there), which is not observed in this test suite. */
6055
6123
  if (me.__transactionFinished) {
6056
6124
  complete();
6057
6125
  return;
6058
6126
  }
6127
+ /* c8 ignore stop -- see comment above */
6059
6128
  me.__transactionEndCallback = complete;
6060
6129
  // The underlying SQL driver's own "queue empty" check
6061
6130
  // (`nonstandardTransCb`, above) typically already ran and
@@ -6091,6 +6160,7 @@
6091
6160
  IDBTransaction.prototype.__createRequest = function (source) {
6092
6161
  var me = this;
6093
6162
  var request = IDBRequest.__createInstance();
6163
+ /* c8 ignore next -- Defensive: every call site (via `__addToTransactionQueue` or directly) always passes an explicit `source`, so the `me.db` fallback is not reachable via the public API. */
6094
6164
  request.__source = source !== undefined ? source : me.db;
6095
6165
  request.__transaction = me;
6096
6166
  return request;
@@ -6160,9 +6230,11 @@
6160
6230
  * @returns {void}
6161
6231
  */
6162
6232
  IDBTransaction.prototype.__assertActive = function () {
6233
+ /* c8 ignore start -- Defensive: every call site (via `__addToTransactionQueue`/`__addNonRequestToTransactionQueue`) either already performed the static `IDBTransaction.__assertActive(tx)` check synchronously just beforehand, or queues against a transaction just created fresh (necessarily active), so this redundant instance-level check is not reachable via the public API. */
6163
6234
  if (!this.__active || !this.__handlerActive || this.__committed) {
6164
6235
  throw createDOMException('TransactionInactiveError', 'A request was placed against a transaction which is currently not active, or which is finished');
6165
6236
  }
6237
+ /* c8 ignore stop -- see comment above */
6166
6238
  };
6167
6239
 
6168
6240
  /**
@@ -6176,6 +6248,7 @@
6176
6248
  }
6177
6249
  };
6178
6250
 
6251
+ /* c8 ignore start -- Dead code: this instance method has no callers anywhere in src/ (confirmed via grep); every real call site uses the static `IDBTransaction.__assertVersionChange(tx)` directly instead. */
6179
6252
  /**
6180
6253
  * @this {IDBTransactionFull}
6181
6254
  * @returns {void}
@@ -6183,6 +6256,7 @@
6183
6256
  IDBTransaction.prototype.__assertVersionChange = function () {
6184
6257
  IDBTransaction.__assertVersionChange(this);
6185
6258
  };
6259
+ /* c8 ignore stop -- see comment above */
6186
6260
 
6187
6261
  /**
6188
6262
  * Returns the specified object store.
@@ -6204,9 +6278,12 @@
6204
6278
  throw createDOMException('NotFoundError', objectStoreName + ' is not participating in this transaction');
6205
6279
  }
6206
6280
  var store = me.db.__objectStores[objectStoreName];
6281
+ /* c8 ignore start -- Defensive: `me.__objectStoreNames` (checked just above) and `me.db.__objectStores` are always kept in sync by every code path that adds/renames/removes a store, so a name that passes the participation check above should always also be found here; not reliably reproducible via the public API. */
6207
6282
  if (!store) {
6208
6283
  throw createDOMException('NotFoundError', objectStoreName + ' does not exist in ' + me.db.name);
6209
6284
  }
6285
+ /* c8 ignore stop -- see comment above */
6286
+
6210
6287
  if (!Object.hasOwn(me.__storeHandles, objectStoreName) ||
6211
6288
  // These latter conditions are to allow store
6212
6289
  // recreation to create new clone object
@@ -6225,10 +6302,12 @@
6225
6302
  IDBTransaction.prototype.__abortTransaction = function (err) {
6226
6303
  var me = this;
6227
6304
  logError('Error', 'An error occurred in a transaction', err);
6305
+ /* c8 ignore start -- Defensive re-entrancy guard: only reached if `__abortTransaction` is invoked a second time on the same transaction after `__errored` is already `true` (e.g. two independent internal error paths racing); not reliably reproducible without a contrived timing race. */
6228
6306
  if (me.__errored) {
6229
6307
  // We've already called "onerror", "onabort", or thrown, so don't do it again.
6230
6308
  return;
6231
6309
  }
6310
+ /* c8 ignore stop -- see comment above */
6232
6311
  me.__errored = true;
6233
6312
  if (me.mode === 'versionchange') {
6234
6313
  // Steps for aborting an upgrade transaction
@@ -6258,19 +6337,16 @@
6258
6337
  if (err !== null) {
6259
6338
  me.__error = err;
6260
6339
  }
6340
+
6341
+ /* c8 ignore start -- Defense in depth: `err` is only ever `null` here via `IDBTransaction.prototype.abort`'s own `__abortTransaction(null)` call, which now checks `__requestsFinished` itself first and throws `InvalidStateError` synchronously before ever reaching this point -- so this guard should not see a non-null `err` in practice. */
6261
6342
  if (me.__requestsFinished && err !== null) {
6262
6343
  // The transaction has already completed, so we can't call "onerror" or "onabort".
6263
- // So throw the error instead. `err` is only ever `null` here via
6264
- // `IDBTransaction.prototype.abort`'s own `__abortTransaction(null)`
6265
- // call, which now checks `__requestsFinished` itself first and
6266
- // throws `InvalidStateError` synchronously before ever reaching
6267
- // this point -- so this guard is just defense in depth against
6268
- // `err` somehow being `null` some other way, not something this
6269
- // path should see in practice.
6344
+ // So throw the error instead.
6270
6345
  setTimeout(function () {
6271
6346
  throw err;
6272
6347
  }, 0);
6273
6348
  }
6349
+ /* c8 ignore stop -- see comment above */
6274
6350
 
6275
6351
  /**
6276
6352
  * @param {import('websql-configurable/lib/websql/WebSQLTransaction.js').default|null} [tx]
@@ -6279,13 +6355,17 @@
6279
6355
  */
6280
6356
  function abort(tx, errOrResult) {
6281
6357
  if (!tx) {
6358
+ /* c8 ignore next -- Debug-only log; only reached via the no-op `abort()` calls below (rare paths), and requires `CFG.DEBUG` to have any effect anyway. */
6282
6359
  if (CFG.DEBUG) {
6283
6360
  console.log('Rollback not possible due to missing transaction', me);
6284
6361
  }
6362
+ /* c8 ignore start -- Defensive: the underlying WebSQL/SQLite driver erroring on the manual `ROLLBACK` executed below (with a result object exposing a numeric `code`) is not reliably reproducible without mocking the SQL layer. */
6285
6363
  } else if (errOrResult && 'code' in errOrResult && typeof errOrResult.code === 'number') {
6286
6364
  if (CFG.DEBUG) {
6287
6365
  console.log('Rollback erred; feature is probably not supported as per WebSQL', me);
6288
6366
  }
6367
+ /* c8 ignore stop -- see comment above */
6368
+ /* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
6289
6369
  } else if (CFG.DEBUG) {
6290
6370
  console.log('Rollback succeeded', me);
6291
6371
  }
@@ -6301,10 +6381,11 @@
6301
6381
  // behaves first-in-first-out with the same timeout so we could
6302
6382
  // just use a `forEach`.
6303
6383
  return promises.then(function () {
6384
+ /* c8 ignore start -- Dead code: the preceding `.filter()` only keeps entries with a truthy `q.req`, and nothing ever resets `q.req` back to a falsy value afterward, so this invariant can't actually be violated. */
6304
6385
  if (!q.req) {
6305
- // TS guard
6306
6386
  throw new Error('Missing request');
6307
6387
  }
6388
+ /* c8 ignore stop -- see comment above */
6308
6389
  q.req.__done = true;
6309
6390
  q.req.__result = undefined;
6310
6391
  q.req.__error = createDOMException('AbortError', 'A request was aborted (an unfinished request).');
@@ -6315,10 +6396,11 @@
6315
6396
  return new SyncPromise(/** @type {(resolve: (value?: unknown) => void) => void} */
6316
6397
  function (resolve) {
6317
6398
  setTimeout(function () {
6399
+ /* c8 ignore start -- Dead code: same invariant as above -- `q.req` was already confirmed truthy by the outer `.filter()` and is never reset. */
6318
6400
  if (!q.req) {
6319
- // TS guard
6320
6401
  throw new Error('Missing request');
6321
6402
  }
6403
+ /* c8 ignore stop -- see comment above */
6322
6404
  q.req.dispatchEvent(reqEvt); // No need to catch errors
6323
6405
  resolve();
6324
6406
  }, 0);
@@ -6338,10 +6420,12 @@
6338
6420
  releaseFinishedTransaction(me);
6339
6421
  }, 0);
6340
6422
  return undefined;
6423
+ /* c8 ignore start -- Diagnostic safety net: nothing in the preceding promise chain normally rejects (the only throws it could catch are the dead invariant-violation checks above), so this handler is not reachable in practice. */
6341
6424
  }).catch(function (err) {
6342
6425
  console.log('Abort error');
6343
6426
  throw err;
6344
6427
  });
6428
+ /* c8 ignore stop -- see comment above */
6345
6429
  }
6346
6430
  me.__transFinishedCb(true, function (rollback) {
6347
6431
  if (rollback && me.__tx) {
@@ -6349,20 +6433,24 @@
6349
6433
  // rollback automatically), but for Node.js, etc., we give chance for
6350
6434
  // manual aborts which would otherwise not work.
6351
6435
  if (me.mode === 'readwrite') {
6436
+ /* c8 ignore start -- Dead code in practice: `__transactionFinished` is only ever set by the driver-queue-idle-races-ahead scenario described earlier in this file (also `c8 ignore`d there), which is not observed in this test suite. */
6352
6437
  if (me.__transactionFinished) {
6353
6438
  abort();
6354
6439
  return;
6355
6440
  }
6441
+ /* c8 ignore stop -- see comment above */
6356
6442
  me.__transactionEndCallback = abort;
6357
6443
  return;
6358
6444
  }
6359
6445
  try {
6360
6446
  me.__tx.executeSql('ROLLBACK', [], abort, /** @type {import('websql-configurable/lib/websql/WebSQLTransaction.js').SqlErrorCallback} */abort); // Not working in some circumstances, even in Node
6447
+ /* c8 ignore start -- Defensive: the underlying WebSQL/SQLite driver throwing synchronously on `ROLLBACK` is not reliably reproducible without mocking the SQL layer. */
6361
6448
  } catch (err) {
6362
6449
  // Browser errs when transaction has ended and since it most likely already erred here,
6363
6450
  // we call to abort
6364
6451
  abort();
6365
6452
  }
6453
+ /* c8 ignore stop -- see comment above */
6366
6454
  } else {
6367
6455
  abort(null, {
6368
6456
  code: 0
@@ -6380,6 +6468,7 @@
6380
6468
  if (!(me instanceof IDBTransaction)) {
6381
6469
  throw new TypeError('Illegal invocation');
6382
6470
  }
6471
+ /* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
6383
6472
  if (CFG.DEBUG) {
6384
6473
  console.log('The transaction was aborted', me);
6385
6474
  }
@@ -6411,6 +6500,7 @@
6411
6500
  if (!me.__active || !me.__handlerActive || me.__committed) {
6412
6501
  throw createDOMException('InvalidStateError', 'Failed to execute \'commit\' on \'IDBTransaction\': The transaction is not active.');
6413
6502
  }
6503
+ /* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
6414
6504
  if (CFG.DEBUG) {
6415
6505
  console.log('The transaction was explicitly committed', me);
6416
6506
  }
@@ -6453,6 +6543,7 @@
6453
6543
  };
6454
6544
 
6455
6545
  // object store methods behave differently: see https://github.com/w3c/IndexedDB/issues/192
6546
+ /* c8 ignore start -- Dead code: this function has no callers anywhere in src/ (confirmed via grep); object store methods use `IDBTransaction.__assertActive`/`__assertNotFinished` directly instead. */
6456
6547
  /**
6457
6548
  *
6458
6549
  * @param {IDBTransactionFull} tx
@@ -6468,6 +6559,7 @@
6468
6559
  throw err;
6469
6560
  }
6470
6561
  };
6562
+ /* c8 ignore stop -- see comment above */
6471
6563
 
6472
6564
  /**
6473
6565
  *
@@ -7565,7 +7657,7 @@
7565
7657
  return Number.isNaN(t) ? "NaN" : t;
7566
7658
  },
7567
7659
  revive: function revive(e) {
7568
- return "NaN" === e ? new Date(NaN) : new Date(e);
7660
+ return new Date("NaN" === e ? NaN : e);
7569
7661
  }
7570
7662
  }
7571
7663
  },
@@ -8425,9 +8517,12 @@
8425
8517
  }).find(function (preset) {
8426
8518
  return preset && !Array.isArray(preset) && 'filelist' in preset;
8427
8519
  });
8428
- var origFileList = specSet && !Array.isArray(specSet) && 'filelist' in specSet ? specSet.filelist : undefined;
8429
- var origTest = origFileList && _typeof(origFileList) === 'object' && 'test' in origFileList && typeof origFileList.test === 'function' ? origFileList.test : undefined;
8430
- var origRevive = origFileList && _typeof(origFileList) === 'object' && 'revive' in origFileList && typeof origFileList.revive === 'function' ? origFileList.revive : undefined;
8520
+ var origFileList = specSet && !Array.isArray(specSet) && 'filelist' in specSet ? specSet.filelist
8521
+ /* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */ : undefined;
8522
+ var origTest = origFileList && _typeof(origFileList) === 'object' && 'test' in origFileList && typeof origFileList.test === 'function' ? origFileList.test
8523
+ /* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.test` ever goes missing */ : undefined;
8524
+ var origRevive = origFileList && _typeof(origFileList) === 'object' && 'revive' in origFileList && typeof origFileList.revive === 'function' ? origFileList.revive
8525
+ /* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.revive` ever goes missing */ : undefined;
8431
8526
  var customFileList = origFileList ? _objectSpread2(_objectSpread2({}, origFileList), {}, {
8432
8527
  /**
8433
8528
  * @param {unknown} x
@@ -8435,10 +8530,7 @@
8435
8530
  * @returns {boolean}
8436
8531
  */
8437
8532
  test: function test(x, state) {
8438
- if (typeof FileList !== 'undefined') {
8439
- return x instanceof FileList;
8440
- }
8441
- return typeof origTest === 'function' ? origTest(x, state) : false;
8533
+ return typeof FileList !== 'undefined' ? x instanceof FileList : typeof origTest === 'function' && origTest(x, state);
8442
8534
  },
8443
8535
  /**
8444
8536
  * @param {unknown} x
@@ -8449,10 +8541,12 @@
8449
8541
  if (typeof FileList !== 'undefined') {
8450
8542
  return Reflect.construct(FileList, [x]);
8451
8543
  }
8544
+ /* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.revive` ever goes missing */
8452
8545
  return typeof origRevive === 'function' ? origRevive(x, state) : undefined;
8453
8546
  }
8454
- }) : undefined;
8455
- var typeson = new Typeson().register([fe, customFileList ? {
8547
+ }) /* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */ : undefined;
8548
+ var typeson = new Typeson().register([fe, /* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */
8549
+ customFileList ? {
8456
8550
  filelist: customFileList
8457
8551
  } : {}]);
8458
8552
 
@@ -8608,7 +8702,6 @@
8608
8702
  * __unique: boolean,
8609
8703
  * __objectStore: import('./IDBObjectStore.js').IDBObjectStoreFull,
8610
8704
  * __keyPath: import('./Key.js').KeyPath,
8611
- * __recreated?: boolean,
8612
8705
  * __fetchIndexData: (
8613
8706
  * range: Query,
8614
8707
  * opType: "value"|"key"|"count",
@@ -8702,6 +8795,7 @@
8702
8795
  storeHandle.__indexHandles[newName] = oldIndexHandle; // Ensure new reference accessible
8703
8796
  me.__pendingName = oldName;
8704
8797
  var colInfoToPreserveArr = [['key', 'BLOB ' + (objectStore.autoIncrement ? 'UNIQUE, inc INTEGER PRIMARY KEY AUTOINCREMENT' : 'PRIMARY KEY')], ['value', 'BLOB']].concat(
8798
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
8705
8799
  // @ts-ignore Has numeric indexes instead of iterator; needed under some TS versions
8706
8800
  _toConsumableArray(objectStore.indexNames).filter(function (indexName) {
8707
8801
  return indexName !== newName;
@@ -8753,7 +8847,7 @@
8753
8847
  }
8754
8848
  });
8755
8849
  /** @type {const} */
8756
- ['__pendingCreate', '__pendingDelete', '__deleted', '__originalName', '__recreated'].forEach(function (p) {
8850
+ ['__pendingCreate', '__pendingDelete', '__deleted', '__originalName'].forEach(function (p) {
8757
8851
  // @ts-expect-error Why is this type "never"?
8758
8852
  idx[p] = index[p];
8759
8853
  });
@@ -8785,11 +8879,12 @@
8785
8879
  var transaction = store.transaction;
8786
8880
  /** @type {import('./IDBTransaction.js').IDBTransactionFull} */
8787
8881
  transaction.__addNonRequestToTransactionQueue(function createIndex(tx, args, success, failure) {
8788
- var columnExists = idx && (idx.__deleted || idx.__recreated); // This check must occur here rather than earlier as properties may not have been set yet otherwise
8882
+ var columnExists = idx && idx.__deleted; // This check must occur here rather than earlier as properties may not have been set yet otherwise
8789
8883
 
8790
8884
  /** @type {{[key: string]: boolean}} */
8791
8885
  var indexValues = {};
8792
8886
 
8887
+ /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
8793
8888
  /**
8794
8889
  * @param {WebSQLTransaction} tx
8795
8890
  * @param {(Error & {code?: number})} err
@@ -8798,6 +8893,7 @@
8798
8893
  function error(tx, err) {
8799
8894
  failure(createDOMException('UnknownError', 'Could not create index "' + indexName + '"' + err.code + '::' + err.message, err));
8800
8895
  }
8896
+ /* c8 ignore stop -- see comment above */
8801
8897
 
8802
8898
  /**
8803
8899
  * @param {WebSQLTransaction} tx
@@ -8847,12 +8943,6 @@
8847
8943
  } else {
8848
8944
  delete index.__pendingCreate;
8849
8945
  delete indexHandle.__pendingCreate;
8850
- if (index.__deleted) {
8851
- delete index.__deleted;
8852
- delete indexHandle.__deleted;
8853
- index.__recreated = true;
8854
- indexHandle.__recreated = true;
8855
- }
8856
8946
  indexValues = {};
8857
8947
  success(store);
8858
8948
  }
@@ -8861,7 +8951,7 @@
8861
8951
  }, /** @type {SqlErrorCallback} */error);
8862
8952
  }
8863
8953
  var escapedStoreNameSQL = escapeStoreNameForSQL(storeName);
8864
- var escapedIndexNameSQL = escapeIndexNameForSQL(index.name);
8954
+ var escapedIndexNameSQL = escapeIndexNameForSQL(indexName);
8865
8955
 
8866
8956
  /**
8867
8957
  * @param {WebSQLTransaction} tx
@@ -8913,6 +9003,7 @@
8913
9003
  var transaction = store.transaction;
8914
9004
  /** @type {import('./IDBTransaction.js').IDBTransactionFull} */
8915
9005
  transaction.__addNonRequestToTransactionQueue(function deleteIndex(tx, args, success, failure) {
9006
+ /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
8916
9007
  /**
8917
9008
  * @param {WebSQLTransaction} tx
8918
9009
  * @param {(Error & {code?: number})} err
@@ -8921,6 +9012,7 @@
8921
9012
  function error(tx, err) {
8922
9013
  failure(createDOMException('UnknownError', 'Could not delete index "' + index.name + '"', err));
8923
9014
  }
9015
+ /* c8 ignore stop -- see comment above */
8924
9016
 
8925
9017
  /**
8926
9018
  * @returns {void}
@@ -8929,7 +9021,6 @@
8929
9021
  // Update the object store's index list
8930
9022
  IDBIndex.__updateIndexList(store, tx, function (store) {
8931
9023
  delete index.__pendingDelete;
8932
- delete index.__recreated;
8933
9024
  index.__deleted = true;
8934
9025
  if (indexHandle) {
8935
9026
  indexHandle.__deleted = true;
@@ -8990,20 +9081,18 @@
8990
9081
  * @param {Query} range
8991
9082
  * @param {"value"|"key"|"count"} opType
8992
9083
  * @param {boolean} nullDisallowed
8993
- * @param {number} [count]
8994
9084
  * @this {IDBIndexFull}
8995
9085
  * @returns {import('./IDBRequest.js').IDBRequestFull}
8996
9086
  */
8997
- IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed, count) {
9087
+ IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed) {
8998
9088
  var me = this;
8999
- if (count !== undefined) {
9000
- count = enforceRange(count, 'unsigned long');
9001
- }
9002
9089
  IDBIndex.__invalidStateIfDeleted(me);
9003
9090
  IDBObjectStore.__invalidStateIfDeleted(me.objectStore);
9091
+ /* c8 ignore start -- Defensive: `IDBObjectStore.__invalidStateIfDeleted` just above already throws when `me.objectStore.__deleted` is true, so this identical check can never be reached. */
9004
9092
  if (me.objectStore.__deleted) {
9005
9093
  throw createDOMException('InvalidStateError', "This index's object store has been deleted");
9006
9094
  }
9095
+ /* c8 ignore stop -- see comment above */
9007
9096
  IDBTransaction.__assertActive(me.objectStore.transaction);
9008
9097
  if (nullDisallowed && isNullish(range)) {
9009
9098
  throw createDOMException('DataError', 'No key or range was specified');
@@ -9013,7 +9102,7 @@
9013
9102
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
9014
9103
  args[_key] = arguments[_key];
9015
9104
  }
9016
- executeFetchIndexData.apply(void 0, [count].concat(_toConsumableArray(fetchArgs), args));
9105
+ executeFetchIndexData.apply(void 0, _toConsumableArray(fetchArgs).concat(args));
9017
9106
  }, undefined, me);
9018
9107
  };
9019
9108
 
@@ -9172,13 +9261,16 @@
9172
9261
  var colInfoToPreserve = colInfoToPreserveArr.map(function (colInfo) {
9173
9262
  return colInfo.join(' ');
9174
9263
  });
9264
+ /* c8 ignore next -- Defensive: the sole caller always supplies a non-empty `colInfoToPreserveArr` (seeded with `key`/`value` column info), so the empty-array fallback is unreachable. */
9175
9265
  var listColInfoToPreserve = colInfoToPreserve.length ? colInfoToPreserve.join(', ') + ', ' : '';
9266
+ /* c8 ignore next -- Defensive: see comment above. */
9176
9267
  var listColsToPreserve = colNamesToPreserve.length ? colNamesToPreserve.join(', ') + ', ' : '';
9177
9268
 
9178
9269
  // We could adapt the approach at https://stackoverflow.com/a/8430746/271577
9179
9270
  // to make the approach reusable without passing column names, but it is a bit fragile
9180
9271
  /** @type {import('./IDBTransaction.js').IDBTransactionFull} */
9181
9272
  store.transaction.__addNonRequestToTransactionQueue(function renameIndex(tx, args, success, error) {
9273
+ /* c8 ignore start -- Defensive: only reached if one of the chained `CREATE TABLE`/`INSERT`/`DROP TABLE`/`ALTER TABLE` statements below fails, which is not reliably reproducible without mocking the SQL layer. */
9182
9274
  /**
9183
9275
  * @param {WebSQLTransaction} tx
9184
9276
  * @param {(Error & {code?: number})} err
@@ -9187,6 +9279,7 @@
9187
9279
  function sqlError(tx, err) {
9188
9280
  error(err);
9189
9281
  }
9282
+ /* c8 ignore stop -- see comment above */
9190
9283
  /**
9191
9284
  * @returns {void}
9192
9285
  */
@@ -9195,8 +9288,14 @@
9195
9288
  cb(tx, success);
9196
9289
  return;
9197
9290
  }
9291
+ /* c8 ignore start -- Defensive: `__renameIndex`'s only caller (the `IDBIndex.prototype.name` setter) always supplies a `cb`, so this fallback is dead with the current call graph. */
9198
9292
  success();
9199
9293
  }
9294
+ /* c8 ignore stop -- see comment above */
9295
+ if (!CFG.useSQLiteIndexes) {
9296
+ finish();
9297
+ return;
9298
+ }
9200
9299
  // See https://www.sqlite.org/lang_altertable.html#otheralter
9201
9300
  // We don't query for indexes as we already have the info
9202
9301
  // This approach has the advantage of auto-deleting indexes via the DROP TABLE
@@ -9220,10 +9319,6 @@
9220
9319
  console.log(sql);
9221
9320
  }
9222
9321
  tx.executeSql(sql, [], function (tx) {
9223
- if (!CFG.useSQLiteIndexes) {
9224
- finish();
9225
- return;
9226
- }
9227
9322
  var indexCreations = colNamesToPreserve.slice(2) // Doing `key` separately and no need for index on `value`
9228
9323
  .map(function (escapedIndexNameSQL) {
9229
9324
  return new SyncPromise(function (resolve, reject) {
@@ -9232,13 +9327,16 @@
9232
9327
  // if (CFG.DEBUG) { console.log(sql); }
9233
9328
  // tx.executeSql(sql, [], function () {
9234
9329
  var sql = 'CREATE INDEX ' + escapedIndexToRecreate + ' ON ' + escapedStoreNameSQL + '(' + escapedIndexNameSQL + ')';
9330
+ /* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
9235
9331
  if (CFG.DEBUG) {
9236
9332
  console.log(sql);
9237
9333
  }
9238
- tx.executeSql(sql, [], resolve, /** @type {SqlErrorCallback} */
9334
+ tx.executeSql(sql, [], resolve, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
9335
+ /** @type {SqlErrorCallback} */
9239
9336
  function (tx, err) {
9240
9337
  reject(err);
9241
- });
9338
+ }
9339
+ /* c8 ignore stop -- see comment above */);
9242
9340
  // }, function (tx, err) {
9243
9341
  // reject(err);
9244
9342
  // });
@@ -9256,19 +9354,25 @@
9256
9354
  if (CFG.DEBUG) {
9257
9355
  console.log(sql);
9258
9356
  }
9259
- tx.executeSql(sql, [], resolve, /** @type {SqlErrorCallback} */
9357
+ tx.executeSql(sql, [], resolve, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
9358
+ /** @type {SqlErrorCallback} */
9260
9359
  function (tx, err) {
9261
9360
  reject(err);
9262
- });
9263
- }, /** @type {SqlErrorCallback} */
9361
+ }
9362
+ /* c8 ignore stop -- see comment above */);
9363
+ }, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
9364
+ /** @type {SqlErrorCallback} */
9264
9365
  function (tx, err) {
9265
9366
  reject(err);
9266
- });
9367
+ }
9368
+ /* c8 ignore stop -- see comment above */);
9267
9369
  }));
9268
9370
  SyncPromise.all(indexCreations).then(finish).catch(/** @type {(reason: unknown) => PromiseLike<never>} */
9269
9371
  error).catch(function (err) {
9372
+ /* c8 ignore start -- Defensive: only reached if `finish` or the outer `error` callback itself throws; not reliably reproducible. */
9270
9373
  console.log('Index rename error');
9271
9374
  throw err;
9375
+ /* c8 ignore stop -- see comment above */
9272
9376
  });
9273
9377
  }, /** @type {SqlErrorCallback} */sqlError);
9274
9378
  }, /** @type {SqlErrorCallback} */sqlError);
@@ -9297,7 +9401,6 @@
9297
9401
  /* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
9298
9402
 
9299
9403
  /**
9300
- * @param {number|null} count
9301
9404
  * @param {boolean} unboundedDisallowed
9302
9405
  * @param {IDBIndexFull} index
9303
9406
  * @param {boolean} hasKey
@@ -9314,12 +9417,9 @@
9314
9417
  * @param {(tx: WebSQLTransaction, err: (Error & {code?: number})) => void} error
9315
9418
  * @returns {void}
9316
9419
  */
9317
- function executeFetchIndexData(count, unboundedDisallowed, index, hasKey, range, opType, multiChecks, sql, sqlValues, tx, args, success, error) {
9420
+ function executeFetchIndexData(unboundedDisallowed, index, hasKey, range, opType, multiChecks, sql, sqlValues, tx, args, success, error) {
9318
9421
  if (unboundedDisallowed) {
9319
- count = 1;
9320
- }
9321
- if (count) {
9322
- sql.push('LIMIT', String(count));
9422
+ sql.push('LIMIT', '1');
9323
9423
  }
9324
9424
  var isCount = opType === 'count';
9325
9425
  if (CFG.DEBUG) {
@@ -9357,41 +9457,48 @@
9357
9457
  var escapedIndexNameForKeyCol = escapeIndexNameForSQLKeyColumn(index.name);
9358
9458
  var encodedKey = _encode(range, index.multiEntry);
9359
9459
  var _loop = function _loop() {
9360
- var row = /** @type {{key: string, value: string, [k: string]: string}} */data.rows.item(i);
9361
- var rowKey = /** @type {import('./Key.js').ValueTypeArray} */
9362
- _decode(row[escapedIndexNameForKeyCol]);
9363
- var record;
9364
- if (hasKey && (multiChecks && /** @type {import('./Key.js').ValueType[]} */range.some(
9365
- /**
9366
- * @param {import('./Key.js').ValueType} check
9367
- * @returns {boolean}
9368
- */
9369
- function (check) {
9370
- return rowKey.includes(check);
9371
- }) ||
9372
- // More precise than our SQL
9373
- isMultiEntryMatch(
9374
- // Added `JSON.stringify` as was having problems with
9375
- // `JSON.stringify` encoding added to nested
9376
- // array keys
9377
- JSON.stringify(encodedKey).slice(1, -1), row[escapedIndexNameForKeyCol]))) {
9378
- recordCount++;
9379
- record = row;
9380
- } else if (!hasKey && !multiChecks) {
9381
- if (rowKey !== undefined) {
9382
- recordCount += Array.isArray(rowKey) ? rowKey.length : 1;
9460
+ var row = /** @type {{key: string, value: string, [k: string]: string}} */data.rows.item(i);
9461
+ var rowKey = /** @type {import('./Key.js').ValueTypeArray} */
9462
+ _decode(row[escapedIndexNameForKeyCol]);
9463
+ var record;
9464
+ if (hasKey && (multiChecks && /** @type {import('./Key.js').ValueType[]} */range.some(
9465
+ /**
9466
+ * @param {import('./Key.js').ValueType} check
9467
+ * @returns {boolean}
9468
+ */
9469
+ function (check) {
9470
+ return rowKey.includes(check);
9471
+ }) ||
9472
+ // More precise than our SQL
9473
+ isMultiEntryMatch(
9474
+ // Added `JSON.stringify` as was having problems with
9475
+ // `JSON.stringify` encoding added to nested
9476
+ // array keys
9477
+ JSON.stringify(encodedKey).slice(1, -1), row[escapedIndexNameForKeyCol]))) {
9478
+ recordCount++;
9383
9479
  record = row;
9480
+ } else if (!hasKey && !multiChecks) {
9481
+ if (rowKey !== undefined) {
9482
+ recordCount += Array.isArray(rowKey) ? rowKey.length : 1;
9483
+ record = row;
9484
+ }
9384
9485
  }
9385
- }
9386
- if (record) {
9486
+ /* c8 ignore start -- Defensive: the SQL `LIKE` clause is a coarse pre-filter and this precise re-check in JS is meant to catch its false positives, but the encoding's per-character dash-prefix plus trailing-space delimiter (see `Key.js` string encoding) and fixed-length number encoding prevent one encoded value from ever being a spurious substring of another, so a `LIKE` hit always also passes this check in practice. */
9487
+ if (!record) {
9488
+ return 0; // continue
9489
+ }
9490
+ /* c8 ignore stop -- see comment above */
9491
+
9387
9492
  records.push(decode$1(record));
9388
9493
  if (unboundedDisallowed) {
9389
9494
  return 1; // break
9390
9495
  }
9391
- }
9392
- };
9496
+ },
9497
+ _ret;
9393
9498
  for (var i = 0; i < data.rows.length; i++) {
9394
- if (_loop()) break;
9499
+ _ret = _loop();
9500
+ if (_ret === 0) continue;
9501
+ if (_ret === 1) break;
9395
9502
  }
9396
9503
  } else {
9397
9504
  for (var _i = 0; _i < data.rows.length; _i++) {
@@ -9405,8 +9512,16 @@
9405
9512
  if (isCount) {
9406
9513
  success(recordCount);
9407
9514
  } else if (recordCount === 0) {
9515
+ // `unboundedDisallowed` is always `true` here: this function is only reached (for
9516
+ // non-`count` `opType`s) via `get`/`getKey`, which always pass `nullDisallowed: true`
9517
+ // through as `unboundedDisallowed`. `getAll`/`getAllKeys`/`getAllRecords` use a
9518
+ // different (cursor-based) code path, so the `unboundedDisallowed`-`false` case
9519
+ // (returning `[]` here) is unreachable given current callers.
9520
+ /* c8 ignore next -- see comment above */
9408
9521
  success(unboundedDisallowed ? undefined : []);
9409
9522
  } else {
9523
+ // `unboundedDisallowed` is always `true` here; see comment above.
9524
+ /* c8 ignore next -- see comment above */
9410
9525
  success(unboundedDisallowed ? records[0] : records);
9411
9526
  }
9412
9527
  }, /** @type {SqlErrorCallback} */error);
@@ -9650,6 +9765,7 @@
9650
9765
  tx.executeSql(sql, sqlValues, function (tx) {
9651
9766
  // This SQL preserves indexes per https://www.sqlite.org/lang_altertable.html
9652
9767
  var sql = 'ALTER TABLE ' + escapeStoreNameForSQL(oldName) + ' RENAME TO ' + escapeStoreNameForSQL(name);
9768
+ /* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG` while renaming a store. */
9653
9769
  if (CFG.DEBUG) {
9654
9770
  console.log(sql);
9655
9771
  }
@@ -9658,8 +9774,10 @@
9658
9774
  success();
9659
9775
  });
9660
9776
  }, function (tx, err) {
9777
+ /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
9661
9778
  error(err);
9662
9779
  return false;
9780
+ /* c8 ignore stop -- see comment above */
9663
9781
  });
9664
9782
  });
9665
9783
  }
@@ -9733,6 +9851,7 @@
9733
9851
  storeHandles[storeName] = IDBObjectStore.__clone(store, transaction);
9734
9852
  }
9735
9853
  transaction.__addNonRequestToTransactionQueue(function createObjectStore(tx, args, success, failure) {
9854
+ /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
9736
9855
  /**
9737
9856
  * @param {WebSQLTransaction} tx
9738
9857
  * @param {(Error & {code?: number})} [err]
@@ -9745,6 +9864,8 @@
9745
9864
  failure(createDOMException('UnknownError', 'Could not create object store "' + storeName + '"', err));
9746
9865
  return false;
9747
9866
  }
9867
+ /* c8 ignore stop -- see comment above */
9868
+
9748
9869
  var escapedStoreNameSQL = escapeStoreNameForSQL(storeName);
9749
9870
  // key INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE
9750
9871
  var sql = ['CREATE TABLE', escapedStoreNameSQL, '(key BLOB', store.autoIncrement ? 'UNIQUE, inc INTEGER PRIMARY KEY AUTOINCREMENT' : 'PRIMARY KEY', ', value BLOB)'].join(' ');
@@ -9799,6 +9920,7 @@
9799
9920
 
9800
9921
  // Remove the object store from WebSQL
9801
9922
  transaction.__addNonRequestToTransactionQueue(function deleteObjectStore(tx, args, success, failure) {
9923
+ /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
9802
9924
  /**
9803
9925
  * @param {WebSQLTransaction} tx
9804
9926
  * @param {(Error & {code?: number})} [err]
@@ -9811,6 +9933,8 @@
9811
9933
  failure(createDOMException('UnknownError', 'Could not delete ObjectStore', err));
9812
9934
  return false;
9813
9935
  }
9936
+ /* c8 ignore stop -- see comment above */
9937
+
9814
9938
  tx.executeSql('SELECT "name" FROM __sys__ WHERE "name" = ?', [escapeSQLiteStatement(store.__currentName)], function (tx, data) {
9815
9939
  if (data.rows.length > 0) {
9816
9940
  tx.executeSql('DROP TABLE ' + escapeStoreNameForSQL(store.__currentName), [], function () {
@@ -9990,13 +10114,15 @@
9990
10114
  return;
9991
10115
  }
9992
10116
  var indexKeyValue = indexKey.value;
10117
+ /* c8 ignore start -- Defensive: unreachable given the current `Key.js` implementation, where a keyPath evaluation that would resolve to `undefined` always instead reports `invalid`/`failure` (caught above, causing an earlier `return`) rather than succeeding with an `undefined` value. */
9993
10118
  if (indexKeyValue === undefined) {
9994
10119
  resolve(undefined);
9995
10120
  return;
9996
10121
  }
10122
+ /* c8 ignore stop -- see comment above */
9997
10123
  var multiCheck = index.multiEntry && Array.isArray(indexKeyValue);
9998
10124
  var fetchArgs = buildFetchIndexDataSQL(true, index, indexKeyValue, 'key', multiCheck);
9999
- executeFetchIndexData.apply(void 0, [null].concat(_toConsumableArray(fetchArgs), [tx, null, function success(key) {
10125
+ executeFetchIndexData.apply(void 0, _toConsumableArray(fetchArgs).concat([tx, null, function success(key) {
10000
10126
  if (key === undefined || excludeKey !== undefined && cmp(/** @type {import('./Key.js').Key} */key, excludeKey) === 0) {
10001
10127
  resolve(undefined);
10002
10128
  return;
@@ -10076,16 +10202,18 @@
10076
10202
  * @returns {void}
10077
10203
  */
10078
10204
  function setIndexInfo(index) {
10205
+ /* c8 ignore start -- Defensive: unreachable given the current `Key.js` implementation, where a keyPath evaluation that would resolve to `undefined` always instead reports `invalid`/`failure` (caught above, causing an earlier `return`) rather than succeeding with an `undefined` value. */
10079
10206
  if (indexKeyValue === undefined) {
10080
10207
  return;
10081
10208
  }
10209
+ /* c8 ignore stop -- see comment above */
10082
10210
  paramMap[index.__currentName] = /** @type {string} */
10083
10211
  _encode(indexKeyValue, index.multiEntry);
10084
10212
  }
10085
10213
  if (index.unique) {
10086
10214
  var multiCheck = index.multiEntry && Array.isArray(indexKeyValue);
10087
10215
  var fetchArgs = buildFetchIndexDataSQL(true, index, indexKeyValue, 'key', multiCheck);
10088
- executeFetchIndexData.apply(void 0, [null].concat(_toConsumableArray(fetchArgs), [tx, null, function success(key) {
10216
+ executeFetchIndexData.apply(void 0, _toConsumableArray(fetchArgs).concat([tx, null, function success(key) {
10089
10217
  if (key === undefined) {
10090
10218
  setIndexInfo(index);
10091
10219
  resolve(undefined);
@@ -10176,6 +10304,7 @@
10176
10304
  _me$__validateKeyAndV2 = _slicedToArray(_me$__validateKeyAndV, 2),
10177
10305
  ky = _me$__validateKeyAndV2[0],
10178
10306
  clonedValue = _me$__validateKeyAndV2[1];
10307
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
10179
10308
  // @ts-ignore -- Private API
10180
10309
  IDBObjectStore.__storingRecordObjectStore(request, me, true, clonedValue, true, ky);
10181
10310
  return request;
@@ -10207,6 +10336,7 @@
10207
10336
  _me$__validateKeyAndV4 = _slicedToArray(_me$__validateKeyAndV3, 2),
10208
10337
  ky = _me$__validateKeyAndV4[0],
10209
10338
  clonedValue = _me$__validateKeyAndV4[1];
10339
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
10210
10340
  // @ts-ignore -- Private API
10211
10341
  IDBObjectStore.__storingRecordObjectStore(request, me, true, clonedValue, false, ky);
10212
10342
  return request;
@@ -10233,8 +10363,10 @@
10233
10363
  }
10234
10364
  cb(tx);
10235
10365
  }, function (tx, err) {
10366
+ /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
10236
10367
  error(err);
10237
10368
  return false;
10369
+ /* c8 ignore stop -- see comment above */
10238
10370
  });
10239
10371
  };
10240
10372
 
@@ -10343,16 +10475,20 @@
10343
10475
  return;
10344
10476
  }
10345
10477
  ret = getKey ? _decode(unescapeSQLiteResponse(/** @type {{key: string}} */data.rows.item(0).key), false) : decode(unescapeSQLiteResponse(/** @type {{value: string}} */data.rows.item(0).value));
10478
+ /* c8 ignore start -- Defensive: catches unexpected decode failures (e.g. corrupted stored data); not reliably reproducible via the public API since encode/decode are always paired and never write undecodable data. */
10346
10479
  } catch (e) {
10347
10480
  // If no result is returned, or error occurs when parsing JSON
10348
10481
  if (CFG.DEBUG) {
10349
10482
  console.log(e);
10350
10483
  }
10351
10484
  }
10485
+ /* c8 ignore stop -- see comment above */
10352
10486
  success(ret);
10353
10487
  }, function (tx, err) {
10488
+ /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
10354
10489
  error(err);
10355
10490
  return false;
10491
+ /* c8 ignore stop -- see comment above */
10356
10492
  });
10357
10493
  }, undefined, me);
10358
10494
  };
@@ -10464,8 +10600,10 @@
10464
10600
  });
10465
10601
  success();
10466
10602
  }, function (tx, err) {
10603
+ /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
10467
10604
  error(err);
10468
10605
  return false;
10606
+ /* c8 ignore stop -- see comment above */
10469
10607
  });
10470
10608
  }, undefined, me);
10471
10609
  };
@@ -10493,8 +10631,10 @@
10493
10631
  });
10494
10632
  success();
10495
10633
  }, function (tx, err) {
10634
+ /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
10496
10635
  error(err);
10497
10636
  return false;
10637
+ /* c8 ignore stop -- see comment above */
10498
10638
  });
10499
10639
  }, undefined, me);
10500
10640
  };
@@ -10829,7 +10969,7 @@
10829
10969
  if (keyPath !== null && !isValidKeyPath(keyPath)) {
10830
10970
  throw createDOMException('SyntaxError', 'The keyPath argument contains an invalid key path.');
10831
10971
  }
10832
- if (Object.hasOwn(this.__objectStores, storeName) && !this.__objectStores[storeName].__pendingDelete) {
10972
+ if (Object.hasOwn(this.__objectStores, storeName) && !this.__objectStores[storeName].__pendingDelete && !this.__objectStores[storeName].__deleted) {
10833
10973
  throw createDOMException('ConstraintError', 'Object store "' + storeName + '" already exists in ' + this.name);
10834
10974
  }
10835
10975
  var autoInc = createOptions.autoIncrement;
@@ -10978,7 +11118,6 @@
10978
11118
  }
10979
11119
  };
10980
11120
 
10981
- // Todo __forceClose: Add tests for `__forceClose`
10982
11121
  /**
10983
11122
  *
10984
11123
  * @param {string} msg
@@ -10987,23 +11126,39 @@
10987
11126
  */
10988
11127
  IDBDatabase.prototype.__forceClose = function (msg) {
10989
11128
  var me = this;
11129
+ // `close()` (below) resets `me.__transactions` to `[]`, so the
11130
+ // transactions to abort -- and the total count the completion check
11131
+ // below needs -- must be captured before calling it, not read back off
11132
+ // `me.__transactions` afterward.
11133
+ var transactions = me.__transactions;
10990
11134
  me.close();
11135
+
11136
+ /**
11137
+ * @returns {void}
11138
+ */
11139
+ function dispatchClose() {
11140
+ // Todo __forceClose: unblock any pending `upgradeneeded` or `deleteDatabase` calls
11141
+ var evt = createEvent('close');
11142
+ setTimeout(function () {
11143
+ me.dispatchEvent(evt);
11144
+ }, 0);
11145
+ }
11146
+ if (!transactions.length) {
11147
+ dispatchClose();
11148
+ return;
11149
+ }
10991
11150
  var ct = 0;
10992
- me.__transactions.forEach(function (trans) {
11151
+ transactions.forEach(function (trans) {
10993
11152
  // eslint-disable-next-line camelcase -- Clear API
10994
11153
  trans.on__abort = function () {
10995
11154
  ct++;
10996
- if (ct === me.__transactions.length) {
10997
- // Todo __forceClose: unblock any pending `upgradeneeded` or `deleteDatabase` calls
10998
- var evt = createEvent('close');
10999
- setTimeout(function () {
11000
- me.dispatchEvent(evt);
11001
- }, 0);
11155
+ if (ct !== transactions.length) {
11156
+ return;
11002
11157
  }
11158
+ dispatchClose();
11003
11159
  };
11004
11160
  trans.__abortTransaction(createDOMException('AbortError', 'The connection was force-closed: ' + (msg || '')));
11005
11161
  });
11006
- me.__transactions = [];
11007
11162
  };
11008
11163
  /* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
11009
11164
  defineOuterInterface(IDBDatabase.prototype, listeners);
@@ -11170,6 +11325,7 @@
11170
11325
  return undefined;
11171
11326
  }
11172
11327
  var e = /** @type {Event & IDBVersionChangeEvent} */
11328
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
11173
11329
  // @ts-ignore It's ok; needed under some TS versions
11174
11330
  new IDBVersionChangeEvent('versionchange', {
11175
11331
  oldVersion: oldVersion,
@@ -11217,6 +11373,7 @@
11217
11373
  }
11218
11374
  };
11219
11375
  var e = /** @type {Event & IDBVersionChangeEvent} */
11376
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
11220
11377
  // @ts-ignore It's ok; needed under some TS versions
11221
11378
  new IDBVersionChangeEvent('blocked', {
11222
11379
  oldVersion: oldVersion,
@@ -11277,6 +11434,13 @@
11277
11434
 
11278
11435
  /** @type {import('websql-configurable/lib/websql/WebSQLDatabase.js').default} */
11279
11436
  var sysdb;
11437
+ // Tracks which `CFG.memoryDatabase` value `sysdb` was opened against, so a
11438
+ // later change to that config (e.g. toggling in-memory mode on and back
11439
+ // off) causes `sysdb` to be recreated for the new setting rather than
11440
+ // staying pinned, forever, to whatever it was the first time any database
11441
+ // was created in the process.
11442
+ /** @type {string|null|undefined} */
11443
+ var sysdbMemoryDatabaseSetting;
11280
11444
  var nameCounter = 0;
11281
11445
 
11282
11446
  /**
@@ -11358,12 +11522,20 @@
11358
11522
  function cleanupDatabaseResources(__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError) {
11359
11523
  var useMemoryDatabase = typeof CFG.memoryDatabase === 'string';
11360
11524
  if (useMemoryDatabase) {
11525
+ /* c8 ignore start -- Defensive: only reachable if `websqlDBCache[name]`
11526
+ was initialized as an empty placeholder by `open()`'s connection-queue
11527
+ setup (`addRequestToConnectionQueue`, above `openDB`) but never
11528
+ populated with an actual instance -- e.g. `__openDatabase` throwing
11529
+ after a `dbVersions` row already existed for `name` from an earlier,
11530
+ successful `open()` -- or if `name` was never added to the cache at
11531
+ all. Not reachable via normal, non-tampered API usage. */
11361
11532
  var latestSQLiteDBCached = Object.hasOwn(websqlDBCache, name) ? getLatestCachedWebSQLDB(name) : null;
11362
11533
  if (!latestSQLiteDBCached) {
11363
11534
  console.warn('Could not find a memory database instance to delete.');
11364
11535
  databaseDeleted();
11365
11536
  return;
11366
11537
  }
11538
+ /* c8 ignore stop -- see comment above */
11367
11539
  var _sqliteDB = latestSQLiteDBCached._db;
11368
11540
  if (!_sqliteDB || !_sqliteDB.close) {
11369
11541
  console.error('The `openDatabase` implementation does not have the expected `._db.close` method for closing the database');
@@ -11417,15 +11589,24 @@
11417
11589
  tables.item(i).name)), [], function () {
11418
11590
  deleteTables(i + 1);
11419
11591
  }, function () {
11592
+ /* c8 ignore start -- Defensive: continues deleting the rest
11593
+ even if this specific store's table is already gone (e.g.
11594
+ duplicate `__sys__` rows for the same escaped table name, or
11595
+ external tampering); not reachable via normal API usage. */
11420
11596
  deleteTables(i + 1);
11421
11597
  return false;
11598
+ /* c8 ignore stop -- see comment above */
11422
11599
  });
11423
11600
  }
11424
11601
  })(0);
11425
11602
  }, function () {
11426
- // __sys__ table does not exist, but that does not mean delete did not happen
11603
+ /* c8 ignore start -- `__sys__` is always created by `openDB` before this
11604
+ database's `dbVersions` row (a prerequisite for reaching this code at
11605
+ all) is ever inserted; only reachable if the file was tampered with/
11606
+ removed externally afterward. */
11427
11607
  databaseDeleted();
11428
11608
  return false;
11609
+ /* c8 ignore stop -- see comment above */
11429
11610
  });
11430
11611
  });
11431
11612
  }
@@ -11456,9 +11637,11 @@
11456
11637
  }
11457
11638
  failure(er);
11458
11639
  }
11459
- if (sysdb) {
11640
+ if (sysdb && sysdbMemoryDatabaseSetting === CFG.memoryDatabase) {
11460
11641
  success();
11461
11642
  } else {
11643
+ // eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Needed
11644
+ sysdbMemoryDatabaseSetting = CFG.memoryDatabase;
11462
11645
  // eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Necessary?
11463
11646
  sysdb = __openDatabase(typeof CFG.memoryDatabase === 'string' ? CFG.memoryDatabase : joinPath(typeof CFG.sysDatabaseBasePath === 'string' ? CFG.sysDatabaseBasePath : CFG.databaseBasePath || '', '__sysdb__' + (CFG.addSQLiteExtension !== false ? '.sqlite' : '')), '1', 'System Database', CFG.DEFAULT_DB_SIZE);
11464
11647
  sysdb.transaction(function (systx) {
@@ -11638,6 +11821,17 @@
11638
11821
  * @returns {void}
11639
11822
  */
11640
11823
  var sysdbFinishedCb = function sysdbFinishedCb(systx, err, cb) {
11824
+ /* c8 ignore start -- This initial definition is always
11825
+ superseded before ever being invoked: the `sysdb.transaction(...)`
11826
+ call below always reaches its `nonstandardTransCb` (4th arg)
11827
+ after this same SQL batch finishes running (since `dbCreateError`
11828
+ always reports errors as "handled" and this call site is never
11829
+ a `readTransaction`), which unconditionally reassigns
11830
+ `sysdbFinishedCb` to a version using the library's own
11831
+ `rollback`/`commit` -- well before any real invocation from
11832
+ `on__beforecomplete`/`on__preabort`/`on__abort` below (those only
11833
+ fire once the upgrade transaction itself later completes/aborts).
11834
+ Kept as a defensive fallback in case that invariant ever changes. */
11641
11835
  if (err) {
11642
11836
  /**
11643
11837
  * @param {unknown} [errorToShow]
@@ -11686,6 +11880,7 @@
11686
11880
  }
11687
11881
  // In browser, should auto-commit
11688
11882
  cb(); // eslint-disable-line promise/no-callback-in-promise -- Convenient
11883
+ /* c8 ignore stop -- see comment above */
11689
11884
  };
11690
11885
  sysdb.transaction(function (systx) {
11691
11886
  /**
@@ -11693,6 +11888,7 @@
11693
11888
  */
11694
11889
  function versionSet() {
11695
11890
  var e = /** @type {import('eventtargeter').EventWithProps & Event & IDBVersionChangeEvent} */
11891
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
11696
11892
  // @ts-ignore It's ok; needed under some TS versions
11697
11893
  new IDBVersionChangeEvent('upgradeneeded', {
11698
11894
  oldVersion: oldVersion,
@@ -11818,9 +12014,17 @@
11818
12014
  // eslint-disable-next-line camelcase -- Clear API
11819
12015
  req.transaction.on__complete = function () {
11820
12016
  var pos = connection.__transactions.indexOf(req.transaction);
12017
+ // `req.transaction` (the versionchange transaction) is created
12018
+ // directly via `IDBTransaction.__createInstance` above, never
12019
+ // via `IDBDatabase.prototype.transaction()` (the only place
12020
+ // that pushes onto `connection.__transactions`), so `pos` is
12021
+ // always -1 here.
12022
+ /* c8 ignore start -- see comment above */
11821
12023
  if (pos !== -1) {
11822
12024
  connection.__transactions.splice(pos, 1);
11823
12025
  }
12026
+ /* c8 ignore stop -- see comment above */
12027
+
11824
12028
  if (/** @type {import('./IDBDatabase.js').IDBDatabaseFull} */req.__result.__closePending) {
11825
12029
  req.__transaction = null;
11826
12030
  var err = createDOMException('AbortError', 'The connection has been closed.');
@@ -11856,9 +12060,16 @@
11856
12060
  systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [version, sqlSafeName], versionSet, dbCreateError);
11857
12061
  }
11858
12062
  }, dbCreateError, undefined, function (currentTask, err, done, rollback, commit) {
12063
+ // Defensive fallback, not reachable in practice: same reasoning
12064
+ // as `deleteDatabase`'s own `nonstandardTransCb` below
12065
+ // (`currentTask.readOnly` is always false here, and
12066
+ // `dbCreateError` always returns `false`, so `err` is never
12067
+ // truthy either).
12068
+ /* c8 ignore start -- see comment above */
11859
12069
  if (currentTask.readOnly || err) {
11860
12070
  return true;
11861
12071
  }
12072
+ /* c8 ignore stop -- see comment above */
11862
12073
  sysdbFinishedCb = function sysdbFinishedCb(systx, err, cb) {
11863
12074
  if (err) {
11864
12075
  rollback(err,
@@ -11873,7 +12084,17 @@
11873
12084
  } else {
11874
12085
  systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [oldVersion, sqlSafeName]);
11875
12086
  }
11876
- }, function (sqlErr) {
12087
+ },
12088
+ // Deeply-nested defensive path: only reached if
12089
+ // the *revert* SQL (undoing the `dbVersions`
12090
+ // INSERT/UPDATE after the original version-
12091
+ // upgrade itself already failed) fails a
12092
+ // *second* time. Not feasibly triggerable
12093
+ // without fault-injecting the underlying SQL
12094
+ // driver on this specific, already-failing
12095
+ // revert statement.
12096
+ function (sqlErr) {
12097
+ /* c8 ignore next 2 -- see comment above */
11877
12098
  isRevertingSysdb = false;
11878
12099
  cb(sqlErr); // eslint-disable-line promise/no-callback-in-promise -- Convenient
11879
12100
  }, function () {
@@ -11889,8 +12110,20 @@
11889
12110
  });
11890
12111
  return undefined;
11891
12112
  }).catch(function (err) {
12113
+ /* c8 ignore start -- Purely defensive: nothing in
12114
+ `triggerAnyVersionChangeAndBlockedEvents`'s promise chain
12115
+ (or this `.then()` continuation above) ever rejects/throws
12116
+ under any reachable application-level condition -- all of
12117
+ its continuations resolve cleanly, and its `dispatchEvent`
12118
+ calls are deliberately fire-and-forget ("No need to catch
12119
+ errors"), running inside a `setTimeout` where a listener
12120
+ throwing becomes an uncaught exception in that macrotask
12121
+ rather than a promise rejection here. This exists solely
12122
+ to surface a truly-unexpected internal bug via the console
12123
+ before rethrowing, not to handle a real, testable error path. */
11892
12124
  console.log('Error within `triggerAnyVersionChangeAndBlockedEvents`');
11893
12125
  throw err;
12126
+ /* c8 ignore stop -- see comment above */
11894
12127
  });
11895
12128
  } else {
11896
12129
  finishRequest();
@@ -11918,11 +12151,19 @@
11918
12151
  if ((useMemoryDatabase || useDatabaseCache) && Object.hasOwn(websqlDBCache, name) && Object.hasOwn(websqlDBCache[name], version)) {
11919
12152
  db = websqlDBCache[name][version];
11920
12153
  } else {
11921
- db = /** @type {DatabaseFull} */me.__openDatabase(useMemoryDatabase ? CFG.memoryDatabase : joinPath(CFG.databaseBasePath || '', escapedDatabaseName), '1', name, CFG.DEFAULT_DB_SIZE);
12154
+ db = /** @type {DatabaseFull} */me.__openDatabase(useMemoryDatabase ? (/** @type {string} */CFG.memoryDatabase) : joinPath(CFG.databaseBasePath || '', escapedDatabaseName), '1', name, CFG.DEFAULT_DB_SIZE);
11922
12155
  if (useDatabaseCache) {
12156
+ /* c8 ignore start -- Defensive: by the time `openDB` runs,
12157
+ `websqlDBCache[name]` has always already been created by
12158
+ `addRequestToConnectionQueue`'s own callback above (guarded
12159
+ by this same `useDatabaseCache` condition), which always
12160
+ runs first and unconditionally ensures the entry exists
12161
+ before ever calling `openDB`. Kept as a safety net in case
12162
+ that invariant ever changes. */
11923
12163
  if (!Object.hasOwn(websqlDBCache, name)) {
11924
12164
  websqlDBCache[name] = {};
11925
12165
  }
12166
+ /* c8 ignore stop -- see comment above */
11926
12167
  websqlDBCache[name][version] = db;
11927
12168
  }
11928
12169
  }
@@ -12073,6 +12314,7 @@
12073
12314
  req.__result = undefined;
12074
12315
  req.__done = true;
12075
12316
  var e = /** @type {Event & IDBVersionChangeEvent} */
12317
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
12076
12318
  // @ts-ignore It's ok; needed under some TS versions
12077
12319
  new IDBVersionChangeEvent('success', {
12078
12320
  oldVersion: version,
@@ -12115,9 +12357,23 @@
12115
12357
  cleanupDatabaseResources(me.__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError);
12116
12358
  }, dbError);
12117
12359
  }, dbError, undefined, function (currentTask, err, done, rollback, commit) {
12360
+ /* c8 ignore start -- Defensive fallback, not reachable in
12361
+ practice: `currentTask.readOnly` is always `false` here
12362
+ (this callback is only ever attached to the writable
12363
+ `sysdb.transaction(...)` call above, never to a
12364
+ `sysdb.readTransaction(...)`), and `err` can only be
12365
+ truthy if the `DELETE FROM dbVersions` statement's own
12366
+ error callback (`dbError`) reports the failure back to
12367
+ `websql-configurable` as unhandled -- but `dbError`
12368
+ deliberately always `return`s `false`, which tells the
12369
+ library the error was already handled (and to keep
12370
+ `err` falsy here), precisely so this custom
12371
+ `sysdbFinishedCbDelete` rollback/commit path below is
12372
+ used instead of the library's own default rollback. */
12118
12373
  if (currentTask.readOnly || err) {
12119
12374
  return true;
12120
12375
  }
12376
+ /* c8 ignore stop -- see comment above */
12121
12377
  sysdbFinishedCbDelete = function sysdbFinishedCbDelete(err, cb) {
12122
12378
  if (err) {
12123
12379
  rollback(err, cb);
@@ -12243,10 +12499,9 @@
12243
12499
  };
12244
12500
 
12245
12501
  /**
12246
- * @todo forceClose: Test
12247
12502
  * This is provided to facilitate unit-testing of the
12248
12503
  * closing of a database connection with a forced flag:
12249
- * <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection>
12504
+ * <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection>.
12250
12505
  * @param {string} dbName
12251
12506
  * @param {Integer} connIdx
12252
12507
  * @param {string} msg
@@ -12347,6 +12602,7 @@
12347
12602
  * @this {IDBRecordFull}
12348
12603
  */
12349
12604
  function IDBRecord() {
12605
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
12350
12606
  // @ts-ignore Should be ok
12351
12607
  this[Symbol.toStringTag] = 'IDBRecord';
12352
12608
  this.__key = key;
@@ -12383,6 +12639,7 @@
12383
12639
  if (!(this instanceof IDBRecordAlias)) {
12384
12640
  throw new TypeError('Illegal invocation');
12385
12641
  }
12642
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
12386
12643
  // @ts-ignore `this` is a real instance past the check above (not an issue in TS7)
12387
12644
  return this['__' + prop];
12388
12645
  });
@@ -12725,6 +12982,7 @@
12725
12982
  success(undefined, undefined, undefined);
12726
12983
  }
12727
12984
  }, function (tx, err) {
12985
+ /* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
12728
12986
  if (CFG.DEBUG) {
12729
12987
  console.log('Could not execute Cursor.continue', sqlStr, sqlValues);
12730
12988
  }
@@ -12908,7 +13166,16 @@
12908
13166
  if (a.key > b.key) {
12909
13167
  return me.direction === 'prev' ? -1 : 1;
12910
13168
  }
13169
+ /* c8 ignore start -- Defensive: only reachable if two matches
13170
+ in the same batch shared both the same `matchingKey` and
13171
+ the same primary `key`, which would require the same
13172
+ record's multi-entry array to contain a duplicate value.
13173
+ `Key.js`'s array-to-key conversion already drops duplicate
13174
+ values when a multi-entry index entry is built, so this
13175
+ can never happen in practice; kept only to satisfy the
13176
+ `Array.prototype.sort` comparator contract. */
12911
13177
  return 0;
13178
+ /* c8 ignore stop -- see comment above */
12912
13179
  });
12913
13180
  me.__prefetchedIndex = 0;
12914
13181
  me.__prefetchedData = {
@@ -12927,13 +13194,19 @@
12927
13194
  console.log('[multiEntry] Preloaded ' + me.__prefetchedData.length + ' records for multiEntry cursor');
12928
13195
  }
12929
13196
  me.__decode(rows[0], success);
12930
- }, function (tx, err) {
13197
+ },
13198
+ /* c8 ignore start -- Defensive: guards against an unexpected SQLite
13199
+ execution error (e.g. I/O error, corruption) while querying for
13200
+ multi-entry cursor matches; not reliably reproducible without
13201
+ mocking the SQL layer. */
13202
+ function (tx, err) {
12931
13203
  if (CFG.DEBUG) {
12932
13204
  console.log('[multiEntry] Could not execute Cursor.continue', sqlStr, sqlValues);
12933
13205
  }
12934
13206
  error(err);
12935
13207
  return false;
12936
13208
  });
13209
+ /* c8 ignore stop -- see comment above */
12937
13210
  }
12938
13211
  runQuery();
12939
13212
  };
@@ -13042,6 +13315,7 @@
13042
13315
  * @returns {void}
13043
13316
  */
13044
13317
  IDBCursor.prototype.__invalidateCache = function () {
13318
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
13045
13319
  // @ts-ignore Why is this not being found?; needed under some TS versions
13046
13320
  this.__prefetchedData = null;
13047
13321
  this.__multiEntryExhausted = false;
@@ -13066,7 +13340,7 @@
13066
13340
  convertValueToKeyRethrowingAndIfInvalid(key);
13067
13341
  var cmpResult = cmp(key, me.key);
13068
13342
  if (cmpResult === 0 || me.direction.includes('next') && cmpResult === -1 || me.direction.includes('prev') && cmpResult === 1) {
13069
- throw createDOMException('DataError', 'Cannot ' + (advanceState ? 'advance' : 'continue') + ' the cursor in an unexpected direction');
13343
+ throw createDOMException('DataError', 'Cannot continue the cursor in an unexpected direction');
13070
13344
  }
13071
13345
  }
13072
13346
  this.__continueFinish(key, undefined, advanceState);
@@ -13323,6 +13597,7 @@
13323
13597
  // continuation logic in `__findBasic` to see this update's
13324
13598
  // effect on ordering (see "Modify records during cursor
13325
13599
  // iteration" in idbcursor_update_index.any.js).
13600
+ // eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
13326
13601
  // @ts-ignore -- API (not erring in TS 6)
13327
13602
  IDBObjectStore.__storingRecordObjectStore(request, me.__store, true, clonedValue, false, key);
13328
13603
  }
@@ -13372,14 +13647,33 @@
13372
13647
  // We don't invalidate the cache (as we don't access it anymore
13373
13648
  // and it will set the index off)
13374
13649
  success(undefined);
13650
+ /* c8 ignore start -- Defensive: `__find` (invoked just above) has
13651
+ already confirmed a row exists for this primary key within the
13652
+ same transaction queue, so `rowsAffected` should always be 1 in
13653
+ normal usage. This branch would only be reached if the underlying
13654
+ row were removed by another request queued in the same
13655
+ transaction between `__find`'s check and this DELETE actually
13656
+ running (e.g. deleting the same record directly via the object
13657
+ store while a cursor over it is mid-iteration); attempts to
13658
+ construct such a scenario instead trigger a transaction abort
13659
+ (`AbortError`) before this callback ever runs, since the default
13660
+ action of an unhandled request error is to abort the
13661
+ transaction. */
13375
13662
  } else {
13376
13663
  // @ts-expect-error Apparently ok
13377
13664
  error('No rows with key found' + key);
13378
13665
  }
13379
- }, function (tx, data) {
13666
+ /* c8 ignore stop -- see comment above */
13667
+ },
13668
+ /* c8 ignore start -- Defensive: guards against an unexpected SQLite
13669
+ execution error (e.g. I/O error, corruption) while deleting the
13670
+ current row; not reliably reproducible without mocking the SQL
13671
+ layer. */
13672
+ function (tx, data) {
13380
13673
  error(data);
13381
13674
  return false;
13382
13675
  });
13676
+ /* c8 ignore stop -- see comment above */
13383
13677
  }, error);
13384
13678
  }, undefined, me);
13385
13679
  };
@@ -13790,7 +14084,7 @@
13790
14084
  setConfig(initialConfig);
13791
14085
  }
13792
14086
  var IDB = /** @type {ShimmedObject & {[key: string]: unknown}} */
13793
- /** @type {unknown} */idb || globalThis || {};
14087
+ /** @type {unknown} */idb || globalThis;
13794
14088
  /**
13795
14089
  * @param {string} name
13796
14090
  * @param {unknown} value
@@ -13881,80 +14175,87 @@
13881
14175
  });
13882
14176
  }
13883
14177
  var shimIDBFactory = IDBFactory;
13884
- if (CFG.win.openDatabase !== undefined) {
13885
- shimIndexedDB.__openDatabase = CFG.win.openDatabase.bind(CFG.win); // We cache here in case the function is overwritten later as by the IndexedDB support promises tests
13886
- // Polyfill ALL of IndexedDB, using WebSQL
13887
- shim('indexedDB', shimIndexedDB, {
13888
- enumerable: true,
13889
- configurable: true,
13890
- get: function get() {
13891
- if (this !== IDB && !isNullish(this) && !this.shimNS) {
13892
- // Latter is hack for test environment
13893
- throw new TypeError('Illegal invocation');
13894
- }
13895
- return shimIndexedDB;
14178
+ if (CFG.win.openDatabase === undefined) {
14179
+ return;
14180
+ }
14181
+ shimIndexedDB.__openDatabase = CFG.win.openDatabase.bind(CFG.win); // We cache here in case the function is overwritten later as by the IndexedDB support promises tests
14182
+ // Polyfill ALL of IndexedDB, using WebSQL
14183
+ shim('indexedDB', shimIndexedDB, {
14184
+ enumerable: true,
14185
+ configurable: true,
14186
+ get: function get() {
14187
+ if (this !== IDB && !isNullish(this) && !this.shimNS) {
14188
+ // Latter is hack for test environment
14189
+ throw new TypeError('Illegal invocation');
13896
14190
  }
13897
- });
13898
- /** @type {[string, unknown][]} */
13899
- [['IDBFactory', shimIDBFactory], ['IDBDatabase', IDBDatabase], ['IDBObjectStore', IDBObjectStore], ['IDBIndex', IDBIndex], ['IDBTransaction', IDBTransaction], ['IDBCursor', IDBCursor], ['IDBCursorWithValue', IDBCursorWithValue], ['IDBRecord', IDBRecord], ['IDBKeyRange', IDBKeyRange], ['IDBRequest', IDBRequest], ['IDBOpenDBRequest', IDBOpenDBRequest], ['IDBVersionChangeEvent', IDBVersionChangeEvent]].forEach(function (_ref3) {
13900
- var _ref4 = _slicedToArray(_ref3, 2),
13901
- prop = _ref4[0],
13902
- obj = _ref4[1];
13903
- shim(prop, obj, {
13904
- enumerable: false,
13905
- configurable: true
13906
- });
13907
- });
13908
- // For Node environments
13909
- if (CFG.fs) {
13910
- setFS(CFG.fs);
14191
+ return shimIndexedDB;
13911
14192
  }
13912
- if (CFG.fullIDLSupport) {
13913
- // Slow per MDN so off by default! Though apparently needed for WebIDL: https://stackoverflow.com/questions/41927589/rationales-consequences-of-webidl-class-inheritance-requirements
13914
-
13915
- Object.setPrototypeOf(IDB.IDBOpenDBRequest, IDB.IDBRequest);
13916
- Object.setPrototypeOf(IDB.IDBCursorWithValue, IDB.IDBCursor);
13917
- Object.setPrototypeOf(IDBDatabase, EventTarget);
13918
- Object.setPrototypeOf(IDBRequest, EventTarget);
13919
- Object.setPrototypeOf(IDBTransaction, EventTarget);
13920
- Object.setPrototypeOf(IDBVersionChangeEvent, ShimEvent);
13921
- // `ShimDOMException` is the real native `DOMException` when one
13922
- // is available (see `DOMException.js`'s `useNativeDOMException`)
13923
- // -- which, unlike the shim classes above, is a single,
13924
- // process-wide singleton shared by reference across every
13925
- // sandbox this library gets installed into (see
13926
- // `node-idb-test.js`'s `sandboxObj`). A native `DOMException`
13927
- // already has the correct prototype chain out of the box
13928
- // (`Object.getPrototypeOf(DOMException) === Function.prototype`,
13929
- // not `Error`), so forcing it here isn't just unneeded but
13930
- // actively wrong -- and, because it's shared, permanently
13931
- // wrong for every later use of `DOMException` in the same
13932
- // process (e.g. a later WPT test file's own idlharness-style
13933
- // check that `DOMException` does *not* inherit from `Error`
13934
- // on the class side), not just this one shim install.
13935
- if (typeof DOMException === 'undefined' || ShimDOMException !== DOMException) {
13936
- Object.setPrototypeOf(ShimDOMException, Error);
13937
- Object.setPrototypeOf(ShimDOMException.prototype, Error.prototype);
13938
- }
14193
+ });
14194
+ /** @type {[string, unknown][]} */
14195
+ [['IDBFactory', shimIDBFactory], ['IDBDatabase', IDBDatabase], ['IDBObjectStore', IDBObjectStore], ['IDBIndex', IDBIndex], ['IDBTransaction', IDBTransaction], ['IDBCursor', IDBCursor], ['IDBCursorWithValue', IDBCursorWithValue], ['IDBRecord', IDBRecord], ['IDBKeyRange', IDBKeyRange], ['IDBRequest', IDBRequest], ['IDBOpenDBRequest', IDBOpenDBRequest], ['IDBVersionChangeEvent', IDBVersionChangeEvent]].forEach(function (_ref3) {
14196
+ var _ref4 = _slicedToArray(_ref3, 2),
14197
+ prop = _ref4[0],
14198
+ obj = _ref4[1];
14199
+ shim(prop, obj, {
14200
+ enumerable: false,
14201
+ configurable: true
14202
+ });
14203
+ });
14204
+ // For Node environments
14205
+ if (CFG.fs) {
14206
+ setFS(CFG.fs);
14207
+ }
14208
+ if (CFG.fullIDLSupport) {
14209
+ // Slow per MDN so off by default! Though apparently needed for WebIDL: https://stackoverflow.com/questions/41927589/rationales-consequences-of-webidl-class-inheritance-requirements
14210
+
14211
+ Object.setPrototypeOf(IDB.IDBOpenDBRequest, IDB.IDBRequest);
14212
+ Object.setPrototypeOf(IDB.IDBCursorWithValue, IDB.IDBCursor);
14213
+ Object.setPrototypeOf(IDBDatabase, EventTarget);
14214
+ Object.setPrototypeOf(IDBRequest, EventTarget);
14215
+ Object.setPrototypeOf(IDBTransaction, EventTarget);
14216
+ Object.setPrototypeOf(IDBVersionChangeEvent, ShimEvent);
14217
+ // `ShimDOMException` is the real native `DOMException` when one
14218
+ // is available (see `DOMException.js`'s `useNativeDOMException`)
14219
+ // -- which, unlike the shim classes above, is a single,
14220
+ // process-wide singleton shared by reference across every
14221
+ // sandbox this library gets installed into (see
14222
+ // `node-idb-test.js`'s `sandboxObj`). A native `DOMException`
14223
+ // already has the correct prototype chain out of the box
14224
+ // (`Object.getPrototypeOf(DOMException) === Function.prototype`,
14225
+ // not `Error`), so forcing it here isn't just unneeded but
14226
+ // actively wrong -- and, because it's shared, permanently
14227
+ // wrong for every later use of `DOMException` in the same
14228
+ // process (e.g. a later WPT test file's own idlharness-style
14229
+ // check that `DOMException` does *not* inherit from `Error`
14230
+ // on the class side), not just this one shim install.
14231
+ if (typeof DOMException === 'undefined' || ShimDOMException !== DOMException) {
14232
+ Object.setPrototypeOf(ShimDOMException, Error);
14233
+ Object.setPrototypeOf(ShimDOMException.prototype, Error.prototype);
13939
14234
  }
13940
- if (IDB.indexedDB && !IDB.indexedDB.toString().includes('[native code]')) {
13941
- if (CFG.addNonIDBGlobals) {
13942
- // As `DOMStringList` exists per IDL (and Chrome) in the global
13943
- // thread (but not in workers), we prefix the name to avoid
13944
- // shadowing or conflicts
13945
- setNonIDBGlobals('Shim');
13946
- }
13947
- if (CFG.replaceNonIDBGlobals) {
13948
- setNonIDBGlobals();
13949
- }
14235
+ }
14236
+ if (IDB.indexedDB && !IDB.indexedDB.toString().includes('[native code]')) {
14237
+ if (CFG.addNonIDBGlobals) {
14238
+ // As `DOMStringList` exists per IDL (and Chrome) in the global
14239
+ // thread (but not in workers), we prefix the name to avoid
14240
+ // shadowing or conflicts
14241
+ setNonIDBGlobals('Shim');
13950
14242
  }
13951
- /* c8 ignore start -- TS guard */
13952
- if (!IDB.shimIndexedDB) {
13953
- return;
14243
+ if (CFG.replaceNonIDBGlobals) {
14244
+ setNonIDBGlobals();
13954
14245
  }
13955
- /* c8 ignore stop -- TS guard */
13956
- IDB.shimIndexedDB.__setConnectionQueueOrigin();
13957
14246
  }
14247
+ /* c8 ignore start -- Defensive: `IDB.shimIndexedDB` was already
14248
+ confirmed truthy just before this function (`__useShim`) was
14249
+ defined and immediately invoked (see the `if ('shimIndexedDB'
14250
+ in IDB && IDB.shimIndexedDB)` guard above), and nothing in
14251
+ this function's body reassigns or deletes it. Only reachable
14252
+ if `IDB` is some unusual object (e.g. a Proxy) whose
14253
+ `shimIndexedDB` property value changes between reads. */
14254
+ if (!IDB.shimIndexedDB) {
14255
+ return;
14256
+ }
14257
+ /* c8 ignore stop -- see comment above */
14258
+ IDB.shimIndexedDB.__setConnectionQueueOrigin();
13958
14259
  };
13959
14260
  IDB.shimIndexedDB.__debug = /** @type {(val: boolean) => void} */function (val) {
13960
14261
  CFG.DEBUG = val;