indexeddbshim 19.0.4 → 19.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/badges/coverage-badge.svg +1 -1
- package/badges/tests-badge.svg +1 -1
- package/dist/CFG.d.ts +1 -1
- package/dist/CFG.d.ts.map +1 -1
- package/dist/DOMException.d.ts.map +1 -1
- package/dist/IDBCursor.d.ts.map +1 -1
- package/dist/IDBDatabase.d.ts.map +1 -1
- package/dist/IDBFactory.d.ts +1 -2
- package/dist/IDBFactory.d.ts.map +1 -1
- package/dist/IDBIndex.d.ts +2 -6
- package/dist/IDBIndex.d.ts.map +1 -1
- package/dist/IDBKeyRange.d.ts.map +1 -1
- package/dist/IDBObjectStore.d.ts.map +1 -1
- package/dist/IDBRecord.d.ts.map +1 -1
- package/dist/IDBRequest.d.ts.map +1 -1
- package/dist/IDBTransaction.d.ts.map +1 -1
- package/dist/Key.d.ts.map +1 -1
- package/dist/Sca.d.ts.map +1 -1
- package/dist/indexeddbshim-Key.js +40 -28
- package/dist/indexeddbshim-Key.js.map +1 -1
- package/dist/indexeddbshim-Key.min.js +2 -2
- package/dist/indexeddbshim-Key.min.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs +525 -225
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.js +553 -252
- package/dist/indexeddbshim-UnicodeIdentifiers.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js +3 -3
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js.map +1 -1
- package/dist/indexeddbshim-node.cjs +525 -225
- package/dist/indexeddbshim-node.cjs.map +1 -1
- package/dist/indexeddbshim-noninvasive.js +553 -252
- package/dist/indexeddbshim-noninvasive.js.map +1 -1
- package/dist/indexeddbshim-noninvasive.min.js +3 -3
- package/dist/indexeddbshim-noninvasive.min.js.map +1 -1
- package/dist/indexeddbshim.js +553 -252
- package/dist/indexeddbshim.js.map +1 -1
- package/dist/indexeddbshim.min.js +3 -3
- package/dist/indexeddbshim.min.js.map +1 -1
- package/dist/nodeWebSQL.d.ts.map +1 -1
- package/dist/setGlobalVars.d.ts +1 -1
- package/dist/setGlobalVars.d.ts.map +1 -1
- package/dist/util.d.ts.map +1 -1
- package/package.json +22 -17
- package/src/CFG.js +18 -4
- package/src/DOMException.js +6 -0
- package/src/DOMStringList.js +3 -0
- package/src/IDBCursor.js +36 -3
- package/src/IDBDatabase.js +26 -10
- package/src/IDBFactory.js +105 -5
- package/src/IDBIndex.js +49 -32
- package/src/IDBKeyRange.js +8 -7
- package/src/IDBObjectStore.js +25 -2
- package/src/IDBRecord.js +2 -0
- package/src/IDBRequest.js +7 -4
- package/src/IDBTransaction.js +111 -34
- package/src/Key.js +17 -16
- package/src/Sca.js +9 -4
- package/src/nodeWebSQL.js +1 -0
- package/src/setGlobalVars.js +86 -77
- package/src/util.js +5 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! indexeddbshim - v19.0.
|
|
1
|
+
/*! indexeddbshim - v19.0.6 - 9/22/2026 */
|
|
2
2
|
|
|
3
3
|
(function (factory) {
|
|
4
4
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
@@ -486,6 +486,7 @@
|
|
|
486
486
|
var ShimDOMException$1 = typeof DOMException === 'undefined'
|
|
487
487
|
// Todo: Better polyfill (if even needed here)
|
|
488
488
|
/* eslint-disable no-shadow -- Polyfill */
|
|
489
|
+
/* 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) */
|
|
489
490
|
// eslint-disable-next-line @stylistic/operator-linebreak -- TS/JSDoc needs
|
|
490
491
|
?
|
|
491
492
|
/**
|
|
@@ -503,9 +504,10 @@
|
|
|
503
504
|
configurable: true
|
|
504
505
|
});
|
|
505
506
|
return err;
|
|
506
|
-
}
|
|
507
|
+
}
|
|
508
|
+
/* c8 ignore stop */ : DOMException;
|
|
507
509
|
|
|
508
|
-
/** @type {WeakMap<object,
|
|
510
|
+
/** @type {WeakMap<object, EventWithProps>} */
|
|
509
511
|
var ev = new WeakMap();
|
|
510
512
|
/** @type {WeakMap<object, EventWithProps>} */
|
|
511
513
|
var evCfg = new WeakMap();
|
|
@@ -551,11 +553,12 @@
|
|
|
551
553
|
obj[prop] = {
|
|
552
554
|
configurable: true,
|
|
553
555
|
get: function get() {
|
|
554
|
-
return Object.hasOwn(_evCfg, prop) ? _evCfg[prop] : Reflect.has(_ev, prop) ? _ev[prop] : ['bubbles', 'cancelable', 'composed'].includes(prop) ? false
|
|
556
|
+
return Object.hasOwn(_evCfg, prop) ? _evCfg[prop] : Reflect.has(_ev, prop) ? _ev[prop] : ['bubbles', 'cancelable', 'composed'].includes(prop) ? false
|
|
557
|
+
/* 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;
|
|
555
558
|
}
|
|
556
559
|
};
|
|
557
560
|
return obj;
|
|
558
|
-
}, /** @type {
|
|
561
|
+
}, /** @type {PropertyDescriptorMap} */{}));
|
|
559
562
|
}
|
|
560
563
|
|
|
561
564
|
/**
|
|
@@ -578,8 +581,9 @@
|
|
|
578
581
|
throw new TypeError('Illegal invocation');
|
|
579
582
|
}
|
|
580
583
|
var _evCfg = getEvCfg(this);
|
|
581
|
-
var _ev = ev.get(this);
|
|
582
|
-
return Boolean(Object.hasOwn(_evCfg, 'isTrusted')
|
|
584
|
+
var _ev = /** @type {EventWithProps} */ /** @type {EventWithProps} */ev.get(this);
|
|
585
|
+
return Boolean(Object.hasOwn(_evCfg, 'isTrusted')
|
|
586
|
+
/* 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);
|
|
583
587
|
}
|
|
584
588
|
|
|
585
589
|
/**
|
|
@@ -730,15 +734,15 @@
|
|
|
730
734
|
// this untyped alias, rather than `ShimEvent.prototype` directly, keeps
|
|
731
735
|
// that dynamic-augmentation pattern working without a `@ts-expect-error`
|
|
732
736
|
// on every single line below.
|
|
733
|
-
|
|
734
|
-
var ShimEventProto = ShimEvent.prototype;
|
|
737
|
+
|
|
738
|
+
var ShimEventProto = /** @type {Record<PropertyKey, unknown>} */ /** @type {unknown} */ShimEvent.prototype;
|
|
735
739
|
|
|
736
740
|
/** @this {EventWithProps} */
|
|
737
741
|
ShimEventProto.preventDefault = function preventDefault() {
|
|
738
742
|
if (!(this instanceof ShimEvent)) {
|
|
739
743
|
throw new TypeError('Illegal invocation');
|
|
740
744
|
}
|
|
741
|
-
var _ev = ev.get(this);
|
|
745
|
+
var _ev = /** @type {EventWithProps} */ /** @type {EventWithProps} */ev.get(this);
|
|
742
746
|
var _evCfg = getEvCfg(this);
|
|
743
747
|
if (this.cancelable && !_evCfg._passive) {
|
|
744
748
|
_evCfg.defaultPrevented = true;
|
|
@@ -936,13 +940,12 @@
|
|
|
936
940
|
return _createClass(CustomEvent);
|
|
937
941
|
}(Event);
|
|
938
942
|
var ShimCustomEvent = CustomEvent;
|
|
939
|
-
/** @type {
|
|
940
|
-
var ShimCustomEventProto = ShimCustomEvent.prototype;
|
|
943
|
+
var ShimCustomEventProto = /** @type {Record<PropertyKey, unknown>} */ /** @type {unknown} */ShimCustomEvent.prototype;
|
|
941
944
|
/**
|
|
942
945
|
* @param {string} type
|
|
943
946
|
* @param {boolean} [bubbles]
|
|
944
947
|
* @param {boolean} [cancelable]
|
|
945
|
-
* @param {
|
|
948
|
+
* @param {unknown} [detail]
|
|
946
949
|
* @this {EventWithProps}
|
|
947
950
|
*/
|
|
948
951
|
ShimCustomEventProto.initCustomEvent = function initCustomEvent(type) {
|
|
@@ -954,6 +957,10 @@
|
|
|
954
957
|
throw new TypeError('Illegal invocation');
|
|
955
958
|
}
|
|
956
959
|
var _evCfg = getEvCfg(this);
|
|
960
|
+
if (_evCfg._dispatched) {
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
|
|
957
964
|
// @ts-expect-error `detail` isn't part of `EventInit`, only used internally here
|
|
958
965
|
// eslint-disable-next-line prefer-rest-params -- Keep signature
|
|
959
966
|
initEventInternal(this, type, {
|
|
@@ -961,16 +968,13 @@
|
|
|
961
968
|
cancelable: cancelable,
|
|
962
969
|
detail: detail
|
|
963
970
|
}, arguments[4]);
|
|
964
|
-
if (_evCfg._dispatched) {
|
|
965
|
-
return;
|
|
966
|
-
}
|
|
967
971
|
if (detail !== undefined) {
|
|
968
972
|
_evCfg.detail = detail;
|
|
969
973
|
}
|
|
970
974
|
// `initCustomEvent` deliberately excluded -- see the matching comment
|
|
971
975
|
// in `initEventInternal` for `initEvent`, above; the same reasoning
|
|
972
976
|
// applies here.
|
|
973
|
-
definePassthroughProps(this, ['detail'], _evCfg, ev.get(this));
|
|
977
|
+
definePassthroughProps(this, ['detail'], _evCfg, /** @type {EventWithProps} */ev.get(this));
|
|
974
978
|
};
|
|
975
979
|
// @ts-expect-error Not part of the class body itself
|
|
976
980
|
ShimCustomEvent[Symbol.toStringTag] = 'Function';
|
|
@@ -1377,7 +1381,7 @@
|
|
|
1377
1381
|
/** @type {string[]} */
|
|
1378
1382
|
this._extraProperties.forEach(function (prop) {
|
|
1379
1383
|
if (Reflect.has(e, prop)) {
|
|
1380
|
-
/** @type {
|
|
1384
|
+
/** @type {PropertyDescriptorMap} */eventCopy[prop] = /** @type {PropertyDescriptorMap} */e[prop]; // Todo: Put internal to `ShimEvent`?
|
|
1381
1385
|
}
|
|
1382
1386
|
});
|
|
1383
1387
|
}
|
|
@@ -1456,6 +1460,7 @@
|
|
|
1456
1460
|
if (child) {
|
|
1457
1461
|
child._defaultSync = this._defaultSync;
|
|
1458
1462
|
}
|
|
1463
|
+
/* 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 */
|
|
1459
1464
|
return (child || this)._dispatchEvent(eventCopy, false);
|
|
1460
1465
|
}
|
|
1461
1466
|
case phases.AT_TARGET:
|
|
@@ -1753,7 +1758,7 @@
|
|
|
1753
1758
|
* databaseNameLengthLimit: number|false,
|
|
1754
1759
|
* escapeNFDForDatabaseNames: boolean,
|
|
1755
1760
|
* addSQLiteExtension: boolean,
|
|
1756
|
-
* memoryDatabase: string,
|
|
1761
|
+
* memoryDatabase: string|null|undefined,
|
|
1757
1762
|
* deleteDatabaseFiles: boolean,
|
|
1758
1763
|
* databaseBasePath: string,
|
|
1759
1764
|
* sysDatabaseBasePath: string,
|
|
@@ -1896,13 +1901,27 @@
|
|
|
1896
1901
|
// Various types of in-memory databases that can auto-delete
|
|
1897
1902
|
['memoryDatabase',
|
|
1898
1903
|
/**
|
|
1899
|
-
*
|
|
1904
|
+
* `null`/`undefined` are accepted (and left unvalidated against the
|
|
1905
|
+
* regex below) specifically so this can be reset back to its
|
|
1906
|
+
* unset/disabled state after being set: unlike other `CFG`
|
|
1907
|
+
* boolean-ish switches (e.g. `sqlMemoryQuota`, which is checked
|
|
1908
|
+
* with a falsy `if (CFG.sqlMemoryQuota)`), `memoryDatabase`'s own
|
|
1909
|
+
* usage sites check `typeof CFG.memoryDatabase === 'string'`, so
|
|
1910
|
+
* even the empty string counts as "on" (it's a distinct, valid
|
|
1911
|
+
* in-memory mode of its own -- an unnamed private temporary
|
|
1912
|
+
* database -- not an "off" state). Without this, once set to any
|
|
1913
|
+
* string there would be no value passable back through this same
|
|
1914
|
+
* validator that turns `useMemoryDatabase` false again.
|
|
1915
|
+
* @param {string|null|undefined} val
|
|
1900
1916
|
* @throws {TypeError}
|
|
1901
1917
|
* @returns {void}
|
|
1902
1918
|
*/
|
|
1903
1919
|
function (val) {
|
|
1920
|
+
if (val === null || val === undefined) {
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1904
1923
|
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)) {
|
|
1905
|
-
throw new TypeError('`memoryDatabase` must be the empty string, ":memory:", or a
|
|
1924
|
+
throw new TypeError('`memoryDatabase` must be `null`/`undefined` (to reset it to disabled), the empty string, ' + '":memory:", or a "file::memory:[?queryString][#hash] URL".');
|
|
1906
1925
|
}
|
|
1907
1926
|
}],
|
|
1908
1927
|
// NODE-SPECIFIC CONFIG
|
|
@@ -1956,10 +1975,7 @@
|
|
|
1956
1975
|
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) {
|
|
1957
1976
|
// Could add a corresponding surrogate for compatibility with `node-sqlite3`: https://bugs.python.org/issue12569 and https://stackoverflow.com/a/6701665/271577
|
|
1958
1977
|
// but Chrome having problems
|
|
1959
|
-
|
|
1960
|
-
return '^2' + unmatchedHighSurrogate.codePointAt().toString(16).padStart(4, '0');
|
|
1961
|
-
}
|
|
1962
|
-
return (precedingLow || '') + '^3' + unmatchedLowSurrogate.codePointAt().toString(16).padStart(4, '0');
|
|
1978
|
+
return unmatchedHighSurrogate ? '^2' + unmatchedHighSurrogate.codePointAt().toString(16).padStart(4, '0') : (precedingLow || '') + '^3' + unmatchedLowSurrogate.codePointAt().toString(16).padStart(4, '0');
|
|
1963
1979
|
});
|
|
1964
1980
|
}
|
|
1965
1981
|
|
|
@@ -2626,7 +2642,8 @@
|
|
|
2626
2642
|
function createNativeDOMException(name, message) {
|
|
2627
2643
|
// @ts-expect-error It's ok
|
|
2628
2644
|
// eslint-disable-next-line new-cap -- Ok
|
|
2629
|
-
return new DOMException.prototype.constructor(message,
|
|
2645
|
+
return new DOMException.prototype.constructor(message, /* c8 ignore next -- Defensive fallback; every call site in this codebase always supplies a `name` */
|
|
2646
|
+
name || 'DOMException');
|
|
2630
2647
|
}
|
|
2631
2648
|
|
|
2632
2649
|
// From web-platform-tests testharness.js name_code_map (though not in new spec)
|
|
@@ -2790,8 +2807,10 @@
|
|
|
2790
2807
|
*/
|
|
2791
2808
|
get: function get() {
|
|
2792
2809
|
if (!(this instanceof DOMException ||
|
|
2810
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2793
2811
|
// @ts-ignore Just checking; needed under some TS versions
|
|
2794
2812
|
this instanceof DummyDOMException ||
|
|
2813
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2795
2814
|
// @ts-ignore Just checking; needed under some TS versions
|
|
2796
2815
|
this instanceof Error)) {
|
|
2797
2816
|
throw new TypeError('Illegal invocation');
|
|
@@ -2850,6 +2869,7 @@
|
|
|
2850
2869
|
value: DOMException
|
|
2851
2870
|
});
|
|
2852
2871
|
|
|
2872
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2853
2873
|
// @ts-ignore We don't need all its properties; needed under some TS versions
|
|
2854
2874
|
return DOMException;
|
|
2855
2875
|
}
|
|
@@ -2862,6 +2882,7 @@
|
|
|
2862
2882
|
* @returns {Error}
|
|
2863
2883
|
*/
|
|
2864
2884
|
function createNonNativeDOMException(name, message) {
|
|
2885
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2865
2886
|
// @ts-ignore It's ok; needed under some TS versions
|
|
2866
2887
|
return new ShimNonNativeDOMException(message, name);
|
|
2867
2888
|
}
|
|
@@ -2884,6 +2905,8 @@
|
|
|
2884
2905
|
return;
|
|
2885
2906
|
}
|
|
2886
2907
|
var msg = error && _typeof(error) === 'object' && error.message ? error.message : (/** @type {string} */error);
|
|
2908
|
+
|
|
2909
|
+
/* c8 ignore next -- Defensive fallback for an environment lacking `console.error` */
|
|
2887
2910
|
var method = typeof console.error === 'function' ? 'error' : 'log';
|
|
2888
2911
|
console[method](name + ': ' + message + '. ' + (msg || ''));
|
|
2889
2912
|
if (console.trace) {
|
|
@@ -3069,8 +3092,10 @@
|
|
|
3069
3092
|
*/
|
|
3070
3093
|
IDBRequest.__super = function IDBRequest() {
|
|
3071
3094
|
var _this = this;
|
|
3095
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
3072
3096
|
// @ts-ignore It's ok
|
|
3073
3097
|
this[Symbol.toStringTag] = 'IDBRequest';
|
|
3098
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
3074
3099
|
// @ts-ignore Part of `ShimEventTarget`
|
|
3075
3100
|
this.__setOptions({
|
|
3076
3101
|
legacyOutputDidListenersThrowFlag: true // Event hook for IndexedB
|
|
@@ -3128,10 +3153,7 @@
|
|
|
3128
3153
|
* @returns {import('./IDBTransaction.js').IDBTransactionFull|null|undefined}
|
|
3129
3154
|
*/
|
|
3130
3155
|
IDBRequest.prototype.__getParent = function () {
|
|
3131
|
-
|
|
3132
|
-
return null;
|
|
3133
|
-
}
|
|
3134
|
-
return this.__transaction;
|
|
3156
|
+
return this.toString() === '[object IDBOpenDBRequest]' ? null : this.__transaction;
|
|
3135
3157
|
};
|
|
3136
3158
|
|
|
3137
3159
|
/* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
|
|
@@ -3190,8 +3212,10 @@
|
|
|
3190
3212
|
function IDBOpenDBRequest() {
|
|
3191
3213
|
IDBRequest.__super.call(this);
|
|
3192
3214
|
|
|
3215
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
3193
3216
|
// @ts-ignore It's ok
|
|
3194
3217
|
this[Symbol.toStringTag] = 'IDBOpenDBRequest';
|
|
3218
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
3195
3219
|
// @ts-ignore It's ok
|
|
3196
3220
|
this.__setOptions({
|
|
3197
3221
|
legacyOutputDidListenersThrowFlag: true,
|
|
@@ -4202,8 +4226,14 @@
|
|
|
4202
4226
|
}
|
|
4203
4227
|
if (!multiEntry || !fullKeys && keys.every(function (k) {
|
|
4204
4228
|
return cmp(/** @type {Key} */k, /** @type {Key} */key.value) !== 0;
|
|
4205
|
-
}) ||
|
|
4206
|
-
|
|
4229
|
+
}) ||
|
|
4230
|
+
// `keys` holds full `{type, value}` objects here (see
|
|
4231
|
+
// `safePush` below), so -- like the sibling branch
|
|
4232
|
+
// above -- `cmp` (which expects raw `Value`s, not
|
|
4233
|
+
// decoded key objects) must compare their `.value`s,
|
|
4234
|
+
// not the wrapper objects themselves.
|
|
4235
|
+
fullKeys && keys.every(function (k) {
|
|
4236
|
+
return cmp(/** @type {Key} */ /** @type {KeyValueObject} */k.value, /** @type {Key} */key.value) !== 0;
|
|
4207
4237
|
})) {
|
|
4208
4238
|
safePush(keys, fullKeys ? key : key.value);
|
|
4209
4239
|
}
|
|
@@ -4228,12 +4258,9 @@
|
|
|
4228
4258
|
{
|
|
4229
4259
|
var date = /** @type {Date} */input;
|
|
4230
4260
|
if (!Number.isNaN(date.getTime())) {
|
|
4231
|
-
return
|
|
4232
|
-
type: type,
|
|
4233
|
-
value: date.getTime()
|
|
4234
|
-
} : {
|
|
4261
|
+
return {
|
|
4235
4262
|
type: type,
|
|
4236
|
-
value: new Date(date)
|
|
4263
|
+
value: fullKeys ? date.getTime() : new Date(date)
|
|
4237
4264
|
};
|
|
4238
4265
|
}
|
|
4239
4266
|
return {
|
|
@@ -4321,10 +4348,7 @@
|
|
|
4321
4348
|
if (r.failure) {
|
|
4322
4349
|
return r;
|
|
4323
4350
|
}
|
|
4324
|
-
|
|
4325
|
-
return convertValueToKeyValueDecoded(r.value, null, false, fullKeys);
|
|
4326
|
-
}
|
|
4327
|
-
return convertValueToMultiEntryKeyDecoded(r.value, fullKeys);
|
|
4351
|
+
return !multiEntry ? convertValueToKeyValueDecoded(r.value, null, false, fullKeys) : convertValueToMultiEntryKeyDecoded(r.value, fullKeys);
|
|
4328
4352
|
}
|
|
4329
4353
|
|
|
4330
4354
|
/**
|
|
@@ -4505,10 +4529,7 @@
|
|
|
4505
4529
|
*/
|
|
4506
4530
|
function isMultiEntryMatch(encodedEntry, encodedKey) {
|
|
4507
4531
|
var keyType = encodedCharToKeyType[encodedKey.slice(0, 1)];
|
|
4508
|
-
|
|
4509
|
-
return encodedKey.indexOf(encodedEntry) > 1;
|
|
4510
|
-
}
|
|
4511
|
-
return encodedKey === encodedEntry;
|
|
4532
|
+
return keyType === 'array' ? encodedKey.indexOf(encodedEntry) > 1 : encodedKey === encodedEntry;
|
|
4512
4533
|
}
|
|
4513
4534
|
|
|
4514
4535
|
/**
|
|
@@ -4626,10 +4647,7 @@
|
|
|
4626
4647
|
* @returns {undefined|ValueType}
|
|
4627
4648
|
*/
|
|
4628
4649
|
function _decode(key, inArray) {
|
|
4629
|
-
|
|
4630
|
-
return undefined;
|
|
4631
|
-
}
|
|
4632
|
-
return types[encodedCharToKeyType[key.slice(0, 1)]].decode(key, inArray);
|
|
4650
|
+
return typeof key !== 'string' ? undefined : types[encodedCharToKeyType[key.slice(0, 1)]].decode(key, inArray);
|
|
4633
4651
|
}
|
|
4634
4652
|
|
|
4635
4653
|
/**
|
|
@@ -5035,10 +5053,11 @@
|
|
|
5035
5053
|
if (hasLower && hasUpper) {
|
|
5036
5054
|
sql.push('AND');
|
|
5037
5055
|
}
|
|
5038
|
-
if (hasUpper) {
|
|
5039
|
-
|
|
5040
|
-
sqlValues.push(escapeSQLiteStatement(/** @type {string} */encodedUpperKey));
|
|
5056
|
+
if (!hasUpper) {
|
|
5057
|
+
return;
|
|
5041
5058
|
}
|
|
5059
|
+
sql.push(quotedKeyColumnName, range.upperOpen ? '<' : '<=', '?');
|
|
5060
|
+
sqlValues.push(escapeSQLiteStatement(/** @type {string} */encodedUpperKey));
|
|
5042
5061
|
}
|
|
5043
5062
|
|
|
5044
5063
|
/**
|
|
@@ -5051,10 +5070,7 @@
|
|
|
5051
5070
|
if (instanceOf(value, IDBKeyRange)) {
|
|
5052
5071
|
// We still need to validate IDBKeyRange-like objects (the above check is based on loose duck-typing)
|
|
5053
5072
|
var range = /** @type {IDBKeyRangeFull} */value;
|
|
5054
|
-
|
|
5055
|
-
return IDBKeyRange.__createInstance(range.lower, range.upper, range.lowerOpen, range.upperOpen);
|
|
5056
|
-
}
|
|
5057
|
-
return range;
|
|
5073
|
+
return range.toString() !== '[object IDBKeyRange]' ? IDBKeyRange.__createInstance(range.lower, range.upper, range.lowerOpen, range.upperOpen) : range;
|
|
5058
5074
|
}
|
|
5059
5075
|
if (isNullish(value)) {
|
|
5060
5076
|
if (nullDisallowed) {
|
|
@@ -5099,9 +5115,11 @@
|
|
|
5099
5115
|
if (testObject.test) {
|
|
5100
5116
|
cleanInterface = true;
|
|
5101
5117
|
}
|
|
5118
|
+
/* c8 ignore start -- Defensive fallback for an engine with a broken `Object.defineProperty` */
|
|
5102
5119
|
} catch (err) {
|
|
5103
5120
|
// Object.defineProperty does not work as intended.
|
|
5104
5121
|
}
|
|
5122
|
+
/* c8 ignore stop -- Defensive fallback for an engine with a broken `Object.defineProperty` */
|
|
5105
5123
|
}
|
|
5106
5124
|
|
|
5107
5125
|
/**
|
|
@@ -5302,6 +5320,7 @@
|
|
|
5302
5320
|
this._length = 0;
|
|
5303
5321
|
};
|
|
5304
5322
|
DOMStringList.prototype = DOMStringListAlias.prototype;
|
|
5323
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
5305
5324
|
// @ts-ignore It's ok; needed under some TS versions
|
|
5306
5325
|
return /** @type {DOMStringListFull} */new DOMStringList();
|
|
5307
5326
|
}
|
|
@@ -5601,12 +5620,14 @@
|
|
|
5601
5620
|
*/
|
|
5602
5621
|
IDBTransaction.prototype.__executeRequests = function () {
|
|
5603
5622
|
var me = this;
|
|
5623
|
+
/* 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. */
|
|
5604
5624
|
if (me.__running) {
|
|
5605
5625
|
if (CFG.DEBUG) {
|
|
5606
5626
|
console.log('Looks like the request set is already running', me.mode);
|
|
5607
5627
|
}
|
|
5608
5628
|
return;
|
|
5609
5629
|
}
|
|
5630
|
+
/* c8 ignore stop -- see comment above */
|
|
5610
5631
|
|
|
5611
5632
|
// The synchronous script that created this transaction (and
|
|
5612
5633
|
// synchronously queued whatever requests it wanted to) has now
|
|
@@ -5626,6 +5647,10 @@
|
|
|
5626
5647
|
var q,
|
|
5627
5648
|
i = -1;
|
|
5628
5649
|
|
|
5650
|
+
// On a standard driver, `keepAliveAndWait` issues a SQL query, which
|
|
5651
|
+
// is a macrotask. Otherwise it issues ten microtasks.
|
|
5652
|
+
var keepAliveAttempts = isStandardDriver ? 1 : 10;
|
|
5653
|
+
|
|
5629
5654
|
/**
|
|
5630
5655
|
* A continuation that must still be able to observe the
|
|
5631
5656
|
* transaction as safe to extend (e.g., re-checking whether an
|
|
@@ -5652,6 +5677,7 @@
|
|
|
5652
5677
|
queueMicrotask(cb);
|
|
5653
5678
|
return;
|
|
5654
5679
|
}
|
|
5680
|
+
/* 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. */
|
|
5655
5681
|
try {
|
|
5656
5682
|
tx.executeSql('SELECT 1', [], function () {
|
|
5657
5683
|
cb();
|
|
@@ -5661,10 +5687,11 @@
|
|
|
5661
5687
|
});
|
|
5662
5688
|
} catch (err) {
|
|
5663
5689
|
// The driver has already finalized the transaction (or otherwise
|
|
5664
|
-
// rejected the call) -- nothing left to hold open
|
|
5665
|
-
//
|
|
5666
|
-
|
|
5690
|
+
// rejected the call) -- nothing left to hold open. We explicitly
|
|
5691
|
+
// abort the transaction here.
|
|
5692
|
+
me.__abortTransaction(/** @type {Error|DOMException} */err);
|
|
5667
5693
|
}
|
|
5694
|
+
/* c8 ignore stop -- see comment above */
|
|
5668
5695
|
}
|
|
5669
5696
|
|
|
5670
5697
|
/**
|
|
@@ -5677,21 +5704,26 @@
|
|
|
5677
5704
|
* @returns {void}
|
|
5678
5705
|
*/
|
|
5679
5706
|
function success(result, req) {
|
|
5707
|
+
/* 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. */
|
|
5680
5708
|
if (me.__errored || me.__requestsFinished) {
|
|
5681
5709
|
// We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
|
|
5682
5710
|
return;
|
|
5683
5711
|
}
|
|
5712
|
+
/* c8 ignore stop -- see comment above */
|
|
5684
5713
|
if (req) {
|
|
5685
5714
|
q.req = req; // Need to do this in case of cursors
|
|
5686
5715
|
}
|
|
5716
|
+
/* 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. */
|
|
5687
5717
|
if (!q.req) {
|
|
5688
|
-
// TS guard
|
|
5689
5718
|
return;
|
|
5690
5719
|
}
|
|
5720
|
+
/* c8 ignore stop -- see comment above */
|
|
5721
|
+
/* 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. */
|
|
5691
5722
|
if (q.req.__done) {
|
|
5692
5723
|
// Avoid continuing with aborted requests
|
|
5693
5724
|
return;
|
|
5694
5725
|
}
|
|
5726
|
+
/* c8 ignore stop -- see comment above */
|
|
5695
5727
|
q.req.__done = true;
|
|
5696
5728
|
q.req.__result = result;
|
|
5697
5729
|
q.req.__error = null;
|
|
@@ -5708,6 +5740,7 @@
|
|
|
5708
5740
|
// is what actually resets `__handlerActive`, once it's
|
|
5709
5741
|
// confirmed (across its own bounded microtask wait) that no
|
|
5710
5742
|
// such continuation queued anything.
|
|
5743
|
+
/* 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. */
|
|
5711
5744
|
if (e.__legacyOutputDidListenersThrowError) {
|
|
5712
5745
|
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
|
|
5713
5746
|
if (!me.__committed) {
|
|
@@ -5717,6 +5750,7 @@
|
|
|
5717
5750
|
return;
|
|
5718
5751
|
}
|
|
5719
5752
|
}
|
|
5753
|
+
/* c8 ignore stop -- see comment above */
|
|
5720
5754
|
runContinuationSafely(advanceAfterDispatch);
|
|
5721
5755
|
}
|
|
5722
5756
|
|
|
@@ -5728,15 +5762,19 @@
|
|
|
5728
5762
|
* @returns {void}
|
|
5729
5763
|
*/
|
|
5730
5764
|
function error() {
|
|
5765
|
+
/* 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. */
|
|
5731
5766
|
if (me.__errored || me.__requestsFinished) {
|
|
5732
5767
|
// We've already called "onerror", "onabort", or thrown within
|
|
5733
5768
|
// the transaction, so don't do it again.
|
|
5734
5769
|
return;
|
|
5735
5770
|
}
|
|
5771
|
+
/* c8 ignore stop -- see comment above */
|
|
5772
|
+
/* 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. */
|
|
5736
5773
|
if (q.req && q.req.__done) {
|
|
5737
5774
|
// Avoid continuing with aborted requests
|
|
5738
5775
|
return;
|
|
5739
5776
|
}
|
|
5777
|
+
/* c8 ignore stop -- see comment above */
|
|
5740
5778
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
5741
5779
|
args[_key] = arguments[_key];
|
|
5742
5780
|
}
|
|
@@ -5761,10 +5799,11 @@
|
|
|
5761
5799
|
}
|
|
5762
5800
|
});
|
|
5763
5801
|
q.req.addDefaultEventListener('error', function () {
|
|
5802
|
+
/* 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. */
|
|
5764
5803
|
if (!q.req) {
|
|
5765
|
-
// TS guard
|
|
5766
5804
|
return;
|
|
5767
5805
|
}
|
|
5806
|
+
/* c8 ignore stop -- see comment above */
|
|
5768
5807
|
me.__abortTransaction(q.req.__error);
|
|
5769
5808
|
});
|
|
5770
5809
|
me.__active = true;
|
|
@@ -5776,16 +5815,19 @@
|
|
|
5776
5815
|
q.req.dispatchEvent(e);
|
|
5777
5816
|
// Do not set __active or __handlerActive flags to false yet --
|
|
5778
5817
|
// see the matching comment in `success`, above.
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
if (me.__committed) {
|
|
5783
|
-
// An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
|
|
5784
|
-
runContinuationSafely(advanceAfterDispatch);
|
|
5785
|
-
return;
|
|
5786
|
-
}
|
|
5787
|
-
me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after error).'));
|
|
5818
|
+
/* 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. */
|
|
5819
|
+
if (!e.__legacyOutputDidListenersThrowError) {
|
|
5820
|
+
return;
|
|
5788
5821
|
}
|
|
5822
|
+
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
|
|
5823
|
+
e.preventDefault(); // Prevent 'error' default as steps indicate we should abort with `AbortError` even without cancellation
|
|
5824
|
+
if (me.__committed) {
|
|
5825
|
+
// An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
|
|
5826
|
+
runContinuationSafely(advanceAfterDispatch);
|
|
5827
|
+
return;
|
|
5828
|
+
}
|
|
5829
|
+
me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after error).'));
|
|
5830
|
+
/* c8 ignore stop -- see comment above */
|
|
5789
5831
|
}
|
|
5790
5832
|
|
|
5791
5833
|
/**
|
|
@@ -5809,10 +5851,12 @@
|
|
|
5809
5851
|
// (not reset here).
|
|
5810
5852
|
return true;
|
|
5811
5853
|
}
|
|
5854
|
+
/* 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. */
|
|
5812
5855
|
if (q.req.__done) {
|
|
5813
5856
|
// Avoid continuing with aborted requests
|
|
5814
5857
|
return false;
|
|
5815
5858
|
}
|
|
5859
|
+
/* c8 ignore stop -- see comment above */
|
|
5816
5860
|
// We're now handing off to (possibly async) work for
|
|
5817
5861
|
// this request, so the transaction is no longer active
|
|
5818
5862
|
// until its own `success`/`error` dispatch (below)
|
|
@@ -5837,18 +5881,22 @@
|
|
|
5837
5881
|
return;
|
|
5838
5882
|
}
|
|
5839
5883
|
q.op(tx, q.args, success, error, executeNextRequest);
|
|
5884
|
+
/* 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. */
|
|
5840
5885
|
} catch (e) {
|
|
5841
5886
|
error(/** @type {Error} */e);
|
|
5842
5887
|
}
|
|
5888
|
+
/* c8 ignore stop -- see comment above */
|
|
5843
5889
|
}
|
|
5844
5890
|
|
|
5845
5891
|
/**
|
|
5846
5892
|
* @returns {void}
|
|
5847
5893
|
*/
|
|
5848
5894
|
function runQueuedRequest() {
|
|
5895
|
+
/* c8 ignore start -- Defensive: only reached if `prepareNextRequest` returns `false` (see its own ignore comment above for why that's not reliably reproducible). */
|
|
5849
5896
|
if (!prepareNextRequest()) {
|
|
5850
5897
|
return;
|
|
5851
5898
|
}
|
|
5899
|
+
/* c8 ignore stop -- see comment above */
|
|
5852
5900
|
launchQueuedOp();
|
|
5853
5901
|
}
|
|
5854
5902
|
|
|
@@ -5870,16 +5918,20 @@
|
|
|
5870
5918
|
* consumer of that same handler (e.g. one that resolves a
|
|
5871
5919
|
* promise from within `onsuccess` and only attaches `oncomplete`
|
|
5872
5920
|
* afterward) ever gets a turn to run, so it can miss `complete`
|
|
5873
|
-
*
|
|
5874
|
-
*
|
|
5875
|
-
*
|
|
5921
|
+
* afterward) ever gets a turn to run, so it can miss `complete`
|
|
5922
|
+
* entirely. On a non-standard driver, `readonly` requests don't hold
|
|
5923
|
+
* a real SQL transaction open, so there's no file-lock/connection
|
|
5924
|
+
* collision risk. On a standard driver, the wait now issues real SQL
|
|
5925
|
+
* inside the read transaction, so this does carry a slight risk.
|
|
5876
5926
|
* @param {number} attemptsLeft
|
|
5877
5927
|
* @returns {void}
|
|
5878
5928
|
*/
|
|
5879
5929
|
function checkQueueEntry(attemptsLeft) {
|
|
5930
|
+
/* 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. */
|
|
5880
5931
|
if (me.__errored || me.__requestsFinished) {
|
|
5881
5932
|
return;
|
|
5882
5933
|
}
|
|
5934
|
+
/* c8 ignore stop -- see comment above */
|
|
5883
5935
|
if (i < me.__requests.length) {
|
|
5884
5936
|
runQueuedRequest();
|
|
5885
5937
|
return;
|
|
@@ -5901,13 +5953,15 @@
|
|
|
5901
5953
|
* @returns {void}
|
|
5902
5954
|
*/
|
|
5903
5955
|
function executeNextRequest() {
|
|
5956
|
+
/* 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. */
|
|
5904
5957
|
if (me.__errored || me.__requestsFinished) {
|
|
5905
5958
|
// We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
|
|
5906
5959
|
return;
|
|
5907
5960
|
}
|
|
5961
|
+
/* c8 ignore stop -- see comment above */
|
|
5908
5962
|
i++;
|
|
5909
5963
|
if (i >= me.__requests.length) {
|
|
5910
|
-
checkQueueEntry(
|
|
5964
|
+
checkQueueEntry(keepAliveAttempts);
|
|
5911
5965
|
return;
|
|
5912
5966
|
}
|
|
5913
5967
|
runQueuedRequest();
|
|
@@ -5939,31 +5993,34 @@
|
|
|
5939
5993
|
* @returns {void}
|
|
5940
5994
|
*/
|
|
5941
5995
|
function advanceAfterDispatch() {
|
|
5996
|
+
/* 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. */
|
|
5942
5997
|
if (me.__errored || me.__requestsFinished) {
|
|
5943
5998
|
return;
|
|
5944
5999
|
}
|
|
6000
|
+
/* c8 ignore stop -- see comment above */
|
|
5945
6001
|
i++;
|
|
5946
6002
|
if (i >= me.__requests.length) {
|
|
5947
|
-
checkQueueEntry(
|
|
6003
|
+
checkQueueEntry(keepAliveAttempts);
|
|
5948
6004
|
return;
|
|
5949
6005
|
}
|
|
5950
6006
|
keepAliveAndWait(function () {
|
|
5951
|
-
if (
|
|
5952
|
-
|
|
5953
|
-
}
|
|
5954
|
-
if (!prepareNextRequest()) {
|
|
6007
|
+
/* 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. */
|
|
6008
|
+
if (me.__errored || me.__requestsFinished || !prepareNextRequest()) {
|
|
5955
6009
|
return;
|
|
5956
6010
|
}
|
|
6011
|
+
/* c8 ignore stop -- see comment above */
|
|
5957
6012
|
launchQueuedOp();
|
|
5958
6013
|
});
|
|
5959
6014
|
}
|
|
5960
6015
|
executeNextRequest();
|
|
5961
6016
|
}, function webSQLError(webSQLErr) {
|
|
6017
|
+
/* 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. */
|
|
5962
6018
|
// @ts-expect-error It's ok
|
|
5963
6019
|
if (webSQLErr === true) {
|
|
5964
6020
|
// Not a genuine SQL error
|
|
5965
6021
|
return;
|
|
5966
6022
|
}
|
|
6023
|
+
/* c8 ignore stop -- see comment above */
|
|
5967
6024
|
var err = webSQLErrback(/** @type {Error & {code?: number}} */webSQLErr);
|
|
5968
6025
|
me.__abortTransaction(err);
|
|
5969
6026
|
}, function () {
|
|
@@ -5974,18 +6031,25 @@
|
|
|
5974
6031
|
// Node
|
|
5975
6032
|
return;
|
|
5976
6033
|
}
|
|
6034
|
+
/* 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. */
|
|
5977
6035
|
if (!me.__transactionEndCallback && !me.__requestsFinished) {
|
|
5978
6036
|
me.__transactionFinished = true;
|
|
5979
6037
|
return;
|
|
5980
6038
|
}
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
6039
|
+
/* c8 ignore stop -- see comment above */
|
|
6040
|
+
/* 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. */
|
|
6041
|
+
if (!me.__transactionEndCallback || me.__completed || me.__transFinishedCbFired) {
|
|
6042
|
+
return;
|
|
5984
6043
|
}
|
|
6044
|
+
me.__transFinishedCbFired = true;
|
|
6045
|
+
me.__transFinishedCb(me.__errored, me.__transactionEndCallback);
|
|
6046
|
+
/* c8 ignore stop -- see comment above */
|
|
5985
6047
|
}, function (currentTask, err, done, rollback, commit) {
|
|
6048
|
+
/* 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. */
|
|
5986
6049
|
if (err) {
|
|
5987
6050
|
return true;
|
|
5988
6051
|
}
|
|
6052
|
+
/* c8 ignore stop -- see comment above */
|
|
5989
6053
|
// `readonly` transactions never hold a real SQL transaction open
|
|
5990
6054
|
// (see `WebSQLTransaction`'s constructor skipping `BEGIN;` for
|
|
5991
6055
|
// them), so there's no commit/rollback round trip to defer --
|
|
@@ -6034,6 +6098,7 @@
|
|
|
6034
6098
|
*/
|
|
6035
6099
|
function complete() {
|
|
6036
6100
|
me.__completed = true;
|
|
6101
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
6037
6102
|
if (CFG.DEBUG) {
|
|
6038
6103
|
console.log('Transaction completed');
|
|
6039
6104
|
}
|
|
@@ -6043,6 +6108,7 @@
|
|
|
6043
6108
|
me.dispatchEvent(evt);
|
|
6044
6109
|
me.__internal = false;
|
|
6045
6110
|
me.dispatchEvent(createEvent('__complete'));
|
|
6111
|
+
/* 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. */
|
|
6046
6112
|
} catch (e) {
|
|
6047
6113
|
me.__internal = false;
|
|
6048
6114
|
// An error occurred in the "oncomplete" handler.
|
|
@@ -6050,6 +6116,7 @@
|
|
|
6050
6116
|
// (this may seem odd/bad, but it's how all native IndexedDB implementations work)
|
|
6051
6117
|
me.__errored = true;
|
|
6052
6118
|
throw e;
|
|
6119
|
+
/* c8 ignore stop -- see comment above */
|
|
6053
6120
|
} finally {
|
|
6054
6121
|
activeTransactions.delete(me);
|
|
6055
6122
|
me.__storeHandles = {};
|
|
@@ -6057,10 +6124,12 @@
|
|
|
6057
6124
|
}
|
|
6058
6125
|
}
|
|
6059
6126
|
if (me.mode === 'readwrite' || me.mode === 'readonly') {
|
|
6127
|
+
/* 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. */
|
|
6060
6128
|
if (me.__transactionFinished) {
|
|
6061
6129
|
complete();
|
|
6062
6130
|
return;
|
|
6063
6131
|
}
|
|
6132
|
+
/* c8 ignore stop -- see comment above */
|
|
6064
6133
|
me.__transactionEndCallback = complete;
|
|
6065
6134
|
// The underlying SQL driver's own "queue empty" check
|
|
6066
6135
|
// (`nonstandardTransCb`, above) typically already ran and
|
|
@@ -6096,6 +6165,7 @@
|
|
|
6096
6165
|
IDBTransaction.prototype.__createRequest = function (source) {
|
|
6097
6166
|
var me = this;
|
|
6098
6167
|
var request = IDBRequest.__createInstance();
|
|
6168
|
+
/* 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. */
|
|
6099
6169
|
request.__source = source !== undefined ? source : me.db;
|
|
6100
6170
|
request.__transaction = me;
|
|
6101
6171
|
return request;
|
|
@@ -6165,9 +6235,11 @@
|
|
|
6165
6235
|
* @returns {void}
|
|
6166
6236
|
*/
|
|
6167
6237
|
IDBTransaction.prototype.__assertActive = function () {
|
|
6238
|
+
/* 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. */
|
|
6168
6239
|
if (!this.__active || !this.__handlerActive || this.__committed) {
|
|
6169
6240
|
throw createDOMException('TransactionInactiveError', 'A request was placed against a transaction which is currently not active, or which is finished');
|
|
6170
6241
|
}
|
|
6242
|
+
/* c8 ignore stop -- see comment above */
|
|
6171
6243
|
};
|
|
6172
6244
|
|
|
6173
6245
|
/**
|
|
@@ -6181,6 +6253,7 @@
|
|
|
6181
6253
|
}
|
|
6182
6254
|
};
|
|
6183
6255
|
|
|
6256
|
+
/* 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. */
|
|
6184
6257
|
/**
|
|
6185
6258
|
* @this {IDBTransactionFull}
|
|
6186
6259
|
* @returns {void}
|
|
@@ -6188,6 +6261,7 @@
|
|
|
6188
6261
|
IDBTransaction.prototype.__assertVersionChange = function () {
|
|
6189
6262
|
IDBTransaction.__assertVersionChange(this);
|
|
6190
6263
|
};
|
|
6264
|
+
/* c8 ignore stop -- see comment above */
|
|
6191
6265
|
|
|
6192
6266
|
/**
|
|
6193
6267
|
* Returns the specified object store.
|
|
@@ -6209,9 +6283,12 @@
|
|
|
6209
6283
|
throw createDOMException('NotFoundError', objectStoreName + ' is not participating in this transaction');
|
|
6210
6284
|
}
|
|
6211
6285
|
var store = me.db.__objectStores[objectStoreName];
|
|
6286
|
+
/* 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. */
|
|
6212
6287
|
if (!store) {
|
|
6213
6288
|
throw createDOMException('NotFoundError', objectStoreName + ' does not exist in ' + me.db.name);
|
|
6214
6289
|
}
|
|
6290
|
+
/* c8 ignore stop -- see comment above */
|
|
6291
|
+
|
|
6215
6292
|
if (!Object.hasOwn(me.__storeHandles, objectStoreName) ||
|
|
6216
6293
|
// These latter conditions are to allow store
|
|
6217
6294
|
// recreation to create new clone object
|
|
@@ -6230,10 +6307,12 @@
|
|
|
6230
6307
|
IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
6231
6308
|
var me = this;
|
|
6232
6309
|
logError('Error', 'An error occurred in a transaction', err);
|
|
6310
|
+
/* 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. */
|
|
6233
6311
|
if (me.__errored) {
|
|
6234
6312
|
// We've already called "onerror", "onabort", or thrown, so don't do it again.
|
|
6235
6313
|
return;
|
|
6236
6314
|
}
|
|
6315
|
+
/* c8 ignore stop -- see comment above */
|
|
6237
6316
|
me.__errored = true;
|
|
6238
6317
|
if (me.mode === 'versionchange') {
|
|
6239
6318
|
// Steps for aborting an upgrade transaction
|
|
@@ -6263,19 +6342,16 @@
|
|
|
6263
6342
|
if (err !== null) {
|
|
6264
6343
|
me.__error = err;
|
|
6265
6344
|
}
|
|
6345
|
+
|
|
6346
|
+
/* 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. */
|
|
6266
6347
|
if (me.__requestsFinished && err !== null) {
|
|
6267
6348
|
// The transaction has already completed, so we can't call "onerror" or "onabort".
|
|
6268
|
-
// So throw the error instead.
|
|
6269
|
-
// `IDBTransaction.prototype.abort`'s own `__abortTransaction(null)`
|
|
6270
|
-
// call, which now checks `__requestsFinished` itself first and
|
|
6271
|
-
// throws `InvalidStateError` synchronously before ever reaching
|
|
6272
|
-
// this point -- so this guard is just defense in depth against
|
|
6273
|
-
// `err` somehow being `null` some other way, not something this
|
|
6274
|
-
// path should see in practice.
|
|
6349
|
+
// So throw the error instead.
|
|
6275
6350
|
setTimeout(function () {
|
|
6276
6351
|
throw err;
|
|
6277
6352
|
}, 0);
|
|
6278
6353
|
}
|
|
6354
|
+
/* c8 ignore stop -- see comment above */
|
|
6279
6355
|
|
|
6280
6356
|
/**
|
|
6281
6357
|
* @param {import('websql-configurable/lib/websql/WebSQLTransaction.js').default|null} [tx]
|
|
@@ -6284,13 +6360,17 @@
|
|
|
6284
6360
|
*/
|
|
6285
6361
|
function abort(tx, errOrResult) {
|
|
6286
6362
|
if (!tx) {
|
|
6363
|
+
/* 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. */
|
|
6287
6364
|
if (CFG.DEBUG) {
|
|
6288
6365
|
console.log('Rollback not possible due to missing transaction', me);
|
|
6289
6366
|
}
|
|
6367
|
+
/* 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. */
|
|
6290
6368
|
} else if (errOrResult && 'code' in errOrResult && typeof errOrResult.code === 'number') {
|
|
6291
6369
|
if (CFG.DEBUG) {
|
|
6292
6370
|
console.log('Rollback erred; feature is probably not supported as per WebSQL', me);
|
|
6293
6371
|
}
|
|
6372
|
+
/* c8 ignore stop -- see comment above */
|
|
6373
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
6294
6374
|
} else if (CFG.DEBUG) {
|
|
6295
6375
|
console.log('Rollback succeeded', me);
|
|
6296
6376
|
}
|
|
@@ -6306,10 +6386,11 @@
|
|
|
6306
6386
|
// behaves first-in-first-out with the same timeout so we could
|
|
6307
6387
|
// just use a `forEach`.
|
|
6308
6388
|
return promises.then(function () {
|
|
6389
|
+
/* 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. */
|
|
6309
6390
|
if (!q.req) {
|
|
6310
|
-
// TS guard
|
|
6311
6391
|
throw new Error('Missing request');
|
|
6312
6392
|
}
|
|
6393
|
+
/* c8 ignore stop -- see comment above */
|
|
6313
6394
|
q.req.__done = true;
|
|
6314
6395
|
q.req.__result = undefined;
|
|
6315
6396
|
q.req.__error = createDOMException('AbortError', 'A request was aborted (an unfinished request).');
|
|
@@ -6320,10 +6401,11 @@
|
|
|
6320
6401
|
return new SyncPromise(/** @type {(resolve: (value?: unknown) => void) => void} */
|
|
6321
6402
|
function (resolve) {
|
|
6322
6403
|
setTimeout(function () {
|
|
6404
|
+
/* c8 ignore start -- Dead code: same invariant as above -- `q.req` was already confirmed truthy by the outer `.filter()` and is never reset. */
|
|
6323
6405
|
if (!q.req) {
|
|
6324
|
-
// TS guard
|
|
6325
6406
|
throw new Error('Missing request');
|
|
6326
6407
|
}
|
|
6408
|
+
/* c8 ignore stop -- see comment above */
|
|
6327
6409
|
q.req.dispatchEvent(reqEvt); // No need to catch errors
|
|
6328
6410
|
resolve();
|
|
6329
6411
|
}, 0);
|
|
@@ -6343,10 +6425,12 @@
|
|
|
6343
6425
|
releaseFinishedTransaction(me);
|
|
6344
6426
|
}, 0);
|
|
6345
6427
|
return undefined;
|
|
6428
|
+
/* 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. */
|
|
6346
6429
|
}).catch(function (err) {
|
|
6347
6430
|
console.log('Abort error');
|
|
6348
6431
|
throw err;
|
|
6349
6432
|
});
|
|
6433
|
+
/* c8 ignore stop -- see comment above */
|
|
6350
6434
|
}
|
|
6351
6435
|
me.__transFinishedCb(true, function (rollback) {
|
|
6352
6436
|
if (rollback && me.__tx) {
|
|
@@ -6354,20 +6438,24 @@
|
|
|
6354
6438
|
// rollback automatically), but for Node.js, etc., we give chance for
|
|
6355
6439
|
// manual aborts which would otherwise not work.
|
|
6356
6440
|
if (me.mode === 'readwrite') {
|
|
6441
|
+
/* 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. */
|
|
6357
6442
|
if (me.__transactionFinished) {
|
|
6358
6443
|
abort();
|
|
6359
6444
|
return;
|
|
6360
6445
|
}
|
|
6446
|
+
/* c8 ignore stop -- see comment above */
|
|
6361
6447
|
me.__transactionEndCallback = abort;
|
|
6362
6448
|
return;
|
|
6363
6449
|
}
|
|
6364
6450
|
try {
|
|
6365
6451
|
me.__tx.executeSql('ROLLBACK', [], abort, /** @type {import('websql-configurable/lib/websql/WebSQLTransaction.js').SqlErrorCallback} */abort); // Not working in some circumstances, even in Node
|
|
6452
|
+
/* c8 ignore start -- Defensive: the underlying WebSQL/SQLite driver throwing synchronously on `ROLLBACK` is not reliably reproducible without mocking the SQL layer. */
|
|
6366
6453
|
} catch (err) {
|
|
6367
6454
|
// Browser errs when transaction has ended and since it most likely already erred here,
|
|
6368
6455
|
// we call to abort
|
|
6369
6456
|
abort();
|
|
6370
6457
|
}
|
|
6458
|
+
/* c8 ignore stop -- see comment above */
|
|
6371
6459
|
} else {
|
|
6372
6460
|
abort(null, {
|
|
6373
6461
|
code: 0
|
|
@@ -6385,6 +6473,7 @@
|
|
|
6385
6473
|
if (!(me instanceof IDBTransaction)) {
|
|
6386
6474
|
throw new TypeError('Illegal invocation');
|
|
6387
6475
|
}
|
|
6476
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
6388
6477
|
if (CFG.DEBUG) {
|
|
6389
6478
|
console.log('The transaction was aborted', me);
|
|
6390
6479
|
}
|
|
@@ -6416,6 +6505,7 @@
|
|
|
6416
6505
|
if (!me.__active || !me.__handlerActive || me.__committed) {
|
|
6417
6506
|
throw createDOMException('InvalidStateError', 'Failed to execute \'commit\' on \'IDBTransaction\': The transaction is not active.');
|
|
6418
6507
|
}
|
|
6508
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
6419
6509
|
if (CFG.DEBUG) {
|
|
6420
6510
|
console.log('The transaction was explicitly committed', me);
|
|
6421
6511
|
}
|
|
@@ -6458,6 +6548,7 @@
|
|
|
6458
6548
|
};
|
|
6459
6549
|
|
|
6460
6550
|
// object store methods behave differently: see https://github.com/w3c/IndexedDB/issues/192
|
|
6551
|
+
/* 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. */
|
|
6461
6552
|
/**
|
|
6462
6553
|
*
|
|
6463
6554
|
* @param {IDBTransactionFull} tx
|
|
@@ -6473,6 +6564,7 @@
|
|
|
6473
6564
|
throw err;
|
|
6474
6565
|
}
|
|
6475
6566
|
};
|
|
6567
|
+
/* c8 ignore stop -- see comment above */
|
|
6476
6568
|
|
|
6477
6569
|
/**
|
|
6478
6570
|
*
|
|
@@ -7570,7 +7662,7 @@
|
|
|
7570
7662
|
return Number.isNaN(t) ? "NaN" : t;
|
|
7571
7663
|
},
|
|
7572
7664
|
revive: function revive(e) {
|
|
7573
|
-
return "NaN" === e ?
|
|
7665
|
+
return new Date("NaN" === e ? NaN : e);
|
|
7574
7666
|
}
|
|
7575
7667
|
}
|
|
7576
7668
|
},
|
|
@@ -8430,9 +8522,12 @@
|
|
|
8430
8522
|
}).find(function (preset) {
|
|
8431
8523
|
return preset && !Array.isArray(preset) && 'filelist' in preset;
|
|
8432
8524
|
});
|
|
8433
|
-
var origFileList = specSet && !Array.isArray(specSet) && 'filelist' in specSet ? specSet.filelist
|
|
8434
|
-
|
|
8435
|
-
var
|
|
8525
|
+
var origFileList = specSet && !Array.isArray(specSet) && 'filelist' in specSet ? specSet.filelist
|
|
8526
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */ : undefined;
|
|
8527
|
+
var origTest = origFileList && _typeof(origFileList) === 'object' && 'test' in origFileList && typeof origFileList.test === 'function' ? origFileList.test
|
|
8528
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.test` ever goes missing */ : undefined;
|
|
8529
|
+
var origRevive = origFileList && _typeof(origFileList) === 'object' && 'revive' in origFileList && typeof origFileList.revive === 'function' ? origFileList.revive
|
|
8530
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.revive` ever goes missing */ : undefined;
|
|
8436
8531
|
var customFileList = origFileList ? _objectSpread2(_objectSpread2({}, origFileList), {}, {
|
|
8437
8532
|
/**
|
|
8438
8533
|
* @param {unknown} x
|
|
@@ -8440,10 +8535,7 @@
|
|
|
8440
8535
|
* @returns {boolean}
|
|
8441
8536
|
*/
|
|
8442
8537
|
test: function test(x, state) {
|
|
8443
|
-
|
|
8444
|
-
return x instanceof FileList;
|
|
8445
|
-
}
|
|
8446
|
-
return typeof origTest === 'function' ? origTest(x, state) : false;
|
|
8538
|
+
return typeof FileList !== 'undefined' ? x instanceof FileList : typeof origTest === 'function' && origTest(x, state);
|
|
8447
8539
|
},
|
|
8448
8540
|
/**
|
|
8449
8541
|
* @param {unknown} x
|
|
@@ -8454,10 +8546,12 @@
|
|
|
8454
8546
|
if (typeof FileList !== 'undefined') {
|
|
8455
8547
|
return Reflect.construct(FileList, [x]);
|
|
8456
8548
|
}
|
|
8549
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.revive` ever goes missing */
|
|
8457
8550
|
return typeof origRevive === 'function' ? origRevive(x, state) : undefined;
|
|
8458
8551
|
}
|
|
8459
|
-
}) : undefined;
|
|
8460
|
-
var typeson = new Typeson().register([fe,
|
|
8552
|
+
}) /* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */ : undefined;
|
|
8553
|
+
var typeson = new Typeson().register([fe, /* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */
|
|
8554
|
+
customFileList ? {
|
|
8461
8555
|
filelist: customFileList
|
|
8462
8556
|
} : {}]);
|
|
8463
8557
|
|
|
@@ -8613,7 +8707,6 @@
|
|
|
8613
8707
|
* __unique: boolean,
|
|
8614
8708
|
* __objectStore: import('./IDBObjectStore.js').IDBObjectStoreFull,
|
|
8615
8709
|
* __keyPath: import('./Key.js').KeyPath,
|
|
8616
|
-
* __recreated?: boolean,
|
|
8617
8710
|
* __fetchIndexData: (
|
|
8618
8711
|
* range: Query,
|
|
8619
8712
|
* opType: "value"|"key"|"count",
|
|
@@ -8707,6 +8800,7 @@
|
|
|
8707
8800
|
storeHandle.__indexHandles[newName] = oldIndexHandle; // Ensure new reference accessible
|
|
8708
8801
|
me.__pendingName = oldName;
|
|
8709
8802
|
var colInfoToPreserveArr = [['key', 'BLOB ' + (objectStore.autoIncrement ? 'UNIQUE, inc INTEGER PRIMARY KEY AUTOINCREMENT' : 'PRIMARY KEY')], ['value', 'BLOB']].concat(
|
|
8803
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
8710
8804
|
// @ts-ignore Has numeric indexes instead of iterator; needed under some TS versions
|
|
8711
8805
|
_toConsumableArray(objectStore.indexNames).filter(function (indexName) {
|
|
8712
8806
|
return indexName !== newName;
|
|
@@ -8758,7 +8852,7 @@
|
|
|
8758
8852
|
}
|
|
8759
8853
|
});
|
|
8760
8854
|
/** @type {const} */
|
|
8761
|
-
['__pendingCreate', '__pendingDelete', '__deleted', '__originalName'
|
|
8855
|
+
['__pendingCreate', '__pendingDelete', '__deleted', '__originalName'].forEach(function (p) {
|
|
8762
8856
|
// @ts-expect-error Why is this type "never"?
|
|
8763
8857
|
idx[p] = index[p];
|
|
8764
8858
|
});
|
|
@@ -8790,11 +8884,12 @@
|
|
|
8790
8884
|
var transaction = store.transaction;
|
|
8791
8885
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
8792
8886
|
transaction.__addNonRequestToTransactionQueue(function createIndex(tx, args, success, failure) {
|
|
8793
|
-
var columnExists = idx &&
|
|
8887
|
+
var columnExists = idx && idx.__deleted; // This check must occur here rather than earlier as properties may not have been set yet otherwise
|
|
8794
8888
|
|
|
8795
8889
|
/** @type {{[key: string]: boolean}} */
|
|
8796
8890
|
var indexValues = {};
|
|
8797
8891
|
|
|
8892
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8798
8893
|
/**
|
|
8799
8894
|
* @param {WebSQLTransaction} tx
|
|
8800
8895
|
* @param {(Error & {code?: number})} err
|
|
@@ -8803,6 +8898,7 @@
|
|
|
8803
8898
|
function error(tx, err) {
|
|
8804
8899
|
failure(createDOMException('UnknownError', 'Could not create index "' + indexName + '"' + err.code + '::' + err.message, err));
|
|
8805
8900
|
}
|
|
8901
|
+
/* c8 ignore stop -- see comment above */
|
|
8806
8902
|
|
|
8807
8903
|
/**
|
|
8808
8904
|
* @param {WebSQLTransaction} tx
|
|
@@ -8852,12 +8948,6 @@
|
|
|
8852
8948
|
} else {
|
|
8853
8949
|
delete index.__pendingCreate;
|
|
8854
8950
|
delete indexHandle.__pendingCreate;
|
|
8855
|
-
if (index.__deleted) {
|
|
8856
|
-
delete index.__deleted;
|
|
8857
|
-
delete indexHandle.__deleted;
|
|
8858
|
-
index.__recreated = true;
|
|
8859
|
-
indexHandle.__recreated = true;
|
|
8860
|
-
}
|
|
8861
8951
|
indexValues = {};
|
|
8862
8952
|
success(store);
|
|
8863
8953
|
}
|
|
@@ -8866,7 +8956,7 @@
|
|
|
8866
8956
|
}, /** @type {SqlErrorCallback} */error);
|
|
8867
8957
|
}
|
|
8868
8958
|
var escapedStoreNameSQL = escapeStoreNameForSQL(storeName);
|
|
8869
|
-
var escapedIndexNameSQL = escapeIndexNameForSQL(
|
|
8959
|
+
var escapedIndexNameSQL = escapeIndexNameForSQL(indexName);
|
|
8870
8960
|
|
|
8871
8961
|
/**
|
|
8872
8962
|
* @param {WebSQLTransaction} tx
|
|
@@ -8918,6 +9008,7 @@
|
|
|
8918
9008
|
var transaction = store.transaction;
|
|
8919
9009
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
8920
9010
|
transaction.__addNonRequestToTransactionQueue(function deleteIndex(tx, args, success, failure) {
|
|
9011
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8921
9012
|
/**
|
|
8922
9013
|
* @param {WebSQLTransaction} tx
|
|
8923
9014
|
* @param {(Error & {code?: number})} err
|
|
@@ -8926,6 +9017,7 @@
|
|
|
8926
9017
|
function error(tx, err) {
|
|
8927
9018
|
failure(createDOMException('UnknownError', 'Could not delete index "' + index.name + '"', err));
|
|
8928
9019
|
}
|
|
9020
|
+
/* c8 ignore stop -- see comment above */
|
|
8929
9021
|
|
|
8930
9022
|
/**
|
|
8931
9023
|
* @returns {void}
|
|
@@ -8934,7 +9026,6 @@
|
|
|
8934
9026
|
// Update the object store's index list
|
|
8935
9027
|
IDBIndex.__updateIndexList(store, tx, function (store) {
|
|
8936
9028
|
delete index.__pendingDelete;
|
|
8937
|
-
delete index.__recreated;
|
|
8938
9029
|
index.__deleted = true;
|
|
8939
9030
|
if (indexHandle) {
|
|
8940
9031
|
indexHandle.__deleted = true;
|
|
@@ -8995,20 +9086,18 @@
|
|
|
8995
9086
|
* @param {Query} range
|
|
8996
9087
|
* @param {"value"|"key"|"count"} opType
|
|
8997
9088
|
* @param {boolean} nullDisallowed
|
|
8998
|
-
* @param {number} [count]
|
|
8999
9089
|
* @this {IDBIndexFull}
|
|
9000
9090
|
* @returns {import('./IDBRequest.js').IDBRequestFull}
|
|
9001
9091
|
*/
|
|
9002
|
-
IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed
|
|
9092
|
+
IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed) {
|
|
9003
9093
|
var me = this;
|
|
9004
|
-
if (count !== undefined) {
|
|
9005
|
-
count = enforceRange(count, 'unsigned long');
|
|
9006
|
-
}
|
|
9007
9094
|
IDBIndex.__invalidStateIfDeleted(me);
|
|
9008
9095
|
IDBObjectStore.__invalidStateIfDeleted(me.objectStore);
|
|
9096
|
+
/* c8 ignore start -- Defensive: `IDBObjectStore.__invalidStateIfDeleted` just above already throws when `me.objectStore.__deleted` is true, so this identical check can never be reached. */
|
|
9009
9097
|
if (me.objectStore.__deleted) {
|
|
9010
9098
|
throw createDOMException('InvalidStateError', "This index's object store has been deleted");
|
|
9011
9099
|
}
|
|
9100
|
+
/* c8 ignore stop -- see comment above */
|
|
9012
9101
|
IDBTransaction.__assertActive(me.objectStore.transaction);
|
|
9013
9102
|
if (nullDisallowed && isNullish(range)) {
|
|
9014
9103
|
throw createDOMException('DataError', 'No key or range was specified');
|
|
@@ -9018,7 +9107,7 @@
|
|
|
9018
9107
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
9019
9108
|
args[_key] = arguments[_key];
|
|
9020
9109
|
}
|
|
9021
|
-
executeFetchIndexData.apply(void 0,
|
|
9110
|
+
executeFetchIndexData.apply(void 0, _toConsumableArray(fetchArgs).concat(args));
|
|
9022
9111
|
}, undefined, me);
|
|
9023
9112
|
};
|
|
9024
9113
|
|
|
@@ -9177,13 +9266,16 @@
|
|
|
9177
9266
|
var colInfoToPreserve = colInfoToPreserveArr.map(function (colInfo) {
|
|
9178
9267
|
return colInfo.join(' ');
|
|
9179
9268
|
});
|
|
9269
|
+
/* 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. */
|
|
9180
9270
|
var listColInfoToPreserve = colInfoToPreserve.length ? colInfoToPreserve.join(', ') + ', ' : '';
|
|
9271
|
+
/* c8 ignore next -- Defensive: see comment above. */
|
|
9181
9272
|
var listColsToPreserve = colNamesToPreserve.length ? colNamesToPreserve.join(', ') + ', ' : '';
|
|
9182
9273
|
|
|
9183
9274
|
// We could adapt the approach at https://stackoverflow.com/a/8430746/271577
|
|
9184
9275
|
// to make the approach reusable without passing column names, but it is a bit fragile
|
|
9185
9276
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
9186
9277
|
store.transaction.__addNonRequestToTransactionQueue(function renameIndex(tx, args, success, error) {
|
|
9278
|
+
/* 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. */
|
|
9187
9279
|
/**
|
|
9188
9280
|
* @param {WebSQLTransaction} tx
|
|
9189
9281
|
* @param {(Error & {code?: number})} err
|
|
@@ -9192,6 +9284,7 @@
|
|
|
9192
9284
|
function sqlError(tx, err) {
|
|
9193
9285
|
error(err);
|
|
9194
9286
|
}
|
|
9287
|
+
/* c8 ignore stop -- see comment above */
|
|
9195
9288
|
/**
|
|
9196
9289
|
* @returns {void}
|
|
9197
9290
|
*/
|
|
@@ -9200,8 +9293,14 @@
|
|
|
9200
9293
|
cb(tx, success);
|
|
9201
9294
|
return;
|
|
9202
9295
|
}
|
|
9296
|
+
/* 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. */
|
|
9203
9297
|
success();
|
|
9204
9298
|
}
|
|
9299
|
+
/* c8 ignore stop -- see comment above */
|
|
9300
|
+
if (!CFG.useSQLiteIndexes) {
|
|
9301
|
+
finish();
|
|
9302
|
+
return;
|
|
9303
|
+
}
|
|
9205
9304
|
// See https://www.sqlite.org/lang_altertable.html#otheralter
|
|
9206
9305
|
// We don't query for indexes as we already have the info
|
|
9207
9306
|
// This approach has the advantage of auto-deleting indexes via the DROP TABLE
|
|
@@ -9225,10 +9324,6 @@
|
|
|
9225
9324
|
console.log(sql);
|
|
9226
9325
|
}
|
|
9227
9326
|
tx.executeSql(sql, [], function (tx) {
|
|
9228
|
-
if (!CFG.useSQLiteIndexes) {
|
|
9229
|
-
finish();
|
|
9230
|
-
return;
|
|
9231
|
-
}
|
|
9232
9327
|
var indexCreations = colNamesToPreserve.slice(2) // Doing `key` separately and no need for index on `value`
|
|
9233
9328
|
.map(function (escapedIndexNameSQL) {
|
|
9234
9329
|
return new SyncPromise(function (resolve, reject) {
|
|
@@ -9237,13 +9332,16 @@
|
|
|
9237
9332
|
// if (CFG.DEBUG) { console.log(sql); }
|
|
9238
9333
|
// tx.executeSql(sql, [], function () {
|
|
9239
9334
|
var sql = 'CREATE INDEX ' + escapedIndexToRecreate + ' ON ' + escapedStoreNameSQL + '(' + escapedIndexNameSQL + ')';
|
|
9335
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
9240
9336
|
if (CFG.DEBUG) {
|
|
9241
9337
|
console.log(sql);
|
|
9242
9338
|
}
|
|
9243
|
-
tx.executeSql(sql, [], resolve,
|
|
9339
|
+
tx.executeSql(sql, [], resolve, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9340
|
+
/** @type {SqlErrorCallback} */
|
|
9244
9341
|
function (tx, err) {
|
|
9245
9342
|
reject(err);
|
|
9246
|
-
}
|
|
9343
|
+
}
|
|
9344
|
+
/* c8 ignore stop -- see comment above */);
|
|
9247
9345
|
// }, function (tx, err) {
|
|
9248
9346
|
// reject(err);
|
|
9249
9347
|
// });
|
|
@@ -9261,19 +9359,25 @@
|
|
|
9261
9359
|
if (CFG.DEBUG) {
|
|
9262
9360
|
console.log(sql);
|
|
9263
9361
|
}
|
|
9264
|
-
tx.executeSql(sql, [], resolve,
|
|
9362
|
+
tx.executeSql(sql, [], resolve, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9363
|
+
/** @type {SqlErrorCallback} */
|
|
9265
9364
|
function (tx, err) {
|
|
9266
9365
|
reject(err);
|
|
9267
|
-
}
|
|
9268
|
-
|
|
9366
|
+
}
|
|
9367
|
+
/* c8 ignore stop -- see comment above */);
|
|
9368
|
+
}, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9369
|
+
/** @type {SqlErrorCallback} */
|
|
9269
9370
|
function (tx, err) {
|
|
9270
9371
|
reject(err);
|
|
9271
|
-
}
|
|
9372
|
+
}
|
|
9373
|
+
/* c8 ignore stop -- see comment above */);
|
|
9272
9374
|
}));
|
|
9273
9375
|
SyncPromise.all(indexCreations).then(finish).catch(/** @type {(reason: unknown) => PromiseLike<never>} */
|
|
9274
9376
|
error).catch(function (err) {
|
|
9377
|
+
/* c8 ignore start -- Defensive: only reached if `finish` or the outer `error` callback itself throws; not reliably reproducible. */
|
|
9275
9378
|
console.log('Index rename error');
|
|
9276
9379
|
throw err;
|
|
9380
|
+
/* c8 ignore stop -- see comment above */
|
|
9277
9381
|
});
|
|
9278
9382
|
}, /** @type {SqlErrorCallback} */sqlError);
|
|
9279
9383
|
}, /** @type {SqlErrorCallback} */sqlError);
|
|
@@ -9302,7 +9406,6 @@
|
|
|
9302
9406
|
/* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
|
|
9303
9407
|
|
|
9304
9408
|
/**
|
|
9305
|
-
* @param {number|null} count
|
|
9306
9409
|
* @param {boolean} unboundedDisallowed
|
|
9307
9410
|
* @param {IDBIndexFull} index
|
|
9308
9411
|
* @param {boolean} hasKey
|
|
@@ -9319,12 +9422,9 @@
|
|
|
9319
9422
|
* @param {(tx: WebSQLTransaction, err: (Error & {code?: number})) => void} error
|
|
9320
9423
|
* @returns {void}
|
|
9321
9424
|
*/
|
|
9322
|
-
function executeFetchIndexData(
|
|
9425
|
+
function executeFetchIndexData(unboundedDisallowed, index, hasKey, range, opType, multiChecks, sql, sqlValues, tx, args, success, error) {
|
|
9323
9426
|
if (unboundedDisallowed) {
|
|
9324
|
-
|
|
9325
|
-
}
|
|
9326
|
-
if (count) {
|
|
9327
|
-
sql.push('LIMIT', String(count));
|
|
9427
|
+
sql.push('LIMIT', '1');
|
|
9328
9428
|
}
|
|
9329
9429
|
var isCount = opType === 'count';
|
|
9330
9430
|
if (CFG.DEBUG) {
|
|
@@ -9362,41 +9462,48 @@
|
|
|
9362
9462
|
var escapedIndexNameForKeyCol = escapeIndexNameForSQLKeyColumn(index.name);
|
|
9363
9463
|
var encodedKey = _encode(range, index.multiEntry);
|
|
9364
9464
|
var _loop = function _loop() {
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
|
|
9381
|
-
|
|
9382
|
-
|
|
9383
|
-
|
|
9384
|
-
record = row;
|
|
9385
|
-
} else if (!hasKey && !multiChecks) {
|
|
9386
|
-
if (rowKey !== undefined) {
|
|
9387
|
-
recordCount += Array.isArray(rowKey) ? rowKey.length : 1;
|
|
9465
|
+
var row = /** @type {{key: string, value: string, [k: string]: string}} */data.rows.item(i);
|
|
9466
|
+
var rowKey = /** @type {import('./Key.js').ValueTypeArray} */
|
|
9467
|
+
_decode(row[escapedIndexNameForKeyCol]);
|
|
9468
|
+
var record;
|
|
9469
|
+
if (hasKey && (multiChecks && /** @type {import('./Key.js').ValueType[]} */range.some(
|
|
9470
|
+
/**
|
|
9471
|
+
* @param {import('./Key.js').ValueType} check
|
|
9472
|
+
* @returns {boolean}
|
|
9473
|
+
*/
|
|
9474
|
+
function (check) {
|
|
9475
|
+
return rowKey.includes(check);
|
|
9476
|
+
}) ||
|
|
9477
|
+
// More precise than our SQL
|
|
9478
|
+
isMultiEntryMatch(
|
|
9479
|
+
// Added `JSON.stringify` as was having problems with
|
|
9480
|
+
// `JSON.stringify` encoding added to nested
|
|
9481
|
+
// array keys
|
|
9482
|
+
JSON.stringify(encodedKey).slice(1, -1), row[escapedIndexNameForKeyCol]))) {
|
|
9483
|
+
recordCount++;
|
|
9388
9484
|
record = row;
|
|
9485
|
+
} else if (!hasKey && !multiChecks) {
|
|
9486
|
+
if (rowKey !== undefined) {
|
|
9487
|
+
recordCount += Array.isArray(rowKey) ? rowKey.length : 1;
|
|
9488
|
+
record = row;
|
|
9489
|
+
}
|
|
9389
9490
|
}
|
|
9390
|
-
|
|
9391
|
-
|
|
9491
|
+
/* 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. */
|
|
9492
|
+
if (!record) {
|
|
9493
|
+
return 0; // continue
|
|
9494
|
+
}
|
|
9495
|
+
/* c8 ignore stop -- see comment above */
|
|
9496
|
+
|
|
9392
9497
|
records.push(decode$1(record));
|
|
9393
9498
|
if (unboundedDisallowed) {
|
|
9394
9499
|
return 1; // break
|
|
9395
9500
|
}
|
|
9396
|
-
}
|
|
9397
|
-
|
|
9501
|
+
},
|
|
9502
|
+
_ret;
|
|
9398
9503
|
for (var i = 0; i < data.rows.length; i++) {
|
|
9399
|
-
|
|
9504
|
+
_ret = _loop();
|
|
9505
|
+
if (_ret === 0) continue;
|
|
9506
|
+
if (_ret === 1) break;
|
|
9400
9507
|
}
|
|
9401
9508
|
} else {
|
|
9402
9509
|
for (var _i = 0; _i < data.rows.length; _i++) {
|
|
@@ -9410,8 +9517,16 @@
|
|
|
9410
9517
|
if (isCount) {
|
|
9411
9518
|
success(recordCount);
|
|
9412
9519
|
} else if (recordCount === 0) {
|
|
9520
|
+
// `unboundedDisallowed` is always `true` here: this function is only reached (for
|
|
9521
|
+
// non-`count` `opType`s) via `get`/`getKey`, which always pass `nullDisallowed: true`
|
|
9522
|
+
// through as `unboundedDisallowed`. `getAll`/`getAllKeys`/`getAllRecords` use a
|
|
9523
|
+
// different (cursor-based) code path, so the `unboundedDisallowed`-`false` case
|
|
9524
|
+
// (returning `[]` here) is unreachable given current callers.
|
|
9525
|
+
/* c8 ignore next -- see comment above */
|
|
9413
9526
|
success(unboundedDisallowed ? undefined : []);
|
|
9414
9527
|
} else {
|
|
9528
|
+
// `unboundedDisallowed` is always `true` here; see comment above.
|
|
9529
|
+
/* c8 ignore next -- see comment above */
|
|
9415
9530
|
success(unboundedDisallowed ? records[0] : records);
|
|
9416
9531
|
}
|
|
9417
9532
|
}, /** @type {SqlErrorCallback} */error);
|
|
@@ -9655,6 +9770,7 @@
|
|
|
9655
9770
|
tx.executeSql(sql, sqlValues, function (tx) {
|
|
9656
9771
|
// This SQL preserves indexes per https://www.sqlite.org/lang_altertable.html
|
|
9657
9772
|
var sql = 'ALTER TABLE ' + escapeStoreNameForSQL(oldName) + ' RENAME TO ' + escapeStoreNameForSQL(name);
|
|
9773
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG` while renaming a store. */
|
|
9658
9774
|
if (CFG.DEBUG) {
|
|
9659
9775
|
console.log(sql);
|
|
9660
9776
|
}
|
|
@@ -9663,8 +9779,10 @@
|
|
|
9663
9779
|
success();
|
|
9664
9780
|
});
|
|
9665
9781
|
}, function (tx, err) {
|
|
9782
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9666
9783
|
error(err);
|
|
9667
9784
|
return false;
|
|
9785
|
+
/* c8 ignore stop -- see comment above */
|
|
9668
9786
|
});
|
|
9669
9787
|
});
|
|
9670
9788
|
}
|
|
@@ -9738,6 +9856,7 @@
|
|
|
9738
9856
|
storeHandles[storeName] = IDBObjectStore.__clone(store, transaction);
|
|
9739
9857
|
}
|
|
9740
9858
|
transaction.__addNonRequestToTransactionQueue(function createObjectStore(tx, args, success, failure) {
|
|
9859
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9741
9860
|
/**
|
|
9742
9861
|
* @param {WebSQLTransaction} tx
|
|
9743
9862
|
* @param {(Error & {code?: number})} [err]
|
|
@@ -9750,6 +9869,8 @@
|
|
|
9750
9869
|
failure(createDOMException('UnknownError', 'Could not create object store "' + storeName + '"', err));
|
|
9751
9870
|
return false;
|
|
9752
9871
|
}
|
|
9872
|
+
/* c8 ignore stop -- see comment above */
|
|
9873
|
+
|
|
9753
9874
|
var escapedStoreNameSQL = escapeStoreNameForSQL(storeName);
|
|
9754
9875
|
// key INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE
|
|
9755
9876
|
var sql = ['CREATE TABLE', escapedStoreNameSQL, '(key BLOB', store.autoIncrement ? 'UNIQUE, inc INTEGER PRIMARY KEY AUTOINCREMENT' : 'PRIMARY KEY', ', value BLOB)'].join(' ');
|
|
@@ -9804,6 +9925,7 @@
|
|
|
9804
9925
|
|
|
9805
9926
|
// Remove the object store from WebSQL
|
|
9806
9927
|
transaction.__addNonRequestToTransactionQueue(function deleteObjectStore(tx, args, success, failure) {
|
|
9928
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9807
9929
|
/**
|
|
9808
9930
|
* @param {WebSQLTransaction} tx
|
|
9809
9931
|
* @param {(Error & {code?: number})} [err]
|
|
@@ -9816,6 +9938,8 @@
|
|
|
9816
9938
|
failure(createDOMException('UnknownError', 'Could not delete ObjectStore', err));
|
|
9817
9939
|
return false;
|
|
9818
9940
|
}
|
|
9941
|
+
/* c8 ignore stop -- see comment above */
|
|
9942
|
+
|
|
9819
9943
|
tx.executeSql('SELECT "name" FROM __sys__ WHERE "name" = ?', [escapeSQLiteStatement(store.__currentName)], function (tx, data) {
|
|
9820
9944
|
if (data.rows.length > 0) {
|
|
9821
9945
|
tx.executeSql('DROP TABLE ' + escapeStoreNameForSQL(store.__currentName), [], function () {
|
|
@@ -9995,13 +10119,15 @@
|
|
|
9995
10119
|
return;
|
|
9996
10120
|
}
|
|
9997
10121
|
var indexKeyValue = indexKey.value;
|
|
10122
|
+
/* 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. */
|
|
9998
10123
|
if (indexKeyValue === undefined) {
|
|
9999
10124
|
resolve(undefined);
|
|
10000
10125
|
return;
|
|
10001
10126
|
}
|
|
10127
|
+
/* c8 ignore stop -- see comment above */
|
|
10002
10128
|
var multiCheck = index.multiEntry && Array.isArray(indexKeyValue);
|
|
10003
10129
|
var fetchArgs = buildFetchIndexDataSQL(true, index, indexKeyValue, 'key', multiCheck);
|
|
10004
|
-
executeFetchIndexData.apply(void 0,
|
|
10130
|
+
executeFetchIndexData.apply(void 0, _toConsumableArray(fetchArgs).concat([tx, null, function success(key) {
|
|
10005
10131
|
if (key === undefined || excludeKey !== undefined && cmp(/** @type {import('./Key.js').Key} */key, excludeKey) === 0) {
|
|
10006
10132
|
resolve(undefined);
|
|
10007
10133
|
return;
|
|
@@ -10081,16 +10207,18 @@
|
|
|
10081
10207
|
* @returns {void}
|
|
10082
10208
|
*/
|
|
10083
10209
|
function setIndexInfo(index) {
|
|
10210
|
+
/* 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. */
|
|
10084
10211
|
if (indexKeyValue === undefined) {
|
|
10085
10212
|
return;
|
|
10086
10213
|
}
|
|
10214
|
+
/* c8 ignore stop -- see comment above */
|
|
10087
10215
|
paramMap[index.__currentName] = /** @type {string} */
|
|
10088
10216
|
_encode(indexKeyValue, index.multiEntry);
|
|
10089
10217
|
}
|
|
10090
10218
|
if (index.unique) {
|
|
10091
10219
|
var multiCheck = index.multiEntry && Array.isArray(indexKeyValue);
|
|
10092
10220
|
var fetchArgs = buildFetchIndexDataSQL(true, index, indexKeyValue, 'key', multiCheck);
|
|
10093
|
-
executeFetchIndexData.apply(void 0,
|
|
10221
|
+
executeFetchIndexData.apply(void 0, _toConsumableArray(fetchArgs).concat([tx, null, function success(key) {
|
|
10094
10222
|
if (key === undefined) {
|
|
10095
10223
|
setIndexInfo(index);
|
|
10096
10224
|
resolve(undefined);
|
|
@@ -10181,6 +10309,7 @@
|
|
|
10181
10309
|
_me$__validateKeyAndV2 = _slicedToArray(_me$__validateKeyAndV, 2),
|
|
10182
10310
|
ky = _me$__validateKeyAndV2[0],
|
|
10183
10311
|
clonedValue = _me$__validateKeyAndV2[1];
|
|
10312
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
10184
10313
|
// @ts-ignore -- Private API
|
|
10185
10314
|
IDBObjectStore.__storingRecordObjectStore(request, me, true, clonedValue, true, ky);
|
|
10186
10315
|
return request;
|
|
@@ -10212,6 +10341,7 @@
|
|
|
10212
10341
|
_me$__validateKeyAndV4 = _slicedToArray(_me$__validateKeyAndV3, 2),
|
|
10213
10342
|
ky = _me$__validateKeyAndV4[0],
|
|
10214
10343
|
clonedValue = _me$__validateKeyAndV4[1];
|
|
10344
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
10215
10345
|
// @ts-ignore -- Private API
|
|
10216
10346
|
IDBObjectStore.__storingRecordObjectStore(request, me, true, clonedValue, false, ky);
|
|
10217
10347
|
return request;
|
|
@@ -10238,8 +10368,10 @@
|
|
|
10238
10368
|
}
|
|
10239
10369
|
cb(tx);
|
|
10240
10370
|
}, function (tx, err) {
|
|
10371
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
10241
10372
|
error(err);
|
|
10242
10373
|
return false;
|
|
10374
|
+
/* c8 ignore stop -- see comment above */
|
|
10243
10375
|
});
|
|
10244
10376
|
};
|
|
10245
10377
|
|
|
@@ -10348,16 +10480,20 @@
|
|
|
10348
10480
|
return;
|
|
10349
10481
|
}
|
|
10350
10482
|
ret = getKey ? _decode(unescapeSQLiteResponse(/** @type {{key: string}} */data.rows.item(0).key), false) : decode(unescapeSQLiteResponse(/** @type {{value: string}} */data.rows.item(0).value));
|
|
10483
|
+
/* 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. */
|
|
10351
10484
|
} catch (e) {
|
|
10352
10485
|
// If no result is returned, or error occurs when parsing JSON
|
|
10353
10486
|
if (CFG.DEBUG) {
|
|
10354
10487
|
console.log(e);
|
|
10355
10488
|
}
|
|
10356
10489
|
}
|
|
10490
|
+
/* c8 ignore stop -- see comment above */
|
|
10357
10491
|
success(ret);
|
|
10358
10492
|
}, function (tx, err) {
|
|
10493
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
10359
10494
|
error(err);
|
|
10360
10495
|
return false;
|
|
10496
|
+
/* c8 ignore stop -- see comment above */
|
|
10361
10497
|
});
|
|
10362
10498
|
}, undefined, me);
|
|
10363
10499
|
};
|
|
@@ -10469,8 +10605,10 @@
|
|
|
10469
10605
|
});
|
|
10470
10606
|
success();
|
|
10471
10607
|
}, function (tx, err) {
|
|
10608
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
10472
10609
|
error(err);
|
|
10473
10610
|
return false;
|
|
10611
|
+
/* c8 ignore stop -- see comment above */
|
|
10474
10612
|
});
|
|
10475
10613
|
}, undefined, me);
|
|
10476
10614
|
};
|
|
@@ -10498,8 +10636,10 @@
|
|
|
10498
10636
|
});
|
|
10499
10637
|
success();
|
|
10500
10638
|
}, function (tx, err) {
|
|
10639
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
10501
10640
|
error(err);
|
|
10502
10641
|
return false;
|
|
10642
|
+
/* c8 ignore stop -- see comment above */
|
|
10503
10643
|
});
|
|
10504
10644
|
}, undefined, me);
|
|
10505
10645
|
};
|
|
@@ -10834,7 +10974,7 @@
|
|
|
10834
10974
|
if (keyPath !== null && !isValidKeyPath(keyPath)) {
|
|
10835
10975
|
throw createDOMException('SyntaxError', 'The keyPath argument contains an invalid key path.');
|
|
10836
10976
|
}
|
|
10837
|
-
if (Object.hasOwn(this.__objectStores, storeName) && !this.__objectStores[storeName].__pendingDelete) {
|
|
10977
|
+
if (Object.hasOwn(this.__objectStores, storeName) && !this.__objectStores[storeName].__pendingDelete && !this.__objectStores[storeName].__deleted) {
|
|
10838
10978
|
throw createDOMException('ConstraintError', 'Object store "' + storeName + '" already exists in ' + this.name);
|
|
10839
10979
|
}
|
|
10840
10980
|
var autoInc = createOptions.autoIncrement;
|
|
@@ -10983,7 +11123,6 @@
|
|
|
10983
11123
|
}
|
|
10984
11124
|
};
|
|
10985
11125
|
|
|
10986
|
-
// Todo __forceClose: Add tests for `__forceClose`
|
|
10987
11126
|
/**
|
|
10988
11127
|
*
|
|
10989
11128
|
* @param {string} msg
|
|
@@ -10992,23 +11131,39 @@
|
|
|
10992
11131
|
*/
|
|
10993
11132
|
IDBDatabase.prototype.__forceClose = function (msg) {
|
|
10994
11133
|
var me = this;
|
|
11134
|
+
// `close()` (below) resets `me.__transactions` to `[]`, so the
|
|
11135
|
+
// transactions to abort -- and the total count the completion check
|
|
11136
|
+
// below needs -- must be captured before calling it, not read back off
|
|
11137
|
+
// `me.__transactions` afterward.
|
|
11138
|
+
var transactions = me.__transactions;
|
|
10995
11139
|
me.close();
|
|
11140
|
+
|
|
11141
|
+
/**
|
|
11142
|
+
* @returns {void}
|
|
11143
|
+
*/
|
|
11144
|
+
function dispatchClose() {
|
|
11145
|
+
// Todo __forceClose: unblock any pending `upgradeneeded` or `deleteDatabase` calls
|
|
11146
|
+
var evt = createEvent('close');
|
|
11147
|
+
setTimeout(function () {
|
|
11148
|
+
me.dispatchEvent(evt);
|
|
11149
|
+
}, 0);
|
|
11150
|
+
}
|
|
11151
|
+
if (!transactions.length) {
|
|
11152
|
+
dispatchClose();
|
|
11153
|
+
return;
|
|
11154
|
+
}
|
|
10996
11155
|
var ct = 0;
|
|
10997
|
-
|
|
11156
|
+
transactions.forEach(function (trans) {
|
|
10998
11157
|
// eslint-disable-next-line camelcase -- Clear API
|
|
10999
11158
|
trans.on__abort = function () {
|
|
11000
11159
|
ct++;
|
|
11001
|
-
if (ct
|
|
11002
|
-
|
|
11003
|
-
var evt = createEvent('close');
|
|
11004
|
-
setTimeout(function () {
|
|
11005
|
-
me.dispatchEvent(evt);
|
|
11006
|
-
}, 0);
|
|
11160
|
+
if (ct !== transactions.length) {
|
|
11161
|
+
return;
|
|
11007
11162
|
}
|
|
11163
|
+
dispatchClose();
|
|
11008
11164
|
};
|
|
11009
11165
|
trans.__abortTransaction(createDOMException('AbortError', 'The connection was force-closed: ' + (msg || '')));
|
|
11010
11166
|
});
|
|
11011
|
-
me.__transactions = [];
|
|
11012
11167
|
};
|
|
11013
11168
|
/* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
|
|
11014
11169
|
defineOuterInterface(IDBDatabase.prototype, listeners);
|
|
@@ -11175,6 +11330,7 @@
|
|
|
11175
11330
|
return undefined;
|
|
11176
11331
|
}
|
|
11177
11332
|
var e = /** @type {Event & IDBVersionChangeEvent} */
|
|
11333
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11178
11334
|
// @ts-ignore It's ok; needed under some TS versions
|
|
11179
11335
|
new IDBVersionChangeEvent('versionchange', {
|
|
11180
11336
|
oldVersion: oldVersion,
|
|
@@ -11222,6 +11378,7 @@
|
|
|
11222
11378
|
}
|
|
11223
11379
|
};
|
|
11224
11380
|
var e = /** @type {Event & IDBVersionChangeEvent} */
|
|
11381
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11225
11382
|
// @ts-ignore It's ok; needed under some TS versions
|
|
11226
11383
|
new IDBVersionChangeEvent('blocked', {
|
|
11227
11384
|
oldVersion: oldVersion,
|
|
@@ -11282,6 +11439,13 @@
|
|
|
11282
11439
|
|
|
11283
11440
|
/** @type {import('websql-configurable/lib/websql/WebSQLDatabase.js').default} */
|
|
11284
11441
|
var sysdb;
|
|
11442
|
+
// Tracks which `CFG.memoryDatabase` value `sysdb` was opened against, so a
|
|
11443
|
+
// later change to that config (e.g. toggling in-memory mode on and back
|
|
11444
|
+
// off) causes `sysdb` to be recreated for the new setting rather than
|
|
11445
|
+
// staying pinned, forever, to whatever it was the first time any database
|
|
11446
|
+
// was created in the process.
|
|
11447
|
+
/** @type {string|null|undefined} */
|
|
11448
|
+
var sysdbMemoryDatabaseSetting;
|
|
11285
11449
|
var nameCounter = 0;
|
|
11286
11450
|
|
|
11287
11451
|
/**
|
|
@@ -11363,12 +11527,20 @@
|
|
|
11363
11527
|
function cleanupDatabaseResources(__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError) {
|
|
11364
11528
|
var useMemoryDatabase = typeof CFG.memoryDatabase === 'string';
|
|
11365
11529
|
if (useMemoryDatabase) {
|
|
11530
|
+
/* c8 ignore start -- Defensive: only reachable if `websqlDBCache[name]`
|
|
11531
|
+
was initialized as an empty placeholder by `open()`'s connection-queue
|
|
11532
|
+
setup (`addRequestToConnectionQueue`, above `openDB`) but never
|
|
11533
|
+
populated with an actual instance -- e.g. `__openDatabase` throwing
|
|
11534
|
+
after a `dbVersions` row already existed for `name` from an earlier,
|
|
11535
|
+
successful `open()` -- or if `name` was never added to the cache at
|
|
11536
|
+
all. Not reachable via normal, non-tampered API usage. */
|
|
11366
11537
|
var latestSQLiteDBCached = Object.hasOwn(websqlDBCache, name) ? getLatestCachedWebSQLDB(name) : null;
|
|
11367
11538
|
if (!latestSQLiteDBCached) {
|
|
11368
11539
|
console.warn('Could not find a memory database instance to delete.');
|
|
11369
11540
|
databaseDeleted();
|
|
11370
11541
|
return;
|
|
11371
11542
|
}
|
|
11543
|
+
/* c8 ignore stop -- see comment above */
|
|
11372
11544
|
var _sqliteDB = latestSQLiteDBCached._db;
|
|
11373
11545
|
if (!_sqliteDB || !_sqliteDB.close) {
|
|
11374
11546
|
console.error('The `openDatabase` implementation does not have the expected `._db.close` method for closing the database');
|
|
@@ -11422,15 +11594,24 @@
|
|
|
11422
11594
|
tables.item(i).name)), [], function () {
|
|
11423
11595
|
deleteTables(i + 1);
|
|
11424
11596
|
}, function () {
|
|
11597
|
+
/* c8 ignore start -- Defensive: continues deleting the rest
|
|
11598
|
+
even if this specific store's table is already gone (e.g.
|
|
11599
|
+
duplicate `__sys__` rows for the same escaped table name, or
|
|
11600
|
+
external tampering); not reachable via normal API usage. */
|
|
11425
11601
|
deleteTables(i + 1);
|
|
11426
11602
|
return false;
|
|
11603
|
+
/* c8 ignore stop -- see comment above */
|
|
11427
11604
|
});
|
|
11428
11605
|
}
|
|
11429
11606
|
})(0);
|
|
11430
11607
|
}, function () {
|
|
11431
|
-
|
|
11608
|
+
/* c8 ignore start -- `__sys__` is always created by `openDB` before this
|
|
11609
|
+
database's `dbVersions` row (a prerequisite for reaching this code at
|
|
11610
|
+
all) is ever inserted; only reachable if the file was tampered with/
|
|
11611
|
+
removed externally afterward. */
|
|
11432
11612
|
databaseDeleted();
|
|
11433
11613
|
return false;
|
|
11614
|
+
/* c8 ignore stop -- see comment above */
|
|
11434
11615
|
});
|
|
11435
11616
|
});
|
|
11436
11617
|
}
|
|
@@ -11461,9 +11642,11 @@
|
|
|
11461
11642
|
}
|
|
11462
11643
|
failure(er);
|
|
11463
11644
|
}
|
|
11464
|
-
if (sysdb) {
|
|
11645
|
+
if (sysdb && sysdbMemoryDatabaseSetting === CFG.memoryDatabase) {
|
|
11465
11646
|
success();
|
|
11466
11647
|
} else {
|
|
11648
|
+
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Needed
|
|
11649
|
+
sysdbMemoryDatabaseSetting = CFG.memoryDatabase;
|
|
11467
11650
|
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Necessary?
|
|
11468
11651
|
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);
|
|
11469
11652
|
sysdb.transaction(function (systx) {
|
|
@@ -11643,6 +11826,17 @@
|
|
|
11643
11826
|
* @returns {void}
|
|
11644
11827
|
*/
|
|
11645
11828
|
var sysdbFinishedCb = function sysdbFinishedCb(systx, err, cb) {
|
|
11829
|
+
/* c8 ignore start -- This initial definition is always
|
|
11830
|
+
superseded before ever being invoked: the `sysdb.transaction(...)`
|
|
11831
|
+
call below always reaches its `nonstandardTransCb` (4th arg)
|
|
11832
|
+
after this same SQL batch finishes running (since `dbCreateError`
|
|
11833
|
+
always reports errors as "handled" and this call site is never
|
|
11834
|
+
a `readTransaction`), which unconditionally reassigns
|
|
11835
|
+
`sysdbFinishedCb` to a version using the library's own
|
|
11836
|
+
`rollback`/`commit` -- well before any real invocation from
|
|
11837
|
+
`on__beforecomplete`/`on__preabort`/`on__abort` below (those only
|
|
11838
|
+
fire once the upgrade transaction itself later completes/aborts).
|
|
11839
|
+
Kept as a defensive fallback in case that invariant ever changes. */
|
|
11646
11840
|
if (err) {
|
|
11647
11841
|
/**
|
|
11648
11842
|
* @param {unknown} [errorToShow]
|
|
@@ -11691,6 +11885,7 @@
|
|
|
11691
11885
|
}
|
|
11692
11886
|
// In browser, should auto-commit
|
|
11693
11887
|
cb(); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11888
|
+
/* c8 ignore stop -- see comment above */
|
|
11694
11889
|
};
|
|
11695
11890
|
sysdb.transaction(function (systx) {
|
|
11696
11891
|
/**
|
|
@@ -11698,6 +11893,7 @@
|
|
|
11698
11893
|
*/
|
|
11699
11894
|
function versionSet() {
|
|
11700
11895
|
var e = /** @type {import('eventtargeter').EventWithProps & Event & IDBVersionChangeEvent} */
|
|
11896
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11701
11897
|
// @ts-ignore It's ok; needed under some TS versions
|
|
11702
11898
|
new IDBVersionChangeEvent('upgradeneeded', {
|
|
11703
11899
|
oldVersion: oldVersion,
|
|
@@ -11823,9 +12019,17 @@
|
|
|
11823
12019
|
// eslint-disable-next-line camelcase -- Clear API
|
|
11824
12020
|
req.transaction.on__complete = function () {
|
|
11825
12021
|
var pos = connection.__transactions.indexOf(req.transaction);
|
|
12022
|
+
// `req.transaction` (the versionchange transaction) is created
|
|
12023
|
+
// directly via `IDBTransaction.__createInstance` above, never
|
|
12024
|
+
// via `IDBDatabase.prototype.transaction()` (the only place
|
|
12025
|
+
// that pushes onto `connection.__transactions`), so `pos` is
|
|
12026
|
+
// always -1 here.
|
|
12027
|
+
/* c8 ignore start -- see comment above */
|
|
11826
12028
|
if (pos !== -1) {
|
|
11827
12029
|
connection.__transactions.splice(pos, 1);
|
|
11828
12030
|
}
|
|
12031
|
+
/* c8 ignore stop -- see comment above */
|
|
12032
|
+
|
|
11829
12033
|
if (/** @type {import('./IDBDatabase.js').IDBDatabaseFull} */req.__result.__closePending) {
|
|
11830
12034
|
req.__transaction = null;
|
|
11831
12035
|
var err = createDOMException('AbortError', 'The connection has been closed.');
|
|
@@ -11861,9 +12065,16 @@
|
|
|
11861
12065
|
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [version, sqlSafeName], versionSet, dbCreateError);
|
|
11862
12066
|
}
|
|
11863
12067
|
}, dbCreateError, undefined, function (currentTask, err, done, rollback, commit) {
|
|
12068
|
+
// Defensive fallback, not reachable in practice: same reasoning
|
|
12069
|
+
// as `deleteDatabase`'s own `nonstandardTransCb` below
|
|
12070
|
+
// (`currentTask.readOnly` is always false here, and
|
|
12071
|
+
// `dbCreateError` always returns `false`, so `err` is never
|
|
12072
|
+
// truthy either).
|
|
12073
|
+
/* c8 ignore start -- see comment above */
|
|
11864
12074
|
if (currentTask.readOnly || err) {
|
|
11865
12075
|
return true;
|
|
11866
12076
|
}
|
|
12077
|
+
/* c8 ignore stop -- see comment above */
|
|
11867
12078
|
sysdbFinishedCb = function sysdbFinishedCb(systx, err, cb) {
|
|
11868
12079
|
if (err) {
|
|
11869
12080
|
rollback(err,
|
|
@@ -11878,7 +12089,17 @@
|
|
|
11878
12089
|
} else {
|
|
11879
12090
|
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [oldVersion, sqlSafeName]);
|
|
11880
12091
|
}
|
|
11881
|
-
},
|
|
12092
|
+
},
|
|
12093
|
+
// Deeply-nested defensive path: only reached if
|
|
12094
|
+
// the *revert* SQL (undoing the `dbVersions`
|
|
12095
|
+
// INSERT/UPDATE after the original version-
|
|
12096
|
+
// upgrade itself already failed) fails a
|
|
12097
|
+
// *second* time. Not feasibly triggerable
|
|
12098
|
+
// without fault-injecting the underlying SQL
|
|
12099
|
+
// driver on this specific, already-failing
|
|
12100
|
+
// revert statement.
|
|
12101
|
+
function (sqlErr) {
|
|
12102
|
+
/* c8 ignore next 2 -- see comment above */
|
|
11882
12103
|
isRevertingSysdb = false;
|
|
11883
12104
|
cb(sqlErr); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11884
12105
|
}, function () {
|
|
@@ -11894,8 +12115,20 @@
|
|
|
11894
12115
|
});
|
|
11895
12116
|
return undefined;
|
|
11896
12117
|
}).catch(function (err) {
|
|
12118
|
+
/* c8 ignore start -- Purely defensive: nothing in
|
|
12119
|
+
`triggerAnyVersionChangeAndBlockedEvents`'s promise chain
|
|
12120
|
+
(or this `.then()` continuation above) ever rejects/throws
|
|
12121
|
+
under any reachable application-level condition -- all of
|
|
12122
|
+
its continuations resolve cleanly, and its `dispatchEvent`
|
|
12123
|
+
calls are deliberately fire-and-forget ("No need to catch
|
|
12124
|
+
errors"), running inside a `setTimeout` where a listener
|
|
12125
|
+
throwing becomes an uncaught exception in that macrotask
|
|
12126
|
+
rather than a promise rejection here. This exists solely
|
|
12127
|
+
to surface a truly-unexpected internal bug via the console
|
|
12128
|
+
before rethrowing, not to handle a real, testable error path. */
|
|
11897
12129
|
console.log('Error within `triggerAnyVersionChangeAndBlockedEvents`');
|
|
11898
12130
|
throw err;
|
|
12131
|
+
/* c8 ignore stop -- see comment above */
|
|
11899
12132
|
});
|
|
11900
12133
|
} else {
|
|
11901
12134
|
finishRequest();
|
|
@@ -11923,11 +12156,19 @@
|
|
|
11923
12156
|
if ((useMemoryDatabase || useDatabaseCache) && Object.hasOwn(websqlDBCache, name) && Object.hasOwn(websqlDBCache[name], version)) {
|
|
11924
12157
|
db = websqlDBCache[name][version];
|
|
11925
12158
|
} else {
|
|
11926
|
-
db = /** @type {DatabaseFull} */me.__openDatabase(useMemoryDatabase ? CFG.memoryDatabase : joinPath(CFG.databaseBasePath || '', escapedDatabaseName), '1', name, CFG.DEFAULT_DB_SIZE);
|
|
12159
|
+
db = /** @type {DatabaseFull} */me.__openDatabase(useMemoryDatabase ? (/** @type {string} */CFG.memoryDatabase) : joinPath(CFG.databaseBasePath || '', escapedDatabaseName), '1', name, CFG.DEFAULT_DB_SIZE);
|
|
11927
12160
|
if (useDatabaseCache) {
|
|
12161
|
+
/* c8 ignore start -- Defensive: by the time `openDB` runs,
|
|
12162
|
+
`websqlDBCache[name]` has always already been created by
|
|
12163
|
+
`addRequestToConnectionQueue`'s own callback above (guarded
|
|
12164
|
+
by this same `useDatabaseCache` condition), which always
|
|
12165
|
+
runs first and unconditionally ensures the entry exists
|
|
12166
|
+
before ever calling `openDB`. Kept as a safety net in case
|
|
12167
|
+
that invariant ever changes. */
|
|
11928
12168
|
if (!Object.hasOwn(websqlDBCache, name)) {
|
|
11929
12169
|
websqlDBCache[name] = {};
|
|
11930
12170
|
}
|
|
12171
|
+
/* c8 ignore stop -- see comment above */
|
|
11931
12172
|
websqlDBCache[name][version] = db;
|
|
11932
12173
|
}
|
|
11933
12174
|
}
|
|
@@ -12078,6 +12319,7 @@
|
|
|
12078
12319
|
req.__result = undefined;
|
|
12079
12320
|
req.__done = true;
|
|
12080
12321
|
var e = /** @type {Event & IDBVersionChangeEvent} */
|
|
12322
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
12081
12323
|
// @ts-ignore It's ok; needed under some TS versions
|
|
12082
12324
|
new IDBVersionChangeEvent('success', {
|
|
12083
12325
|
oldVersion: version,
|
|
@@ -12120,9 +12362,23 @@
|
|
|
12120
12362
|
cleanupDatabaseResources(me.__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError);
|
|
12121
12363
|
}, dbError);
|
|
12122
12364
|
}, dbError, undefined, function (currentTask, err, done, rollback, commit) {
|
|
12365
|
+
/* c8 ignore start -- Defensive fallback, not reachable in
|
|
12366
|
+
practice: `currentTask.readOnly` is always `false` here
|
|
12367
|
+
(this callback is only ever attached to the writable
|
|
12368
|
+
`sysdb.transaction(...)` call above, never to a
|
|
12369
|
+
`sysdb.readTransaction(...)`), and `err` can only be
|
|
12370
|
+
truthy if the `DELETE FROM dbVersions` statement's own
|
|
12371
|
+
error callback (`dbError`) reports the failure back to
|
|
12372
|
+
`websql-configurable` as unhandled -- but `dbError`
|
|
12373
|
+
deliberately always `return`s `false`, which tells the
|
|
12374
|
+
library the error was already handled (and to keep
|
|
12375
|
+
`err` falsy here), precisely so this custom
|
|
12376
|
+
`sysdbFinishedCbDelete` rollback/commit path below is
|
|
12377
|
+
used instead of the library's own default rollback. */
|
|
12123
12378
|
if (currentTask.readOnly || err) {
|
|
12124
12379
|
return true;
|
|
12125
12380
|
}
|
|
12381
|
+
/* c8 ignore stop -- see comment above */
|
|
12126
12382
|
sysdbFinishedCbDelete = function sysdbFinishedCbDelete(err, cb) {
|
|
12127
12383
|
if (err) {
|
|
12128
12384
|
rollback(err, cb);
|
|
@@ -12248,10 +12504,9 @@
|
|
|
12248
12504
|
};
|
|
12249
12505
|
|
|
12250
12506
|
/**
|
|
12251
|
-
* @todo forceClose: Test
|
|
12252
12507
|
* This is provided to facilitate unit-testing of the
|
|
12253
12508
|
* closing of a database connection with a forced flag:
|
|
12254
|
-
* <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection
|
|
12509
|
+
* <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection>.
|
|
12255
12510
|
* @param {string} dbName
|
|
12256
12511
|
* @param {Integer} connIdx
|
|
12257
12512
|
* @param {string} msg
|
|
@@ -12352,6 +12607,7 @@
|
|
|
12352
12607
|
* @this {IDBRecordFull}
|
|
12353
12608
|
*/
|
|
12354
12609
|
function IDBRecord() {
|
|
12610
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
12355
12611
|
// @ts-ignore Should be ok
|
|
12356
12612
|
this[Symbol.toStringTag] = 'IDBRecord';
|
|
12357
12613
|
this.__key = key;
|
|
@@ -12388,6 +12644,7 @@
|
|
|
12388
12644
|
if (!(this instanceof IDBRecordAlias)) {
|
|
12389
12645
|
throw new TypeError('Illegal invocation');
|
|
12390
12646
|
}
|
|
12647
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
12391
12648
|
// @ts-ignore `this` is a real instance past the check above (not an issue in TS7)
|
|
12392
12649
|
return this['__' + prop];
|
|
12393
12650
|
});
|
|
@@ -12730,6 +12987,7 @@
|
|
|
12730
12987
|
success(undefined, undefined, undefined);
|
|
12731
12988
|
}
|
|
12732
12989
|
}, function (tx, err) {
|
|
12990
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
12733
12991
|
if (CFG.DEBUG) {
|
|
12734
12992
|
console.log('Could not execute Cursor.continue', sqlStr, sqlValues);
|
|
12735
12993
|
}
|
|
@@ -12913,7 +13171,16 @@
|
|
|
12913
13171
|
if (a.key > b.key) {
|
|
12914
13172
|
return me.direction === 'prev' ? -1 : 1;
|
|
12915
13173
|
}
|
|
13174
|
+
/* c8 ignore start -- Defensive: only reachable if two matches
|
|
13175
|
+
in the same batch shared both the same `matchingKey` and
|
|
13176
|
+
the same primary `key`, which would require the same
|
|
13177
|
+
record's multi-entry array to contain a duplicate value.
|
|
13178
|
+
`Key.js`'s array-to-key conversion already drops duplicate
|
|
13179
|
+
values when a multi-entry index entry is built, so this
|
|
13180
|
+
can never happen in practice; kept only to satisfy the
|
|
13181
|
+
`Array.prototype.sort` comparator contract. */
|
|
12916
13182
|
return 0;
|
|
13183
|
+
/* c8 ignore stop -- see comment above */
|
|
12917
13184
|
});
|
|
12918
13185
|
me.__prefetchedIndex = 0;
|
|
12919
13186
|
me.__prefetchedData = {
|
|
@@ -12932,13 +13199,19 @@
|
|
|
12932
13199
|
console.log('[multiEntry] Preloaded ' + me.__prefetchedData.length + ' records for multiEntry cursor');
|
|
12933
13200
|
}
|
|
12934
13201
|
me.__decode(rows[0], success);
|
|
12935
|
-
},
|
|
13202
|
+
},
|
|
13203
|
+
/* c8 ignore start -- Defensive: guards against an unexpected SQLite
|
|
13204
|
+
execution error (e.g. I/O error, corruption) while querying for
|
|
13205
|
+
multi-entry cursor matches; not reliably reproducible without
|
|
13206
|
+
mocking the SQL layer. */
|
|
13207
|
+
function (tx, err) {
|
|
12936
13208
|
if (CFG.DEBUG) {
|
|
12937
13209
|
console.log('[multiEntry] Could not execute Cursor.continue', sqlStr, sqlValues);
|
|
12938
13210
|
}
|
|
12939
13211
|
error(err);
|
|
12940
13212
|
return false;
|
|
12941
13213
|
});
|
|
13214
|
+
/* c8 ignore stop -- see comment above */
|
|
12942
13215
|
}
|
|
12943
13216
|
runQuery();
|
|
12944
13217
|
};
|
|
@@ -13047,6 +13320,7 @@
|
|
|
13047
13320
|
* @returns {void}
|
|
13048
13321
|
*/
|
|
13049
13322
|
IDBCursor.prototype.__invalidateCache = function () {
|
|
13323
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
13050
13324
|
// @ts-ignore Why is this not being found?; needed under some TS versions
|
|
13051
13325
|
this.__prefetchedData = null;
|
|
13052
13326
|
this.__multiEntryExhausted = false;
|
|
@@ -13071,7 +13345,7 @@
|
|
|
13071
13345
|
convertValueToKeyRethrowingAndIfInvalid(key);
|
|
13072
13346
|
var cmpResult = cmp(key, me.key);
|
|
13073
13347
|
if (cmpResult === 0 || me.direction.includes('next') && cmpResult === -1 || me.direction.includes('prev') && cmpResult === 1) {
|
|
13074
|
-
throw createDOMException('DataError', 'Cannot
|
|
13348
|
+
throw createDOMException('DataError', 'Cannot continue the cursor in an unexpected direction');
|
|
13075
13349
|
}
|
|
13076
13350
|
}
|
|
13077
13351
|
this.__continueFinish(key, undefined, advanceState);
|
|
@@ -13328,6 +13602,7 @@
|
|
|
13328
13602
|
// continuation logic in `__findBasic` to see this update's
|
|
13329
13603
|
// effect on ordering (see "Modify records during cursor
|
|
13330
13604
|
// iteration" in idbcursor_update_index.any.js).
|
|
13605
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
13331
13606
|
// @ts-ignore -- API (not erring in TS 6)
|
|
13332
13607
|
IDBObjectStore.__storingRecordObjectStore(request, me.__store, true, clonedValue, false, key);
|
|
13333
13608
|
}
|
|
@@ -13377,14 +13652,33 @@
|
|
|
13377
13652
|
// We don't invalidate the cache (as we don't access it anymore
|
|
13378
13653
|
// and it will set the index off)
|
|
13379
13654
|
success(undefined);
|
|
13655
|
+
/* c8 ignore start -- Defensive: `__find` (invoked just above) has
|
|
13656
|
+
already confirmed a row exists for this primary key within the
|
|
13657
|
+
same transaction queue, so `rowsAffected` should always be 1 in
|
|
13658
|
+
normal usage. This branch would only be reached if the underlying
|
|
13659
|
+
row were removed by another request queued in the same
|
|
13660
|
+
transaction between `__find`'s check and this DELETE actually
|
|
13661
|
+
running (e.g. deleting the same record directly via the object
|
|
13662
|
+
store while a cursor over it is mid-iteration); attempts to
|
|
13663
|
+
construct such a scenario instead trigger a transaction abort
|
|
13664
|
+
(`AbortError`) before this callback ever runs, since the default
|
|
13665
|
+
action of an unhandled request error is to abort the
|
|
13666
|
+
transaction. */
|
|
13380
13667
|
} else {
|
|
13381
13668
|
// @ts-expect-error Apparently ok
|
|
13382
13669
|
error('No rows with key found' + key);
|
|
13383
13670
|
}
|
|
13384
|
-
|
|
13671
|
+
/* c8 ignore stop -- see comment above */
|
|
13672
|
+
},
|
|
13673
|
+
/* c8 ignore start -- Defensive: guards against an unexpected SQLite
|
|
13674
|
+
execution error (e.g. I/O error, corruption) while deleting the
|
|
13675
|
+
current row; not reliably reproducible without mocking the SQL
|
|
13676
|
+
layer. */
|
|
13677
|
+
function (tx, data) {
|
|
13385
13678
|
error(data);
|
|
13386
13679
|
return false;
|
|
13387
13680
|
});
|
|
13681
|
+
/* c8 ignore stop -- see comment above */
|
|
13388
13682
|
}, error);
|
|
13389
13683
|
}, undefined, me);
|
|
13390
13684
|
};
|
|
@@ -13792,7 +14086,7 @@
|
|
|
13792
14086
|
*/
|
|
13793
14087
|
function setGlobalVars(idb, initialConfig) {
|
|
13794
14088
|
var IDB = /** @type {ShimmedObject & {[key: string]: unknown}} */
|
|
13795
|
-
/** @type {unknown} */globalThis
|
|
14089
|
+
/** @type {unknown} */globalThis;
|
|
13796
14090
|
/**
|
|
13797
14091
|
* @param {string} name
|
|
13798
14092
|
* @param {unknown} value
|
|
@@ -13883,80 +14177,87 @@
|
|
|
13883
14177
|
});
|
|
13884
14178
|
}
|
|
13885
14179
|
var shimIDBFactory = IDBFactory;
|
|
13886
|
-
if (CFG.win.openDatabase
|
|
13887
|
-
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
14180
|
+
if (CFG.win.openDatabase === undefined) {
|
|
14181
|
+
return;
|
|
14182
|
+
}
|
|
14183
|
+
shimIndexedDB$1.__openDatabase = CFG.win.openDatabase.bind(CFG.win); // We cache here in case the function is overwritten later as by the IndexedDB support promises tests
|
|
14184
|
+
// Polyfill ALL of IndexedDB, using WebSQL
|
|
14185
|
+
shim('indexedDB', shimIndexedDB$1, {
|
|
14186
|
+
enumerable: true,
|
|
14187
|
+
configurable: true,
|
|
14188
|
+
get: function get() {
|
|
14189
|
+
if (this !== IDB && !isNullish(this) && !this.shimNS) {
|
|
14190
|
+
// Latter is hack for test environment
|
|
14191
|
+
throw new TypeError('Illegal invocation');
|
|
13898
14192
|
}
|
|
13899
|
-
|
|
13900
|
-
/** @type {[string, unknown][]} */
|
|
13901
|
-
[['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) {
|
|
13902
|
-
var _ref4 = _slicedToArray(_ref3, 2),
|
|
13903
|
-
prop = _ref4[0],
|
|
13904
|
-
obj = _ref4[1];
|
|
13905
|
-
shim(prop, obj, {
|
|
13906
|
-
enumerable: false,
|
|
13907
|
-
configurable: true
|
|
13908
|
-
});
|
|
13909
|
-
});
|
|
13910
|
-
// For Node environments
|
|
13911
|
-
if (CFG.fs) {
|
|
13912
|
-
setFS(CFG.fs);
|
|
14193
|
+
return shimIndexedDB$1;
|
|
13913
14194
|
}
|
|
13914
|
-
|
|
13915
|
-
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
|
|
14195
|
+
});
|
|
14196
|
+
/** @type {[string, unknown][]} */
|
|
14197
|
+
[['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) {
|
|
14198
|
+
var _ref4 = _slicedToArray(_ref3, 2),
|
|
14199
|
+
prop = _ref4[0],
|
|
14200
|
+
obj = _ref4[1];
|
|
14201
|
+
shim(prop, obj, {
|
|
14202
|
+
enumerable: false,
|
|
14203
|
+
configurable: true
|
|
14204
|
+
});
|
|
14205
|
+
});
|
|
14206
|
+
// For Node environments
|
|
14207
|
+
if (CFG.fs) {
|
|
14208
|
+
setFS(CFG.fs);
|
|
14209
|
+
}
|
|
14210
|
+
if (CFG.fullIDLSupport) {
|
|
14211
|
+
// Slow per MDN so off by default! Though apparently needed for WebIDL: https://stackoverflow.com/questions/41927589/rationales-consequences-of-webidl-class-inheritance-requirements
|
|
14212
|
+
|
|
14213
|
+
Object.setPrototypeOf(IDB.IDBOpenDBRequest, IDB.IDBRequest);
|
|
14214
|
+
Object.setPrototypeOf(IDB.IDBCursorWithValue, IDB.IDBCursor);
|
|
14215
|
+
Object.setPrototypeOf(IDBDatabase, EventTarget);
|
|
14216
|
+
Object.setPrototypeOf(IDBRequest, EventTarget);
|
|
14217
|
+
Object.setPrototypeOf(IDBTransaction, EventTarget);
|
|
14218
|
+
Object.setPrototypeOf(IDBVersionChangeEvent, ShimEvent);
|
|
14219
|
+
// `ShimDOMException` is the real native `DOMException` when one
|
|
14220
|
+
// is available (see `DOMException.js`'s `useNativeDOMException`)
|
|
14221
|
+
// -- which, unlike the shim classes above, is a single,
|
|
14222
|
+
// process-wide singleton shared by reference across every
|
|
14223
|
+
// sandbox this library gets installed into (see
|
|
14224
|
+
// `node-idb-test.js`'s `sandboxObj`). A native `DOMException`
|
|
14225
|
+
// already has the correct prototype chain out of the box
|
|
14226
|
+
// (`Object.getPrototypeOf(DOMException) === Function.prototype`,
|
|
14227
|
+
// not `Error`), so forcing it here isn't just unneeded but
|
|
14228
|
+
// actively wrong -- and, because it's shared, permanently
|
|
14229
|
+
// wrong for every later use of `DOMException` in the same
|
|
14230
|
+
// process (e.g. a later WPT test file's own idlharness-style
|
|
14231
|
+
// check that `DOMException` does *not* inherit from `Error`
|
|
14232
|
+
// on the class side), not just this one shim install.
|
|
14233
|
+
if (typeof DOMException === 'undefined' || ShimDOMException !== DOMException) {
|
|
14234
|
+
Object.setPrototypeOf(ShimDOMException, Error);
|
|
14235
|
+
Object.setPrototypeOf(ShimDOMException.prototype, Error.prototype);
|
|
13941
14236
|
}
|
|
13942
|
-
|
|
13943
|
-
|
|
13944
|
-
|
|
13945
|
-
|
|
13946
|
-
|
|
13947
|
-
|
|
13948
|
-
|
|
13949
|
-
if (CFG.replaceNonIDBGlobals) {
|
|
13950
|
-
setNonIDBGlobals();
|
|
13951
|
-
}
|
|
14237
|
+
}
|
|
14238
|
+
if (IDB.indexedDB && !IDB.indexedDB.toString().includes('[native code]')) {
|
|
14239
|
+
if (CFG.addNonIDBGlobals) {
|
|
14240
|
+
// As `DOMStringList` exists per IDL (and Chrome) in the global
|
|
14241
|
+
// thread (but not in workers), we prefix the name to avoid
|
|
14242
|
+
// shadowing or conflicts
|
|
14243
|
+
setNonIDBGlobals('Shim');
|
|
13952
14244
|
}
|
|
13953
|
-
|
|
13954
|
-
|
|
13955
|
-
return;
|
|
14245
|
+
if (CFG.replaceNonIDBGlobals) {
|
|
14246
|
+
setNonIDBGlobals();
|
|
13956
14247
|
}
|
|
13957
|
-
/* c8 ignore stop -- TS guard */
|
|
13958
|
-
IDB.shimIndexedDB.__setConnectionQueueOrigin();
|
|
13959
14248
|
}
|
|
14249
|
+
/* c8 ignore start -- Defensive: `IDB.shimIndexedDB` was already
|
|
14250
|
+
confirmed truthy just before this function (`__useShim`) was
|
|
14251
|
+
defined and immediately invoked (see the `if ('shimIndexedDB'
|
|
14252
|
+
in IDB && IDB.shimIndexedDB)` guard above), and nothing in
|
|
14253
|
+
this function's body reassigns or deletes it. Only reachable
|
|
14254
|
+
if `IDB` is some unusual object (e.g. a Proxy) whose
|
|
14255
|
+
`shimIndexedDB` property value changes between reads. */
|
|
14256
|
+
if (!IDB.shimIndexedDB) {
|
|
14257
|
+
return;
|
|
14258
|
+
}
|
|
14259
|
+
/* c8 ignore stop -- see comment above */
|
|
14260
|
+
IDB.shimIndexedDB.__setConnectionQueueOrigin();
|
|
13960
14261
|
};
|
|
13961
14262
|
IDB.shimIndexedDB.__debug = /** @type {(val: boolean) => void} */function (val) {
|
|
13962
14263
|
CFG.DEBUG = val;
|