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.
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 +525 -225
  24. package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
  25. package/dist/indexeddbshim-UnicodeIdentifiers.js +553 -252
  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 +525 -225
  30. package/dist/indexeddbshim-node.cjs.map +1 -1
  31. package/dist/indexeddbshim-noninvasive.js +553 -252
  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 +553 -252
  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 +111 -34
  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
@@ -297,6 +299,10 @@ IDBTransaction.prototype.__executeRequests = function () {
297
299
  let q,
298
300
  i = -1;
299
301
 
302
+ // On a standard driver, `keepAliveAndWait` issues a SQL query, which
303
+ // is a macrotask. Otherwise it issues ten microtasks.
304
+ const keepAliveAttempts = isStandardDriver ? 1 : 10;
305
+
300
306
  /**
301
307
  * A continuation that must still be able to observe the
302
308
  * transaction as safe to extend (e.g., re-checking whether an
@@ -323,6 +329,7 @@ IDBTransaction.prototype.__executeRequests = function () {
323
329
  queueMicrotask(cb);
324
330
  return;
325
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. */
326
333
  try {
327
334
  tx.executeSql('SELECT 1', [], function () {
328
335
  cb();
@@ -332,10 +339,11 @@ IDBTransaction.prototype.__executeRequests = function () {
332
339
  });
333
340
  } catch (err) {
334
341
  // The driver has already finalized the transaction (or otherwise
335
- // rejected the call) -- nothing left to hold open, so fall back
336
- // to a plain microtask hop for the continuation itself.
337
- queueMicrotask(cb);
342
+ // rejected the call) -- nothing left to hold open. We explicitly
343
+ // abort the transaction here.
344
+ me.__abortTransaction(/** @type {Error|DOMException} */ (err));
338
345
  }
346
+ /* c8 ignore stop -- see comment above */
339
347
  }
340
348
 
341
349
  /**
@@ -348,19 +356,25 @@ IDBTransaction.prototype.__executeRequests = function () {
348
356
  * @returns {void}
349
357
  */
350
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. */
351
360
  if (me.__errored || me.__requestsFinished) {
352
361
  // We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
353
362
  return;
354
363
  }
364
+ /* c8 ignore stop -- see comment above */
355
365
  if (req) {
356
366
  q.req = req; // Need to do this in case of cursors
357
367
  }
358
- 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) {
359
370
  return;
360
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. */
361
374
  if (q.req.__done) { // Avoid continuing with aborted requests
362
375
  return;
363
376
  }
377
+ /* c8 ignore stop -- see comment above */
364
378
  q.req.__done = true;
365
379
  q.req.__result = result;
366
380
  q.req.__error = null;
@@ -378,6 +392,7 @@ IDBTransaction.prototype.__executeRequests = function () {
378
392
  // is what actually resets `__handlerActive`, once it's
379
393
  // confirmed (across its own bounded microtask wait) that no
380
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. */
381
396
  if (e.__legacyOutputDidListenersThrowError) {
382
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
383
398
  if (!me.__committed) { // An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
@@ -386,6 +401,7 @@ IDBTransaction.prototype.__executeRequests = function () {
386
401
  return;
387
402
  }
388
403
  }
404
+ /* c8 ignore stop -- see comment above */
389
405
  util.runContinuationSafely(advanceAfterDispatch);
390
406
  }
391
407
 
@@ -397,14 +413,18 @@ IDBTransaction.prototype.__executeRequests = function () {
397
413
  * @returns {void}
398
414
  */
399
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. */
400
417
  if (me.__errored || me.__requestsFinished) {
401
418
  // We've already called "onerror", "onabort", or thrown within
402
419
  // the transaction, so don't do it again.
403
420
  return;
404
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. */
405
424
  if (q.req && q.req.__done) { // Avoid continuing with aborted requests
406
425
  return;
407
426
  }
427
+ /* c8 ignore stop -- see comment above */
408
428
  const err = /** @type {Error|DOMException} */ (findError(args));
409
429
  if (!q.req) {
410
430
  me.__abortTransaction(err);
@@ -428,9 +448,11 @@ IDBTransaction.prototype.__executeRequests = function () {
428
448
  }
429
449
  );
430
450
  q.req.addDefaultEventListener('error', function () {
431
- 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) {
432
453
  return;
433
454
  }
455
+ /* c8 ignore stop -- see comment above */
434
456
  me.__abortTransaction(q.req.__error);
435
457
  });
436
458
 
@@ -440,15 +462,19 @@ IDBTransaction.prototype.__executeRequests = function () {
440
462
  q.req.dispatchEvent(e);
441
463
  // Do not set __active or __handlerActive flags to false yet --
442
464
  // see the matching comment in `success`, above.
443
- if (e.__legacyOutputDidListenersThrowError) {
444
- 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
445
- e.preventDefault(); // Prevent 'error' default as steps indicate we should abort with `AbortError` even without cancellation
446
- if (me.__committed) { // An explicit `commit()` locks in the commit, so errors thrown afterward must not abort it
447
- util.runContinuationSafely(advanceAfterDispatch);
448
- return;
449
- }
450
- 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;
451
475
  }
476
+ me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after error).'));
477
+ /* c8 ignore stop -- see comment above */
452
478
  }
453
479
 
454
480
  /**
@@ -472,9 +498,11 @@ IDBTransaction.prototype.__executeRequests = function () {
472
498
  // (not reset here).
473
499
  return true;
474
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. */
475
502
  if (q.req.__done) { // Avoid continuing with aborted requests
476
503
  return false;
477
504
  }
505
+ /* c8 ignore stop -- see comment above */
478
506
  // We're now handing off to (possibly async) work for
479
507
  // this request, so the transaction is no longer active
480
508
  // until its own `success`/`error` dispatch (below)
@@ -497,18 +525,22 @@ IDBTransaction.prototype.__executeRequests = function () {
497
525
  return;
498
526
  }
499
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. */
500
529
  } catch (e) {
501
530
  error(/** @type {Error} */ (e));
502
531
  }
532
+ /* c8 ignore stop -- see comment above */
503
533
  }
504
534
 
505
535
  /**
506
536
  * @returns {void}
507
537
  */
508
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). */
509
540
  if (!prepareNextRequest()) {
510
541
  return;
511
542
  }
543
+ /* c8 ignore stop -- see comment above */
512
544
  launchQueuedOp();
513
545
  }
514
546
 
@@ -530,16 +562,20 @@ IDBTransaction.prototype.__executeRequests = function () {
530
562
  * consumer of that same handler (e.g. one that resolves a
531
563
  * promise from within `onsuccess` and only attaches `oncomplete`
532
564
  * afterward) ever gets a turn to run, so it can miss `complete`
533
- * entirely. `readonly` requests don't hold a real SQL
534
- * transaction open, though, so there's no file-lock/connection
535
- * collision risk in waiting the same bounded amount here.
565
+ * afterward) ever gets a turn to run, so it can miss `complete`
566
+ * entirely. On a non-standard driver, `readonly` requests don't hold
567
+ * a real SQL transaction open, so there's no file-lock/connection
568
+ * collision risk. On a standard driver, the wait now issues real SQL
569
+ * inside the read transaction, so this does carry a slight risk.
536
570
  * @param {number} attemptsLeft
537
571
  * @returns {void}
538
572
  */
539
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. */
540
575
  if (me.__errored || me.__requestsFinished) {
541
576
  return;
542
577
  }
578
+ /* c8 ignore stop -- see comment above */
543
579
  if (i < me.__requests.length) {
544
580
  runQueuedRequest();
545
581
  return;
@@ -561,13 +597,15 @@ IDBTransaction.prototype.__executeRequests = function () {
561
597
  * @returns {void}
562
598
  */
563
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. */
564
601
  if (me.__errored || me.__requestsFinished) {
565
602
  // We've already called "onerror", "onabort", or thrown within the transaction, so don't do it again.
566
603
  return;
567
604
  }
605
+ /* c8 ignore stop -- see comment above */
568
606
  i++;
569
607
  if (i >= me.__requests.length) {
570
- checkQueueEntry(10);
608
+ checkQueueEntry(keepAliveAttempts);
571
609
  return;
572
610
  }
573
611
  runQueuedRequest();
@@ -599,21 +637,22 @@ IDBTransaction.prototype.__executeRequests = function () {
599
637
  * @returns {void}
600
638
  */
601
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. */
602
641
  if (me.__errored || me.__requestsFinished) {
603
642
  return;
604
643
  }
644
+ /* c8 ignore stop -- see comment above */
605
645
  i++;
606
646
  if (i >= me.__requests.length) {
607
- checkQueueEntry(10);
647
+ checkQueueEntry(keepAliveAttempts);
608
648
  return;
609
649
  }
610
650
  keepAliveAndWait(() => {
611
- if (me.__errored || me.__requestsFinished) {
612
- return;
613
- }
614
- 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()) {
615
653
  return;
616
654
  }
655
+ /* c8 ignore stop -- see comment above */
617
656
  launchQueuedOp();
618
657
  });
619
658
  }
@@ -621,10 +660,12 @@ IDBTransaction.prototype.__executeRequests = function () {
621
660
  executeNextRequest();
622
661
  },
623
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. */
624
664
  // @ts-expect-error It's ok
625
665
  if (webSQLErr === true) { // Not a genuine SQL error
626
666
  return;
627
667
  }
668
+ /* c8 ignore stop -- see comment above */
628
669
  const err = webSQLErrback(/** @type {Error & {code?: number}} */ (webSQLErr));
629
670
  me.__abortTransaction(err);
630
671
  },
@@ -635,19 +676,27 @@ IDBTransaction.prototype.__executeRequests = function () {
635
676
  if (me.__transFinishedCb !== IDBTransaction.prototype.__transFinishedCb) { // Node
636
677
  return;
637
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. */
638
680
  if (!me.__transactionEndCallback && !me.__requestsFinished) {
639
681
  me.__transactionFinished = true;
640
682
  return;
641
683
  }
642
- if (me.__transactionEndCallback && !me.__completed && !me.__transFinishedCbFired) {
643
- me.__transFinishedCbFired = true;
644
- 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;
645
688
  }
689
+
690
+ me.__transFinishedCbFired = true;
691
+ me.__transFinishedCb(me.__errored, me.__transactionEndCallback);
692
+ /* c8 ignore stop -- see comment above */
646
693
  },
647
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. */
648
696
  if (err) {
649
697
  return true;
650
698
  }
699
+ /* c8 ignore stop -- see comment above */
651
700
  // `readonly` transactions never hold a real SQL transaction open
652
701
  // (see `WebSQLTransaction`'s constructor skipping `BEGIN;` for
653
702
  // them), so there's no commit/rollback round trip to defer --
@@ -699,6 +748,7 @@ IDBTransaction.prototype.__executeRequests = function () {
699
748
  */
700
749
  function complete () {
701
750
  me.__completed = true;
751
+ /* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
702
752
  if (CFG.DEBUG) { console.log('Transaction completed'); }
703
753
  const evt = createEvent('complete');
704
754
  try {
@@ -706,6 +756,7 @@ IDBTransaction.prototype.__executeRequests = function () {
706
756
  me.dispatchEvent(evt);
707
757
  me.__internal = false;
708
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. */
709
760
  } catch (e) {
710
761
  me.__internal = false;
711
762
  // An error occurred in the "oncomplete" handler.
@@ -713,6 +764,7 @@ IDBTransaction.prototype.__executeRequests = function () {
713
764
  // (this may seem odd/bad, but it's how all native IndexedDB implementations work)
714
765
  me.__errored = true;
715
766
  throw e;
767
+ /* c8 ignore stop -- see comment above */
716
768
  } finally {
717
769
  activeTransactions.delete(me);
718
770
  me.__storeHandles = {};
@@ -720,10 +772,12 @@ IDBTransaction.prototype.__executeRequests = function () {
720
772
  }
721
773
  }
722
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. */
723
776
  if (me.__transactionFinished) {
724
777
  complete();
725
778
  return;
726
779
  }
780
+ /* c8 ignore stop -- see comment above */
727
781
  me.__transactionEndCallback = complete;
728
782
  // The underlying SQL driver's own "queue empty" check
729
783
  // (`nonstandardTransCb`, above) typically already ran and
@@ -760,6 +814,7 @@ IDBTransaction.prototype.__executeRequests = function () {
760
814
  IDBTransaction.prototype.__createRequest = function (source) {
761
815
  const me = this;
762
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. */
763
818
  request.__source = source !== undefined ? source : me.db;
764
819
  request.__transaction = me;
765
820
  return request;
@@ -829,9 +884,11 @@ IDBTransaction.prototype.__pushToQueue = function (request, callback, args) {
829
884
  * @returns {void}
830
885
  */
831
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. */
832
888
  if (!this.__active || !this.__handlerActive || this.__committed) {
833
889
  throw createDOMException('TransactionInactiveError', 'A request was placed against a transaction which is currently not active, or which is finished');
834
890
  }
891
+ /* c8 ignore stop -- see comment above */
835
892
  };
836
893
 
837
894
  /**
@@ -845,6 +902,7 @@ IDBTransaction.prototype.__assertWritable = function () {
845
902
  }
846
903
  };
847
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. */
848
906
  /**
849
907
  * @this {IDBTransactionFull}
850
908
  * @returns {void}
@@ -852,6 +910,7 @@ IDBTransaction.prototype.__assertWritable = function () {
852
910
  IDBTransaction.prototype.__assertVersionChange = function () {
853
911
  IDBTransaction.__assertVersionChange(this);
854
912
  };
913
+ /* c8 ignore stop -- see comment above */
855
914
 
856
915
  /**
857
916
  * Returns the specified object store.
@@ -872,9 +931,11 @@ IDBTransaction.prototype.objectStore = function (objectStoreName) {
872
931
  throw createDOMException('NotFoundError', objectStoreName + ' is not participating in this transaction');
873
932
  }
874
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. */
875
935
  if (!store) {
876
936
  throw createDOMException('NotFoundError', objectStoreName + ' does not exist in ' + me.db.name);
877
937
  }
938
+ /* c8 ignore stop -- see comment above */
878
939
 
879
940
  if (!Object.hasOwn(me.__storeHandles, objectStoreName) ||
880
941
  // These latter conditions are to allow store
@@ -895,10 +956,12 @@ IDBTransaction.prototype.objectStore = function (objectStoreName) {
895
956
  IDBTransaction.prototype.__abortTransaction = function (err) {
896
957
  const me = this;
897
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. */
898
960
  if (me.__errored) {
899
961
  // We've already called "onerror", "onabort", or thrown, so don't do it again.
900
962
  return;
901
963
  }
964
+ /* c8 ignore stop -- see comment above */
902
965
  me.__errored = true;
903
966
 
904
967
  if (me.mode === 'versionchange') { // Steps for aborting an upgrade transaction
@@ -936,19 +999,15 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
936
999
  me.__error = err;
937
1000
  }
938
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. */
939
1003
  if (me.__requestsFinished && err !== null) {
940
1004
  // The transaction has already completed, so we can't call "onerror" or "onabort".
941
- // So throw the error instead. `err` is only ever `null` here via
942
- // `IDBTransaction.prototype.abort`'s own `__abortTransaction(null)`
943
- // call, which now checks `__requestsFinished` itself first and
944
- // throws `InvalidStateError` synchronously before ever reaching
945
- // this point -- so this guard is just defense in depth against
946
- // `err` somehow being `null` some other way, not something this
947
- // path should see in practice.
1005
+ // So throw the error instead.
948
1006
  setTimeout(() => {
949
1007
  throw err;
950
1008
  }, 0);
951
1009
  }
1010
+ /* c8 ignore stop -- see comment above */
952
1011
 
953
1012
  /**
954
1013
  * @param {import('websql-configurable/lib/websql/WebSQLTransaction.js').default|null} [tx]
@@ -957,9 +1016,13 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
957
1016
  */
958
1017
  function abort (tx, errOrResult) {
959
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. */
960
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. */
961
1022
  } else if (errOrResult && 'code' in errOrResult && typeof errOrResult.code === 'number') {
962
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`. */
963
1026
  } else if (CFG.DEBUG) { console.log('Rollback succeeded', me); }
964
1027
 
965
1028
  me.dispatchEvent(createEvent('__preabort'));
@@ -973,9 +1036,11 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
973
1036
  // behaves first-in-first-out with the same timeout so we could
974
1037
  // just use a `forEach`.
975
1038
  return promises.then(function () {
976
- 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) {
977
1041
  throw new Error('Missing request');
978
1042
  }
1043
+ /* c8 ignore stop -- see comment above */
979
1044
  q.req.__done = true;
980
1045
  q.req.__result = undefined;
981
1046
  q.req.__error = createDOMException('AbortError', 'A request was aborted (an unfinished request).');
@@ -984,9 +1049,11 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
984
1049
  /** @type {(resolve: (value?: unknown) => void) => void} */
985
1050
  (resolve) => {
986
1051
  setTimeout(() => {
987
- 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) {
988
1054
  throw new Error('Missing request');
989
1055
  }
1056
+ /* c8 ignore stop -- see comment above */
990
1057
  q.req.dispatchEvent(reqEvt); // No need to catch errors
991
1058
  resolve();
992
1059
  }, 0);
@@ -1003,10 +1070,12 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
1003
1070
  releaseFinishedTransaction(me);
1004
1071
  }, 0);
1005
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. */
1006
1074
  }).catch((err) => {
1007
1075
  console.log('Abort error');
1008
1076
  throw err;
1009
1077
  });
1078
+ /* c8 ignore stop -- see comment above */
1010
1079
  }
1011
1080
 
1012
1081
  me.__transFinishedCb(true, function (rollback) {
@@ -1014,10 +1083,12 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
1014
1083
  // rollback automatically), but for Node.js, etc., we give chance for
1015
1084
  // manual aborts which would otherwise not work.
1016
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. */
1017
1087
  if (me.__transactionFinished) {
1018
1088
  abort();
1019
1089
  return;
1020
1090
  }
1091
+ /* c8 ignore stop -- see comment above */
1021
1092
  me.__transactionEndCallback = abort;
1022
1093
  return;
1023
1094
  }
@@ -1028,11 +1099,13 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
1028
1099
  abort,
1029
1100
  /** @type {import('websql-configurable/lib/websql/WebSQLTransaction.js').SqlErrorCallback} */ (abort)
1030
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. */
1031
1103
  } catch (err) {
1032
1104
  // Browser errs when transaction has ended and since it most likely already erred here,
1033
1105
  // we call to abort
1034
1106
  abort();
1035
1107
  }
1108
+ /* c8 ignore stop -- see comment above */
1036
1109
  } else {
1037
1110
  abort(null, {code: 0});
1038
1111
  }
@@ -1048,6 +1121,7 @@ IDBTransaction.prototype.abort = function () {
1048
1121
  if (!(me instanceof IDBTransaction)) {
1049
1122
  throw new TypeError('Illegal invocation');
1050
1123
  }
1124
+ /* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
1051
1125
  if (CFG.DEBUG) { console.log('The transaction was aborted', me); }
1052
1126
  IDBTransaction.__assertNotFinished(me);
1053
1127
  if (me.__committed) {
@@ -1077,6 +1151,7 @@ IDBTransaction.prototype.commit = function () {
1077
1151
  if (!me.__active || !me.__handlerActive || me.__committed) {
1078
1152
  throw createDOMException('InvalidStateError', 'Failed to execute \'commit\' on \'IDBTransaction\': The transaction is not active.');
1079
1153
  }
1154
+ /* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
1080
1155
  if (CFG.DEBUG) { console.log('The transaction was explicitly committed', me); }
1081
1156
  me.__committed = true;
1082
1157
  };
@@ -1118,6 +1193,7 @@ IDBTransaction.__assertNotFinished = function (tx) {
1118
1193
  };
1119
1194
 
1120
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. */
1121
1197
  /**
1122
1198
  *
1123
1199
  * @param {IDBTransactionFull} tx
@@ -1133,6 +1209,7 @@ IDBTransaction.__assertNotFinishedObjectStoreMethod = function (tx) {
1133
1209
  throw err;
1134
1210
  }
1135
1211
  };
1212
+ /* c8 ignore stop -- see comment above */
1136
1213
 
1137
1214
  /**
1138
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) {