indexeddbshim 16.1.0 → 17.1.0

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 (82) hide show
  1. package/README.md +65 -3
  2. package/badges/licenses-badge-dev.svg +1 -1
  3. package/badges/licenses-badge.svg +1 -1
  4. package/dist/CFG.d.ts +1 -0
  5. package/dist/CFG.d.ts.map +1 -1
  6. package/dist/DOMException.d.ts.map +1 -1
  7. package/dist/DOMStringList.d.ts.map +1 -1
  8. package/dist/IDBCursor.d.ts +12 -3
  9. package/dist/IDBCursor.d.ts.map +1 -1
  10. package/dist/IDBDatabase.d.ts +2 -1
  11. package/dist/IDBDatabase.d.ts.map +1 -1
  12. package/dist/IDBFactory.d.ts +2 -1
  13. package/dist/IDBFactory.d.ts.map +1 -1
  14. package/dist/IDBIndex.d.ts +2 -1
  15. package/dist/IDBIndex.d.ts.map +1 -1
  16. package/dist/IDBKeyRange.d.ts +1 -1
  17. package/dist/IDBKeyRange.d.ts.map +1 -1
  18. package/dist/IDBObjectStore.d.ts +2 -1
  19. package/dist/IDBObjectStore.d.ts.map +1 -1
  20. package/dist/IDBRequest.d.ts +5 -3
  21. package/dist/IDBRequest.d.ts.map +1 -1
  22. package/dist/IDBTransaction.d.ts +23 -1
  23. package/dist/IDBTransaction.d.ts.map +1 -1
  24. package/dist/Key.d.ts.map +1 -1
  25. package/dist/Sca.d.ts.map +1 -1
  26. package/dist/UnicodeIdentifiers.d.ts.map +1 -1
  27. package/dist/browser-noninvasive.d.ts.map +1 -1
  28. package/dist/indexeddbshim-Key.js +1863 -1669
  29. package/dist/indexeddbshim-Key.js.map +1 -1
  30. package/dist/indexeddbshim-Key.min.js +2 -2
  31. package/dist/indexeddbshim-Key.min.js.map +1 -1
  32. package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs +2373 -1893
  33. package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
  34. package/dist/indexeddbshim-UnicodeIdentifiers.js +3124 -2285
  35. package/dist/indexeddbshim-UnicodeIdentifiers.js.map +1 -1
  36. package/dist/indexeddbshim-UnicodeIdentifiers.min.js +9 -2
  37. package/dist/indexeddbshim-UnicodeIdentifiers.min.js.map +1 -1
  38. package/dist/indexeddbshim-node.cjs +2373 -1893
  39. package/dist/indexeddbshim-node.cjs.map +1 -1
  40. package/dist/indexeddbshim-noninvasive.js +3123 -2284
  41. package/dist/indexeddbshim-noninvasive.js.map +1 -1
  42. package/dist/indexeddbshim-noninvasive.min.js +9 -2
  43. package/dist/indexeddbshim-noninvasive.min.js.map +1 -1
  44. package/dist/indexeddbshim.js +3120 -2282
  45. package/dist/indexeddbshim.js.map +1 -1
  46. package/dist/indexeddbshim.min.js +9 -2
  47. package/dist/indexeddbshim.min.js.map +1 -1
  48. package/dist/node-UnicodeIdentifiers.d.ts +2 -2
  49. package/dist/node-UnicodeIdentifiers.d.ts.map +1 -1
  50. package/dist/node.d.ts +2 -2
  51. package/dist/node.d.ts.map +1 -1
  52. package/dist/nodeSQLiteDatabase.d.ts +65 -0
  53. package/dist/nodeSQLiteDatabase.d.ts.map +1 -0
  54. package/dist/nodeWebSQL.d.ts.map +1 -1
  55. package/dist/util.d.ts +5 -0
  56. package/dist/util.d.ts.map +1 -1
  57. package/package.json +118 -106
  58. package/src/CFG.js +5 -3
  59. package/src/DOMException.js +11 -9
  60. package/src/DOMStringList.js +8 -3
  61. package/src/Event.js +2 -0
  62. package/src/IDBCursor.js +152 -95
  63. package/src/IDBDatabase.js +9 -6
  64. package/src/IDBFactory.js +31 -20
  65. package/src/IDBIndex.js +83 -79
  66. package/src/IDBKeyRange.js +42 -35
  67. package/src/IDBObjectStore.js +83 -77
  68. package/src/IDBRequest.js +28 -15
  69. package/src/IDBTransaction.js +40 -6
  70. package/src/IDBVersionChangeEvent.js +2 -0
  71. package/src/Key.js +28 -14
  72. package/src/Sca.js +2 -1
  73. package/src/UnicodeIdentifiers.js +2 -2
  74. package/src/browser-UnicodeIdentifiers.js +0 -1
  75. package/src/browser-noninvasive.js +0 -1
  76. package/src/browser.js +0 -1
  77. package/src/node-UnicodeIdentifiers.js +6 -2
  78. package/src/node.js +6 -2
  79. package/src/nodeSQLiteDatabase.js +174 -0
  80. package/src/nodeWebSQL.js +1 -3
  81. package/src/setGlobalVars.js +13 -13
  82. package/src/util.js +75 -15
package/src/IDBCursor.js CHANGED
@@ -46,6 +46,9 @@ import CFG from './CFG.js';
46
46
  * __unique: boolean,
47
47
  * __sqlDirection: "DESC"|"ASC",
48
48
  * __matchedKeys: {[key: string]: true},
49
+ * __continuationKey: import('./Key.js').Key|undefined,
50
+ * __continuationPrimaryKey: import('./Key.js').Key|undefined,
51
+ * __multiEntryExhausted: boolean,
49
52
  * __invalidateCache: () => void
50
53
  * }} IDBCursorFull
51
54
  */
@@ -58,6 +61,7 @@ import CFG from './CFG.js';
58
61
 
59
62
  /**
60
63
  * @class
64
+ * @throws {TypeError}
61
65
  */
62
66
  function IDBCursor () {
63
67
  throw new TypeError('Illegal constructor');
@@ -67,7 +71,7 @@ const IDBCursorAlias = IDBCursor;
67
71
  /* eslint-disable func-name-matching -- API */
68
72
  /**
69
73
  * The IndexedDB Cursor Object.
70
- * @see http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBCursor
74
+ * @see https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBCursor
71
75
  * @param {IDBKeyRange} query
72
76
  * @param {string} direction
73
77
  * @param {import('./IDBObjectStore.js').IDBObjectStoreFull} store
@@ -116,6 +120,9 @@ IDBCursor.__super = function IDBCursor (query, direction, store, source, keyColu
116
120
  this.__valueDecoder = this.__keyOnly ? Key : Sca;
117
121
  this.__count = count;
118
122
  this.__prefetchedIndex = -1;
123
+ this.__continuationKey = undefined;
124
+ this.__continuationPrimaryKey = undefined;
125
+ this.__multiEntryExhausted = false;
119
126
  this.__multiEntryIndex = this.__indexSource
120
127
  ? 'multiEntry' in source && source.multiEntry
121
128
  : false;
@@ -151,11 +158,10 @@ IDBCursor.__createInstance = function (...args) {
151
158
  * @returns {void}
152
159
  */
153
160
  IDBCursor.prototype.__find = function (...args /* key, tx, success, error, recordsToLoad */) {
161
+ const [key, primaryKey, tx, success, error, recordsToLoad] = args;
154
162
  if (this.__multiEntryIndex) {
155
- const [key, primaryKey, tx, success, error, recordsToLoad] = args;
156
163
  this.__findMultiEntry(key, primaryKey, tx, success, error, recordsToLoad);
157
164
  } else {
158
- const [key, primaryKey, tx, success, error, recordsToLoad] = args;
159
165
  this.__findBasic(key, primaryKey, tx, success, error, recordsToLoad);
160
166
  }
161
167
  };
@@ -185,7 +191,7 @@ IDBCursor.prototype.__find = function (...args /* key, tx, success, error, recor
185
191
  */
186
192
  IDBCursor.prototype.__findBasic = function (key, primaryKey, tx, success, error, recordsToLoad) {
187
193
  const continueCall = recordsToLoad !== undefined;
188
- recordsToLoad = recordsToLoad || 1;
194
+ recordsToLoad ||= 1;
189
195
 
190
196
  const me = this;
191
197
  const quotedKeyColumnName = util.sqlQuote(me.__keyColumnName);
@@ -270,77 +276,107 @@ const leftBracketRegex = /\[/gu;
270
276
  * @param {SQLTransaction} tx
271
277
  * @param {KeySuccess} success
272
278
  * @param {FindError} error
273
- * @param {Integer|undefined} recordsToLoad
279
+ * @param {Integer} [recordsToLoad]
274
280
  * @this {IDBCursorFull}
275
281
  * @returns {void}
276
282
  */
277
- IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, error, recordsToLoad) {
283
+ IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, error, recordsToLoad = 1) {
278
284
  const me = this;
279
285
 
280
- if (me.__prefetchedData && me.__prefetchedData.length === me.__prefetchedIndex) {
281
- if (CFG.DEBUG) { console.log('Reached end of multiEntry cursor'); }
286
+ if (me.__multiEntryExhausted) {
287
+ if (CFG.DEBUG) { console.log('[multiEntry] Reached end of multiEntry cursor (already exhausted)'); }
282
288
  success(undefined, undefined, undefined);
283
289
  return;
284
290
  }
285
291
 
286
292
  const quotedKeyColumnName = util.sqlQuote(me.__keyColumnName);
287
- const sql = ['SELECT * FROM', util.escapeStoreNameForSQL(me.__store.__currentName)];
288
- /** @type {string[]} */
289
- const sqlValues = [];
290
- sql.push('WHERE', quotedKeyColumnName, 'NOT NULL');
291
- if (me.__range && (me.__range.lower !== undefined && Array.isArray(me.__range.upper))) {
292
- if (me.__range.upper.indexOf(me.__range.lower) === 0) {
293
- sql.push('AND', quotedKeyColumnName, "LIKE ? ESCAPE '^'");
294
- sqlValues.push(
295
- '%' + util.sqlLIKEEscape(
296
- /** @type {string} */ (me.__range.__lowerCached).slice(0, -1)
297
- ) + '%'
298
- );
299
- }
300
- }
293
+ const quotedKey = util.sqlQuote('key');
301
294
 
302
295
  // Determine the ORDER BY direction based on the cursor.
303
296
  const direction = me.__sqlDirection;
304
297
  const op = direction === 'ASC' ? '>' : '<';
305
- const quotedKey = util.sqlQuote('key');
306
298
 
307
- if (primaryKey !== undefined) {
308
- sql.push('AND', quotedKey, op + '= ?');
309
- // Key.convertValueToKey(primaryKey); // Already checked by `continuePrimaryKey`
310
- sqlValues.push(/** @type {string} */ (Key.encode(primaryKey)));
311
- }
312
- if (key !== undefined) {
313
- sql.push('AND', quotedKeyColumnName, op + '= ?');
314
- // Key.convertValueToKey(key); // Already checked by `continue` or `continuePrimaryKey`
315
- sqlValues.push(/** @type {string} */ (Key.encode(key)));
316
- } else if (me.__key !== undefined) {
317
- sql.push('AND', quotedKeyColumnName, op + ' ?');
318
- // Key.convertValueToKey(me.__key); // Already checked when entered
319
- sqlValues.push(/** @type {string} */ (Key.encode(me.__key)));
320
- }
321
-
322
- if (!me.__count) {
323
- // 1. Sort by key
324
- sql.push('ORDER BY', quotedKeyColumnName, direction);
299
+ /**
300
+ * Runs (and, if a batch of underlying rows produces no matching
301
+ * multi-entry values, repeatedly re-runs) the query for the next batch
302
+ * of underlying rows, advancing `me.__continuationKey`/
303
+ * `me.__continuationPrimaryKey` (tracking the last *physical* row
304
+ * scanned) each time, until either some matches are found or the
305
+ * underlying table is exhausted.
306
+ * @returns {void}
307
+ */
308
+ function runQuery () {
309
+ const sql = ['SELECT * FROM', util.escapeStoreNameForSQL(me.__store.__currentName)];
310
+ /** @type {string[]} */
311
+ const sqlValues = [];
312
+ sql.push('WHERE', quotedKeyColumnName, 'NOT NULL');
313
+ if (me.__range && (me.__range.lower !== undefined && Array.isArray(me.__range.upper))) {
314
+ if (me.__range.upper.indexOf(me.__range.lower) === 0) {
315
+ sql.push('AND', quotedKeyColumnName, "LIKE ? ESCAPE '^'");
316
+ sqlValues.push(
317
+ '%' + util.sqlLIKEEscape(
318
+ /** @type {string} */ (me.__range.__lowerCached).slice(0, -1)
319
+ ) + '%'
320
+ );
321
+ }
322
+ }
325
323
 
326
- // 2. Sort by primaryKey (if defined and not unique)
327
- if (!me.__unique && me.__keyColumnName !== 'key') { // Avoid adding 'key' twice
328
- sql.push(',', util.sqlQuote('key'), direction);
324
+ if (primaryKey !== undefined) {
325
+ sql.push('AND', quotedKey, op + '= ?');
326
+ // Key.convertValueToKey(primaryKey); // Already checked by `continuePrimaryKey`
327
+ sqlValues.push(/** @type {string} */ (Key.encode(primaryKey)));
328
+ }
329
+ if (key !== undefined) {
330
+ sql.push('AND', quotedKeyColumnName, op + '= ?');
331
+ // Key.convertValueToKey(key); // Already checked by `continue` or `continuePrimaryKey`
332
+ sqlValues.push(/** @type {string} */ (Key.encode(key)));
333
+ } else if (me.__continuationKey !== undefined) {
334
+ // Resume from the last underlying (physical) row we scanned, not
335
+ // from the last *matching* multi-entry value (which lives in a
336
+ // different key-space than the raw index column and cannot be
337
+ // reliably compared against it, e.g. for array index keys).
338
+ sql.push(
339
+ 'AND (', quotedKeyColumnName, op, '?',
340
+ 'OR (', quotedKeyColumnName, '= ?', 'AND', quotedKey, op, '?))'
341
+ );
342
+ const encodedContinuationKey = /** @type {string} */ (
343
+ Key.encode(me.__continuationKey, true)
344
+ );
345
+ sqlValues.push(
346
+ encodedContinuationKey,
347
+ encodedContinuationKey,
348
+ /** @type {string} */ (Key.encode(me.__continuationPrimaryKey))
349
+ );
329
350
  }
330
351
 
331
- // 3. Sort by position (if defined)
352
+ if (!me.__count) {
353
+ // 1. Sort by key
354
+ sql.push('ORDER BY', quotedKeyColumnName, direction);
332
355
 
333
- if (!me.__unique && me.__indexSource) {
334
- // 4. Sort by object store position (if defined and not unique)
335
- sql.push(',', util.sqlQuote(me.__valueColumnName), direction);
356
+ // 2. Sort by primaryKey (if defined and not unique)
357
+ if (!me.__unique && me.__keyColumnName !== 'key') { // Avoid adding 'key' twice
358
+ sql.push(',', util.sqlQuote('key'), direction);
359
+ }
360
+
361
+ // 3. Sort by position (if defined)
362
+
363
+ if (!me.__unique && me.__indexSource) {
364
+ // 4. Sort by object store position (if defined and not unique)
365
+ sql.push(',', util.sqlQuote(me.__valueColumnName), direction);
366
+ }
367
+ sql.push('LIMIT', String(recordsToLoad));
336
368
  }
337
- sql.push('LIMIT', String(recordsToLoad));
338
- }
339
- const sqlStr = sql.join(' ');
340
- if (CFG.DEBUG) { console.log(sqlStr, sqlValues); }
369
+ const sqlStr = sql.join(' ');
370
+ if (CFG.DEBUG) { console.log('[multiEntry] query', sqlStr, sqlValues); }
371
+
372
+ tx.executeSql(sqlStr, sqlValues, function (tx, data) {
373
+ if (data.rows.length === 0) {
374
+ me.__multiEntryExhausted = true;
375
+ if (CFG.DEBUG) { console.log('[multiEntry] Reached end of multiEntry cursor (no more rows)'); }
376
+ success(undefined, undefined, undefined);
377
+ return;
378
+ }
341
379
 
342
- tx.executeSql(sqlStr, sqlValues, function (tx, data) {
343
- if (data.rows.length > 0) {
344
380
  if (me.__count) { // Avoid caching and other processing below
345
381
  let ct = 0;
346
382
  for (let i = 0; i < data.rows.length; i++) {
@@ -352,6 +388,17 @@ IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, e
352
388
  success(undefined, ct, undefined);
353
389
  return;
354
390
  }
391
+
392
+ // Track how far we've physically scanned, regardless of whether
393
+ // this batch produced any matches, so the next batch (if any)
394
+ // resumes after this one instead of re-scanning or stopping early.
395
+ const lastRawRow = data.rows.item(data.rows.length - 1);
396
+ me.__continuationKey = Key.decode(lastRawRow[me.__keyColumnName], true);
397
+ me.__continuationPrimaryKey = Key.decode(lastRawRow.key);
398
+ if (data.rows.length < recordsToLoad) {
399
+ me.__multiEntryExhausted = true;
400
+ }
401
+
355
402
  const rows = [];
356
403
  for (let i = 0; i < data.rows.length; i++) {
357
404
  const rowItem = data.rows.item(i);
@@ -366,13 +413,25 @@ IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, e
366
413
  matchingKey: /** @type {string} */ (
367
414
  Key.encode(matchingKey, true)
368
415
  ),
369
- key: rowItem.key
416
+ key: rowItem.key,
417
+ [me.__keyColumnName]: rowItem[me.__keyColumnName],
418
+ [me.__valueColumnName]: rowItem[me.__valueColumnName]
370
419
  };
371
- clone[me.__keyColumnName] = rowItem[me.__keyColumnName];
372
- clone[me.__valueColumnName] = rowItem[me.__valueColumnName];
373
420
  rows.push(clone);
374
421
  }
375
422
  }
423
+
424
+ if (rows.length === 0) {
425
+ if (me.__multiEntryExhausted) {
426
+ if (CFG.DEBUG) { console.log('[multiEntry] Reached end of multiEntry cursor (last batch had no matches)'); }
427
+ success(undefined, undefined, undefined);
428
+ return;
429
+ }
430
+ if (CFG.DEBUG) { console.log('[multiEntry] batch had no matches; fetching next batch'); }
431
+ runQuery();
432
+ return;
433
+ }
434
+
376
435
  const reverse = me.direction.indexOf('prev') === 0;
377
436
  rows.sort(function (a, b) {
378
437
  if (a.matchingKey.replaceAll(leftBracketRegex, 'z') < b.matchingKey.replaceAll(leftBracketRegex, 'z')) {
@@ -390,37 +449,28 @@ IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, e
390
449
  return 0;
391
450
  });
392
451
 
393
- if (rows.length > 1) {
394
- me.__prefetchedIndex = 0;
395
- me.__prefetchedData = {
396
- data: rows,
397
- length: rows.length,
398
- /**
399
- * @param {Integer} index
400
- * @returns {RowItemNonNull}
401
- */
402
- item (index) {
403
- return this.data[index];
404
- }
405
- };
406
- if (CFG.DEBUG) { console.log('Preloaded ' + me.__prefetchedData.length + ' records for multiEntry cursor'); }
407
- me.__decode(rows[0], success);
408
- } else if (rows.length === 1) {
409
- if (CFG.DEBUG) { console.log('Reached end of multiEntry cursor'); }
410
- me.__decode(rows[0], success);
411
- } else {
412
- if (CFG.DEBUG) { console.log('Reached end of multiEntry cursor'); }
413
- success(undefined, undefined, undefined);
414
- }
415
- } else {
416
- if (CFG.DEBUG) { console.log('Reached end of multiEntry cursor'); }
417
- success(undefined, undefined, undefined);
418
- }
419
- }, function (tx, err) {
420
- if (CFG.DEBUG) { console.log('Could not execute Cursor.continue', sqlStr, sqlValues); }
421
- error(err);
422
- return false;
423
- });
452
+ me.__prefetchedIndex = 0;
453
+ me.__prefetchedData = {
454
+ data: rows,
455
+ length: rows.length,
456
+ /**
457
+ * @param {Integer} index
458
+ * @returns {RowItemNonNull}
459
+ */
460
+ item (index) {
461
+ return this.data[index];
462
+ }
463
+ };
464
+ if (CFG.DEBUG) { console.log('[multiEntry] Preloaded ' + me.__prefetchedData.length + ' records for multiEntry cursor'); }
465
+ me.__decode(rows[0], success);
466
+ }, function (tx, err) {
467
+ if (CFG.DEBUG) { console.log('[multiEntry] Could not execute Cursor.continue', sqlStr, sqlValues); }
468
+ error(err);
469
+ return false;
470
+ });
471
+ }
472
+
473
+ runQuery();
424
474
  };
425
475
 
426
476
  /**
@@ -496,7 +546,7 @@ IDBCursor.prototype.__decode = function (rowItem, callback) {
496
546
  if (!me.__matchedKeys) {
497
547
  me.__matchedKeys = {};
498
548
  }
499
- if (me.__matchedKeys[rowItem.matchingKey]) {
549
+ if (me.__matchedKeys[rowItem.matchingKey] === true) {
500
550
  callback(undefined, undefined, undefined);
501
551
  return;
502
552
  }
@@ -540,6 +590,7 @@ IDBCursor.prototype.__sourceOrEffectiveObjStoreDeleted = function () {
540
590
  IDBCursor.prototype.__invalidateCache = function () {
541
591
  // @ts-expect-error Why is this not being found?
542
592
  this.__prefetchedData = null;
593
+ this.__multiEntryExhausted = false;
543
594
  };
544
595
 
545
596
  /**
@@ -599,9 +650,8 @@ IDBCursor.prototype.__continueFinish = function (key, primaryKey, advanceState)
599
650
  me.__advanceCount--;
600
651
  me.__key = k;
601
652
  me.__continue(undefined, true);
602
- /** @type {() => void} */ (
603
- executeNextRequest
604
- )(); // We don't call success yet but do need to advance the transaction queue
653
+ // We don't call success yet but do need to advance the transaction queue
654
+ util.runContinuationSafely(/** @type {() => void} */ (executeNextRequest));
605
655
  return;
606
656
  }
607
657
  me.__advanceCount = undefined;
@@ -627,12 +677,12 @@ IDBCursor.prototype.__continueFinish = function (key, primaryKey, advanceState)
627
677
  return;
628
678
  }
629
679
  // @ts-expect-error Todo: Our bug to fix
630
- cursorContinue(tx, args, success, error);
680
+ util.runContinuationSafely(() => cursorContinue(tx, args, success, error));
631
681
  }
632
682
  if (me.__unique && !me.__multiEntryIndex &&
633
683
  encKey === Key.encode(me.key, me.__multiEntryIndex)) {
634
684
  // @ts-expect-error Todo: Our bug to fix
635
- cursorContinue(tx, args, success, error);
685
+ util.runContinuationSafely(() => cursorContinue(tx, args, success, error));
636
686
  return;
637
687
  }
638
688
  checkKey();
@@ -779,6 +829,7 @@ IDBCursor.prototype.update = function (valueToUpdate) {
779
829
  if (cmp(me.primaryKey, evaluatedKey) !== 0) {
780
830
  throw createDOMException('DataError', 'The key of the supplied value to `update` is not equal to the cursor\'s effective key');
781
831
  }
832
+ // eslint-disable-next-line unicorn/prefer-hoisting-branch-code -- Different
782
833
  addToQueue(clonedValue);
783
834
  } else {
784
835
  const clonedValue = Sca.clone(valueToUpdate);
@@ -836,6 +887,7 @@ IDBCursor.prototype.delete = function () {
836
887
 
837
888
  IDBCursor.prototype[Symbol.toStringTag] = 'IDBCursorPrototype';
838
889
 
890
+ /* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
839
891
  util.defineReadonlyOuterInterface(
840
892
  IDBCursor.prototype,
841
893
  ['source', 'direction', 'key', 'primaryKey', 'request']
@@ -843,14 +895,17 @@ util.defineReadonlyOuterInterface(
843
895
  Object.defineProperty(IDBCursor, 'prototype', {
844
896
  writable: false
845
897
  });
898
+ /* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
846
899
 
847
900
  /**
848
901
  * @class
902
+ * @throws {TypeError}
849
903
  */
850
904
  function IDBCursorWithValue () {
851
905
  throw new TypeError('Illegal constructor');
852
906
  }
853
907
 
908
+ /* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
854
909
  // @ts-expect-error It's ok
855
910
  IDBCursorWithValue.prototype = Object.create(IDBCursor.prototype);
856
911
  Object.defineProperty(IDBCursorWithValue.prototype, 'constructor', {
@@ -859,6 +914,7 @@ Object.defineProperty(IDBCursorWithValue.prototype, 'constructor', {
859
914
  configurable: true,
860
915
  value: IDBCursorWithValue
861
916
  });
917
+ /* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
862
918
 
863
919
  const IDBCursorWithValueAlias = IDBCursorWithValue;
864
920
  /**
@@ -884,12 +940,13 @@ IDBCursorWithValue.__createInstance = function (...args) {
884
940
  return new IDBCursorWithValue();
885
941
  };
886
942
 
943
+ /* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
887
944
  util.defineReadonlyOuterInterface(IDBCursorWithValue.prototype, ['value']);
888
-
889
945
  IDBCursorWithValue.prototype[Symbol.toStringTag] = 'IDBCursorWithValuePrototype';
890
946
 
891
947
  Object.defineProperty(IDBCursorWithValue, 'prototype', {
892
948
  writable: false
893
949
  });
950
+ /* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
894
951
 
895
952
  export {IDBCursor, IDBCursorWithValue};
@@ -23,8 +23,9 @@ const readonlyProperties = ['name', 'version', 'objectStoreNames'];
23
23
 
24
24
  /**
25
25
  * IDB Database Object.
26
- * @see http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#database-interface
26
+ * @see https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#database-interface
27
27
  * @class
28
+ * @throws {TypeError}
28
29
  */
29
30
  function IDBDatabase () {
30
31
  this.__versionTransaction = null;
@@ -165,7 +166,7 @@ IDBDatabase.prototype.createObjectStore = function (storeName /* , createOptions
165
166
  throw createDOMException('SyntaxError', 'The keyPath argument contains an invalid key path.');
166
167
  }
167
168
 
168
- if (this.__objectStores[storeName] && !this.__objectStores[storeName].__pendingDelete) {
169
+ if (Object.hasOwn(this.__objectStores, storeName) && !this.__objectStores[storeName].__pendingDelete) {
169
170
  throw createDOMException('ConstraintError', 'Object store "' + storeName + '" already exists in ' + this.name);
170
171
  }
171
172
 
@@ -244,7 +245,8 @@ IDBDatabase.prototype.transaction = function (storeNames /* , mode */) {
244
245
  // Creating new array also ensures sequence is passed by value: https://heycam.github.io/webidl/#idl-sequence
245
246
  ? [...new Set( // to be unique
246
247
  util.convertToSequenceDOMString(storeNames) // iterables have `ToString` applied (and we convert to array for convenience)
247
- )].sort() // must be sorted
248
+ // eslint-disable-next-line unicorn/require-array-sort-compare -- IndexedDB requires code unit comparison (default behavior)
249
+ )].toSorted() // must be sorted
248
250
  : [util.convertToDOMString(storeNames)];
249
251
 
250
252
  /* (function () {
@@ -258,7 +260,7 @@ IDBDatabase.prototype.transaction = function (storeNames /* , mode */) {
258
260
  // prioritizing readonly but not starving readwrite).
259
261
  // Even for readonly transactions, due to [issue 17](https://github.com/nolanlawson/node-websql/issues/17),
260
262
  // we're not currently actually running the SQL requests in parallel.
261
- mode = mode || 'readonly';
263
+ mode ||= 'readonly';
262
264
 
263
265
  IDBTransaction.__assertNotVersionChange(this.__versionTransaction);
264
266
  if (this.__closePending) {
@@ -321,7 +323,7 @@ IDBDatabase.prototype.__forceClose = function (msg) {
321
323
  const evt = createEvent('close');
322
324
  setTimeout(() => {
323
325
  me.dispatchEvent(evt);
324
- });
326
+ }, 0);
325
327
  }
326
328
  };
327
329
  trans.__abortTransaction(createDOMException(
@@ -331,7 +333,7 @@ IDBDatabase.prototype.__forceClose = function (msg) {
331
333
  });
332
334
  me.__transactions = [];
333
335
  };
334
-
336
+ /* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
335
337
  util.defineOuterInterface(IDBDatabase.prototype, listeners);
336
338
  util.defineReadonlyOuterInterface(IDBDatabase.prototype, readonlyProperties);
337
339
 
@@ -345,5 +347,6 @@ Object.defineProperty(IDBDatabase.prototype, 'constructor', {
345
347
  Object.defineProperty(IDBDatabase, 'prototype', {
346
348
  writable: false
347
349
  });
350
+ /* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
348
351
 
349
352
  export default IDBDatabase;