indexeddbshim 19.0.4 → 19.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/badges/coverage-badge.svg +1 -1
- package/badges/tests-badge.svg +1 -1
- package/dist/CFG.d.ts +1 -1
- package/dist/CFG.d.ts.map +1 -1
- package/dist/DOMException.d.ts.map +1 -1
- package/dist/IDBCursor.d.ts.map +1 -1
- package/dist/IDBDatabase.d.ts.map +1 -1
- package/dist/IDBFactory.d.ts +1 -2
- package/dist/IDBFactory.d.ts.map +1 -1
- package/dist/IDBIndex.d.ts +2 -6
- package/dist/IDBIndex.d.ts.map +1 -1
- package/dist/IDBKeyRange.d.ts.map +1 -1
- package/dist/IDBObjectStore.d.ts.map +1 -1
- package/dist/IDBRecord.d.ts.map +1 -1
- package/dist/IDBRequest.d.ts.map +1 -1
- package/dist/IDBTransaction.d.ts.map +1 -1
- package/dist/Key.d.ts.map +1 -1
- package/dist/Sca.d.ts.map +1 -1
- package/dist/indexeddbshim-Key.js +40 -28
- package/dist/indexeddbshim-Key.js.map +1 -1
- package/dist/indexeddbshim-Key.min.js +2 -2
- package/dist/indexeddbshim-Key.min.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs +525 -225
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.js +553 -252
- package/dist/indexeddbshim-UnicodeIdentifiers.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js +3 -3
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js.map +1 -1
- package/dist/indexeddbshim-node.cjs +525 -225
- package/dist/indexeddbshim-node.cjs.map +1 -1
- package/dist/indexeddbshim-noninvasive.js +553 -252
- package/dist/indexeddbshim-noninvasive.js.map +1 -1
- package/dist/indexeddbshim-noninvasive.min.js +3 -3
- package/dist/indexeddbshim-noninvasive.min.js.map +1 -1
- package/dist/indexeddbshim.js +553 -252
- package/dist/indexeddbshim.js.map +1 -1
- package/dist/indexeddbshim.min.js +3 -3
- package/dist/indexeddbshim.min.js.map +1 -1
- package/dist/nodeWebSQL.d.ts.map +1 -1
- package/dist/setGlobalVars.d.ts +1 -1
- package/dist/setGlobalVars.d.ts.map +1 -1
- package/dist/util.d.ts.map +1 -1
- package/package.json +22 -17
- package/src/CFG.js +18 -4
- package/src/DOMException.js +6 -0
- package/src/DOMStringList.js +3 -0
- package/src/IDBCursor.js +36 -3
- package/src/IDBDatabase.js +26 -10
- package/src/IDBFactory.js +105 -5
- package/src/IDBIndex.js +49 -32
- package/src/IDBKeyRange.js +8 -7
- package/src/IDBObjectStore.js +25 -2
- package/src/IDBRecord.js +2 -0
- package/src/IDBRequest.js +7 -4
- package/src/IDBTransaction.js +111 -34
- package/src/Key.js +17 -16
- package/src/Sca.js +9 -4
- package/src/nodeWebSQL.js +1 -0
- package/src/setGlobalVars.js +86 -77
- package/src/util.js +5 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! indexeddbshim - v19.0.
|
|
1
|
+
/*! indexeddbshim - v19.0.6 - 9/22/2026 */
|
|
2
2
|
|
|
3
3
|
'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,
|
|
@@ -3781,7 +3805,13 @@ function convertValueToKeyValueDecoded(input, seen, multiEntry, fullKeys) {
|
|
|
3781
3805
|
message: 'Bad array entry value-to-key conversion'
|
|
3782
3806
|
};
|
|
3783
3807
|
}
|
|
3784
|
-
if (!multiEntry || !fullKeys && keys.every(k => cmp(/** @type {Key} */k, /** @type {Key} */key.value) !== 0) ||
|
|
3808
|
+
if (!multiEntry || !fullKeys && keys.every(k => cmp(/** @type {Key} */k, /** @type {Key} */key.value) !== 0) ||
|
|
3809
|
+
// `keys` holds full `{type, value}` objects here (see
|
|
3810
|
+
// `safePush` below), so -- like the sibling branch
|
|
3811
|
+
// above -- `cmp` (which expects raw `Value`s, not
|
|
3812
|
+
// decoded key objects) must compare their `.value`s,
|
|
3813
|
+
// not the wrapper objects themselves.
|
|
3814
|
+
fullKeys && keys.every(k => cmp(/** @type {Key} */ /** @type {KeyValueObject} */k.value, /** @type {Key} */key.value) !== 0)) {
|
|
3785
3815
|
safePush(keys, fullKeys ? key : key.value);
|
|
3786
3816
|
}
|
|
3787
3817
|
} catch (err) {
|
|
@@ -3799,12 +3829,9 @@ function convertValueToKeyValueDecoded(input, seen, multiEntry, fullKeys) {
|
|
|
3799
3829
|
{
|
|
3800
3830
|
const date = /** @type {Date} */input;
|
|
3801
3831
|
if (!Number.isNaN(date.getTime())) {
|
|
3802
|
-
return
|
|
3803
|
-
type,
|
|
3804
|
-
value: date.getTime()
|
|
3805
|
-
} : {
|
|
3832
|
+
return {
|
|
3806
3833
|
type,
|
|
3807
|
-
value: new Date(date)
|
|
3834
|
+
value: fullKeys ? date.getTime() : new Date(date)
|
|
3808
3835
|
};
|
|
3809
3836
|
}
|
|
3810
3837
|
return {
|
|
@@ -3892,10 +3919,7 @@ function extractKeyValueDecodedFromValueUsingKeyPath(value, keyPath, multiEntry,
|
|
|
3892
3919
|
if (r.failure) {
|
|
3893
3920
|
return r;
|
|
3894
3921
|
}
|
|
3895
|
-
|
|
3896
|
-
return convertValueToKeyValueDecoded(r.value, null, false, fullKeys);
|
|
3897
|
-
}
|
|
3898
|
-
return convertValueToMultiEntryKeyDecoded(r.value, fullKeys);
|
|
3922
|
+
return !multiEntry ? convertValueToKeyValueDecoded(r.value, null, false, fullKeys) : convertValueToMultiEntryKeyDecoded(r.value, fullKeys);
|
|
3899
3923
|
}
|
|
3900
3924
|
|
|
3901
3925
|
/**
|
|
@@ -4067,10 +4091,7 @@ function isKeyInRange(key, range, checkCached) {
|
|
|
4067
4091
|
*/
|
|
4068
4092
|
function isMultiEntryMatch(encodedEntry, encodedKey) {
|
|
4069
4093
|
const keyType = encodedCharToKeyType[encodedKey.slice(0, 1)];
|
|
4070
|
-
|
|
4071
|
-
return encodedKey.indexOf(encodedEntry) > 1;
|
|
4072
|
-
}
|
|
4073
|
-
return encodedKey === encodedEntry;
|
|
4094
|
+
return keyType === 'array' ? encodedKey.indexOf(encodedEntry) > 1 : encodedKey === encodedEntry;
|
|
4074
4095
|
}
|
|
4075
4096
|
|
|
4076
4097
|
/**
|
|
@@ -4181,10 +4202,7 @@ function encode$1(key, inArray) {
|
|
|
4181
4202
|
* @returns {undefined|ValueType}
|
|
4182
4203
|
*/
|
|
4183
4204
|
function decode$1(key, inArray) {
|
|
4184
|
-
|
|
4185
|
-
return undefined;
|
|
4186
|
-
}
|
|
4187
|
-
return types[encodedCharToKeyType[key.slice(0, 1)]].decode(key, inArray);
|
|
4205
|
+
return typeof key !== 'string' ? undefined : types[encodedCharToKeyType[key.slice(0, 1)]].decode(key, inArray);
|
|
4188
4206
|
}
|
|
4189
4207
|
|
|
4190
4208
|
/**
|
|
@@ -4596,10 +4614,11 @@ function setSQLForKeyRange(range, quotedKeyColumnName, sql, sqlValues, addAnd, c
|
|
|
4596
4614
|
if (hasLower && hasUpper) {
|
|
4597
4615
|
sql.push('AND');
|
|
4598
4616
|
}
|
|
4599
|
-
if (hasUpper) {
|
|
4600
|
-
|
|
4601
|
-
sqlValues.push(escapeSQLiteStatement(/** @type {string} */encodedUpperKey));
|
|
4617
|
+
if (!hasUpper) {
|
|
4618
|
+
return;
|
|
4602
4619
|
}
|
|
4620
|
+
sql.push(quotedKeyColumnName, range.upperOpen ? '<' : '<=', '?');
|
|
4621
|
+
sqlValues.push(escapeSQLiteStatement(/** @type {string} */encodedUpperKey));
|
|
4603
4622
|
}
|
|
4604
4623
|
|
|
4605
4624
|
/**
|
|
@@ -4612,10 +4631,7 @@ function convertValueToKeyRange(value, nullDisallowed) {
|
|
|
4612
4631
|
if (instanceOf(value, IDBKeyRange)) {
|
|
4613
4632
|
// We still need to validate IDBKeyRange-like objects (the above check is based on loose duck-typing)
|
|
4614
4633
|
const range = /** @type {IDBKeyRangeFull} */value;
|
|
4615
|
-
|
|
4616
|
-
return IDBKeyRange.__createInstance(range.lower, range.upper, range.lowerOpen, range.upperOpen);
|
|
4617
|
-
}
|
|
4618
|
-
return range;
|
|
4634
|
+
return range.toString() !== '[object IDBKeyRange]' ? IDBKeyRange.__createInstance(range.lower, range.upper, range.lowerOpen, range.upperOpen) : range;
|
|
4619
4635
|
}
|
|
4620
4636
|
if (isNullish(value)) {
|
|
4621
4637
|
if (nullDisallowed) {
|
|
@@ -4660,9 +4676,11 @@ if (Object.defineProperty) {
|
|
|
4660
4676
|
if (testObject.test) {
|
|
4661
4677
|
cleanInterface = true;
|
|
4662
4678
|
}
|
|
4679
|
+
/* c8 ignore start -- Defensive fallback for an engine with a broken `Object.defineProperty` */
|
|
4663
4680
|
} catch (err) {
|
|
4664
4681
|
// Object.defineProperty does not work as intended.
|
|
4665
4682
|
}
|
|
4683
|
+
/* c8 ignore stop -- Defensive fallback for an engine with a broken `Object.defineProperty` */
|
|
4666
4684
|
}
|
|
4667
4685
|
|
|
4668
4686
|
/**
|
|
@@ -4860,6 +4878,7 @@ Object.defineProperty(DOMStringList, '__createInstance', {
|
|
|
4860
4878
|
this._length = 0;
|
|
4861
4879
|
};
|
|
4862
4880
|
DOMStringList.prototype = DOMStringListAlias.prototype;
|
|
4881
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
4863
4882
|
// @ts-ignore It's ok; needed under some TS versions
|
|
4864
4883
|
return /** @type {DOMStringListFull} */new DOMStringList();
|
|
4865
4884
|
}
|
|
@@ -5157,12 +5176,14 @@ IDBTransaction.prototype.__callTransFinishedCb = function (err, cb) {
|
|
|
5157
5176
|
*/
|
|
5158
5177
|
IDBTransaction.prototype.__executeRequests = function () {
|
|
5159
5178
|
const me = this;
|
|
5179
|
+
/* 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
5180
|
if (me.__running) {
|
|
5161
5181
|
if (CFG.DEBUG) {
|
|
5162
5182
|
console.log('Looks like the request set is already running', me.mode);
|
|
5163
5183
|
}
|
|
5164
5184
|
return;
|
|
5165
5185
|
}
|
|
5186
|
+
/* c8 ignore stop -- see comment above */
|
|
5166
5187
|
|
|
5167
5188
|
// The synchronous script that created this transaction (and
|
|
5168
5189
|
// synchronously queued whatever requests it wanted to) has now
|
|
@@ -5182,6 +5203,10 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5182
5203
|
let q,
|
|
5183
5204
|
i = -1;
|
|
5184
5205
|
|
|
5206
|
+
// On a standard driver, `keepAliveAndWait` issues a SQL query, which
|
|
5207
|
+
// is a macrotask. Otherwise it issues ten microtasks.
|
|
5208
|
+
const keepAliveAttempts = isStandardDriver ? 1 : 10;
|
|
5209
|
+
|
|
5185
5210
|
/**
|
|
5186
5211
|
* A continuation that must still be able to observe the
|
|
5187
5212
|
* transaction as safe to extend (e.g., re-checking whether an
|
|
@@ -5208,6 +5233,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5208
5233
|
queueMicrotask(cb);
|
|
5209
5234
|
return;
|
|
5210
5235
|
}
|
|
5236
|
+
/* 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. */
|
|
5211
5237
|
try {
|
|
5212
5238
|
tx.executeSql('SELECT 1', [], function () {
|
|
5213
5239
|
cb();
|
|
@@ -5217,10 +5243,11 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5217
5243
|
});
|
|
5218
5244
|
} catch (err) {
|
|
5219
5245
|
// The driver has already finalized the transaction (or otherwise
|
|
5220
|
-
// rejected the call) -- nothing left to hold open
|
|
5221
|
-
//
|
|
5222
|
-
|
|
5246
|
+
// rejected the call) -- nothing left to hold open. We explicitly
|
|
5247
|
+
// abort the transaction here.
|
|
5248
|
+
me.__abortTransaction(/** @type {Error|DOMException} */err);
|
|
5223
5249
|
}
|
|
5250
|
+
/* c8 ignore stop -- see comment above */
|
|
5224
5251
|
}
|
|
5225
5252
|
|
|
5226
5253
|
/**
|
|
@@ -5233,21 +5260,26 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5233
5260
|
* @returns {void}
|
|
5234
5261
|
*/
|
|
5235
5262
|
function success(result, req) {
|
|
5263
|
+
/* 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. */
|
|
5236
5264
|
if (me.__errored || me.__requestsFinished) {
|
|
5237
5265
|
// We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
|
|
5238
5266
|
return;
|
|
5239
5267
|
}
|
|
5268
|
+
/* c8 ignore stop -- see comment above */
|
|
5240
5269
|
if (req) {
|
|
5241
5270
|
q.req = req; // Need to do this in case of cursors
|
|
5242
5271
|
}
|
|
5272
|
+
/* 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. */
|
|
5243
5273
|
if (!q.req) {
|
|
5244
|
-
// TS guard
|
|
5245
5274
|
return;
|
|
5246
5275
|
}
|
|
5276
|
+
/* c8 ignore stop -- see comment above */
|
|
5277
|
+
/* 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. */
|
|
5247
5278
|
if (q.req.__done) {
|
|
5248
5279
|
// Avoid continuing with aborted requests
|
|
5249
5280
|
return;
|
|
5250
5281
|
}
|
|
5282
|
+
/* c8 ignore stop -- see comment above */
|
|
5251
5283
|
q.req.__done = true;
|
|
5252
5284
|
q.req.__result = result;
|
|
5253
5285
|
q.req.__error = null;
|
|
@@ -5264,6 +5296,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5264
5296
|
// is what actually resets `__handlerActive`, once it's
|
|
5265
5297
|
// confirmed (across its own bounded microtask wait) that no
|
|
5266
5298
|
// such continuation queued anything.
|
|
5299
|
+
/* 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. */
|
|
5267
5300
|
if (e.__legacyOutputDidListenersThrowError) {
|
|
5268
5301
|
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
|
|
5269
5302
|
if (!me.__committed) {
|
|
@@ -5273,6 +5306,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5273
5306
|
return;
|
|
5274
5307
|
}
|
|
5275
5308
|
}
|
|
5309
|
+
/* c8 ignore stop -- see comment above */
|
|
5276
5310
|
runContinuationSafely(advanceAfterDispatch);
|
|
5277
5311
|
}
|
|
5278
5312
|
|
|
@@ -5284,15 +5318,19 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5284
5318
|
* @returns {void}
|
|
5285
5319
|
*/
|
|
5286
5320
|
function error(...args /* tx, err */) {
|
|
5321
|
+
/* 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. */
|
|
5287
5322
|
if (me.__errored || me.__requestsFinished) {
|
|
5288
5323
|
// We've already called "onerror", "onabort", or thrown within
|
|
5289
5324
|
// the transaction, so don't do it again.
|
|
5290
5325
|
return;
|
|
5291
5326
|
}
|
|
5327
|
+
/* c8 ignore stop -- see comment above */
|
|
5328
|
+
/* 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. */
|
|
5292
5329
|
if (q.req && q.req.__done) {
|
|
5293
5330
|
// Avoid continuing with aborted requests
|
|
5294
5331
|
return;
|
|
5295
5332
|
}
|
|
5333
|
+
/* c8 ignore stop -- see comment above */
|
|
5296
5334
|
const err = /** @type {Error|DOMException} */findError(args);
|
|
5297
5335
|
if (!q.req) {
|
|
5298
5336
|
me.__abortTransaction(err);
|
|
@@ -5314,10 +5352,11 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5314
5352
|
}
|
|
5315
5353
|
});
|
|
5316
5354
|
q.req.addDefaultEventListener('error', function () {
|
|
5355
|
+
/* 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. */
|
|
5317
5356
|
if (!q.req) {
|
|
5318
|
-
// TS guard
|
|
5319
5357
|
return;
|
|
5320
5358
|
}
|
|
5359
|
+
/* c8 ignore stop -- see comment above */
|
|
5321
5360
|
me.__abortTransaction(q.req.__error);
|
|
5322
5361
|
});
|
|
5323
5362
|
me.__active = true;
|
|
@@ -5329,16 +5368,19 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5329
5368
|
q.req.dispatchEvent(e);
|
|
5330
5369
|
// Do not set __active or __handlerActive flags to false yet --
|
|
5331
5370
|
// see the matching comment in `success`, above.
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5371
|
+
/* 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. */
|
|
5372
|
+
if (!e.__legacyOutputDidListenersThrowError) {
|
|
5373
|
+
return;
|
|
5374
|
+
}
|
|
5375
|
+
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
|
|
5376
|
+
e.preventDefault(); // Prevent 'error' default as steps indicate we should abort with `AbortError` even without cancellation
|
|
5377
|
+
if (me.__committed) {
|
|
5378
|
+
// An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
|
|
5379
|
+
runContinuationSafely(advanceAfterDispatch);
|
|
5380
|
+
return;
|
|
5341
5381
|
}
|
|
5382
|
+
me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after error).'));
|
|
5383
|
+
/* c8 ignore stop -- see comment above */
|
|
5342
5384
|
}
|
|
5343
5385
|
|
|
5344
5386
|
/**
|
|
@@ -5362,10 +5404,12 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5362
5404
|
// (not reset here).
|
|
5363
5405
|
return true;
|
|
5364
5406
|
}
|
|
5407
|
+
/* 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. */
|
|
5365
5408
|
if (q.req.__done) {
|
|
5366
5409
|
// Avoid continuing with aborted requests
|
|
5367
5410
|
return false;
|
|
5368
5411
|
}
|
|
5412
|
+
/* c8 ignore stop -- see comment above */
|
|
5369
5413
|
// We're now handing off to (possibly async) work for
|
|
5370
5414
|
// this request, so the transaction is no longer active
|
|
5371
5415
|
// until its own `success`/`error` dispatch (below)
|
|
@@ -5388,18 +5432,22 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5388
5432
|
return;
|
|
5389
5433
|
}
|
|
5390
5434
|
q.op(tx, q.args, success, error, executeNextRequest);
|
|
5435
|
+
/* 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. */
|
|
5391
5436
|
} catch (e) {
|
|
5392
5437
|
error(/** @type {Error} */e);
|
|
5393
5438
|
}
|
|
5439
|
+
/* c8 ignore stop -- see comment above */
|
|
5394
5440
|
}
|
|
5395
5441
|
|
|
5396
5442
|
/**
|
|
5397
5443
|
* @returns {void}
|
|
5398
5444
|
*/
|
|
5399
5445
|
function runQueuedRequest() {
|
|
5446
|
+
/* c8 ignore start -- Defensive: only reached if `prepareNextRequest` returns `false` (see its own ignore comment above for why that's not reliably reproducible). */
|
|
5400
5447
|
if (!prepareNextRequest()) {
|
|
5401
5448
|
return;
|
|
5402
5449
|
}
|
|
5450
|
+
/* c8 ignore stop -- see comment above */
|
|
5403
5451
|
launchQueuedOp();
|
|
5404
5452
|
}
|
|
5405
5453
|
|
|
@@ -5421,16 +5469,20 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5421
5469
|
* consumer of that same handler (e.g. one that resolves a
|
|
5422
5470
|
* promise from within `onsuccess` and only attaches `oncomplete`
|
|
5423
5471
|
* afterward) ever gets a turn to run, so it can miss `complete`
|
|
5424
|
-
*
|
|
5425
|
-
*
|
|
5426
|
-
*
|
|
5472
|
+
* afterward) ever gets a turn to run, so it can miss `complete`
|
|
5473
|
+
* entirely. On a non-standard driver, `readonly` requests don't hold
|
|
5474
|
+
* a real SQL transaction open, so there's no file-lock/connection
|
|
5475
|
+
* collision risk. On a standard driver, the wait now issues real SQL
|
|
5476
|
+
* inside the read transaction, so this does carry a slight risk.
|
|
5427
5477
|
* @param {number} attemptsLeft
|
|
5428
5478
|
* @returns {void}
|
|
5429
5479
|
*/
|
|
5430
5480
|
function checkQueueEntry(attemptsLeft) {
|
|
5481
|
+
/* 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. */
|
|
5431
5482
|
if (me.__errored || me.__requestsFinished) {
|
|
5432
5483
|
return;
|
|
5433
5484
|
}
|
|
5485
|
+
/* c8 ignore stop -- see comment above */
|
|
5434
5486
|
if (i < me.__requests.length) {
|
|
5435
5487
|
runQueuedRequest();
|
|
5436
5488
|
return;
|
|
@@ -5452,13 +5504,15 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5452
5504
|
* @returns {void}
|
|
5453
5505
|
*/
|
|
5454
5506
|
function executeNextRequest() {
|
|
5507
|
+
/* 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. */
|
|
5455
5508
|
if (me.__errored || me.__requestsFinished) {
|
|
5456
5509
|
// We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
|
|
5457
5510
|
return;
|
|
5458
5511
|
}
|
|
5512
|
+
/* c8 ignore stop -- see comment above */
|
|
5459
5513
|
i++;
|
|
5460
5514
|
if (i >= me.__requests.length) {
|
|
5461
|
-
checkQueueEntry(
|
|
5515
|
+
checkQueueEntry(keepAliveAttempts);
|
|
5462
5516
|
return;
|
|
5463
5517
|
}
|
|
5464
5518
|
runQueuedRequest();
|
|
@@ -5490,31 +5544,34 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5490
5544
|
* @returns {void}
|
|
5491
5545
|
*/
|
|
5492
5546
|
function advanceAfterDispatch() {
|
|
5547
|
+
/* 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. */
|
|
5493
5548
|
if (me.__errored || me.__requestsFinished) {
|
|
5494
5549
|
return;
|
|
5495
5550
|
}
|
|
5551
|
+
/* c8 ignore stop -- see comment above */
|
|
5496
5552
|
i++;
|
|
5497
5553
|
if (i >= me.__requests.length) {
|
|
5498
|
-
checkQueueEntry(
|
|
5554
|
+
checkQueueEntry(keepAliveAttempts);
|
|
5499
5555
|
return;
|
|
5500
5556
|
}
|
|
5501
5557
|
keepAliveAndWait(() => {
|
|
5502
|
-
if (
|
|
5503
|
-
|
|
5504
|
-
}
|
|
5505
|
-
if (!prepareNextRequest()) {
|
|
5558
|
+
/* 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. */
|
|
5559
|
+
if (me.__errored || me.__requestsFinished || !prepareNextRequest()) {
|
|
5506
5560
|
return;
|
|
5507
5561
|
}
|
|
5562
|
+
/* c8 ignore stop -- see comment above */
|
|
5508
5563
|
launchQueuedOp();
|
|
5509
5564
|
});
|
|
5510
5565
|
}
|
|
5511
5566
|
executeNextRequest();
|
|
5512
5567
|
}, function webSQLError(webSQLErr) {
|
|
5568
|
+
/* 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. */
|
|
5513
5569
|
// @ts-expect-error It's ok
|
|
5514
5570
|
if (webSQLErr === true) {
|
|
5515
5571
|
// Not a genuine SQL error
|
|
5516
5572
|
return;
|
|
5517
5573
|
}
|
|
5574
|
+
/* c8 ignore stop -- see comment above */
|
|
5518
5575
|
const err = webSQLErrback(/** @type {Error & {code?: number}} */webSQLErr);
|
|
5519
5576
|
me.__abortTransaction(err);
|
|
5520
5577
|
}, function () {
|
|
@@ -5525,18 +5582,25 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5525
5582
|
// Node
|
|
5526
5583
|
return;
|
|
5527
5584
|
}
|
|
5585
|
+
/* 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. */
|
|
5528
5586
|
if (!me.__transactionEndCallback && !me.__requestsFinished) {
|
|
5529
5587
|
me.__transactionFinished = true;
|
|
5530
5588
|
return;
|
|
5531
5589
|
}
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5590
|
+
/* c8 ignore stop -- see comment above */
|
|
5591
|
+
/* 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. */
|
|
5592
|
+
if (!me.__transactionEndCallback || me.__completed || me.__transFinishedCbFired) {
|
|
5593
|
+
return;
|
|
5535
5594
|
}
|
|
5595
|
+
me.__transFinishedCbFired = true;
|
|
5596
|
+
me.__transFinishedCb(me.__errored, me.__transactionEndCallback);
|
|
5597
|
+
/* c8 ignore stop -- see comment above */
|
|
5536
5598
|
}, function (currentTask, err, done, rollback, commit) {
|
|
5599
|
+
/* 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. */
|
|
5537
5600
|
if (err) {
|
|
5538
5601
|
return true;
|
|
5539
5602
|
}
|
|
5603
|
+
/* c8 ignore stop -- see comment above */
|
|
5540
5604
|
// `readonly` transactions never hold a real SQL transaction open
|
|
5541
5605
|
// (see `WebSQLTransaction`'s constructor skipping `BEGIN;` for
|
|
5542
5606
|
// them), so there's no commit/rollback round trip to defer --
|
|
@@ -5585,6 +5649,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5585
5649
|
*/
|
|
5586
5650
|
function complete() {
|
|
5587
5651
|
me.__completed = true;
|
|
5652
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
5588
5653
|
if (CFG.DEBUG) {
|
|
5589
5654
|
console.log('Transaction completed');
|
|
5590
5655
|
}
|
|
@@ -5594,6 +5659,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5594
5659
|
me.dispatchEvent(evt);
|
|
5595
5660
|
me.__internal = false;
|
|
5596
5661
|
me.dispatchEvent(createEvent('__complete'));
|
|
5662
|
+
/* 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. */
|
|
5597
5663
|
} catch (e) {
|
|
5598
5664
|
me.__internal = false;
|
|
5599
5665
|
// An error occurred in the "oncomplete" handler.
|
|
@@ -5601,6 +5667,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5601
5667
|
// (this may seem odd/bad, but it's how all native IndexedDB implementations work)
|
|
5602
5668
|
me.__errored = true;
|
|
5603
5669
|
throw e;
|
|
5670
|
+
/* c8 ignore stop -- see comment above */
|
|
5604
5671
|
} finally {
|
|
5605
5672
|
activeTransactions.delete(me);
|
|
5606
5673
|
me.__storeHandles = {};
|
|
@@ -5608,10 +5675,12 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5608
5675
|
}
|
|
5609
5676
|
}
|
|
5610
5677
|
if (me.mode === 'readwrite' || me.mode === 'readonly') {
|
|
5678
|
+
/* 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. */
|
|
5611
5679
|
if (me.__transactionFinished) {
|
|
5612
5680
|
complete();
|
|
5613
5681
|
return;
|
|
5614
5682
|
}
|
|
5683
|
+
/* c8 ignore stop -- see comment above */
|
|
5615
5684
|
me.__transactionEndCallback = complete;
|
|
5616
5685
|
// The underlying SQL driver's own "queue empty" check
|
|
5617
5686
|
// (`nonstandardTransCb`, above) typically already ran and
|
|
@@ -5647,6 +5716,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
5647
5716
|
IDBTransaction.prototype.__createRequest = function (source) {
|
|
5648
5717
|
const me = this;
|
|
5649
5718
|
const request = IDBRequest.__createInstance();
|
|
5719
|
+
/* 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. */
|
|
5650
5720
|
request.__source = source !== undefined ? source : me.db;
|
|
5651
5721
|
request.__transaction = me;
|
|
5652
5722
|
return request;
|
|
@@ -5716,9 +5786,11 @@ IDBTransaction.prototype.__pushToQueue = function (request, callback, args) {
|
|
|
5716
5786
|
* @returns {void}
|
|
5717
5787
|
*/
|
|
5718
5788
|
IDBTransaction.prototype.__assertActive = function () {
|
|
5789
|
+
/* 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. */
|
|
5719
5790
|
if (!this.__active || !this.__handlerActive || this.__committed) {
|
|
5720
5791
|
throw createDOMException('TransactionInactiveError', 'A request was placed against a transaction which is currently not active, or which is finished');
|
|
5721
5792
|
}
|
|
5793
|
+
/* c8 ignore stop -- see comment above */
|
|
5722
5794
|
};
|
|
5723
5795
|
|
|
5724
5796
|
/**
|
|
@@ -5732,6 +5804,7 @@ IDBTransaction.prototype.__assertWritable = function () {
|
|
|
5732
5804
|
}
|
|
5733
5805
|
};
|
|
5734
5806
|
|
|
5807
|
+
/* 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. */
|
|
5735
5808
|
/**
|
|
5736
5809
|
* @this {IDBTransactionFull}
|
|
5737
5810
|
* @returns {void}
|
|
@@ -5739,6 +5812,7 @@ IDBTransaction.prototype.__assertWritable = function () {
|
|
|
5739
5812
|
IDBTransaction.prototype.__assertVersionChange = function () {
|
|
5740
5813
|
IDBTransaction.__assertVersionChange(this);
|
|
5741
5814
|
};
|
|
5815
|
+
/* c8 ignore stop -- see comment above */
|
|
5742
5816
|
|
|
5743
5817
|
/**
|
|
5744
5818
|
* Returns the specified object store.
|
|
@@ -5760,9 +5834,12 @@ IDBTransaction.prototype.objectStore = function (objectStoreName) {
|
|
|
5760
5834
|
throw createDOMException('NotFoundError', objectStoreName + ' is not participating in this transaction');
|
|
5761
5835
|
}
|
|
5762
5836
|
const store = me.db.__objectStores[objectStoreName];
|
|
5837
|
+
/* 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. */
|
|
5763
5838
|
if (!store) {
|
|
5764
5839
|
throw createDOMException('NotFoundError', objectStoreName + ' does not exist in ' + me.db.name);
|
|
5765
5840
|
}
|
|
5841
|
+
/* c8 ignore stop -- see comment above */
|
|
5842
|
+
|
|
5766
5843
|
if (!Object.hasOwn(me.__storeHandles, objectStoreName) ||
|
|
5767
5844
|
// These latter conditions are to allow store
|
|
5768
5845
|
// recreation to create new clone object
|
|
@@ -5781,10 +5858,12 @@ IDBTransaction.prototype.objectStore = function (objectStoreName) {
|
|
|
5781
5858
|
IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
5782
5859
|
const me = this;
|
|
5783
5860
|
logError('Error', 'An error occurred in a transaction', err);
|
|
5861
|
+
/* 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. */
|
|
5784
5862
|
if (me.__errored) {
|
|
5785
5863
|
// We've already called "onerror", "onabort", or thrown, so don't do it again.
|
|
5786
5864
|
return;
|
|
5787
5865
|
}
|
|
5866
|
+
/* c8 ignore stop -- see comment above */
|
|
5788
5867
|
me.__errored = true;
|
|
5789
5868
|
if (me.mode === 'versionchange') {
|
|
5790
5869
|
// Steps for aborting an upgrade transaction
|
|
@@ -5814,19 +5893,16 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
5814
5893
|
if (err !== null) {
|
|
5815
5894
|
me.__error = err;
|
|
5816
5895
|
}
|
|
5896
|
+
|
|
5897
|
+
/* 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. */
|
|
5817
5898
|
if (me.__requestsFinished && err !== null) {
|
|
5818
5899
|
// The transaction has already completed, so we can't call "onerror" or "onabort".
|
|
5819
|
-
// So throw the error instead.
|
|
5820
|
-
// `IDBTransaction.prototype.abort`'s own `__abortTransaction(null)`
|
|
5821
|
-
// call, which now checks `__requestsFinished` itself first and
|
|
5822
|
-
// throws `InvalidStateError` synchronously before ever reaching
|
|
5823
|
-
// this point -- so this guard is just defense in depth against
|
|
5824
|
-
// `err` somehow being `null` some other way, not something this
|
|
5825
|
-
// path should see in practice.
|
|
5900
|
+
// So throw the error instead.
|
|
5826
5901
|
setTimeout(() => {
|
|
5827
5902
|
throw err;
|
|
5828
5903
|
}, 0);
|
|
5829
5904
|
}
|
|
5905
|
+
/* c8 ignore stop -- see comment above */
|
|
5830
5906
|
|
|
5831
5907
|
/**
|
|
5832
5908
|
* @param {import('websql-configurable/lib/websql/WebSQLTransaction.js').default|null} [tx]
|
|
@@ -5835,13 +5911,17 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
5835
5911
|
*/
|
|
5836
5912
|
function abort(tx, errOrResult) {
|
|
5837
5913
|
if (!tx) {
|
|
5914
|
+
/* 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. */
|
|
5838
5915
|
if (CFG.DEBUG) {
|
|
5839
5916
|
console.log('Rollback not possible due to missing transaction', me);
|
|
5840
5917
|
}
|
|
5918
|
+
/* 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. */
|
|
5841
5919
|
} else if (errOrResult && 'code' in errOrResult && typeof errOrResult.code === 'number') {
|
|
5842
5920
|
if (CFG.DEBUG) {
|
|
5843
5921
|
console.log('Rollback erred; feature is probably not supported as per WebSQL', me);
|
|
5844
5922
|
}
|
|
5923
|
+
/* c8 ignore stop -- see comment above */
|
|
5924
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
5845
5925
|
} else if (CFG.DEBUG) {
|
|
5846
5926
|
console.log('Rollback succeeded', me);
|
|
5847
5927
|
}
|
|
@@ -5855,10 +5935,11 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
5855
5935
|
// behaves first-in-first-out with the same timeout so we could
|
|
5856
5936
|
// just use a `forEach`.
|
|
5857
5937
|
return promises.then(function () {
|
|
5938
|
+
/* 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. */
|
|
5858
5939
|
if (!q.req) {
|
|
5859
|
-
// TS guard
|
|
5860
5940
|
throw new Error('Missing request');
|
|
5861
5941
|
}
|
|
5942
|
+
/* c8 ignore stop -- see comment above */
|
|
5862
5943
|
q.req.__done = true;
|
|
5863
5944
|
q.req.__result = undefined;
|
|
5864
5945
|
q.req.__error = createDOMException('AbortError', 'A request was aborted (an unfinished request).');
|
|
@@ -5869,10 +5950,11 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
5869
5950
|
return new SyncPromise(/** @type {(resolve: (value?: unknown) => void) => void} */
|
|
5870
5951
|
resolve => {
|
|
5871
5952
|
setTimeout(() => {
|
|
5953
|
+
/* c8 ignore start -- Dead code: same invariant as above -- `q.req` was already confirmed truthy by the outer `.filter()` and is never reset. */
|
|
5872
5954
|
if (!q.req) {
|
|
5873
|
-
// TS guard
|
|
5874
5955
|
throw new Error('Missing request');
|
|
5875
5956
|
}
|
|
5957
|
+
/* c8 ignore stop -- see comment above */
|
|
5876
5958
|
q.req.dispatchEvent(reqEvt); // No need to catch errors
|
|
5877
5959
|
resolve();
|
|
5878
5960
|
}, 0);
|
|
@@ -5892,10 +5974,12 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
5892
5974
|
releaseFinishedTransaction(me);
|
|
5893
5975
|
}, 0);
|
|
5894
5976
|
return undefined;
|
|
5977
|
+
/* 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. */
|
|
5895
5978
|
}).catch(err => {
|
|
5896
5979
|
console.log('Abort error');
|
|
5897
5980
|
throw err;
|
|
5898
5981
|
});
|
|
5982
|
+
/* c8 ignore stop -- see comment above */
|
|
5899
5983
|
}
|
|
5900
5984
|
me.__transFinishedCb(true, function (rollback) {
|
|
5901
5985
|
if (rollback && me.__tx) {
|
|
@@ -5903,20 +5987,24 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
5903
5987
|
// rollback automatically), but for Node.js, etc., we give chance for
|
|
5904
5988
|
// manual aborts which would otherwise not work.
|
|
5905
5989
|
if (me.mode === 'readwrite') {
|
|
5990
|
+
/* 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. */
|
|
5906
5991
|
if (me.__transactionFinished) {
|
|
5907
5992
|
abort();
|
|
5908
5993
|
return;
|
|
5909
5994
|
}
|
|
5995
|
+
/* c8 ignore stop -- see comment above */
|
|
5910
5996
|
me.__transactionEndCallback = abort;
|
|
5911
5997
|
return;
|
|
5912
5998
|
}
|
|
5913
5999
|
try {
|
|
5914
6000
|
me.__tx.executeSql('ROLLBACK', [], abort, /** @type {import('websql-configurable/lib/websql/WebSQLTransaction.js').SqlErrorCallback} */abort); // Not working in some circumstances, even in Node
|
|
6001
|
+
/* c8 ignore start -- Defensive: the underlying WebSQL/SQLite driver throwing synchronously on `ROLLBACK` is not reliably reproducible without mocking the SQL layer. */
|
|
5915
6002
|
} catch (err) {
|
|
5916
6003
|
// Browser errs when transaction has ended and since it most likely already erred here,
|
|
5917
6004
|
// we call to abort
|
|
5918
6005
|
abort();
|
|
5919
6006
|
}
|
|
6007
|
+
/* c8 ignore stop -- see comment above */
|
|
5920
6008
|
} else {
|
|
5921
6009
|
abort(null, {
|
|
5922
6010
|
code: 0
|
|
@@ -5934,6 +6022,7 @@ IDBTransaction.prototype.abort = function () {
|
|
|
5934
6022
|
if (!(me instanceof IDBTransaction)) {
|
|
5935
6023
|
throw new TypeError('Illegal invocation');
|
|
5936
6024
|
}
|
|
6025
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
5937
6026
|
if (CFG.DEBUG) {
|
|
5938
6027
|
console.log('The transaction was aborted', me);
|
|
5939
6028
|
}
|
|
@@ -5965,6 +6054,7 @@ IDBTransaction.prototype.commit = function () {
|
|
|
5965
6054
|
if (!me.__active || !me.__handlerActive || me.__committed) {
|
|
5966
6055
|
throw createDOMException('InvalidStateError', 'Failed to execute \'commit\' on \'IDBTransaction\': The transaction is not active.');
|
|
5967
6056
|
}
|
|
6057
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
5968
6058
|
if (CFG.DEBUG) {
|
|
5969
6059
|
console.log('The transaction was explicitly committed', me);
|
|
5970
6060
|
}
|
|
@@ -6007,6 +6097,7 @@ IDBTransaction.__assertNotFinished = function (tx) {
|
|
|
6007
6097
|
};
|
|
6008
6098
|
|
|
6009
6099
|
// object store methods behave differently: see https://github.com/w3c/IndexedDB/issues/192
|
|
6100
|
+
/* 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. */
|
|
6010
6101
|
/**
|
|
6011
6102
|
*
|
|
6012
6103
|
* @param {IDBTransactionFull} tx
|
|
@@ -6022,6 +6113,7 @@ IDBTransaction.__assertNotFinishedObjectStoreMethod = function (tx) {
|
|
|
6022
6113
|
throw err;
|
|
6023
6114
|
}
|
|
6024
6115
|
};
|
|
6116
|
+
/* c8 ignore stop -- see comment above */
|
|
6025
6117
|
|
|
6026
6118
|
/**
|
|
6027
6119
|
*
|
|
@@ -6946,7 +7038,7 @@ const w = {
|
|
|
6946
7038
|
const t = e.getTime();
|
|
6947
7039
|
return Number.isNaN(t) ? "NaN" : t;
|
|
6948
7040
|
},
|
|
6949
|
-
revive: e => "NaN" === e ?
|
|
7041
|
+
revive: e => new Date("NaN" === e ? NaN : e)
|
|
6950
7042
|
}
|
|
6951
7043
|
},
|
|
6952
7044
|
T = {
|
|
@@ -7634,9 +7726,12 @@ const pe = ye.concat({
|
|
|
7634
7726
|
// we need to override it so it works with our tests
|
|
7635
7727
|
|
|
7636
7728
|
const specSet = fe.flatMap(preset => Array.isArray(preset) ? preset : [preset]).find(preset => preset && !Array.isArray(preset) && 'filelist' in preset);
|
|
7637
|
-
const origFileList = specSet && !Array.isArray(specSet) && 'filelist' in specSet ? specSet.filelist
|
|
7638
|
-
|
|
7639
|
-
const
|
|
7729
|
+
const origFileList = specSet && !Array.isArray(specSet) && 'filelist' in specSet ? specSet.filelist
|
|
7730
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */ : undefined;
|
|
7731
|
+
const origTest = origFileList && typeof origFileList === 'object' && 'test' in origFileList && typeof origFileList.test === 'function' ? origFileList.test
|
|
7732
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.test` ever goes missing */ : undefined;
|
|
7733
|
+
const origRevive = origFileList && typeof origFileList === 'object' && 'revive' in origFileList && typeof origFileList.revive === 'function' ? origFileList.revive
|
|
7734
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.revive` ever goes missing */ : undefined;
|
|
7640
7735
|
const customFileList = origFileList ? {
|
|
7641
7736
|
...origFileList,
|
|
7642
7737
|
/**
|
|
@@ -7645,10 +7740,7 @@ const customFileList = origFileList ? {
|
|
|
7645
7740
|
* @returns {boolean}
|
|
7646
7741
|
*/
|
|
7647
7742
|
test(x, state) {
|
|
7648
|
-
|
|
7649
|
-
return x instanceof FileList;
|
|
7650
|
-
}
|
|
7651
|
-
return typeof origTest === 'function' ? origTest(x, state) : false;
|
|
7743
|
+
return typeof FileList !== 'undefined' ? x instanceof FileList : typeof origTest === 'function' && origTest(x, state);
|
|
7652
7744
|
},
|
|
7653
7745
|
/**
|
|
7654
7746
|
* @param {unknown} x
|
|
@@ -7659,10 +7751,13 @@ const customFileList = origFileList ? {
|
|
|
7659
7751
|
if (typeof FileList !== 'undefined') {
|
|
7660
7752
|
return Reflect.construct(FileList, [x]);
|
|
7661
7753
|
}
|
|
7754
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.revive` ever goes missing */
|
|
7662
7755
|
return typeof origRevive === 'function' ? origRevive(x, state) : undefined;
|
|
7663
7756
|
}
|
|
7664
|
-
}
|
|
7665
|
-
|
|
7757
|
+
}
|
|
7758
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */ : undefined;
|
|
7759
|
+
let typeson = new Typeson().register([fe, /* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */
|
|
7760
|
+
customFileList ? {
|
|
7666
7761
|
filelist: customFileList
|
|
7667
7762
|
} : {}]);
|
|
7668
7763
|
|
|
@@ -7818,7 +7913,6 @@ const IDBIndexAlias = IDBIndex;
|
|
|
7818
7913
|
* __unique: boolean,
|
|
7819
7914
|
* __objectStore: import('./IDBObjectStore.js').IDBObjectStoreFull,
|
|
7820
7915
|
* __keyPath: import('./Key.js').KeyPath,
|
|
7821
|
-
* __recreated?: boolean,
|
|
7822
7916
|
* __fetchIndexData: (
|
|
7823
7917
|
* range: Query,
|
|
7824
7918
|
* opType: "value"|"key"|"count",
|
|
@@ -7916,6 +8010,7 @@ IDBIndex.__createInstance = function (store, indexProperties) {
|
|
|
7916
8010
|
storeHandle.__indexHandles[newName] = oldIndexHandle; // Ensure new reference accessible
|
|
7917
8011
|
me.__pendingName = oldName;
|
|
7918
8012
|
const colInfoToPreserveArr = [['key', 'BLOB ' + (objectStore.autoIncrement ? 'UNIQUE, inc INTEGER PRIMARY KEY AUTOINCREMENT' : 'PRIMARY KEY')], ['value', 'BLOB']].concat(
|
|
8013
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
7919
8014
|
// @ts-ignore Has numeric indexes instead of iterator; needed under some TS versions
|
|
7920
8015
|
[...objectStore.indexNames].filter(indexName => indexName !== newName).map(indexName => [escapeIndexNameForSQL(indexName), 'BLOB']));
|
|
7921
8016
|
me.__renameIndex(objectStore, oldName, newName, colInfoToPreserveArr, function (tx, success) {
|
|
@@ -7963,7 +8058,7 @@ IDBIndex.__clone = function (index, store) {
|
|
|
7963
8058
|
}
|
|
7964
8059
|
});
|
|
7965
8060
|
/** @type {const} */
|
|
7966
|
-
['__pendingCreate', '__pendingDelete', '__deleted', '__originalName'
|
|
8061
|
+
['__pendingCreate', '__pendingDelete', '__deleted', '__originalName'].forEach(p => {
|
|
7967
8062
|
// @ts-expect-error Why is this type "never"?
|
|
7968
8063
|
idx[p] = index[p];
|
|
7969
8064
|
});
|
|
@@ -7997,11 +8092,12 @@ IDBIndex.__createIndex = function (store, index) {
|
|
|
7997
8092
|
} = store;
|
|
7998
8093
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
7999
8094
|
transaction.__addNonRequestToTransactionQueue(function createIndex(tx, args, success, failure) {
|
|
8000
|
-
const columnExists = idx &&
|
|
8095
|
+
const columnExists = idx && idx.__deleted; // This check must occur here rather than earlier as properties may not have been set yet otherwise
|
|
8001
8096
|
|
|
8002
8097
|
/** @type {{[key: string]: boolean}} */
|
|
8003
8098
|
let indexValues = {};
|
|
8004
8099
|
|
|
8100
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8005
8101
|
/**
|
|
8006
8102
|
* @param {WebSQLTransaction} tx
|
|
8007
8103
|
* @param {(Error & {code?: number})} err
|
|
@@ -8010,6 +8106,7 @@ IDBIndex.__createIndex = function (store, index) {
|
|
|
8010
8106
|
function error(tx, err) {
|
|
8011
8107
|
failure(createDOMException('UnknownError', 'Could not create index "' + indexName + '"' + err.code + '::' + err.message, err));
|
|
8012
8108
|
}
|
|
8109
|
+
/* c8 ignore stop -- see comment above */
|
|
8013
8110
|
|
|
8014
8111
|
/**
|
|
8015
8112
|
* @param {WebSQLTransaction} tx
|
|
@@ -8059,12 +8156,6 @@ IDBIndex.__createIndex = function (store, index) {
|
|
|
8059
8156
|
} else {
|
|
8060
8157
|
delete index.__pendingCreate;
|
|
8061
8158
|
delete indexHandle.__pendingCreate;
|
|
8062
|
-
if (index.__deleted) {
|
|
8063
|
-
delete index.__deleted;
|
|
8064
|
-
delete indexHandle.__deleted;
|
|
8065
|
-
index.__recreated = true;
|
|
8066
|
-
indexHandle.__recreated = true;
|
|
8067
|
-
}
|
|
8068
8159
|
indexValues = {};
|
|
8069
8160
|
success(store);
|
|
8070
8161
|
}
|
|
@@ -8073,7 +8164,7 @@ IDBIndex.__createIndex = function (store, index) {
|
|
|
8073
8164
|
}, /** @type {SqlErrorCallback} */error);
|
|
8074
8165
|
}
|
|
8075
8166
|
const escapedStoreNameSQL = escapeStoreNameForSQL(storeName);
|
|
8076
|
-
const escapedIndexNameSQL = escapeIndexNameForSQL(
|
|
8167
|
+
const escapedIndexNameSQL = escapeIndexNameForSQL(indexName);
|
|
8077
8168
|
|
|
8078
8169
|
/**
|
|
8079
8170
|
* @param {WebSQLTransaction} tx
|
|
@@ -8127,6 +8218,7 @@ IDBIndex.__deleteIndex = function (store, index) {
|
|
|
8127
8218
|
} = store;
|
|
8128
8219
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
8129
8220
|
transaction.__addNonRequestToTransactionQueue(function deleteIndex(tx, args, success, failure) {
|
|
8221
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8130
8222
|
/**
|
|
8131
8223
|
* @param {WebSQLTransaction} tx
|
|
8132
8224
|
* @param {(Error & {code?: number})} err
|
|
@@ -8135,6 +8227,7 @@ IDBIndex.__deleteIndex = function (store, index) {
|
|
|
8135
8227
|
function error(tx, err) {
|
|
8136
8228
|
failure(createDOMException('UnknownError', 'Could not delete index "' + index.name + '"', err));
|
|
8137
8229
|
}
|
|
8230
|
+
/* c8 ignore stop -- see comment above */
|
|
8138
8231
|
|
|
8139
8232
|
/**
|
|
8140
8233
|
* @returns {void}
|
|
@@ -8143,7 +8236,6 @@ IDBIndex.__deleteIndex = function (store, index) {
|
|
|
8143
8236
|
// Update the object store's index list
|
|
8144
8237
|
IDBIndex.__updateIndexList(store, tx, function (store) {
|
|
8145
8238
|
delete index.__pendingDelete;
|
|
8146
|
-
delete index.__recreated;
|
|
8147
8239
|
index.__deleted = true;
|
|
8148
8240
|
if (indexHandle) {
|
|
8149
8241
|
indexHandle.__deleted = true;
|
|
@@ -8204,27 +8296,25 @@ IDBIndex.__updateIndexList = function (store, tx, success, failure) {
|
|
|
8204
8296
|
* @param {Query} range
|
|
8205
8297
|
* @param {"value"|"key"|"count"} opType
|
|
8206
8298
|
* @param {boolean} nullDisallowed
|
|
8207
|
-
* @param {number} [count]
|
|
8208
8299
|
* @this {IDBIndexFull}
|
|
8209
8300
|
* @returns {import('./IDBRequest.js').IDBRequestFull}
|
|
8210
8301
|
*/
|
|
8211
|
-
IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed
|
|
8302
|
+
IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed) {
|
|
8212
8303
|
const me = this;
|
|
8213
|
-
if (count !== undefined) {
|
|
8214
|
-
count = enforceRange(count, 'unsigned long');
|
|
8215
|
-
}
|
|
8216
8304
|
IDBIndex.__invalidStateIfDeleted(me);
|
|
8217
8305
|
IDBObjectStore.__invalidStateIfDeleted(me.objectStore);
|
|
8306
|
+
/* c8 ignore start -- Defensive: `IDBObjectStore.__invalidStateIfDeleted` just above already throws when `me.objectStore.__deleted` is true, so this identical check can never be reached. */
|
|
8218
8307
|
if (me.objectStore.__deleted) {
|
|
8219
8308
|
throw createDOMException('InvalidStateError', "This index's object store has been deleted");
|
|
8220
8309
|
}
|
|
8310
|
+
/* c8 ignore stop -- see comment above */
|
|
8221
8311
|
IDBTransaction.__assertActive(me.objectStore.transaction);
|
|
8222
8312
|
if (nullDisallowed && isNullish(range)) {
|
|
8223
8313
|
throw createDOMException('DataError', 'No key or range was specified');
|
|
8224
8314
|
}
|
|
8225
8315
|
const fetchArgs = buildFetchIndexDataSQL(nullDisallowed, me, range, opType, false);
|
|
8226
8316
|
return /** @type {import('./IDBTransaction.js').IDBTransactionFull} */me.objectStore.transaction.__addToTransactionQueue(function (...args) {
|
|
8227
|
-
executeFetchIndexData(
|
|
8317
|
+
executeFetchIndexData(...fetchArgs,
|
|
8228
8318
|
// @ts-expect-error It's ok
|
|
8229
8319
|
...args);
|
|
8230
8320
|
}, undefined, me);
|
|
@@ -8378,13 +8468,16 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
8378
8468
|
const escapedTmpStoreNameSQL = sqlQuote('tmp_' + escapeStoreNameForSQL(storeName).slice(1, -1));
|
|
8379
8469
|
const colNamesToPreserve = colInfoToPreserveArr.map(colInfo => colInfo[0]);
|
|
8380
8470
|
const colInfoToPreserve = colInfoToPreserveArr.map(colInfo => colInfo.join(' '));
|
|
8471
|
+
/* 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. */
|
|
8381
8472
|
const listColInfoToPreserve = colInfoToPreserve.length ? colInfoToPreserve.join(', ') + ', ' : '';
|
|
8473
|
+
/* c8 ignore next -- Defensive: see comment above. */
|
|
8382
8474
|
const listColsToPreserve = colNamesToPreserve.length ? colNamesToPreserve.join(', ') + ', ' : '';
|
|
8383
8475
|
|
|
8384
8476
|
// We could adapt the approach at https://stackoverflow.com/a/8430746/271577
|
|
8385
8477
|
// to make the approach reusable without passing column names, but it is a bit fragile
|
|
8386
8478
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */
|
|
8387
8479
|
store.transaction.__addNonRequestToTransactionQueue(function renameIndex(tx, args, success, error) {
|
|
8480
|
+
/* 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. */
|
|
8388
8481
|
/**
|
|
8389
8482
|
* @param {WebSQLTransaction} tx
|
|
8390
8483
|
* @param {(Error & {code?: number})} err
|
|
@@ -8393,6 +8486,7 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
8393
8486
|
function sqlError(tx, err) {
|
|
8394
8487
|
error(err);
|
|
8395
8488
|
}
|
|
8489
|
+
/* c8 ignore stop -- see comment above */
|
|
8396
8490
|
/**
|
|
8397
8491
|
* @returns {void}
|
|
8398
8492
|
*/
|
|
@@ -8401,8 +8495,14 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
8401
8495
|
cb(tx, success);
|
|
8402
8496
|
return;
|
|
8403
8497
|
}
|
|
8498
|
+
/* 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. */
|
|
8404
8499
|
success();
|
|
8405
8500
|
}
|
|
8501
|
+
/* c8 ignore stop -- see comment above */
|
|
8502
|
+
if (!CFG.useSQLiteIndexes) {
|
|
8503
|
+
finish();
|
|
8504
|
+
return;
|
|
8505
|
+
}
|
|
8406
8506
|
// See https://www.sqlite.org/lang_altertable.html#otheralter
|
|
8407
8507
|
// We don't query for indexes as we already have the info
|
|
8408
8508
|
// This approach has the advantage of auto-deleting indexes via the DROP TABLE
|
|
@@ -8426,10 +8526,6 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
8426
8526
|
console.log(sql);
|
|
8427
8527
|
}
|
|
8428
8528
|
tx.executeSql(sql, [], function (tx) {
|
|
8429
|
-
if (!CFG.useSQLiteIndexes) {
|
|
8430
|
-
finish();
|
|
8431
|
-
return;
|
|
8432
|
-
}
|
|
8433
8529
|
const indexCreations = colNamesToPreserve.slice(2) // Doing `key` separately and no need for index on `value`
|
|
8434
8530
|
.map(escapedIndexNameSQL => new SyncPromise(function (resolve, reject) {
|
|
8435
8531
|
const escapedIndexToRecreate = sqlQuote(escapedStoreNameSQL.slice(1, -1) + '^5' + escapedIndexNameSQL.slice(1, -1));
|
|
@@ -8437,13 +8533,16 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
8437
8533
|
// if (CFG.DEBUG) { console.log(sql); }
|
|
8438
8534
|
// tx.executeSql(sql, [], function () {
|
|
8439
8535
|
const sql = 'CREATE INDEX ' + escapedIndexToRecreate + ' ON ' + escapedStoreNameSQL + '(' + escapedIndexNameSQL + ')';
|
|
8536
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
8440
8537
|
if (CFG.DEBUG) {
|
|
8441
8538
|
console.log(sql);
|
|
8442
8539
|
}
|
|
8443
|
-
tx.executeSql(sql, [], resolve,
|
|
8540
|
+
tx.executeSql(sql, [], resolve, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8541
|
+
/** @type {SqlErrorCallback} */
|
|
8444
8542
|
function (tx, err) {
|
|
8445
8543
|
reject(err);
|
|
8446
|
-
}
|
|
8544
|
+
}
|
|
8545
|
+
/* c8 ignore stop -- see comment above */);
|
|
8447
8546
|
// }, function (tx, err) {
|
|
8448
8547
|
// reject(err);
|
|
8449
8548
|
// });
|
|
@@ -8460,19 +8559,25 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
8460
8559
|
if (CFG.DEBUG) {
|
|
8461
8560
|
console.log(sql);
|
|
8462
8561
|
}
|
|
8463
|
-
tx.executeSql(sql, [], resolve,
|
|
8562
|
+
tx.executeSql(sql, [], resolve, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8563
|
+
/** @type {SqlErrorCallback} */
|
|
8464
8564
|
function (tx, err) {
|
|
8465
8565
|
reject(err);
|
|
8466
|
-
}
|
|
8467
|
-
|
|
8566
|
+
}
|
|
8567
|
+
/* c8 ignore stop -- see comment above */);
|
|
8568
|
+
}, /* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8569
|
+
/** @type {SqlErrorCallback} */
|
|
8468
8570
|
function (tx, err) {
|
|
8469
8571
|
reject(err);
|
|
8470
|
-
}
|
|
8572
|
+
}
|
|
8573
|
+
/* c8 ignore stop -- see comment above */);
|
|
8471
8574
|
}));
|
|
8472
8575
|
SyncPromise.all(indexCreations).then(finish).catch(/** @type {(reason: unknown) => PromiseLike<never>} */
|
|
8473
8576
|
error).catch(err => {
|
|
8577
|
+
/* c8 ignore start -- Defensive: only reached if `finish` or the outer `error` callback itself throws; not reliably reproducible. */
|
|
8474
8578
|
console.log('Index rename error');
|
|
8475
8579
|
throw err;
|
|
8580
|
+
/* c8 ignore stop -- see comment above */
|
|
8476
8581
|
});
|
|
8477
8582
|
}, /** @type {SqlErrorCallback} */sqlError);
|
|
8478
8583
|
}, /** @type {SqlErrorCallback} */sqlError);
|
|
@@ -8499,7 +8604,6 @@ Object.defineProperty(IDBIndex, 'prototype', {
|
|
|
8499
8604
|
/* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
|
|
8500
8605
|
|
|
8501
8606
|
/**
|
|
8502
|
-
* @param {number|null} count
|
|
8503
8607
|
* @param {boolean} unboundedDisallowed
|
|
8504
8608
|
* @param {IDBIndexFull} index
|
|
8505
8609
|
* @param {boolean} hasKey
|
|
@@ -8516,12 +8620,9 @@ Object.defineProperty(IDBIndex, 'prototype', {
|
|
|
8516
8620
|
* @param {(tx: WebSQLTransaction, err: (Error & {code?: number})) => void} error
|
|
8517
8621
|
* @returns {void}
|
|
8518
8622
|
*/
|
|
8519
|
-
function executeFetchIndexData(
|
|
8623
|
+
function executeFetchIndexData(unboundedDisallowed, index, hasKey, range, opType, multiChecks, sql, sqlValues, tx, args, success, error) {
|
|
8520
8624
|
if (unboundedDisallowed) {
|
|
8521
|
-
|
|
8522
|
-
}
|
|
8523
|
-
if (count) {
|
|
8524
|
-
sql.push('LIMIT', String(count));
|
|
8625
|
+
sql.push('LIMIT', '1');
|
|
8525
8626
|
}
|
|
8526
8627
|
const isCount = opType === 'count';
|
|
8527
8628
|
if (CFG.DEBUG) {
|
|
@@ -8583,11 +8684,15 @@ function executeFetchIndexData(count, unboundedDisallowed, index, hasKey, range,
|
|
|
8583
8684
|
record = row;
|
|
8584
8685
|
}
|
|
8585
8686
|
}
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
|
|
8590
|
-
|
|
8687
|
+
/* 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. */
|
|
8688
|
+
if (!record) {
|
|
8689
|
+
continue;
|
|
8690
|
+
}
|
|
8691
|
+
/* c8 ignore stop -- see comment above */
|
|
8692
|
+
|
|
8693
|
+
records.push(decode$2(record));
|
|
8694
|
+
if (unboundedDisallowed) {
|
|
8695
|
+
break;
|
|
8591
8696
|
}
|
|
8592
8697
|
}
|
|
8593
8698
|
} else {
|
|
@@ -8602,8 +8707,16 @@ function executeFetchIndexData(count, unboundedDisallowed, index, hasKey, range,
|
|
|
8602
8707
|
if (isCount) {
|
|
8603
8708
|
success(recordCount);
|
|
8604
8709
|
} else if (recordCount === 0) {
|
|
8710
|
+
// `unboundedDisallowed` is always `true` here: this function is only reached (for
|
|
8711
|
+
// non-`count` `opType`s) via `get`/`getKey`, which always pass `nullDisallowed: true`
|
|
8712
|
+
// through as `unboundedDisallowed`. `getAll`/`getAllKeys`/`getAllRecords` use a
|
|
8713
|
+
// different (cursor-based) code path, so the `unboundedDisallowed`-`false` case
|
|
8714
|
+
// (returning `[]` here) is unreachable given current callers.
|
|
8715
|
+
/* c8 ignore next -- see comment above */
|
|
8605
8716
|
success(unboundedDisallowed ? undefined : []);
|
|
8606
8717
|
} else {
|
|
8718
|
+
// `unboundedDisallowed` is always `true` here; see comment above.
|
|
8719
|
+
/* c8 ignore next -- see comment above */
|
|
8607
8720
|
success(unboundedDisallowed ? records[0] : records);
|
|
8608
8721
|
}
|
|
8609
8722
|
}, /** @type {SqlErrorCallback} */error);
|
|
@@ -8849,6 +8962,7 @@ IDBObjectStore.__createInstance = function (storeProperties, transaction) {
|
|
|
8849
8962
|
tx.executeSql(sql, sqlValues, function (tx) {
|
|
8850
8963
|
// This SQL preserves indexes per https://www.sqlite.org/lang_altertable.html
|
|
8851
8964
|
const sql = 'ALTER TABLE ' + escapeStoreNameForSQL(oldName) + ' RENAME TO ' + escapeStoreNameForSQL(name);
|
|
8965
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG` while renaming a store. */
|
|
8852
8966
|
if (CFG.DEBUG) {
|
|
8853
8967
|
console.log(sql);
|
|
8854
8968
|
}
|
|
@@ -8857,8 +8971,10 @@ IDBObjectStore.__createInstance = function (storeProperties, transaction) {
|
|
|
8857
8971
|
success();
|
|
8858
8972
|
});
|
|
8859
8973
|
}, function (tx, err) {
|
|
8974
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8860
8975
|
error(err);
|
|
8861
8976
|
return false;
|
|
8977
|
+
/* c8 ignore stop -- see comment above */
|
|
8862
8978
|
});
|
|
8863
8979
|
});
|
|
8864
8980
|
}
|
|
@@ -8932,6 +9048,7 @@ IDBObjectStore.__createObjectStore = function (db, store) {
|
|
|
8932
9048
|
storeHandles[storeName] = IDBObjectStore.__clone(store, transaction);
|
|
8933
9049
|
}
|
|
8934
9050
|
transaction.__addNonRequestToTransactionQueue(function createObjectStore(tx, args, success, failure) {
|
|
9051
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
8935
9052
|
/**
|
|
8936
9053
|
* @param {WebSQLTransaction} tx
|
|
8937
9054
|
* @param {(Error & {code?: number})} [err]
|
|
@@ -8944,6 +9061,8 @@ IDBObjectStore.__createObjectStore = function (db, store) {
|
|
|
8944
9061
|
failure(createDOMException('UnknownError', 'Could not create object store "' + storeName + '"', err));
|
|
8945
9062
|
return false;
|
|
8946
9063
|
}
|
|
9064
|
+
/* c8 ignore stop -- see comment above */
|
|
9065
|
+
|
|
8947
9066
|
const escapedStoreNameSQL = escapeStoreNameForSQL(storeName);
|
|
8948
9067
|
// key INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE
|
|
8949
9068
|
const sql = ['CREATE TABLE', escapedStoreNameSQL, '(key BLOB', store.autoIncrement ? 'UNIQUE, inc INTEGER PRIMARY KEY AUTOINCREMENT' : 'PRIMARY KEY', ', value BLOB)'].join(' ');
|
|
@@ -8998,6 +9117,7 @@ IDBObjectStore.__deleteObjectStore = function (db, store) {
|
|
|
8998
9117
|
|
|
8999
9118
|
// Remove the object store from WebSQL
|
|
9000
9119
|
transaction.__addNonRequestToTransactionQueue(function deleteObjectStore(tx, args, success, failure) {
|
|
9120
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9001
9121
|
/**
|
|
9002
9122
|
* @param {WebSQLTransaction} tx
|
|
9003
9123
|
* @param {(Error & {code?: number})} [err]
|
|
@@ -9010,6 +9130,8 @@ IDBObjectStore.__deleteObjectStore = function (db, store) {
|
|
|
9010
9130
|
failure(createDOMException('UnknownError', 'Could not delete ObjectStore', err));
|
|
9011
9131
|
return false;
|
|
9012
9132
|
}
|
|
9133
|
+
/* c8 ignore stop -- see comment above */
|
|
9134
|
+
|
|
9013
9135
|
tx.executeSql('SELECT "name" FROM __sys__ WHERE "name" = ?', [escapeSQLiteStatement(store.__currentName)], function (tx, data) {
|
|
9014
9136
|
if (data.rows.length > 0) {
|
|
9015
9137
|
tx.executeSql('DROP TABLE ' + escapeStoreNameForSQL(store.__currentName), [], function () {
|
|
@@ -9189,13 +9311,15 @@ IDBObjectStore.prototype.__checkIndexConstraints = function (tx, value, excludeK
|
|
|
9189
9311
|
return;
|
|
9190
9312
|
}
|
|
9191
9313
|
const indexKeyValue = indexKey.value;
|
|
9314
|
+
/* 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. */
|
|
9192
9315
|
if (indexKeyValue === undefined) {
|
|
9193
9316
|
resolve(undefined);
|
|
9194
9317
|
return;
|
|
9195
9318
|
}
|
|
9319
|
+
/* c8 ignore stop -- see comment above */
|
|
9196
9320
|
const multiCheck = index.multiEntry && Array.isArray(indexKeyValue);
|
|
9197
9321
|
const fetchArgs = buildFetchIndexDataSQL(true, index, indexKeyValue, 'key', multiCheck);
|
|
9198
|
-
executeFetchIndexData(
|
|
9322
|
+
executeFetchIndexData(...fetchArgs, tx, null, function success(key) {
|
|
9199
9323
|
if (key === undefined || excludeKey !== undefined && cmp(/** @type {import('./Key.js').Key} */key, excludeKey) === 0) {
|
|
9200
9324
|
resolve(undefined);
|
|
9201
9325
|
return;
|
|
@@ -9275,16 +9399,18 @@ IDBObjectStore.prototype.__insertData = function (tx, encoded, value, clonedKeyO
|
|
|
9275
9399
|
* @returns {void}
|
|
9276
9400
|
*/
|
|
9277
9401
|
function setIndexInfo(index) {
|
|
9402
|
+
/* 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. */
|
|
9278
9403
|
if (indexKeyValue === undefined) {
|
|
9279
9404
|
return;
|
|
9280
9405
|
}
|
|
9406
|
+
/* c8 ignore stop -- see comment above */
|
|
9281
9407
|
paramMap[index.__currentName] = /** @type {string} */
|
|
9282
9408
|
encode$1(indexKeyValue, index.multiEntry);
|
|
9283
9409
|
}
|
|
9284
9410
|
if (index.unique) {
|
|
9285
9411
|
const multiCheck = index.multiEntry && Array.isArray(indexKeyValue);
|
|
9286
9412
|
const fetchArgs = buildFetchIndexDataSQL(true, index, indexKeyValue, 'key', multiCheck);
|
|
9287
|
-
executeFetchIndexData(
|
|
9413
|
+
executeFetchIndexData(...fetchArgs, tx, null, function success(key) {
|
|
9288
9414
|
if (key === undefined) {
|
|
9289
9415
|
setIndexInfo(index);
|
|
9290
9416
|
resolve(undefined);
|
|
@@ -9369,6 +9495,7 @@ IDBObjectStore.prototype.add = function (value /* , key */) {
|
|
|
9369
9495
|
me.transaction.__assertWritable();
|
|
9370
9496
|
const request = /** @type {import('./IDBTransaction.js').IDBTransactionFull} */me.transaction.__createRequest(me);
|
|
9371
9497
|
const [ky, clonedValue] = me.__validateKeyAndValueAndCloneValue(value, key, false);
|
|
9498
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
9372
9499
|
// @ts-ignore -- Private API
|
|
9373
9500
|
IDBObjectStore.__storingRecordObjectStore(request, me, true, clonedValue, true, ky);
|
|
9374
9501
|
return request;
|
|
@@ -9397,6 +9524,7 @@ IDBObjectStore.prototype.put = function (value /* , key */) {
|
|
|
9397
9524
|
me.transaction.__assertWritable();
|
|
9398
9525
|
const request = /** @type {import('./IDBTransaction.js').IDBTransactionFull} */me.transaction.__createRequest(me);
|
|
9399
9526
|
const [ky, clonedValue] = me.__validateKeyAndValueAndCloneValue(value, key, false);
|
|
9527
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
9400
9528
|
// @ts-ignore -- Private API
|
|
9401
9529
|
IDBObjectStore.__storingRecordObjectStore(request, me, true, clonedValue, false, ky);
|
|
9402
9530
|
return request;
|
|
@@ -9423,8 +9551,10 @@ IDBObjectStore.prototype.__overwrite = function (tx, key, cb, error) {
|
|
|
9423
9551
|
}
|
|
9424
9552
|
cb(tx);
|
|
9425
9553
|
}, function (tx, err) {
|
|
9554
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9426
9555
|
error(err);
|
|
9427
9556
|
return false;
|
|
9557
|
+
/* c8 ignore stop -- see comment above */
|
|
9428
9558
|
});
|
|
9429
9559
|
};
|
|
9430
9560
|
|
|
@@ -9533,16 +9663,20 @@ IDBObjectStore.prototype.__get = function (query, getKey) {
|
|
|
9533
9663
|
return;
|
|
9534
9664
|
}
|
|
9535
9665
|
ret = getKey ? decode$1(unescapeSQLiteResponse(/** @type {{key: string}} */data.rows.item(0).key), false) : decode(unescapeSQLiteResponse(/** @type {{value: string}} */data.rows.item(0).value));
|
|
9666
|
+
/* 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. */
|
|
9536
9667
|
} catch (e) {
|
|
9537
9668
|
// If no result is returned, or error occurs when parsing JSON
|
|
9538
9669
|
if (CFG.DEBUG) {
|
|
9539
9670
|
console.log(e);
|
|
9540
9671
|
}
|
|
9541
9672
|
}
|
|
9673
|
+
/* c8 ignore stop -- see comment above */
|
|
9542
9674
|
success(ret);
|
|
9543
9675
|
}, function (tx, err) {
|
|
9676
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9544
9677
|
error(err);
|
|
9545
9678
|
return false;
|
|
9679
|
+
/* c8 ignore stop -- see comment above */
|
|
9546
9680
|
});
|
|
9547
9681
|
}, undefined, me);
|
|
9548
9682
|
};
|
|
@@ -9657,8 +9791,10 @@ IDBObjectStore.prototype.delete = function (query) {
|
|
|
9657
9791
|
});
|
|
9658
9792
|
success();
|
|
9659
9793
|
}, function (tx, err) {
|
|
9794
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9660
9795
|
error(err);
|
|
9661
9796
|
return false;
|
|
9797
|
+
/* c8 ignore stop -- see comment above */
|
|
9662
9798
|
});
|
|
9663
9799
|
}, undefined, me);
|
|
9664
9800
|
};
|
|
@@ -9686,8 +9822,10 @@ IDBObjectStore.prototype.clear = function () {
|
|
|
9686
9822
|
});
|
|
9687
9823
|
success();
|
|
9688
9824
|
}, function (tx, err) {
|
|
9825
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
9689
9826
|
error(err);
|
|
9690
9827
|
return false;
|
|
9828
|
+
/* c8 ignore stop -- see comment above */
|
|
9691
9829
|
});
|
|
9692
9830
|
}, undefined, me);
|
|
9693
9831
|
};
|
|
@@ -10017,7 +10155,7 @@ IDBDatabase.prototype.createObjectStore = function (storeName /* , createOptions
|
|
|
10017
10155
|
if (keyPath !== null && !isValidKeyPath(keyPath)) {
|
|
10018
10156
|
throw createDOMException('SyntaxError', 'The keyPath argument contains an invalid key path.');
|
|
10019
10157
|
}
|
|
10020
|
-
if (Object.hasOwn(this.__objectStores, storeName) && !this.__objectStores[storeName].__pendingDelete) {
|
|
10158
|
+
if (Object.hasOwn(this.__objectStores, storeName) && !this.__objectStores[storeName].__pendingDelete && !this.__objectStores[storeName].__deleted) {
|
|
10021
10159
|
throw createDOMException('ConstraintError', 'Object store "' + storeName + '" already exists in ' + this.name);
|
|
10022
10160
|
}
|
|
10023
10161
|
const autoInc = createOptions.autoIncrement;
|
|
@@ -10165,7 +10303,6 @@ IDBDatabase.prototype.throwIfUpgradeTransactionNull = function () {
|
|
|
10165
10303
|
}
|
|
10166
10304
|
};
|
|
10167
10305
|
|
|
10168
|
-
// Todo __forceClose: Add tests for `__forceClose`
|
|
10169
10306
|
/**
|
|
10170
10307
|
*
|
|
10171
10308
|
* @param {string} msg
|
|
@@ -10174,23 +10311,39 @@ IDBDatabase.prototype.throwIfUpgradeTransactionNull = function () {
|
|
|
10174
10311
|
*/
|
|
10175
10312
|
IDBDatabase.prototype.__forceClose = function (msg) {
|
|
10176
10313
|
const me = this;
|
|
10314
|
+
// `close()` (below) resets `me.__transactions` to `[]`, so the
|
|
10315
|
+
// transactions to abort -- and the total count the completion check
|
|
10316
|
+
// below needs -- must be captured before calling it, not read back off
|
|
10317
|
+
// `me.__transactions` afterward.
|
|
10318
|
+
const transactions = me.__transactions;
|
|
10177
10319
|
me.close();
|
|
10320
|
+
|
|
10321
|
+
/**
|
|
10322
|
+
* @returns {void}
|
|
10323
|
+
*/
|
|
10324
|
+
function dispatchClose() {
|
|
10325
|
+
// Todo __forceClose: unblock any pending `upgradeneeded` or `deleteDatabase` calls
|
|
10326
|
+
const evt = createEvent('close');
|
|
10327
|
+
setTimeout(() => {
|
|
10328
|
+
me.dispatchEvent(evt);
|
|
10329
|
+
}, 0);
|
|
10330
|
+
}
|
|
10331
|
+
if (!transactions.length) {
|
|
10332
|
+
dispatchClose();
|
|
10333
|
+
return;
|
|
10334
|
+
}
|
|
10178
10335
|
let ct = 0;
|
|
10179
|
-
|
|
10336
|
+
transactions.forEach(function (trans) {
|
|
10180
10337
|
// eslint-disable-next-line camelcase -- Clear API
|
|
10181
10338
|
trans.on__abort = function () {
|
|
10182
10339
|
ct++;
|
|
10183
|
-
if (ct
|
|
10184
|
-
|
|
10185
|
-
const evt = createEvent('close');
|
|
10186
|
-
setTimeout(() => {
|
|
10187
|
-
me.dispatchEvent(evt);
|
|
10188
|
-
}, 0);
|
|
10340
|
+
if (ct !== transactions.length) {
|
|
10341
|
+
return;
|
|
10189
10342
|
}
|
|
10343
|
+
dispatchClose();
|
|
10190
10344
|
};
|
|
10191
10345
|
trans.__abortTransaction(createDOMException('AbortError', 'The connection was force-closed: ' + (msg || '')));
|
|
10192
10346
|
});
|
|
10193
|
-
me.__transactions = [];
|
|
10194
10347
|
};
|
|
10195
10348
|
/* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
|
|
10196
10349
|
defineOuterInterface(IDBDatabase.prototype, listeners);
|
|
@@ -10351,6 +10504,7 @@ function triggerAnyVersionChangeAndBlockedEvents(openConnections, req, oldVersio
|
|
|
10351
10504
|
return undefined;
|
|
10352
10505
|
}
|
|
10353
10506
|
const e = /** @type {Event & IDBVersionChangeEvent} */
|
|
10507
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
10354
10508
|
// @ts-ignore It's ok; needed under some TS versions
|
|
10355
10509
|
new IDBVersionChangeEvent('versionchange', {
|
|
10356
10510
|
oldVersion,
|
|
@@ -10398,6 +10552,7 @@ function triggerAnyVersionChangeAndBlockedEvents(openConnections, req, oldVersio
|
|
|
10398
10552
|
}
|
|
10399
10553
|
};
|
|
10400
10554
|
const e = /** @type {Event & IDBVersionChangeEvent} */
|
|
10555
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
10401
10556
|
// @ts-ignore It's ok; needed under some TS versions
|
|
10402
10557
|
new IDBVersionChangeEvent('blocked', {
|
|
10403
10558
|
oldVersion,
|
|
@@ -10458,6 +10613,13 @@ const pendingVersionChanges = new Map();
|
|
|
10458
10613
|
|
|
10459
10614
|
/** @type {import('websql-configurable/lib/websql/WebSQLDatabase.js').default} */
|
|
10460
10615
|
let sysdb;
|
|
10616
|
+
// Tracks which `CFG.memoryDatabase` value `sysdb` was opened against, so a
|
|
10617
|
+
// later change to that config (e.g. toggling in-memory mode on and back
|
|
10618
|
+
// off) causes `sysdb` to be recreated for the new setting rather than
|
|
10619
|
+
// staying pinned, forever, to whatever it was the first time any database
|
|
10620
|
+
// was created in the process.
|
|
10621
|
+
/** @type {string|null|undefined} */
|
|
10622
|
+
let sysdbMemoryDatabaseSetting;
|
|
10461
10623
|
let nameCounter = 0;
|
|
10462
10624
|
|
|
10463
10625
|
/**
|
|
@@ -10539,12 +10701,20 @@ function closeCachedWebSQLConnections(name, cb) {
|
|
|
10539
10701
|
function cleanupDatabaseResources(__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError) {
|
|
10540
10702
|
const useMemoryDatabase = typeof CFG.memoryDatabase === 'string';
|
|
10541
10703
|
if (useMemoryDatabase) {
|
|
10704
|
+
/* c8 ignore start -- Defensive: only reachable if `websqlDBCache[name]`
|
|
10705
|
+
was initialized as an empty placeholder by `open()`'s connection-queue
|
|
10706
|
+
setup (`addRequestToConnectionQueue`, above `openDB`) but never
|
|
10707
|
+
populated with an actual instance -- e.g. `__openDatabase` throwing
|
|
10708
|
+
after a `dbVersions` row already existed for `name` from an earlier,
|
|
10709
|
+
successful `open()` -- or if `name` was never added to the cache at
|
|
10710
|
+
all. Not reachable via normal, non-tampered API usage. */
|
|
10542
10711
|
const latestSQLiteDBCached = Object.hasOwn(websqlDBCache, name) ? getLatestCachedWebSQLDB(name) : null;
|
|
10543
10712
|
if (!latestSQLiteDBCached) {
|
|
10544
10713
|
console.warn('Could not find a memory database instance to delete.');
|
|
10545
10714
|
databaseDeleted();
|
|
10546
10715
|
return;
|
|
10547
10716
|
}
|
|
10717
|
+
/* c8 ignore stop -- see comment above */
|
|
10548
10718
|
const sqliteDB = latestSQLiteDBCached._db;
|
|
10549
10719
|
if (!sqliteDB || !sqliteDB.close) {
|
|
10550
10720
|
console.error('The `openDatabase` implementation does not have the expected `._db.close` method for closing the database');
|
|
@@ -10598,15 +10768,24 @@ function cleanupDatabaseResources(__openDatabase, name, escapedDatabaseName, dat
|
|
|
10598
10768
|
tables.item(i).name)), [], function () {
|
|
10599
10769
|
deleteTables(i + 1);
|
|
10600
10770
|
}, function () {
|
|
10771
|
+
/* c8 ignore start -- Defensive: continues deleting the rest
|
|
10772
|
+
even if this specific store's table is already gone (e.g.
|
|
10773
|
+
duplicate `__sys__` rows for the same escaped table name, or
|
|
10774
|
+
external tampering); not reachable via normal API usage. */
|
|
10601
10775
|
deleteTables(i + 1);
|
|
10602
10776
|
return false;
|
|
10777
|
+
/* c8 ignore stop -- see comment above */
|
|
10603
10778
|
});
|
|
10604
10779
|
}
|
|
10605
10780
|
})(0);
|
|
10606
10781
|
}, function () {
|
|
10607
|
-
|
|
10782
|
+
/* c8 ignore start -- `__sys__` is always created by `openDB` before this
|
|
10783
|
+
database's `dbVersions` row (a prerequisite for reaching this code at
|
|
10784
|
+
all) is ever inserted; only reachable if the file was tampered with/
|
|
10785
|
+
removed externally afterward. */
|
|
10608
10786
|
databaseDeleted();
|
|
10609
10787
|
return false;
|
|
10788
|
+
/* c8 ignore stop -- see comment above */
|
|
10610
10789
|
});
|
|
10611
10790
|
});
|
|
10612
10791
|
}
|
|
@@ -10637,9 +10816,11 @@ function createSysDB(__openDatabase, success, failure) {
|
|
|
10637
10816
|
}
|
|
10638
10817
|
failure(er);
|
|
10639
10818
|
}
|
|
10640
|
-
if (sysdb) {
|
|
10819
|
+
if (sysdb && sysdbMemoryDatabaseSetting === CFG.memoryDatabase) {
|
|
10641
10820
|
success();
|
|
10642
10821
|
} else {
|
|
10822
|
+
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Needed
|
|
10823
|
+
sysdbMemoryDatabaseSetting = CFG.memoryDatabase;
|
|
10643
10824
|
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Necessary?
|
|
10644
10825
|
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);
|
|
10645
10826
|
sysdb.transaction(function (systx) {
|
|
@@ -10819,6 +11000,17 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
10819
11000
|
* @returns {void}
|
|
10820
11001
|
*/
|
|
10821
11002
|
let sysdbFinishedCb = function (systx, err, cb) {
|
|
11003
|
+
/* c8 ignore start -- This initial definition is always
|
|
11004
|
+
superseded before ever being invoked: the `sysdb.transaction(...)`
|
|
11005
|
+
call below always reaches its `nonstandardTransCb` (4th arg)
|
|
11006
|
+
after this same SQL batch finishes running (since `dbCreateError`
|
|
11007
|
+
always reports errors as "handled" and this call site is never
|
|
11008
|
+
a `readTransaction`), which unconditionally reassigns
|
|
11009
|
+
`sysdbFinishedCb` to a version using the library's own
|
|
11010
|
+
`rollback`/`commit` -- well before any real invocation from
|
|
11011
|
+
`on__beforecomplete`/`on__preabort`/`on__abort` below (those only
|
|
11012
|
+
fire once the upgrade transaction itself later completes/aborts).
|
|
11013
|
+
Kept as a defensive fallback in case that invariant ever changes. */
|
|
10822
11014
|
if (err) {
|
|
10823
11015
|
/**
|
|
10824
11016
|
* @param {unknown} [errorToShow]
|
|
@@ -10867,6 +11059,7 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
10867
11059
|
}
|
|
10868
11060
|
// In browser, should auto-commit
|
|
10869
11061
|
cb(); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11062
|
+
/* c8 ignore stop -- see comment above */
|
|
10870
11063
|
};
|
|
10871
11064
|
sysdb.transaction(function (systx) {
|
|
10872
11065
|
/**
|
|
@@ -10874,6 +11067,7 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
10874
11067
|
*/
|
|
10875
11068
|
function versionSet() {
|
|
10876
11069
|
const e = /** @type {import('eventtargeter').EventWithProps & Event & IDBVersionChangeEvent} */
|
|
11070
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
10877
11071
|
// @ts-ignore It's ok; needed under some TS versions
|
|
10878
11072
|
new IDBVersionChangeEvent('upgradeneeded', {
|
|
10879
11073
|
oldVersion,
|
|
@@ -10999,9 +11193,17 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
10999
11193
|
// eslint-disable-next-line camelcase -- Clear API
|
|
11000
11194
|
req.transaction.on__complete = function () {
|
|
11001
11195
|
const pos = connection.__transactions.indexOf(req.transaction);
|
|
11196
|
+
// `req.transaction` (the versionchange transaction) is created
|
|
11197
|
+
// directly via `IDBTransaction.__createInstance` above, never
|
|
11198
|
+
// via `IDBDatabase.prototype.transaction()` (the only place
|
|
11199
|
+
// that pushes onto `connection.__transactions`), so `pos` is
|
|
11200
|
+
// always -1 here.
|
|
11201
|
+
/* c8 ignore start -- see comment above */
|
|
11002
11202
|
if (pos !== -1) {
|
|
11003
11203
|
connection.__transactions.splice(pos, 1);
|
|
11004
11204
|
}
|
|
11205
|
+
/* c8 ignore stop -- see comment above */
|
|
11206
|
+
|
|
11005
11207
|
if (/** @type {import('./IDBDatabase.js').IDBDatabaseFull} */req.__result.__closePending) {
|
|
11006
11208
|
req.__transaction = null;
|
|
11007
11209
|
const err = createDOMException('AbortError', 'The connection has been closed.');
|
|
@@ -11037,9 +11239,16 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
11037
11239
|
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [version, sqlSafeName], versionSet, dbCreateError);
|
|
11038
11240
|
}
|
|
11039
11241
|
}, dbCreateError, undefined, function (currentTask, err, done, rollback, commit) {
|
|
11242
|
+
// Defensive fallback, not reachable in practice: same reasoning
|
|
11243
|
+
// as `deleteDatabase`'s own `nonstandardTransCb` below
|
|
11244
|
+
// (`currentTask.readOnly` is always false here, and
|
|
11245
|
+
// `dbCreateError` always returns `false`, so `err` is never
|
|
11246
|
+
// truthy either).
|
|
11247
|
+
/* c8 ignore start -- see comment above */
|
|
11040
11248
|
if (currentTask.readOnly || err) {
|
|
11041
11249
|
return true;
|
|
11042
11250
|
}
|
|
11251
|
+
/* c8 ignore stop -- see comment above */
|
|
11043
11252
|
sysdbFinishedCb = function (systx, err, cb) {
|
|
11044
11253
|
if (err) {
|
|
11045
11254
|
rollback(err,
|
|
@@ -11054,7 +11263,17 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
11054
11263
|
} else {
|
|
11055
11264
|
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [oldVersion, sqlSafeName]);
|
|
11056
11265
|
}
|
|
11057
|
-
},
|
|
11266
|
+
},
|
|
11267
|
+
// Deeply-nested defensive path: only reached if
|
|
11268
|
+
// the *revert* SQL (undoing the `dbVersions`
|
|
11269
|
+
// INSERT/UPDATE after the original version-
|
|
11270
|
+
// upgrade itself already failed) fails a
|
|
11271
|
+
// *second* time. Not feasibly triggerable
|
|
11272
|
+
// without fault-injecting the underlying SQL
|
|
11273
|
+
// driver on this specific, already-failing
|
|
11274
|
+
// revert statement.
|
|
11275
|
+
function (sqlErr) {
|
|
11276
|
+
/* c8 ignore next 2 -- see comment above */
|
|
11058
11277
|
isRevertingSysdb = false;
|
|
11059
11278
|
cb(sqlErr); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11060
11279
|
}, function () {
|
|
@@ -11070,8 +11289,20 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
11070
11289
|
});
|
|
11071
11290
|
return undefined;
|
|
11072
11291
|
}).catch(err => {
|
|
11292
|
+
/* c8 ignore start -- Purely defensive: nothing in
|
|
11293
|
+
`triggerAnyVersionChangeAndBlockedEvents`'s promise chain
|
|
11294
|
+
(or this `.then()` continuation above) ever rejects/throws
|
|
11295
|
+
under any reachable application-level condition -- all of
|
|
11296
|
+
its continuations resolve cleanly, and its `dispatchEvent`
|
|
11297
|
+
calls are deliberately fire-and-forget ("No need to catch
|
|
11298
|
+
errors"), running inside a `setTimeout` where a listener
|
|
11299
|
+
throwing becomes an uncaught exception in that macrotask
|
|
11300
|
+
rather than a promise rejection here. This exists solely
|
|
11301
|
+
to surface a truly-unexpected internal bug via the console
|
|
11302
|
+
before rethrowing, not to handle a real, testable error path. */
|
|
11073
11303
|
console.log('Error within `triggerAnyVersionChangeAndBlockedEvents`');
|
|
11074
11304
|
throw err;
|
|
11305
|
+
/* c8 ignore stop -- see comment above */
|
|
11075
11306
|
});
|
|
11076
11307
|
} else {
|
|
11077
11308
|
finishRequest();
|
|
@@ -11099,11 +11330,19 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
11099
11330
|
if ((useMemoryDatabase || useDatabaseCache) && Object.hasOwn(websqlDBCache, name) && Object.hasOwn(websqlDBCache[name], version)) {
|
|
11100
11331
|
db = websqlDBCache[name][version];
|
|
11101
11332
|
} else {
|
|
11102
|
-
db = /** @type {DatabaseFull} */me.__openDatabase(useMemoryDatabase ? CFG.memoryDatabase : joinPath(CFG.databaseBasePath || '', escapedDatabaseName), '1', name, CFG.DEFAULT_DB_SIZE);
|
|
11333
|
+
db = /** @type {DatabaseFull} */me.__openDatabase(useMemoryDatabase ? (/** @type {string} */CFG.memoryDatabase) : joinPath(CFG.databaseBasePath || '', escapedDatabaseName), '1', name, CFG.DEFAULT_DB_SIZE);
|
|
11103
11334
|
if (useDatabaseCache) {
|
|
11335
|
+
/* c8 ignore start -- Defensive: by the time `openDB` runs,
|
|
11336
|
+
`websqlDBCache[name]` has always already been created by
|
|
11337
|
+
`addRequestToConnectionQueue`'s own callback above (guarded
|
|
11338
|
+
by this same `useDatabaseCache` condition), which always
|
|
11339
|
+
runs first and unconditionally ensures the entry exists
|
|
11340
|
+
before ever calling `openDB`. Kept as a safety net in case
|
|
11341
|
+
that invariant ever changes. */
|
|
11104
11342
|
if (!Object.hasOwn(websqlDBCache, name)) {
|
|
11105
11343
|
websqlDBCache[name] = {};
|
|
11106
11344
|
}
|
|
11345
|
+
/* c8 ignore stop -- see comment above */
|
|
11107
11346
|
websqlDBCache[name][version] = db;
|
|
11108
11347
|
}
|
|
11109
11348
|
}
|
|
@@ -11254,6 +11493,7 @@ IDBFactory.prototype.deleteDatabase = function (name) {
|
|
|
11254
11493
|
req.__result = undefined;
|
|
11255
11494
|
req.__done = true;
|
|
11256
11495
|
const e = /** @type {Event & IDBVersionChangeEvent} */
|
|
11496
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11257
11497
|
// @ts-ignore It's ok; needed under some TS versions
|
|
11258
11498
|
new IDBVersionChangeEvent('success', {
|
|
11259
11499
|
oldVersion: version,
|
|
@@ -11297,9 +11537,23 @@ IDBFactory.prototype.deleteDatabase = function (name) {
|
|
|
11297
11537
|
cleanupDatabaseResources(me.__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError);
|
|
11298
11538
|
}, dbError);
|
|
11299
11539
|
}, dbError, undefined, function (currentTask, err, done, rollback, commit) {
|
|
11540
|
+
/* c8 ignore start -- Defensive fallback, not reachable in
|
|
11541
|
+
practice: `currentTask.readOnly` is always `false` here
|
|
11542
|
+
(this callback is only ever attached to the writable
|
|
11543
|
+
`sysdb.transaction(...)` call above, never to a
|
|
11544
|
+
`sysdb.readTransaction(...)`), and `err` can only be
|
|
11545
|
+
truthy if the `DELETE FROM dbVersions` statement's own
|
|
11546
|
+
error callback (`dbError`) reports the failure back to
|
|
11547
|
+
`websql-configurable` as unhandled -- but `dbError`
|
|
11548
|
+
deliberately always `return`s `false`, which tells the
|
|
11549
|
+
library the error was already handled (and to keep
|
|
11550
|
+
`err` falsy here), precisely so this custom
|
|
11551
|
+
`sysdbFinishedCbDelete` rollback/commit path below is
|
|
11552
|
+
used instead of the library's own default rollback. */
|
|
11300
11553
|
if (currentTask.readOnly || err) {
|
|
11301
11554
|
return true;
|
|
11302
11555
|
}
|
|
11556
|
+
/* c8 ignore stop -- see comment above */
|
|
11303
11557
|
sysdbFinishedCbDelete = function (err, cb) {
|
|
11304
11558
|
if (err) {
|
|
11305
11559
|
rollback(err, cb);
|
|
@@ -11426,10 +11680,9 @@ IDBFactory.prototype.databases = function () {
|
|
|
11426
11680
|
};
|
|
11427
11681
|
|
|
11428
11682
|
/**
|
|
11429
|
-
* @todo forceClose: Test
|
|
11430
11683
|
* This is provided to facilitate unit-testing of the
|
|
11431
11684
|
* closing of a database connection with a forced flag:
|
|
11432
|
-
* <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection
|
|
11685
|
+
* <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection>.
|
|
11433
11686
|
* @param {string} dbName
|
|
11434
11687
|
* @param {Integer} connIdx
|
|
11435
11688
|
* @param {string} msg
|
|
@@ -11529,6 +11782,7 @@ IDBRecord.__createInstance = function (key, primaryKey, value) {
|
|
|
11529
11782
|
* @this {IDBRecordFull}
|
|
11530
11783
|
*/
|
|
11531
11784
|
function IDBRecord() {
|
|
11785
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11532
11786
|
// @ts-ignore Should be ok
|
|
11533
11787
|
this[Symbol.toStringTag] = 'IDBRecord';
|
|
11534
11788
|
this.__key = key;
|
|
@@ -11569,6 +11823,7 @@ readonlyProperties.forEach(prop => {
|
|
|
11569
11823
|
if (!(this instanceof IDBRecordAlias)) {
|
|
11570
11824
|
throw new TypeError('Illegal invocation');
|
|
11571
11825
|
}
|
|
11826
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
11572
11827
|
// @ts-ignore `this` is a real instance past the check above (not an issue in TS7)
|
|
11573
11828
|
return this['__' + prop];
|
|
11574
11829
|
}
|
|
@@ -11912,6 +12167,7 @@ IDBCursor.prototype.__findBasic = function (key, primaryKey, tx, success, error,
|
|
|
11912
12167
|
success(undefined, undefined, undefined);
|
|
11913
12168
|
}
|
|
11914
12169
|
}, function (tx, err) {
|
|
12170
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
11915
12171
|
if (CFG.DEBUG) {
|
|
11916
12172
|
console.log('Could not execute Cursor.continue', sqlStr, sqlValues);
|
|
11917
12173
|
}
|
|
@@ -12087,7 +12343,16 @@ IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, e
|
|
|
12087
12343
|
if (a.key > b.key) {
|
|
12088
12344
|
return me.direction === 'prev' ? -1 : 1;
|
|
12089
12345
|
}
|
|
12346
|
+
/* c8 ignore start -- Defensive: only reachable if two matches
|
|
12347
|
+
in the same batch shared both the same `matchingKey` and
|
|
12348
|
+
the same primary `key`, which would require the same
|
|
12349
|
+
record's multi-entry array to contain a duplicate value.
|
|
12350
|
+
`Key.js`'s array-to-key conversion already drops duplicate
|
|
12351
|
+
values when a multi-entry index entry is built, so this
|
|
12352
|
+
can never happen in practice; kept only to satisfy the
|
|
12353
|
+
`Array.prototype.sort` comparator contract. */
|
|
12090
12354
|
return 0;
|
|
12355
|
+
/* c8 ignore stop -- see comment above */
|
|
12091
12356
|
});
|
|
12092
12357
|
me.__prefetchedIndex = 0;
|
|
12093
12358
|
me.__prefetchedData = {
|
|
@@ -12106,13 +12371,19 @@ IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, e
|
|
|
12106
12371
|
console.log('[multiEntry] Preloaded ' + me.__prefetchedData.length + ' records for multiEntry cursor');
|
|
12107
12372
|
}
|
|
12108
12373
|
me.__decode(rows[0], success);
|
|
12109
|
-
},
|
|
12374
|
+
},
|
|
12375
|
+
/* c8 ignore start -- Defensive: guards against an unexpected SQLite
|
|
12376
|
+
execution error (e.g. I/O error, corruption) while querying for
|
|
12377
|
+
multi-entry cursor matches; not reliably reproducible without
|
|
12378
|
+
mocking the SQL layer. */
|
|
12379
|
+
function (tx, err) {
|
|
12110
12380
|
if (CFG.DEBUG) {
|
|
12111
12381
|
console.log('[multiEntry] Could not execute Cursor.continue', sqlStr, sqlValues);
|
|
12112
12382
|
}
|
|
12113
12383
|
error(err);
|
|
12114
12384
|
return false;
|
|
12115
12385
|
});
|
|
12386
|
+
/* c8 ignore stop -- see comment above */
|
|
12116
12387
|
}
|
|
12117
12388
|
runQuery();
|
|
12118
12389
|
};
|
|
@@ -12221,6 +12492,7 @@ IDBCursor.prototype.__sourceOrEffectiveObjStoreDeleted = function () {
|
|
|
12221
12492
|
* @returns {void}
|
|
12222
12493
|
*/
|
|
12223
12494
|
IDBCursor.prototype.__invalidateCache = function () {
|
|
12495
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
12224
12496
|
// @ts-ignore Why is this not being found?; needed under some TS versions
|
|
12225
12497
|
this.__prefetchedData = null;
|
|
12226
12498
|
this.__multiEntryExhausted = false;
|
|
@@ -12245,7 +12517,7 @@ IDBCursor.prototype.__continue = function (key, advanceContinue) {
|
|
|
12245
12517
|
convertValueToKeyRethrowingAndIfInvalid(key);
|
|
12246
12518
|
const cmpResult = cmp(key, me.key);
|
|
12247
12519
|
if (cmpResult === 0 || me.direction.includes('next') && cmpResult === -1 || me.direction.includes('prev') && cmpResult === 1) {
|
|
12248
|
-
throw createDOMException('DataError', 'Cannot
|
|
12520
|
+
throw createDOMException('DataError', 'Cannot continue the cursor in an unexpected direction');
|
|
12249
12521
|
}
|
|
12250
12522
|
}
|
|
12251
12523
|
this.__continueFinish(key, undefined, advanceState);
|
|
@@ -12494,6 +12766,7 @@ IDBCursor.prototype.update = function (valueToUpdate) {
|
|
|
12494
12766
|
// continuation logic in `__findBasic` to see this update's
|
|
12495
12767
|
// effect on ordering (see "Modify records during cursor
|
|
12496
12768
|
// iteration" in idbcursor_update_index.any.js).
|
|
12769
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
12497
12770
|
// @ts-ignore -- API (not erring in TS 6)
|
|
12498
12771
|
IDBObjectStore.__storingRecordObjectStore(request, me.__store, true, clonedValue, false, key);
|
|
12499
12772
|
}
|
|
@@ -12540,14 +12813,33 @@ IDBCursor.prototype.delete = function () {
|
|
|
12540
12813
|
// We don't invalidate the cache (as we don't access it anymore
|
|
12541
12814
|
// and it will set the index off)
|
|
12542
12815
|
success(undefined);
|
|
12816
|
+
/* c8 ignore start -- Defensive: `__find` (invoked just above) has
|
|
12817
|
+
already confirmed a row exists for this primary key within the
|
|
12818
|
+
same transaction queue, so `rowsAffected` should always be 1 in
|
|
12819
|
+
normal usage. This branch would only be reached if the underlying
|
|
12820
|
+
row were removed by another request queued in the same
|
|
12821
|
+
transaction between `__find`'s check and this DELETE actually
|
|
12822
|
+
running (e.g. deleting the same record directly via the object
|
|
12823
|
+
store while a cursor over it is mid-iteration); attempts to
|
|
12824
|
+
construct such a scenario instead trigger a transaction abort
|
|
12825
|
+
(`AbortError`) before this callback ever runs, since the default
|
|
12826
|
+
action of an unhandled request error is to abort the
|
|
12827
|
+
transaction. */
|
|
12543
12828
|
} else {
|
|
12544
12829
|
// @ts-expect-error Apparently ok
|
|
12545
12830
|
error('No rows with key found' + key);
|
|
12546
12831
|
}
|
|
12547
|
-
|
|
12832
|
+
/* c8 ignore stop -- see comment above */
|
|
12833
|
+
},
|
|
12834
|
+
/* c8 ignore start -- Defensive: guards against an unexpected SQLite
|
|
12835
|
+
execution error (e.g. I/O error, corruption) while deleting the
|
|
12836
|
+
current row; not reliably reproducible without mocking the SQL
|
|
12837
|
+
layer. */
|
|
12838
|
+
function (tx, data) {
|
|
12548
12839
|
error(data);
|
|
12549
12840
|
return false;
|
|
12550
12841
|
});
|
|
12842
|
+
/* c8 ignore stop -- see comment above */
|
|
12551
12843
|
}, error);
|
|
12552
12844
|
}, undefined, me);
|
|
12553
12845
|
};
|
|
@@ -12953,7 +13245,7 @@ function setGlobalVars(idb, initialConfig) {
|
|
|
12953
13245
|
setConfig(initialConfig);
|
|
12954
13246
|
}
|
|
12955
13247
|
const IDB = /** @type {ShimmedObject & {[key: string]: unknown}} */
|
|
12956
|
-
/** @type {unknown} */idb || globalThis
|
|
13248
|
+
/** @type {unknown} */idb || globalThis;
|
|
12957
13249
|
/**
|
|
12958
13250
|
* @param {string} name
|
|
12959
13251
|
* @param {unknown} value
|
|
@@ -13048,77 +13340,84 @@ function setGlobalVars(idb, initialConfig) {
|
|
|
13048
13340
|
});
|
|
13049
13341
|
}
|
|
13050
13342
|
const shimIDBFactory = IDBFactory;
|
|
13051
|
-
if (CFG.win.openDatabase
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13058
|
-
|
|
13059
|
-
|
|
13060
|
-
|
|
13061
|
-
|
|
13062
|
-
|
|
13343
|
+
if (CFG.win.openDatabase === undefined) {
|
|
13344
|
+
return;
|
|
13345
|
+
}
|
|
13346
|
+
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
|
|
13347
|
+
// Polyfill ALL of IndexedDB, using WebSQL
|
|
13348
|
+
shim('indexedDB', shimIndexedDB, {
|
|
13349
|
+
enumerable: true,
|
|
13350
|
+
configurable: true,
|
|
13351
|
+
get() {
|
|
13352
|
+
if (this !== IDB && !isNullish(this) && !this.shimNS) {
|
|
13353
|
+
// Latter is hack for test environment
|
|
13354
|
+
throw new TypeError('Illegal invocation');
|
|
13063
13355
|
}
|
|
13064
|
-
|
|
13065
|
-
/** @type {[string, unknown][]} */
|
|
13066
|
-
[['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]) => {
|
|
13067
|
-
shim(prop, obj, {
|
|
13068
|
-
enumerable: false,
|
|
13069
|
-
configurable: true
|
|
13070
|
-
});
|
|
13071
|
-
});
|
|
13072
|
-
// For Node environments
|
|
13073
|
-
if (CFG.fs) {
|
|
13074
|
-
setFS(CFG.fs);
|
|
13356
|
+
return shimIndexedDB;
|
|
13075
13357
|
}
|
|
13076
|
-
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
|
|
13080
|
-
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
|
|
13086
|
-
|
|
13087
|
-
|
|
13088
|
-
|
|
13089
|
-
|
|
13090
|
-
|
|
13091
|
-
|
|
13092
|
-
|
|
13093
|
-
|
|
13094
|
-
|
|
13095
|
-
|
|
13096
|
-
|
|
13097
|
-
|
|
13098
|
-
|
|
13099
|
-
|
|
13100
|
-
|
|
13101
|
-
|
|
13102
|
-
|
|
13358
|
+
});
|
|
13359
|
+
/** @type {[string, unknown][]} */
|
|
13360
|
+
[['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]) => {
|
|
13361
|
+
shim(prop, obj, {
|
|
13362
|
+
enumerable: false,
|
|
13363
|
+
configurable: true
|
|
13364
|
+
});
|
|
13365
|
+
});
|
|
13366
|
+
// For Node environments
|
|
13367
|
+
if (CFG.fs) {
|
|
13368
|
+
setFS(CFG.fs);
|
|
13369
|
+
}
|
|
13370
|
+
if (CFG.fullIDLSupport) {
|
|
13371
|
+
// Slow per MDN so off by default! Though apparently needed for WebIDL: https://stackoverflow.com/questions/41927589/rationales-consequences-of-webidl-class-inheritance-requirements
|
|
13372
|
+
|
|
13373
|
+
Object.setPrototypeOf(IDB.IDBOpenDBRequest, IDB.IDBRequest);
|
|
13374
|
+
Object.setPrototypeOf(IDB.IDBCursorWithValue, IDB.IDBCursor);
|
|
13375
|
+
Object.setPrototypeOf(IDBDatabase, EventTarget);
|
|
13376
|
+
Object.setPrototypeOf(IDBRequest, EventTarget);
|
|
13377
|
+
Object.setPrototypeOf(IDBTransaction, EventTarget);
|
|
13378
|
+
Object.setPrototypeOf(IDBVersionChangeEvent, ShimEvent);
|
|
13379
|
+
// `ShimDOMException` is the real native `DOMException` when one
|
|
13380
|
+
// is available (see `DOMException.js`'s `useNativeDOMException`)
|
|
13381
|
+
// -- which, unlike the shim classes above, is a single,
|
|
13382
|
+
// process-wide singleton shared by reference across every
|
|
13383
|
+
// sandbox this library gets installed into (see
|
|
13384
|
+
// `node-idb-test.js`'s `sandboxObj`). A native `DOMException`
|
|
13385
|
+
// already has the correct prototype chain out of the box
|
|
13386
|
+
// (`Object.getPrototypeOf(DOMException) === Function.prototype`,
|
|
13387
|
+
// not `Error`), so forcing it here isn't just unneeded but
|
|
13388
|
+
// actively wrong -- and, because it's shared, permanently
|
|
13389
|
+
// wrong for every later use of `DOMException` in the same
|
|
13390
|
+
// process (e.g. a later WPT test file's own idlharness-style
|
|
13391
|
+
// check that `DOMException` does *not* inherit from `Error`
|
|
13392
|
+
// on the class side), not just this one shim install.
|
|
13393
|
+
if (typeof DOMException === 'undefined' || ShimDOMException !== DOMException) {
|
|
13394
|
+
Object.setPrototypeOf(ShimDOMException, Error);
|
|
13395
|
+
Object.setPrototypeOf(ShimDOMException.prototype, Error.prototype);
|
|
13103
13396
|
}
|
|
13104
|
-
|
|
13105
|
-
|
|
13106
|
-
|
|
13107
|
-
|
|
13108
|
-
|
|
13109
|
-
|
|
13110
|
-
|
|
13111
|
-
if (CFG.replaceNonIDBGlobals) {
|
|
13112
|
-
setNonIDBGlobals();
|
|
13113
|
-
}
|
|
13397
|
+
}
|
|
13398
|
+
if (IDB.indexedDB && !IDB.indexedDB.toString().includes('[native code]')) {
|
|
13399
|
+
if (CFG.addNonIDBGlobals) {
|
|
13400
|
+
// As `DOMStringList` exists per IDL (and Chrome) in the global
|
|
13401
|
+
// thread (but not in workers), we prefix the name to avoid
|
|
13402
|
+
// shadowing or conflicts
|
|
13403
|
+
setNonIDBGlobals('Shim');
|
|
13114
13404
|
}
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
return;
|
|
13405
|
+
if (CFG.replaceNonIDBGlobals) {
|
|
13406
|
+
setNonIDBGlobals();
|
|
13118
13407
|
}
|
|
13119
|
-
/* c8 ignore stop -- TS guard */
|
|
13120
|
-
IDB.shimIndexedDB.__setConnectionQueueOrigin();
|
|
13121
13408
|
}
|
|
13409
|
+
/* c8 ignore start -- Defensive: `IDB.shimIndexedDB` was already
|
|
13410
|
+
confirmed truthy just before this function (`__useShim`) was
|
|
13411
|
+
defined and immediately invoked (see the `if ('shimIndexedDB'
|
|
13412
|
+
in IDB && IDB.shimIndexedDB)` guard above), and nothing in
|
|
13413
|
+
this function's body reassigns or deletes it. Only reachable
|
|
13414
|
+
if `IDB` is some unusual object (e.g. a Proxy) whose
|
|
13415
|
+
`shimIndexedDB` property value changes between reads. */
|
|
13416
|
+
if (!IDB.shimIndexedDB) {
|
|
13417
|
+
return;
|
|
13418
|
+
}
|
|
13419
|
+
/* c8 ignore stop -- see comment above */
|
|
13420
|
+
IDB.shimIndexedDB.__setConnectionQueueOrigin();
|
|
13122
13421
|
};
|
|
13123
13422
|
IDB.shimIndexedDB.__debug = /** @type {(val: boolean) => void} */function (val) {
|
|
13124
13423
|
CFG.DEBUG = val;
|
|
@@ -13226,6 +13525,7 @@ function setGlobalVars(idb, initialConfig) {
|
|
|
13226
13525
|
* @returns {SQLiteDatabaseInstance}
|
|
13227
13526
|
*/
|
|
13228
13527
|
function wrappedSQLiteDatabase(name) {
|
|
13528
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
13229
13529
|
// @ts-ignore It's ok; needed under some TS versions
|
|
13230
13530
|
const db = new SQLiteDatabase(name, {});
|
|
13231
13531
|
if (CFG.sqlBusyTimeout) {
|