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.
Files changed (60) hide show
  1. package/badges/coverage-badge.svg +1 -1
  2. package/badges/tests-badge.svg +1 -1
  3. package/dist/CFG.d.ts +1 -1
  4. package/dist/CFG.d.ts.map +1 -1
  5. package/dist/DOMException.d.ts.map +1 -1
  6. package/dist/IDBCursor.d.ts.map +1 -1
  7. package/dist/IDBDatabase.d.ts.map +1 -1
  8. package/dist/IDBFactory.d.ts +1 -2
  9. package/dist/IDBFactory.d.ts.map +1 -1
  10. package/dist/IDBIndex.d.ts +2 -6
  11. package/dist/IDBIndex.d.ts.map +1 -1
  12. package/dist/IDBKeyRange.d.ts.map +1 -1
  13. package/dist/IDBObjectStore.d.ts.map +1 -1
  14. package/dist/IDBRecord.d.ts.map +1 -1
  15. package/dist/IDBRequest.d.ts.map +1 -1
  16. package/dist/IDBTransaction.d.ts.map +1 -1
  17. package/dist/Key.d.ts.map +1 -1
  18. package/dist/Sca.d.ts.map +1 -1
  19. package/dist/indexeddbshim-Key.js +40 -28
  20. package/dist/indexeddbshim-Key.js.map +1 -1
  21. package/dist/indexeddbshim-Key.min.js +2 -2
  22. package/dist/indexeddbshim-Key.min.js.map +1 -1
  23. package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs +511 -217
  24. package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
  25. package/dist/indexeddbshim-UnicodeIdentifiers.js +539 -244
  26. package/dist/indexeddbshim-UnicodeIdentifiers.js.map +1 -1
  27. package/dist/indexeddbshim-UnicodeIdentifiers.min.js +3 -3
  28. package/dist/indexeddbshim-UnicodeIdentifiers.min.js.map +1 -1
  29. package/dist/indexeddbshim-node.cjs +511 -217
  30. package/dist/indexeddbshim-node.cjs.map +1 -1
  31. package/dist/indexeddbshim-noninvasive.js +539 -244
  32. package/dist/indexeddbshim-noninvasive.js.map +1 -1
  33. package/dist/indexeddbshim-noninvasive.min.js +3 -3
  34. package/dist/indexeddbshim-noninvasive.min.js.map +1 -1
  35. package/dist/indexeddbshim.js +539 -244
  36. package/dist/indexeddbshim.js.map +1 -1
  37. package/dist/indexeddbshim.min.js +3 -3
  38. package/dist/indexeddbshim.min.js.map +1 -1
  39. package/dist/nodeWebSQL.d.ts.map +1 -1
  40. package/dist/setGlobalVars.d.ts +1 -1
  41. package/dist/setGlobalVars.d.ts.map +1 -1
  42. package/dist/util.d.ts.map +1 -1
  43. package/package.json +22 -17
  44. package/src/CFG.js +18 -4
  45. package/src/DOMException.js +6 -0
  46. package/src/DOMStringList.js +3 -0
  47. package/src/IDBCursor.js +36 -3
  48. package/src/IDBDatabase.js +26 -10
  49. package/src/IDBFactory.js +105 -5
  50. package/src/IDBIndex.js +49 -32
  51. package/src/IDBKeyRange.js +8 -7
  52. package/src/IDBObjectStore.js +25 -2
  53. package/src/IDBRecord.js +2 -0
  54. package/src/IDBRequest.js +7 -4
  55. package/src/IDBTransaction.js +97 -26
  56. package/src/Key.js +17 -16
  57. package/src/Sca.js +9 -4
  58. package/src/nodeWebSQL.js +1 -0
  59. package/src/setGlobalVars.js +86 -77
  60. package/src/util.js +5 -6
@@ -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
- if (!q.req) { // TS guard
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
- if (!q.req) { // TS guard
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
- if (e.__legacyOutputDidListenersThrowError) {
448
- 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
449
- e.preventDefault(); // Prevent 'error' default as steps indicate we should abort with `AbortError` even without cancellation
450
- if (me.__committed) { // An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
451
- util.runContinuationSafely(advanceAfterDispatch);
452
- return;
453
- }
454
- me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after error).'));
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 (me.__errored || me.__requestsFinished) {
618
- return;
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
- if (me.__transactionEndCallback && !me.__completed && !me.__transFinishedCbFired) {
649
- me.__transFinishedCbFired = true;
650
- me.__transFinishedCb(me.__errored, me.__transactionEndCallback);
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. `err` is only ever `null` here via
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
- if (!q.req) { // TS guard
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
- if (!q.req) { // TS guard
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} */ (k), /** @type {Key} */ (/** @type {unknown} */ (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
- if (!multiEntry) {
711
- return convertValueToKeyValueDecoded(r.value, null, false, fullKeys);
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
- if (keyType === 'array') {
893
- return encodedKey.indexOf(encodedEntry) > 1;
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
- if (typeof key !== 'string') {
997
- return undefined;
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
- if (typeof FileList !== 'undefined') {
38
- return x instanceof FileList;
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) {