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.
- package/badges/coverage-badge.svg +1 -1
- package/badges/tests-badge.svg +1 -1
- package/dist/CFG.d.ts +1 -1
- package/dist/CFG.d.ts.map +1 -1
- package/dist/DOMException.d.ts.map +1 -1
- package/dist/IDBCursor.d.ts.map +1 -1
- package/dist/IDBDatabase.d.ts.map +1 -1
- package/dist/IDBFactory.d.ts +1 -2
- package/dist/IDBFactory.d.ts.map +1 -1
- package/dist/IDBIndex.d.ts +2 -6
- package/dist/IDBIndex.d.ts.map +1 -1
- package/dist/IDBKeyRange.d.ts.map +1 -1
- package/dist/IDBObjectStore.d.ts.map +1 -1
- package/dist/IDBRecord.d.ts.map +1 -1
- package/dist/IDBRequest.d.ts.map +1 -1
- package/dist/IDBTransaction.d.ts.map +1 -1
- package/dist/Key.d.ts.map +1 -1
- package/dist/Sca.d.ts.map +1 -1
- package/dist/indexeddbshim-Key.js +40 -28
- package/dist/indexeddbshim-Key.js.map +1 -1
- package/dist/indexeddbshim-Key.min.js +2 -2
- package/dist/indexeddbshim-Key.min.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs +525 -225
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.js +553 -252
- package/dist/indexeddbshim-UnicodeIdentifiers.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js +3 -3
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js.map +1 -1
- package/dist/indexeddbshim-node.cjs +525 -225
- package/dist/indexeddbshim-node.cjs.map +1 -1
- package/dist/indexeddbshim-noninvasive.js +553 -252
- package/dist/indexeddbshim-noninvasive.js.map +1 -1
- package/dist/indexeddbshim-noninvasive.min.js +3 -3
- package/dist/indexeddbshim-noninvasive.min.js.map +1 -1
- package/dist/indexeddbshim.js +553 -252
- package/dist/indexeddbshim.js.map +1 -1
- package/dist/indexeddbshim.min.js +3 -3
- package/dist/indexeddbshim.min.js.map +1 -1
- package/dist/nodeWebSQL.d.ts.map +1 -1
- package/dist/setGlobalVars.d.ts +1 -1
- package/dist/setGlobalVars.d.ts.map +1 -1
- package/dist/util.d.ts.map +1 -1
- package/package.json +22 -17
- package/src/CFG.js +18 -4
- package/src/DOMException.js +6 -0
- package/src/DOMStringList.js +3 -0
- package/src/IDBCursor.js +36 -3
- package/src/IDBDatabase.js +26 -10
- package/src/IDBFactory.js +105 -5
- package/src/IDBIndex.js +49 -32
- package/src/IDBKeyRange.js +8 -7
- package/src/IDBObjectStore.js +25 -2
- package/src/IDBRecord.js +2 -0
- package/src/IDBRequest.js +7 -4
- package/src/IDBTransaction.js +111 -34
- package/src/Key.js +17 -16
- package/src/Sca.js +9 -4
- package/src/nodeWebSQL.js +1 -0
- package/src/setGlobalVars.js +86 -77
- package/src/util.js +5 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! indexeddbshim - v19.0.
|
|
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
|
-
}
|
|
502
|
+
}
|
|
503
|
+
/* c8 ignore stop */ : DOMException;
|
|
502
504
|
|
|
503
|
-
/** @type {WeakMap<object,
|
|
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
|
|
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 {
|
|
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')
|
|
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
|
-
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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
|
-
*
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
}) ||
|
|
4201
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
5660
|
-
//
|
|
5661
|
-
|
|
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
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
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
|
-
*
|
|
5869
|
-
*
|
|
5870
|
-
*
|
|
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(
|
|
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(
|
|
5998
|
+
checkQueueEntry(keepAliveAttempts);
|
|
5943
5999
|
return;
|
|
5944
6000
|
}
|
|
5945
6001
|
keepAliveAndWait(function () {
|
|
5946
|
-
if (
|
|
5947
|
-
|
|
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
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
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.
|
|
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 ?
|
|
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
|
|
8429
|
-
|
|
8430
|
-
var
|
|
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
|
-
|
|
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,
|
|
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'
|
|
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 &&
|
|
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(
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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(
|
|
9420
|
+
function executeFetchIndexData(unboundedDisallowed, index, hasKey, range, opType, multiChecks, sql, sqlValues, tx, args, success, error) {
|
|
9318
9421
|
if (unboundedDisallowed) {
|
|
9319
|
-
|
|
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
|
-
|
|
9361
|
-
|
|
9362
|
-
|
|
9363
|
-
|
|
9364
|
-
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
9378
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
|
10997
|
-
|
|
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
|
-
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
|
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
|
-
|
|
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
|
|
13885
|
-
|
|
13886
|
-
|
|
13887
|
-
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
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
|
-
|
|
13913
|
-
|
|
13914
|
-
|
|
13915
|
-
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
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
|
-
|
|
13941
|
-
|
|
13942
|
-
|
|
13943
|
-
|
|
13944
|
-
|
|
13945
|
-
|
|
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
|
-
|
|
13952
|
-
|
|
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;
|