indexeddbshim 19.0.5 → 19.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/badges/coverage-badge.svg +1 -1
- package/badges/tests-badge.svg +1 -1
- package/dist/CFG.d.ts +1 -1
- package/dist/CFG.d.ts.map +1 -1
- package/dist/DOMException.d.ts.map +1 -1
- package/dist/IDBCursor.d.ts.map +1 -1
- package/dist/IDBDatabase.d.ts.map +1 -1
- package/dist/IDBFactory.d.ts +1 -2
- package/dist/IDBFactory.d.ts.map +1 -1
- package/dist/IDBIndex.d.ts +2 -6
- package/dist/IDBIndex.d.ts.map +1 -1
- package/dist/IDBKeyRange.d.ts.map +1 -1
- package/dist/IDBObjectStore.d.ts.map +1 -1
- package/dist/IDBRecord.d.ts.map +1 -1
- package/dist/IDBRequest.d.ts.map +1 -1
- package/dist/IDBTransaction.d.ts.map +1 -1
- package/dist/Key.d.ts.map +1 -1
- package/dist/Sca.d.ts.map +1 -1
- package/dist/indexeddbshim-Key.js +40 -28
- package/dist/indexeddbshim-Key.js.map +1 -1
- package/dist/indexeddbshim-Key.min.js +2 -2
- package/dist/indexeddbshim-Key.min.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs +511 -217
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.js +539 -244
- package/dist/indexeddbshim-UnicodeIdentifiers.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js +3 -3
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js.map +1 -1
- package/dist/indexeddbshim-node.cjs +511 -217
- package/dist/indexeddbshim-node.cjs.map +1 -1
- package/dist/indexeddbshim-noninvasive.js +539 -244
- package/dist/indexeddbshim-noninvasive.js.map +1 -1
- package/dist/indexeddbshim-noninvasive.min.js +3 -3
- package/dist/indexeddbshim-noninvasive.min.js.map +1 -1
- package/dist/indexeddbshim.js +539 -244
- package/dist/indexeddbshim.js.map +1 -1
- package/dist/indexeddbshim.min.js +3 -3
- package/dist/indexeddbshim.min.js.map +1 -1
- package/dist/nodeWebSQL.d.ts.map +1 -1
- package/dist/setGlobalVars.d.ts +1 -1
- package/dist/setGlobalVars.d.ts.map +1 -1
- package/dist/util.d.ts.map +1 -1
- package/package.json +22 -17
- package/src/CFG.js +18 -4
- package/src/DOMException.js +6 -0
- package/src/DOMStringList.js +3 -0
- package/src/IDBCursor.js +36 -3
- package/src/IDBDatabase.js +26 -10
- package/src/IDBFactory.js +105 -5
- package/src/IDBIndex.js +49 -32
- package/src/IDBKeyRange.js +8 -7
- package/src/IDBObjectStore.js +25 -2
- package/src/IDBRecord.js +2 -0
- package/src/IDBRequest.js +7 -4
- package/src/IDBTransaction.js +97 -26
- package/src/Key.js +17 -16
- package/src/Sca.js +9 -4
- package/src/nodeWebSQL.js +1 -0
- package/src/setGlobalVars.js +86 -77
- package/src/util.js +5 -6
package/src/IDBTransaction.js
CHANGED
|
@@ -273,10 +273,12 @@ IDBTransaction.prototype.__callTransFinishedCb = function (err, cb) {
|
|
|
273
273
|
*/
|
|
274
274
|
IDBTransaction.prototype.__executeRequests = function () {
|
|
275
275
|
const me = this;
|
|
276
|
+
/* 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. */
|
|
276
277
|
if (me.__running) {
|
|
277
278
|
if (CFG.DEBUG) { console.log('Looks like the request set is already running', me.mode); }
|
|
278
279
|
return;
|
|
279
280
|
}
|
|
281
|
+
/* c8 ignore stop -- see comment above */
|
|
280
282
|
|
|
281
283
|
// The synchronous script that created this transaction (and
|
|
282
284
|
// synchronously queued whatever requests it wanted to) has now
|
|
@@ -327,6 +329,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
327
329
|
queueMicrotask(cb);
|
|
328
330
|
return;
|
|
329
331
|
}
|
|
332
|
+
/* 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. */
|
|
330
333
|
try {
|
|
331
334
|
tx.executeSql('SELECT 1', [], function () {
|
|
332
335
|
cb();
|
|
@@ -340,6 +343,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
340
343
|
// abort the transaction here.
|
|
341
344
|
me.__abortTransaction(/** @type {Error|DOMException} */ (err));
|
|
342
345
|
}
|
|
346
|
+
/* c8 ignore stop -- see comment above */
|
|
343
347
|
}
|
|
344
348
|
|
|
345
349
|
/**
|
|
@@ -352,19 +356,25 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
352
356
|
* @returns {void}
|
|
353
357
|
*/
|
|
354
358
|
function success (result, req) {
|
|
359
|
+
/* 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. */
|
|
355
360
|
if (me.__errored || me.__requestsFinished) {
|
|
356
361
|
// We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
|
|
357
362
|
return;
|
|
358
363
|
}
|
|
364
|
+
/* c8 ignore stop -- see comment above */
|
|
359
365
|
if (req) {
|
|
360
366
|
q.req = req; // Need to do this in case of cursors
|
|
361
367
|
}
|
|
362
|
-
|
|
368
|
+
/* 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. */
|
|
369
|
+
if (!q.req) {
|
|
363
370
|
return;
|
|
364
371
|
}
|
|
372
|
+
/* c8 ignore stop -- see comment above */
|
|
373
|
+
/* 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. */
|
|
365
374
|
if (q.req.__done) { // Avoid continuing with aborted requests
|
|
366
375
|
return;
|
|
367
376
|
}
|
|
377
|
+
/* c8 ignore stop -- see comment above */
|
|
368
378
|
q.req.__done = true;
|
|
369
379
|
q.req.__result = result;
|
|
370
380
|
q.req.__error = null;
|
|
@@ -382,6 +392,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
382
392
|
// is what actually resets `__handlerActive`, once it's
|
|
383
393
|
// confirmed (across its own bounded microtask wait) that no
|
|
384
394
|
// such continuation queued anything.
|
|
395
|
+
/* 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. */
|
|
385
396
|
if (e.__legacyOutputDidListenersThrowError) {
|
|
386
397
|
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
|
|
387
398
|
if (!me.__committed) { // An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
|
|
@@ -390,6 +401,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
390
401
|
return;
|
|
391
402
|
}
|
|
392
403
|
}
|
|
404
|
+
/* c8 ignore stop -- see comment above */
|
|
393
405
|
util.runContinuationSafely(advanceAfterDispatch);
|
|
394
406
|
}
|
|
395
407
|
|
|
@@ -401,14 +413,18 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
401
413
|
* @returns {void}
|
|
402
414
|
*/
|
|
403
415
|
function error (...args /* tx, err */) {
|
|
416
|
+
/* 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. */
|
|
404
417
|
if (me.__errored || me.__requestsFinished) {
|
|
405
418
|
// We've already called "onerror", "onabort", or thrown within
|
|
406
419
|
// the transaction, so don't do it again.
|
|
407
420
|
return;
|
|
408
421
|
}
|
|
422
|
+
/* c8 ignore stop -- see comment above */
|
|
423
|
+
/* 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. */
|
|
409
424
|
if (q.req && q.req.__done) { // Avoid continuing with aborted requests
|
|
410
425
|
return;
|
|
411
426
|
}
|
|
427
|
+
/* c8 ignore stop -- see comment above */
|
|
412
428
|
const err = /** @type {Error|DOMException} */ (findError(args));
|
|
413
429
|
if (!q.req) {
|
|
414
430
|
me.__abortTransaction(err);
|
|
@@ -432,9 +448,11 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
432
448
|
}
|
|
433
449
|
);
|
|
434
450
|
q.req.addDefaultEventListener('error', function () {
|
|
435
|
-
|
|
451
|
+
/* 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. */
|
|
452
|
+
if (!q.req) {
|
|
436
453
|
return;
|
|
437
454
|
}
|
|
455
|
+
/* c8 ignore stop -- see comment above */
|
|
438
456
|
me.__abortTransaction(q.req.__error);
|
|
439
457
|
});
|
|
440
458
|
|
|
@@ -444,15 +462,19 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
444
462
|
q.req.dispatchEvent(e);
|
|
445
463
|
// Do not set __active or __handlerActive flags to false yet --
|
|
446
464
|
// see the matching comment in `success`, above.
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
465
|
+
/* 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. */
|
|
466
|
+
if (!e.__legacyOutputDidListenersThrowError) {
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
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
|
|
471
|
+
e.preventDefault(); // Prevent 'error' default as steps indicate we should abort with `AbortError` even without cancellation
|
|
472
|
+
if (me.__committed) { // An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
|
|
473
|
+
util.runContinuationSafely(advanceAfterDispatch);
|
|
474
|
+
return;
|
|
455
475
|
}
|
|
476
|
+
me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after error).'));
|
|
477
|
+
/* c8 ignore stop -- see comment above */
|
|
456
478
|
}
|
|
457
479
|
|
|
458
480
|
/**
|
|
@@ -476,9 +498,11 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
476
498
|
// (not reset here).
|
|
477
499
|
return true;
|
|
478
500
|
}
|
|
501
|
+
/* 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. */
|
|
479
502
|
if (q.req.__done) { // Avoid continuing with aborted requests
|
|
480
503
|
return false;
|
|
481
504
|
}
|
|
505
|
+
/* c8 ignore stop -- see comment above */
|
|
482
506
|
// We're now handing off to (possibly async) work for
|
|
483
507
|
// this request, so the transaction is no longer active
|
|
484
508
|
// until its own `success`/`error` dispatch (below)
|
|
@@ -501,18 +525,22 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
501
525
|
return;
|
|
502
526
|
}
|
|
503
527
|
q.op(tx, q.args, success, error, executeNextRequest);
|
|
528
|
+
/* 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. */
|
|
504
529
|
} catch (e) {
|
|
505
530
|
error(/** @type {Error} */ (e));
|
|
506
531
|
}
|
|
532
|
+
/* c8 ignore stop -- see comment above */
|
|
507
533
|
}
|
|
508
534
|
|
|
509
535
|
/**
|
|
510
536
|
* @returns {void}
|
|
511
537
|
*/
|
|
512
538
|
function runQueuedRequest () {
|
|
539
|
+
/* c8 ignore start -- Defensive: only reached if `prepareNextRequest` returns `false` (see its own ignore comment above for why that's not reliably reproducible). */
|
|
513
540
|
if (!prepareNextRequest()) {
|
|
514
541
|
return;
|
|
515
542
|
}
|
|
543
|
+
/* c8 ignore stop -- see comment above */
|
|
516
544
|
launchQueuedOp();
|
|
517
545
|
}
|
|
518
546
|
|
|
@@ -543,9 +571,11 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
543
571
|
* @returns {void}
|
|
544
572
|
*/
|
|
545
573
|
function checkQueueEntry (attemptsLeft) {
|
|
574
|
+
/* 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. */
|
|
546
575
|
if (me.__errored || me.__requestsFinished) {
|
|
547
576
|
return;
|
|
548
577
|
}
|
|
578
|
+
/* c8 ignore stop -- see comment above */
|
|
549
579
|
if (i < me.__requests.length) {
|
|
550
580
|
runQueuedRequest();
|
|
551
581
|
return;
|
|
@@ -567,10 +597,12 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
567
597
|
* @returns {void}
|
|
568
598
|
*/
|
|
569
599
|
function executeNextRequest () {
|
|
600
|
+
/* 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. */
|
|
570
601
|
if (me.__errored || me.__requestsFinished) {
|
|
571
602
|
// We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
|
|
572
603
|
return;
|
|
573
604
|
}
|
|
605
|
+
/* c8 ignore stop -- see comment above */
|
|
574
606
|
i++;
|
|
575
607
|
if (i >= me.__requests.length) {
|
|
576
608
|
checkQueueEntry(keepAliveAttempts);
|
|
@@ -605,21 +637,22 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
605
637
|
* @returns {void}
|
|
606
638
|
*/
|
|
607
639
|
function advanceAfterDispatch () {
|
|
640
|
+
/* 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. */
|
|
608
641
|
if (me.__errored || me.__requestsFinished) {
|
|
609
642
|
return;
|
|
610
643
|
}
|
|
644
|
+
/* c8 ignore stop -- see comment above */
|
|
611
645
|
i++;
|
|
612
646
|
if (i >= me.__requests.length) {
|
|
613
647
|
checkQueueEntry(keepAliveAttempts);
|
|
614
648
|
return;
|
|
615
649
|
}
|
|
616
650
|
keepAliveAndWait(() => {
|
|
617
|
-
if (
|
|
618
|
-
|
|
619
|
-
}
|
|
620
|
-
if (!prepareNextRequest()) {
|
|
651
|
+
/* 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. */
|
|
652
|
+
if (me.__errored || me.__requestsFinished || !prepareNextRequest()) {
|
|
621
653
|
return;
|
|
622
654
|
}
|
|
655
|
+
/* c8 ignore stop -- see comment above */
|
|
623
656
|
launchQueuedOp();
|
|
624
657
|
});
|
|
625
658
|
}
|
|
@@ -627,10 +660,12 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
627
660
|
executeNextRequest();
|
|
628
661
|
},
|
|
629
662
|
function webSQLError (webSQLErr) {
|
|
663
|
+
/* 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. */
|
|
630
664
|
// @ts-expect-error It's ok
|
|
631
665
|
if (webSQLErr === true) { // Not a genuine SQL error
|
|
632
666
|
return;
|
|
633
667
|
}
|
|
668
|
+
/* c8 ignore stop -- see comment above */
|
|
634
669
|
const err = webSQLErrback(/** @type {Error & {code?: number}} */ (webSQLErr));
|
|
635
670
|
me.__abortTransaction(err);
|
|
636
671
|
},
|
|
@@ -641,19 +676,27 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
641
676
|
if (me.__transFinishedCb !== IDBTransaction.prototype.__transFinishedCb) { // Node
|
|
642
677
|
return;
|
|
643
678
|
}
|
|
679
|
+
/* 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. */
|
|
644
680
|
if (!me.__transactionEndCallback && !me.__requestsFinished) {
|
|
645
681
|
me.__transactionFinished = true;
|
|
646
682
|
return;
|
|
647
683
|
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
684
|
+
/* c8 ignore stop -- see comment above */
|
|
685
|
+
/* 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. */
|
|
686
|
+
if (!me.__transactionEndCallback || me.__completed || me.__transFinishedCbFired) {
|
|
687
|
+
return;
|
|
651
688
|
}
|
|
689
|
+
|
|
690
|
+
me.__transFinishedCbFired = true;
|
|
691
|
+
me.__transFinishedCb(me.__errored, me.__transactionEndCallback);
|
|
692
|
+
/* c8 ignore stop -- see comment above */
|
|
652
693
|
},
|
|
653
694
|
function (currentTask, err, done, rollback, commit) {
|
|
695
|
+
/* 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. */
|
|
654
696
|
if (err) {
|
|
655
697
|
return true;
|
|
656
698
|
}
|
|
699
|
+
/* c8 ignore stop -- see comment above */
|
|
657
700
|
// `readonly` transactions never hold a real SQL transaction open
|
|
658
701
|
// (see `WebSQLTransaction`'s constructor skipping `BEGIN;` for
|
|
659
702
|
// them), so there's no commit/rollback round trip to defer --
|
|
@@ -705,6 +748,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
705
748
|
*/
|
|
706
749
|
function complete () {
|
|
707
750
|
me.__completed = true;
|
|
751
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
708
752
|
if (CFG.DEBUG) { console.log('Transaction completed'); }
|
|
709
753
|
const evt = createEvent('complete');
|
|
710
754
|
try {
|
|
@@ -712,6 +756,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
712
756
|
me.dispatchEvent(evt);
|
|
713
757
|
me.__internal = false;
|
|
714
758
|
me.dispatchEvent(createEvent('__complete'));
|
|
759
|
+
/* 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. */
|
|
715
760
|
} catch (e) {
|
|
716
761
|
me.__internal = false;
|
|
717
762
|
// An error occurred in the "oncomplete" handler.
|
|
@@ -719,6 +764,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
719
764
|
// (this may seem odd/bad, but it's how all native IndexedDB implementations work)
|
|
720
765
|
me.__errored = true;
|
|
721
766
|
throw e;
|
|
767
|
+
/* c8 ignore stop -- see comment above */
|
|
722
768
|
} finally {
|
|
723
769
|
activeTransactions.delete(me);
|
|
724
770
|
me.__storeHandles = {};
|
|
@@ -726,10 +772,12 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
726
772
|
}
|
|
727
773
|
}
|
|
728
774
|
if (me.mode === 'readwrite' || me.mode === 'readonly') {
|
|
775
|
+
/* 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. */
|
|
729
776
|
if (me.__transactionFinished) {
|
|
730
777
|
complete();
|
|
731
778
|
return;
|
|
732
779
|
}
|
|
780
|
+
/* c8 ignore stop -- see comment above */
|
|
733
781
|
me.__transactionEndCallback = complete;
|
|
734
782
|
// The underlying SQL driver's own "queue empty" check
|
|
735
783
|
// (`nonstandardTransCb`, above) typically already ran and
|
|
@@ -766,6 +814,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
766
814
|
IDBTransaction.prototype.__createRequest = function (source) {
|
|
767
815
|
const me = this;
|
|
768
816
|
const request = IDBRequest.__createInstance();
|
|
817
|
+
/* 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. */
|
|
769
818
|
request.__source = source !== undefined ? source : me.db;
|
|
770
819
|
request.__transaction = me;
|
|
771
820
|
return request;
|
|
@@ -835,9 +884,11 @@ IDBTransaction.prototype.__pushToQueue = function (request, callback, args) {
|
|
|
835
884
|
* @returns {void}
|
|
836
885
|
*/
|
|
837
886
|
IDBTransaction.prototype.__assertActive = function () {
|
|
887
|
+
/* 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. */
|
|
838
888
|
if (!this.__active || !this.__handlerActive || this.__committed) {
|
|
839
889
|
throw createDOMException('TransactionInactiveError', 'A request was placed against a transaction which is currently not active, or which is finished');
|
|
840
890
|
}
|
|
891
|
+
/* c8 ignore stop -- see comment above */
|
|
841
892
|
};
|
|
842
893
|
|
|
843
894
|
/**
|
|
@@ -851,6 +902,7 @@ IDBTransaction.prototype.__assertWritable = function () {
|
|
|
851
902
|
}
|
|
852
903
|
};
|
|
853
904
|
|
|
905
|
+
/* 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. */
|
|
854
906
|
/**
|
|
855
907
|
* @this {IDBTransactionFull}
|
|
856
908
|
* @returns {void}
|
|
@@ -858,6 +910,7 @@ IDBTransaction.prototype.__assertWritable = function () {
|
|
|
858
910
|
IDBTransaction.prototype.__assertVersionChange = function () {
|
|
859
911
|
IDBTransaction.__assertVersionChange(this);
|
|
860
912
|
};
|
|
913
|
+
/* c8 ignore stop -- see comment above */
|
|
861
914
|
|
|
862
915
|
/**
|
|
863
916
|
* Returns the specified object store.
|
|
@@ -878,9 +931,11 @@ IDBTransaction.prototype.objectStore = function (objectStoreName) {
|
|
|
878
931
|
throw createDOMException('NotFoundError', objectStoreName + ' is not participating in this transaction');
|
|
879
932
|
}
|
|
880
933
|
const store = me.db.__objectStores[objectStoreName];
|
|
934
|
+
/* 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. */
|
|
881
935
|
if (!store) {
|
|
882
936
|
throw createDOMException('NotFoundError', objectStoreName + ' does not exist in ' + me.db.name);
|
|
883
937
|
}
|
|
938
|
+
/* c8 ignore stop -- see comment above */
|
|
884
939
|
|
|
885
940
|
if (!Object.hasOwn(me.__storeHandles, objectStoreName) ||
|
|
886
941
|
// These latter conditions are to allow store
|
|
@@ -901,10 +956,12 @@ IDBTransaction.prototype.objectStore = function (objectStoreName) {
|
|
|
901
956
|
IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
902
957
|
const me = this;
|
|
903
958
|
logError('Error', 'An error occurred in a transaction', err);
|
|
959
|
+
/* 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. */
|
|
904
960
|
if (me.__errored) {
|
|
905
961
|
// We've already called "onerror", "onabort", or thrown, so don't do it again.
|
|
906
962
|
return;
|
|
907
963
|
}
|
|
964
|
+
/* c8 ignore stop -- see comment above */
|
|
908
965
|
me.__errored = true;
|
|
909
966
|
|
|
910
967
|
if (me.mode === 'versionchange') { // Steps for aborting an upgrade transaction
|
|
@@ -942,19 +999,15 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
942
999
|
me.__error = err;
|
|
943
1000
|
}
|
|
944
1001
|
|
|
1002
|
+
/* 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. */
|
|
945
1003
|
if (me.__requestsFinished && err !== null) {
|
|
946
1004
|
// The transaction has already completed, so we can't call "onerror" or "onabort".
|
|
947
|
-
// So throw the error instead.
|
|
948
|
-
// `IDBTransaction.prototype.abort`'s own `__abortTransaction(null)`
|
|
949
|
-
// call, which now checks `__requestsFinished` itself first and
|
|
950
|
-
// throws `InvalidStateError` synchronously before ever reaching
|
|
951
|
-
// this point -- so this guard is just defense in depth against
|
|
952
|
-
// `err` somehow being `null` some other way, not something this
|
|
953
|
-
// path should see in practice.
|
|
1005
|
+
// So throw the error instead.
|
|
954
1006
|
setTimeout(() => {
|
|
955
1007
|
throw err;
|
|
956
1008
|
}, 0);
|
|
957
1009
|
}
|
|
1010
|
+
/* c8 ignore stop -- see comment above */
|
|
958
1011
|
|
|
959
1012
|
/**
|
|
960
1013
|
* @param {import('websql-configurable/lib/websql/WebSQLTransaction.js').default|null} [tx]
|
|
@@ -963,9 +1016,13 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
963
1016
|
*/
|
|
964
1017
|
function abort (tx, errOrResult) {
|
|
965
1018
|
if (!tx) {
|
|
1019
|
+
/* 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. */
|
|
966
1020
|
if (CFG.DEBUG) { console.log('Rollback not possible due to missing transaction', me); }
|
|
1021
|
+
/* 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. */
|
|
967
1022
|
} else if (errOrResult && 'code' in errOrResult && typeof errOrResult.code === 'number') {
|
|
968
1023
|
if (CFG.DEBUG) { console.log('Rollback erred; feature is probably not supported as per WebSQL', me); }
|
|
1024
|
+
/* c8 ignore stop -- see comment above */
|
|
1025
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
969
1026
|
} else if (CFG.DEBUG) { console.log('Rollback succeeded', me); }
|
|
970
1027
|
|
|
971
1028
|
me.dispatchEvent(createEvent('__preabort'));
|
|
@@ -979,9 +1036,11 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
979
1036
|
// behaves first-in-first-out with the same timeout so we could
|
|
980
1037
|
// just use a `forEach`.
|
|
981
1038
|
return promises.then(function () {
|
|
982
|
-
|
|
1039
|
+
/* 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. */
|
|
1040
|
+
if (!q.req) {
|
|
983
1041
|
throw new Error('Missing request');
|
|
984
1042
|
}
|
|
1043
|
+
/* c8 ignore stop -- see comment above */
|
|
985
1044
|
q.req.__done = true;
|
|
986
1045
|
q.req.__result = undefined;
|
|
987
1046
|
q.req.__error = createDOMException('AbortError', 'A request was aborted (an unfinished request).');
|
|
@@ -990,9 +1049,11 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
990
1049
|
/** @type {(resolve: (value?: unknown) => void) => void} */
|
|
991
1050
|
(resolve) => {
|
|
992
1051
|
setTimeout(() => {
|
|
993
|
-
|
|
1052
|
+
/* c8 ignore start -- Dead code: same invariant as above -- `q.req` was already confirmed truthy by the outer `.filter()` and is never reset. */
|
|
1053
|
+
if (!q.req) {
|
|
994
1054
|
throw new Error('Missing request');
|
|
995
1055
|
}
|
|
1056
|
+
/* c8 ignore stop -- see comment above */
|
|
996
1057
|
q.req.dispatchEvent(reqEvt); // No need to catch errors
|
|
997
1058
|
resolve();
|
|
998
1059
|
}, 0);
|
|
@@ -1009,10 +1070,12 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
1009
1070
|
releaseFinishedTransaction(me);
|
|
1010
1071
|
}, 0);
|
|
1011
1072
|
return undefined;
|
|
1073
|
+
/* 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. */
|
|
1012
1074
|
}).catch((err) => {
|
|
1013
1075
|
console.log('Abort error');
|
|
1014
1076
|
throw err;
|
|
1015
1077
|
});
|
|
1078
|
+
/* c8 ignore stop -- see comment above */
|
|
1016
1079
|
}
|
|
1017
1080
|
|
|
1018
1081
|
me.__transFinishedCb(true, function (rollback) {
|
|
@@ -1020,10 +1083,12 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
1020
1083
|
// rollback automatically), but for Node.js, etc., we give chance for
|
|
1021
1084
|
// manual aborts which would otherwise not work.
|
|
1022
1085
|
if (me.mode === 'readwrite') {
|
|
1086
|
+
/* 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. */
|
|
1023
1087
|
if (me.__transactionFinished) {
|
|
1024
1088
|
abort();
|
|
1025
1089
|
return;
|
|
1026
1090
|
}
|
|
1091
|
+
/* c8 ignore stop -- see comment above */
|
|
1027
1092
|
me.__transactionEndCallback = abort;
|
|
1028
1093
|
return;
|
|
1029
1094
|
}
|
|
@@ -1034,11 +1099,13 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
1034
1099
|
abort,
|
|
1035
1100
|
/** @type {import('websql-configurable/lib/websql/WebSQLTransaction.js').SqlErrorCallback} */ (abort)
|
|
1036
1101
|
); // Not working in some circumstances, even in Node
|
|
1102
|
+
/* c8 ignore start -- Defensive: the underlying WebSQL/SQLite driver throwing synchronously on `ROLLBACK` is not reliably reproducible without mocking the SQL layer. */
|
|
1037
1103
|
} catch (err) {
|
|
1038
1104
|
// Browser errs when transaction has ended and since it most likely already erred here,
|
|
1039
1105
|
// we call to abort
|
|
1040
1106
|
abort();
|
|
1041
1107
|
}
|
|
1108
|
+
/* c8 ignore stop -- see comment above */
|
|
1042
1109
|
} else {
|
|
1043
1110
|
abort(null, {code: 0});
|
|
1044
1111
|
}
|
|
@@ -1054,6 +1121,7 @@ IDBTransaction.prototype.abort = function () {
|
|
|
1054
1121
|
if (!(me instanceof IDBTransaction)) {
|
|
1055
1122
|
throw new TypeError('Illegal invocation');
|
|
1056
1123
|
}
|
|
1124
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
1057
1125
|
if (CFG.DEBUG) { console.log('The transaction was aborted', me); }
|
|
1058
1126
|
IDBTransaction.__assertNotFinished(me);
|
|
1059
1127
|
if (me.__committed) {
|
|
@@ -1083,6 +1151,7 @@ IDBTransaction.prototype.commit = function () {
|
|
|
1083
1151
|
if (!me.__active || !me.__handlerActive || me.__committed) {
|
|
1084
1152
|
throw createDOMException('InvalidStateError', 'Failed to execute \'commit\' on \'IDBTransaction\': The transaction is not active.');
|
|
1085
1153
|
}
|
|
1154
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
1086
1155
|
if (CFG.DEBUG) { console.log('The transaction was explicitly committed', me); }
|
|
1087
1156
|
me.__committed = true;
|
|
1088
1157
|
};
|
|
@@ -1124,6 +1193,7 @@ IDBTransaction.__assertNotFinished = function (tx) {
|
|
|
1124
1193
|
};
|
|
1125
1194
|
|
|
1126
1195
|
// object store methods behave differently: see https://github.com/w3c/IndexedDB/issues/192
|
|
1196
|
+
/* 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. */
|
|
1127
1197
|
/**
|
|
1128
1198
|
*
|
|
1129
1199
|
* @param {IDBTransactionFull} tx
|
|
@@ -1139,6 +1209,7 @@ IDBTransaction.__assertNotFinishedObjectStoreMethod = function (tx) {
|
|
|
1139
1209
|
throw err;
|
|
1140
1210
|
}
|
|
1141
1211
|
};
|
|
1212
|
+
/* c8 ignore stop -- see comment above */
|
|
1142
1213
|
|
|
1143
1214
|
/**
|
|
1144
1215
|
*
|
package/src/Key.js
CHANGED
|
@@ -613,8 +613,14 @@ function convertValueToKeyValueDecoded (input, seen, multiEntry, fullKeys) {
|
|
|
613
613
|
(!fullKeys && keys.every((k) => cmp(
|
|
614
614
|
/** @type {Key} */ (k), /** @type {Key} */ (key.value)
|
|
615
615
|
) !== 0)) ||
|
|
616
|
+
// `keys` holds full `{type, value}` objects here (see
|
|
617
|
+
// `safePush` below), so -- like the sibling branch
|
|
618
|
+
// above -- `cmp` (which expects raw `Value`s, not
|
|
619
|
+
// decoded key objects) must compare their `.value`s,
|
|
620
|
+
// not the wrapper objects themselves.
|
|
616
621
|
(fullKeys && keys.every((k) => cmp(
|
|
617
|
-
/** @type {Key} */ (
|
|
622
|
+
/** @type {Key} */ (/** @type {KeyValueObject} */ (k).value),
|
|
623
|
+
/** @type {Key} */ (key.value)
|
|
618
624
|
) !== 0))
|
|
619
625
|
) {
|
|
620
626
|
safePush(keys, fullKeys ? key : key.value);
|
|
@@ -629,9 +635,7 @@ function convertValueToKeyValueDecoded (input, seen, multiEntry, fullKeys) {
|
|
|
629
635
|
} case 'date': {
|
|
630
636
|
const date = /** @type {Date} */ (input);
|
|
631
637
|
if (!Number.isNaN(date.getTime())) {
|
|
632
|
-
return fullKeys
|
|
633
|
-
? {type, value: date.getTime()}
|
|
634
|
-
: {type, value: new Date(date)};
|
|
638
|
+
return {type, value: fullKeys ? date.getTime() : new Date(date)};
|
|
635
639
|
}
|
|
636
640
|
return {type, invalid: true, message: 'Not a valid date'};
|
|
637
641
|
// Falls through
|
|
@@ -707,10 +711,9 @@ function extractKeyValueDecodedFromValueUsingKeyPath (value, keyPath, multiEntry
|
|
|
707
711
|
if (r.failure) {
|
|
708
712
|
return r;
|
|
709
713
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
return convertValueToMultiEntryKeyDecoded(r.value, fullKeys);
|
|
714
|
+
return !multiEntry
|
|
715
|
+
? convertValueToKeyValueDecoded(r.value, null, false, fullKeys)
|
|
716
|
+
: convertValueToMultiEntryKeyDecoded(r.value, fullKeys);
|
|
714
717
|
}
|
|
715
718
|
|
|
716
719
|
/**
|
|
@@ -889,10 +892,9 @@ function isKeyInRange (key, range, checkCached) {
|
|
|
889
892
|
function isMultiEntryMatch (encodedEntry, encodedKey) {
|
|
890
893
|
const keyType = encodedCharToKeyType[encodedKey.slice(0, 1)];
|
|
891
894
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
return encodedKey === encodedEntry;
|
|
895
|
+
return keyType === 'array'
|
|
896
|
+
? encodedKey.indexOf(encodedEntry) > 1
|
|
897
|
+
: encodedKey === encodedEntry;
|
|
896
898
|
}
|
|
897
899
|
|
|
898
900
|
/**
|
|
@@ -993,10 +995,9 @@ function encode (key, inArray) {
|
|
|
993
995
|
* @returns {undefined|ValueType}
|
|
994
996
|
*/
|
|
995
997
|
function decode (key, inArray) {
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
return types[encodedCharToKeyType[key.slice(0, 1)]].decode(key, inArray);
|
|
998
|
+
return typeof key !== 'string'
|
|
999
|
+
? undefined
|
|
1000
|
+
: types[encodedCharToKeyType[key.slice(0, 1)]].decode(key, inArray);
|
|
1000
1001
|
}
|
|
1001
1002
|
|
|
1002
1003
|
/**
|
package/src/Sca.js
CHANGED
|
@@ -15,14 +15,17 @@ const specSet = structuredCloningForStorage
|
|
|
15
15
|
|
|
16
16
|
const origFileList = specSet && !Array.isArray(specSet) && 'filelist' in specSet
|
|
17
17
|
? specSet.filelist
|
|
18
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */
|
|
18
19
|
: undefined;
|
|
19
20
|
|
|
20
21
|
const origTest = origFileList && typeof origFileList === 'object' && 'test' in origFileList && typeof origFileList.test === 'function'
|
|
21
22
|
? origFileList.test
|
|
23
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.test` ever goes missing */
|
|
22
24
|
: undefined;
|
|
23
25
|
|
|
24
26
|
const origRevive = origFileList && typeof origFileList === 'object' && 'revive' in origFileList && typeof origFileList.revive === 'function'
|
|
25
27
|
? origFileList.revive
|
|
28
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.revive` ever goes missing */
|
|
26
29
|
: undefined;
|
|
27
30
|
|
|
28
31
|
const customFileList = origFileList
|
|
@@ -34,10 +37,9 @@ const customFileList = origFileList
|
|
|
34
37
|
* @returns {boolean}
|
|
35
38
|
*/
|
|
36
39
|
test (x, state) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return typeof origTest === 'function' ? origTest(x, state) : false;
|
|
40
|
+
return typeof FileList !== 'undefined'
|
|
41
|
+
? x instanceof FileList
|
|
42
|
+
: ((typeof origTest === 'function') && origTest(x, state));
|
|
41
43
|
},
|
|
42
44
|
/**
|
|
43
45
|
* @param {unknown} x
|
|
@@ -48,13 +50,16 @@ const customFileList = origFileList
|
|
|
48
50
|
if (typeof FileList !== 'undefined') {
|
|
49
51
|
return Reflect.construct(FileList, [x]);
|
|
50
52
|
}
|
|
53
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist.revive` ever goes missing */
|
|
51
54
|
return typeof origRevive === 'function' ? origRevive(x, state) : undefined;
|
|
52
55
|
}
|
|
53
56
|
}
|
|
57
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */
|
|
54
58
|
: undefined;
|
|
55
59
|
|
|
56
60
|
let typeson = new Typeson().register([
|
|
57
61
|
structuredCloningForStorage,
|
|
62
|
+
/* c8 ignore next -- Defensive fallback if typeson-registry's `filelist` preset entry ever goes missing */
|
|
58
63
|
customFileList ? {filelist: customFileList} : {}
|
|
59
64
|
]);
|
|
60
65
|
|
package/src/nodeWebSQL.js
CHANGED
|
@@ -29,6 +29,7 @@ import CFG from './CFG.js';
|
|
|
29
29
|
* @returns {SQLiteDatabaseInstance}
|
|
30
30
|
*/
|
|
31
31
|
function wrappedSQLiteDatabase (name) {
|
|
32
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
32
33
|
// @ts-ignore It's ok; needed under some TS versions
|
|
33
34
|
const db = new SQLiteDatabase(name, {});
|
|
34
35
|
if (CFG.sqlBusyTimeout) {
|