indexeddbshim 19.0.4 → 19.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/badges/coverage-badge.svg +1 -1
- package/badges/tests-badge.svg +1 -1
- package/dist/CFG.d.ts +1 -1
- package/dist/CFG.d.ts.map +1 -1
- package/dist/DOMException.d.ts.map +1 -1
- package/dist/IDBCursor.d.ts.map +1 -1
- package/dist/IDBDatabase.d.ts.map +1 -1
- package/dist/IDBFactory.d.ts +1 -2
- package/dist/IDBFactory.d.ts.map +1 -1
- package/dist/IDBIndex.d.ts +2 -6
- package/dist/IDBIndex.d.ts.map +1 -1
- package/dist/IDBKeyRange.d.ts.map +1 -1
- package/dist/IDBObjectStore.d.ts.map +1 -1
- package/dist/IDBRecord.d.ts.map +1 -1
- package/dist/IDBRequest.d.ts.map +1 -1
- package/dist/IDBTransaction.d.ts.map +1 -1
- package/dist/Key.d.ts.map +1 -1
- package/dist/Sca.d.ts.map +1 -1
- package/dist/indexeddbshim-Key.js +40 -28
- package/dist/indexeddbshim-Key.js.map +1 -1
- package/dist/indexeddbshim-Key.min.js +2 -2
- package/dist/indexeddbshim-Key.min.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs +525 -225
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.js +553 -252
- package/dist/indexeddbshim-UnicodeIdentifiers.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js +3 -3
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js.map +1 -1
- package/dist/indexeddbshim-node.cjs +525 -225
- package/dist/indexeddbshim-node.cjs.map +1 -1
- package/dist/indexeddbshim-noninvasive.js +553 -252
- package/dist/indexeddbshim-noninvasive.js.map +1 -1
- package/dist/indexeddbshim-noninvasive.min.js +3 -3
- package/dist/indexeddbshim-noninvasive.min.js.map +1 -1
- package/dist/indexeddbshim.js +553 -252
- package/dist/indexeddbshim.js.map +1 -1
- package/dist/indexeddbshim.min.js +3 -3
- package/dist/indexeddbshim.min.js.map +1 -1
- package/dist/nodeWebSQL.d.ts.map +1 -1
- package/dist/setGlobalVars.d.ts +1 -1
- package/dist/setGlobalVars.d.ts.map +1 -1
- package/dist/util.d.ts.map +1 -1
- package/package.json +22 -17
- package/src/CFG.js +18 -4
- package/src/DOMException.js +6 -0
- package/src/DOMStringList.js +3 -0
- package/src/IDBCursor.js +36 -3
- package/src/IDBDatabase.js +26 -10
- package/src/IDBFactory.js +105 -5
- package/src/IDBIndex.js +49 -32
- package/src/IDBKeyRange.js +8 -7
- package/src/IDBObjectStore.js +25 -2
- package/src/IDBRecord.js +2 -0
- package/src/IDBRequest.js +7 -4
- package/src/IDBTransaction.js +111 -34
- package/src/Key.js +17 -16
- package/src/Sca.js +9 -4
- package/src/nodeWebSQL.js +1 -0
- package/src/setGlobalVars.js +86 -77
- package/src/util.js +5 -6
package/dist/indexeddbshim.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! indexeddbshim - v19.0.
|
|
1
|
+
/*! indexeddbshim - v19.0.6 - 9/22/2026 */
|
|
2
2
|
|
|
3
3
|
(function (factory) {
|
|
4
4
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
@@ -473,6 +473,7 @@
|
|
|
473
473
|
var ShimDOMException$1 = typeof DOMException === 'undefined'
|
|
474
474
|
// Todo: Better polyfill (if even needed here)
|
|
475
475
|
/* eslint-disable no-shadow -- Polyfill */
|
|
476
|
+
/* 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) */
|
|
476
477
|
// eslint-disable-next-line @stylistic/operator-linebreak -- TS/JSDoc needs
|
|
477
478
|
?
|
|
478
479
|
/**
|
|
@@ -490,9 +491,10 @@
|
|
|
490
491
|
configurable: true
|
|
491
492
|
});
|
|
492
493
|
return err;
|
|
493
|
-
}
|
|
494
|
+
}
|
|
495
|
+
/* c8 ignore stop */ : DOMException;
|
|
494
496
|
|
|
495
|
-
/** @type {WeakMap<object,
|
|
497
|
+
/** @type {WeakMap<object, EventWithProps>} */
|
|
496
498
|
var ev = new WeakMap();
|
|
497
499
|
/** @type {WeakMap<object, EventWithProps>} */
|
|
498
500
|
var evCfg = new WeakMap();
|
|
@@ -538,11 +540,12 @@
|
|
|
538
540
|
obj[prop] = {
|
|
539
541
|
configurable: true,
|
|
540
542
|
get: function get() {
|
|
541
|
-
return Object.hasOwn(_evCfg, prop) ? _evCfg[prop] : Reflect.has(_ev, prop) ? _ev[prop] : ['bubbles', 'cancelable', 'composed'].includes(prop) ? false
|
|
543
|
+
return Object.hasOwn(_evCfg, prop) ? _evCfg[prop] : Reflect.has(_ev, prop) ? _ev[prop] : ['bubbles', 'cancelable', 'composed'].includes(prop) ? false
|
|
544
|
+
/* 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;
|
|
542
545
|
}
|
|
543
546
|
};
|
|
544
547
|
return obj;
|
|
545
|
-
}, /** @type {
|
|
548
|
+
}, /** @type {PropertyDescriptorMap} */{}));
|
|
546
549
|
}
|
|
547
550
|
|
|
548
551
|
/**
|
|
@@ -565,8 +568,9 @@
|
|
|
565
568
|
throw new TypeError('Illegal invocation');
|
|
566
569
|
}
|
|
567
570
|
var _evCfg = getEvCfg(this);
|
|
568
|
-
var _ev = ev.get(this);
|
|
569
|
-
return Boolean(Object.hasOwn(_evCfg, 'isTrusted')
|
|
571
|
+
var _ev = /** @type {EventWithProps} */ /** @type {EventWithProps} */ev.get(this);
|
|
572
|
+
return Boolean(Object.hasOwn(_evCfg, 'isTrusted')
|
|
573
|
+
/* 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);
|
|
570
574
|
}
|
|
571
575
|
|
|
572
576
|
/**
|
|
@@ -717,15 +721,15 @@
|
|
|
717
721
|
// this untyped alias, rather than `ShimEvent.prototype` directly, keeps
|
|
718
722
|
// that dynamic-augmentation pattern working without a `@ts-expect-error`
|
|
719
723
|
// on every single line below.
|
|
720
|
-
|
|
721
|
-
var ShimEventProto = ShimEvent.prototype;
|
|
724
|
+
|
|
725
|
+
var ShimEventProto = /** @type {Record<PropertyKey, unknown>} */ /** @type {unknown} */ShimEvent.prototype;
|
|
722
726
|
|
|
723
727
|
/** @this {EventWithProps} */
|
|
724
728
|
ShimEventProto.preventDefault = function preventDefault() {
|
|
725
729
|
if (!(this instanceof ShimEvent)) {
|
|
726
730
|
throw new TypeError('Illegal invocation');
|
|
727
731
|
}
|
|
728
|
-
var _ev = ev.get(this);
|
|
732
|
+
var _ev = /** @type {EventWithProps} */ /** @type {EventWithProps} */ev.get(this);
|
|
729
733
|
var _evCfg = getEvCfg(this);
|
|
730
734
|
if (this.cancelable && !_evCfg._passive) {
|
|
731
735
|
_evCfg.defaultPrevented = true;
|
|
@@ -923,13 +927,12 @@
|
|
|
923
927
|
return _createClass(CustomEvent);
|
|
924
928
|
}(Event);
|
|
925
929
|
var ShimCustomEvent = CustomEvent;
|
|
926
|
-
/** @type {
|
|
927
|
-
var ShimCustomEventProto = ShimCustomEvent.prototype;
|
|
930
|
+
var ShimCustomEventProto = /** @type {Record<PropertyKey, unknown>} */ /** @type {unknown} */ShimCustomEvent.prototype;
|
|
928
931
|
/**
|
|
929
932
|
* @param {string} type
|
|
930
933
|
* @param {boolean} [bubbles]
|
|
931
934
|
* @param {boolean} [cancelable]
|
|
932
|
-
* @param {
|
|
935
|
+
* @param {unknown} [detail]
|
|
933
936
|
* @this {EventWithProps}
|
|
934
937
|
*/
|
|
935
938
|
ShimCustomEventProto.initCustomEvent = function initCustomEvent(type) {
|
|
@@ -941,6 +944,10 @@
|
|
|
941
944
|
throw new TypeError('Illegal invocation');
|
|
942
945
|
}
|
|
943
946
|
var _evCfg = getEvCfg(this);
|
|
947
|
+
if (_evCfg._dispatched) {
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
|
|
944
951
|
// @ts-expect-error `detail` isn't part of `EventInit`, only used internally here
|
|
945
952
|
// eslint-disable-next-line prefer-rest-params -- Keep signature
|
|
946
953
|
initEventInternal(this, type, {
|
|
@@ -948,16 +955,13 @@
|
|
|
948
955
|
cancelable: cancelable,
|
|
949
956
|
detail: detail
|
|
950
957
|
}, arguments[4]);
|
|
951
|
-
if (_evCfg._dispatched) {
|
|
952
|
-
return;
|
|
953
|
-
}
|
|
954
958
|
if (detail !== undefined) {
|
|
955
959
|
_evCfg.detail = detail;
|
|
956
960
|
}
|
|
957
961
|
// `initCustomEvent` deliberately excluded -- see the matching comment
|
|
958
962
|
// in `initEventInternal` for `initEvent`, above; the same reasoning
|
|
959
963
|
// applies here.
|
|
960
|
-
definePassthroughProps(this, ['detail'], _evCfg, ev.get(this));
|
|
964
|
+
definePassthroughProps(this, ['detail'], _evCfg, /** @type {EventWithProps} */ev.get(this));
|
|
961
965
|
};
|
|
962
966
|
// @ts-expect-error Not part of the class body itself
|
|
963
967
|
ShimCustomEvent[Symbol.toStringTag] = 'Function';
|
|
@@ -1364,7 +1368,7 @@
|
|
|
1364
1368
|
/** @type {string[]} */
|
|
1365
1369
|
this._extraProperties.forEach(function (prop) {
|
|
1366
1370
|
if (Reflect.has(e, prop)) {
|
|
1367
|
-
/** @type {
|
|
1371
|
+
/** @type {PropertyDescriptorMap} */eventCopy[prop] = /** @type {PropertyDescriptorMap} */e[prop]; // Todo: Put internal to `ShimEvent`?
|
|
1368
1372
|
}
|
|
1369
1373
|
});
|
|
1370
1374
|
}
|
|
@@ -1443,6 +1447,7 @@
|
|
|
1443
1447
|
if (child) {
|
|
1444
1448
|
child._defaultSync = this._defaultSync;
|
|
1445
1449
|
}
|
|
1450
|
+
/* 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 */
|
|
1446
1451
|
return (child || this)._dispatchEvent(eventCopy, false);
|
|
1447
1452
|
}
|
|
1448
1453
|
case phases.AT_TARGET:
|
|
@@ -1740,7 +1745,7 @@
|
|
|
1740
1745
|
* databaseNameLengthLimit: number|false,
|
|
1741
1746
|
* escapeNFDForDatabaseNames: boolean,
|
|
1742
1747
|
* addSQLiteExtension: boolean,
|
|
1743
|
-
* memoryDatabase: string,
|
|
1748
|
+
* memoryDatabase: string|null|undefined,
|
|
1744
1749
|
* deleteDatabaseFiles: boolean,
|
|
1745
1750
|
* databaseBasePath: string,
|
|
1746
1751
|
* sysDatabaseBasePath: string,
|
|
@@ -1883,13 +1888,27 @@
|
|
|
1883
1888
|
// Various types of in-memory databases that can auto-delete
|
|
1884
1889
|
['memoryDatabase',
|
|
1885
1890
|
/**
|
|
1886
|
-
*
|
|
1891
|
+
* `null`/`undefined` are accepted (and left unvalidated against the
|
|
1892
|
+
* regex below) specifically so this can be reset back to its
|
|
1893
|
+
* unset/disabled state after being set: unlike other `CFG`
|
|
1894
|
+
* boolean-ish switches (e.g. `sqlMemoryQuota`, which is checked
|
|
1895
|
+
* with a falsy `if (CFG.sqlMemoryQuota)`), `memoryDatabase`'s own
|
|
1896
|
+
* usage sites check `typeof CFG.memoryDatabase === 'string'`, so
|
|
1897
|
+
* even the empty string counts as "on" (it's a distinct, valid
|
|
1898
|
+
* in-memory mode of its own -- an unnamed private temporary
|
|
1899
|
+
* database -- not an "off" state). Without this, once set to any
|
|
1900
|
+
* string there would be no value passable back through this same
|
|
1901
|
+
* validator that turns `useMemoryDatabase` false again.
|
|
1902
|
+
* @param {string|null|undefined} val
|
|
1887
1903
|
* @throws {TypeError}
|
|
1888
1904
|
* @returns {void}
|
|
1889
1905
|
*/
|
|
1890
1906
|
function (val) {
|
|
1907
|
+
if (val === null || val === undefined) {
|
|
1908
|
+
return;
|
|
1909
|
+
}
|
|
1891
1910
|
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)) {
|
|
1892
|
-
throw new TypeError('`memoryDatabase` must be the empty string, ":memory:", or a
|
|
1911
|
+
throw new TypeError('`memoryDatabase` must be `null`/`undefined` (to reset it to disabled), the empty string, ' + '":memory:", or a "file::memory:[?queryString][#hash] URL".');
|
|
1893
1912
|
}
|
|
1894
1913
|
}],
|
|
1895
1914
|
// NODE-SPECIFIC CONFIG
|
|
@@ -1943,10 +1962,7 @@
|
|
|
1943
1962
|
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) {
|
|
1944
1963
|
// Could add a corresponding surrogate for compatibility with `node-sqlite3`: https://bugs.python.org/issue12569 and https://stackoverflow.com/a/6701665/271577
|
|
1945
1964
|
// but Chrome having problems
|
|
1946
|
-
|
|
1947
|
-
return '^2' + unmatchedHighSurrogate.codePointAt().toString(16).padStart(4, '0');
|
|
1948
|
-
}
|
|
1949
|
-
return (precedingLow || '') + '^3' + unmatchedLowSurrogate.codePointAt().toString(16).padStart(4, '0');
|
|
1965
|
+
return unmatchedHighSurrogate ? '^2' + unmatchedHighSurrogate.codePointAt().toString(16).padStart(4, '0') : (precedingLow || '') + '^3' + unmatchedLowSurrogate.codePointAt().toString(16).padStart(4, '0');
|
|
1950
1966
|
});
|
|
1951
1967
|
}
|
|
1952
1968
|
|
|
@@ -2613,7 +2629,8 @@
|
|
|
2613
2629
|
function createNativeDOMException(name, message) {
|
|
2614
2630
|
// @ts-expect-error It's ok
|
|
2615
2631
|
// eslint-disable-next-line new-cap -- Ok
|
|
2616
|
-
return new DOMException.prototype.constructor(message,
|
|
2632
|
+
return new DOMException.prototype.constructor(message, /* c8 ignore next -- Defensive fallback; every call site in this codebase always supplies a `name` */
|
|
2633
|
+
name || 'DOMException');
|
|
2617
2634
|
}
|
|
2618
2635
|
|
|
2619
2636
|
// From web-platform-tests testharness.js name_code_map (though not in new spec)
|
|
@@ -2777,8 +2794,10 @@
|
|
|
2777
2794
|
*/
|
|
2778
2795
|
get: function get() {
|
|
2779
2796
|
if (!(this instanceof DOMException ||
|
|
2797
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2780
2798
|
// @ts-ignore Just checking; needed under some TS versions
|
|
2781
2799
|
this instanceof DummyDOMException ||
|
|
2800
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2782
2801
|
// @ts-ignore Just checking; needed under some TS versions
|
|
2783
2802
|
this instanceof Error)) {
|
|
2784
2803
|
throw new TypeError('Illegal invocation');
|
|
@@ -2837,6 +2856,7 @@
|
|
|
2837
2856
|
value: DOMException
|
|
2838
2857
|
});
|
|
2839
2858
|
|
|
2859
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2840
2860
|
// @ts-ignore We don't need all its properties; needed under some TS versions
|
|
2841
2861
|
return DOMException;
|
|
2842
2862
|
}
|
|
@@ -2849,6 +2869,7 @@
|
|
|
2849
2869
|
* @returns {Error}
|
|
2850
2870
|
*/
|
|
2851
2871
|
function createNonNativeDOMException(name, message) {
|
|
2872
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2852
2873
|
// @ts-ignore It's ok; needed under some TS versions
|
|
2853
2874
|
return new ShimNonNativeDOMException(message, name);
|
|
2854
2875
|
}
|
|
@@ -2871,6 +2892,8 @@
|
|
|
2871
2892
|
return;
|
|
2872
2893
|
}
|
|
2873
2894
|
var msg = error && _typeof(error) === 'object' && error.message ? error.message : (/** @type {string} */error);
|
|
2895
|
+
|
|
2896
|
+
/* c8 ignore next -- Defensive fallback for an environment lacking `console.error` */
|
|
2874
2897
|
var method = typeof console.error === 'function' ? 'error' : 'log';
|
|
2875
2898
|
console[method](name + ': ' + message + '. ' + (msg || ''));
|
|
2876
2899
|
if (console.trace) {
|
|
@@ -3056,8 +3079,10 @@
|
|
|
3056
3079
|
*/
|
|
3057
3080
|
IDBRequest.__super = function IDBRequest() {
|
|
3058
3081
|
var _this = this;
|
|
3082
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
3059
3083
|
// @ts-ignore It's ok
|
|
3060
3084
|
this[Symbol.toStringTag] = 'IDBRequest';
|
|
3085
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
3061
3086
|
// @ts-ignore Part of `ShimEventTarget`
|
|
3062
3087
|
this.__setOptions({
|
|
3063
3088
|
legacyOutputDidListenersThrowFlag: true // Event hook for IndexedB
|
|
@@ -3115,10 +3140,7 @@
|
|
|
3115
3140
|
* @returns {import('./IDBTransaction.js').IDBTransactionFull|null|undefined}
|
|
3116
3141
|
*/
|
|
3117
3142
|
IDBRequest.prototype.__getParent = function () {
|
|
3118
|
-
|
|
3119
|
-
return null;
|
|
3120
|
-
}
|
|
3121
|
-
return this.__transaction;
|
|
3143
|
+
return this.toString() === '[object IDBOpenDBRequest]' ? null : this.__transaction;
|
|
3122
3144
|
};
|
|
3123
3145
|
|
|
3124
3146
|
/* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
|
|
@@ -3177,8 +3199,10 @@
|
|
|
3177
3199
|
function IDBOpenDBRequest() {
|
|
3178
3200
|
IDBRequest.__super.call(this);
|
|
3179
3201
|
|
|
3202
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
3180
3203
|
// @ts-ignore It's ok
|
|
3181
3204
|
this[Symbol.toStringTag] = 'IDBOpenDBRequest';
|
|
3205
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
3182
3206
|
// @ts-ignore It's ok
|
|
3183
3207
|
this.__setOptions({
|
|
3184
3208
|
legacyOutputDidListenersThrowFlag: true,
|
|
@@ -4189,8 +4213,14 @@
|
|
|
4189
4213
|
}
|
|
4190
4214
|
if (!multiEntry || !fullKeys && keys.every(function (k) {
|
|
4191
4215
|
return cmp(/** @type {Key} */k, /** @type {Key} */key.value) !== 0;
|
|
4192
|
-
}) ||
|
|
4193
|
-
|
|
4216
|
+
}) ||
|
|
4217
|
+
// `keys` holds full `{type, value}` objects here (see
|
|
4218
|
+
// `safePush` below), so -- like the sibling branch
|
|
4219
|
+
// above -- `cmp` (which expects raw `Value`s, not
|
|
4220
|
+
// decoded key objects) must compare their `.value`s,
|
|
4221
|
+
// not the wrapper objects themselves.
|
|
4222
|
+
fullKeys && keys.every(function (k) {
|
|
4223
|
+
return cmp(/** @type {Key} */ /** @type {KeyValueObject} */k.value, /** @type {Key} */key.value) !== 0;
|
|
4194
4224
|
})) {
|
|
4195
4225
|
safePush(keys, fullKeys ? key : key.value);
|
|
4196
4226
|
}
|
|
@@ -4215,12 +4245,9 @@
|
|
|
4215
4245
|
{
|
|
4216
4246
|
var date = /** @type {Date} */input;
|
|
4217
4247
|
if (!Number.isNaN(date.getTime())) {
|
|
4218
|
-
return
|
|
4219
|
-
type: type,
|
|
4220
|
-
value: date.getTime()
|
|
4221
|
-
} : {
|
|
4248
|
+
return {
|
|
4222
4249
|
type: type,
|
|
4223
|
-
value: new Date(date)
|
|
4250
|
+
value: fullKeys ? date.getTime() : new Date(date)
|
|
4224
4251
|
};
|
|
4225
4252
|
}
|
|
4226
4253
|
return {
|
|
@@ -4308,10 +4335,7 @@
|
|
|
4308
4335
|
if (r.failure) {
|
|
4309
4336
|
return r;
|
|
4310
4337
|
}
|
|
4311
|
-
|
|
4312
|
-
return convertValueToKeyValueDecoded(r.value, null, false, fullKeys);
|
|
4313
|
-
}
|
|
4314
|
-
return convertValueToMultiEntryKeyDecoded(r.value, fullKeys);
|
|
4338
|
+
return !multiEntry ? convertValueToKeyValueDecoded(r.value, null, false, fullKeys) : convertValueToMultiEntryKeyDecoded(r.value, fullKeys);
|
|
4315
4339
|
}
|
|
4316
4340
|
|
|
4317
4341
|
/**
|
|
@@ -4492,10 +4516,7 @@
|
|
|
4492
4516
|
*/
|
|
4493
4517
|
function isMultiEntryMatch(encodedEntry, encodedKey) {
|
|
4494
4518
|
var keyType = encodedCharToKeyType[encodedKey.slice(0, 1)];
|
|
4495
|
-
|
|
4496
|
-
return encodedKey.indexOf(encodedEntry) > 1;
|
|
4497
|
-
}
|
|
4498
|
-
return encodedKey === encodedEntry;
|
|
4519
|
+
return keyType === 'array' ? encodedKey.indexOf(encodedEntry) > 1 : encodedKey === encodedEntry;
|
|
4499
4520
|
}
|
|
4500
4521
|
|
|
4501
4522
|
/**
|
|
@@ -4613,10 +4634,7 @@
|
|
|
4613
4634
|
* @returns {undefined|ValueType}
|
|
4614
4635
|
*/
|
|
4615
4636
|
function _decode(key, inArray) {
|
|
4616
|
-
|
|
4617
|
-
return undefined;
|
|
4618
|
-
}
|
|
4619
|
-
return types[encodedCharToKeyType[key.slice(0, 1)]].decode(key, inArray);
|
|
4637
|
+
return typeof key !== 'string' ? undefined : types[encodedCharToKeyType[key.slice(0, 1)]].decode(key, inArray);
|
|
4620
4638
|
}
|
|
4621
4639
|
|
|
4622
4640
|
/**
|
|
@@ -5022,10 +5040,11 @@
|
|
|
5022
5040
|
if (hasLower && hasUpper) {
|
|
5023
5041
|
sql.push('AND');
|
|
5024
5042
|
}
|
|
5025
|
-
if (hasUpper) {
|
|
5026
|
-
|
|
5027
|
-
sqlValues.push(escapeSQLiteStatement(/** @type {string} */encodedUpperKey));
|
|
5043
|
+
if (!hasUpper) {
|
|
5044
|
+
return;
|
|
5028
5045
|
}
|
|
5046
|
+
sql.push(quotedKeyColumnName, range.upperOpen ? '<' : '<=', '?');
|
|
5047
|
+
sqlValues.push(escapeSQLiteStatement(/** @type {string} */encodedUpperKey));
|
|
5029
5048
|
}
|
|
5030
5049
|
|
|
5031
5050
|
/**
|
|
@@ -5038,10 +5057,7 @@
|
|
|
5038
5057
|
if (instanceOf(value, IDBKeyRange)) {
|
|
5039
5058
|
// We still need to validate IDBKeyRange-like objects (the above check is based on loose duck-typing)
|
|
5040
5059
|
var range = /** @type {IDBKeyRangeFull} */value;
|
|
5041
|
-
|
|
5042
|
-
return IDBKeyRange.__createInstance(range.lower, range.upper, range.lowerOpen, range.upperOpen);
|
|
5043
|
-
}
|
|
5044
|
-
return range;
|
|
5060
|
+
return range.toString() !== '[object IDBKeyRange]' ? IDBKeyRange.__createInstance(range.lower, range.upper, range.lowerOpen, range.upperOpen) : range;
|
|
5045
5061
|
}
|
|
5046
5062
|
if (isNullish(value)) {
|
|
5047
5063
|
if (nullDisallowed) {
|
|
@@ -5086,9 +5102,11 @@
|
|
|
5086
5102
|
if (testObject.test) {
|
|
5087
5103
|
cleanInterface = true;
|
|
5088
5104
|
}
|
|
5105
|
+
/* c8 ignore start -- Defensive fallback for an engine with a broken `Object.defineProperty` */
|
|
5089
5106
|
} catch (err) {
|
|
5090
5107
|
// Object.defineProperty does not work as intended.
|
|
5091
5108
|
}
|
|
5109
|
+
/* c8 ignore stop -- Defensive fallback for an engine with a broken `Object.defineProperty` */
|
|
5092
5110
|
}
|
|
5093
5111
|
|
|
5094
5112
|
/**
|
|
@@ -5289,6 +5307,7 @@
|
|
|
5289
5307
|
this._length = 0;
|
|
5290
5308
|
};
|
|
5291
5309
|
DOMStringList.prototype = DOMStringListAlias.prototype;
|
|
5310
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
5292
5311
|
// @ts-ignore It's ok; needed under some TS versions
|
|
5293
5312
|
return /** @type {DOMStringListFull} */new DOMStringList();
|
|
5294
5313
|
}
|
|
@@ -5588,12 +5607,14 @@
|
|
|
5588
5607
|
*/
|
|
5589
5608
|
IDBTransaction.prototype.__executeRequests = function () {
|
|
5590
5609
|
var me = this;
|
|
5610
|
+
/* 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. */
|
|
5591
5611
|
if (me.__running) {
|
|
5592
5612
|
if (CFG.DEBUG) {
|
|
5593
5613
|
console.log('Looks like the request set is already running', me.mode);
|
|
5594
5614
|
}
|
|
5595
5615
|
return;
|
|
5596
5616
|
}
|
|
5617
|
+
/* c8 ignore stop -- see comment above */
|
|
5597
5618
|
|
|
5598
5619
|
// The synchronous script that created this transaction (and
|
|
5599
5620
|
// synchronously queued whatever requests it wanted to) has now
|
|
@@ -5613,6 +5634,10 @@
|
|
|
5613
5634
|
var q,
|
|
5614
5635
|
i = -1;
|
|
5615
5636
|
|
|
5637
|
+
// On a standard driver, `keepAliveAndWait` issues a SQL query, which
|
|
5638
|
+
// is a macrotask. Otherwise it issues ten microtasks.
|
|
5639
|
+
var keepAliveAttempts = isStandardDriver ? 1 : 10;
|
|
5640
|
+
|
|
5616
5641
|
/**
|
|
5617
5642
|
* A continuation that must still be able to observe the
|
|
5618
5643
|
* transaction as safe to extend (e.g., re-checking whether an
|
|
@@ -5639,6 +5664,7 @@
|
|
|
5639
5664
|
queueMicrotask(cb);
|
|
5640
5665
|
return;
|
|
5641
5666
|
}
|
|
5667
|
+
/* 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. */
|
|
5642
5668
|
try {
|
|
5643
5669
|
tx.executeSql('SELECT 1', [], function () {
|
|
5644
5670
|
cb();
|
|
@@ -5648,10 +5674,11 @@
|
|
|
5648
5674
|
});
|
|
5649
5675
|
} catch (err) {
|
|
5650
5676
|
// The driver has already finalized the transaction (or otherwise
|
|
5651
|
-
// rejected the call) -- nothing left to hold open
|
|
5652
|
-
//
|
|
5653
|
-
|
|
5677
|
+
// rejected the call) -- nothing left to hold open. We explicitly
|
|
5678
|
+
// abort the transaction here.
|
|
5679
|
+
me.__abortTransaction(/** @type {Error|DOMException} */err);
|
|
5654
5680
|
}
|
|
5681
|
+
/* c8 ignore stop -- see comment above */
|
|
5655
5682
|
}
|
|
5656
5683
|
|
|
5657
5684
|
/**
|
|
@@ -5664,21 +5691,26 @@
|
|
|
5664
5691
|
* @returns {void}
|
|
5665
5692
|
*/
|
|
5666
5693
|
function success(result, req) {
|
|
5694
|
+
/* 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. */
|
|
5667
5695
|
if (me.__errored || me.__requestsFinished) {
|
|
5668
5696
|
// We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
|
|
5669
5697
|
return;
|
|
5670
5698
|
}
|
|
5699
|
+
/* c8 ignore stop -- see comment above */
|
|
5671
5700
|
if (req) {
|
|
5672
5701
|
q.req = req; // Need to do this in case of cursors
|
|
5673
5702
|
}
|
|
5703
|
+
/* 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. */
|
|
5674
5704
|
if (!q.req) {
|
|
5675
|
-
// TS guard
|
|
5676
5705
|
return;
|
|
5677
5706
|
}
|
|
5707
|
+
/* c8 ignore stop -- see comment above */
|
|
5708
|
+
/* 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. */
|
|
5678
5709
|
if (q.req.__done) {
|
|
5679
5710
|
// Avoid continuing with aborted requests
|
|
5680
5711
|
return;
|
|
5681
5712
|
}
|
|
5713
|
+
/* c8 ignore stop -- see comment above */
|
|
5682
5714
|
q.req.__done = true;
|
|
5683
5715
|
q.req.__result = result;
|
|
5684
5716
|
q.req.__error = null;
|
|
@@ -5695,6 +5727,7 @@
|
|
|
5695
5727
|
// is what actually resets `__handlerActive`, once it's
|
|
5696
5728
|
// confirmed (across its own bounded microtask wait) that no
|
|
5697
5729
|
// such continuation queued anything.
|
|
5730
|
+
/* 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. */
|
|
5698
5731
|
if (e.__legacyOutputDidListenersThrowError) {
|
|
5699
5732
|
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
|
|
5700
5733
|
if (!me.__committed) {
|
|
@@ -5704,6 +5737,7 @@
|
|
|
5704
5737
|
return;
|
|
5705
5738
|
}
|
|
5706
5739
|
}
|
|
5740
|
+
/* c8 ignore stop -- see comment above */
|
|
5707
5741
|
runContinuationSafely(advanceAfterDispatch);
|
|
5708
5742
|
}
|
|
5709
5743
|
|
|
@@ -5715,15 +5749,19 @@
|
|
|
5715
5749
|
* @returns {void}
|
|
5716
5750
|
*/
|
|
5717
5751
|
function error() {
|
|
5752
|
+
/* 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. */
|
|
5718
5753
|
if (me.__errored || me.__requestsFinished) {
|
|
5719
5754
|
// We've already called "onerror", "onabort", or thrown within
|
|
5720
5755
|
// the transaction, so don't do it again.
|
|
5721
5756
|
return;
|
|
5722
5757
|
}
|
|
5758
|
+
/* c8 ignore stop -- see comment above */
|
|
5759
|
+
/* 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. */
|
|
5723
5760
|
if (q.req && q.req.__done) {
|
|
5724
5761
|
// Avoid continuing with aborted requests
|
|
5725
5762
|
return;
|
|
5726
5763
|
}
|
|
5764
|
+
/* c8 ignore stop -- see comment above */
|
|
5727
5765
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
5728
5766
|
args[_key] = arguments[_key];
|
|
5729
5767
|
}
|
|
@@ -5748,10 +5786,11 @@
|
|
|
5748
5786
|
}
|
|
5749
5787
|
});
|
|
5750
5788
|
q.req.addDefaultEventListener('error', function () {
|
|
5789
|
+
/* 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. */
|
|
5751
5790
|
if (!q.req) {
|
|
5752
|
-
// TS guard
|
|
5753
5791
|
return;
|
|
5754
5792
|
}
|
|
5793
|
+
/* c8 ignore stop -- see comment above */
|
|
5755
5794
|
me.__abortTransaction(q.req.__error);
|
|
5756
5795
|
});
|
|
5757
5796
|
me.__active = true;
|
|
@@ -5763,16 +5802,19 @@
|
|
|
5763
5802
|
q.req.dispatchEvent(e);
|
|
5764
5803
|
// Do not set __active or __handlerActive flags to false yet --
|
|
5765
5804
|
// see the matching comment in `success`, above.
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
if (me.__committed) {
|
|
5770
|
-
// An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
|
|
5771
|
-
runContinuationSafely(advanceAfterDispatch);
|
|
5772
|
-
return;
|
|
5773
|
-
}
|
|
5774
|
-
me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after error).'));
|
|
5805
|
+
/* 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. */
|
|
5806
|
+
if (!e.__legacyOutputDidListenersThrowError) {
|
|
5807
|
+
return;
|
|
5775
5808
|
}
|
|
5809
|
+
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
|
|
5810
|
+
e.preventDefault(); // Prevent 'error' default as steps indicate we should abort with `AbortError` even without cancellation
|
|
5811
|
+
if (me.__committed) {
|
|
5812
|
+
// An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
|
|
5813
|
+
runContinuationSafely(advanceAfterDispatch);
|
|
5814
|
+
return;
|
|
5815
|
+
}
|
|
5816
|
+
me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after error).'));
|
|
5817
|
+
/* c8 ignore stop -- see comment above */
|
|
5776
5818
|
}
|
|
5777
5819
|
|
|
5778
5820
|
/**
|
|
@@ -5796,10 +5838,12 @@
|
|
|
5796
5838
|
// (not reset here).
|
|
5797
5839
|
return true;
|
|
5798
5840
|
}
|
|
5841
|
+
/* 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. */
|
|
5799
5842
|
if (q.req.__done) {
|
|
5800
5843
|
// Avoid continuing with aborted requests
|
|
5801
5844
|
return false;
|
|
5802
5845
|
}
|
|
5846
|
+
/* c8 ignore stop -- see comment above */
|
|
5803
5847
|
// We're now handing off to (possibly async) work for
|
|
5804
5848
|
// this request, so the transaction is no longer active
|
|
5805
5849
|
// until its own `success`/`error` dispatch (below)
|
|
@@ -5824,18 +5868,22 @@
|
|
|
5824
5868
|
return;
|
|
5825
5869
|
}
|
|
5826
5870
|
q.op(tx, q.args, success, error, executeNextRequest);
|
|
5871
|
+
/* 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. */
|
|
5827
5872
|
} catch (e) {
|
|
5828
5873
|
error(/** @type {Error} */e);
|
|
5829
5874
|
}
|
|
5875
|
+
/* c8 ignore stop -- see comment above */
|
|
5830
5876
|
}
|
|
5831
5877
|
|
|
5832
5878
|
/**
|
|
5833
5879
|
* @returns {void}
|
|
5834
5880
|
*/
|
|
5835
5881
|
function runQueuedRequest() {
|
|
5882
|
+
/* c8 ignore start -- Defensive: only reached if `prepareNextRequest` returns `false` (see its own ignore comment above for why that's not reliably reproducible). */
|
|
5836
5883
|
if (!prepareNextRequest()) {
|
|
5837
5884
|
return;
|
|
5838
5885
|
}
|
|
5886
|
+
/* c8 ignore stop -- see comment above */
|
|
5839
5887
|
launchQueuedOp();
|
|
5840
5888
|
}
|
|
5841
5889
|
|
|
@@ -5857,16 +5905,20 @@
|
|
|
5857
5905
|
* consumer of that same handler (e.g. one that resolves a
|
|
5858
5906
|
* promise from within `onsuccess` and only attaches `oncomplete`
|
|
5859
5907
|
* afterward) ever gets a turn to run, so it can miss `complete`
|
|
5860
|
-
*
|
|
5861
|
-
*
|
|
5862
|
-
*
|
|
5908
|
+
* afterward) ever gets a turn to run, so it can miss `complete`
|
|
5909
|
+
* entirely. On a non-standard driver, `readonly` requests don't hold
|
|
5910
|
+
* a real SQL transaction open, so there's no file-lock/connection
|
|
5911
|
+
* collision risk. On a standard driver, the wait now issues real SQL
|
|
5912
|
+
* inside the read transaction, so this does carry a slight risk.
|
|
5863
5913
|
* @param {number} attemptsLeft
|
|
5864
5914
|
* @returns {void}
|
|
5865
5915
|
*/
|
|
5866
5916
|
function checkQueueEntry(attemptsLeft) {
|
|
5917
|
+
/* 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. */
|
|
5867
5918
|
if (me.__errored || me.__requestsFinished) {
|
|
5868
5919
|
return;
|
|
5869
5920
|
}
|
|
5921
|
+
/* c8 ignore stop -- see comment above */
|
|
5870
5922
|
if (i < me.__requests.length) {
|
|
5871
5923
|
runQueuedRequest();
|
|
5872
5924
|
return;
|
|
@@ -5888,13 +5940,15 @@
|
|
|
5888
5940
|
* @returns {void}
|
|
5889
5941
|
*/
|
|
5890
5942
|
function executeNextRequest() {
|
|
5943
|
+
/* 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. */
|
|
5891
5944
|
if (me.__errored || me.__requestsFinished) {
|
|
5892
5945
|
// We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
|
|
5893
5946
|
return;
|
|
5894
5947
|
}
|
|
5948
|
+
/* c8 ignore stop -- see comment above */
|
|
5895
5949
|
i++;
|
|
5896
5950
|
if (i >= me.__requests.length) {
|
|
5897
|
-
checkQueueEntry(
|
|
5951
|
+
checkQueueEntry(keepAliveAttempts);
|
|
5898
5952
|
return;
|
|
5899
5953
|
}
|
|
5900
5954
|
runQueuedRequest();
|
|
@@ -5926,31 +5980,34 @@
|
|
|
5926
5980
|
* @returns {void}
|
|
5927
5981
|
*/
|
|
5928
5982
|
function advanceAfterDispatch() {
|
|
5983
|
+
/* 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. */
|
|
5929
5984
|
if (me.__errored || me.__requestsFinished) {
|
|
5930
5985
|
return;
|
|
5931
5986
|
}
|
|
5987
|
+
/* c8 ignore stop -- see comment above */
|
|
5932
5988
|
i++;
|
|
5933
5989
|
if (i >= me.__requests.length) {
|
|
5934
|
-
checkQueueEntry(
|
|
5990
|
+
checkQueueEntry(keepAliveAttempts);
|
|
5935
5991
|
return;
|
|
5936
5992
|
}
|
|
5937
5993
|
keepAliveAndWait(function () {
|
|
5938
|
-
if (
|
|
5939
|
-
|
|
5940
|
-
}
|
|
5941
|
-
if (!prepareNextRequest()) {
|
|
5994
|
+
/* 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. */
|
|
5995
|
+
if (me.__errored || me.__requestsFinished || !prepareNextRequest()) {
|
|
5942
5996
|
return;
|
|
5943
5997
|
}
|
|
5998
|
+
/* c8 ignore stop -- see comment above */
|
|
5944
5999
|
launchQueuedOp();
|
|
5945
6000
|
});
|
|
5946
6001
|
}
|
|
5947
6002
|
executeNextRequest();
|
|
5948
6003
|
}, function webSQLError(webSQLErr) {
|
|
6004
|
+
/* 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. */
|
|
5949
6005
|
// @ts-expect-error It's ok
|
|
5950
6006
|
if (webSQLErr === true) {
|
|
5951
6007
|
// Not a genuine SQL error
|
|
5952
6008
|
return;
|
|
5953
6009
|
}
|
|
6010
|
+
/* c8 ignore stop -- see comment above */
|
|
5954
6011
|
var err = webSQLErrback(/** @type {Error & {code?: number}} */webSQLErr);
|
|
5955
6012
|
me.__abortTransaction(err);
|
|
5956
6013
|
}, function () {
|
|
@@ -5961,18 +6018,25 @@
|
|
|
5961
6018
|
// Node
|
|
5962
6019
|
return;
|
|
5963
6020
|
}
|
|
6021
|
+
/* 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. */
|
|
5964
6022
|
if (!me.__transactionEndCallback && !me.__requestsFinished) {
|
|
5965
6023
|
me.__transactionFinished = true;
|
|
5966
6024
|
return;
|
|
5967
6025
|
}
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
6026
|
+
/* c8 ignore stop -- see comment above */
|
|
6027
|
+
/* 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. */
|
|
6028
|
+
if (!me.__transactionEndCallback || me.__completed || me.__transFinishedCbFired) {
|
|
6029
|
+
return;
|
|
5971
6030
|
}
|
|
6031
|
+
me.__transFinishedCbFired = true;
|
|
6032
|
+
me.__transFinishedCb(me.__errored, me.__transactionEndCallback);
|
|
6033
|
+
/* c8 ignore stop -- see comment above */
|
|
5972
6034
|
}, function (currentTask, err, done, rollback, commit) {
|
|
6035
|
+
/* 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. */
|
|
5973
6036
|
if (err) {
|
|
5974
6037
|
return true;
|
|
5975
6038
|
}
|
|
6039
|
+
/* c8 ignore stop -- see comment above */
|
|
5976
6040
|
// `readonly` transactions never hold a real SQL transaction open
|
|
5977
6041
|
// (see `WebSQLTransaction`'s constructor skipping `BEGIN;` for
|
|
5978
6042
|
// them), so there's no commit/rollback round trip to defer --
|
|
@@ -6021,6 +6085,7 @@
|
|
|
6021
6085
|
*/
|
|
6022
6086
|
function complete() {
|
|
6023
6087
|
me.__completed = true;
|
|
6088
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
6024
6089
|
if (CFG.DEBUG) {
|
|
6025
6090
|
console.log('Transaction completed');
|
|
6026
6091
|
}
|
|
@@ -6030,6 +6095,7 @@
|
|
|
6030
6095
|
me.dispatchEvent(evt);
|
|
6031
6096
|
me.__internal = false;
|
|
6032
6097
|
me.dispatchEvent(createEvent('__complete'));
|
|
6098
|
+
/* 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. */
|
|
6033
6099
|
} catch (e) {
|
|
6034
6100
|
me.__internal = false;
|
|
6035
6101
|
// An error occurred in the "oncomplete" handler.
|
|
@@ -6037,6 +6103,7 @@
|
|
|
6037
6103
|
// (this may seem odd/bad, but it's how all native IndexedDB implementations work)
|
|
6038
6104
|
me.__errored = true;
|
|
6039
6105
|
throw e;
|
|
6106
|
+
/* c8 ignore stop -- see comment above */
|
|
6040
6107
|
} finally {
|
|
6041
6108
|
activeTransactions.delete(me);
|
|
6042
6109
|
me.__storeHandles = {};
|
|
@@ -6044,10 +6111,12 @@
|
|
|
6044
6111
|
}
|
|
6045
6112
|
}
|
|
6046
6113
|
if (me.mode === 'readwrite' || me.mode === 'readonly') {
|
|
6114
|
+
/* 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. */
|
|
6047
6115
|
if (me.__transactionFinished) {
|
|
6048
6116
|
complete();
|
|
6049
6117
|
return;
|
|
6050
6118
|
}
|
|
6119
|
+
/* c8 ignore stop -- see comment above */
|
|
6051
6120
|
me.__transactionEndCallback = complete;
|
|
6052
6121
|
// The underlying SQL driver's own "queue empty" check
|
|
6053
6122
|
// (`nonstandardTransCb`, above) typically already ran and
|
|
@@ -6083,6 +6152,7 @@
|
|
|
6083
6152
|
IDBTransaction.prototype.__createRequest = function (source) {
|
|
6084
6153
|
var me = this;
|
|
6085
6154
|
var request = IDBRequest.__createInstance();
|
|
6155
|
+
/* 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. */
|
|
6086
6156
|
request.__source = source !== undefined ? source : me.db;
|
|
6087
6157
|
request.__transaction = me;
|
|
6088
6158
|
return request;
|
|
@@ -6152,9 +6222,11 @@
|
|
|
6152
6222
|
* @returns {void}
|
|
6153
6223
|
*/
|
|
6154
6224
|
IDBTransaction.prototype.__assertActive = function () {
|
|
6225
|
+
/* 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. */
|
|
6155
6226
|
if (!this.__active || !this.__handlerActive || this.__committed) {
|
|
6156
6227
|
throw createDOMException('TransactionInactiveError', 'A request was placed against a transaction which is currently not active, or which is finished');
|
|
6157
6228
|
}
|
|
6229
|
+
/* c8 ignore stop -- see comment above */
|
|
6158
6230
|
};
|
|
6159
6231
|
|
|
6160
6232
|
/**
|
|
@@ -6168,6 +6240,7 @@
|
|
|
6168
6240
|
}
|
|
6169
6241
|
};
|
|
6170
6242
|
|
|
6243
|
+
/* 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. */
|
|
6171
6244
|
/**
|
|
6172
6245
|
* @this {IDBTransactionFull}
|
|
6173
6246
|
* @returns {void}
|
|
@@ -6175,6 +6248,7 @@
|
|
|
6175
6248
|
IDBTransaction.prototype.__assertVersionChange = function () {
|
|
6176
6249
|
IDBTransaction.__assertVersionChange(this);
|
|
6177
6250
|
};
|
|
6251
|
+
/* c8 ignore stop -- see comment above */
|
|
6178
6252
|
|
|
6179
6253
|
/**
|
|
6180
6254
|
* Returns the specified object store.
|
|
@@ -6196,9 +6270,12 @@
|
|
|
6196
6270
|
throw createDOMException('NotFoundError', objectStoreName + ' is not participating in this transaction');
|
|
6197
6271
|
}
|
|
6198
6272
|
var store = me.db.__objectStores[objectStoreName];
|
|
6273
|
+
/* 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. */
|
|
6199
6274
|
if (!store) {
|
|
6200
6275
|
throw createDOMException('NotFoundError', objectStoreName + ' does not exist in ' + me.db.name);
|
|
6201
6276
|
}
|
|
6277
|
+
/* c8 ignore stop -- see comment above */
|
|
6278
|
+
|
|
6202
6279
|
if (!Object.hasOwn(me.__storeHandles, objectStoreName) ||
|
|
6203
6280
|
// These latter conditions are to allow store
|
|
6204
6281
|
// recreation to create new clone object
|
|
@@ -6217,10 +6294,12 @@
|
|
|
6217
6294
|
IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
6218
6295
|
var me = this;
|
|
6219
6296
|
logError('Error', 'An error occurred in a transaction', err);
|
|
6297
|
+
/* 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. */
|
|
6220
6298
|
if (me.__errored) {
|
|
6221
6299
|
// We've already called "onerror", "onabort", or thrown, so don't do it again.
|
|
6222
6300
|
return;
|
|
6223
6301
|
}
|
|
6302
|
+
/* c8 ignore stop -- see comment above */
|
|
6224
6303
|
me.__errored = true;
|
|
6225
6304
|
if (me.mode === 'versionchange') {
|
|
6226
6305
|
// Steps for aborting an upgrade transaction
|
|
@@ -6250,19 +6329,16 @@
|
|
|
6250
6329
|
if (err !== null) {
|
|
6251
6330
|
me.__error = err;
|
|
6252
6331
|
}
|
|
6332
|
+
|
|
6333
|
+
/* 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. */
|
|
6253
6334
|
if (me.__requestsFinished && err !== null) {
|
|
6254
6335
|
// The transaction has already completed, so we can't call "onerror" or "onabort".
|
|
6255
|
-
// So throw the error instead.
|
|
6256
|
-
// `IDBTransaction.prototype.abort`'s own `__abortTransaction(null)`
|
|
6257
|
-
// call, which now checks `__requestsFinished` itself first and
|
|
6258
|
-
// throws `InvalidStateError` synchronously before ever reaching
|
|
6259
|
-
// this point -- so this guard is just defense in depth against
|
|
6260
|
-
// `err` somehow being `null` some other way, not something this
|
|
6261
|
-
// path should see in practice.
|
|
6336
|
+
// So throw the error instead.
|
|
6262
6337
|
setTimeout(function () {
|
|
6263
6338
|
throw err;
|
|
6264
6339
|
}, 0);
|
|
6265
6340
|
}
|
|
6341
|
+
/* c8 ignore stop -- see comment above */
|
|
6266
6342
|
|
|
6267
6343
|
/**
|
|
6268
6344
|
* @param {import('websql-configurable/lib/websql/WebSQLTransaction.js').default|null} [tx]
|
|
@@ -6271,13 +6347,17 @@
|
|
|
6271
6347
|
*/
|
|
6272
6348
|
function abort(tx, errOrResult) {
|
|
6273
6349
|
if (!tx) {
|
|
6350
|
+
/* 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. */
|
|
6274
6351
|
if (CFG.DEBUG) {
|
|
6275
6352
|
console.log('Rollback not possible due to missing transaction', me);
|
|
6276
6353
|
}
|
|
6354
|
+
/* 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. */
|
|
6277
6355
|
} else if (errOrResult && 'code' in errOrResult && typeof errOrResult.code === 'number') {
|
|
6278
6356
|
if (CFG.DEBUG) {
|
|
6279
6357
|
console.log('Rollback erred; feature is probably not supported as per WebSQL', me);
|
|
6280
6358
|
}
|
|
6359
|
+
/* c8 ignore stop -- see comment above */
|
|
6360
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
6281
6361
|
} else if (CFG.DEBUG) {
|
|
6282
6362
|
console.log('Rollback succeeded', me);
|
|
6283
6363
|
}
|
|
@@ -6293,10 +6373,11 @@
|
|
|
6293
6373
|
// behaves first-in-first-out with the same timeout so we could
|
|
6294
6374
|
// just use a `forEach`.
|
|
6295
6375
|
return promises.then(function () {
|
|
6376
|
+
/* 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. */
|
|
6296
6377
|
if (!q.req) {
|
|
6297
|
-
// TS guard
|
|
6298
6378
|
throw new Error('Missing request');
|
|
6299
6379
|
}
|
|
6380
|
+
/* c8 ignore stop -- see comment above */
|
|
6300
6381
|
q.req.__done = true;
|
|
6301
6382
|
q.req.__result = undefined;
|
|
6302
6383
|
q.req.__error = createDOMException('AbortError', 'A request was aborted (an unfinished request).');
|
|
@@ -6307,10 +6388,11 @@
|
|
|
6307
6388
|
return new SyncPromise(/** @type {(resolve: (value?: unknown) => void) => void} */
|
|
6308
6389
|
function (resolve) {
|
|
6309
6390
|
setTimeout(function () {
|
|
6391
|
+
/* c8 ignore start -- Dead code: same invariant as above -- `q.req` was already confirmed truthy by the outer `.filter()` and is never reset. */
|
|
6310
6392
|
if (!q.req) {
|
|
6311
|
-
// TS guard
|
|
6312
6393
|
throw new Error('Missing request');
|
|
6313
6394
|
}
|
|
6395
|
+
/* c8 ignore stop -- see comment above */
|
|
6314
6396
|
q.req.dispatchEvent(reqEvt); // No need to catch errors
|
|
6315
6397
|
resolve();
|
|
6316
6398
|
}, 0);
|
|
@@ -6330,10 +6412,12 @@
|
|
|
6330
6412
|
releaseFinishedTransaction(me);
|
|
6331
6413
|
}, 0);
|
|
6332
6414
|
return undefined;
|
|
6415
|
+
/* 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. */
|
|
6333
6416
|
}).catch(function (err) {
|
|
6334
6417
|
console.log('Abort error');
|
|
6335
6418
|
throw err;
|
|
6336
6419
|
});
|
|
6420
|
+
/* c8 ignore stop -- see comment above */
|
|
6337
6421
|
}
|
|
6338
6422
|
me.__transFinishedCb(true, function (rollback) {
|
|
6339
6423
|
if (rollback && me.__tx) {
|
|
@@ -6341,20 +6425,24 @@
|
|
|
6341
6425
|
// rollback automatically), but for Node.js, etc., we give chance for
|
|
6342
6426
|
// manual aborts which would otherwise not work.
|
|
6343
6427
|
if (me.mode === 'readwrite') {
|
|
6428
|
+
/* 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. */
|
|
6344
6429
|
if (me.__transactionFinished) {
|
|
6345
6430
|
abort();
|
|
6346
6431
|
return;
|
|
6347
6432
|
}
|
|
6433
|
+
/* c8 ignore stop -- see comment above */
|
|
6348
6434
|
me.__transactionEndCallback = abort;
|
|
6349
6435
|
return;
|
|
6350
6436
|
}
|
|
6351
6437
|
try {
|
|
6352
6438
|
me.__tx.executeSql('ROLLBACK', [], abort, /** @type {import('websql-configurable/lib/websql/WebSQLTransaction.js').SqlErrorCallback} */abort); // Not working in some circumstances, even in Node
|
|
6439
|
+
/* c8 ignore start -- Defensive: the underlying WebSQL/SQLite driver throwing synchronously on `ROLLBACK` is not reliably reproducible without mocking the SQL layer. */
|
|
6353
6440
|
} catch (err) {
|
|
6354
6441
|
// Browser errs when transaction has ended and since it most likely already erred here,
|
|
6355
6442
|
// we call to abort
|
|
6356
6443
|
abort();
|
|
6357
6444
|
}
|
|
6445
|
+
/* c8 ignore stop -- see comment above */
|
|
6358
6446
|
} else {
|
|
6359
6447
|
abort(null, {
|
|
6360
6448
|
code: 0
|
|
@@ -6372,6 +6460,7 @@
|
|
|
6372
6460
|
if (!(me instanceof IDBTransaction)) {
|
|
6373
6461
|
throw new TypeError('Illegal invocation');
|
|
6374
6462
|
}
|
|
6463
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
6375
6464
|
if (CFG.DEBUG) {
|
|
6376
6465
|
console.log('The transaction was aborted', me);
|
|
6377
6466
|
}
|
|
@@ -6403,6 +6492,7 @@
|
|
|
6403
6492
|
if (!me.__active || !me.__handlerActive || me.__committed) {
|
|
6404
6493
|
throw createDOMException('InvalidStateError', 'Failed to execute \'commit\' on \'IDBTransaction\': The transaction is not active.');
|
|
6405
6494
|
}
|
|
6495
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
6406
6496
|
if (CFG.DEBUG) {
|
|
6407
6497
|
console.log('The transaction was explicitly committed', me);
|
|
6408
6498
|
}
|
|
@@ -6445,6 +6535,7 @@
|
|
|
6445
6535
|
};
|
|
6446
6536
|
|
|
6447
6537
|
// object store methods behave differently: see https://github.com/w3c/IndexedDB/issues/192
|
|
6538
|
+
/* 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. */
|
|
6448
6539
|
/**
|
|
6449
6540
|
*
|
|
6450
6541
|
* @param {IDBTransactionFull} tx
|
|
@@ -6460,6 +6551,7 @@
|
|
|
6460
6551
|
throw err;
|
|
6461
6552
|
}
|
|
6462
6553
|
};
|
|
6554
|
+
/* c8 ignore stop -- see comment above */
|
|
6463
6555
|
|
|
6464
6556
|
/**
|
|
6465
6557
|
*
|
|
@@ -7557,7 +7649,7 @@
|
|
|
7557
7649
|
return Number.isNaN(t) ? "NaN" : t;
|
|
7558
7650
|
},
|
|
7559
7651
|
revive: function revive(e) {
|
|
7560
|
-
return "NaN" === e ?
|
|
7652
|
+
return new Date("NaN" === e ? NaN : e);
|
|
7561
7653
|
}
|
|
7562
7654
|
}
|
|
7563
7655
|
},
|
|
@@ -8417,9 +8509,12 @@
|
|
|
8417
8509
|
}).find(function (preset) {
|
|
8418
8510
|
return preset && !Array.isArray(preset) && 'filelist' in preset;
|
|
8419
8511
|
});
|
|
8420
|
-
var origFileList = specSet && !Array.isArray(specSet) && 'filelist' in specSet ? specSet.filelist
|
|
8421
|
-
|
|
8422
|
-
var
|
|
8512
|
+
var origFileList = specSet && !Array.isArray(specSet) && 'filelist' in specSet ? specSet.filelist
|
|
8513
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */ : undefined;
|
|
8514
|
+
var origTest = origFileList && _typeof(origFileList) === 'object' && 'test' in origFileList && typeof origFileList.test === 'function' ? origFileList.test
|
|
8515
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.test` ever goes missing */ : undefined;
|
|
8516
|
+
var origRevive = origFileList && _typeof(origFileList) === 'object' && 'revive' in origFileList && typeof origFileList.revive === 'function' ? origFileList.revive
|
|
8517
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.revive` ever goes missing */ : undefined;
|
|
8423
8518
|
var customFileList = origFileList ? _objectSpread2(_objectSpread2({}, origFileList), {}, {
|
|
8424
8519
|
/**
|
|
8425
8520
|
* @param {unknown} x
|
|
@@ -8427,10 +8522,7 @@
|
|
|
8427
8522
|
* @returns {boolean}
|
|
8428
8523
|
*/
|
|
8429
8524
|
test: function test(x, state) {
|
|
8430
|
-
|
|
8431
|
-
return x instanceof FileList;
|
|
8432
|
-
}
|
|
8433
|
-
return typeof origTest === 'function' ? origTest(x, state) : false;
|
|
8525
|
+
return typeof FileList !== 'undefined' ? x instanceof FileList : typeof origTest === 'function' && origTest(x, state);
|
|
8434
8526
|
},
|
|
8435
8527
|
/**
|
|
8436
8528
|
* @param {unknown} x
|
|
@@ -8441,10 +8533,12 @@
|
|
|
8441
8533
|
if (typeof FileList !== 'undefined') {
|
|
8442
8534
|
return Reflect.construct(FileList, [x]);
|
|
8443
8535
|
}
|
|
8536
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.revive` ever goes missing */
|
|
8444
8537
|
return typeof origRevive === 'function' ? origRevive(x, state) : undefined;
|
|
8445
8538
|
}
|
|
8446
|
-
}) : undefined;
|
|
8447
|
-
var typeson = new Typeson().register([fe,
|
|
8539
|
+
}) /* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */ : undefined;
|
|
8540
|
+
var typeson = new Typeson().register([fe, /* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */
|
|
8541
|
+
customFileList ? {
|
|
8448
8542
|
filelist: customFileList
|
|
8449
8543
|
} : {}]);
|
|
8450
8544
|
|
|
@@ -8600,7 +8694,6 @@
|
|
|
8600
8694
|
* __unique: boolean,
|
|
8601
8695
|
* __objectStore: import('./IDBObjectStore.js').IDBObjectStoreFull,
|
|
8602
8696
|
* __keyPath: import('./Key.js').KeyPath,
|
|
8603
|
-
* __recreated?: boolean,
|
|
8604
8697
|
* __fetchIndexData: (
|
|
8605
8698
|
* range: Query,
|
|
8606
8699
|
* opType: "value"|"key"|"count",
|
|
@@ -8694,6 +8787,7 @@
|
|
|
8694
8787
|
storeHandle.__indexHandles[newName] = oldIndexHandle; // Ensure new reference accessible
|
|
8695
8788
|
me.__pendingName = oldName;
|
|
8696
8789
|
var colInfoToPreserveArr = [['key', 'BLOB ' + (objectStore.autoIncrement ? 'UNIQUE, inc INTEGER PRIMARY KEY AUTOINCREMENT' : 'PRIMARY KEY')], ['value', 'BLOB']].concat(
|
|
8790
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
8697
8791
|
// @ts-ignore Has numeric indexes instead of iterator; needed under some TS versions
|
|
8698
8792
|
_toConsumableArray(objectStore.indexNames).filter(function (indexName) {
|
|
8699
8793
|
return indexName !== newName;
|
|
@@ -8745,7 +8839,7 @@
|
|
|
8745
8839
|
}
|
|
8746
8840
|
});
|
|
8747
8841
|
/** @type {const} */
|
|
8748
|
-
['__pendingCreate', '__pendingDelete', '__deleted', '__originalName'
|
|
8842
|
+
['__pendingCreate', '__pendingDelete', '__deleted', '__originalName'].forEach(function (p) {
|
|
8749
8843
|
// @ts-expect-error Why is this type "never"?
|
|
8750
8844
|
idx[p] = index[p];
|
|
8751
8845
|
});
|
|
@@ -8777,11 +8871,12 @@
|
|
|
8777
8871
|
var transaction = store.transaction;
|
|
8778
8872
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
8779
8873
|
transaction.__addNonRequestToTransactionQueue(function createIndex(tx, args, success, failure) {
|
|
8780
|
-
var columnExists = idx &&
|
|
8874
|
+
var columnExists = idx && idx.__deleted; // This check must occur here rather than earlier as properties may not have been set yet otherwise
|
|
8781
8875
|
|
|
8782
8876
|
/** @type {{[key: string]: boolean}} */
|
|
8783
8877
|
var indexValues = {};
|
|
8784
8878
|
|
|
8879
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8785
8880
|
/**
|
|
8786
8881
|
* @param {WebSQLTransaction} tx
|
|
8787
8882
|
* @param {(Error & {code?: number})} err
|
|
@@ -8790,6 +8885,7 @@
|
|
|
8790
8885
|
function error(tx, err) {
|
|
8791
8886
|
failure(createDOMException('UnknownError', 'Could not create index "' + indexName + '"' + err.code + '::' + err.message, err));
|
|
8792
8887
|
}
|
|
8888
|
+
/* c8 ignore stop -- see comment above */
|
|
8793
8889
|
|
|
8794
8890
|
/**
|
|
8795
8891
|
* @param {WebSQLTransaction} tx
|
|
@@ -8839,12 +8935,6 @@
|
|
|
8839
8935
|
} else {
|
|
8840
8936
|
delete index.__pendingCreate;
|
|
8841
8937
|
delete indexHandle.__pendingCreate;
|
|
8842
|
-
if (index.__deleted) {
|
|
8843
|
-
delete index.__deleted;
|
|
8844
|
-
delete indexHandle.__deleted;
|
|
8845
|
-
index.__recreated = true;
|
|
8846
|
-
indexHandle.__recreated = true;
|
|
8847
|
-
}
|
|
8848
8938
|
indexValues = {};
|
|
8849
8939
|
success(store);
|
|
8850
8940
|
}
|
|
@@ -8853,7 +8943,7 @@
|
|
|
8853
8943
|
}, /** @type {SqlErrorCallback} */error);
|
|
8854
8944
|
}
|
|
8855
8945
|
var escapedStoreNameSQL = escapeStoreNameForSQL(storeName);
|
|
8856
|
-
var escapedIndexNameSQL = escapeIndexNameForSQL(
|
|
8946
|
+
var escapedIndexNameSQL = escapeIndexNameForSQL(indexName);
|
|
8857
8947
|
|
|
8858
8948
|
/**
|
|
8859
8949
|
* @param {WebSQLTransaction} tx
|
|
@@ -8905,6 +8995,7 @@
|
|
|
8905
8995
|
var transaction = store.transaction;
|
|
8906
8996
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
8907
8997
|
transaction.__addNonRequestToTransactionQueue(function deleteIndex(tx, args, success, failure) {
|
|
8998
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8908
8999
|
/**
|
|
8909
9000
|
* @param {WebSQLTransaction} tx
|
|
8910
9001
|
* @param {(Error & {code?: number})} err
|
|
@@ -8913,6 +9004,7 @@
|
|
|
8913
9004
|
function error(tx, err) {
|
|
8914
9005
|
failure(createDOMException('UnknownError', 'Could not delete index "' + index.name + '"', err));
|
|
8915
9006
|
}
|
|
9007
|
+
/* c8 ignore stop -- see comment above */
|
|
8916
9008
|
|
|
8917
9009
|
/**
|
|
8918
9010
|
* @returns {void}
|
|
@@ -8921,7 +9013,6 @@
|
|
|
8921
9013
|
// Update the object store's index list
|
|
8922
9014
|
IDBIndex.__updateIndexList(store, tx, function (store) {
|
|
8923
9015
|
delete index.__pendingDelete;
|
|
8924
|
-
delete index.__recreated;
|
|
8925
9016
|
index.__deleted = true;
|
|
8926
9017
|
if (indexHandle) {
|
|
8927
9018
|
indexHandle.__deleted = true;
|
|
@@ -8982,20 +9073,18 @@
|
|
|
8982
9073
|
* @param {Query} range
|
|
8983
9074
|
* @param {"value"|"key"|"count"} opType
|
|
8984
9075
|
* @param {boolean} nullDisallowed
|
|
8985
|
-
* @param {number} [count]
|
|
8986
9076
|
* @this {IDBIndexFull}
|
|
8987
9077
|
* @returns {import('./IDBRequest.js').IDBRequestFull}
|
|
8988
9078
|
*/
|
|
8989
|
-
IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed
|
|
9079
|
+
IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed) {
|
|
8990
9080
|
var me = this;
|
|
8991
|
-
if (count !== undefined) {
|
|
8992
|
-
count = enforceRange(count, 'unsigned long');
|
|
8993
|
-
}
|
|
8994
9081
|
IDBIndex.__invalidStateIfDeleted(me);
|
|
8995
9082
|
IDBObjectStore.__invalidStateIfDeleted(me.objectStore);
|
|
9083
|
+
/* c8 ignore start -- Defensive: `IDBObjectStore.__invalidStateIfDeleted` just above already throws when `me.objectStore.__deleted` is true, so this identical check can never be reached. */
|
|
8996
9084
|
if (me.objectStore.__deleted) {
|
|
8997
9085
|
throw createDOMException('InvalidStateError', "This index's object store has been deleted");
|
|
8998
9086
|
}
|
|
9087
|
+
/* c8 ignore stop -- see comment above */
|
|
8999
9088
|
IDBTransaction.__assertActive(me.objectStore.transaction);
|
|
9000
9089
|
if (nullDisallowed && isNullish(range)) {
|
|
9001
9090
|
throw createDOMException('DataError', 'No key or range was specified');
|
|
@@ -9005,7 +9094,7 @@
|
|
|
9005
9094
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
9006
9095
|
args[_key] = arguments[_key];
|
|
9007
9096
|
}
|
|
9008
|
-
executeFetchIndexData.apply(void 0,
|
|
9097
|
+
executeFetchIndexData.apply(void 0, _toConsumableArray(fetchArgs).concat(args));
|
|
9009
9098
|
}, undefined, me);
|
|
9010
9099
|
};
|
|
9011
9100
|
|
|
@@ -9164,13 +9253,16 @@
|
|
|
9164
9253
|
var colInfoToPreserve = colInfoToPreserveArr.map(function (colInfo) {
|
|
9165
9254
|
return colInfo.join(' ');
|
|
9166
9255
|
});
|
|
9256
|
+
/* 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. */
|
|
9167
9257
|
var listColInfoToPreserve = colInfoToPreserve.length ? colInfoToPreserve.join(', ') + ', ' : '';
|
|
9258
|
+
/* c8 ignore next -- Defensive: see comment above. */
|
|
9168
9259
|
var listColsToPreserve = colNamesToPreserve.length ? colNamesToPreserve.join(', ') + ', ' : '';
|
|
9169
9260
|
|
|
9170
9261
|
// We could adapt the approach at https://stackoverflow.com/a/8430746/271577
|
|
9171
9262
|
// to make the approach reusable without passing column names, but it is a bit fragile
|
|
9172
9263
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
9173
9264
|
store.transaction.__addNonRequestToTransactionQueue(function renameIndex(tx, args, success, error) {
|
|
9265
|
+
/* 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. */
|
|
9174
9266
|
/**
|
|
9175
9267
|
* @param {WebSQLTransaction} tx
|
|
9176
9268
|
* @param {(Error & {code?: number})} err
|
|
@@ -9179,6 +9271,7 @@
|
|
|
9179
9271
|
function sqlError(tx, err) {
|
|
9180
9272
|
error(err);
|
|
9181
9273
|
}
|
|
9274
|
+
/* c8 ignore stop -- see comment above */
|
|
9182
9275
|
/**
|
|
9183
9276
|
* @returns {void}
|
|
9184
9277
|
*/
|
|
@@ -9187,8 +9280,14 @@
|
|
|
9187
9280
|
cb(tx, success);
|
|
9188
9281
|
return;
|
|
9189
9282
|
}
|
|
9283
|
+
/* 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. */
|
|
9190
9284
|
success();
|
|
9191
9285
|
}
|
|
9286
|
+
/* c8 ignore stop -- see comment above */
|
|
9287
|
+
if (!CFG.useSQLiteIndexes) {
|
|
9288
|
+
finish();
|
|
9289
|
+
return;
|
|
9290
|
+
}
|
|
9192
9291
|
// See https://www.sqlite.org/lang_altertable.html#otheralter
|
|
9193
9292
|
// We don't query for indexes as we already have the info
|
|
9194
9293
|
// This approach has the advantage of auto-deleting indexes via the DROP TABLE
|
|
@@ -9212,10 +9311,6 @@
|
|
|
9212
9311
|
console.log(sql);
|
|
9213
9312
|
}
|
|
9214
9313
|
tx.executeSql(sql, [], function (tx) {
|
|
9215
|
-
if (!CFG.useSQLiteIndexes) {
|
|
9216
|
-
finish();
|
|
9217
|
-
return;
|
|
9218
|
-
}
|
|
9219
9314
|
var indexCreations = colNamesToPreserve.slice(2) // Doing `key` separately and no need for index on `value`
|
|
9220
9315
|
.map(function (escapedIndexNameSQL) {
|
|
9221
9316
|
return new SyncPromise(function (resolve, reject) {
|
|
@@ -9224,13 +9319,16 @@
|
|
|
9224
9319
|
// if (CFG.DEBUG) { console.log(sql); }
|
|
9225
9320
|
// tx.executeSql(sql, [], function () {
|
|
9226
9321
|
var sql = 'CREATE INDEX ' + escapedIndexToRecreate + ' ON ' + escapedStoreNameSQL + '(' + escapedIndexNameSQL + ')';
|
|
9322
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
9227
9323
|
if (CFG.DEBUG) {
|
|
9228
9324
|
console.log(sql);
|
|
9229
9325
|
}
|
|
9230
|
-
tx.executeSql(sql, [], resolve,
|
|
9326
|
+
tx.executeSql(sql, [], resolve, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9327
|
+
/** @type {SqlErrorCallback} */
|
|
9231
9328
|
function (tx, err) {
|
|
9232
9329
|
reject(err);
|
|
9233
|
-
}
|
|
9330
|
+
}
|
|
9331
|
+
/* c8 ignore stop -- see comment above */);
|
|
9234
9332
|
// }, function (tx, err) {
|
|
9235
9333
|
// reject(err);
|
|
9236
9334
|
// });
|
|
@@ -9248,19 +9346,25 @@
|
|
|
9248
9346
|
if (CFG.DEBUG) {
|
|
9249
9347
|
console.log(sql);
|
|
9250
9348
|
}
|
|
9251
|
-
tx.executeSql(sql, [], resolve,
|
|
9349
|
+
tx.executeSql(sql, [], resolve, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9350
|
+
/** @type {SqlErrorCallback} */
|
|
9252
9351
|
function (tx, err) {
|
|
9253
9352
|
reject(err);
|
|
9254
|
-
}
|
|
9255
|
-
|
|
9353
|
+
}
|
|
9354
|
+
/* c8 ignore stop -- see comment above */);
|
|
9355
|
+
}, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9356
|
+
/** @type {SqlErrorCallback} */
|
|
9256
9357
|
function (tx, err) {
|
|
9257
9358
|
reject(err);
|
|
9258
|
-
}
|
|
9359
|
+
}
|
|
9360
|
+
/* c8 ignore stop -- see comment above */);
|
|
9259
9361
|
}));
|
|
9260
9362
|
SyncPromise.all(indexCreations).then(finish).catch(/** @type {(reason: unknown) => PromiseLike<never>} */
|
|
9261
9363
|
error).catch(function (err) {
|
|
9364
|
+
/* c8 ignore start -- Defensive: only reached if `finish` or the outer `error` callback itself throws; not reliably reproducible. */
|
|
9262
9365
|
console.log('Index rename error');
|
|
9263
9366
|
throw err;
|
|
9367
|
+
/* c8 ignore stop -- see comment above */
|
|
9264
9368
|
});
|
|
9265
9369
|
}, /** @type {SqlErrorCallback} */sqlError);
|
|
9266
9370
|
}, /** @type {SqlErrorCallback} */sqlError);
|
|
@@ -9289,7 +9393,6 @@
|
|
|
9289
9393
|
/* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
|
|
9290
9394
|
|
|
9291
9395
|
/**
|
|
9292
|
-
* @param {number|null} count
|
|
9293
9396
|
* @param {boolean} unboundedDisallowed
|
|
9294
9397
|
* @param {IDBIndexFull} index
|
|
9295
9398
|
* @param {boolean} hasKey
|
|
@@ -9306,12 +9409,9 @@
|
|
|
9306
9409
|
* @param {(tx: WebSQLTransaction, err: (Error & {code?: number})) => void} error
|
|
9307
9410
|
* @returns {void}
|
|
9308
9411
|
*/
|
|
9309
|
-
function executeFetchIndexData(
|
|
9412
|
+
function executeFetchIndexData(unboundedDisallowed, index, hasKey, range, opType, multiChecks, sql, sqlValues, tx, args, success, error) {
|
|
9310
9413
|
if (unboundedDisallowed) {
|
|
9311
|
-
|
|
9312
|
-
}
|
|
9313
|
-
if (count) {
|
|
9314
|
-
sql.push('LIMIT', String(count));
|
|
9414
|
+
sql.push('LIMIT', '1');
|
|
9315
9415
|
}
|
|
9316
9416
|
var isCount = opType === 'count';
|
|
9317
9417
|
if (CFG.DEBUG) {
|
|
@@ -9349,41 +9449,48 @@
|
|
|
9349
9449
|
var escapedIndexNameForKeyCol = escapeIndexNameForSQLKeyColumn(index.name);
|
|
9350
9450
|
var encodedKey = _encode(range, index.multiEntry);
|
|
9351
9451
|
var _loop = function _loop() {
|
|
9352
|
-
|
|
9353
|
-
|
|
9354
|
-
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9361
|
-
|
|
9362
|
-
|
|
9363
|
-
|
|
9364
|
-
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
record = row;
|
|
9372
|
-
} else if (!hasKey && !multiChecks) {
|
|
9373
|
-
if (rowKey !== undefined) {
|
|
9374
|
-
recordCount += Array.isArray(rowKey) ? rowKey.length : 1;
|
|
9452
|
+
var row = /** @type {{key: string, value: string, [k: string]: string}} */data.rows.item(i);
|
|
9453
|
+
var rowKey = /** @type {import('./Key.js').ValueTypeArray} */
|
|
9454
|
+
_decode(row[escapedIndexNameForKeyCol]);
|
|
9455
|
+
var record;
|
|
9456
|
+
if (hasKey && (multiChecks && /** @type {import('./Key.js').ValueType[]} */range.some(
|
|
9457
|
+
/**
|
|
9458
|
+
* @param {import('./Key.js').ValueType} check
|
|
9459
|
+
* @returns {boolean}
|
|
9460
|
+
*/
|
|
9461
|
+
function (check) {
|
|
9462
|
+
return rowKey.includes(check);
|
|
9463
|
+
}) ||
|
|
9464
|
+
// More precise than our SQL
|
|
9465
|
+
isMultiEntryMatch(
|
|
9466
|
+
// Added `JSON.stringify` as was having problems with
|
|
9467
|
+
// `JSON.stringify` encoding added to nested
|
|
9468
|
+
// array keys
|
|
9469
|
+
JSON.stringify(encodedKey).slice(1, -1), row[escapedIndexNameForKeyCol]))) {
|
|
9470
|
+
recordCount++;
|
|
9375
9471
|
record = row;
|
|
9472
|
+
} else if (!hasKey && !multiChecks) {
|
|
9473
|
+
if (rowKey !== undefined) {
|
|
9474
|
+
recordCount += Array.isArray(rowKey) ? rowKey.length : 1;
|
|
9475
|
+
record = row;
|
|
9476
|
+
}
|
|
9376
9477
|
}
|
|
9377
|
-
|
|
9378
|
-
|
|
9478
|
+
/* 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. */
|
|
9479
|
+
if (!record) {
|
|
9480
|
+
return 0; // continue
|
|
9481
|
+
}
|
|
9482
|
+
/* c8 ignore stop -- see comment above */
|
|
9483
|
+
|
|
9379
9484
|
records.push(decode$1(record));
|
|
9380
9485
|
if (unboundedDisallowed) {
|
|
9381
9486
|
return 1; // break
|
|
9382
9487
|
}
|
|
9383
|
-
}
|
|
9384
|
-
|
|
9488
|
+
},
|
|
9489
|
+
_ret;
|
|
9385
9490
|
for (var i = 0; i < data.rows.length; i++) {
|
|
9386
|
-
|
|
9491
|
+
_ret = _loop();
|
|
9492
|
+
if (_ret === 0) continue;
|
|
9493
|
+
if (_ret === 1) break;
|
|
9387
9494
|
}
|
|
9388
9495
|
} else {
|
|
9389
9496
|
for (var _i = 0; _i < data.rows.length; _i++) {
|
|
@@ -9397,8 +9504,16 @@
|
|
|
9397
9504
|
if (isCount) {
|
|
9398
9505
|
success(recordCount);
|
|
9399
9506
|
} else if (recordCount === 0) {
|
|
9507
|
+
// `unboundedDisallowed` is always `true` here: this function is only reached (for
|
|
9508
|
+
// non-`count` `opType`s) via `get`/`getKey`, which always pass `nullDisallowed: true`
|
|
9509
|
+
// through as `unboundedDisallowed`. `getAll`/`getAllKeys`/`getAllRecords` use a
|
|
9510
|
+
// different (cursor-based) code path, so the `unboundedDisallowed`-`false` case
|
|
9511
|
+
// (returning `[]` here) is unreachable given current callers.
|
|
9512
|
+
/* c8 ignore next -- see comment above */
|
|
9400
9513
|
success(unboundedDisallowed ? undefined : []);
|
|
9401
9514
|
} else {
|
|
9515
|
+
// `unboundedDisallowed` is always `true` here; see comment above.
|
|
9516
|
+
/* c8 ignore next -- see comment above */
|
|
9402
9517
|
success(unboundedDisallowed ? records[0] : records);
|
|
9403
9518
|
}
|
|
9404
9519
|
}, /** @type {SqlErrorCallback} */error);
|
|
@@ -9642,6 +9757,7 @@
|
|
|
9642
9757
|
tx.executeSql(sql, sqlValues, function (tx) {
|
|
9643
9758
|
// This SQL preserves indexes per https://www.sqlite.org/lang_altertable.html
|
|
9644
9759
|
var sql = 'ALTER TABLE ' + escapeStoreNameForSQL(oldName) + ' RENAME TO ' + escapeStoreNameForSQL(name);
|
|
9760
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG` while renaming a store. */
|
|
9645
9761
|
if (CFG.DEBUG) {
|
|
9646
9762
|
console.log(sql);
|
|
9647
9763
|
}
|
|
@@ -9650,8 +9766,10 @@
|
|
|
9650
9766
|
success();
|
|
9651
9767
|
});
|
|
9652
9768
|
}, function (tx, err) {
|
|
9769
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9653
9770
|
error(err);
|
|
9654
9771
|
return false;
|
|
9772
|
+
/* c8 ignore stop -- see comment above */
|
|
9655
9773
|
});
|
|
9656
9774
|
});
|
|
9657
9775
|
}
|
|
@@ -9725,6 +9843,7 @@
|
|
|
9725
9843
|
storeHandles[storeName] = IDBObjectStore.__clone(store, transaction);
|
|
9726
9844
|
}
|
|
9727
9845
|
transaction.__addNonRequestToTransactionQueue(function createObjectStore(tx, args, success, failure) {
|
|
9846
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9728
9847
|
/**
|
|
9729
9848
|
* @param {WebSQLTransaction} tx
|
|
9730
9849
|
* @param {(Error & {code?: number})} [err]
|
|
@@ -9737,6 +9856,8 @@
|
|
|
9737
9856
|
failure(createDOMException('UnknownError', 'Could not create object store "' + storeName + '"', err));
|
|
9738
9857
|
return false;
|
|
9739
9858
|
}
|
|
9859
|
+
/* c8 ignore stop -- see comment above */
|
|
9860
|
+
|
|
9740
9861
|
var escapedStoreNameSQL = escapeStoreNameForSQL(storeName);
|
|
9741
9862
|
// key INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE
|
|
9742
9863
|
var sql = ['CREATE TABLE', escapedStoreNameSQL, '(key BLOB', store.autoIncrement ? 'UNIQUE, inc INTEGER PRIMARY KEY AUTOINCREMENT' : 'PRIMARY KEY', ', value BLOB)'].join(' ');
|
|
@@ -9791,6 +9912,7 @@
|
|
|
9791
9912
|
|
|
9792
9913
|
// Remove the object store from WebSQL
|
|
9793
9914
|
transaction.__addNonRequestToTransactionQueue(function deleteObjectStore(tx, args, success, failure) {
|
|
9915
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9794
9916
|
/**
|
|
9795
9917
|
* @param {WebSQLTransaction} tx
|
|
9796
9918
|
* @param {(Error & {code?: number})} [err]
|
|
@@ -9803,6 +9925,8 @@
|
|
|
9803
9925
|
failure(createDOMException('UnknownError', 'Could not delete ObjectStore', err));
|
|
9804
9926
|
return false;
|
|
9805
9927
|
}
|
|
9928
|
+
/* c8 ignore stop -- see comment above */
|
|
9929
|
+
|
|
9806
9930
|
tx.executeSql('SELECT "name" FROM __sys__ WHERE "name" = ?', [escapeSQLiteStatement(store.__currentName)], function (tx, data) {
|
|
9807
9931
|
if (data.rows.length > 0) {
|
|
9808
9932
|
tx.executeSql('DROP TABLE ' + escapeStoreNameForSQL(store.__currentName), [], function () {
|
|
@@ -9982,13 +10106,15 @@
|
|
|
9982
10106
|
return;
|
|
9983
10107
|
}
|
|
9984
10108
|
var indexKeyValue = indexKey.value;
|
|
10109
|
+
/* 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. */
|
|
9985
10110
|
if (indexKeyValue === undefined) {
|
|
9986
10111
|
resolve(undefined);
|
|
9987
10112
|
return;
|
|
9988
10113
|
}
|
|
10114
|
+
/* c8 ignore stop -- see comment above */
|
|
9989
10115
|
var multiCheck = index.multiEntry && Array.isArray(indexKeyValue);
|
|
9990
10116
|
var fetchArgs = buildFetchIndexDataSQL(true, index, indexKeyValue, 'key', multiCheck);
|
|
9991
|
-
executeFetchIndexData.apply(void 0,
|
|
10117
|
+
executeFetchIndexData.apply(void 0, _toConsumableArray(fetchArgs).concat([tx, null, function success(key) {
|
|
9992
10118
|
if (key === undefined || excludeKey !== undefined && cmp(/** @type {import('./Key.js').Key} */key, excludeKey) === 0) {
|
|
9993
10119
|
resolve(undefined);
|
|
9994
10120
|
return;
|
|
@@ -10068,16 +10194,18 @@
|
|
|
10068
10194
|
* @returns {void}
|
|
10069
10195
|
*/
|
|
10070
10196
|
function setIndexInfo(index) {
|
|
10197
|
+
/* 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. */
|
|
10071
10198
|
if (indexKeyValue === undefined) {
|
|
10072
10199
|
return;
|
|
10073
10200
|
}
|
|
10201
|
+
/* c8 ignore stop -- see comment above */
|
|
10074
10202
|
paramMap[index.__currentName] = /** @type {string} */
|
|
10075
10203
|
_encode(indexKeyValue, index.multiEntry);
|
|
10076
10204
|
}
|
|
10077
10205
|
if (index.unique) {
|
|
10078
10206
|
var multiCheck = index.multiEntry && Array.isArray(indexKeyValue);
|
|
10079
10207
|
var fetchArgs = buildFetchIndexDataSQL(true, index, indexKeyValue, 'key', multiCheck);
|
|
10080
|
-
executeFetchIndexData.apply(void 0,
|
|
10208
|
+
executeFetchIndexData.apply(void 0, _toConsumableArray(fetchArgs).concat([tx, null, function success(key) {
|
|
10081
10209
|
if (key === undefined) {
|
|
10082
10210
|
setIndexInfo(index);
|
|
10083
10211
|
resolve(undefined);
|
|
@@ -10168,6 +10296,7 @@
|
|
|
10168
10296
|
_me$__validateKeyAndV2 = _slicedToArray(_me$__validateKeyAndV, 2),
|
|
10169
10297
|
ky = _me$__validateKeyAndV2[0],
|
|
10170
10298
|
clonedValue = _me$__validateKeyAndV2[1];
|
|
10299
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
10171
10300
|
// @ts-ignore -- Private API
|
|
10172
10301
|
IDBObjectStore.__storingRecordObjectStore(request, me, true, clonedValue, true, ky);
|
|
10173
10302
|
return request;
|
|
@@ -10199,6 +10328,7 @@
|
|
|
10199
10328
|
_me$__validateKeyAndV4 = _slicedToArray(_me$__validateKeyAndV3, 2),
|
|
10200
10329
|
ky = _me$__validateKeyAndV4[0],
|
|
10201
10330
|
clonedValue = _me$__validateKeyAndV4[1];
|
|
10331
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
10202
10332
|
// @ts-ignore -- Private API
|
|
10203
10333
|
IDBObjectStore.__storingRecordObjectStore(request, me, true, clonedValue, false, ky);
|
|
10204
10334
|
return request;
|
|
@@ -10225,8 +10355,10 @@
|
|
|
10225
10355
|
}
|
|
10226
10356
|
cb(tx);
|
|
10227
10357
|
}, function (tx, err) {
|
|
10358
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
10228
10359
|
error(err);
|
|
10229
10360
|
return false;
|
|
10361
|
+
/* c8 ignore stop -- see comment above */
|
|
10230
10362
|
});
|
|
10231
10363
|
};
|
|
10232
10364
|
|
|
@@ -10335,16 +10467,20 @@
|
|
|
10335
10467
|
return;
|
|
10336
10468
|
}
|
|
10337
10469
|
ret = getKey ? _decode(unescapeSQLiteResponse(/** @type {{key: string}} */data.rows.item(0).key), false) : decode(unescapeSQLiteResponse(/** @type {{value: string}} */data.rows.item(0).value));
|
|
10470
|
+
/* 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. */
|
|
10338
10471
|
} catch (e) {
|
|
10339
10472
|
// If no result is returned, or error occurs when parsing JSON
|
|
10340
10473
|
if (CFG.DEBUG) {
|
|
10341
10474
|
console.log(e);
|
|
10342
10475
|
}
|
|
10343
10476
|
}
|
|
10477
|
+
/* c8 ignore stop -- see comment above */
|
|
10344
10478
|
success(ret);
|
|
10345
10479
|
}, function (tx, err) {
|
|
10480
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
10346
10481
|
error(err);
|
|
10347
10482
|
return false;
|
|
10483
|
+
/* c8 ignore stop -- see comment above */
|
|
10348
10484
|
});
|
|
10349
10485
|
}, undefined, me);
|
|
10350
10486
|
};
|
|
@@ -10456,8 +10592,10 @@
|
|
|
10456
10592
|
});
|
|
10457
10593
|
success();
|
|
10458
10594
|
}, function (tx, err) {
|
|
10595
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
10459
10596
|
error(err);
|
|
10460
10597
|
return false;
|
|
10598
|
+
/* c8 ignore stop -- see comment above */
|
|
10461
10599
|
});
|
|
10462
10600
|
}, undefined, me);
|
|
10463
10601
|
};
|
|
@@ -10485,8 +10623,10 @@
|
|
|
10485
10623
|
});
|
|
10486
10624
|
success();
|
|
10487
10625
|
}, function (tx, err) {
|
|
10626
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
10488
10627
|
error(err);
|
|
10489
10628
|
return false;
|
|
10629
|
+
/* c8 ignore stop -- see comment above */
|
|
10490
10630
|
});
|
|
10491
10631
|
}, undefined, me);
|
|
10492
10632
|
};
|
|
@@ -10821,7 +10961,7 @@
|
|
|
10821
10961
|
if (keyPath !== null && !isValidKeyPath(keyPath)) {
|
|
10822
10962
|
throw createDOMException('SyntaxError', 'The keyPath argument contains an invalid key path.');
|
|
10823
10963
|
}
|
|
10824
|
-
if (Object.hasOwn(this.__objectStores, storeName) && !this.__objectStores[storeName].__pendingDelete) {
|
|
10964
|
+
if (Object.hasOwn(this.__objectStores, storeName) && !this.__objectStores[storeName].__pendingDelete && !this.__objectStores[storeName].__deleted) {
|
|
10825
10965
|
throw createDOMException('ConstraintError', 'Object store "' + storeName + '" already exists in ' + this.name);
|
|
10826
10966
|
}
|
|
10827
10967
|
var autoInc = createOptions.autoIncrement;
|
|
@@ -10970,7 +11110,6 @@
|
|
|
10970
11110
|
}
|
|
10971
11111
|
};
|
|
10972
11112
|
|
|
10973
|
-
// Todo __forceClose: Add tests for `__forceClose`
|
|
10974
11113
|
/**
|
|
10975
11114
|
*
|
|
10976
11115
|
* @param {string} msg
|
|
@@ -10979,23 +11118,39 @@
|
|
|
10979
11118
|
*/
|
|
10980
11119
|
IDBDatabase.prototype.__forceClose = function (msg) {
|
|
10981
11120
|
var me = this;
|
|
11121
|
+
// `close()` (below) resets `me.__transactions` to `[]`, so the
|
|
11122
|
+
// transactions to abort -- and the total count the completion check
|
|
11123
|
+
// below needs -- must be captured before calling it, not read back off
|
|
11124
|
+
// `me.__transactions` afterward.
|
|
11125
|
+
var transactions = me.__transactions;
|
|
10982
11126
|
me.close();
|
|
11127
|
+
|
|
11128
|
+
/**
|
|
11129
|
+
* @returns {void}
|
|
11130
|
+
*/
|
|
11131
|
+
function dispatchClose() {
|
|
11132
|
+
// Todo __forceClose: unblock any pending `upgradeneeded` or `deleteDatabase` calls
|
|
11133
|
+
var evt = createEvent('close');
|
|
11134
|
+
setTimeout(function () {
|
|
11135
|
+
me.dispatchEvent(evt);
|
|
11136
|
+
}, 0);
|
|
11137
|
+
}
|
|
11138
|
+
if (!transactions.length) {
|
|
11139
|
+
dispatchClose();
|
|
11140
|
+
return;
|
|
11141
|
+
}
|
|
10983
11142
|
var ct = 0;
|
|
10984
|
-
|
|
11143
|
+
transactions.forEach(function (trans) {
|
|
10985
11144
|
// eslint-disable-next-line camelcase -- Clear API
|
|
10986
11145
|
trans.on__abort = function () {
|
|
10987
11146
|
ct++;
|
|
10988
|
-
if (ct
|
|
10989
|
-
|
|
10990
|
-
var evt = createEvent('close');
|
|
10991
|
-
setTimeout(function () {
|
|
10992
|
-
me.dispatchEvent(evt);
|
|
10993
|
-
}, 0);
|
|
11147
|
+
if (ct !== transactions.length) {
|
|
11148
|
+
return;
|
|
10994
11149
|
}
|
|
11150
|
+
dispatchClose();
|
|
10995
11151
|
};
|
|
10996
11152
|
trans.__abortTransaction(createDOMException('AbortError', 'The connection was force-closed: ' + (msg || '')));
|
|
10997
11153
|
});
|
|
10998
|
-
me.__transactions = [];
|
|
10999
11154
|
};
|
|
11000
11155
|
/* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
|
|
11001
11156
|
defineOuterInterface(IDBDatabase.prototype, listeners);
|
|
@@ -11162,6 +11317,7 @@
|
|
|
11162
11317
|
return undefined;
|
|
11163
11318
|
}
|
|
11164
11319
|
var e = /** @type {Event & IDBVersionChangeEvent} */
|
|
11320
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11165
11321
|
// @ts-ignore It's ok; needed under some TS versions
|
|
11166
11322
|
new IDBVersionChangeEvent('versionchange', {
|
|
11167
11323
|
oldVersion: oldVersion,
|
|
@@ -11209,6 +11365,7 @@
|
|
|
11209
11365
|
}
|
|
11210
11366
|
};
|
|
11211
11367
|
var e = /** @type {Event & IDBVersionChangeEvent} */
|
|
11368
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11212
11369
|
// @ts-ignore It's ok; needed under some TS versions
|
|
11213
11370
|
new IDBVersionChangeEvent('blocked', {
|
|
11214
11371
|
oldVersion: oldVersion,
|
|
@@ -11269,6 +11426,13 @@
|
|
|
11269
11426
|
|
|
11270
11427
|
/** @type {import('websql-configurable/lib/websql/WebSQLDatabase.js').default} */
|
|
11271
11428
|
var sysdb;
|
|
11429
|
+
// Tracks which `CFG.memoryDatabase` value `sysdb` was opened against, so a
|
|
11430
|
+
// later change to that config (e.g. toggling in-memory mode on and back
|
|
11431
|
+
// off) causes `sysdb` to be recreated for the new setting rather than
|
|
11432
|
+
// staying pinned, forever, to whatever it was the first time any database
|
|
11433
|
+
// was created in the process.
|
|
11434
|
+
/** @type {string|null|undefined} */
|
|
11435
|
+
var sysdbMemoryDatabaseSetting;
|
|
11272
11436
|
var nameCounter = 0;
|
|
11273
11437
|
|
|
11274
11438
|
/**
|
|
@@ -11350,12 +11514,20 @@
|
|
|
11350
11514
|
function cleanupDatabaseResources(__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError) {
|
|
11351
11515
|
var useMemoryDatabase = typeof CFG.memoryDatabase === 'string';
|
|
11352
11516
|
if (useMemoryDatabase) {
|
|
11517
|
+
/* c8 ignore start -- Defensive: only reachable if `websqlDBCache[name]`
|
|
11518
|
+
was initialized as an empty placeholder by `open()`'s connection-queue
|
|
11519
|
+
setup (`addRequestToConnectionQueue`, above `openDB`) but never
|
|
11520
|
+
populated with an actual instance -- e.g. `__openDatabase` throwing
|
|
11521
|
+
after a `dbVersions` row already existed for `name` from an earlier,
|
|
11522
|
+
successful `open()` -- or if `name` was never added to the cache at
|
|
11523
|
+
all. Not reachable via normal, non-tampered API usage. */
|
|
11353
11524
|
var latestSQLiteDBCached = Object.hasOwn(websqlDBCache, name) ? getLatestCachedWebSQLDB(name) : null;
|
|
11354
11525
|
if (!latestSQLiteDBCached) {
|
|
11355
11526
|
console.warn('Could not find a memory database instance to delete.');
|
|
11356
11527
|
databaseDeleted();
|
|
11357
11528
|
return;
|
|
11358
11529
|
}
|
|
11530
|
+
/* c8 ignore stop -- see comment above */
|
|
11359
11531
|
var _sqliteDB = latestSQLiteDBCached._db;
|
|
11360
11532
|
if (!_sqliteDB || !_sqliteDB.close) {
|
|
11361
11533
|
console.error('The `openDatabase` implementation does not have the expected `._db.close` method for closing the database');
|
|
@@ -11409,15 +11581,24 @@
|
|
|
11409
11581
|
tables.item(i).name)), [], function () {
|
|
11410
11582
|
deleteTables(i + 1);
|
|
11411
11583
|
}, function () {
|
|
11584
|
+
/* c8 ignore start -- Defensive: continues deleting the rest
|
|
11585
|
+
even if this specific store's table is already gone (e.g.
|
|
11586
|
+
duplicate `__sys__` rows for the same escaped table name, or
|
|
11587
|
+
external tampering); not reachable via normal API usage. */
|
|
11412
11588
|
deleteTables(i + 1);
|
|
11413
11589
|
return false;
|
|
11590
|
+
/* c8 ignore stop -- see comment above */
|
|
11414
11591
|
});
|
|
11415
11592
|
}
|
|
11416
11593
|
})(0);
|
|
11417
11594
|
}, function () {
|
|
11418
|
-
|
|
11595
|
+
/* c8 ignore start -- `__sys__` is always created by `openDB` before this
|
|
11596
|
+
database's `dbVersions` row (a prerequisite for reaching this code at
|
|
11597
|
+
all) is ever inserted; only reachable if the file was tampered with/
|
|
11598
|
+
removed externally afterward. */
|
|
11419
11599
|
databaseDeleted();
|
|
11420
11600
|
return false;
|
|
11601
|
+
/* c8 ignore stop -- see comment above */
|
|
11421
11602
|
});
|
|
11422
11603
|
});
|
|
11423
11604
|
}
|
|
@@ -11448,9 +11629,11 @@
|
|
|
11448
11629
|
}
|
|
11449
11630
|
failure(er);
|
|
11450
11631
|
}
|
|
11451
|
-
if (sysdb) {
|
|
11632
|
+
if (sysdb && sysdbMemoryDatabaseSetting === CFG.memoryDatabase) {
|
|
11452
11633
|
success();
|
|
11453
11634
|
} else {
|
|
11635
|
+
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Needed
|
|
11636
|
+
sysdbMemoryDatabaseSetting = CFG.memoryDatabase;
|
|
11454
11637
|
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Necessary?
|
|
11455
11638
|
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);
|
|
11456
11639
|
sysdb.transaction(function (systx) {
|
|
@@ -11630,6 +11813,17 @@
|
|
|
11630
11813
|
* @returns {void}
|
|
11631
11814
|
*/
|
|
11632
11815
|
var sysdbFinishedCb = function sysdbFinishedCb(systx, err, cb) {
|
|
11816
|
+
/* c8 ignore start -- This initial definition is always
|
|
11817
|
+
superseded before ever being invoked: the `sysdb.transaction(...)`
|
|
11818
|
+
call below always reaches its `nonstandardTransCb` (4th arg)
|
|
11819
|
+
after this same SQL batch finishes running (since `dbCreateError`
|
|
11820
|
+
always reports errors as "handled" and this call site is never
|
|
11821
|
+
a `readTransaction`), which unconditionally reassigns
|
|
11822
|
+
`sysdbFinishedCb` to a version using the library's own
|
|
11823
|
+
`rollback`/`commit` -- well before any real invocation from
|
|
11824
|
+
`on__beforecomplete`/`on__preabort`/`on__abort` below (those only
|
|
11825
|
+
fire once the upgrade transaction itself later completes/aborts).
|
|
11826
|
+
Kept as a defensive fallback in case that invariant ever changes. */
|
|
11633
11827
|
if (err) {
|
|
11634
11828
|
/**
|
|
11635
11829
|
* @param {unknown} [errorToShow]
|
|
@@ -11678,6 +11872,7 @@
|
|
|
11678
11872
|
}
|
|
11679
11873
|
// In browser, should auto-commit
|
|
11680
11874
|
cb(); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11875
|
+
/* c8 ignore stop -- see comment above */
|
|
11681
11876
|
};
|
|
11682
11877
|
sysdb.transaction(function (systx) {
|
|
11683
11878
|
/**
|
|
@@ -11685,6 +11880,7 @@
|
|
|
11685
11880
|
*/
|
|
11686
11881
|
function versionSet() {
|
|
11687
11882
|
var e = /** @type {import('eventtargeter').EventWithProps & Event & IDBVersionChangeEvent} */
|
|
11883
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11688
11884
|
// @ts-ignore It's ok; needed under some TS versions
|
|
11689
11885
|
new IDBVersionChangeEvent('upgradeneeded', {
|
|
11690
11886
|
oldVersion: oldVersion,
|
|
@@ -11810,9 +12006,17 @@
|
|
|
11810
12006
|
// eslint-disable-next-line camelcase -- Clear API
|
|
11811
12007
|
req.transaction.on__complete = function () {
|
|
11812
12008
|
var pos = connection.__transactions.indexOf(req.transaction);
|
|
12009
|
+
// `req.transaction` (the versionchange transaction) is created
|
|
12010
|
+
// directly via `IDBTransaction.__createInstance` above, never
|
|
12011
|
+
// via `IDBDatabase.prototype.transaction()` (the only place
|
|
12012
|
+
// that pushes onto `connection.__transactions`), so `pos` is
|
|
12013
|
+
// always -1 here.
|
|
12014
|
+
/* c8 ignore start -- see comment above */
|
|
11813
12015
|
if (pos !== -1) {
|
|
11814
12016
|
connection.__transactions.splice(pos, 1);
|
|
11815
12017
|
}
|
|
12018
|
+
/* c8 ignore stop -- see comment above */
|
|
12019
|
+
|
|
11816
12020
|
if (/** @type {import('./IDBDatabase.js').IDBDatabaseFull} */req.__result.__closePending) {
|
|
11817
12021
|
req.__transaction = null;
|
|
11818
12022
|
var err = createDOMException('AbortError', 'The connection has been closed.');
|
|
@@ -11848,9 +12052,16 @@
|
|
|
11848
12052
|
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [version, sqlSafeName], versionSet, dbCreateError);
|
|
11849
12053
|
}
|
|
11850
12054
|
}, dbCreateError, undefined, function (currentTask, err, done, rollback, commit) {
|
|
12055
|
+
// Defensive fallback, not reachable in practice: same reasoning
|
|
12056
|
+
// as `deleteDatabase`'s own `nonstandardTransCb` below
|
|
12057
|
+
// (`currentTask.readOnly` is always false here, and
|
|
12058
|
+
// `dbCreateError` always returns `false`, so `err` is never
|
|
12059
|
+
// truthy either).
|
|
12060
|
+
/* c8 ignore start -- see comment above */
|
|
11851
12061
|
if (currentTask.readOnly || err) {
|
|
11852
12062
|
return true;
|
|
11853
12063
|
}
|
|
12064
|
+
/* c8 ignore stop -- see comment above */
|
|
11854
12065
|
sysdbFinishedCb = function sysdbFinishedCb(systx, err, cb) {
|
|
11855
12066
|
if (err) {
|
|
11856
12067
|
rollback(err,
|
|
@@ -11865,7 +12076,17 @@
|
|
|
11865
12076
|
} else {
|
|
11866
12077
|
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [oldVersion, sqlSafeName]);
|
|
11867
12078
|
}
|
|
11868
|
-
},
|
|
12079
|
+
},
|
|
12080
|
+
// Deeply-nested defensive path: only reached if
|
|
12081
|
+
// the *revert* SQL (undoing the `dbVersions`
|
|
12082
|
+
// INSERT/UPDATE after the original version-
|
|
12083
|
+
// upgrade itself already failed) fails a
|
|
12084
|
+
// *second* time. Not feasibly triggerable
|
|
12085
|
+
// without fault-injecting the underlying SQL
|
|
12086
|
+
// driver on this specific, already-failing
|
|
12087
|
+
// revert statement.
|
|
12088
|
+
function (sqlErr) {
|
|
12089
|
+
/* c8 ignore next 2 -- see comment above */
|
|
11869
12090
|
isRevertingSysdb = false;
|
|
11870
12091
|
cb(sqlErr); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11871
12092
|
}, function () {
|
|
@@ -11881,8 +12102,20 @@
|
|
|
11881
12102
|
});
|
|
11882
12103
|
return undefined;
|
|
11883
12104
|
}).catch(function (err) {
|
|
12105
|
+
/* c8 ignore start -- Purely defensive: nothing in
|
|
12106
|
+
`triggerAnyVersionChangeAndBlockedEvents`'s promise chain
|
|
12107
|
+
(or this `.then()` continuation above) ever rejects/throws
|
|
12108
|
+
under any reachable application-level condition -- all of
|
|
12109
|
+
its continuations resolve cleanly, and its `dispatchEvent`
|
|
12110
|
+
calls are deliberately fire-and-forget ("No need to catch
|
|
12111
|
+
errors"), running inside a `setTimeout` where a listener
|
|
12112
|
+
throwing becomes an uncaught exception in that macrotask
|
|
12113
|
+
rather than a promise rejection here. This exists solely
|
|
12114
|
+
to surface a truly-unexpected internal bug via the console
|
|
12115
|
+
before rethrowing, not to handle a real, testable error path. */
|
|
11884
12116
|
console.log('Error within `triggerAnyVersionChangeAndBlockedEvents`');
|
|
11885
12117
|
throw err;
|
|
12118
|
+
/* c8 ignore stop -- see comment above */
|
|
11886
12119
|
});
|
|
11887
12120
|
} else {
|
|
11888
12121
|
finishRequest();
|
|
@@ -11910,11 +12143,19 @@
|
|
|
11910
12143
|
if ((useMemoryDatabase || useDatabaseCache) && Object.hasOwn(websqlDBCache, name) && Object.hasOwn(websqlDBCache[name], version)) {
|
|
11911
12144
|
db = websqlDBCache[name][version];
|
|
11912
12145
|
} else {
|
|
11913
|
-
db = /** @type {DatabaseFull} */me.__openDatabase(useMemoryDatabase ? CFG.memoryDatabase : joinPath(CFG.databaseBasePath || '', escapedDatabaseName), '1', name, CFG.DEFAULT_DB_SIZE);
|
|
12146
|
+
db = /** @type {DatabaseFull} */me.__openDatabase(useMemoryDatabase ? (/** @type {string} */CFG.memoryDatabase) : joinPath(CFG.databaseBasePath || '', escapedDatabaseName), '1', name, CFG.DEFAULT_DB_SIZE);
|
|
11914
12147
|
if (useDatabaseCache) {
|
|
12148
|
+
/* c8 ignore start -- Defensive: by the time `openDB` runs,
|
|
12149
|
+
`websqlDBCache[name]` has always already been created by
|
|
12150
|
+
`addRequestToConnectionQueue`'s own callback above (guarded
|
|
12151
|
+
by this same `useDatabaseCache` condition), which always
|
|
12152
|
+
runs first and unconditionally ensures the entry exists
|
|
12153
|
+
before ever calling `openDB`. Kept as a safety net in case
|
|
12154
|
+
that invariant ever changes. */
|
|
11915
12155
|
if (!Object.hasOwn(websqlDBCache, name)) {
|
|
11916
12156
|
websqlDBCache[name] = {};
|
|
11917
12157
|
}
|
|
12158
|
+
/* c8 ignore stop -- see comment above */
|
|
11918
12159
|
websqlDBCache[name][version] = db;
|
|
11919
12160
|
}
|
|
11920
12161
|
}
|
|
@@ -12065,6 +12306,7 @@
|
|
|
12065
12306
|
req.__result = undefined;
|
|
12066
12307
|
req.__done = true;
|
|
12067
12308
|
var e = /** @type {Event & IDBVersionChangeEvent} */
|
|
12309
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
12068
12310
|
// @ts-ignore It's ok; needed under some TS versions
|
|
12069
12311
|
new IDBVersionChangeEvent('success', {
|
|
12070
12312
|
oldVersion: version,
|
|
@@ -12107,9 +12349,23 @@
|
|
|
12107
12349
|
cleanupDatabaseResources(me.__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError);
|
|
12108
12350
|
}, dbError);
|
|
12109
12351
|
}, dbError, undefined, function (currentTask, err, done, rollback, commit) {
|
|
12352
|
+
/* c8 ignore start -- Defensive fallback, not reachable in
|
|
12353
|
+
practice: `currentTask.readOnly` is always `false` here
|
|
12354
|
+
(this callback is only ever attached to the writable
|
|
12355
|
+
`sysdb.transaction(...)` call above, never to a
|
|
12356
|
+
`sysdb.readTransaction(...)`), and `err` can only be
|
|
12357
|
+
truthy if the `DELETE FROM dbVersions` statement's own
|
|
12358
|
+
error callback (`dbError`) reports the failure back to
|
|
12359
|
+
`websql-configurable` as unhandled -- but `dbError`
|
|
12360
|
+
deliberately always `return`s `false`, which tells the
|
|
12361
|
+
library the error was already handled (and to keep
|
|
12362
|
+
`err` falsy here), precisely so this custom
|
|
12363
|
+
`sysdbFinishedCbDelete` rollback/commit path below is
|
|
12364
|
+
used instead of the library's own default rollback. */
|
|
12110
12365
|
if (currentTask.readOnly || err) {
|
|
12111
12366
|
return true;
|
|
12112
12367
|
}
|
|
12368
|
+
/* c8 ignore stop -- see comment above */
|
|
12113
12369
|
sysdbFinishedCbDelete = function sysdbFinishedCbDelete(err, cb) {
|
|
12114
12370
|
if (err) {
|
|
12115
12371
|
rollback(err, cb);
|
|
@@ -12235,10 +12491,9 @@
|
|
|
12235
12491
|
};
|
|
12236
12492
|
|
|
12237
12493
|
/**
|
|
12238
|
-
* @todo forceClose: Test
|
|
12239
12494
|
* This is provided to facilitate unit-testing of the
|
|
12240
12495
|
* closing of a database connection with a forced flag:
|
|
12241
|
-
* <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection
|
|
12496
|
+
* <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection>.
|
|
12242
12497
|
* @param {string} dbName
|
|
12243
12498
|
* @param {Integer} connIdx
|
|
12244
12499
|
* @param {string} msg
|
|
@@ -12339,6 +12594,7 @@
|
|
|
12339
12594
|
* @this {IDBRecordFull}
|
|
12340
12595
|
*/
|
|
12341
12596
|
function IDBRecord() {
|
|
12597
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
12342
12598
|
// @ts-ignore Should be ok
|
|
12343
12599
|
this[Symbol.toStringTag] = 'IDBRecord';
|
|
12344
12600
|
this.__key = key;
|
|
@@ -12375,6 +12631,7 @@
|
|
|
12375
12631
|
if (!(this instanceof IDBRecordAlias)) {
|
|
12376
12632
|
throw new TypeError('Illegal invocation');
|
|
12377
12633
|
}
|
|
12634
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
12378
12635
|
// @ts-ignore `this` is a real instance past the check above (not an issue in TS7)
|
|
12379
12636
|
return this['__' + prop];
|
|
12380
12637
|
});
|
|
@@ -12717,6 +12974,7 @@
|
|
|
12717
12974
|
success(undefined, undefined, undefined);
|
|
12718
12975
|
}
|
|
12719
12976
|
}, function (tx, err) {
|
|
12977
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
12720
12978
|
if (CFG.DEBUG) {
|
|
12721
12979
|
console.log('Could not execute Cursor.continue', sqlStr, sqlValues);
|
|
12722
12980
|
}
|
|
@@ -12900,7 +13158,16 @@
|
|
|
12900
13158
|
if (a.key > b.key) {
|
|
12901
13159
|
return me.direction === 'prev' ? -1 : 1;
|
|
12902
13160
|
}
|
|
13161
|
+
/* c8 ignore start -- Defensive: only reachable if two matches
|
|
13162
|
+
in the same batch shared both the same `matchingKey` and
|
|
13163
|
+
the same primary `key`, which would require the same
|
|
13164
|
+
record's multi-entry array to contain a duplicate value.
|
|
13165
|
+
`Key.js`'s array-to-key conversion already drops duplicate
|
|
13166
|
+
values when a multi-entry index entry is built, so this
|
|
13167
|
+
can never happen in practice; kept only to satisfy the
|
|
13168
|
+
`Array.prototype.sort` comparator contract. */
|
|
12903
13169
|
return 0;
|
|
13170
|
+
/* c8 ignore stop -- see comment above */
|
|
12904
13171
|
});
|
|
12905
13172
|
me.__prefetchedIndex = 0;
|
|
12906
13173
|
me.__prefetchedData = {
|
|
@@ -12919,13 +13186,19 @@
|
|
|
12919
13186
|
console.log('[multiEntry] Preloaded ' + me.__prefetchedData.length + ' records for multiEntry cursor');
|
|
12920
13187
|
}
|
|
12921
13188
|
me.__decode(rows[0], success);
|
|
12922
|
-
},
|
|
13189
|
+
},
|
|
13190
|
+
/* c8 ignore start -- Defensive: guards against an unexpected SQLite
|
|
13191
|
+
execution error (e.g. I/O error, corruption) while querying for
|
|
13192
|
+
multi-entry cursor matches; not reliably reproducible without
|
|
13193
|
+
mocking the SQL layer. */
|
|
13194
|
+
function (tx, err) {
|
|
12923
13195
|
if (CFG.DEBUG) {
|
|
12924
13196
|
console.log('[multiEntry] Could not execute Cursor.continue', sqlStr, sqlValues);
|
|
12925
13197
|
}
|
|
12926
13198
|
error(err);
|
|
12927
13199
|
return false;
|
|
12928
13200
|
});
|
|
13201
|
+
/* c8 ignore stop -- see comment above */
|
|
12929
13202
|
}
|
|
12930
13203
|
runQuery();
|
|
12931
13204
|
};
|
|
@@ -13034,6 +13307,7 @@
|
|
|
13034
13307
|
* @returns {void}
|
|
13035
13308
|
*/
|
|
13036
13309
|
IDBCursor.prototype.__invalidateCache = function () {
|
|
13310
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
13037
13311
|
// @ts-ignore Why is this not being found?; needed under some TS versions
|
|
13038
13312
|
this.__prefetchedData = null;
|
|
13039
13313
|
this.__multiEntryExhausted = false;
|
|
@@ -13058,7 +13332,7 @@
|
|
|
13058
13332
|
convertValueToKeyRethrowingAndIfInvalid(key);
|
|
13059
13333
|
var cmpResult = cmp(key, me.key);
|
|
13060
13334
|
if (cmpResult === 0 || me.direction.includes('next') && cmpResult === -1 || me.direction.includes('prev') && cmpResult === 1) {
|
|
13061
|
-
throw createDOMException('DataError', 'Cannot
|
|
13335
|
+
throw createDOMException('DataError', 'Cannot continue the cursor in an unexpected direction');
|
|
13062
13336
|
}
|
|
13063
13337
|
}
|
|
13064
13338
|
this.__continueFinish(key, undefined, advanceState);
|
|
@@ -13315,6 +13589,7 @@
|
|
|
13315
13589
|
// continuation logic in `__findBasic` to see this update's
|
|
13316
13590
|
// effect on ordering (see "Modify records during cursor
|
|
13317
13591
|
// iteration" in idbcursor_update_index.any.js).
|
|
13592
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
13318
13593
|
// @ts-ignore -- API (not erring in TS 6)
|
|
13319
13594
|
IDBObjectStore.__storingRecordObjectStore(request, me.__store, true, clonedValue, false, key);
|
|
13320
13595
|
}
|
|
@@ -13364,14 +13639,33 @@
|
|
|
13364
13639
|
// We don't invalidate the cache (as we don't access it anymore
|
|
13365
13640
|
// and it will set the index off)
|
|
13366
13641
|
success(undefined);
|
|
13642
|
+
/* c8 ignore start -- Defensive: `__find` (invoked just above) has
|
|
13643
|
+
already confirmed a row exists for this primary key within the
|
|
13644
|
+
same transaction queue, so `rowsAffected` should always be 1 in
|
|
13645
|
+
normal usage. This branch would only be reached if the underlying
|
|
13646
|
+
row were removed by another request queued in the same
|
|
13647
|
+
transaction between `__find`'s check and this DELETE actually
|
|
13648
|
+
running (e.g. deleting the same record directly via the object
|
|
13649
|
+
store while a cursor over it is mid-iteration); attempts to
|
|
13650
|
+
construct such a scenario instead trigger a transaction abort
|
|
13651
|
+
(`AbortError`) before this callback ever runs, since the default
|
|
13652
|
+
action of an unhandled request error is to abort the
|
|
13653
|
+
transaction. */
|
|
13367
13654
|
} else {
|
|
13368
13655
|
// @ts-expect-error Apparently ok
|
|
13369
13656
|
error('No rows with key found' + key);
|
|
13370
13657
|
}
|
|
13371
|
-
|
|
13658
|
+
/* c8 ignore stop -- see comment above */
|
|
13659
|
+
},
|
|
13660
|
+
/* c8 ignore start -- Defensive: guards against an unexpected SQLite
|
|
13661
|
+
execution error (e.g. I/O error, corruption) while deleting the
|
|
13662
|
+
current row; not reliably reproducible without mocking the SQL
|
|
13663
|
+
layer. */
|
|
13664
|
+
function (tx, data) {
|
|
13372
13665
|
error(data);
|
|
13373
13666
|
return false;
|
|
13374
13667
|
});
|
|
13668
|
+
/* c8 ignore stop -- see comment above */
|
|
13375
13669
|
}, error);
|
|
13376
13670
|
}, undefined, me);
|
|
13377
13671
|
};
|
|
@@ -13779,7 +14073,7 @@
|
|
|
13779
14073
|
*/
|
|
13780
14074
|
function setGlobalVars(idb, initialConfig) {
|
|
13781
14075
|
var IDB = /** @type {ShimmedObject & {[key: string]: unknown}} */
|
|
13782
|
-
/** @type {unknown} */globalThis
|
|
14076
|
+
/** @type {unknown} */globalThis;
|
|
13783
14077
|
/**
|
|
13784
14078
|
* @param {string} name
|
|
13785
14079
|
* @param {unknown} value
|
|
@@ -13870,80 +14164,87 @@
|
|
|
13870
14164
|
});
|
|
13871
14165
|
}
|
|
13872
14166
|
var shimIDBFactory = IDBFactory;
|
|
13873
|
-
if (CFG.win.openDatabase
|
|
13874
|
-
|
|
13875
|
-
|
|
13876
|
-
|
|
13877
|
-
|
|
13878
|
-
|
|
13879
|
-
|
|
13880
|
-
|
|
13881
|
-
|
|
13882
|
-
|
|
13883
|
-
|
|
13884
|
-
|
|
14167
|
+
if (CFG.win.openDatabase === undefined) {
|
|
14168
|
+
return;
|
|
14169
|
+
}
|
|
14170
|
+
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
|
|
14171
|
+
// Polyfill ALL of IndexedDB, using WebSQL
|
|
14172
|
+
shim('indexedDB', shimIndexedDB, {
|
|
14173
|
+
enumerable: true,
|
|
14174
|
+
configurable: true,
|
|
14175
|
+
get: function get() {
|
|
14176
|
+
if (this !== IDB && !isNullish(this) && !this.shimNS) {
|
|
14177
|
+
// Latter is hack for test environment
|
|
14178
|
+
throw new TypeError('Illegal invocation');
|
|
13885
14179
|
}
|
|
13886
|
-
|
|
13887
|
-
/** @type {[string, unknown][]} */
|
|
13888
|
-
[['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) {
|
|
13889
|
-
var _ref4 = _slicedToArray(_ref3, 2),
|
|
13890
|
-
prop = _ref4[0],
|
|
13891
|
-
obj = _ref4[1];
|
|
13892
|
-
shim(prop, obj, {
|
|
13893
|
-
enumerable: false,
|
|
13894
|
-
configurable: true
|
|
13895
|
-
});
|
|
13896
|
-
});
|
|
13897
|
-
// For Node environments
|
|
13898
|
-
if (CFG.fs) {
|
|
13899
|
-
setFS(CFG.fs);
|
|
14180
|
+
return shimIndexedDB;
|
|
13900
14181
|
}
|
|
13901
|
-
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
13905
|
-
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
|
|
13909
|
-
|
|
13910
|
-
|
|
13911
|
-
|
|
13912
|
-
|
|
13913
|
-
|
|
13914
|
-
|
|
13915
|
-
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
14182
|
+
});
|
|
14183
|
+
/** @type {[string, unknown][]} */
|
|
14184
|
+
[['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) {
|
|
14185
|
+
var _ref4 = _slicedToArray(_ref3, 2),
|
|
14186
|
+
prop = _ref4[0],
|
|
14187
|
+
obj = _ref4[1];
|
|
14188
|
+
shim(prop, obj, {
|
|
14189
|
+
enumerable: false,
|
|
14190
|
+
configurable: true
|
|
14191
|
+
});
|
|
14192
|
+
});
|
|
14193
|
+
// For Node environments
|
|
14194
|
+
if (CFG.fs) {
|
|
14195
|
+
setFS(CFG.fs);
|
|
14196
|
+
}
|
|
14197
|
+
if (CFG.fullIDLSupport) {
|
|
14198
|
+
// Slow per MDN so off by default! Though apparently needed for WebIDL: https://stackoverflow.com/questions/41927589/rationales-consequences-of-webidl-class-inheritance-requirements
|
|
14199
|
+
|
|
14200
|
+
Object.setPrototypeOf(IDB.IDBOpenDBRequest, IDB.IDBRequest);
|
|
14201
|
+
Object.setPrototypeOf(IDB.IDBCursorWithValue, IDB.IDBCursor);
|
|
14202
|
+
Object.setPrototypeOf(IDBDatabase, EventTarget);
|
|
14203
|
+
Object.setPrototypeOf(IDBRequest, EventTarget);
|
|
14204
|
+
Object.setPrototypeOf(IDBTransaction, EventTarget);
|
|
14205
|
+
Object.setPrototypeOf(IDBVersionChangeEvent, ShimEvent);
|
|
14206
|
+
// `ShimDOMException` is the real native `DOMException` when one
|
|
14207
|
+
// is available (see `DOMException.js`'s `useNativeDOMException`)
|
|
14208
|
+
// -- which, unlike the shim classes above, is a single,
|
|
14209
|
+
// process-wide singleton shared by reference across every
|
|
14210
|
+
// sandbox this library gets installed into (see
|
|
14211
|
+
// `node-idb-test.js`'s `sandboxObj`). A native `DOMException`
|
|
14212
|
+
// already has the correct prototype chain out of the box
|
|
14213
|
+
// (`Object.getPrototypeOf(DOMException) === Function.prototype`,
|
|
14214
|
+
// not `Error`), so forcing it here isn't just unneeded but
|
|
14215
|
+
// actively wrong -- and, because it's shared, permanently
|
|
14216
|
+
// wrong for every later use of `DOMException` in the same
|
|
14217
|
+
// process (e.g. a later WPT test file's own idlharness-style
|
|
14218
|
+
// check that `DOMException` does *not* inherit from `Error`
|
|
14219
|
+
// on the class side), not just this one shim install.
|
|
14220
|
+
if (typeof DOMException === 'undefined' || ShimDOMException !== DOMException) {
|
|
14221
|
+
Object.setPrototypeOf(ShimDOMException, Error);
|
|
14222
|
+
Object.setPrototypeOf(ShimDOMException.prototype, Error.prototype);
|
|
13928
14223
|
}
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
if (CFG.replaceNonIDBGlobals) {
|
|
13937
|
-
setNonIDBGlobals();
|
|
13938
|
-
}
|
|
14224
|
+
}
|
|
14225
|
+
if (IDB.indexedDB && !IDB.indexedDB.toString().includes('[native code]')) {
|
|
14226
|
+
if (CFG.addNonIDBGlobals) {
|
|
14227
|
+
// As `DOMStringList` exists per IDL (and Chrome) in the global
|
|
14228
|
+
// thread (but not in workers), we prefix the name to avoid
|
|
14229
|
+
// shadowing or conflicts
|
|
14230
|
+
setNonIDBGlobals('Shim');
|
|
13939
14231
|
}
|
|
13940
|
-
|
|
13941
|
-
|
|
13942
|
-
return;
|
|
14232
|
+
if (CFG.replaceNonIDBGlobals) {
|
|
14233
|
+
setNonIDBGlobals();
|
|
13943
14234
|
}
|
|
13944
|
-
/* c8 ignore stop -- TS guard */
|
|
13945
|
-
IDB.shimIndexedDB.__setConnectionQueueOrigin();
|
|
13946
14235
|
}
|
|
14236
|
+
/* c8 ignore start -- Defensive: `IDB.shimIndexedDB` was already
|
|
14237
|
+
confirmed truthy just before this function (`__useShim`) was
|
|
14238
|
+
defined and immediately invoked (see the `if ('shimIndexedDB'
|
|
14239
|
+
in IDB && IDB.shimIndexedDB)` guard above), and nothing in
|
|
14240
|
+
this function's body reassigns or deletes it. Only reachable
|
|
14241
|
+
if `IDB` is some unusual object (e.g. a Proxy) whose
|
|
14242
|
+
`shimIndexedDB` property value changes between reads. */
|
|
14243
|
+
if (!IDB.shimIndexedDB) {
|
|
14244
|
+
return;
|
|
14245
|
+
}
|
|
14246
|
+
/* c8 ignore stop -- see comment above */
|
|
14247
|
+
IDB.shimIndexedDB.__setConnectionQueueOrigin();
|
|
13947
14248
|
};
|
|
13948
14249
|
IDB.shimIndexedDB.__debug = /** @type {(val: boolean) => void} */function (val) {
|
|
13949
14250
|
CFG.DEBUG = val;
|