indexeddbshim 19.0.5 → 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 +511 -217
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.js +539 -244
- 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 +511 -217
- package/dist/indexeddbshim-node.cjs.map +1 -1
- package/dist/indexeddbshim-noninvasive.js +539 -244
- 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 +539 -244
- 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 +97 -26
- 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
|
|
@@ -5651,6 +5672,7 @@
|
|
|
5651
5672
|
queueMicrotask(cb);
|
|
5652
5673
|
return;
|
|
5653
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. */
|
|
5654
5676
|
try {
|
|
5655
5677
|
tx.executeSql('SELECT 1', [], function () {
|
|
5656
5678
|
cb();
|
|
@@ -5664,6 +5686,7 @@
|
|
|
5664
5686
|
// abort the transaction here.
|
|
5665
5687
|
me.__abortTransaction(/** @type {Error|DOMException} */err);
|
|
5666
5688
|
}
|
|
5689
|
+
/* c8 ignore stop -- see comment above */
|
|
5667
5690
|
}
|
|
5668
5691
|
|
|
5669
5692
|
/**
|
|
@@ -5676,21 +5699,26 @@
|
|
|
5676
5699
|
* @returns {void}
|
|
5677
5700
|
*/
|
|
5678
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. */
|
|
5679
5703
|
if (me.__errored || me.__requestsFinished) {
|
|
5680
5704
|
// We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
|
|
5681
5705
|
return;
|
|
5682
5706
|
}
|
|
5707
|
+
/* c8 ignore stop -- see comment above */
|
|
5683
5708
|
if (req) {
|
|
5684
5709
|
q.req = req; // Need to do this in case of cursors
|
|
5685
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. */
|
|
5686
5712
|
if (!q.req) {
|
|
5687
|
-
// TS guard
|
|
5688
5713
|
return;
|
|
5689
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. */
|
|
5690
5717
|
if (q.req.__done) {
|
|
5691
5718
|
// Avoid continuing with aborted requests
|
|
5692
5719
|
return;
|
|
5693
5720
|
}
|
|
5721
|
+
/* c8 ignore stop -- see comment above */
|
|
5694
5722
|
q.req.__done = true;
|
|
5695
5723
|
q.req.__result = result;
|
|
5696
5724
|
q.req.__error = null;
|
|
@@ -5707,6 +5735,7 @@
|
|
|
5707
5735
|
// is what actually resets `__handlerActive`, once it's
|
|
5708
5736
|
// confirmed (across its own bounded microtask wait) that no
|
|
5709
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. */
|
|
5710
5739
|
if (e.__legacyOutputDidListenersThrowError) {
|
|
5711
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
|
|
5712
5741
|
if (!me.__committed) {
|
|
@@ -5716,6 +5745,7 @@
|
|
|
5716
5745
|
return;
|
|
5717
5746
|
}
|
|
5718
5747
|
}
|
|
5748
|
+
/* c8 ignore stop -- see comment above */
|
|
5719
5749
|
runContinuationSafely(advanceAfterDispatch);
|
|
5720
5750
|
}
|
|
5721
5751
|
|
|
@@ -5727,15 +5757,19 @@
|
|
|
5727
5757
|
* @returns {void}
|
|
5728
5758
|
*/
|
|
5729
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. */
|
|
5730
5761
|
if (me.__errored || me.__requestsFinished) {
|
|
5731
5762
|
// We've already called "onerror", "onabort", or thrown within
|
|
5732
5763
|
// the transaction, so don't do it again.
|
|
5733
5764
|
return;
|
|
5734
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. */
|
|
5735
5768
|
if (q.req && q.req.__done) {
|
|
5736
5769
|
// Avoid continuing with aborted requests
|
|
5737
5770
|
return;
|
|
5738
5771
|
}
|
|
5772
|
+
/* c8 ignore stop -- see comment above */
|
|
5739
5773
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
5740
5774
|
args[_key] = arguments[_key];
|
|
5741
5775
|
}
|
|
@@ -5760,10 +5794,11 @@
|
|
|
5760
5794
|
}
|
|
5761
5795
|
});
|
|
5762
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. */
|
|
5763
5798
|
if (!q.req) {
|
|
5764
|
-
// TS guard
|
|
5765
5799
|
return;
|
|
5766
5800
|
}
|
|
5801
|
+
/* c8 ignore stop -- see comment above */
|
|
5767
5802
|
me.__abortTransaction(q.req.__error);
|
|
5768
5803
|
});
|
|
5769
5804
|
me.__active = true;
|
|
@@ -5775,16 +5810,19 @@
|
|
|
5775
5810
|
q.req.dispatchEvent(e);
|
|
5776
5811
|
// Do not set __active or __handlerActive flags to false yet --
|
|
5777
5812
|
// see the matching comment in `success`, above.
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
if (me.__committed) {
|
|
5782
|
-
// An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
|
|
5783
|
-
runContinuationSafely(advanceAfterDispatch);
|
|
5784
|
-
return;
|
|
5785
|
-
}
|
|
5786
|
-
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;
|
|
5787
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 */
|
|
5788
5826
|
}
|
|
5789
5827
|
|
|
5790
5828
|
/**
|
|
@@ -5808,10 +5846,12 @@
|
|
|
5808
5846
|
// (not reset here).
|
|
5809
5847
|
return true;
|
|
5810
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. */
|
|
5811
5850
|
if (q.req.__done) {
|
|
5812
5851
|
// Avoid continuing with aborted requests
|
|
5813
5852
|
return false;
|
|
5814
5853
|
}
|
|
5854
|
+
/* c8 ignore stop -- see comment above */
|
|
5815
5855
|
// We're now handing off to (possibly async) work for
|
|
5816
5856
|
// this request, so the transaction is no longer active
|
|
5817
5857
|
// until its own `success`/`error` dispatch (below)
|
|
@@ -5836,18 +5876,22 @@
|
|
|
5836
5876
|
return;
|
|
5837
5877
|
}
|
|
5838
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. */
|
|
5839
5880
|
} catch (e) {
|
|
5840
5881
|
error(/** @type {Error} */e);
|
|
5841
5882
|
}
|
|
5883
|
+
/* c8 ignore stop -- see comment above */
|
|
5842
5884
|
}
|
|
5843
5885
|
|
|
5844
5886
|
/**
|
|
5845
5887
|
* @returns {void}
|
|
5846
5888
|
*/
|
|
5847
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). */
|
|
5848
5891
|
if (!prepareNextRequest()) {
|
|
5849
5892
|
return;
|
|
5850
5893
|
}
|
|
5894
|
+
/* c8 ignore stop -- see comment above */
|
|
5851
5895
|
launchQueuedOp();
|
|
5852
5896
|
}
|
|
5853
5897
|
|
|
@@ -5878,9 +5922,11 @@
|
|
|
5878
5922
|
* @returns {void}
|
|
5879
5923
|
*/
|
|
5880
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. */
|
|
5881
5926
|
if (me.__errored || me.__requestsFinished) {
|
|
5882
5927
|
return;
|
|
5883
5928
|
}
|
|
5929
|
+
/* c8 ignore stop -- see comment above */
|
|
5884
5930
|
if (i < me.__requests.length) {
|
|
5885
5931
|
runQueuedRequest();
|
|
5886
5932
|
return;
|
|
@@ -5902,10 +5948,12 @@
|
|
|
5902
5948
|
* @returns {void}
|
|
5903
5949
|
*/
|
|
5904
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. */
|
|
5905
5952
|
if (me.__errored || me.__requestsFinished) {
|
|
5906
5953
|
// We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
|
|
5907
5954
|
return;
|
|
5908
5955
|
}
|
|
5956
|
+
/* c8 ignore stop -- see comment above */
|
|
5909
5957
|
i++;
|
|
5910
5958
|
if (i >= me.__requests.length) {
|
|
5911
5959
|
checkQueueEntry(keepAliveAttempts);
|
|
@@ -5940,31 +5988,34 @@
|
|
|
5940
5988
|
* @returns {void}
|
|
5941
5989
|
*/
|
|
5942
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. */
|
|
5943
5992
|
if (me.__errored || me.__requestsFinished) {
|
|
5944
5993
|
return;
|
|
5945
5994
|
}
|
|
5995
|
+
/* c8 ignore stop -- see comment above */
|
|
5946
5996
|
i++;
|
|
5947
5997
|
if (i >= me.__requests.length) {
|
|
5948
5998
|
checkQueueEntry(keepAliveAttempts);
|
|
5949
5999
|
return;
|
|
5950
6000
|
}
|
|
5951
6001
|
keepAliveAndWait(function () {
|
|
5952
|
-
if (
|
|
5953
|
-
|
|
5954
|
-
}
|
|
5955
|
-
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()) {
|
|
5956
6004
|
return;
|
|
5957
6005
|
}
|
|
6006
|
+
/* c8 ignore stop -- see comment above */
|
|
5958
6007
|
launchQueuedOp();
|
|
5959
6008
|
});
|
|
5960
6009
|
}
|
|
5961
6010
|
executeNextRequest();
|
|
5962
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. */
|
|
5963
6013
|
// @ts-expect-error It's ok
|
|
5964
6014
|
if (webSQLErr === true) {
|
|
5965
6015
|
// Not a genuine SQL error
|
|
5966
6016
|
return;
|
|
5967
6017
|
}
|
|
6018
|
+
/* c8 ignore stop -- see comment above */
|
|
5968
6019
|
var err = webSQLErrback(/** @type {Error & {code?: number}} */webSQLErr);
|
|
5969
6020
|
me.__abortTransaction(err);
|
|
5970
6021
|
}, function () {
|
|
@@ -5975,18 +6026,25 @@
|
|
|
5975
6026
|
// Node
|
|
5976
6027
|
return;
|
|
5977
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. */
|
|
5978
6030
|
if (!me.__transactionEndCallback && !me.__requestsFinished) {
|
|
5979
6031
|
me.__transactionFinished = true;
|
|
5980
6032
|
return;
|
|
5981
6033
|
}
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
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;
|
|
5985
6038
|
}
|
|
6039
|
+
me.__transFinishedCbFired = true;
|
|
6040
|
+
me.__transFinishedCb(me.__errored, me.__transactionEndCallback);
|
|
6041
|
+
/* c8 ignore stop -- see comment above */
|
|
5986
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. */
|
|
5987
6044
|
if (err) {
|
|
5988
6045
|
return true;
|
|
5989
6046
|
}
|
|
6047
|
+
/* c8 ignore stop -- see comment above */
|
|
5990
6048
|
// `readonly` transactions never hold a real SQL transaction open
|
|
5991
6049
|
// (see `WebSQLTransaction`'s constructor skipping `BEGIN;` for
|
|
5992
6050
|
// them), so there's no commit/rollback round trip to defer --
|
|
@@ -6035,6 +6093,7 @@
|
|
|
6035
6093
|
*/
|
|
6036
6094
|
function complete() {
|
|
6037
6095
|
me.__completed = true;
|
|
6096
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
6038
6097
|
if (CFG.DEBUG) {
|
|
6039
6098
|
console.log('Transaction completed');
|
|
6040
6099
|
}
|
|
@@ -6044,6 +6103,7 @@
|
|
|
6044
6103
|
me.dispatchEvent(evt);
|
|
6045
6104
|
me.__internal = false;
|
|
6046
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. */
|
|
6047
6107
|
} catch (e) {
|
|
6048
6108
|
me.__internal = false;
|
|
6049
6109
|
// An error occurred in the "oncomplete" handler.
|
|
@@ -6051,6 +6111,7 @@
|
|
|
6051
6111
|
// (this may seem odd/bad, but it's how all native IndexedDB implementations work)
|
|
6052
6112
|
me.__errored = true;
|
|
6053
6113
|
throw e;
|
|
6114
|
+
/* c8 ignore stop -- see comment above */
|
|
6054
6115
|
} finally {
|
|
6055
6116
|
activeTransactions.delete(me);
|
|
6056
6117
|
me.__storeHandles = {};
|
|
@@ -6058,10 +6119,12 @@
|
|
|
6058
6119
|
}
|
|
6059
6120
|
}
|
|
6060
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. */
|
|
6061
6123
|
if (me.__transactionFinished) {
|
|
6062
6124
|
complete();
|
|
6063
6125
|
return;
|
|
6064
6126
|
}
|
|
6127
|
+
/* c8 ignore stop -- see comment above */
|
|
6065
6128
|
me.__transactionEndCallback = complete;
|
|
6066
6129
|
// The underlying SQL driver's own "queue empty" check
|
|
6067
6130
|
// (`nonstandardTransCb`, above) typically already ran and
|
|
@@ -6097,6 +6160,7 @@
|
|
|
6097
6160
|
IDBTransaction.prototype.__createRequest = function (source) {
|
|
6098
6161
|
var me = this;
|
|
6099
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. */
|
|
6100
6164
|
request.__source = source !== undefined ? source : me.db;
|
|
6101
6165
|
request.__transaction = me;
|
|
6102
6166
|
return request;
|
|
@@ -6166,9 +6230,11 @@
|
|
|
6166
6230
|
* @returns {void}
|
|
6167
6231
|
*/
|
|
6168
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. */
|
|
6169
6234
|
if (!this.__active || !this.__handlerActive || this.__committed) {
|
|
6170
6235
|
throw createDOMException('TransactionInactiveError', 'A request was placed against a transaction which is currently not active, or which is finished');
|
|
6171
6236
|
}
|
|
6237
|
+
/* c8 ignore stop -- see comment above */
|
|
6172
6238
|
};
|
|
6173
6239
|
|
|
6174
6240
|
/**
|
|
@@ -6182,6 +6248,7 @@
|
|
|
6182
6248
|
}
|
|
6183
6249
|
};
|
|
6184
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. */
|
|
6185
6252
|
/**
|
|
6186
6253
|
* @this {IDBTransactionFull}
|
|
6187
6254
|
* @returns {void}
|
|
@@ -6189,6 +6256,7 @@
|
|
|
6189
6256
|
IDBTransaction.prototype.__assertVersionChange = function () {
|
|
6190
6257
|
IDBTransaction.__assertVersionChange(this);
|
|
6191
6258
|
};
|
|
6259
|
+
/* c8 ignore stop -- see comment above */
|
|
6192
6260
|
|
|
6193
6261
|
/**
|
|
6194
6262
|
* Returns the specified object store.
|
|
@@ -6210,9 +6278,12 @@
|
|
|
6210
6278
|
throw createDOMException('NotFoundError', objectStoreName + ' is not participating in this transaction');
|
|
6211
6279
|
}
|
|
6212
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. */
|
|
6213
6282
|
if (!store) {
|
|
6214
6283
|
throw createDOMException('NotFoundError', objectStoreName + ' does not exist in ' + me.db.name);
|
|
6215
6284
|
}
|
|
6285
|
+
/* c8 ignore stop -- see comment above */
|
|
6286
|
+
|
|
6216
6287
|
if (!Object.hasOwn(me.__storeHandles, objectStoreName) ||
|
|
6217
6288
|
// These latter conditions are to allow store
|
|
6218
6289
|
// recreation to create new clone object
|
|
@@ -6231,10 +6302,12 @@
|
|
|
6231
6302
|
IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
6232
6303
|
var me = this;
|
|
6233
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. */
|
|
6234
6306
|
if (me.__errored) {
|
|
6235
6307
|
// We've already called "onerror", "onabort", or thrown, so don't do it again.
|
|
6236
6308
|
return;
|
|
6237
6309
|
}
|
|
6310
|
+
/* c8 ignore stop -- see comment above */
|
|
6238
6311
|
me.__errored = true;
|
|
6239
6312
|
if (me.mode === 'versionchange') {
|
|
6240
6313
|
// Steps for aborting an upgrade transaction
|
|
@@ -6264,19 +6337,16 @@
|
|
|
6264
6337
|
if (err !== null) {
|
|
6265
6338
|
me.__error = err;
|
|
6266
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. */
|
|
6267
6342
|
if (me.__requestsFinished && err !== null) {
|
|
6268
6343
|
// The transaction has already completed, so we can't call "onerror" or "onabort".
|
|
6269
|
-
// So throw the error instead.
|
|
6270
|
-
// `IDBTransaction.prototype.abort`'s own `__abortTransaction(null)`
|
|
6271
|
-
// call, which now checks `__requestsFinished` itself first and
|
|
6272
|
-
// throws `InvalidStateError` synchronously before ever reaching
|
|
6273
|
-
// this point -- so this guard is just defense in depth against
|
|
6274
|
-
// `err` somehow being `null` some other way, not something this
|
|
6275
|
-
// path should see in practice.
|
|
6344
|
+
// So throw the error instead.
|
|
6276
6345
|
setTimeout(function () {
|
|
6277
6346
|
throw err;
|
|
6278
6347
|
}, 0);
|
|
6279
6348
|
}
|
|
6349
|
+
/* c8 ignore stop -- see comment above */
|
|
6280
6350
|
|
|
6281
6351
|
/**
|
|
6282
6352
|
* @param {import('websql-configurable/lib/websql/WebSQLTransaction.js').default|null} [tx]
|
|
@@ -6285,13 +6355,17 @@
|
|
|
6285
6355
|
*/
|
|
6286
6356
|
function abort(tx, errOrResult) {
|
|
6287
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. */
|
|
6288
6359
|
if (CFG.DEBUG) {
|
|
6289
6360
|
console.log('Rollback not possible due to missing transaction', me);
|
|
6290
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. */
|
|
6291
6363
|
} else if (errOrResult && 'code' in errOrResult && typeof errOrResult.code === 'number') {
|
|
6292
6364
|
if (CFG.DEBUG) {
|
|
6293
6365
|
console.log('Rollback erred; feature is probably not supported as per WebSQL', me);
|
|
6294
6366
|
}
|
|
6367
|
+
/* c8 ignore stop -- see comment above */
|
|
6368
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
6295
6369
|
} else if (CFG.DEBUG) {
|
|
6296
6370
|
console.log('Rollback succeeded', me);
|
|
6297
6371
|
}
|
|
@@ -6307,10 +6381,11 @@
|
|
|
6307
6381
|
// behaves first-in-first-out with the same timeout so we could
|
|
6308
6382
|
// just use a `forEach`.
|
|
6309
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. */
|
|
6310
6385
|
if (!q.req) {
|
|
6311
|
-
// TS guard
|
|
6312
6386
|
throw new Error('Missing request');
|
|
6313
6387
|
}
|
|
6388
|
+
/* c8 ignore stop -- see comment above */
|
|
6314
6389
|
q.req.__done = true;
|
|
6315
6390
|
q.req.__result = undefined;
|
|
6316
6391
|
q.req.__error = createDOMException('AbortError', 'A request was aborted (an unfinished request).');
|
|
@@ -6321,10 +6396,11 @@
|
|
|
6321
6396
|
return new SyncPromise(/** @type {(resolve: (value?: unknown) => void) => void} */
|
|
6322
6397
|
function (resolve) {
|
|
6323
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. */
|
|
6324
6400
|
if (!q.req) {
|
|
6325
|
-
// TS guard
|
|
6326
6401
|
throw new Error('Missing request');
|
|
6327
6402
|
}
|
|
6403
|
+
/* c8 ignore stop -- see comment above */
|
|
6328
6404
|
q.req.dispatchEvent(reqEvt); // No need to catch errors
|
|
6329
6405
|
resolve();
|
|
6330
6406
|
}, 0);
|
|
@@ -6344,10 +6420,12 @@
|
|
|
6344
6420
|
releaseFinishedTransaction(me);
|
|
6345
6421
|
}, 0);
|
|
6346
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. */
|
|
6347
6424
|
}).catch(function (err) {
|
|
6348
6425
|
console.log('Abort error');
|
|
6349
6426
|
throw err;
|
|
6350
6427
|
});
|
|
6428
|
+
/* c8 ignore stop -- see comment above */
|
|
6351
6429
|
}
|
|
6352
6430
|
me.__transFinishedCb(true, function (rollback) {
|
|
6353
6431
|
if (rollback && me.__tx) {
|
|
@@ -6355,20 +6433,24 @@
|
|
|
6355
6433
|
// rollback automatically), but for Node.js, etc., we give chance for
|
|
6356
6434
|
// manual aborts which would otherwise not work.
|
|
6357
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. */
|
|
6358
6437
|
if (me.__transactionFinished) {
|
|
6359
6438
|
abort();
|
|
6360
6439
|
return;
|
|
6361
6440
|
}
|
|
6441
|
+
/* c8 ignore stop -- see comment above */
|
|
6362
6442
|
me.__transactionEndCallback = abort;
|
|
6363
6443
|
return;
|
|
6364
6444
|
}
|
|
6365
6445
|
try {
|
|
6366
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. */
|
|
6367
6448
|
} catch (err) {
|
|
6368
6449
|
// Browser errs when transaction has ended and since it most likely already erred here,
|
|
6369
6450
|
// we call to abort
|
|
6370
6451
|
abort();
|
|
6371
6452
|
}
|
|
6453
|
+
/* c8 ignore stop -- see comment above */
|
|
6372
6454
|
} else {
|
|
6373
6455
|
abort(null, {
|
|
6374
6456
|
code: 0
|
|
@@ -6386,6 +6468,7 @@
|
|
|
6386
6468
|
if (!(me instanceof IDBTransaction)) {
|
|
6387
6469
|
throw new TypeError('Illegal invocation');
|
|
6388
6470
|
}
|
|
6471
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
6389
6472
|
if (CFG.DEBUG) {
|
|
6390
6473
|
console.log('The transaction was aborted', me);
|
|
6391
6474
|
}
|
|
@@ -6417,6 +6500,7 @@
|
|
|
6417
6500
|
if (!me.__active || !me.__handlerActive || me.__committed) {
|
|
6418
6501
|
throw createDOMException('InvalidStateError', 'Failed to execute \'commit\' on \'IDBTransaction\': The transaction is not active.');
|
|
6419
6502
|
}
|
|
6503
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
6420
6504
|
if (CFG.DEBUG) {
|
|
6421
6505
|
console.log('The transaction was explicitly committed', me);
|
|
6422
6506
|
}
|
|
@@ -6459,6 +6543,7 @@
|
|
|
6459
6543
|
};
|
|
6460
6544
|
|
|
6461
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. */
|
|
6462
6547
|
/**
|
|
6463
6548
|
*
|
|
6464
6549
|
* @param {IDBTransactionFull} tx
|
|
@@ -6474,6 +6559,7 @@
|
|
|
6474
6559
|
throw err;
|
|
6475
6560
|
}
|
|
6476
6561
|
};
|
|
6562
|
+
/* c8 ignore stop -- see comment above */
|
|
6477
6563
|
|
|
6478
6564
|
/**
|
|
6479
6565
|
*
|
|
@@ -7571,7 +7657,7 @@
|
|
|
7571
7657
|
return Number.isNaN(t) ? "NaN" : t;
|
|
7572
7658
|
},
|
|
7573
7659
|
revive: function revive(e) {
|
|
7574
|
-
return "NaN" === e ?
|
|
7660
|
+
return new Date("NaN" === e ? NaN : e);
|
|
7575
7661
|
}
|
|
7576
7662
|
}
|
|
7577
7663
|
},
|
|
@@ -8431,9 +8517,12 @@
|
|
|
8431
8517
|
}).find(function (preset) {
|
|
8432
8518
|
return preset && !Array.isArray(preset) && 'filelist' in preset;
|
|
8433
8519
|
});
|
|
8434
|
-
var origFileList = specSet && !Array.isArray(specSet) && 'filelist' in specSet ? specSet.filelist
|
|
8435
|
-
|
|
8436
|
-
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;
|
|
8437
8526
|
var customFileList = origFileList ? _objectSpread2(_objectSpread2({}, origFileList), {}, {
|
|
8438
8527
|
/**
|
|
8439
8528
|
* @param {unknown} x
|
|
@@ -8441,10 +8530,7 @@
|
|
|
8441
8530
|
* @returns {boolean}
|
|
8442
8531
|
*/
|
|
8443
8532
|
test: function test(x, state) {
|
|
8444
|
-
|
|
8445
|
-
return x instanceof FileList;
|
|
8446
|
-
}
|
|
8447
|
-
return typeof origTest === 'function' ? origTest(x, state) : false;
|
|
8533
|
+
return typeof FileList !== 'undefined' ? x instanceof FileList : typeof origTest === 'function' && origTest(x, state);
|
|
8448
8534
|
},
|
|
8449
8535
|
/**
|
|
8450
8536
|
* @param {unknown} x
|
|
@@ -8455,10 +8541,12 @@
|
|
|
8455
8541
|
if (typeof FileList !== 'undefined') {
|
|
8456
8542
|
return Reflect.construct(FileList, [x]);
|
|
8457
8543
|
}
|
|
8544
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.revive` ever goes missing */
|
|
8458
8545
|
return typeof origRevive === 'function' ? origRevive(x, state) : undefined;
|
|
8459
8546
|
}
|
|
8460
|
-
}) : undefined;
|
|
8461
|
-
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 ? {
|
|
8462
8550
|
filelist: customFileList
|
|
8463
8551
|
} : {}]);
|
|
8464
8552
|
|
|
@@ -8614,7 +8702,6 @@
|
|
|
8614
8702
|
* __unique: boolean,
|
|
8615
8703
|
* __objectStore: import('./IDBObjectStore.js').IDBObjectStoreFull,
|
|
8616
8704
|
* __keyPath: import('./Key.js').KeyPath,
|
|
8617
|
-
* __recreated?: boolean,
|
|
8618
8705
|
* __fetchIndexData: (
|
|
8619
8706
|
* range: Query,
|
|
8620
8707
|
* opType: "value"|"key"|"count",
|
|
@@ -8708,6 +8795,7 @@
|
|
|
8708
8795
|
storeHandle.__indexHandles[newName] = oldIndexHandle; // Ensure new reference accessible
|
|
8709
8796
|
me.__pendingName = oldName;
|
|
8710
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
|
|
8711
8799
|
// @ts-ignore Has numeric indexes instead of iterator; needed under some TS versions
|
|
8712
8800
|
_toConsumableArray(objectStore.indexNames).filter(function (indexName) {
|
|
8713
8801
|
return indexName !== newName;
|
|
@@ -8759,7 +8847,7 @@
|
|
|
8759
8847
|
}
|
|
8760
8848
|
});
|
|
8761
8849
|
/** @type {const} */
|
|
8762
|
-
['__pendingCreate', '__pendingDelete', '__deleted', '__originalName'
|
|
8850
|
+
['__pendingCreate', '__pendingDelete', '__deleted', '__originalName'].forEach(function (p) {
|
|
8763
8851
|
// @ts-expect-error Why is this type "never"?
|
|
8764
8852
|
idx[p] = index[p];
|
|
8765
8853
|
});
|
|
@@ -8791,11 +8879,12 @@
|
|
|
8791
8879
|
var transaction = store.transaction;
|
|
8792
8880
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
8793
8881
|
transaction.__addNonRequestToTransactionQueue(function createIndex(tx, args, success, failure) {
|
|
8794
|
-
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
|
|
8795
8883
|
|
|
8796
8884
|
/** @type {{[key: string]: boolean}} */
|
|
8797
8885
|
var indexValues = {};
|
|
8798
8886
|
|
|
8887
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8799
8888
|
/**
|
|
8800
8889
|
* @param {WebSQLTransaction} tx
|
|
8801
8890
|
* @param {(Error & {code?: number})} err
|
|
@@ -8804,6 +8893,7 @@
|
|
|
8804
8893
|
function error(tx, err) {
|
|
8805
8894
|
failure(createDOMException('UnknownError', 'Could not create index "' + indexName + '"' + err.code + '::' + err.message, err));
|
|
8806
8895
|
}
|
|
8896
|
+
/* c8 ignore stop -- see comment above */
|
|
8807
8897
|
|
|
8808
8898
|
/**
|
|
8809
8899
|
* @param {WebSQLTransaction} tx
|
|
@@ -8853,12 +8943,6 @@
|
|
|
8853
8943
|
} else {
|
|
8854
8944
|
delete index.__pendingCreate;
|
|
8855
8945
|
delete indexHandle.__pendingCreate;
|
|
8856
|
-
if (index.__deleted) {
|
|
8857
|
-
delete index.__deleted;
|
|
8858
|
-
delete indexHandle.__deleted;
|
|
8859
|
-
index.__recreated = true;
|
|
8860
|
-
indexHandle.__recreated = true;
|
|
8861
|
-
}
|
|
8862
8946
|
indexValues = {};
|
|
8863
8947
|
success(store);
|
|
8864
8948
|
}
|
|
@@ -8867,7 +8951,7 @@
|
|
|
8867
8951
|
}, /** @type {SqlErrorCallback} */error);
|
|
8868
8952
|
}
|
|
8869
8953
|
var escapedStoreNameSQL = escapeStoreNameForSQL(storeName);
|
|
8870
|
-
var escapedIndexNameSQL = escapeIndexNameForSQL(
|
|
8954
|
+
var escapedIndexNameSQL = escapeIndexNameForSQL(indexName);
|
|
8871
8955
|
|
|
8872
8956
|
/**
|
|
8873
8957
|
* @param {WebSQLTransaction} tx
|
|
@@ -8919,6 +9003,7 @@
|
|
|
8919
9003
|
var transaction = store.transaction;
|
|
8920
9004
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
8921
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. */
|
|
8922
9007
|
/**
|
|
8923
9008
|
* @param {WebSQLTransaction} tx
|
|
8924
9009
|
* @param {(Error & {code?: number})} err
|
|
@@ -8927,6 +9012,7 @@
|
|
|
8927
9012
|
function error(tx, err) {
|
|
8928
9013
|
failure(createDOMException('UnknownError', 'Could not delete index "' + index.name + '"', err));
|
|
8929
9014
|
}
|
|
9015
|
+
/* c8 ignore stop -- see comment above */
|
|
8930
9016
|
|
|
8931
9017
|
/**
|
|
8932
9018
|
* @returns {void}
|
|
@@ -8935,7 +9021,6 @@
|
|
|
8935
9021
|
// Update the object store's index list
|
|
8936
9022
|
IDBIndex.__updateIndexList(store, tx, function (store) {
|
|
8937
9023
|
delete index.__pendingDelete;
|
|
8938
|
-
delete index.__recreated;
|
|
8939
9024
|
index.__deleted = true;
|
|
8940
9025
|
if (indexHandle) {
|
|
8941
9026
|
indexHandle.__deleted = true;
|
|
@@ -8996,20 +9081,18 @@
|
|
|
8996
9081
|
* @param {Query} range
|
|
8997
9082
|
* @param {"value"|"key"|"count"} opType
|
|
8998
9083
|
* @param {boolean} nullDisallowed
|
|
8999
|
-
* @param {number} [count]
|
|
9000
9084
|
* @this {IDBIndexFull}
|
|
9001
9085
|
* @returns {import('./IDBRequest.js').IDBRequestFull}
|
|
9002
9086
|
*/
|
|
9003
|
-
IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed
|
|
9087
|
+
IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed) {
|
|
9004
9088
|
var me = this;
|
|
9005
|
-
if (count !== undefined) {
|
|
9006
|
-
count = enforceRange(count, 'unsigned long');
|
|
9007
|
-
}
|
|
9008
9089
|
IDBIndex.__invalidStateIfDeleted(me);
|
|
9009
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. */
|
|
9010
9092
|
if (me.objectStore.__deleted) {
|
|
9011
9093
|
throw createDOMException('InvalidStateError', "This index's object store has been deleted");
|
|
9012
9094
|
}
|
|
9095
|
+
/* c8 ignore stop -- see comment above */
|
|
9013
9096
|
IDBTransaction.__assertActive(me.objectStore.transaction);
|
|
9014
9097
|
if (nullDisallowed && isNullish(range)) {
|
|
9015
9098
|
throw createDOMException('DataError', 'No key or range was specified');
|
|
@@ -9019,7 +9102,7 @@
|
|
|
9019
9102
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
9020
9103
|
args[_key] = arguments[_key];
|
|
9021
9104
|
}
|
|
9022
|
-
executeFetchIndexData.apply(void 0,
|
|
9105
|
+
executeFetchIndexData.apply(void 0, _toConsumableArray(fetchArgs).concat(args));
|
|
9023
9106
|
}, undefined, me);
|
|
9024
9107
|
};
|
|
9025
9108
|
|
|
@@ -9178,13 +9261,16 @@
|
|
|
9178
9261
|
var colInfoToPreserve = colInfoToPreserveArr.map(function (colInfo) {
|
|
9179
9262
|
return colInfo.join(' ');
|
|
9180
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. */
|
|
9181
9265
|
var listColInfoToPreserve = colInfoToPreserve.length ? colInfoToPreserve.join(', ') + ', ' : '';
|
|
9266
|
+
/* c8 ignore next -- Defensive: see comment above. */
|
|
9182
9267
|
var listColsToPreserve = colNamesToPreserve.length ? colNamesToPreserve.join(', ') + ', ' : '';
|
|
9183
9268
|
|
|
9184
9269
|
// We could adapt the approach at https://stackoverflow.com/a/8430746/271577
|
|
9185
9270
|
// to make the approach reusable without passing column names, but it is a bit fragile
|
|
9186
9271
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
9187
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. */
|
|
9188
9274
|
/**
|
|
9189
9275
|
* @param {WebSQLTransaction} tx
|
|
9190
9276
|
* @param {(Error & {code?: number})} err
|
|
@@ -9193,6 +9279,7 @@
|
|
|
9193
9279
|
function sqlError(tx, err) {
|
|
9194
9280
|
error(err);
|
|
9195
9281
|
}
|
|
9282
|
+
/* c8 ignore stop -- see comment above */
|
|
9196
9283
|
/**
|
|
9197
9284
|
* @returns {void}
|
|
9198
9285
|
*/
|
|
@@ -9201,8 +9288,14 @@
|
|
|
9201
9288
|
cb(tx, success);
|
|
9202
9289
|
return;
|
|
9203
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. */
|
|
9204
9292
|
success();
|
|
9205
9293
|
}
|
|
9294
|
+
/* c8 ignore stop -- see comment above */
|
|
9295
|
+
if (!CFG.useSQLiteIndexes) {
|
|
9296
|
+
finish();
|
|
9297
|
+
return;
|
|
9298
|
+
}
|
|
9206
9299
|
// See https://www.sqlite.org/lang_altertable.html#otheralter
|
|
9207
9300
|
// We don't query for indexes as we already have the info
|
|
9208
9301
|
// This approach has the advantage of auto-deleting indexes via the DROP TABLE
|
|
@@ -9226,10 +9319,6 @@
|
|
|
9226
9319
|
console.log(sql);
|
|
9227
9320
|
}
|
|
9228
9321
|
tx.executeSql(sql, [], function (tx) {
|
|
9229
|
-
if (!CFG.useSQLiteIndexes) {
|
|
9230
|
-
finish();
|
|
9231
|
-
return;
|
|
9232
|
-
}
|
|
9233
9322
|
var indexCreations = colNamesToPreserve.slice(2) // Doing `key` separately and no need for index on `value`
|
|
9234
9323
|
.map(function (escapedIndexNameSQL) {
|
|
9235
9324
|
return new SyncPromise(function (resolve, reject) {
|
|
@@ -9238,13 +9327,16 @@
|
|
|
9238
9327
|
// if (CFG.DEBUG) { console.log(sql); }
|
|
9239
9328
|
// tx.executeSql(sql, [], function () {
|
|
9240
9329
|
var sql = 'CREATE INDEX ' + escapedIndexToRecreate + ' ON ' + escapedStoreNameSQL + '(' + escapedIndexNameSQL + ')';
|
|
9330
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
9241
9331
|
if (CFG.DEBUG) {
|
|
9242
9332
|
console.log(sql);
|
|
9243
9333
|
}
|
|
9244
|
-
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} */
|
|
9245
9336
|
function (tx, err) {
|
|
9246
9337
|
reject(err);
|
|
9247
|
-
}
|
|
9338
|
+
}
|
|
9339
|
+
/* c8 ignore stop -- see comment above */);
|
|
9248
9340
|
// }, function (tx, err) {
|
|
9249
9341
|
// reject(err);
|
|
9250
9342
|
// });
|
|
@@ -9262,19 +9354,25 @@
|
|
|
9262
9354
|
if (CFG.DEBUG) {
|
|
9263
9355
|
console.log(sql);
|
|
9264
9356
|
}
|
|
9265
|
-
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} */
|
|
9266
9359
|
function (tx, err) {
|
|
9267
9360
|
reject(err);
|
|
9268
|
-
}
|
|
9269
|
-
|
|
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} */
|
|
9270
9365
|
function (tx, err) {
|
|
9271
9366
|
reject(err);
|
|
9272
|
-
}
|
|
9367
|
+
}
|
|
9368
|
+
/* c8 ignore stop -- see comment above */);
|
|
9273
9369
|
}));
|
|
9274
9370
|
SyncPromise.all(indexCreations).then(finish).catch(/** @type {(reason: unknown) => PromiseLike<never>} */
|
|
9275
9371
|
error).catch(function (err) {
|
|
9372
|
+
/* c8 ignore start -- Defensive: only reached if `finish` or the outer `error` callback itself throws; not reliably reproducible. */
|
|
9276
9373
|
console.log('Index rename error');
|
|
9277
9374
|
throw err;
|
|
9375
|
+
/* c8 ignore stop -- see comment above */
|
|
9278
9376
|
});
|
|
9279
9377
|
}, /** @type {SqlErrorCallback} */sqlError);
|
|
9280
9378
|
}, /** @type {SqlErrorCallback} */sqlError);
|
|
@@ -9303,7 +9401,6 @@
|
|
|
9303
9401
|
/* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
|
|
9304
9402
|
|
|
9305
9403
|
/**
|
|
9306
|
-
* @param {number|null} count
|
|
9307
9404
|
* @param {boolean} unboundedDisallowed
|
|
9308
9405
|
* @param {IDBIndexFull} index
|
|
9309
9406
|
* @param {boolean} hasKey
|
|
@@ -9320,12 +9417,9 @@
|
|
|
9320
9417
|
* @param {(tx: WebSQLTransaction, err: (Error & {code?: number})) => void} error
|
|
9321
9418
|
* @returns {void}
|
|
9322
9419
|
*/
|
|
9323
|
-
function executeFetchIndexData(
|
|
9420
|
+
function executeFetchIndexData(unboundedDisallowed, index, hasKey, range, opType, multiChecks, sql, sqlValues, tx, args, success, error) {
|
|
9324
9421
|
if (unboundedDisallowed) {
|
|
9325
|
-
|
|
9326
|
-
}
|
|
9327
|
-
if (count) {
|
|
9328
|
-
sql.push('LIMIT', String(count));
|
|
9422
|
+
sql.push('LIMIT', '1');
|
|
9329
9423
|
}
|
|
9330
9424
|
var isCount = opType === 'count';
|
|
9331
9425
|
if (CFG.DEBUG) {
|
|
@@ -9363,41 +9457,48 @@
|
|
|
9363
9457
|
var escapedIndexNameForKeyCol = escapeIndexNameForSQLKeyColumn(index.name);
|
|
9364
9458
|
var encodedKey = _encode(range, index.multiEntry);
|
|
9365
9459
|
var _loop = function _loop() {
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
|
|
9381
|
-
|
|
9382
|
-
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
record = row;
|
|
9386
|
-
} else if (!hasKey && !multiChecks) {
|
|
9387
|
-
if (rowKey !== undefined) {
|
|
9388
|
-
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++;
|
|
9389
9479
|
record = row;
|
|
9480
|
+
} else if (!hasKey && !multiChecks) {
|
|
9481
|
+
if (rowKey !== undefined) {
|
|
9482
|
+
recordCount += Array.isArray(rowKey) ? rowKey.length : 1;
|
|
9483
|
+
record = row;
|
|
9484
|
+
}
|
|
9390
9485
|
}
|
|
9391
|
-
|
|
9392
|
-
|
|
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
|
+
|
|
9393
9492
|
records.push(decode$1(record));
|
|
9394
9493
|
if (unboundedDisallowed) {
|
|
9395
9494
|
return 1; // break
|
|
9396
9495
|
}
|
|
9397
|
-
}
|
|
9398
|
-
|
|
9496
|
+
},
|
|
9497
|
+
_ret;
|
|
9399
9498
|
for (var i = 0; i < data.rows.length; i++) {
|
|
9400
|
-
|
|
9499
|
+
_ret = _loop();
|
|
9500
|
+
if (_ret === 0) continue;
|
|
9501
|
+
if (_ret === 1) break;
|
|
9401
9502
|
}
|
|
9402
9503
|
} else {
|
|
9403
9504
|
for (var _i = 0; _i < data.rows.length; _i++) {
|
|
@@ -9411,8 +9512,16 @@
|
|
|
9411
9512
|
if (isCount) {
|
|
9412
9513
|
success(recordCount);
|
|
9413
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 */
|
|
9414
9521
|
success(unboundedDisallowed ? undefined : []);
|
|
9415
9522
|
} else {
|
|
9523
|
+
// `unboundedDisallowed` is always `true` here; see comment above.
|
|
9524
|
+
/* c8 ignore next -- see comment above */
|
|
9416
9525
|
success(unboundedDisallowed ? records[0] : records);
|
|
9417
9526
|
}
|
|
9418
9527
|
}, /** @type {SqlErrorCallback} */error);
|
|
@@ -9656,6 +9765,7 @@
|
|
|
9656
9765
|
tx.executeSql(sql, sqlValues, function (tx) {
|
|
9657
9766
|
// This SQL preserves indexes per https://www.sqlite.org/lang_altertable.html
|
|
9658
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. */
|
|
9659
9769
|
if (CFG.DEBUG) {
|
|
9660
9770
|
console.log(sql);
|
|
9661
9771
|
}
|
|
@@ -9664,8 +9774,10 @@
|
|
|
9664
9774
|
success();
|
|
9665
9775
|
});
|
|
9666
9776
|
}, function (tx, err) {
|
|
9777
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9667
9778
|
error(err);
|
|
9668
9779
|
return false;
|
|
9780
|
+
/* c8 ignore stop -- see comment above */
|
|
9669
9781
|
});
|
|
9670
9782
|
});
|
|
9671
9783
|
}
|
|
@@ -9739,6 +9851,7 @@
|
|
|
9739
9851
|
storeHandles[storeName] = IDBObjectStore.__clone(store, transaction);
|
|
9740
9852
|
}
|
|
9741
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. */
|
|
9742
9855
|
/**
|
|
9743
9856
|
* @param {WebSQLTransaction} tx
|
|
9744
9857
|
* @param {(Error & {code?: number})} [err]
|
|
@@ -9751,6 +9864,8 @@
|
|
|
9751
9864
|
failure(createDOMException('UnknownError', 'Could not create object store "' + storeName + '"', err));
|
|
9752
9865
|
return false;
|
|
9753
9866
|
}
|
|
9867
|
+
/* c8 ignore stop -- see comment above */
|
|
9868
|
+
|
|
9754
9869
|
var escapedStoreNameSQL = escapeStoreNameForSQL(storeName);
|
|
9755
9870
|
// key INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE
|
|
9756
9871
|
var sql = ['CREATE TABLE', escapedStoreNameSQL, '(key BLOB', store.autoIncrement ? 'UNIQUE, inc INTEGER PRIMARY KEY AUTOINCREMENT' : 'PRIMARY KEY', ', value BLOB)'].join(' ');
|
|
@@ -9805,6 +9920,7 @@
|
|
|
9805
9920
|
|
|
9806
9921
|
// Remove the object store from WebSQL
|
|
9807
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. */
|
|
9808
9924
|
/**
|
|
9809
9925
|
* @param {WebSQLTransaction} tx
|
|
9810
9926
|
* @param {(Error & {code?: number})} [err]
|
|
@@ -9817,6 +9933,8 @@
|
|
|
9817
9933
|
failure(createDOMException('UnknownError', 'Could not delete ObjectStore', err));
|
|
9818
9934
|
return false;
|
|
9819
9935
|
}
|
|
9936
|
+
/* c8 ignore stop -- see comment above */
|
|
9937
|
+
|
|
9820
9938
|
tx.executeSql('SELECT "name" FROM __sys__ WHERE "name" = ?', [escapeSQLiteStatement(store.__currentName)], function (tx, data) {
|
|
9821
9939
|
if (data.rows.length > 0) {
|
|
9822
9940
|
tx.executeSql('DROP TABLE ' + escapeStoreNameForSQL(store.__currentName), [], function () {
|
|
@@ -9996,13 +10114,15 @@
|
|
|
9996
10114
|
return;
|
|
9997
10115
|
}
|
|
9998
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. */
|
|
9999
10118
|
if (indexKeyValue === undefined) {
|
|
10000
10119
|
resolve(undefined);
|
|
10001
10120
|
return;
|
|
10002
10121
|
}
|
|
10122
|
+
/* c8 ignore stop -- see comment above */
|
|
10003
10123
|
var multiCheck = index.multiEntry && Array.isArray(indexKeyValue);
|
|
10004
10124
|
var fetchArgs = buildFetchIndexDataSQL(true, index, indexKeyValue, 'key', multiCheck);
|
|
10005
|
-
executeFetchIndexData.apply(void 0,
|
|
10125
|
+
executeFetchIndexData.apply(void 0, _toConsumableArray(fetchArgs).concat([tx, null, function success(key) {
|
|
10006
10126
|
if (key === undefined || excludeKey !== undefined && cmp(/** @type {import('./Key.js').Key} */key, excludeKey) === 0) {
|
|
10007
10127
|
resolve(undefined);
|
|
10008
10128
|
return;
|
|
@@ -10082,16 +10202,18 @@
|
|
|
10082
10202
|
* @returns {void}
|
|
10083
10203
|
*/
|
|
10084
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. */
|
|
10085
10206
|
if (indexKeyValue === undefined) {
|
|
10086
10207
|
return;
|
|
10087
10208
|
}
|
|
10209
|
+
/* c8 ignore stop -- see comment above */
|
|
10088
10210
|
paramMap[index.__currentName] = /** @type {string} */
|
|
10089
10211
|
_encode(indexKeyValue, index.multiEntry);
|
|
10090
10212
|
}
|
|
10091
10213
|
if (index.unique) {
|
|
10092
10214
|
var multiCheck = index.multiEntry && Array.isArray(indexKeyValue);
|
|
10093
10215
|
var fetchArgs = buildFetchIndexDataSQL(true, index, indexKeyValue, 'key', multiCheck);
|
|
10094
|
-
executeFetchIndexData.apply(void 0,
|
|
10216
|
+
executeFetchIndexData.apply(void 0, _toConsumableArray(fetchArgs).concat([tx, null, function success(key) {
|
|
10095
10217
|
if (key === undefined) {
|
|
10096
10218
|
setIndexInfo(index);
|
|
10097
10219
|
resolve(undefined);
|
|
@@ -10182,6 +10304,7 @@
|
|
|
10182
10304
|
_me$__validateKeyAndV2 = _slicedToArray(_me$__validateKeyAndV, 2),
|
|
10183
10305
|
ky = _me$__validateKeyAndV2[0],
|
|
10184
10306
|
clonedValue = _me$__validateKeyAndV2[1];
|
|
10307
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
10185
10308
|
// @ts-ignore -- Private API
|
|
10186
10309
|
IDBObjectStore.__storingRecordObjectStore(request, me, true, clonedValue, true, ky);
|
|
10187
10310
|
return request;
|
|
@@ -10213,6 +10336,7 @@
|
|
|
10213
10336
|
_me$__validateKeyAndV4 = _slicedToArray(_me$__validateKeyAndV3, 2),
|
|
10214
10337
|
ky = _me$__validateKeyAndV4[0],
|
|
10215
10338
|
clonedValue = _me$__validateKeyAndV4[1];
|
|
10339
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
10216
10340
|
// @ts-ignore -- Private API
|
|
10217
10341
|
IDBObjectStore.__storingRecordObjectStore(request, me, true, clonedValue, false, ky);
|
|
10218
10342
|
return request;
|
|
@@ -10239,8 +10363,10 @@
|
|
|
10239
10363
|
}
|
|
10240
10364
|
cb(tx);
|
|
10241
10365
|
}, function (tx, err) {
|
|
10366
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
10242
10367
|
error(err);
|
|
10243
10368
|
return false;
|
|
10369
|
+
/* c8 ignore stop -- see comment above */
|
|
10244
10370
|
});
|
|
10245
10371
|
};
|
|
10246
10372
|
|
|
@@ -10349,16 +10475,20 @@
|
|
|
10349
10475
|
return;
|
|
10350
10476
|
}
|
|
10351
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. */
|
|
10352
10479
|
} catch (e) {
|
|
10353
10480
|
// If no result is returned, or error occurs when parsing JSON
|
|
10354
10481
|
if (CFG.DEBUG) {
|
|
10355
10482
|
console.log(e);
|
|
10356
10483
|
}
|
|
10357
10484
|
}
|
|
10485
|
+
/* c8 ignore stop -- see comment above */
|
|
10358
10486
|
success(ret);
|
|
10359
10487
|
}, function (tx, err) {
|
|
10488
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
10360
10489
|
error(err);
|
|
10361
10490
|
return false;
|
|
10491
|
+
/* c8 ignore stop -- see comment above */
|
|
10362
10492
|
});
|
|
10363
10493
|
}, undefined, me);
|
|
10364
10494
|
};
|
|
@@ -10470,8 +10600,10 @@
|
|
|
10470
10600
|
});
|
|
10471
10601
|
success();
|
|
10472
10602
|
}, function (tx, err) {
|
|
10603
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
10473
10604
|
error(err);
|
|
10474
10605
|
return false;
|
|
10606
|
+
/* c8 ignore stop -- see comment above */
|
|
10475
10607
|
});
|
|
10476
10608
|
}, undefined, me);
|
|
10477
10609
|
};
|
|
@@ -10499,8 +10631,10 @@
|
|
|
10499
10631
|
});
|
|
10500
10632
|
success();
|
|
10501
10633
|
}, function (tx, err) {
|
|
10634
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
10502
10635
|
error(err);
|
|
10503
10636
|
return false;
|
|
10637
|
+
/* c8 ignore stop -- see comment above */
|
|
10504
10638
|
});
|
|
10505
10639
|
}, undefined, me);
|
|
10506
10640
|
};
|
|
@@ -10835,7 +10969,7 @@
|
|
|
10835
10969
|
if (keyPath !== null && !isValidKeyPath(keyPath)) {
|
|
10836
10970
|
throw createDOMException('SyntaxError', 'The keyPath argument contains an invalid key path.');
|
|
10837
10971
|
}
|
|
10838
|
-
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) {
|
|
10839
10973
|
throw createDOMException('ConstraintError', 'Object store "' + storeName + '" already exists in ' + this.name);
|
|
10840
10974
|
}
|
|
10841
10975
|
var autoInc = createOptions.autoIncrement;
|
|
@@ -10984,7 +11118,6 @@
|
|
|
10984
11118
|
}
|
|
10985
11119
|
};
|
|
10986
11120
|
|
|
10987
|
-
// Todo __forceClose: Add tests for `__forceClose`
|
|
10988
11121
|
/**
|
|
10989
11122
|
*
|
|
10990
11123
|
* @param {string} msg
|
|
@@ -10993,23 +11126,39 @@
|
|
|
10993
11126
|
*/
|
|
10994
11127
|
IDBDatabase.prototype.__forceClose = function (msg) {
|
|
10995
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;
|
|
10996
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
|
+
}
|
|
10997
11150
|
var ct = 0;
|
|
10998
|
-
|
|
11151
|
+
transactions.forEach(function (trans) {
|
|
10999
11152
|
// eslint-disable-next-line camelcase -- Clear API
|
|
11000
11153
|
trans.on__abort = function () {
|
|
11001
11154
|
ct++;
|
|
11002
|
-
if (ct
|
|
11003
|
-
|
|
11004
|
-
var evt = createEvent('close');
|
|
11005
|
-
setTimeout(function () {
|
|
11006
|
-
me.dispatchEvent(evt);
|
|
11007
|
-
}, 0);
|
|
11155
|
+
if (ct !== transactions.length) {
|
|
11156
|
+
return;
|
|
11008
11157
|
}
|
|
11158
|
+
dispatchClose();
|
|
11009
11159
|
};
|
|
11010
11160
|
trans.__abortTransaction(createDOMException('AbortError', 'The connection was force-closed: ' + (msg || '')));
|
|
11011
11161
|
});
|
|
11012
|
-
me.__transactions = [];
|
|
11013
11162
|
};
|
|
11014
11163
|
/* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
|
|
11015
11164
|
defineOuterInterface(IDBDatabase.prototype, listeners);
|
|
@@ -11176,6 +11325,7 @@
|
|
|
11176
11325
|
return undefined;
|
|
11177
11326
|
}
|
|
11178
11327
|
var e = /** @type {Event & IDBVersionChangeEvent} */
|
|
11328
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11179
11329
|
// @ts-ignore It's ok; needed under some TS versions
|
|
11180
11330
|
new IDBVersionChangeEvent('versionchange', {
|
|
11181
11331
|
oldVersion: oldVersion,
|
|
@@ -11223,6 +11373,7 @@
|
|
|
11223
11373
|
}
|
|
11224
11374
|
};
|
|
11225
11375
|
var e = /** @type {Event & IDBVersionChangeEvent} */
|
|
11376
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11226
11377
|
// @ts-ignore It's ok; needed under some TS versions
|
|
11227
11378
|
new IDBVersionChangeEvent('blocked', {
|
|
11228
11379
|
oldVersion: oldVersion,
|
|
@@ -11283,6 +11434,13 @@
|
|
|
11283
11434
|
|
|
11284
11435
|
/** @type {import('websql-configurable/lib/websql/WebSQLDatabase.js').default} */
|
|
11285
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;
|
|
11286
11444
|
var nameCounter = 0;
|
|
11287
11445
|
|
|
11288
11446
|
/**
|
|
@@ -11364,12 +11522,20 @@
|
|
|
11364
11522
|
function cleanupDatabaseResources(__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError) {
|
|
11365
11523
|
var useMemoryDatabase = typeof CFG.memoryDatabase === 'string';
|
|
11366
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. */
|
|
11367
11532
|
var latestSQLiteDBCached = Object.hasOwn(websqlDBCache, name) ? getLatestCachedWebSQLDB(name) : null;
|
|
11368
11533
|
if (!latestSQLiteDBCached) {
|
|
11369
11534
|
console.warn('Could not find a memory database instance to delete.');
|
|
11370
11535
|
databaseDeleted();
|
|
11371
11536
|
return;
|
|
11372
11537
|
}
|
|
11538
|
+
/* c8 ignore stop -- see comment above */
|
|
11373
11539
|
var _sqliteDB = latestSQLiteDBCached._db;
|
|
11374
11540
|
if (!_sqliteDB || !_sqliteDB.close) {
|
|
11375
11541
|
console.error('The `openDatabase` implementation does not have the expected `._db.close` method for closing the database');
|
|
@@ -11423,15 +11589,24 @@
|
|
|
11423
11589
|
tables.item(i).name)), [], function () {
|
|
11424
11590
|
deleteTables(i + 1);
|
|
11425
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. */
|
|
11426
11596
|
deleteTables(i + 1);
|
|
11427
11597
|
return false;
|
|
11598
|
+
/* c8 ignore stop -- see comment above */
|
|
11428
11599
|
});
|
|
11429
11600
|
}
|
|
11430
11601
|
})(0);
|
|
11431
11602
|
}, function () {
|
|
11432
|
-
|
|
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. */
|
|
11433
11607
|
databaseDeleted();
|
|
11434
11608
|
return false;
|
|
11609
|
+
/* c8 ignore stop -- see comment above */
|
|
11435
11610
|
});
|
|
11436
11611
|
});
|
|
11437
11612
|
}
|
|
@@ -11462,9 +11637,11 @@
|
|
|
11462
11637
|
}
|
|
11463
11638
|
failure(er);
|
|
11464
11639
|
}
|
|
11465
|
-
if (sysdb) {
|
|
11640
|
+
if (sysdb && sysdbMemoryDatabaseSetting === CFG.memoryDatabase) {
|
|
11466
11641
|
success();
|
|
11467
11642
|
} else {
|
|
11643
|
+
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Needed
|
|
11644
|
+
sysdbMemoryDatabaseSetting = CFG.memoryDatabase;
|
|
11468
11645
|
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Necessary?
|
|
11469
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);
|
|
11470
11647
|
sysdb.transaction(function (systx) {
|
|
@@ -11644,6 +11821,17 @@
|
|
|
11644
11821
|
* @returns {void}
|
|
11645
11822
|
*/
|
|
11646
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. */
|
|
11647
11835
|
if (err) {
|
|
11648
11836
|
/**
|
|
11649
11837
|
* @param {unknown} [errorToShow]
|
|
@@ -11692,6 +11880,7 @@
|
|
|
11692
11880
|
}
|
|
11693
11881
|
// In browser, should auto-commit
|
|
11694
11882
|
cb(); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11883
|
+
/* c8 ignore stop -- see comment above */
|
|
11695
11884
|
};
|
|
11696
11885
|
sysdb.transaction(function (systx) {
|
|
11697
11886
|
/**
|
|
@@ -11699,6 +11888,7 @@
|
|
|
11699
11888
|
*/
|
|
11700
11889
|
function versionSet() {
|
|
11701
11890
|
var e = /** @type {import('eventtargeter').EventWithProps & Event & IDBVersionChangeEvent} */
|
|
11891
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11702
11892
|
// @ts-ignore It's ok; needed under some TS versions
|
|
11703
11893
|
new IDBVersionChangeEvent('upgradeneeded', {
|
|
11704
11894
|
oldVersion: oldVersion,
|
|
@@ -11824,9 +12014,17 @@
|
|
|
11824
12014
|
// eslint-disable-next-line camelcase -- Clear API
|
|
11825
12015
|
req.transaction.on__complete = function () {
|
|
11826
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 */
|
|
11827
12023
|
if (pos !== -1) {
|
|
11828
12024
|
connection.__transactions.splice(pos, 1);
|
|
11829
12025
|
}
|
|
12026
|
+
/* c8 ignore stop -- see comment above */
|
|
12027
|
+
|
|
11830
12028
|
if (/** @type {import('./IDBDatabase.js').IDBDatabaseFull} */req.__result.__closePending) {
|
|
11831
12029
|
req.__transaction = null;
|
|
11832
12030
|
var err = createDOMException('AbortError', 'The connection has been closed.');
|
|
@@ -11862,9 +12060,16 @@
|
|
|
11862
12060
|
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [version, sqlSafeName], versionSet, dbCreateError);
|
|
11863
12061
|
}
|
|
11864
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 */
|
|
11865
12069
|
if (currentTask.readOnly || err) {
|
|
11866
12070
|
return true;
|
|
11867
12071
|
}
|
|
12072
|
+
/* c8 ignore stop -- see comment above */
|
|
11868
12073
|
sysdbFinishedCb = function sysdbFinishedCb(systx, err, cb) {
|
|
11869
12074
|
if (err) {
|
|
11870
12075
|
rollback(err,
|
|
@@ -11879,7 +12084,17 @@
|
|
|
11879
12084
|
} else {
|
|
11880
12085
|
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [oldVersion, sqlSafeName]);
|
|
11881
12086
|
}
|
|
11882
|
-
},
|
|
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 */
|
|
11883
12098
|
isRevertingSysdb = false;
|
|
11884
12099
|
cb(sqlErr); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11885
12100
|
}, function () {
|
|
@@ -11895,8 +12110,20 @@
|
|
|
11895
12110
|
});
|
|
11896
12111
|
return undefined;
|
|
11897
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. */
|
|
11898
12124
|
console.log('Error within `triggerAnyVersionChangeAndBlockedEvents`');
|
|
11899
12125
|
throw err;
|
|
12126
|
+
/* c8 ignore stop -- see comment above */
|
|
11900
12127
|
});
|
|
11901
12128
|
} else {
|
|
11902
12129
|
finishRequest();
|
|
@@ -11924,11 +12151,19 @@
|
|
|
11924
12151
|
if ((useMemoryDatabase || useDatabaseCache) && Object.hasOwn(websqlDBCache, name) && Object.hasOwn(websqlDBCache[name], version)) {
|
|
11925
12152
|
db = websqlDBCache[name][version];
|
|
11926
12153
|
} else {
|
|
11927
|
-
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);
|
|
11928
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. */
|
|
11929
12163
|
if (!Object.hasOwn(websqlDBCache, name)) {
|
|
11930
12164
|
websqlDBCache[name] = {};
|
|
11931
12165
|
}
|
|
12166
|
+
/* c8 ignore stop -- see comment above */
|
|
11932
12167
|
websqlDBCache[name][version] = db;
|
|
11933
12168
|
}
|
|
11934
12169
|
}
|
|
@@ -12079,6 +12314,7 @@
|
|
|
12079
12314
|
req.__result = undefined;
|
|
12080
12315
|
req.__done = true;
|
|
12081
12316
|
var e = /** @type {Event & IDBVersionChangeEvent} */
|
|
12317
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
12082
12318
|
// @ts-ignore It's ok; needed under some TS versions
|
|
12083
12319
|
new IDBVersionChangeEvent('success', {
|
|
12084
12320
|
oldVersion: version,
|
|
@@ -12121,9 +12357,23 @@
|
|
|
12121
12357
|
cleanupDatabaseResources(me.__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError);
|
|
12122
12358
|
}, dbError);
|
|
12123
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. */
|
|
12124
12373
|
if (currentTask.readOnly || err) {
|
|
12125
12374
|
return true;
|
|
12126
12375
|
}
|
|
12376
|
+
/* c8 ignore stop -- see comment above */
|
|
12127
12377
|
sysdbFinishedCbDelete = function sysdbFinishedCbDelete(err, cb) {
|
|
12128
12378
|
if (err) {
|
|
12129
12379
|
rollback(err, cb);
|
|
@@ -12249,10 +12499,9 @@
|
|
|
12249
12499
|
};
|
|
12250
12500
|
|
|
12251
12501
|
/**
|
|
12252
|
-
* @todo forceClose: Test
|
|
12253
12502
|
* This is provided to facilitate unit-testing of the
|
|
12254
12503
|
* closing of a database connection with a forced flag:
|
|
12255
|
-
* <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection
|
|
12504
|
+
* <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection>.
|
|
12256
12505
|
* @param {string} dbName
|
|
12257
12506
|
* @param {Integer} connIdx
|
|
12258
12507
|
* @param {string} msg
|
|
@@ -12353,6 +12602,7 @@
|
|
|
12353
12602
|
* @this {IDBRecordFull}
|
|
12354
12603
|
*/
|
|
12355
12604
|
function IDBRecord() {
|
|
12605
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
12356
12606
|
// @ts-ignore Should be ok
|
|
12357
12607
|
this[Symbol.toStringTag] = 'IDBRecord';
|
|
12358
12608
|
this.__key = key;
|
|
@@ -12389,6 +12639,7 @@
|
|
|
12389
12639
|
if (!(this instanceof IDBRecordAlias)) {
|
|
12390
12640
|
throw new TypeError('Illegal invocation');
|
|
12391
12641
|
}
|
|
12642
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
12392
12643
|
// @ts-ignore `this` is a real instance past the check above (not an issue in TS7)
|
|
12393
12644
|
return this['__' + prop];
|
|
12394
12645
|
});
|
|
@@ -12731,6 +12982,7 @@
|
|
|
12731
12982
|
success(undefined, undefined, undefined);
|
|
12732
12983
|
}
|
|
12733
12984
|
}, function (tx, err) {
|
|
12985
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
12734
12986
|
if (CFG.DEBUG) {
|
|
12735
12987
|
console.log('Could not execute Cursor.continue', sqlStr, sqlValues);
|
|
12736
12988
|
}
|
|
@@ -12914,7 +13166,16 @@
|
|
|
12914
13166
|
if (a.key > b.key) {
|
|
12915
13167
|
return me.direction === 'prev' ? -1 : 1;
|
|
12916
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. */
|
|
12917
13177
|
return 0;
|
|
13178
|
+
/* c8 ignore stop -- see comment above */
|
|
12918
13179
|
});
|
|
12919
13180
|
me.__prefetchedIndex = 0;
|
|
12920
13181
|
me.__prefetchedData = {
|
|
@@ -12933,13 +13194,19 @@
|
|
|
12933
13194
|
console.log('[multiEntry] Preloaded ' + me.__prefetchedData.length + ' records for multiEntry cursor');
|
|
12934
13195
|
}
|
|
12935
13196
|
me.__decode(rows[0], success);
|
|
12936
|
-
},
|
|
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) {
|
|
12937
13203
|
if (CFG.DEBUG) {
|
|
12938
13204
|
console.log('[multiEntry] Could not execute Cursor.continue', sqlStr, sqlValues);
|
|
12939
13205
|
}
|
|
12940
13206
|
error(err);
|
|
12941
13207
|
return false;
|
|
12942
13208
|
});
|
|
13209
|
+
/* c8 ignore stop -- see comment above */
|
|
12943
13210
|
}
|
|
12944
13211
|
runQuery();
|
|
12945
13212
|
};
|
|
@@ -13048,6 +13315,7 @@
|
|
|
13048
13315
|
* @returns {void}
|
|
13049
13316
|
*/
|
|
13050
13317
|
IDBCursor.prototype.__invalidateCache = function () {
|
|
13318
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
13051
13319
|
// @ts-ignore Why is this not being found?; needed under some TS versions
|
|
13052
13320
|
this.__prefetchedData = null;
|
|
13053
13321
|
this.__multiEntryExhausted = false;
|
|
@@ -13072,7 +13340,7 @@
|
|
|
13072
13340
|
convertValueToKeyRethrowingAndIfInvalid(key);
|
|
13073
13341
|
var cmpResult = cmp(key, me.key);
|
|
13074
13342
|
if (cmpResult === 0 || me.direction.includes('next') && cmpResult === -1 || me.direction.includes('prev') && cmpResult === 1) {
|
|
13075
|
-
throw createDOMException('DataError', 'Cannot
|
|
13343
|
+
throw createDOMException('DataError', 'Cannot continue the cursor in an unexpected direction');
|
|
13076
13344
|
}
|
|
13077
13345
|
}
|
|
13078
13346
|
this.__continueFinish(key, undefined, advanceState);
|
|
@@ -13329,6 +13597,7 @@
|
|
|
13329
13597
|
// continuation logic in `__findBasic` to see this update's
|
|
13330
13598
|
// effect on ordering (see "Modify records during cursor
|
|
13331
13599
|
// iteration" in idbcursor_update_index.any.js).
|
|
13600
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
13332
13601
|
// @ts-ignore -- API (not erring in TS 6)
|
|
13333
13602
|
IDBObjectStore.__storingRecordObjectStore(request, me.__store, true, clonedValue, false, key);
|
|
13334
13603
|
}
|
|
@@ -13378,14 +13647,33 @@
|
|
|
13378
13647
|
// We don't invalidate the cache (as we don't access it anymore
|
|
13379
13648
|
// and it will set the index off)
|
|
13380
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. */
|
|
13381
13662
|
} else {
|
|
13382
13663
|
// @ts-expect-error Apparently ok
|
|
13383
13664
|
error('No rows with key found' + key);
|
|
13384
13665
|
}
|
|
13385
|
-
|
|
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) {
|
|
13386
13673
|
error(data);
|
|
13387
13674
|
return false;
|
|
13388
13675
|
});
|
|
13676
|
+
/* c8 ignore stop -- see comment above */
|
|
13389
13677
|
}, error);
|
|
13390
13678
|
}, undefined, me);
|
|
13391
13679
|
};
|
|
@@ -13796,7 +14084,7 @@
|
|
|
13796
14084
|
setConfig(initialConfig);
|
|
13797
14085
|
}
|
|
13798
14086
|
var IDB = /** @type {ShimmedObject & {[key: string]: unknown}} */
|
|
13799
|
-
/** @type {unknown} */idb || globalThis
|
|
14087
|
+
/** @type {unknown} */idb || globalThis;
|
|
13800
14088
|
/**
|
|
13801
14089
|
* @param {string} name
|
|
13802
14090
|
* @param {unknown} value
|
|
@@ -13887,80 +14175,87 @@
|
|
|
13887
14175
|
});
|
|
13888
14176
|
}
|
|
13889
14177
|
var shimIDBFactory = IDBFactory;
|
|
13890
|
-
if (CFG.win.openDatabase
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
13898
|
-
|
|
13899
|
-
|
|
13900
|
-
|
|
13901
|
-
|
|
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');
|
|
13902
14190
|
}
|
|
13903
|
-
|
|
13904
|
-
/** @type {[string, unknown][]} */
|
|
13905
|
-
[['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) {
|
|
13906
|
-
var _ref4 = _slicedToArray(_ref3, 2),
|
|
13907
|
-
prop = _ref4[0],
|
|
13908
|
-
obj = _ref4[1];
|
|
13909
|
-
shim(prop, obj, {
|
|
13910
|
-
enumerable: false,
|
|
13911
|
-
configurable: true
|
|
13912
|
-
});
|
|
13913
|
-
});
|
|
13914
|
-
// For Node environments
|
|
13915
|
-
if (CFG.fs) {
|
|
13916
|
-
setFS(CFG.fs);
|
|
14191
|
+
return shimIndexedDB;
|
|
13917
14192
|
}
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
|
|
13941
|
-
|
|
13942
|
-
|
|
13943
|
-
|
|
13944
|
-
|
|
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);
|
|
13945
14234
|
}
|
|
13946
|
-
|
|
13947
|
-
|
|
13948
|
-
|
|
13949
|
-
|
|
13950
|
-
|
|
13951
|
-
|
|
13952
|
-
|
|
13953
|
-
if (CFG.replaceNonIDBGlobals) {
|
|
13954
|
-
setNonIDBGlobals();
|
|
13955
|
-
}
|
|
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');
|
|
13956
14242
|
}
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
return;
|
|
14243
|
+
if (CFG.replaceNonIDBGlobals) {
|
|
14244
|
+
setNonIDBGlobals();
|
|
13960
14245
|
}
|
|
13961
|
-
/* c8 ignore stop -- TS guard */
|
|
13962
|
-
IDB.shimIndexedDB.__setConnectionQueueOrigin();
|
|
13963
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();
|
|
13964
14259
|
};
|
|
13965
14260
|
IDB.shimIndexedDB.__debug = /** @type {(val: boolean) => void} */function (val) {
|
|
13966
14261
|
CFG.DEBUG = val;
|