indexeddbshim 19.0.5 → 19.0.7
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/README.md +2 -0
- 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 +73 -33
- 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 +543 -221
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.js +572 -249
- 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 +543 -221
- package/dist/indexeddbshim-node.cjs.map +1 -1
- package/dist/indexeddbshim-noninvasive.js +572 -249
- 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 +572 -249
- 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/licenseInfo.json +8 -0
- package/package.json +106 -102
- package/src/CFG.js +18 -4
- package/src/DOMException.js +6 -0
- package/src/DOMStringList.js +3 -0
- package/src/IDBCursor.js +36 -3
- package/src/IDBDatabase.js +26 -10
- package/src/IDBFactory.js +105 -5
- package/src/IDBIndex.js +49 -32
- package/src/IDBKeyRange.js +8 -7
- package/src/IDBObjectStore.js +25 -2
- package/src/IDBRecord.js +2 -0
- package/src/IDBRequest.js +7 -4
- package/src/IDBTransaction.js +97 -26
- package/src/Key.js +53 -22
- 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.7 - 9/23/2026 */
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
@@ -110,6 +110,7 @@ const phases = {
|
|
|
110
110
|
const ShimDOMException$1 = typeof DOMException === 'undefined'
|
|
111
111
|
// Todo: Better polyfill (if even needed here)
|
|
112
112
|
/* eslint-disable no-shadow -- Polyfill */
|
|
113
|
+
/* 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) */
|
|
113
114
|
// eslint-disable-next-line @stylistic/operator-linebreak -- TS/JSDoc needs
|
|
114
115
|
?
|
|
115
116
|
/**
|
|
@@ -127,9 +128,10 @@ function DOMException(msg, name) {
|
|
|
127
128
|
configurable: true
|
|
128
129
|
});
|
|
129
130
|
return err;
|
|
130
|
-
}
|
|
131
|
+
}
|
|
132
|
+
/* c8 ignore stop */ : DOMException;
|
|
131
133
|
|
|
132
|
-
/** @type {WeakMap<object,
|
|
134
|
+
/** @type {WeakMap<object, EventWithProps>} */
|
|
133
135
|
const ev = new WeakMap();
|
|
134
136
|
/** @type {WeakMap<object, EventWithProps>} */
|
|
135
137
|
const evCfg = new WeakMap();
|
|
@@ -175,11 +177,12 @@ function definePassthroughProps(instance, props, _evCfg, _ev) {
|
|
|
175
177
|
obj[prop] = {
|
|
176
178
|
configurable: true,
|
|
177
179
|
get() {
|
|
178
|
-
return Object.hasOwn(_evCfg, prop) ? _evCfg[prop] : Reflect.has(_ev, prop) ? _ev[prop] : ['bubbles', 'cancelable', 'composed'].includes(prop) ? false
|
|
180
|
+
return Object.hasOwn(_evCfg, prop) ? _evCfg[prop] : Reflect.has(_ev, prop) ? _ev[prop] : ['bubbles', 'cancelable', 'composed'].includes(prop) ? false
|
|
181
|
+
/* 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;
|
|
179
182
|
}
|
|
180
183
|
};
|
|
181
184
|
return obj;
|
|
182
|
-
}, /** @type {
|
|
185
|
+
}, /** @type {PropertyDescriptorMap} */{}));
|
|
183
186
|
}
|
|
184
187
|
|
|
185
188
|
/**
|
|
@@ -202,8 +205,9 @@ function getIsTrusted() {
|
|
|
202
205
|
throw new TypeError('Illegal invocation');
|
|
203
206
|
}
|
|
204
207
|
const _evCfg = getEvCfg(this);
|
|
205
|
-
const _ev = ev.get(this);
|
|
206
|
-
return Boolean(Object.hasOwn(_evCfg, 'isTrusted')
|
|
208
|
+
const _ev = /** @type {EventWithProps} */ /** @type {EventWithProps} */ev.get(this);
|
|
209
|
+
return Boolean(Object.hasOwn(_evCfg, 'isTrusted')
|
|
210
|
+
/* 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);
|
|
207
211
|
}
|
|
208
212
|
|
|
209
213
|
/**
|
|
@@ -353,15 +357,15 @@ const ShimEvent = Event;
|
|
|
353
357
|
// this untyped alias, rather than `ShimEvent.prototype` directly, keeps
|
|
354
358
|
// that dynamic-augmentation pattern working without a `@ts-expect-error`
|
|
355
359
|
// on every single line below.
|
|
356
|
-
|
|
357
|
-
const ShimEventProto = ShimEvent.prototype;
|
|
360
|
+
|
|
361
|
+
const ShimEventProto = /** @type {Record<PropertyKey, unknown>} */ /** @type {unknown} */ShimEvent.prototype;
|
|
358
362
|
|
|
359
363
|
/** @this {EventWithProps} */
|
|
360
364
|
ShimEventProto.preventDefault = function preventDefault() {
|
|
361
365
|
if (!(this instanceof ShimEvent)) {
|
|
362
366
|
throw new TypeError('Illegal invocation');
|
|
363
367
|
}
|
|
364
|
-
const _ev = ev.get(this);
|
|
368
|
+
const _ev = /** @type {EventWithProps} */ /** @type {EventWithProps} */ev.get(this);
|
|
365
369
|
const _evCfg = getEvCfg(this);
|
|
366
370
|
if (this.cancelable && !_evCfg._passive) {
|
|
367
371
|
_evCfg.defaultPrevented = true;
|
|
@@ -547,13 +551,12 @@ class CustomEvent extends Event {
|
|
|
547
551
|
}
|
|
548
552
|
}
|
|
549
553
|
const ShimCustomEvent = CustomEvent;
|
|
550
|
-
/** @type {
|
|
551
|
-
const ShimCustomEventProto = ShimCustomEvent.prototype;
|
|
554
|
+
const ShimCustomEventProto = /** @type {Record<PropertyKey, unknown>} */ /** @type {unknown} */ShimCustomEvent.prototype;
|
|
552
555
|
/**
|
|
553
556
|
* @param {string} type
|
|
554
557
|
* @param {boolean} [bubbles]
|
|
555
558
|
* @param {boolean} [cancelable]
|
|
556
|
-
* @param {
|
|
559
|
+
* @param {unknown} [detail]
|
|
557
560
|
* @this {EventWithProps}
|
|
558
561
|
*/
|
|
559
562
|
ShimCustomEventProto.initCustomEvent = function initCustomEvent(type, bubbles = false, cancelable = false, detail = null) {
|
|
@@ -562,6 +565,10 @@ ShimCustomEventProto.initCustomEvent = function initCustomEvent(type, bubbles =
|
|
|
562
565
|
throw new TypeError('Illegal invocation');
|
|
563
566
|
}
|
|
564
567
|
const _evCfg = getEvCfg(this);
|
|
568
|
+
if (_evCfg._dispatched) {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
|
|
565
572
|
// @ts-expect-error `detail` isn't part of `EventInit`, only used internally here
|
|
566
573
|
// eslint-disable-next-line prefer-rest-params -- Keep signature
|
|
567
574
|
initEventInternal(this, type, {
|
|
@@ -569,16 +576,13 @@ ShimCustomEventProto.initCustomEvent = function initCustomEvent(type, bubbles =
|
|
|
569
576
|
cancelable,
|
|
570
577
|
detail
|
|
571
578
|
}, arguments[4]);
|
|
572
|
-
if (_evCfg._dispatched) {
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
579
|
if (detail !== undefined) {
|
|
576
580
|
_evCfg.detail = detail;
|
|
577
581
|
}
|
|
578
582
|
// `initCustomEvent` deliberately excluded -- see the matching comment
|
|
579
583
|
// in `initEventInternal` for `initEvent`, above; the same reasoning
|
|
580
584
|
// applies here.
|
|
581
|
-
definePassthroughProps(this, ['detail'], _evCfg, ev.get(this));
|
|
585
|
+
definePassthroughProps(this, ['detail'], _evCfg, /** @type {EventWithProps} */ev.get(this));
|
|
582
586
|
};
|
|
583
587
|
// @ts-expect-error Not part of the class body itself
|
|
584
588
|
ShimCustomEvent[Symbol.toStringTag] = 'Function';
|
|
@@ -998,7 +1002,7 @@ Object.assign(EventTarget.prototype, {
|
|
|
998
1002
|
/** @type {string[]} */
|
|
999
1003
|
this._extraProperties.forEach(prop => {
|
|
1000
1004
|
if (Reflect.has(e, prop)) {
|
|
1001
|
-
/** @type {
|
|
1005
|
+
/** @type {PropertyDescriptorMap} */eventCopy[prop] = /** @type {PropertyDescriptorMap} */e[prop]; // Todo: Put internal to `ShimEvent`?
|
|
1002
1006
|
}
|
|
1003
1007
|
});
|
|
1004
1008
|
}
|
|
@@ -1078,6 +1082,7 @@ Object.assign(EventTarget.prototype, {
|
|
|
1078
1082
|
if (child) {
|
|
1079
1083
|
child._defaultSync = this._defaultSync;
|
|
1080
1084
|
}
|
|
1085
|
+
/* 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 */
|
|
1081
1086
|
return (child || this)._dispatchEvent(eventCopy, false);
|
|
1082
1087
|
}
|
|
1083
1088
|
case phases.AT_TARGET:
|
|
@@ -1380,7 +1385,7 @@ EventTarget.EventTargetFactory = EventTargetFactory;
|
|
|
1380
1385
|
* databaseNameLengthLimit: number|false,
|
|
1381
1386
|
* escapeNFDForDatabaseNames: boolean,
|
|
1382
1387
|
* addSQLiteExtension: boolean,
|
|
1383
|
-
* memoryDatabase: string,
|
|
1388
|
+
* memoryDatabase: string|null|undefined,
|
|
1384
1389
|
* deleteDatabaseFiles: boolean,
|
|
1385
1390
|
* databaseBasePath: string,
|
|
1386
1391
|
* sysDatabaseBasePath: string,
|
|
@@ -1523,13 +1528,27 @@ const CFG = /** @type {ConfigValues} */{};
|
|
|
1523
1528
|
// Various types of in-memory databases that can auto-delete
|
|
1524
1529
|
['memoryDatabase',
|
|
1525
1530
|
/**
|
|
1526
|
-
*
|
|
1531
|
+
* `null`/`undefined` are accepted (and left unvalidated against the
|
|
1532
|
+
* regex below) specifically so this can be reset back to its
|
|
1533
|
+
* unset/disabled state after being set: unlike other `CFG`
|
|
1534
|
+
* boolean-ish switches (e.g. `sqlMemoryQuota`, which is checked
|
|
1535
|
+
* with a falsy `if (CFG.sqlMemoryQuota)`), `memoryDatabase`'s own
|
|
1536
|
+
* usage sites check `typeof CFG.memoryDatabase === 'string'`, so
|
|
1537
|
+
* even the empty string counts as "on" (it's a distinct, valid
|
|
1538
|
+
* in-memory mode of its own -- an unnamed private temporary
|
|
1539
|
+
* database -- not an "off" state). Without this, once set to any
|
|
1540
|
+
* string there would be no value passable back through this same
|
|
1541
|
+
* validator that turns `useMemoryDatabase` false again.
|
|
1542
|
+
* @param {string|null|undefined} val
|
|
1527
1543
|
* @throws {TypeError}
|
|
1528
1544
|
* @returns {void}
|
|
1529
1545
|
*/
|
|
1530
1546
|
val => {
|
|
1547
|
+
if (val === null || val === undefined) {
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1531
1550
|
if (!/^(?::memory:|file::memory:(\?[^#]*)?(#.*)?)?$/u.test(/** @type {string} */val)) {
|
|
1532
|
-
throw new TypeError('`memoryDatabase` must be the empty string, ":memory:", or a
|
|
1551
|
+
throw new TypeError('`memoryDatabase` must be `null`/`undefined` (to reset it to disabled), the empty string, ' + '":memory:", or a "file::memory:[?queryString][#hash] URL".');
|
|
1533
1552
|
}
|
|
1534
1553
|
}],
|
|
1535
1554
|
// NODE-SPECIFIC CONFIG
|
|
@@ -1582,10 +1601,7 @@ function escapeUnmatchedSurrogates(arg) {
|
|
|
1582
1601
|
return arg.replaceAll(/([\uD800-\uDBFF])(?![\uDC00-\uDFFF])|(^|[^\uD800-\uDBFF])([\uDC00-\uDFFF])/gu, function (_, unmatchedHighSurrogate, precedingLow, unmatchedLowSurrogate) {
|
|
1583
1602
|
// Could add a corresponding surrogate for compatibility with `node-sqlite3`: https://bugs.python.org/issue12569 and https://stackoverflow.com/a/6701665/271577
|
|
1584
1603
|
// but Chrome having problems
|
|
1585
|
-
|
|
1586
|
-
return '^2' + unmatchedHighSurrogate.codePointAt().toString(16).padStart(4, '0');
|
|
1587
|
-
}
|
|
1588
|
-
return (precedingLow || '') + '^3' + unmatchedLowSurrogate.codePointAt().toString(16).padStart(4, '0');
|
|
1604
|
+
return unmatchedHighSurrogate ? '^2' + unmatchedHighSurrogate.codePointAt().toString(16).padStart(4, '0') : (precedingLow || '') + '^3' + unmatchedLowSurrogate.codePointAt().toString(16).padStart(4, '0');
|
|
1589
1605
|
});
|
|
1590
1606
|
}
|
|
1591
1607
|
|
|
@@ -2260,7 +2276,8 @@ Object.defineProperty(IDBVersionChangeEvent, Symbol.hasInstance, {
|
|
|
2260
2276
|
function createNativeDOMException(name, message) {
|
|
2261
2277
|
// @ts-expect-error It's ok
|
|
2262
2278
|
// eslint-disable-next-line new-cap -- Ok
|
|
2263
|
-
return new DOMException.prototype.constructor(message,
|
|
2279
|
+
return new DOMException.prototype.constructor(message, /* c8 ignore next -- Defensive fallback; every call site in this codebase always supplies a `name` */
|
|
2280
|
+
name || 'DOMException');
|
|
2264
2281
|
}
|
|
2265
2282
|
|
|
2266
2283
|
// From web-platform-tests testharness.js name_code_map (though not in new spec)
|
|
@@ -2424,8 +2441,10 @@ function createNonNativeDOMExceptionClass() {
|
|
|
2424
2441
|
*/
|
|
2425
2442
|
get() {
|
|
2426
2443
|
if (!(this instanceof DOMException ||
|
|
2444
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2427
2445
|
// @ts-ignore Just checking; needed under some TS versions
|
|
2428
2446
|
this instanceof DummyDOMException ||
|
|
2447
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2429
2448
|
// @ts-ignore Just checking; needed under some TS versions
|
|
2430
2449
|
this instanceof Error)) {
|
|
2431
2450
|
throw new TypeError('Illegal invocation');
|
|
@@ -2484,6 +2503,7 @@ function createNonNativeDOMExceptionClass() {
|
|
|
2484
2503
|
value: DOMException
|
|
2485
2504
|
});
|
|
2486
2505
|
|
|
2506
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2487
2507
|
// @ts-ignore We don't need all its properties; needed under some TS versions
|
|
2488
2508
|
return DOMException;
|
|
2489
2509
|
}
|
|
@@ -2496,6 +2516,7 @@ const ShimNonNativeDOMException = createNonNativeDOMExceptionClass();
|
|
|
2496
2516
|
* @returns {Error}
|
|
2497
2517
|
*/
|
|
2498
2518
|
function createNonNativeDOMException(name, message) {
|
|
2519
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2499
2520
|
// @ts-ignore It's ok; needed under some TS versions
|
|
2500
2521
|
return new ShimNonNativeDOMException(message, name);
|
|
2501
2522
|
}
|
|
@@ -2518,6 +2539,8 @@ function logError(name, message, error) {
|
|
|
2518
2539
|
return;
|
|
2519
2540
|
}
|
|
2520
2541
|
const msg = error && typeof error === 'object' && error.message ? error.message : (/** @type {string} */error);
|
|
2542
|
+
|
|
2543
|
+
/* c8 ignore next -- Defensive fallback for an environment lacking `console.error` */
|
|
2521
2544
|
const method = typeof console.error === 'function' ? 'error' : 'log';
|
|
2522
2545
|
console[method](name + ': ' + message + '. ' + (msg || ''));
|
|
2523
2546
|
if (console.trace) {
|
|
@@ -2693,8 +2716,10 @@ function IDBRequest() {
|
|
|
2693
2716
|
* @this {IDBRequestFull}
|
|
2694
2717
|
*/
|
|
2695
2718
|
IDBRequest.__super = function IDBRequest() {
|
|
2719
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2696
2720
|
// @ts-ignore It's ok
|
|
2697
2721
|
this[Symbol.toStringTag] = 'IDBRequest';
|
|
2722
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2698
2723
|
// @ts-ignore Part of `ShimEventTarget`
|
|
2699
2724
|
this.__setOptions({
|
|
2700
2725
|
legacyOutputDidListenersThrowFlag: true // Event hook for IndexedB
|
|
@@ -2755,10 +2780,7 @@ IDBRequest.prototype[Symbol.toStringTag] = 'IDBRequestPrototype';
|
|
|
2755
2780
|
* @returns {import('./IDBTransaction.js').IDBTransactionFull|null|undefined}
|
|
2756
2781
|
*/
|
|
2757
2782
|
IDBRequest.prototype.__getParent = function () {
|
|
2758
|
-
|
|
2759
|
-
return null;
|
|
2760
|
-
}
|
|
2761
|
-
return this.__transaction;
|
|
2783
|
+
return this.toString() === '[object IDBOpenDBRequest]' ? null : this.__transaction;
|
|
2762
2784
|
};
|
|
2763
2785
|
|
|
2764
2786
|
/* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
|
|
@@ -2817,8 +2839,10 @@ IDBOpenDBRequest.__createInstance = function () {
|
|
|
2817
2839
|
function IDBOpenDBRequest() {
|
|
2818
2840
|
IDBRequest.__super.call(this);
|
|
2819
2841
|
|
|
2842
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2820
2843
|
// @ts-ignore It's ok
|
|
2821
2844
|
this[Symbol.toStringTag] = 'IDBOpenDBRequest';
|
|
2845
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
2822
2846
|
// @ts-ignore It's ok
|
|
2823
2847
|
this.__setOptions({
|
|
2824
2848
|
legacyOutputDidListenersThrowFlag: true,
|
|
@@ -3646,6 +3670,33 @@ function convertValueToMultiEntryKey(input) {
|
|
|
3646
3670
|
return convertValueToKeyValueDecoded(input, null, true, true);
|
|
3647
3671
|
}
|
|
3648
3672
|
|
|
3673
|
+
/**
|
|
3674
|
+
* @param {BufferSource|ArrayBufferLike} buffer
|
|
3675
|
+
* @returns {boolean}
|
|
3676
|
+
*/
|
|
3677
|
+
function isBufferDetached(buffer) {
|
|
3678
|
+
// Use the standard property if available
|
|
3679
|
+
// @ts-expect-error - More recent API
|
|
3680
|
+
if (typeof buffer.detached === 'boolean') {
|
|
3681
|
+
// @ts-expect-error - More recent API
|
|
3682
|
+
return buffer.detached;
|
|
3683
|
+
}
|
|
3684
|
+
/* c8 ignore next 14 -- Older browsers */
|
|
3685
|
+
|
|
3686
|
+
// Fallback check via byteLength and constructor test
|
|
3687
|
+
if (buffer.byteLength !== 0) {
|
|
3688
|
+
return false;
|
|
3689
|
+
}
|
|
3690
|
+
try {
|
|
3691
|
+
// @ts-expect-error Ok
|
|
3692
|
+
// eslint-disable-next-line no-new -- Throwaway
|
|
3693
|
+
new Uint8Array(buffer);
|
|
3694
|
+
return false;
|
|
3695
|
+
} catch {
|
|
3696
|
+
return true;
|
|
3697
|
+
}
|
|
3698
|
+
}
|
|
3699
|
+
|
|
3649
3700
|
/**
|
|
3650
3701
|
*
|
|
3651
3702
|
* @param {BufferSource} O
|
|
@@ -3658,15 +3709,16 @@ function getCopyBytesHeldByBufferSource(O) {
|
|
|
3658
3709
|
let length;
|
|
3659
3710
|
if (ArrayBuffer.isView(O)) {
|
|
3660
3711
|
// Has [[ViewedArrayBuffer]] internal slot
|
|
3661
|
-
const arrayBuffer = O.buffer;
|
|
3662
|
-
if (arrayBuffer === undefined) {
|
|
3663
|
-
throw new TypeError('Could not copy the bytes held by a buffer source as the buffer was undefined.');
|
|
3664
|
-
}
|
|
3665
3712
|
offset = O.byteOffset; // [[ByteOffset]] (will also throw as desired if detached)
|
|
3666
3713
|
length = O.byteLength; // [[ByteLength]] (will also throw as desired if detached)
|
|
3667
3714
|
} else {
|
|
3668
3715
|
length = O.byteLength; // [[ArrayBufferByteLength]] on ArrayBuffer (will also throw as desired if detached)
|
|
3669
3716
|
}
|
|
3717
|
+
const arrayBuffer = ArrayBuffer.isView(O) ? O.buffer : O;
|
|
3718
|
+
if (isBufferDetached(arrayBuffer)) {
|
|
3719
|
+
throw new TypeError('Could not copy the bytes held by a buffer source as the buffer was detached.');
|
|
3720
|
+
}
|
|
3721
|
+
|
|
3670
3722
|
// const octets = new Uint8Array(input);
|
|
3671
3723
|
// const octets = types.binary.decode(types.binary.encode(input));
|
|
3672
3724
|
return new Uint8Array(
|
|
@@ -3781,7 +3833,13 @@ function convertValueToKeyValueDecoded(input, seen, multiEntry, fullKeys) {
|
|
|
3781
3833
|
message: 'Bad array entry value-to-key conversion'
|
|
3782
3834
|
};
|
|
3783
3835
|
}
|
|
3784
|
-
if (!multiEntry || !fullKeys && keys.every(k => cmp(/** @type {Key} */k, /** @type {Key} */key.value) !== 0) ||
|
|
3836
|
+
if (!multiEntry || !fullKeys && keys.every(k => cmp(/** @type {Key} */k, /** @type {Key} */key.value) !== 0) ||
|
|
3837
|
+
// `keys` holds full `{type, value}` objects here (see
|
|
3838
|
+
// `safePush` below), so -- like the sibling branch
|
|
3839
|
+
// above -- `cmp` (which expects raw `Value`s, not
|
|
3840
|
+
// decoded key objects) must compare their `.value`s,
|
|
3841
|
+
// not the wrapper objects themselves.
|
|
3842
|
+
fullKeys && keys.every(k => cmp(/** @type {Key} */ /** @type {KeyValueObject} */k.value, /** @type {Key} */key.value) !== 0)) {
|
|
3785
3843
|
safePush(keys, fullKeys ? key : key.value);
|
|
3786
3844
|
}
|
|
3787
3845
|
} catch (err) {
|
|
@@ -3799,12 +3857,9 @@ function convertValueToKeyValueDecoded(input, seen, multiEntry, fullKeys) {
|
|
|
3799
3857
|
{
|
|
3800
3858
|
const date = /** @type {Date} */input;
|
|
3801
3859
|
if (!Number.isNaN(date.getTime())) {
|
|
3802
|
-
return
|
|
3803
|
-
type,
|
|
3804
|
-
value: date.getTime()
|
|
3805
|
-
} : {
|
|
3860
|
+
return {
|
|
3806
3861
|
type,
|
|
3807
|
-
value: new Date(date)
|
|
3862
|
+
value: fullKeys ? date.getTime() : new Date(date)
|
|
3808
3863
|
};
|
|
3809
3864
|
}
|
|
3810
3865
|
return {
|
|
@@ -3892,10 +3947,7 @@ function extractKeyValueDecodedFromValueUsingKeyPath(value, keyPath, multiEntry,
|
|
|
3892
3947
|
if (r.failure) {
|
|
3893
3948
|
return r;
|
|
3894
3949
|
}
|
|
3895
|
-
|
|
3896
|
-
return convertValueToKeyValueDecoded(r.value, null, false, fullKeys);
|
|
3897
|
-
}
|
|
3898
|
-
return convertValueToMultiEntryKeyDecoded(r.value, fullKeys);
|
|
3950
|
+
return !multiEntry ? convertValueToKeyValueDecoded(r.value, null, false, fullKeys) : convertValueToMultiEntryKeyDecoded(r.value, fullKeys);
|
|
3899
3951
|
}
|
|
3900
3952
|
|
|
3901
3953
|
/**
|
|
@@ -4067,10 +4119,7 @@ function isKeyInRange(key, range, checkCached) {
|
|
|
4067
4119
|
*/
|
|
4068
4120
|
function isMultiEntryMatch(encodedEntry, encodedKey) {
|
|
4069
4121
|
const keyType = encodedCharToKeyType[encodedKey.slice(0, 1)];
|
|
4070
|
-
|
|
4071
|
-
return encodedKey.indexOf(encodedEntry) > 1;
|
|
4072
|
-
}
|
|
4073
|
-
return encodedKey === encodedEntry;
|
|
4122
|
+
return keyType === 'array' ? encodedKey.indexOf(encodedEntry) > 1 : encodedKey === encodedEntry;
|
|
4074
4123
|
}
|
|
4075
4124
|
|
|
4076
4125
|
/**
|
|
@@ -4181,10 +4230,7 @@ function encode$1(key, inArray) {
|
|
|
4181
4230
|
* @returns {undefined|ValueType}
|
|
4182
4231
|
*/
|
|
4183
4232
|
function decode$1(key, inArray) {
|
|
4184
|
-
|
|
4185
|
-
return undefined;
|
|
4186
|
-
}
|
|
4187
|
-
return types[encodedCharToKeyType[key.slice(0, 1)]].decode(key, inArray);
|
|
4233
|
+
return typeof key !== 'string' ? undefined : types[encodedCharToKeyType[key.slice(0, 1)]].decode(key, inArray);
|
|
4188
4234
|
}
|
|
4189
4235
|
|
|
4190
4236
|
/**
|
|
@@ -4596,10 +4642,11 @@ function setSQLForKeyRange(range, quotedKeyColumnName, sql, sqlValues, addAnd, c
|
|
|
4596
4642
|
if (hasLower && hasUpper) {
|
|
4597
4643
|
sql.push('AND');
|
|
4598
4644
|
}
|
|
4599
|
-
if (hasUpper) {
|
|
4600
|
-
|
|
4601
|
-
sqlValues.push(escapeSQLiteStatement(/** @type {string} */encodedUpperKey));
|
|
4645
|
+
if (!hasUpper) {
|
|
4646
|
+
return;
|
|
4602
4647
|
}
|
|
4648
|
+
sql.push(quotedKeyColumnName, range.upperOpen ? '<' : '<=', '?');
|
|
4649
|
+
sqlValues.push(escapeSQLiteStatement(/** @type {string} */encodedUpperKey));
|
|
4603
4650
|
}
|
|
4604
4651
|
|
|
4605
4652
|
/**
|
|
@@ -4612,10 +4659,7 @@ function convertValueToKeyRange(value, nullDisallowed) {
|
|
|
4612
4659
|
if (instanceOf(value, IDBKeyRange)) {
|
|
4613
4660
|
// We still need to validate IDBKeyRange-like objects (the above check is based on loose duck-typing)
|
|
4614
4661
|
const range = /** @type {IDBKeyRangeFull} */value;
|
|
4615
|
-
|
|
4616
|
-
return IDBKeyRange.__createInstance(range.lower, range.upper, range.lowerOpen, range.upperOpen);
|
|
4617
|
-
}
|
|
4618
|
-
return range;
|
|
4662
|
+
return range.toString() !== '[object IDBKeyRange]' ? IDBKeyRange.__createInstance(range.lower, range.upper, range.lowerOpen, range.upperOpen) : range;
|
|
4619
4663
|
}
|
|
4620
4664
|
if (isNullish(value)) {
|
|
4621
4665
|
if (nullDisallowed) {
|
|
@@ -4660,9 +4704,11 @@ if (Object.defineProperty) {
|
|
|
4660
4704
|
if (testObject.test) {
|
|
4661
4705
|
cleanInterface = true;
|
|
4662
4706
|
}
|
|
4707
|
+
/* c8 ignore start -- Defensive fallback for an engine with a broken `Object.defineProperty` */
|
|
4663
4708
|
} catch (err) {
|
|
4664
4709
|
// Object.defineProperty does not work as intended.
|
|
4665
4710
|
}
|
|
4711
|
+
/* c8 ignore stop -- Defensive fallback for an engine with a broken `Object.defineProperty` */
|
|
4666
4712
|
}
|
|
4667
4713
|
|
|
4668
4714
|
/**
|
|
@@ -4860,6 +4906,7 @@ Object.defineProperty(DOMStringList, '__createInstance', {
|
|
|
4860
4906
|
this._length = 0;
|
|
4861
4907
|
};
|
|
4862
4908
|
DOMStringList.prototype = DOMStringListAlias.prototype;
|
|
4909
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
4863
4910
|
// @ts-ignore It's ok; needed under some TS versions
|
|
4864
4911
|
return /** @type {DOMStringListFull} */new DOMStringList();
|
|
4865
4912
|
}
|
|
@@ -5157,12 +5204,14 @@ IDBTransaction.prototype.__callTransFinishedCb = function (err, cb) {
|
|
|
5157
5204
|
*/
|
|
5158
5205
|
IDBTransaction.prototype.__executeRequests = function () {
|
|
5159
5206
|
const me = this;
|
|
5207
|
+
/* 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. */
|
|
5160
5208
|
if (me.__running) {
|
|
5161
5209
|
if (CFG.DEBUG) {
|
|
5162
5210
|
console.log('Looks like the request set is already running', me.mode);
|
|
5163
5211
|
}
|
|
5164
5212
|
return;
|
|
5165
5213
|
}
|
|
5214
|
+
/* c8 ignore stop -- see comment above */
|
|
5166
5215
|
|
|
5167
5216
|
// The synchronous script that created this transaction (and
|
|
5168
5217
|
// synchronously queued whatever requests it wanted to) has now
|
|
@@ -5212,6 +5261,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5212
5261
|
queueMicrotask(cb);
|
|
5213
5262
|
return;
|
|
5214
5263
|
}
|
|
5264
|
+
/* 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. */
|
|
5215
5265
|
try {
|
|
5216
5266
|
tx.executeSql('SELECT 1', [], function () {
|
|
5217
5267
|
cb();
|
|
@@ -5225,6 +5275,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5225
5275
|
// abort the transaction here.
|
|
5226
5276
|
me.__abortTransaction(/** @type {Error|DOMException} */err);
|
|
5227
5277
|
}
|
|
5278
|
+
/* c8 ignore stop -- see comment above */
|
|
5228
5279
|
}
|
|
5229
5280
|
|
|
5230
5281
|
/**
|
|
@@ -5237,21 +5288,26 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5237
5288
|
* @returns {void}
|
|
5238
5289
|
*/
|
|
5239
5290
|
function success(result, req) {
|
|
5291
|
+
/* 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. */
|
|
5240
5292
|
if (me.__errored || me.__requestsFinished) {
|
|
5241
5293
|
// We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
|
|
5242
5294
|
return;
|
|
5243
5295
|
}
|
|
5296
|
+
/* c8 ignore stop -- see comment above */
|
|
5244
5297
|
if (req) {
|
|
5245
5298
|
q.req = req; // Need to do this in case of cursors
|
|
5246
5299
|
}
|
|
5300
|
+
/* 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. */
|
|
5247
5301
|
if (!q.req) {
|
|
5248
|
-
// TS guard
|
|
5249
5302
|
return;
|
|
5250
5303
|
}
|
|
5304
|
+
/* c8 ignore stop -- see comment above */
|
|
5305
|
+
/* 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. */
|
|
5251
5306
|
if (q.req.__done) {
|
|
5252
5307
|
// Avoid continuing with aborted requests
|
|
5253
5308
|
return;
|
|
5254
5309
|
}
|
|
5310
|
+
/* c8 ignore stop -- see comment above */
|
|
5255
5311
|
q.req.__done = true;
|
|
5256
5312
|
q.req.__result = result;
|
|
5257
5313
|
q.req.__error = null;
|
|
@@ -5268,6 +5324,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5268
5324
|
// is what actually resets `__handlerActive`, once it's
|
|
5269
5325
|
// confirmed (across its own bounded microtask wait) that no
|
|
5270
5326
|
// such continuation queued anything.
|
|
5327
|
+
/* 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. */
|
|
5271
5328
|
if (e.__legacyOutputDidListenersThrowError) {
|
|
5272
5329
|
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
|
|
5273
5330
|
if (!me.__committed) {
|
|
@@ -5277,6 +5334,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5277
5334
|
return;
|
|
5278
5335
|
}
|
|
5279
5336
|
}
|
|
5337
|
+
/* c8 ignore stop -- see comment above */
|
|
5280
5338
|
runContinuationSafely(advanceAfterDispatch);
|
|
5281
5339
|
}
|
|
5282
5340
|
|
|
@@ -5288,15 +5346,19 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5288
5346
|
* @returns {void}
|
|
5289
5347
|
*/
|
|
5290
5348
|
function error(...args /* tx, err */) {
|
|
5349
|
+
/* 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. */
|
|
5291
5350
|
if (me.__errored || me.__requestsFinished) {
|
|
5292
5351
|
// We've already called "onerror", "onabort", or thrown within
|
|
5293
5352
|
// the transaction, so don't do it again.
|
|
5294
5353
|
return;
|
|
5295
5354
|
}
|
|
5355
|
+
/* c8 ignore stop -- see comment above */
|
|
5356
|
+
/* 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. */
|
|
5296
5357
|
if (q.req && q.req.__done) {
|
|
5297
5358
|
// Avoid continuing with aborted requests
|
|
5298
5359
|
return;
|
|
5299
5360
|
}
|
|
5361
|
+
/* c8 ignore stop -- see comment above */
|
|
5300
5362
|
const err = /** @type {Error|DOMException} */findError(args);
|
|
5301
5363
|
if (!q.req) {
|
|
5302
5364
|
me.__abortTransaction(err);
|
|
@@ -5318,10 +5380,11 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5318
5380
|
}
|
|
5319
5381
|
});
|
|
5320
5382
|
q.req.addDefaultEventListener('error', function () {
|
|
5383
|
+
/* 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. */
|
|
5321
5384
|
if (!q.req) {
|
|
5322
|
-
// TS guard
|
|
5323
5385
|
return;
|
|
5324
5386
|
}
|
|
5387
|
+
/* c8 ignore stop -- see comment above */
|
|
5325
5388
|
me.__abortTransaction(q.req.__error);
|
|
5326
5389
|
});
|
|
5327
5390
|
me.__active = true;
|
|
@@ -5333,16 +5396,19 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5333
5396
|
q.req.dispatchEvent(e);
|
|
5334
5397
|
// Do not set __active or __handlerActive flags to false yet --
|
|
5335
5398
|
// see the matching comment in `success`, above.
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
if (me.__committed) {
|
|
5340
|
-
// An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
|
|
5341
|
-
runContinuationSafely(advanceAfterDispatch);
|
|
5342
|
-
return;
|
|
5343
|
-
}
|
|
5344
|
-
me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after error).'));
|
|
5399
|
+
/* 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. */
|
|
5400
|
+
if (!e.__legacyOutputDidListenersThrowError) {
|
|
5401
|
+
return;
|
|
5345
5402
|
}
|
|
5403
|
+
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
|
|
5404
|
+
e.preventDefault(); // Prevent 'error' default as steps indicate we should abort with `AbortError` even without cancellation
|
|
5405
|
+
if (me.__committed) {
|
|
5406
|
+
// An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
|
|
5407
|
+
runContinuationSafely(advanceAfterDispatch);
|
|
5408
|
+
return;
|
|
5409
|
+
}
|
|
5410
|
+
me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after error).'));
|
|
5411
|
+
/* c8 ignore stop -- see comment above */
|
|
5346
5412
|
}
|
|
5347
5413
|
|
|
5348
5414
|
/**
|
|
@@ -5366,10 +5432,12 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5366
5432
|
// (not reset here).
|
|
5367
5433
|
return true;
|
|
5368
5434
|
}
|
|
5435
|
+
/* 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. */
|
|
5369
5436
|
if (q.req.__done) {
|
|
5370
5437
|
// Avoid continuing with aborted requests
|
|
5371
5438
|
return false;
|
|
5372
5439
|
}
|
|
5440
|
+
/* c8 ignore stop -- see comment above */
|
|
5373
5441
|
// We're now handing off to (possibly async) work for
|
|
5374
5442
|
// this request, so the transaction is no longer active
|
|
5375
5443
|
// until its own `success`/`error` dispatch (below)
|
|
@@ -5392,18 +5460,22 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5392
5460
|
return;
|
|
5393
5461
|
}
|
|
5394
5462
|
q.op(tx, q.args, success, error, executeNextRequest);
|
|
5463
|
+
/* 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. */
|
|
5395
5464
|
} catch (e) {
|
|
5396
5465
|
error(/** @type {Error} */e);
|
|
5397
5466
|
}
|
|
5467
|
+
/* c8 ignore stop -- see comment above */
|
|
5398
5468
|
}
|
|
5399
5469
|
|
|
5400
5470
|
/**
|
|
5401
5471
|
* @returns {void}
|
|
5402
5472
|
*/
|
|
5403
5473
|
function runQueuedRequest() {
|
|
5474
|
+
/* c8 ignore start -- Defensive: only reached if `prepareNextRequest` returns `false` (see its own ignore comment above for why that's not reliably reproducible). */
|
|
5404
5475
|
if (!prepareNextRequest()) {
|
|
5405
5476
|
return;
|
|
5406
5477
|
}
|
|
5478
|
+
/* c8 ignore stop -- see comment above */
|
|
5407
5479
|
launchQueuedOp();
|
|
5408
5480
|
}
|
|
5409
5481
|
|
|
@@ -5434,9 +5506,11 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5434
5506
|
* @returns {void}
|
|
5435
5507
|
*/
|
|
5436
5508
|
function checkQueueEntry(attemptsLeft) {
|
|
5509
|
+
/* 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. */
|
|
5437
5510
|
if (me.__errored || me.__requestsFinished) {
|
|
5438
5511
|
return;
|
|
5439
5512
|
}
|
|
5513
|
+
/* c8 ignore stop -- see comment above */
|
|
5440
5514
|
if (i < me.__requests.length) {
|
|
5441
5515
|
runQueuedRequest();
|
|
5442
5516
|
return;
|
|
@@ -5458,10 +5532,12 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5458
5532
|
* @returns {void}
|
|
5459
5533
|
*/
|
|
5460
5534
|
function executeNextRequest() {
|
|
5535
|
+
/* 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. */
|
|
5461
5536
|
if (me.__errored || me.__requestsFinished) {
|
|
5462
5537
|
// We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
|
|
5463
5538
|
return;
|
|
5464
5539
|
}
|
|
5540
|
+
/* c8 ignore stop -- see comment above */
|
|
5465
5541
|
i++;
|
|
5466
5542
|
if (i >= me.__requests.length) {
|
|
5467
5543
|
checkQueueEntry(keepAliveAttempts);
|
|
@@ -5496,31 +5572,34 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5496
5572
|
* @returns {void}
|
|
5497
5573
|
*/
|
|
5498
5574
|
function advanceAfterDispatch() {
|
|
5575
|
+
/* 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. */
|
|
5499
5576
|
if (me.__errored || me.__requestsFinished) {
|
|
5500
5577
|
return;
|
|
5501
5578
|
}
|
|
5579
|
+
/* c8 ignore stop -- see comment above */
|
|
5502
5580
|
i++;
|
|
5503
5581
|
if (i >= me.__requests.length) {
|
|
5504
5582
|
checkQueueEntry(keepAliveAttempts);
|
|
5505
5583
|
return;
|
|
5506
5584
|
}
|
|
5507
5585
|
keepAliveAndWait(() => {
|
|
5508
|
-
if (
|
|
5509
|
-
|
|
5510
|
-
}
|
|
5511
|
-
if (!prepareNextRequest()) {
|
|
5586
|
+
/* 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. */
|
|
5587
|
+
if (me.__errored || me.__requestsFinished || !prepareNextRequest()) {
|
|
5512
5588
|
return;
|
|
5513
5589
|
}
|
|
5590
|
+
/* c8 ignore stop -- see comment above */
|
|
5514
5591
|
launchQueuedOp();
|
|
5515
5592
|
});
|
|
5516
5593
|
}
|
|
5517
5594
|
executeNextRequest();
|
|
5518
5595
|
}, function webSQLError(webSQLErr) {
|
|
5596
|
+
/* 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. */
|
|
5519
5597
|
// @ts-expect-error It's ok
|
|
5520
5598
|
if (webSQLErr === true) {
|
|
5521
5599
|
// Not a genuine SQL error
|
|
5522
5600
|
return;
|
|
5523
5601
|
}
|
|
5602
|
+
/* c8 ignore stop -- see comment above */
|
|
5524
5603
|
const err = webSQLErrback(/** @type {Error & {code?: number}} */webSQLErr);
|
|
5525
5604
|
me.__abortTransaction(err);
|
|
5526
5605
|
}, function () {
|
|
@@ -5531,18 +5610,25 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5531
5610
|
// Node
|
|
5532
5611
|
return;
|
|
5533
5612
|
}
|
|
5613
|
+
/* 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. */
|
|
5534
5614
|
if (!me.__transactionEndCallback && !me.__requestsFinished) {
|
|
5535
5615
|
me.__transactionFinished = true;
|
|
5536
5616
|
return;
|
|
5537
5617
|
}
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5618
|
+
/* c8 ignore stop -- see comment above */
|
|
5619
|
+
/* 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. */
|
|
5620
|
+
if (!me.__transactionEndCallback || me.__completed || me.__transFinishedCbFired) {
|
|
5621
|
+
return;
|
|
5541
5622
|
}
|
|
5623
|
+
me.__transFinishedCbFired = true;
|
|
5624
|
+
me.__transFinishedCb(me.__errored, me.__transactionEndCallback);
|
|
5625
|
+
/* c8 ignore stop -- see comment above */
|
|
5542
5626
|
}, function (currentTask, err, done, rollback, commit) {
|
|
5627
|
+
/* 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. */
|
|
5543
5628
|
if (err) {
|
|
5544
5629
|
return true;
|
|
5545
5630
|
}
|
|
5631
|
+
/* c8 ignore stop -- see comment above */
|
|
5546
5632
|
// `readonly` transactions never hold a real SQL transaction open
|
|
5547
5633
|
// (see `WebSQLTransaction`'s constructor skipping `BEGIN;` for
|
|
5548
5634
|
// them), so there's no commit/rollback round trip to defer --
|
|
@@ -5591,6 +5677,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5591
5677
|
*/
|
|
5592
5678
|
function complete() {
|
|
5593
5679
|
me.__completed = true;
|
|
5680
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
5594
5681
|
if (CFG.DEBUG) {
|
|
5595
5682
|
console.log('Transaction completed');
|
|
5596
5683
|
}
|
|
@@ -5600,6 +5687,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5600
5687
|
me.dispatchEvent(evt);
|
|
5601
5688
|
me.__internal = false;
|
|
5602
5689
|
me.dispatchEvent(createEvent('__complete'));
|
|
5690
|
+
/* 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. */
|
|
5603
5691
|
} catch (e) {
|
|
5604
5692
|
me.__internal = false;
|
|
5605
5693
|
// An error occurred in the "oncomplete" handler.
|
|
@@ -5607,6 +5695,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5607
5695
|
// (this may seem odd/bad, but it's how all native IndexedDB implementations work)
|
|
5608
5696
|
me.__errored = true;
|
|
5609
5697
|
throw e;
|
|
5698
|
+
/* c8 ignore stop -- see comment above */
|
|
5610
5699
|
} finally {
|
|
5611
5700
|
activeTransactions.delete(me);
|
|
5612
5701
|
me.__storeHandles = {};
|
|
@@ -5614,10 +5703,12 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5614
5703
|
}
|
|
5615
5704
|
}
|
|
5616
5705
|
if (me.mode === 'readwrite' || me.mode === 'readonly') {
|
|
5706
|
+
/* 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. */
|
|
5617
5707
|
if (me.__transactionFinished) {
|
|
5618
5708
|
complete();
|
|
5619
5709
|
return;
|
|
5620
5710
|
}
|
|
5711
|
+
/* c8 ignore stop -- see comment above */
|
|
5621
5712
|
me.__transactionEndCallback = complete;
|
|
5622
5713
|
// The underlying SQL driver's own "queue empty" check
|
|
5623
5714
|
// (`nonstandardTransCb`, above) typically already ran and
|
|
@@ -5653,6 +5744,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5653
5744
|
IDBTransaction.prototype.__createRequest = function (source) {
|
|
5654
5745
|
const me = this;
|
|
5655
5746
|
const request = IDBRequest.__createInstance();
|
|
5747
|
+
/* 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. */
|
|
5656
5748
|
request.__source = source !== undefined ? source : me.db;
|
|
5657
5749
|
request.__transaction = me;
|
|
5658
5750
|
return request;
|
|
@@ -5722,9 +5814,11 @@ IDBTransaction.prototype.__pushToQueue = function (request, callback, args) {
|
|
|
5722
5814
|
* @returns {void}
|
|
5723
5815
|
*/
|
|
5724
5816
|
IDBTransaction.prototype.__assertActive = function () {
|
|
5817
|
+
/* 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. */
|
|
5725
5818
|
if (!this.__active || !this.__handlerActive || this.__committed) {
|
|
5726
5819
|
throw createDOMException('TransactionInactiveError', 'A request was placed against a transaction which is currently not active, or which is finished');
|
|
5727
5820
|
}
|
|
5821
|
+
/* c8 ignore stop -- see comment above */
|
|
5728
5822
|
};
|
|
5729
5823
|
|
|
5730
5824
|
/**
|
|
@@ -5738,6 +5832,7 @@ IDBTransaction.prototype.__assertWritable = function () {
|
|
|
5738
5832
|
}
|
|
5739
5833
|
};
|
|
5740
5834
|
|
|
5835
|
+
/* 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. */
|
|
5741
5836
|
/**
|
|
5742
5837
|
* @this {IDBTransactionFull}
|
|
5743
5838
|
* @returns {void}
|
|
@@ -5745,6 +5840,7 @@ IDBTransaction.prototype.__assertWritable = function () {
|
|
|
5745
5840
|
IDBTransaction.prototype.__assertVersionChange = function () {
|
|
5746
5841
|
IDBTransaction.__assertVersionChange(this);
|
|
5747
5842
|
};
|
|
5843
|
+
/* c8 ignore stop -- see comment above */
|
|
5748
5844
|
|
|
5749
5845
|
/**
|
|
5750
5846
|
* Returns the specified object store.
|
|
@@ -5766,9 +5862,12 @@ IDBTransaction.prototype.objectStore = function (objectStoreName) {
|
|
|
5766
5862
|
throw createDOMException('NotFoundError', objectStoreName + ' is not participating in this transaction');
|
|
5767
5863
|
}
|
|
5768
5864
|
const store = me.db.__objectStores[objectStoreName];
|
|
5865
|
+
/* 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. */
|
|
5769
5866
|
if (!store) {
|
|
5770
5867
|
throw createDOMException('NotFoundError', objectStoreName + ' does not exist in ' + me.db.name);
|
|
5771
5868
|
}
|
|
5869
|
+
/* c8 ignore stop -- see comment above */
|
|
5870
|
+
|
|
5772
5871
|
if (!Object.hasOwn(me.__storeHandles, objectStoreName) ||
|
|
5773
5872
|
// These latter conditions are to allow store
|
|
5774
5873
|
// recreation to create new clone object
|
|
@@ -5787,10 +5886,12 @@ IDBTransaction.prototype.objectStore = function (objectStoreName) {
|
|
|
5787
5886
|
IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
5788
5887
|
const me = this;
|
|
5789
5888
|
logError('Error', 'An error occurred in a transaction', err);
|
|
5889
|
+
/* 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. */
|
|
5790
5890
|
if (me.__errored) {
|
|
5791
5891
|
// We've already called "onerror", "onabort", or thrown, so don't do it again.
|
|
5792
5892
|
return;
|
|
5793
5893
|
}
|
|
5894
|
+
/* c8 ignore stop -- see comment above */
|
|
5794
5895
|
me.__errored = true;
|
|
5795
5896
|
if (me.mode === 'versionchange') {
|
|
5796
5897
|
// Steps for aborting an upgrade transaction
|
|
@@ -5820,19 +5921,16 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
5820
5921
|
if (err !== null) {
|
|
5821
5922
|
me.__error = err;
|
|
5822
5923
|
}
|
|
5924
|
+
|
|
5925
|
+
/* 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. */
|
|
5823
5926
|
if (me.__requestsFinished && err !== null) {
|
|
5824
5927
|
// The transaction has already completed, so we can't call "onerror" or "onabort".
|
|
5825
|
-
// So throw the error instead.
|
|
5826
|
-
// `IDBTransaction.prototype.abort`'s own `__abortTransaction(null)`
|
|
5827
|
-
// call, which now checks `__requestsFinished` itself first and
|
|
5828
|
-
// throws `InvalidStateError` synchronously before ever reaching
|
|
5829
|
-
// this point -- so this guard is just defense in depth against
|
|
5830
|
-
// `err` somehow being `null` some other way, not something this
|
|
5831
|
-
// path should see in practice.
|
|
5928
|
+
// So throw the error instead.
|
|
5832
5929
|
setTimeout(() => {
|
|
5833
5930
|
throw err;
|
|
5834
5931
|
}, 0);
|
|
5835
5932
|
}
|
|
5933
|
+
/* c8 ignore stop -- see comment above */
|
|
5836
5934
|
|
|
5837
5935
|
/**
|
|
5838
5936
|
* @param {import('websql-configurable/lib/websql/WebSQLTransaction.js').default|null} [tx]
|
|
@@ -5841,13 +5939,17 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
5841
5939
|
*/
|
|
5842
5940
|
function abort(tx, errOrResult) {
|
|
5843
5941
|
if (!tx) {
|
|
5942
|
+
/* 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. */
|
|
5844
5943
|
if (CFG.DEBUG) {
|
|
5845
5944
|
console.log('Rollback not possible due to missing transaction', me);
|
|
5846
5945
|
}
|
|
5946
|
+
/* 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. */
|
|
5847
5947
|
} else if (errOrResult && 'code' in errOrResult && typeof errOrResult.code === 'number') {
|
|
5848
5948
|
if (CFG.DEBUG) {
|
|
5849
5949
|
console.log('Rollback erred; feature is probably not supported as per WebSQL', me);
|
|
5850
5950
|
}
|
|
5951
|
+
/* c8 ignore stop -- see comment above */
|
|
5952
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
5851
5953
|
} else if (CFG.DEBUG) {
|
|
5852
5954
|
console.log('Rollback succeeded', me);
|
|
5853
5955
|
}
|
|
@@ -5861,10 +5963,11 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
5861
5963
|
// behaves first-in-first-out with the same timeout so we could
|
|
5862
5964
|
// just use a `forEach`.
|
|
5863
5965
|
return promises.then(function () {
|
|
5966
|
+
/* 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. */
|
|
5864
5967
|
if (!q.req) {
|
|
5865
|
-
// TS guard
|
|
5866
5968
|
throw new Error('Missing request');
|
|
5867
5969
|
}
|
|
5970
|
+
/* c8 ignore stop -- see comment above */
|
|
5868
5971
|
q.req.__done = true;
|
|
5869
5972
|
q.req.__result = undefined;
|
|
5870
5973
|
q.req.__error = createDOMException('AbortError', 'A request was aborted (an unfinished request).');
|
|
@@ -5875,10 +5978,11 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
5875
5978
|
return new SyncPromise(/** @type {(resolve: (value?: unknown) => void) => void} */
|
|
5876
5979
|
resolve => {
|
|
5877
5980
|
setTimeout(() => {
|
|
5981
|
+
/* c8 ignore start -- Dead code: same invariant as above -- `q.req` was already confirmed truthy by the outer `.filter()` and is never reset. */
|
|
5878
5982
|
if (!q.req) {
|
|
5879
|
-
// TS guard
|
|
5880
5983
|
throw new Error('Missing request');
|
|
5881
5984
|
}
|
|
5985
|
+
/* c8 ignore stop -- see comment above */
|
|
5882
5986
|
q.req.dispatchEvent(reqEvt); // No need to catch errors
|
|
5883
5987
|
resolve();
|
|
5884
5988
|
}, 0);
|
|
@@ -5898,10 +6002,12 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
5898
6002
|
releaseFinishedTransaction(me);
|
|
5899
6003
|
}, 0);
|
|
5900
6004
|
return undefined;
|
|
6005
|
+
/* 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. */
|
|
5901
6006
|
}).catch(err => {
|
|
5902
6007
|
console.log('Abort error');
|
|
5903
6008
|
throw err;
|
|
5904
6009
|
});
|
|
6010
|
+
/* c8 ignore stop -- see comment above */
|
|
5905
6011
|
}
|
|
5906
6012
|
me.__transFinishedCb(true, function (rollback) {
|
|
5907
6013
|
if (rollback && me.__tx) {
|
|
@@ -5909,20 +6015,24 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
5909
6015
|
// rollback automatically), but for Node.js, etc., we give chance for
|
|
5910
6016
|
// manual aborts which would otherwise not work.
|
|
5911
6017
|
if (me.mode === 'readwrite') {
|
|
6018
|
+
/* 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. */
|
|
5912
6019
|
if (me.__transactionFinished) {
|
|
5913
6020
|
abort();
|
|
5914
6021
|
return;
|
|
5915
6022
|
}
|
|
6023
|
+
/* c8 ignore stop -- see comment above */
|
|
5916
6024
|
me.__transactionEndCallback = abort;
|
|
5917
6025
|
return;
|
|
5918
6026
|
}
|
|
5919
6027
|
try {
|
|
5920
6028
|
me.__tx.executeSql('ROLLBACK', [], abort, /** @type {import('websql-configurable/lib/websql/WebSQLTransaction.js').SqlErrorCallback} */abort); // Not working in some circumstances, even in Node
|
|
6029
|
+
/* c8 ignore start -- Defensive: the underlying WebSQL/SQLite driver throwing synchronously on `ROLLBACK` is not reliably reproducible without mocking the SQL layer. */
|
|
5921
6030
|
} catch (err) {
|
|
5922
6031
|
// Browser errs when transaction has ended and since it most likely already erred here,
|
|
5923
6032
|
// we call to abort
|
|
5924
6033
|
abort();
|
|
5925
6034
|
}
|
|
6035
|
+
/* c8 ignore stop -- see comment above */
|
|
5926
6036
|
} else {
|
|
5927
6037
|
abort(null, {
|
|
5928
6038
|
code: 0
|
|
@@ -5940,6 +6050,7 @@ IDBTransaction.prototype.abort = function () {
|
|
|
5940
6050
|
if (!(me instanceof IDBTransaction)) {
|
|
5941
6051
|
throw new TypeError('Illegal invocation');
|
|
5942
6052
|
}
|
|
6053
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
5943
6054
|
if (CFG.DEBUG) {
|
|
5944
6055
|
console.log('The transaction was aborted', me);
|
|
5945
6056
|
}
|
|
@@ -5971,6 +6082,7 @@ IDBTransaction.prototype.commit = function () {
|
|
|
5971
6082
|
if (!me.__active || !me.__handlerActive || me.__committed) {
|
|
5972
6083
|
throw createDOMException('InvalidStateError', 'Failed to execute \'commit\' on \'IDBTransaction\': The transaction is not active.');
|
|
5973
6084
|
}
|
|
6085
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
5974
6086
|
if (CFG.DEBUG) {
|
|
5975
6087
|
console.log('The transaction was explicitly committed', me);
|
|
5976
6088
|
}
|
|
@@ -6013,6 +6125,7 @@ IDBTransaction.__assertNotFinished = function (tx) {
|
|
|
6013
6125
|
};
|
|
6014
6126
|
|
|
6015
6127
|
// object store methods behave differently: see https://github.com/w3c/IndexedDB/issues/192
|
|
6128
|
+
/* 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. */
|
|
6016
6129
|
/**
|
|
6017
6130
|
*
|
|
6018
6131
|
* @param {IDBTransactionFull} tx
|
|
@@ -6028,6 +6141,7 @@ IDBTransaction.__assertNotFinishedObjectStoreMethod = function (tx) {
|
|
|
6028
6141
|
throw err;
|
|
6029
6142
|
}
|
|
6030
6143
|
};
|
|
6144
|
+
/* c8 ignore stop -- see comment above */
|
|
6031
6145
|
|
|
6032
6146
|
/**
|
|
6033
6147
|
*
|
|
@@ -6952,7 +7066,7 @@ const w = {
|
|
|
6952
7066
|
const t = e.getTime();
|
|
6953
7067
|
return Number.isNaN(t) ? "NaN" : t;
|
|
6954
7068
|
},
|
|
6955
|
-
revive: e => "NaN" === e ?
|
|
7069
|
+
revive: e => new Date("NaN" === e ? NaN : e)
|
|
6956
7070
|
}
|
|
6957
7071
|
},
|
|
6958
7072
|
T = {
|
|
@@ -7640,9 +7754,12 @@ const pe = ye.concat({
|
|
|
7640
7754
|
// we need to override it so it works with our tests
|
|
7641
7755
|
|
|
7642
7756
|
const specSet = fe.flatMap(preset => Array.isArray(preset) ? preset : [preset]).find(preset => preset && !Array.isArray(preset) && 'filelist' in preset);
|
|
7643
|
-
const origFileList = specSet && !Array.isArray(specSet) && 'filelist' in specSet ? specSet.filelist
|
|
7644
|
-
|
|
7645
|
-
const
|
|
7757
|
+
const origFileList = specSet && !Array.isArray(specSet) && 'filelist' in specSet ? specSet.filelist
|
|
7758
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */ : undefined;
|
|
7759
|
+
const origTest = origFileList && typeof origFileList === 'object' && 'test' in origFileList && typeof origFileList.test === 'function' ? origFileList.test
|
|
7760
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.test` ever goes missing */ : undefined;
|
|
7761
|
+
const origRevive = origFileList && typeof origFileList === 'object' && 'revive' in origFileList && typeof origFileList.revive === 'function' ? origFileList.revive
|
|
7762
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.revive` ever goes missing */ : undefined;
|
|
7646
7763
|
const customFileList = origFileList ? {
|
|
7647
7764
|
...origFileList,
|
|
7648
7765
|
/**
|
|
@@ -7651,10 +7768,7 @@ const customFileList = origFileList ? {
|
|
|
7651
7768
|
* @returns {boolean}
|
|
7652
7769
|
*/
|
|
7653
7770
|
test(x, state) {
|
|
7654
|
-
|
|
7655
|
-
return x instanceof FileList;
|
|
7656
|
-
}
|
|
7657
|
-
return typeof origTest === 'function' ? origTest(x, state) : false;
|
|
7771
|
+
return typeof FileList !== 'undefined' ? x instanceof FileList : typeof origTest === 'function' && origTest(x, state);
|
|
7658
7772
|
},
|
|
7659
7773
|
/**
|
|
7660
7774
|
* @param {unknown} x
|
|
@@ -7665,10 +7779,13 @@ const customFileList = origFileList ? {
|
|
|
7665
7779
|
if (typeof FileList !== 'undefined') {
|
|
7666
7780
|
return Reflect.construct(FileList, [x]);
|
|
7667
7781
|
}
|
|
7782
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.revive` ever goes missing */
|
|
7668
7783
|
return typeof origRevive === 'function' ? origRevive(x, state) : undefined;
|
|
7669
7784
|
}
|
|
7670
|
-
}
|
|
7671
|
-
|
|
7785
|
+
}
|
|
7786
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */ : undefined;
|
|
7787
|
+
let typeson = new Typeson().register([fe, /* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */
|
|
7788
|
+
customFileList ? {
|
|
7672
7789
|
filelist: customFileList
|
|
7673
7790
|
} : {}]);
|
|
7674
7791
|
|
|
@@ -7824,7 +7941,6 @@ const IDBIndexAlias = IDBIndex;
|
|
|
7824
7941
|
* __unique: boolean,
|
|
7825
7942
|
* __objectStore: import('./IDBObjectStore.js').IDBObjectStoreFull,
|
|
7826
7943
|
* __keyPath: import('./Key.js').KeyPath,
|
|
7827
|
-
* __recreated?: boolean,
|
|
7828
7944
|
* __fetchIndexData: (
|
|
7829
7945
|
* range: Query,
|
|
7830
7946
|
* opType: "value"|"key"|"count",
|
|
@@ -7922,6 +8038,7 @@ IDBIndex.__createInstance = function (store, indexProperties) {
|
|
|
7922
8038
|
storeHandle.__indexHandles[newName] = oldIndexHandle; // Ensure new reference accessible
|
|
7923
8039
|
me.__pendingName = oldName;
|
|
7924
8040
|
const colInfoToPreserveArr = [['key', 'BLOB ' + (objectStore.autoIncrement ? 'UNIQUE, inc INTEGER PRIMARY KEY AUTOINCREMENT' : 'PRIMARY KEY')], ['value', 'BLOB']].concat(
|
|
8041
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
7925
8042
|
// @ts-ignore Has numeric indexes instead of iterator; needed under some TS versions
|
|
7926
8043
|
[...objectStore.indexNames].filter(indexName => indexName !== newName).map(indexName => [escapeIndexNameForSQL(indexName), 'BLOB']));
|
|
7927
8044
|
me.__renameIndex(objectStore, oldName, newName, colInfoToPreserveArr, function (tx, success) {
|
|
@@ -7969,7 +8086,7 @@ IDBIndex.__clone = function (index, store) {
|
|
|
7969
8086
|
}
|
|
7970
8087
|
});
|
|
7971
8088
|
/** @type {const} */
|
|
7972
|
-
['__pendingCreate', '__pendingDelete', '__deleted', '__originalName'
|
|
8089
|
+
['__pendingCreate', '__pendingDelete', '__deleted', '__originalName'].forEach(p => {
|
|
7973
8090
|
// @ts-expect-error Why is this type "never"?
|
|
7974
8091
|
idx[p] = index[p];
|
|
7975
8092
|
});
|
|
@@ -8003,11 +8120,12 @@ IDBIndex.__createIndex = function (store, index) {
|
|
|
8003
8120
|
} = store;
|
|
8004
8121
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
8005
8122
|
transaction.__addNonRequestToTransactionQueue(function createIndex(tx, args, success, failure) {
|
|
8006
|
-
const columnExists = idx &&
|
|
8123
|
+
const columnExists = idx && idx.__deleted; // This check must occur here rather than earlier as properties may not have been set yet otherwise
|
|
8007
8124
|
|
|
8008
8125
|
/** @type {{[key: string]: boolean}} */
|
|
8009
8126
|
let indexValues = {};
|
|
8010
8127
|
|
|
8128
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8011
8129
|
/**
|
|
8012
8130
|
* @param {WebSQLTransaction} tx
|
|
8013
8131
|
* @param {(Error & {code?: number})} err
|
|
@@ -8016,6 +8134,7 @@ IDBIndex.__createIndex = function (store, index) {
|
|
|
8016
8134
|
function error(tx, err) {
|
|
8017
8135
|
failure(createDOMException('UnknownError', 'Could not create index "' + indexName + '"' + err.code + '::' + err.message, err));
|
|
8018
8136
|
}
|
|
8137
|
+
/* c8 ignore stop -- see comment above */
|
|
8019
8138
|
|
|
8020
8139
|
/**
|
|
8021
8140
|
* @param {WebSQLTransaction} tx
|
|
@@ -8065,12 +8184,6 @@ IDBIndex.__createIndex = function (store, index) {
|
|
|
8065
8184
|
} else {
|
|
8066
8185
|
delete index.__pendingCreate;
|
|
8067
8186
|
delete indexHandle.__pendingCreate;
|
|
8068
|
-
if (index.__deleted) {
|
|
8069
|
-
delete index.__deleted;
|
|
8070
|
-
delete indexHandle.__deleted;
|
|
8071
|
-
index.__recreated = true;
|
|
8072
|
-
indexHandle.__recreated = true;
|
|
8073
|
-
}
|
|
8074
8187
|
indexValues = {};
|
|
8075
8188
|
success(store);
|
|
8076
8189
|
}
|
|
@@ -8079,7 +8192,7 @@ IDBIndex.__createIndex = function (store, index) {
|
|
|
8079
8192
|
}, /** @type {SqlErrorCallback} */error);
|
|
8080
8193
|
}
|
|
8081
8194
|
const escapedStoreNameSQL = escapeStoreNameForSQL(storeName);
|
|
8082
|
-
const escapedIndexNameSQL = escapeIndexNameForSQL(
|
|
8195
|
+
const escapedIndexNameSQL = escapeIndexNameForSQL(indexName);
|
|
8083
8196
|
|
|
8084
8197
|
/**
|
|
8085
8198
|
* @param {WebSQLTransaction} tx
|
|
@@ -8133,6 +8246,7 @@ IDBIndex.__deleteIndex = function (store, index) {
|
|
|
8133
8246
|
} = store;
|
|
8134
8247
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
8135
8248
|
transaction.__addNonRequestToTransactionQueue(function deleteIndex(tx, args, success, failure) {
|
|
8249
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8136
8250
|
/**
|
|
8137
8251
|
* @param {WebSQLTransaction} tx
|
|
8138
8252
|
* @param {(Error & {code?: number})} err
|
|
@@ -8141,6 +8255,7 @@ IDBIndex.__deleteIndex = function (store, index) {
|
|
|
8141
8255
|
function error(tx, err) {
|
|
8142
8256
|
failure(createDOMException('UnknownError', 'Could not delete index "' + index.name + '"', err));
|
|
8143
8257
|
}
|
|
8258
|
+
/* c8 ignore stop -- see comment above */
|
|
8144
8259
|
|
|
8145
8260
|
/**
|
|
8146
8261
|
* @returns {void}
|
|
@@ -8149,7 +8264,6 @@ IDBIndex.__deleteIndex = function (store, index) {
|
|
|
8149
8264
|
// Update the object store's index list
|
|
8150
8265
|
IDBIndex.__updateIndexList(store, tx, function (store) {
|
|
8151
8266
|
delete index.__pendingDelete;
|
|
8152
|
-
delete index.__recreated;
|
|
8153
8267
|
index.__deleted = true;
|
|
8154
8268
|
if (indexHandle) {
|
|
8155
8269
|
indexHandle.__deleted = true;
|
|
@@ -8210,27 +8324,25 @@ IDBIndex.__updateIndexList = function (store, tx, success, failure) {
|
|
|
8210
8324
|
* @param {Query} range
|
|
8211
8325
|
* @param {"value"|"key"|"count"} opType
|
|
8212
8326
|
* @param {boolean} nullDisallowed
|
|
8213
|
-
* @param {number} [count]
|
|
8214
8327
|
* @this {IDBIndexFull}
|
|
8215
8328
|
* @returns {import('./IDBRequest.js').IDBRequestFull}
|
|
8216
8329
|
*/
|
|
8217
|
-
IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed
|
|
8330
|
+
IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed) {
|
|
8218
8331
|
const me = this;
|
|
8219
|
-
if (count !== undefined) {
|
|
8220
|
-
count = enforceRange(count, 'unsigned long');
|
|
8221
|
-
}
|
|
8222
8332
|
IDBIndex.__invalidStateIfDeleted(me);
|
|
8223
8333
|
IDBObjectStore.__invalidStateIfDeleted(me.objectStore);
|
|
8334
|
+
/* c8 ignore start -- Defensive: `IDBObjectStore.__invalidStateIfDeleted` just above already throws when `me.objectStore.__deleted` is true, so this identical check can never be reached. */
|
|
8224
8335
|
if (me.objectStore.__deleted) {
|
|
8225
8336
|
throw createDOMException('InvalidStateError', "This index's object store has been deleted");
|
|
8226
8337
|
}
|
|
8338
|
+
/* c8 ignore stop -- see comment above */
|
|
8227
8339
|
IDBTransaction.__assertActive(me.objectStore.transaction);
|
|
8228
8340
|
if (nullDisallowed && isNullish(range)) {
|
|
8229
8341
|
throw createDOMException('DataError', 'No key or range was specified');
|
|
8230
8342
|
}
|
|
8231
8343
|
const fetchArgs = buildFetchIndexDataSQL(nullDisallowed, me, range, opType, false);
|
|
8232
8344
|
return /** @type {import('./IDBTransaction.js').IDBTransactionFull} */me.objectStore.transaction.__addToTransactionQueue(function (...args) {
|
|
8233
|
-
executeFetchIndexData(
|
|
8345
|
+
executeFetchIndexData(...fetchArgs,
|
|
8234
8346
|
// @ts-expect-error It's ok
|
|
8235
8347
|
...args);
|
|
8236
8348
|
}, undefined, me);
|
|
@@ -8384,13 +8496,16 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
8384
8496
|
const escapedTmpStoreNameSQL = sqlQuote('tmp_' + escapeStoreNameForSQL(storeName).slice(1, -1));
|
|
8385
8497
|
const colNamesToPreserve = colInfoToPreserveArr.map(colInfo => colInfo[0]);
|
|
8386
8498
|
const colInfoToPreserve = colInfoToPreserveArr.map(colInfo => colInfo.join(' '));
|
|
8499
|
+
/* 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. */
|
|
8387
8500
|
const listColInfoToPreserve = colInfoToPreserve.length ? colInfoToPreserve.join(', ') + ', ' : '';
|
|
8501
|
+
/* c8 ignore next -- Defensive: see comment above. */
|
|
8388
8502
|
const listColsToPreserve = colNamesToPreserve.length ? colNamesToPreserve.join(', ') + ', ' : '';
|
|
8389
8503
|
|
|
8390
8504
|
// We could adapt the approach at https://stackoverflow.com/a/8430746/271577
|
|
8391
8505
|
// to make the approach reusable without passing column names, but it is a bit fragile
|
|
8392
8506
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
8393
8507
|
store.transaction.__addNonRequestToTransactionQueue(function renameIndex(tx, args, success, error) {
|
|
8508
|
+
/* 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. */
|
|
8394
8509
|
/**
|
|
8395
8510
|
* @param {WebSQLTransaction} tx
|
|
8396
8511
|
* @param {(Error & {code?: number})} err
|
|
@@ -8399,6 +8514,7 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
8399
8514
|
function sqlError(tx, err) {
|
|
8400
8515
|
error(err);
|
|
8401
8516
|
}
|
|
8517
|
+
/* c8 ignore stop -- see comment above */
|
|
8402
8518
|
/**
|
|
8403
8519
|
* @returns {void}
|
|
8404
8520
|
*/
|
|
@@ -8407,8 +8523,14 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
8407
8523
|
cb(tx, success);
|
|
8408
8524
|
return;
|
|
8409
8525
|
}
|
|
8526
|
+
/* 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. */
|
|
8410
8527
|
success();
|
|
8411
8528
|
}
|
|
8529
|
+
/* c8 ignore stop -- see comment above */
|
|
8530
|
+
if (!CFG.useSQLiteIndexes) {
|
|
8531
|
+
finish();
|
|
8532
|
+
return;
|
|
8533
|
+
}
|
|
8412
8534
|
// See https://www.sqlite.org/lang_altertable.html#otheralter
|
|
8413
8535
|
// We don't query for indexes as we already have the info
|
|
8414
8536
|
// This approach has the advantage of auto-deleting indexes via the DROP TABLE
|
|
@@ -8432,10 +8554,6 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
8432
8554
|
console.log(sql);
|
|
8433
8555
|
}
|
|
8434
8556
|
tx.executeSql(sql, [], function (tx) {
|
|
8435
|
-
if (!CFG.useSQLiteIndexes) {
|
|
8436
|
-
finish();
|
|
8437
|
-
return;
|
|
8438
|
-
}
|
|
8439
8557
|
const indexCreations = colNamesToPreserve.slice(2) // Doing `key` separately and no need for index on `value`
|
|
8440
8558
|
.map(escapedIndexNameSQL => new SyncPromise(function (resolve, reject) {
|
|
8441
8559
|
const escapedIndexToRecreate = sqlQuote(escapedStoreNameSQL.slice(1, -1) + '^5' + escapedIndexNameSQL.slice(1, -1));
|
|
@@ -8443,13 +8561,16 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
8443
8561
|
// if (CFG.DEBUG) { console.log(sql); }
|
|
8444
8562
|
// tx.executeSql(sql, [], function () {
|
|
8445
8563
|
const sql = 'CREATE INDEX ' + escapedIndexToRecreate + ' ON ' + escapedStoreNameSQL + '(' + escapedIndexNameSQL + ')';
|
|
8564
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
8446
8565
|
if (CFG.DEBUG) {
|
|
8447
8566
|
console.log(sql);
|
|
8448
8567
|
}
|
|
8449
|
-
tx.executeSql(sql, [], resolve,
|
|
8568
|
+
tx.executeSql(sql, [], resolve, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8569
|
+
/** @type {SqlErrorCallback} */
|
|
8450
8570
|
function (tx, err) {
|
|
8451
8571
|
reject(err);
|
|
8452
|
-
}
|
|
8572
|
+
}
|
|
8573
|
+
/* c8 ignore stop -- see comment above */);
|
|
8453
8574
|
// }, function (tx, err) {
|
|
8454
8575
|
// reject(err);
|
|
8455
8576
|
// });
|
|
@@ -8466,19 +8587,25 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
8466
8587
|
if (CFG.DEBUG) {
|
|
8467
8588
|
console.log(sql);
|
|
8468
8589
|
}
|
|
8469
|
-
tx.executeSql(sql, [], resolve,
|
|
8590
|
+
tx.executeSql(sql, [], resolve, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8591
|
+
/** @type {SqlErrorCallback} */
|
|
8470
8592
|
function (tx, err) {
|
|
8471
8593
|
reject(err);
|
|
8472
|
-
}
|
|
8473
|
-
|
|
8594
|
+
}
|
|
8595
|
+
/* c8 ignore stop -- see comment above */);
|
|
8596
|
+
}, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8597
|
+
/** @type {SqlErrorCallback} */
|
|
8474
8598
|
function (tx, err) {
|
|
8475
8599
|
reject(err);
|
|
8476
|
-
}
|
|
8600
|
+
}
|
|
8601
|
+
/* c8 ignore stop -- see comment above */);
|
|
8477
8602
|
}));
|
|
8478
8603
|
SyncPromise.all(indexCreations).then(finish).catch(/** @type {(reason: unknown) => PromiseLike<never>} */
|
|
8479
8604
|
error).catch(err => {
|
|
8605
|
+
/* c8 ignore start -- Defensive: only reached if `finish` or the outer `error` callback itself throws; not reliably reproducible. */
|
|
8480
8606
|
console.log('Index rename error');
|
|
8481
8607
|
throw err;
|
|
8608
|
+
/* c8 ignore stop -- see comment above */
|
|
8482
8609
|
});
|
|
8483
8610
|
}, /** @type {SqlErrorCallback} */sqlError);
|
|
8484
8611
|
}, /** @type {SqlErrorCallback} */sqlError);
|
|
@@ -8505,7 +8632,6 @@ Object.defineProperty(IDBIndex, 'prototype', {
|
|
|
8505
8632
|
/* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
|
|
8506
8633
|
|
|
8507
8634
|
/**
|
|
8508
|
-
* @param {number|null} count
|
|
8509
8635
|
* @param {boolean} unboundedDisallowed
|
|
8510
8636
|
* @param {IDBIndexFull} index
|
|
8511
8637
|
* @param {boolean} hasKey
|
|
@@ -8522,12 +8648,9 @@ Object.defineProperty(IDBIndex, 'prototype', {
|
|
|
8522
8648
|
* @param {(tx: WebSQLTransaction, err: (Error & {code?: number})) => void} error
|
|
8523
8649
|
* @returns {void}
|
|
8524
8650
|
*/
|
|
8525
|
-
function executeFetchIndexData(
|
|
8651
|
+
function executeFetchIndexData(unboundedDisallowed, index, hasKey, range, opType, multiChecks, sql, sqlValues, tx, args, success, error) {
|
|
8526
8652
|
if (unboundedDisallowed) {
|
|
8527
|
-
|
|
8528
|
-
}
|
|
8529
|
-
if (count) {
|
|
8530
|
-
sql.push('LIMIT', String(count));
|
|
8653
|
+
sql.push('LIMIT', '1');
|
|
8531
8654
|
}
|
|
8532
8655
|
const isCount = opType === 'count';
|
|
8533
8656
|
if (CFG.DEBUG) {
|
|
@@ -8589,11 +8712,15 @@ function executeFetchIndexData(count, unboundedDisallowed, index, hasKey, range,
|
|
|
8589
8712
|
record = row;
|
|
8590
8713
|
}
|
|
8591
8714
|
}
|
|
8592
|
-
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8715
|
+
/* 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. */
|
|
8716
|
+
if (!record) {
|
|
8717
|
+
continue;
|
|
8718
|
+
}
|
|
8719
|
+
/* c8 ignore stop -- see comment above */
|
|
8720
|
+
|
|
8721
|
+
records.push(decode$2(record));
|
|
8722
|
+
if (unboundedDisallowed) {
|
|
8723
|
+
break;
|
|
8597
8724
|
}
|
|
8598
8725
|
}
|
|
8599
8726
|
} else {
|
|
@@ -8608,8 +8735,16 @@ function executeFetchIndexData(count, unboundedDisallowed, index, hasKey, range,
|
|
|
8608
8735
|
if (isCount) {
|
|
8609
8736
|
success(recordCount);
|
|
8610
8737
|
} else if (recordCount === 0) {
|
|
8738
|
+
// `unboundedDisallowed` is always `true` here: this function is only reached (for
|
|
8739
|
+
// non-`count` `opType`s) via `get`/`getKey`, which always pass `nullDisallowed: true`
|
|
8740
|
+
// through as `unboundedDisallowed`. `getAll`/`getAllKeys`/`getAllRecords` use a
|
|
8741
|
+
// different (cursor-based) code path, so the `unboundedDisallowed`-`false` case
|
|
8742
|
+
// (returning `[]` here) is unreachable given current callers.
|
|
8743
|
+
/* c8 ignore next -- see comment above */
|
|
8611
8744
|
success(unboundedDisallowed ? undefined : []);
|
|
8612
8745
|
} else {
|
|
8746
|
+
// `unboundedDisallowed` is always `true` here; see comment above.
|
|
8747
|
+
/* c8 ignore next -- see comment above */
|
|
8613
8748
|
success(unboundedDisallowed ? records[0] : records);
|
|
8614
8749
|
}
|
|
8615
8750
|
}, /** @type {SqlErrorCallback} */error);
|
|
@@ -8855,6 +8990,7 @@ IDBObjectStore.__createInstance = function (storeProperties, transaction) {
|
|
|
8855
8990
|
tx.executeSql(sql, sqlValues, function (tx) {
|
|
8856
8991
|
// This SQL preserves indexes per https://www.sqlite.org/lang_altertable.html
|
|
8857
8992
|
const sql = 'ALTER TABLE ' + escapeStoreNameForSQL(oldName) + ' RENAME TO ' + escapeStoreNameForSQL(name);
|
|
8993
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG` while renaming a store. */
|
|
8858
8994
|
if (CFG.DEBUG) {
|
|
8859
8995
|
console.log(sql);
|
|
8860
8996
|
}
|
|
@@ -8863,8 +8999,10 @@ IDBObjectStore.__createInstance = function (storeProperties, transaction) {
|
|
|
8863
8999
|
success();
|
|
8864
9000
|
});
|
|
8865
9001
|
}, function (tx, err) {
|
|
9002
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8866
9003
|
error(err);
|
|
8867
9004
|
return false;
|
|
9005
|
+
/* c8 ignore stop -- see comment above */
|
|
8868
9006
|
});
|
|
8869
9007
|
});
|
|
8870
9008
|
}
|
|
@@ -8938,6 +9076,7 @@ IDBObjectStore.__createObjectStore = function (db, store) {
|
|
|
8938
9076
|
storeHandles[storeName] = IDBObjectStore.__clone(store, transaction);
|
|
8939
9077
|
}
|
|
8940
9078
|
transaction.__addNonRequestToTransactionQueue(function createObjectStore(tx, args, success, failure) {
|
|
9079
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8941
9080
|
/**
|
|
8942
9081
|
* @param {WebSQLTransaction} tx
|
|
8943
9082
|
* @param {(Error & {code?: number})} [err]
|
|
@@ -8950,6 +9089,8 @@ IDBObjectStore.__createObjectStore = function (db, store) {
|
|
|
8950
9089
|
failure(createDOMException('UnknownError', 'Could not create object store "' + storeName + '"', err));
|
|
8951
9090
|
return false;
|
|
8952
9091
|
}
|
|
9092
|
+
/* c8 ignore stop -- see comment above */
|
|
9093
|
+
|
|
8953
9094
|
const escapedStoreNameSQL = escapeStoreNameForSQL(storeName);
|
|
8954
9095
|
// key INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE
|
|
8955
9096
|
const sql = ['CREATE TABLE', escapedStoreNameSQL, '(key BLOB', store.autoIncrement ? 'UNIQUE, inc INTEGER PRIMARY KEY AUTOINCREMENT' : 'PRIMARY KEY', ', value BLOB)'].join(' ');
|
|
@@ -9004,6 +9145,7 @@ IDBObjectStore.__deleteObjectStore = function (db, store) {
|
|
|
9004
9145
|
|
|
9005
9146
|
// Remove the object store from WebSQL
|
|
9006
9147
|
transaction.__addNonRequestToTransactionQueue(function deleteObjectStore(tx, args, success, failure) {
|
|
9148
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9007
9149
|
/**
|
|
9008
9150
|
* @param {WebSQLTransaction} tx
|
|
9009
9151
|
* @param {(Error & {code?: number})} [err]
|
|
@@ -9016,6 +9158,8 @@ IDBObjectStore.__deleteObjectStore = function (db, store) {
|
|
|
9016
9158
|
failure(createDOMException('UnknownError', 'Could not delete ObjectStore', err));
|
|
9017
9159
|
return false;
|
|
9018
9160
|
}
|
|
9161
|
+
/* c8 ignore stop -- see comment above */
|
|
9162
|
+
|
|
9019
9163
|
tx.executeSql('SELECT "name" FROM __sys__ WHERE "name" = ?', [escapeSQLiteStatement(store.__currentName)], function (tx, data) {
|
|
9020
9164
|
if (data.rows.length > 0) {
|
|
9021
9165
|
tx.executeSql('DROP TABLE ' + escapeStoreNameForSQL(store.__currentName), [], function () {
|
|
@@ -9195,13 +9339,15 @@ IDBObjectStore.prototype.__checkIndexConstraints = function (tx, value, excludeK
|
|
|
9195
9339
|
return;
|
|
9196
9340
|
}
|
|
9197
9341
|
const indexKeyValue = indexKey.value;
|
|
9342
|
+
/* 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. */
|
|
9198
9343
|
if (indexKeyValue === undefined) {
|
|
9199
9344
|
resolve(undefined);
|
|
9200
9345
|
return;
|
|
9201
9346
|
}
|
|
9347
|
+
/* c8 ignore stop -- see comment above */
|
|
9202
9348
|
const multiCheck = index.multiEntry && Array.isArray(indexKeyValue);
|
|
9203
9349
|
const fetchArgs = buildFetchIndexDataSQL(true, index, indexKeyValue, 'key', multiCheck);
|
|
9204
|
-
executeFetchIndexData(
|
|
9350
|
+
executeFetchIndexData(...fetchArgs, tx, null, function success(key) {
|
|
9205
9351
|
if (key === undefined || excludeKey !== undefined && cmp(/** @type {import('./Key.js').Key} */key, excludeKey) === 0) {
|
|
9206
9352
|
resolve(undefined);
|
|
9207
9353
|
return;
|
|
@@ -9281,16 +9427,18 @@ IDBObjectStore.prototype.__insertData = function (tx, encoded, value, clonedKeyO
|
|
|
9281
9427
|
* @returns {void}
|
|
9282
9428
|
*/
|
|
9283
9429
|
function setIndexInfo(index) {
|
|
9430
|
+
/* 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. */
|
|
9284
9431
|
if (indexKeyValue === undefined) {
|
|
9285
9432
|
return;
|
|
9286
9433
|
}
|
|
9434
|
+
/* c8 ignore stop -- see comment above */
|
|
9287
9435
|
paramMap[index.__currentName] = /** @type {string} */
|
|
9288
9436
|
encode$1(indexKeyValue, index.multiEntry);
|
|
9289
9437
|
}
|
|
9290
9438
|
if (index.unique) {
|
|
9291
9439
|
const multiCheck = index.multiEntry && Array.isArray(indexKeyValue);
|
|
9292
9440
|
const fetchArgs = buildFetchIndexDataSQL(true, index, indexKeyValue, 'key', multiCheck);
|
|
9293
|
-
executeFetchIndexData(
|
|
9441
|
+
executeFetchIndexData(...fetchArgs, tx, null, function success(key) {
|
|
9294
9442
|
if (key === undefined) {
|
|
9295
9443
|
setIndexInfo(index);
|
|
9296
9444
|
resolve(undefined);
|
|
@@ -9375,6 +9523,7 @@ IDBObjectStore.prototype.add = function (value /* , key */) {
|
|
|
9375
9523
|
me.transaction.__assertWritable();
|
|
9376
9524
|
const request = /** @type {import('./IDBTransaction.js').IDBTransactionFull} */me.transaction.__createRequest(me);
|
|
9377
9525
|
const [ky, clonedValue] = me.__validateKeyAndValueAndCloneValue(value, key, false);
|
|
9526
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
9378
9527
|
// @ts-ignore -- Private API
|
|
9379
9528
|
IDBObjectStore.__storingRecordObjectStore(request, me, true, clonedValue, true, ky);
|
|
9380
9529
|
return request;
|
|
@@ -9403,6 +9552,7 @@ IDBObjectStore.prototype.put = function (value /* , key */) {
|
|
|
9403
9552
|
me.transaction.__assertWritable();
|
|
9404
9553
|
const request = /** @type {import('./IDBTransaction.js').IDBTransactionFull} */me.transaction.__createRequest(me);
|
|
9405
9554
|
const [ky, clonedValue] = me.__validateKeyAndValueAndCloneValue(value, key, false);
|
|
9555
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
9406
9556
|
// @ts-ignore -- Private API
|
|
9407
9557
|
IDBObjectStore.__storingRecordObjectStore(request, me, true, clonedValue, false, ky);
|
|
9408
9558
|
return request;
|
|
@@ -9429,8 +9579,10 @@ IDBObjectStore.prototype.__overwrite = function (tx, key, cb, error) {
|
|
|
9429
9579
|
}
|
|
9430
9580
|
cb(tx);
|
|
9431
9581
|
}, function (tx, err) {
|
|
9582
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9432
9583
|
error(err);
|
|
9433
9584
|
return false;
|
|
9585
|
+
/* c8 ignore stop -- see comment above */
|
|
9434
9586
|
});
|
|
9435
9587
|
};
|
|
9436
9588
|
|
|
@@ -9539,16 +9691,20 @@ IDBObjectStore.prototype.__get = function (query, getKey) {
|
|
|
9539
9691
|
return;
|
|
9540
9692
|
}
|
|
9541
9693
|
ret = getKey ? decode$1(unescapeSQLiteResponse(/** @type {{key: string}} */data.rows.item(0).key), false) : decode(unescapeSQLiteResponse(/** @type {{value: string}} */data.rows.item(0).value));
|
|
9694
|
+
/* 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. */
|
|
9542
9695
|
} catch (e) {
|
|
9543
9696
|
// If no result is returned, or error occurs when parsing JSON
|
|
9544
9697
|
if (CFG.DEBUG) {
|
|
9545
9698
|
console.log(e);
|
|
9546
9699
|
}
|
|
9547
9700
|
}
|
|
9701
|
+
/* c8 ignore stop -- see comment above */
|
|
9548
9702
|
success(ret);
|
|
9549
9703
|
}, function (tx, err) {
|
|
9704
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9550
9705
|
error(err);
|
|
9551
9706
|
return false;
|
|
9707
|
+
/* c8 ignore stop -- see comment above */
|
|
9552
9708
|
});
|
|
9553
9709
|
}, undefined, me);
|
|
9554
9710
|
};
|
|
@@ -9663,8 +9819,10 @@ IDBObjectStore.prototype.delete = function (query) {
|
|
|
9663
9819
|
});
|
|
9664
9820
|
success();
|
|
9665
9821
|
}, function (tx, err) {
|
|
9822
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9666
9823
|
error(err);
|
|
9667
9824
|
return false;
|
|
9825
|
+
/* c8 ignore stop -- see comment above */
|
|
9668
9826
|
});
|
|
9669
9827
|
}, undefined, me);
|
|
9670
9828
|
};
|
|
@@ -9692,8 +9850,10 @@ IDBObjectStore.prototype.clear = function () {
|
|
|
9692
9850
|
});
|
|
9693
9851
|
success();
|
|
9694
9852
|
}, function (tx, err) {
|
|
9853
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9695
9854
|
error(err);
|
|
9696
9855
|
return false;
|
|
9856
|
+
/* c8 ignore stop -- see comment above */
|
|
9697
9857
|
});
|
|
9698
9858
|
}, undefined, me);
|
|
9699
9859
|
};
|
|
@@ -10023,7 +10183,7 @@ IDBDatabase.prototype.createObjectStore = function (storeName /* , createOptions
|
|
|
10023
10183
|
if (keyPath !== null && !isValidKeyPath(keyPath)) {
|
|
10024
10184
|
throw createDOMException('SyntaxError', 'The keyPath argument contains an invalid key path.');
|
|
10025
10185
|
}
|
|
10026
|
-
if (Object.hasOwn(this.__objectStores, storeName) && !this.__objectStores[storeName].__pendingDelete) {
|
|
10186
|
+
if (Object.hasOwn(this.__objectStores, storeName) && !this.__objectStores[storeName].__pendingDelete && !this.__objectStores[storeName].__deleted) {
|
|
10027
10187
|
throw createDOMException('ConstraintError', 'Object store "' + storeName + '" already exists in ' + this.name);
|
|
10028
10188
|
}
|
|
10029
10189
|
const autoInc = createOptions.autoIncrement;
|
|
@@ -10171,7 +10331,6 @@ IDBDatabase.prototype.throwIfUpgradeTransactionNull = function () {
|
|
|
10171
10331
|
}
|
|
10172
10332
|
};
|
|
10173
10333
|
|
|
10174
|
-
// Todo __forceClose: Add tests for `__forceClose`
|
|
10175
10334
|
/**
|
|
10176
10335
|
*
|
|
10177
10336
|
* @param {string} msg
|
|
@@ -10180,23 +10339,39 @@ IDBDatabase.prototype.throwIfUpgradeTransactionNull = function () {
|
|
|
10180
10339
|
*/
|
|
10181
10340
|
IDBDatabase.prototype.__forceClose = function (msg) {
|
|
10182
10341
|
const me = this;
|
|
10342
|
+
// `close()` (below) resets `me.__transactions` to `[]`, so the
|
|
10343
|
+
// transactions to abort -- and the total count the completion check
|
|
10344
|
+
// below needs -- must be captured before calling it, not read back off
|
|
10345
|
+
// `me.__transactions` afterward.
|
|
10346
|
+
const transactions = me.__transactions;
|
|
10183
10347
|
me.close();
|
|
10348
|
+
|
|
10349
|
+
/**
|
|
10350
|
+
* @returns {void}
|
|
10351
|
+
*/
|
|
10352
|
+
function dispatchClose() {
|
|
10353
|
+
// Todo __forceClose: unblock any pending `upgradeneeded` or `deleteDatabase` calls
|
|
10354
|
+
const evt = createEvent('close');
|
|
10355
|
+
setTimeout(() => {
|
|
10356
|
+
me.dispatchEvent(evt);
|
|
10357
|
+
}, 0);
|
|
10358
|
+
}
|
|
10359
|
+
if (!transactions.length) {
|
|
10360
|
+
dispatchClose();
|
|
10361
|
+
return;
|
|
10362
|
+
}
|
|
10184
10363
|
let ct = 0;
|
|
10185
|
-
|
|
10364
|
+
transactions.forEach(function (trans) {
|
|
10186
10365
|
// eslint-disable-next-line camelcase -- Clear API
|
|
10187
10366
|
trans.on__abort = function () {
|
|
10188
10367
|
ct++;
|
|
10189
|
-
if (ct
|
|
10190
|
-
|
|
10191
|
-
const evt = createEvent('close');
|
|
10192
|
-
setTimeout(() => {
|
|
10193
|
-
me.dispatchEvent(evt);
|
|
10194
|
-
}, 0);
|
|
10368
|
+
if (ct !== transactions.length) {
|
|
10369
|
+
return;
|
|
10195
10370
|
}
|
|
10371
|
+
dispatchClose();
|
|
10196
10372
|
};
|
|
10197
10373
|
trans.__abortTransaction(createDOMException('AbortError', 'The connection was force-closed: ' + (msg || '')));
|
|
10198
10374
|
});
|
|
10199
|
-
me.__transactions = [];
|
|
10200
10375
|
};
|
|
10201
10376
|
/* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
|
|
10202
10377
|
defineOuterInterface(IDBDatabase.prototype, listeners);
|
|
@@ -10357,6 +10532,7 @@ function triggerAnyVersionChangeAndBlockedEvents(openConnections, req, oldVersio
|
|
|
10357
10532
|
return undefined;
|
|
10358
10533
|
}
|
|
10359
10534
|
const e = /** @type {Event & IDBVersionChangeEvent} */
|
|
10535
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
10360
10536
|
// @ts-ignore It's ok; needed under some TS versions
|
|
10361
10537
|
new IDBVersionChangeEvent('versionchange', {
|
|
10362
10538
|
oldVersion,
|
|
@@ -10404,6 +10580,7 @@ function triggerAnyVersionChangeAndBlockedEvents(openConnections, req, oldVersio
|
|
|
10404
10580
|
}
|
|
10405
10581
|
};
|
|
10406
10582
|
const e = /** @type {Event & IDBVersionChangeEvent} */
|
|
10583
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
10407
10584
|
// @ts-ignore It's ok; needed under some TS versions
|
|
10408
10585
|
new IDBVersionChangeEvent('blocked', {
|
|
10409
10586
|
oldVersion,
|
|
@@ -10464,6 +10641,13 @@ const pendingVersionChanges = new Map();
|
|
|
10464
10641
|
|
|
10465
10642
|
/** @type {import('websql-configurable/lib/websql/WebSQLDatabase.js').default} */
|
|
10466
10643
|
let sysdb;
|
|
10644
|
+
// Tracks which `CFG.memoryDatabase` value `sysdb` was opened against, so a
|
|
10645
|
+
// later change to that config (e.g. toggling in-memory mode on and back
|
|
10646
|
+
// off) causes `sysdb` to be recreated for the new setting rather than
|
|
10647
|
+
// staying pinned, forever, to whatever it was the first time any database
|
|
10648
|
+
// was created in the process.
|
|
10649
|
+
/** @type {string|null|undefined} */
|
|
10650
|
+
let sysdbMemoryDatabaseSetting;
|
|
10467
10651
|
let nameCounter = 0;
|
|
10468
10652
|
|
|
10469
10653
|
/**
|
|
@@ -10545,12 +10729,20 @@ function closeCachedWebSQLConnections(name, cb) {
|
|
|
10545
10729
|
function cleanupDatabaseResources(__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError) {
|
|
10546
10730
|
const useMemoryDatabase = typeof CFG.memoryDatabase === 'string';
|
|
10547
10731
|
if (useMemoryDatabase) {
|
|
10732
|
+
/* c8 ignore start -- Defensive: only reachable if `websqlDBCache[name]`
|
|
10733
|
+
was initialized as an empty placeholder by `open()`'s connection-queue
|
|
10734
|
+
setup (`addRequestToConnectionQueue`, above `openDB`) but never
|
|
10735
|
+
populated with an actual instance -- e.g. `__openDatabase` throwing
|
|
10736
|
+
after a `dbVersions` row already existed for `name` from an earlier,
|
|
10737
|
+
successful `open()` -- or if `name` was never added to the cache at
|
|
10738
|
+
all. Not reachable via normal, non-tampered API usage. */
|
|
10548
10739
|
const latestSQLiteDBCached = Object.hasOwn(websqlDBCache, name) ? getLatestCachedWebSQLDB(name) : null;
|
|
10549
10740
|
if (!latestSQLiteDBCached) {
|
|
10550
10741
|
console.warn('Could not find a memory database instance to delete.');
|
|
10551
10742
|
databaseDeleted();
|
|
10552
10743
|
return;
|
|
10553
10744
|
}
|
|
10745
|
+
/* c8 ignore stop -- see comment above */
|
|
10554
10746
|
const sqliteDB = latestSQLiteDBCached._db;
|
|
10555
10747
|
if (!sqliteDB || !sqliteDB.close) {
|
|
10556
10748
|
console.error('The `openDatabase` implementation does not have the expected `._db.close` method for closing the database');
|
|
@@ -10604,15 +10796,24 @@ function cleanupDatabaseResources(__openDatabase, name, escapedDatabaseName, dat
|
|
|
10604
10796
|
tables.item(i).name)), [], function () {
|
|
10605
10797
|
deleteTables(i + 1);
|
|
10606
10798
|
}, function () {
|
|
10799
|
+
/* c8 ignore start -- Defensive: continues deleting the rest
|
|
10800
|
+
even if this specific store's table is already gone (e.g.
|
|
10801
|
+
duplicate `__sys__` rows for the same escaped table name, or
|
|
10802
|
+
external tampering); not reachable via normal API usage. */
|
|
10607
10803
|
deleteTables(i + 1);
|
|
10608
10804
|
return false;
|
|
10805
|
+
/* c8 ignore stop -- see comment above */
|
|
10609
10806
|
});
|
|
10610
10807
|
}
|
|
10611
10808
|
})(0);
|
|
10612
10809
|
}, function () {
|
|
10613
|
-
|
|
10810
|
+
/* c8 ignore start -- `__sys__` is always created by `openDB` before this
|
|
10811
|
+
database's `dbVersions` row (a prerequisite for reaching this code at
|
|
10812
|
+
all) is ever inserted; only reachable if the file was tampered with/
|
|
10813
|
+
removed externally afterward. */
|
|
10614
10814
|
databaseDeleted();
|
|
10615
10815
|
return false;
|
|
10816
|
+
/* c8 ignore stop -- see comment above */
|
|
10616
10817
|
});
|
|
10617
10818
|
});
|
|
10618
10819
|
}
|
|
@@ -10643,9 +10844,11 @@ function createSysDB(__openDatabase, success, failure) {
|
|
|
10643
10844
|
}
|
|
10644
10845
|
failure(er);
|
|
10645
10846
|
}
|
|
10646
|
-
if (sysdb) {
|
|
10847
|
+
if (sysdb && sysdbMemoryDatabaseSetting === CFG.memoryDatabase) {
|
|
10647
10848
|
success();
|
|
10648
10849
|
} else {
|
|
10850
|
+
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Needed
|
|
10851
|
+
sysdbMemoryDatabaseSetting = CFG.memoryDatabase;
|
|
10649
10852
|
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Necessary?
|
|
10650
10853
|
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);
|
|
10651
10854
|
sysdb.transaction(function (systx) {
|
|
@@ -10825,6 +11028,17 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
10825
11028
|
* @returns {void}
|
|
10826
11029
|
*/
|
|
10827
11030
|
let sysdbFinishedCb = function (systx, err, cb) {
|
|
11031
|
+
/* c8 ignore start -- This initial definition is always
|
|
11032
|
+
superseded before ever being invoked: the `sysdb.transaction(...)`
|
|
11033
|
+
call below always reaches its `nonstandardTransCb` (4th arg)
|
|
11034
|
+
after this same SQL batch finishes running (since `dbCreateError`
|
|
11035
|
+
always reports errors as "handled" and this call site is never
|
|
11036
|
+
a `readTransaction`), which unconditionally reassigns
|
|
11037
|
+
`sysdbFinishedCb` to a version using the library's own
|
|
11038
|
+
`rollback`/`commit` -- well before any real invocation from
|
|
11039
|
+
`on__beforecomplete`/`on__preabort`/`on__abort` below (those only
|
|
11040
|
+
fire once the upgrade transaction itself later completes/aborts).
|
|
11041
|
+
Kept as a defensive fallback in case that invariant ever changes. */
|
|
10828
11042
|
if (err) {
|
|
10829
11043
|
/**
|
|
10830
11044
|
* @param {unknown} [errorToShow]
|
|
@@ -10873,6 +11087,7 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
10873
11087
|
}
|
|
10874
11088
|
// In browser, should auto-commit
|
|
10875
11089
|
cb(); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11090
|
+
/* c8 ignore stop -- see comment above */
|
|
10876
11091
|
};
|
|
10877
11092
|
sysdb.transaction(function (systx) {
|
|
10878
11093
|
/**
|
|
@@ -10880,6 +11095,7 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
10880
11095
|
*/
|
|
10881
11096
|
function versionSet() {
|
|
10882
11097
|
const e = /** @type {import('eventtargeter').EventWithProps & Event & IDBVersionChangeEvent} */
|
|
11098
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
10883
11099
|
// @ts-ignore It's ok; needed under some TS versions
|
|
10884
11100
|
new IDBVersionChangeEvent('upgradeneeded', {
|
|
10885
11101
|
oldVersion,
|
|
@@ -11005,9 +11221,17 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
11005
11221
|
// eslint-disable-next-line camelcase -- Clear API
|
|
11006
11222
|
req.transaction.on__complete = function () {
|
|
11007
11223
|
const pos = connection.__transactions.indexOf(req.transaction);
|
|
11224
|
+
// `req.transaction` (the versionchange transaction) is created
|
|
11225
|
+
// directly via `IDBTransaction.__createInstance` above, never
|
|
11226
|
+
// via `IDBDatabase.prototype.transaction()` (the only place
|
|
11227
|
+
// that pushes onto `connection.__transactions`), so `pos` is
|
|
11228
|
+
// always -1 here.
|
|
11229
|
+
/* c8 ignore start -- see comment above */
|
|
11008
11230
|
if (pos !== -1) {
|
|
11009
11231
|
connection.__transactions.splice(pos, 1);
|
|
11010
11232
|
}
|
|
11233
|
+
/* c8 ignore stop -- see comment above */
|
|
11234
|
+
|
|
11011
11235
|
if (/** @type {import('./IDBDatabase.js').IDBDatabaseFull} */req.__result.__closePending) {
|
|
11012
11236
|
req.__transaction = null;
|
|
11013
11237
|
const err = createDOMException('AbortError', 'The connection has been closed.');
|
|
@@ -11043,9 +11267,16 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
11043
11267
|
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [version, sqlSafeName], versionSet, dbCreateError);
|
|
11044
11268
|
}
|
|
11045
11269
|
}, dbCreateError, undefined, function (currentTask, err, done, rollback, commit) {
|
|
11270
|
+
// Defensive fallback, not reachable in practice: same reasoning
|
|
11271
|
+
// as `deleteDatabase`'s own `nonstandardTransCb` below
|
|
11272
|
+
// (`currentTask.readOnly` is always false here, and
|
|
11273
|
+
// `dbCreateError` always returns `false`, so `err` is never
|
|
11274
|
+
// truthy either).
|
|
11275
|
+
/* c8 ignore start -- see comment above */
|
|
11046
11276
|
if (currentTask.readOnly || err) {
|
|
11047
11277
|
return true;
|
|
11048
11278
|
}
|
|
11279
|
+
/* c8 ignore stop -- see comment above */
|
|
11049
11280
|
sysdbFinishedCb = function (systx, err, cb) {
|
|
11050
11281
|
if (err) {
|
|
11051
11282
|
rollback(err,
|
|
@@ -11060,7 +11291,17 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
11060
11291
|
} else {
|
|
11061
11292
|
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [oldVersion, sqlSafeName]);
|
|
11062
11293
|
}
|
|
11063
|
-
},
|
|
11294
|
+
},
|
|
11295
|
+
// Deeply-nested defensive path: only reached if
|
|
11296
|
+
// the *revert* SQL (undoing the `dbVersions`
|
|
11297
|
+
// INSERT/UPDATE after the original version-
|
|
11298
|
+
// upgrade itself already failed) fails a
|
|
11299
|
+
// *second* time. Not feasibly triggerable
|
|
11300
|
+
// without fault-injecting the underlying SQL
|
|
11301
|
+
// driver on this specific, already-failing
|
|
11302
|
+
// revert statement.
|
|
11303
|
+
function (sqlErr) {
|
|
11304
|
+
/* c8 ignore next 2 -- see comment above */
|
|
11064
11305
|
isRevertingSysdb = false;
|
|
11065
11306
|
cb(sqlErr); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11066
11307
|
}, function () {
|
|
@@ -11076,8 +11317,20 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
11076
11317
|
});
|
|
11077
11318
|
return undefined;
|
|
11078
11319
|
}).catch(err => {
|
|
11320
|
+
/* c8 ignore start -- Purely defensive: nothing in
|
|
11321
|
+
`triggerAnyVersionChangeAndBlockedEvents`'s promise chain
|
|
11322
|
+
(or this `.then()` continuation above) ever rejects/throws
|
|
11323
|
+
under any reachable application-level condition -- all of
|
|
11324
|
+
its continuations resolve cleanly, and its `dispatchEvent`
|
|
11325
|
+
calls are deliberately fire-and-forget ("No need to catch
|
|
11326
|
+
errors"), running inside a `setTimeout` where a listener
|
|
11327
|
+
throwing becomes an uncaught exception in that macrotask
|
|
11328
|
+
rather than a promise rejection here. This exists solely
|
|
11329
|
+
to surface a truly-unexpected internal bug via the console
|
|
11330
|
+
before rethrowing, not to handle a real, testable error path. */
|
|
11079
11331
|
console.log('Error within `triggerAnyVersionChangeAndBlockedEvents`');
|
|
11080
11332
|
throw err;
|
|
11333
|
+
/* c8 ignore stop -- see comment above */
|
|
11081
11334
|
});
|
|
11082
11335
|
} else {
|
|
11083
11336
|
finishRequest();
|
|
@@ -11105,11 +11358,19 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
11105
11358
|
if ((useMemoryDatabase || useDatabaseCache) && Object.hasOwn(websqlDBCache, name) && Object.hasOwn(websqlDBCache[name], version)) {
|
|
11106
11359
|
db = websqlDBCache[name][version];
|
|
11107
11360
|
} else {
|
|
11108
|
-
db = /** @type {DatabaseFull} */me.__openDatabase(useMemoryDatabase ? CFG.memoryDatabase : joinPath(CFG.databaseBasePath || '', escapedDatabaseName), '1', name, CFG.DEFAULT_DB_SIZE);
|
|
11361
|
+
db = /** @type {DatabaseFull} */me.__openDatabase(useMemoryDatabase ? (/** @type {string} */CFG.memoryDatabase) : joinPath(CFG.databaseBasePath || '', escapedDatabaseName), '1', name, CFG.DEFAULT_DB_SIZE);
|
|
11109
11362
|
if (useDatabaseCache) {
|
|
11363
|
+
/* c8 ignore start -- Defensive: by the time `openDB` runs,
|
|
11364
|
+
`websqlDBCache[name]` has always already been created by
|
|
11365
|
+
`addRequestToConnectionQueue`'s own callback above (guarded
|
|
11366
|
+
by this same `useDatabaseCache` condition), which always
|
|
11367
|
+
runs first and unconditionally ensures the entry exists
|
|
11368
|
+
before ever calling `openDB`. Kept as a safety net in case
|
|
11369
|
+
that invariant ever changes. */
|
|
11110
11370
|
if (!Object.hasOwn(websqlDBCache, name)) {
|
|
11111
11371
|
websqlDBCache[name] = {};
|
|
11112
11372
|
}
|
|
11373
|
+
/* c8 ignore stop -- see comment above */
|
|
11113
11374
|
websqlDBCache[name][version] = db;
|
|
11114
11375
|
}
|
|
11115
11376
|
}
|
|
@@ -11260,6 +11521,7 @@ IDBFactory.prototype.deleteDatabase = function (name) {
|
|
|
11260
11521
|
req.__result = undefined;
|
|
11261
11522
|
req.__done = true;
|
|
11262
11523
|
const e = /** @type {Event & IDBVersionChangeEvent} */
|
|
11524
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11263
11525
|
// @ts-ignore It's ok; needed under some TS versions
|
|
11264
11526
|
new IDBVersionChangeEvent('success', {
|
|
11265
11527
|
oldVersion: version,
|
|
@@ -11303,9 +11565,23 @@ IDBFactory.prototype.deleteDatabase = function (name) {
|
|
|
11303
11565
|
cleanupDatabaseResources(me.__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError);
|
|
11304
11566
|
}, dbError);
|
|
11305
11567
|
}, dbError, undefined, function (currentTask, err, done, rollback, commit) {
|
|
11568
|
+
/* c8 ignore start -- Defensive fallback, not reachable in
|
|
11569
|
+
practice: `currentTask.readOnly` is always `false` here
|
|
11570
|
+
(this callback is only ever attached to the writable
|
|
11571
|
+
`sysdb.transaction(...)` call above, never to a
|
|
11572
|
+
`sysdb.readTransaction(...)`), and `err` can only be
|
|
11573
|
+
truthy if the `DELETE FROM dbVersions` statement's own
|
|
11574
|
+
error callback (`dbError`) reports the failure back to
|
|
11575
|
+
`websql-configurable` as unhandled -- but `dbError`
|
|
11576
|
+
deliberately always `return`s `false`, which tells the
|
|
11577
|
+
library the error was already handled (and to keep
|
|
11578
|
+
`err` falsy here), precisely so this custom
|
|
11579
|
+
`sysdbFinishedCbDelete` rollback/commit path below is
|
|
11580
|
+
used instead of the library's own default rollback. */
|
|
11306
11581
|
if (currentTask.readOnly || err) {
|
|
11307
11582
|
return true;
|
|
11308
11583
|
}
|
|
11584
|
+
/* c8 ignore stop -- see comment above */
|
|
11309
11585
|
sysdbFinishedCbDelete = function (err, cb) {
|
|
11310
11586
|
if (err) {
|
|
11311
11587
|
rollback(err, cb);
|
|
@@ -11432,10 +11708,9 @@ IDBFactory.prototype.databases = function () {
|
|
|
11432
11708
|
};
|
|
11433
11709
|
|
|
11434
11710
|
/**
|
|
11435
|
-
* @todo forceClose: Test
|
|
11436
11711
|
* This is provided to facilitate unit-testing of the
|
|
11437
11712
|
* closing of a database connection with a forced flag:
|
|
11438
|
-
* <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection
|
|
11713
|
+
* <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection>.
|
|
11439
11714
|
* @param {string} dbName
|
|
11440
11715
|
* @param {Integer} connIdx
|
|
11441
11716
|
* @param {string} msg
|
|
@@ -11535,6 +11810,7 @@ IDBRecord.__createInstance = function (key, primaryKey, value) {
|
|
|
11535
11810
|
* @this {IDBRecordFull}
|
|
11536
11811
|
*/
|
|
11537
11812
|
function IDBRecord() {
|
|
11813
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11538
11814
|
// @ts-ignore Should be ok
|
|
11539
11815
|
this[Symbol.toStringTag] = 'IDBRecord';
|
|
11540
11816
|
this.__key = key;
|
|
@@ -11575,6 +11851,7 @@ readonlyProperties.forEach(prop => {
|
|
|
11575
11851
|
if (!(this instanceof IDBRecordAlias)) {
|
|
11576
11852
|
throw new TypeError('Illegal invocation');
|
|
11577
11853
|
}
|
|
11854
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11578
11855
|
// @ts-ignore `this` is a real instance past the check above (not an issue in TS7)
|
|
11579
11856
|
return this['__' + prop];
|
|
11580
11857
|
}
|
|
@@ -11918,6 +12195,7 @@ IDBCursor.prototype.__findBasic = function (key, primaryKey, tx, success, error,
|
|
|
11918
12195
|
success(undefined, undefined, undefined);
|
|
11919
12196
|
}
|
|
11920
12197
|
}, function (tx, err) {
|
|
12198
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
11921
12199
|
if (CFG.DEBUG) {
|
|
11922
12200
|
console.log('Could not execute Cursor.continue', sqlStr, sqlValues);
|
|
11923
12201
|
}
|
|
@@ -12093,7 +12371,16 @@ IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, e
|
|
|
12093
12371
|
if (a.key > b.key) {
|
|
12094
12372
|
return me.direction === 'prev' ? -1 : 1;
|
|
12095
12373
|
}
|
|
12374
|
+
/* c8 ignore start -- Defensive: only reachable if two matches
|
|
12375
|
+
in the same batch shared both the same `matchingKey` and
|
|
12376
|
+
the same primary `key`, which would require the same
|
|
12377
|
+
record's multi-entry array to contain a duplicate value.
|
|
12378
|
+
`Key.js`'s array-to-key conversion already drops duplicate
|
|
12379
|
+
values when a multi-entry index entry is built, so this
|
|
12380
|
+
can never happen in practice; kept only to satisfy the
|
|
12381
|
+
`Array.prototype.sort` comparator contract. */
|
|
12096
12382
|
return 0;
|
|
12383
|
+
/* c8 ignore stop -- see comment above */
|
|
12097
12384
|
});
|
|
12098
12385
|
me.__prefetchedIndex = 0;
|
|
12099
12386
|
me.__prefetchedData = {
|
|
@@ -12112,13 +12399,19 @@ IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, e
|
|
|
12112
12399
|
console.log('[multiEntry] Preloaded ' + me.__prefetchedData.length + ' records for multiEntry cursor');
|
|
12113
12400
|
}
|
|
12114
12401
|
me.__decode(rows[0], success);
|
|
12115
|
-
},
|
|
12402
|
+
},
|
|
12403
|
+
/* c8 ignore start -- Defensive: guards against an unexpected SQLite
|
|
12404
|
+
execution error (e.g. I/O error, corruption) while querying for
|
|
12405
|
+
multi-entry cursor matches; not reliably reproducible without
|
|
12406
|
+
mocking the SQL layer. */
|
|
12407
|
+
function (tx, err) {
|
|
12116
12408
|
if (CFG.DEBUG) {
|
|
12117
12409
|
console.log('[multiEntry] Could not execute Cursor.continue', sqlStr, sqlValues);
|
|
12118
12410
|
}
|
|
12119
12411
|
error(err);
|
|
12120
12412
|
return false;
|
|
12121
12413
|
});
|
|
12414
|
+
/* c8 ignore stop -- see comment above */
|
|
12122
12415
|
}
|
|
12123
12416
|
runQuery();
|
|
12124
12417
|
};
|
|
@@ -12227,6 +12520,7 @@ IDBCursor.prototype.__sourceOrEffectiveObjStoreDeleted = function () {
|
|
|
12227
12520
|
* @returns {void}
|
|
12228
12521
|
*/
|
|
12229
12522
|
IDBCursor.prototype.__invalidateCache = function () {
|
|
12523
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
12230
12524
|
// @ts-ignore Why is this not being found?; needed under some TS versions
|
|
12231
12525
|
this.__prefetchedData = null;
|
|
12232
12526
|
this.__multiEntryExhausted = false;
|
|
@@ -12251,7 +12545,7 @@ IDBCursor.prototype.__continue = function (key, advanceContinue) {
|
|
|
12251
12545
|
convertValueToKeyRethrowingAndIfInvalid(key);
|
|
12252
12546
|
const cmpResult = cmp(key, me.key);
|
|
12253
12547
|
if (cmpResult === 0 || me.direction.includes('next') && cmpResult === -1 || me.direction.includes('prev') && cmpResult === 1) {
|
|
12254
|
-
throw createDOMException('DataError', 'Cannot
|
|
12548
|
+
throw createDOMException('DataError', 'Cannot continue the cursor in an unexpected direction');
|
|
12255
12549
|
}
|
|
12256
12550
|
}
|
|
12257
12551
|
this.__continueFinish(key, undefined, advanceState);
|
|
@@ -12500,6 +12794,7 @@ IDBCursor.prototype.update = function (valueToUpdate) {
|
|
|
12500
12794
|
// continuation logic in `__findBasic` to see this update's
|
|
12501
12795
|
// effect on ordering (see "Modify records during cursor
|
|
12502
12796
|
// iteration" in idbcursor_update_index.any.js).
|
|
12797
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
12503
12798
|
// @ts-ignore -- API (not erring in TS 6)
|
|
12504
12799
|
IDBObjectStore.__storingRecordObjectStore(request, me.__store, true, clonedValue, false, key);
|
|
12505
12800
|
}
|
|
@@ -12546,14 +12841,33 @@ IDBCursor.prototype.delete = function () {
|
|
|
12546
12841
|
// We don't invalidate the cache (as we don't access it anymore
|
|
12547
12842
|
// and it will set the index off)
|
|
12548
12843
|
success(undefined);
|
|
12844
|
+
/* c8 ignore start -- Defensive: `__find` (invoked just above) has
|
|
12845
|
+
already confirmed a row exists for this primary key within the
|
|
12846
|
+
same transaction queue, so `rowsAffected` should always be 1 in
|
|
12847
|
+
normal usage. This branch would only be reached if the underlying
|
|
12848
|
+
row were removed by another request queued in the same
|
|
12849
|
+
transaction between `__find`'s check and this DELETE actually
|
|
12850
|
+
running (e.g. deleting the same record directly via the object
|
|
12851
|
+
store while a cursor over it is mid-iteration); attempts to
|
|
12852
|
+
construct such a scenario instead trigger a transaction abort
|
|
12853
|
+
(`AbortError`) before this callback ever runs, since the default
|
|
12854
|
+
action of an unhandled request error is to abort the
|
|
12855
|
+
transaction. */
|
|
12549
12856
|
} else {
|
|
12550
12857
|
// @ts-expect-error Apparently ok
|
|
12551
12858
|
error('No rows with key found' + key);
|
|
12552
12859
|
}
|
|
12553
|
-
|
|
12860
|
+
/* c8 ignore stop -- see comment above */
|
|
12861
|
+
},
|
|
12862
|
+
/* c8 ignore start -- Defensive: guards against an unexpected SQLite
|
|
12863
|
+
execution error (e.g. I/O error, corruption) while deleting the
|
|
12864
|
+
current row; not reliably reproducible without mocking the SQL
|
|
12865
|
+
layer. */
|
|
12866
|
+
function (tx, data) {
|
|
12554
12867
|
error(data);
|
|
12555
12868
|
return false;
|
|
12556
12869
|
});
|
|
12870
|
+
/* c8 ignore stop -- see comment above */
|
|
12557
12871
|
}, error);
|
|
12558
12872
|
}, undefined, me);
|
|
12559
12873
|
};
|
|
@@ -12959,7 +13273,7 @@ function setGlobalVars(idb, initialConfig) {
|
|
|
12959
13273
|
setConfig(initialConfig);
|
|
12960
13274
|
}
|
|
12961
13275
|
const IDB = /** @type {ShimmedObject & {[key: string]: unknown}} */
|
|
12962
|
-
/** @type {unknown} */idb || globalThis
|
|
13276
|
+
/** @type {unknown} */idb || globalThis;
|
|
12963
13277
|
/**
|
|
12964
13278
|
* @param {string} name
|
|
12965
13279
|
* @param {unknown} value
|
|
@@ -13054,77 +13368,84 @@ function setGlobalVars(idb, initialConfig) {
|
|
|
13054
13368
|
});
|
|
13055
13369
|
}
|
|
13056
13370
|
const shimIDBFactory = IDBFactory;
|
|
13057
|
-
if (CFG.win.openDatabase
|
|
13058
|
-
|
|
13059
|
-
|
|
13060
|
-
|
|
13061
|
-
|
|
13062
|
-
|
|
13063
|
-
|
|
13064
|
-
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13371
|
+
if (CFG.win.openDatabase === undefined) {
|
|
13372
|
+
return;
|
|
13373
|
+
}
|
|
13374
|
+
shimIndexedDB.__openDatabase = CFG.win.openDatabase.bind(CFG.win); // We cache here in case the function is overwritten later as by the IndexedDB support promises tests
|
|
13375
|
+
// Polyfill ALL of IndexedDB, using WebSQL
|
|
13376
|
+
shim('indexedDB', shimIndexedDB, {
|
|
13377
|
+
enumerable: true,
|
|
13378
|
+
configurable: true,
|
|
13379
|
+
get() {
|
|
13380
|
+
if (this !== IDB && !isNullish(this) && !this.shimNS) {
|
|
13381
|
+
// Latter is hack for test environment
|
|
13382
|
+
throw new TypeError('Illegal invocation');
|
|
13069
13383
|
}
|
|
13070
|
-
|
|
13071
|
-
/** @type {[string, unknown][]} */
|
|
13072
|
-
[['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(([prop, obj]) => {
|
|
13073
|
-
shim(prop, obj, {
|
|
13074
|
-
enumerable: false,
|
|
13075
|
-
configurable: true
|
|
13076
|
-
});
|
|
13077
|
-
});
|
|
13078
|
-
// For Node environments
|
|
13079
|
-
if (CFG.fs) {
|
|
13080
|
-
setFS(CFG.fs);
|
|
13384
|
+
return shimIndexedDB;
|
|
13081
13385
|
}
|
|
13082
|
-
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
|
|
13086
|
-
|
|
13087
|
-
|
|
13088
|
-
|
|
13089
|
-
|
|
13090
|
-
|
|
13091
|
-
|
|
13092
|
-
|
|
13093
|
-
|
|
13094
|
-
|
|
13095
|
-
|
|
13096
|
-
|
|
13097
|
-
|
|
13098
|
-
|
|
13099
|
-
|
|
13100
|
-
|
|
13101
|
-
|
|
13102
|
-
|
|
13103
|
-
|
|
13104
|
-
|
|
13105
|
-
|
|
13106
|
-
|
|
13107
|
-
|
|
13108
|
-
|
|
13386
|
+
});
|
|
13387
|
+
/** @type {[string, unknown][]} */
|
|
13388
|
+
[['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(([prop, obj]) => {
|
|
13389
|
+
shim(prop, obj, {
|
|
13390
|
+
enumerable: false,
|
|
13391
|
+
configurable: true
|
|
13392
|
+
});
|
|
13393
|
+
});
|
|
13394
|
+
// For Node environments
|
|
13395
|
+
if (CFG.fs) {
|
|
13396
|
+
setFS(CFG.fs);
|
|
13397
|
+
}
|
|
13398
|
+
if (CFG.fullIDLSupport) {
|
|
13399
|
+
// Slow per MDN so off by default! Though apparently needed for WebIDL: https://stackoverflow.com/questions/41927589/rationales-consequences-of-webidl-class-inheritance-requirements
|
|
13400
|
+
|
|
13401
|
+
Object.setPrototypeOf(IDB.IDBOpenDBRequest, IDB.IDBRequest);
|
|
13402
|
+
Object.setPrototypeOf(IDB.IDBCursorWithValue, IDB.IDBCursor);
|
|
13403
|
+
Object.setPrototypeOf(IDBDatabase, EventTarget);
|
|
13404
|
+
Object.setPrototypeOf(IDBRequest, EventTarget);
|
|
13405
|
+
Object.setPrototypeOf(IDBTransaction, EventTarget);
|
|
13406
|
+
Object.setPrototypeOf(IDBVersionChangeEvent, ShimEvent);
|
|
13407
|
+
// `ShimDOMException` is the real native `DOMException` when one
|
|
13408
|
+
// is available (see `DOMException.js`'s `useNativeDOMException`)
|
|
13409
|
+
// -- which, unlike the shim classes above, is a single,
|
|
13410
|
+
// process-wide singleton shared by reference across every
|
|
13411
|
+
// sandbox this library gets installed into (see
|
|
13412
|
+
// `node-idb-test.js`'s `sandboxObj`). A native `DOMException`
|
|
13413
|
+
// already has the correct prototype chain out of the box
|
|
13414
|
+
// (`Object.getPrototypeOf(DOMException) === Function.prototype`,
|
|
13415
|
+
// not `Error`), so forcing it here isn't just unneeded but
|
|
13416
|
+
// actively wrong -- and, because it's shared, permanently
|
|
13417
|
+
// wrong for every later use of `DOMException` in the same
|
|
13418
|
+
// process (e.g. a later WPT test file's own idlharness-style
|
|
13419
|
+
// check that `DOMException` does *not* inherit from `Error`
|
|
13420
|
+
// on the class side), not just this one shim install.
|
|
13421
|
+
if (typeof DOMException === 'undefined' || ShimDOMException !== DOMException) {
|
|
13422
|
+
Object.setPrototypeOf(ShimDOMException, Error);
|
|
13423
|
+
Object.setPrototypeOf(ShimDOMException.prototype, Error.prototype);
|
|
13109
13424
|
}
|
|
13110
|
-
|
|
13111
|
-
|
|
13112
|
-
|
|
13113
|
-
|
|
13114
|
-
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
if (CFG.replaceNonIDBGlobals) {
|
|
13118
|
-
setNonIDBGlobals();
|
|
13119
|
-
}
|
|
13425
|
+
}
|
|
13426
|
+
if (IDB.indexedDB && !IDB.indexedDB.toString().includes('[native code]')) {
|
|
13427
|
+
if (CFG.addNonIDBGlobals) {
|
|
13428
|
+
// As `DOMStringList` exists per IDL (and Chrome) in the global
|
|
13429
|
+
// thread (but not in workers), we prefix the name to avoid
|
|
13430
|
+
// shadowing or conflicts
|
|
13431
|
+
setNonIDBGlobals('Shim');
|
|
13120
13432
|
}
|
|
13121
|
-
|
|
13122
|
-
|
|
13123
|
-
return;
|
|
13433
|
+
if (CFG.replaceNonIDBGlobals) {
|
|
13434
|
+
setNonIDBGlobals();
|
|
13124
13435
|
}
|
|
13125
|
-
/* c8 ignore stop -- TS guard */
|
|
13126
|
-
IDB.shimIndexedDB.__setConnectionQueueOrigin();
|
|
13127
13436
|
}
|
|
13437
|
+
/* c8 ignore start -- Defensive: `IDB.shimIndexedDB` was already
|
|
13438
|
+
confirmed truthy just before this function (`__useShim`) was
|
|
13439
|
+
defined and immediately invoked (see the `if ('shimIndexedDB'
|
|
13440
|
+
in IDB && IDB.shimIndexedDB)` guard above), and nothing in
|
|
13441
|
+
this function's body reassigns or deletes it. Only reachable
|
|
13442
|
+
if `IDB` is some unusual object (e.g. a Proxy) whose
|
|
13443
|
+
`shimIndexedDB` property value changes between reads. */
|
|
13444
|
+
if (!IDB.shimIndexedDB) {
|
|
13445
|
+
return;
|
|
13446
|
+
}
|
|
13447
|
+
/* c8 ignore stop -- see comment above */
|
|
13448
|
+
IDB.shimIndexedDB.__setConnectionQueueOrigin();
|
|
13128
13449
|
};
|
|
13129
13450
|
IDB.shimIndexedDB.__debug = /** @type {(val: boolean) => void} */function (val) {
|
|
13130
13451
|
CFG.DEBUG = val;
|
|
@@ -13232,6 +13553,7 @@ function setGlobalVars(idb, initialConfig) {
|
|
|
13232
13553
|
* @returns {SQLiteDatabaseInstance}
|
|
13233
13554
|
*/
|
|
13234
13555
|
function wrappedSQLiteDatabase(name) {
|
|
13556
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
13235
13557
|
// @ts-ignore It's ok; needed under some TS versions
|
|
13236
13558
|
const db = new SQLiteDatabase(name, {});
|
|
13237
13559
|
if (CFG.sqlBusyTimeout) {
|