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
@@ -18,8 +18,9 @@ const readonlyProperties = ['keyPath', 'indexNames', 'transaction', 'autoIncreme
18
18
 
19
19
  /**
20
20
  * IndexedDB Object Store.
21
- * @see http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBObjectStore
21
+ * @see https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBObjectStore
22
22
  * @class
23
+ * @throws {TypeError}
23
24
  */
24
25
  function IDBObjectStore () {
25
26
  throw new TypeError('Illegal constructor');
@@ -85,89 +86,93 @@ IDBObjectStore.__createInstance = function (storeProperties, transaction) {
85
86
  me.__indexNames = DOMStringList.__createInstance();
86
87
  const {indexList} = storeProperties;
87
88
  for (const indexName in indexList) {
88
- if (Object.hasOwn(indexList, indexName)) {
89
- const index = IDBIndex.__createInstance(me, indexList[indexName]);
90
- me.__indexes[index.name] = index;
91
- if (!index.__deleted) {
92
- me.indexNames.push(index.name);
93
- }
89
+ if (!Object.hasOwn(indexList, indexName)) {
90
+ continue;
91
+ }
92
+
93
+ const index = IDBIndex.__createInstance(me, indexList[indexName]);
94
+ me.__indexes[index.name] = index;
95
+ if (!index.__deleted) {
96
+ me.indexNames.push(index.name);
94
97
  }
95
98
  }
96
99
  me.__oldIndexNames = me.indexNames.clone();
97
- Object.defineProperty(this, '__currentName', {
98
- get () {
99
- return '__pendingName' in this ? this.__pendingName : this.name;
100
- }
101
- });
102
- Object.defineProperty(this, 'name', {
103
- enumerable: false,
104
- configurable: false,
105
- /**
106
- * @this {IDBObjectStoreFull}
107
- * @returns {string}
108
- */
109
- get () {
110
- return this.__name;
111
- },
112
- /**
113
- * @param {string} name
114
- * @this {IDBObjectStoreFull}
115
- * @returns {void}
116
- */
117
- set (name) {
118
- const me = this;
119
- name = util.convertToDOMString(name);
120
- const oldName = me.name;
121
- IDBObjectStoreAlias.__invalidStateIfDeleted(me);
122
- IDBTransaction.__assertVersionChange(me.transaction);
123
- IDBTransaction.__assertActive(me.transaction);
124
- if (oldName === name) {
125
- return;
126
- }
127
- if (me.__idbdb.__objectStores[name] && !me.__idbdb.__objectStores[name].__pendingDelete) {
128
- throw createDOMException('ConstraintError', 'Object store "' + name + '" already exists in ' + me.__idbdb.name);
100
+ Object.defineProperties(this, {
101
+ __currentName: {
102
+ get () {
103
+ return '__pendingName' in this ? this.__pendingName : this.name;
129
104
  }
105
+ },
106
+ name: {
107
+ enumerable: false,
108
+ configurable: false,
109
+ /**
110
+ * @this {IDBObjectStoreFull}
111
+ * @returns {string}
112
+ */
113
+ get () {
114
+ return this.__name;
115
+ },
116
+ /**
117
+ * @param {string} name
118
+ * @this {IDBObjectStoreFull}
119
+ * @returns {void}
120
+ */
121
+ set (name) {
122
+ const me = this;
123
+ name = util.convertToDOMString(name);
124
+ const oldName = me.name;
125
+ IDBObjectStoreAlias.__invalidStateIfDeleted(me);
126
+ IDBTransaction.__assertVersionChange(me.transaction);
127
+ IDBTransaction.__assertActive(me.transaction);
128
+ if (oldName === name) {
129
+ return;
130
+ }
131
+ if (Object.hasOwn(me.__idbdb.__objectStores, name) && !me.__idbdb.__objectStores[name].__pendingDelete) {
132
+ throw createDOMException('ConstraintError', 'Object store "' + name + '" already exists in ' + me.__idbdb.name);
133
+ }
130
134
 
131
- me.__name = name;
135
+ me.__name = name;
132
136
 
133
- const oldStore = me.__idbdb.__objectStores[oldName];
134
- oldStore.__name = name; // Fix old references
135
- me.__idbdb.__objectStores[name] = oldStore; // Ensure new reference accessible
136
- delete me.__idbdb.__objectStores[oldName]; // Ensure won't be found
137
+ const oldStore = me.__idbdb.__objectStores[oldName];
138
+ oldStore.__name = name; // Fix old references
139
+ me.__idbdb.__objectStores[name] = oldStore; // Ensure new reference accessible
140
+ delete me.__idbdb.__objectStores[oldName]; // Ensure won't be found
137
141
 
138
- me.__idbdb.objectStoreNames.splice(me.__idbdb.objectStoreNames.indexOf(oldName), 1, name);
142
+ me.__idbdb.objectStoreNames.splice(me.__idbdb.objectStoreNames.indexOf(oldName), 1, name);
139
143
 
140
- const oldHandle = /** @type {IDBObjectStoreFull} */ (
144
+ const oldHandle = /** @type {IDBObjectStoreFull} */ (
145
+ /** @type {import('./IDBTransaction.js').IDBTransactionFull} */ (
146
+ me.transaction
147
+ ).__storeHandles[oldName]
148
+ );
149
+ oldHandle.__name = name; // Fix old references
141
150
  /** @type {import('./IDBTransaction.js').IDBTransactionFull} */ (
142
151
  me.transaction
143
- ).__storeHandles[oldName]
144
- );
145
- oldHandle.__name = name; // Fix old references
146
- /** @type {import('./IDBTransaction.js').IDBTransactionFull} */ (
147
- me.transaction
148
- ).__storeHandles[name] = oldHandle; // Ensure new reference accessible
149
-
150
- me.__pendingName = oldName;
151
-
152
- const sql = 'UPDATE __sys__ SET "name" = ? WHERE "name" = ?';
153
- const sqlValues = [util.escapeSQLiteStatement(name), util.escapeSQLiteStatement(oldName)];
154
- if (CFG.DEBUG) { console.log(sql, sqlValues); }
155
- /** @type {import('./IDBTransaction.js').IDBTransactionFull} */ (
156
- me.transaction
157
- ).__addNonRequestToTransactionQueue(function objectStoreClear (tx, args, success, error) {
158
- tx.executeSql(sql, sqlValues, function (tx) {
159
- // This SQL preserves indexes per https://www.sqlite.org/lang_altertable.html
160
- const sql = 'ALTER TABLE ' + util.escapeStoreNameForSQL(oldName) + ' RENAME TO ' + util.escapeStoreNameForSQL(name);
161
- if (CFG.DEBUG) { console.log(sql); }
162
- tx.executeSql(sql, [], function () {
163
- delete me.__pendingName;
164
- success();
152
+ ).__storeHandles[name] = oldHandle; // Ensure new reference accessible
153
+
154
+ me.__pendingName = oldName;
155
+
156
+ const sql = 'UPDATE __sys__ SET "name" = ? WHERE "name" = ?';
157
+ const sqlValues = [util.escapeSQLiteStatement(name), util.escapeSQLiteStatement(oldName)];
158
+ if (CFG.DEBUG) { console.log(sql, sqlValues); }
159
+ /** @type {import('./IDBTransaction.js').IDBTransactionFull} */ (
160
+ me.transaction
161
+ ).__addNonRequestToTransactionQueue(function objectStoreClear (tx, args, success, error) {
162
+ tx.executeSql(sql, sqlValues, function (tx) {
163
+ // This SQL preserves indexes per https://www.sqlite.org/lang_altertable.html
164
+ const sql = 'ALTER TABLE ' + util.escapeStoreNameForSQL(oldName) + ' RENAME TO ' + util.escapeStoreNameForSQL(name);
165
+ if (CFG.DEBUG) { console.log(sql); }
166
+ tx.executeSql(sql, [], function () {
167
+ delete me.__pendingName;
168
+ success();
169
+ });
170
+ }, function (tx, err) {
171
+ error(err);
172
+ return false;
165
173
  });
166
- }, function (tx, err) {
167
- error(err);
168
- return false;
169
174
  });
170
- });
175
+ }
171
176
  }
172
177
  });
173
178
  }
@@ -239,7 +244,7 @@ IDBObjectStore.__createObjectStore = function (db, store) {
239
244
  );
240
245
 
241
246
  const storeHandles = transaction.__storeHandles;
242
- if (!storeHandles[storeName] ||
247
+ if (!Object.hasOwn(storeHandles, storeName) ||
243
248
  // These latter conditions are to allow store
244
249
  // recreation to create new clone object
245
250
  storeHandles[storeName].__pendingDelete ||
@@ -609,7 +614,6 @@ IDBObjectStore.prototype.__insertData = function (tx, encoded, value, clonedKeyO
609
614
  return false;
610
615
  });
611
616
  return undefined;
612
- // eslint-disable-next-line sonarjs/no-invariant-returns -- Convenient
613
617
  }).catch(function (err) {
614
618
  /**
615
619
  * @returns {void}
@@ -1036,7 +1040,7 @@ IDBObjectStore.prototype.index = function (indexName) {
1036
1040
  throw createDOMException('NotFoundError', 'Index "' + indexName + '" does not exist on ' + me.__currentName);
1037
1041
  }
1038
1042
 
1039
- if (!me.__indexHandles[indexName] ||
1043
+ if (!Object.hasOwn(me.__indexHandles, indexName) ||
1040
1044
  me.__indexes[indexName].__pendingDelete ||
1041
1045
  me.__indexes[indexName].__deleted
1042
1046
  ) {
@@ -1069,7 +1073,7 @@ IDBObjectStore.prototype.createIndex = function (indexName, keyPath /* , optiona
1069
1073
  IDBTransaction.__assertVersionChange(me.transaction);
1070
1074
  IDBObjectStore.__invalidStateIfDeleted(me);
1071
1075
  IDBTransaction.__assertActive(me.transaction);
1072
- if (me.__indexes[indexName] && !me.__indexes[indexName].__deleted && !me.__indexes[indexName].__pendingDelete) {
1076
+ if (Object.hasOwn(me.__indexes, indexName) && !me.__indexes[indexName].__deleted && !me.__indexes[indexName].__pendingDelete) {
1073
1077
  throw createDOMException('ConstraintError', 'Index "' + indexName + '" already exists on ' + me.__currentName);
1074
1078
  }
1075
1079
 
@@ -1081,7 +1085,7 @@ IDBObjectStore.prototype.createIndex = function (indexName, keyPath /* , optiona
1081
1085
  throw createDOMException('InvalidAccessError', 'The keyPath argument was an array and the multiEntry option is true.');
1082
1086
  }
1083
1087
 
1084
- optionalParameters = optionalParameters || {};
1088
+ optionalParameters ||= {};
1085
1089
  /** @type {import('./IDBIndex.js').IDBIndexProperties} */
1086
1090
  const indexProperties = {
1087
1091
  columnName: indexName,
@@ -1121,6 +1125,7 @@ IDBObjectStore.prototype.deleteIndex = function (name) {
1121
1125
  IDBIndex.__deleteIndex(me, index);
1122
1126
  };
1123
1127
 
1128
+ /* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
1124
1129
  util.defineReadonlyOuterInterface(IDBObjectStore.prototype, readonlyProperties);
1125
1130
  util.defineOuterInterface(IDBObjectStore.prototype, ['name']);
1126
1131
 
@@ -1129,5 +1134,6 @@ IDBObjectStore.prototype[Symbol.toStringTag] = 'IDBObjectStorePrototype';
1129
1134
  Object.defineProperty(IDBObjectStore, 'prototype', {
1130
1135
  writable: false
1131
1136
  });
1137
+ /* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
1132
1138
 
1133
1139
  export default IDBObjectStore;
package/src/IDBRequest.js CHANGED
@@ -8,8 +8,9 @@ const doneFlagGetters = ['result', 'error'];
8
8
 
9
9
  /**
10
10
  * The IDBRequest Object that is returns for all async calls.
11
- * @see http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#request-api
11
+ * @see https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#request-api
12
12
  * @class
13
+ * @throws {TypeError}
13
14
  */
14
15
  function IDBRequest () {
15
16
  throw new TypeError('Illegal constructor');
@@ -48,21 +49,26 @@ IDBRequest.__super = function IDBRequest () {
48
49
  legacyOutputDidListenersThrowFlag: true // Event hook for IndexedB
49
50
  });
50
51
  doneFlagGetters.forEach((prop) => {
51
- Object.defineProperty(this, '__' + prop, {
52
- enumerable: false,
53
- configurable: false,
54
- writable: true
55
- });
56
- Object.defineProperty(this, prop, {
57
- enumerable: true,
58
- configurable: true,
59
- get () {
60
- if (!this.__done) {
61
- throw createDOMException('InvalidStateError', "Can't get " + prop + '; the request is still pending.');
52
+ Object.defineProperties(
53
+ this,
54
+ {
55
+ ['__' + prop]: {
56
+ enumerable: false,
57
+ configurable: false,
58
+ writable: true
59
+ },
60
+ [prop]: {
61
+ enumerable: true,
62
+ configurable: true,
63
+ get () {
64
+ if (!this.__done) {
65
+ throw createDOMException('InvalidStateError', "Can't get " + prop + '; the request is still pending.');
66
+ }
67
+ return this['__' + prop];
68
+ }
62
69
  }
63
- return this['__' + prop];
64
70
  }
65
- });
71
+ );
66
72
  });
67
73
  util.defineReadonlyProperties(this, readonlyProperties, {
68
74
  readyState: {
@@ -106,6 +112,7 @@ IDBRequest.prototype.__getParent = function () {
106
112
  return this.__transaction;
107
113
  };
108
114
 
115
+ /* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
109
116
  // Illegal invocations
110
117
  util.defineReadonlyOuterInterface(IDBRequest.prototype, readonlyProperties);
111
118
  util.defineReadonlyOuterInterface(IDBRequest.prototype, doneFlagGetters);
@@ -123,16 +130,18 @@ IDBRequest.__super.prototype = IDBRequest.prototype;
123
130
  Object.defineProperty(IDBRequest, 'prototype', {
124
131
  writable: false
125
132
  });
133
+ /* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
126
134
 
127
135
  const openListeners = ['onblocked', 'onupgradeneeded'];
128
136
 
129
137
  /**
130
- * @typedef {IDBRequestFull & IDBOpenDBRequest & {}} IDBOpenDBRequestFull
138
+ * @typedef {IDBRequestFull & IDBOpenDBRequest} IDBOpenDBRequestFull
131
139
  */
132
140
 
133
141
  /**
134
142
  * The IDBOpenDBRequest called when a database is opened.
135
143
  * @class
144
+ * @throws {TypeError}
136
145
  */
137
146
  function IDBOpenDBRequest () {
138
147
  throw new TypeError('Illegal constructor');
@@ -141,12 +150,14 @@ function IDBOpenDBRequest () {
141
150
  // @ts-expect-error It's ok
142
151
  IDBOpenDBRequest.prototype = Object.create(IDBRequest.prototype);
143
152
 
153
+ /* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
144
154
  Object.defineProperty(IDBOpenDBRequest.prototype, 'constructor', {
145
155
  enumerable: false,
146
156
  writable: true,
147
157
  configurable: true,
148
158
  value: IDBOpenDBRequest
149
159
  });
160
+ /* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
150
161
 
151
162
  const IDBOpenDBRequestAlias = IDBOpenDBRequest;
152
163
  /**
@@ -175,6 +186,7 @@ IDBOpenDBRequest.__createInstance = function () {
175
186
  return new IDBOpenDBRequest();
176
187
  };
177
188
 
189
+ /* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
178
190
  util.defineOuterInterface(IDBOpenDBRequest.prototype, openListeners);
179
191
 
180
192
  IDBOpenDBRequest.prototype[Symbol.toStringTag] = 'IDBOpenDBRequestPrototype';
@@ -182,5 +194,6 @@ IDBOpenDBRequest.prototype[Symbol.toStringTag] = 'IDBOpenDBRequestPrototype';
182
194
  Object.defineProperty(IDBOpenDBRequest, 'prototype', {
183
195
  writable: false
184
196
  });
197
+ /* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
185
198
 
186
199
  export {IDBRequest, IDBOpenDBRequest};
@@ -50,6 +50,7 @@ const readonlyProperties = ['objectStoreNames', 'mode', 'db', 'error'];
50
50
  * },
51
51
  * __requestsFinished: boolean,
52
52
  * __transFinishedCb: (err: boolean, cb: ((bool?: boolean) => void)) => void,
53
+ * __callTransFinishedCb: (err: boolean, cb: ((bool?: boolean) => void)) => void,
53
54
  * __transactionEndCallback: () => void,
54
55
  * __transactionFinished: boolean,
55
56
  * __completed: boolean,
@@ -85,8 +86,9 @@ const readonlyProperties = ['objectStoreNames', 'mode', 'db', 'error'];
85
86
 
86
87
  /**
87
88
  * The IndexedDB Transaction.
88
- * @see http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBTransaction
89
+ * @see https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBTransaction
89
90
  * @class
91
+ * @throws {TypeError}
90
92
  */
91
93
  function IDBTransaction () {
92
94
  throw new TypeError('Illegal constructor');
@@ -108,6 +110,7 @@ IDBTransaction.__createInstance = function (db, storeNames, mode) {
108
110
  // @ts-expect-error It's ok
109
111
  me[Symbol.toStringTag] = 'IDBTransaction';
110
112
  util.defineReadonlyProperties(me, readonlyProperties);
113
+ // eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Debugging only
111
114
  me.__id = ++uniqueID; // for debugging simultaneous transactions
112
115
  me.__active = true;
113
116
  me.__running = false;
@@ -155,6 +158,35 @@ IDBTransaction.prototype = EventTargetFactory.createInstance({
155
158
  IDBTransaction.prototype.__transFinishedCb = function (err, cb) {
156
159
  cb(Boolean(err));
157
160
  };
161
+
162
+ /**
163
+ * In Node, the real (SQL-commit-capable) `__transFinishedCb` is only
164
+ * installed once the underlying WebSQL driver's own SQL-queue-idle check
165
+ * has fired at least once for this transaction (asynchronously, via the
166
+ * `nonstandardTransCb` passed to `db.transaction`/`.readTransaction`).
167
+ * Since our own request processing can now finish synchronously (e.g., a
168
+ * trivial upgrade using a synchronous SQL driver), it is possible to reach
169
+ * transaction completion here before that has happened, in which case
170
+ * `__transFinishedCb` is still the non-committing default above. Calling
171
+ * that default directly would silently skip the actual SQL commit and
172
+ * leave the underlying WebSQL transaction "running" forever, hanging any
173
+ * later transaction on that same database connection. So, if the real
174
+ * callback isn't installed yet, defer and retry until it is.
175
+ * @this {IDBTransactionFull}
176
+ * @param {boolean} err
177
+ * @param {(bool?: boolean) => void} cb
178
+ * @returns {void}
179
+ */
180
+ IDBTransaction.prototype.__callTransFinishedCb = function (err, cb) {
181
+ const me = this;
182
+ if (me.__transFinishedCb === IDBTransaction.prototype.__transFinishedCb) {
183
+ setTimeout(() => {
184
+ me.__callTransFinishedCb(err, cb);
185
+ }, 0);
186
+ return;
187
+ }
188
+ me.__transFinishedCb(err, cb);
189
+ };
158
190
  /**
159
191
  * @this {IDBTransactionFull}
160
192
  * @returns {void}
@@ -212,7 +244,7 @@ IDBTransaction.prototype.__executeRequests = function () {
212
244
  me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after success).'));
213
245
  return;
214
246
  }
215
- executeNextRequest();
247
+ util.runContinuationSafely(executeNextRequest);
216
248
  }
217
249
 
218
250
  /**
@@ -280,7 +312,7 @@ IDBTransaction.prototype.__executeRequests = function () {
280
312
  try {
281
313
  q = me.__requests[i];
282
314
  if (!q.req) {
283
- q.op(tx, q.args, executeNextRequest, error);
315
+ q.op(tx, q.args, () => util.runContinuationSafely(executeNextRequest), error);
284
316
  return;
285
317
  }
286
318
  if (q.req.__done) { // Avoid continuing with aborted requests
@@ -509,7 +541,7 @@ IDBTransaction.prototype.objectStore = function (objectStoreName) {
509
541
  throw createDOMException('NotFoundError', objectStoreName + ' does not exist in ' + me.db.name);
510
542
  }
511
543
 
512
- if (!me.__storeHandles[objectStoreName] ||
544
+ if (!Object.hasOwn(me.__storeHandles, objectStoreName) ||
513
545
  // These latter conditions are to allow store
514
546
  // recreation to create new clone object
515
547
  me.__storeHandles[objectStoreName].__pendingDelete ||
@@ -615,7 +647,7 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
615
647
  }
616
648
  q.req.dispatchEvent(reqEvt); // No need to catch errors
617
649
  resolve();
618
- });
650
+ }, 0);
619
651
  }
620
652
  );
621
653
  });
@@ -626,7 +658,7 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
626
658
  me.dispatchEvent(evt);
627
659
  me.__storeHandles = {};
628
660
  me.dispatchEvent(createEvent('__abort'));
629
- });
661
+ }, 0);
630
662
  return undefined;
631
663
  }).catch((err) => {
632
664
  console.log('Abort error');
@@ -752,6 +784,7 @@ IDBTransaction.prototype.__getParent = function () {
752
784
  return this.db;
753
785
  };
754
786
 
787
+ /* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
755
788
  util.defineOuterInterface(IDBTransaction.prototype, listeners);
756
789
  util.defineReadonlyOuterInterface(IDBTransaction.prototype, readonlyProperties);
757
790
 
@@ -765,5 +798,6 @@ Object.defineProperty(IDBTransaction.prototype, 'constructor', {
765
798
  Object.defineProperty(IDBTransaction, 'prototype', {
766
799
  writable: false
767
800
  });
801
+ /* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
768
802
 
769
803
  export default IDBTransaction;
@@ -29,6 +29,7 @@ IDBVersionChangeEvent.prototype[Symbol.toStringTag] = 'IDBVersionChangeEventProt
29
29
  * @typedef {number} Integer
30
30
  */
31
31
 
32
+ /* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
32
33
  readonlyProperties.forEach((prop) => {
33
34
  // Ensure for proper interface testing that "get <name>" is the function name
34
35
  const o = {
@@ -73,5 +74,6 @@ Object.defineProperty(IDBVersionChangeEvent.prototype, 'constructor', {
73
74
  Object.defineProperty(IDBVersionChangeEvent, 'prototype', {
74
75
  writable: false
75
76
  });
77
+ /* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
76
78
 
77
79
  export default IDBVersionChangeEvent;
package/src/Key.js CHANGED
@@ -64,12 +64,15 @@ const keyTypeToEncodedChar = {
64
64
  binary: 500,
65
65
  array: 600
66
66
  };
67
+
68
+ /* eslint-disable unicorn/no-top-level-side-effects -- Would be good */
67
69
  const keyTypes = /** @type {(KeyType|"invalid")[]} */ (Object.keys(keyTypeToEncodedChar));
68
70
  keyTypes.forEach((k) => {
69
71
  keyTypeToEncodedChar[k] = String.fromCodePoint(
70
72
  /** @type {number} */ (keyTypeToEncodedChar[k])
71
73
  );
72
74
  });
75
+ /* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
73
76
 
74
77
  const encodedCharToKeyType = keyTypes.reduce((o, k) => {
75
78
  o[keyTypeToEncodedChar[k]] = k;
@@ -160,15 +163,14 @@ const types = {
160
163
  if (key > -1) {
161
164
  sign = signValues.indexOf('smallNegative');
162
165
  exponent = padBase32Exponent(significantDigitIndex);
163
- mantissa = flipBase32(padBase32Mantissa(key32));
164
166
  // Non-negative exponent case:
165
167
  } else {
166
168
  sign = signValues.indexOf('bigNegative');
167
169
  exponent = flipBase32(padBase32Exponent(
168
170
  (decimalIndex !== -1) ? decimalIndex : key32.length
169
171
  ));
170
- mantissa = flipBase32(padBase32Mantissa(key32));
171
172
  }
173
+ mantissa = flipBase32(padBase32Mantissa(key32));
172
174
  // Non-negative cases:
173
175
  // Negative exponent case:
174
176
  } else if (key < 1) {
@@ -208,9 +210,9 @@ const types = {
208
210
 
209
211
  switch (signValues[sign]) {
210
212
  case 'negativeInfinity':
211
- return Number.NEGATIVE_INFINITY;
213
+ return -Infinity;
212
214
  case 'positiveInfinity':
213
- return Number.POSITIVE_INFINITY;
215
+ return Infinity;
214
216
  case 'bigPositive':
215
217
  return pow32(mantissa, exponent);
216
218
  case 'smallPositive':
@@ -281,14 +283,22 @@ const types = {
281
283
  encoded[i] = encodedItem;
282
284
  }
283
285
  encoded.push(keyTypeToEncodedChar.invalid + '-'); // append an extra item, so empty arrays sort correctly
284
- return keyTypeToEncodedChar.array + '-' + JSON.stringify(encoded);
286
+ let encodedKey = JSON.stringify(encoded);
287
+ if (CFG.escapeNULForSQLiteStatements === false) {
288
+ encodedKey = encodedKey.replaceAll(String.raw`\u0000`, '\0');
289
+ }
290
+ return keyTypeToEncodedChar.array + '-' + encodedKey;
285
291
  },
286
292
  /**
287
293
  * @param {string} key
288
294
  * @returns {ValueTypeArray}
289
295
  */
290
296
  decode (key) {
291
- const decoded = JSON.parse(key.slice(2));
297
+ let decodedKey = key.slice(2);
298
+ if (CFG.escapeNULForSQLiteStatements === false) {
299
+ decodedKey = decodedKey.replaceAll('\0', String.raw`\u0000`);
300
+ }
301
+ const decoded = JSON.parse(decodedKey);
292
302
  decoded.pop(); // remove the extra item
293
303
  for (let i = 0; i < decoded.length; i++) {
294
304
  const item = decoded[i];
@@ -336,7 +346,7 @@ const types = {
336
346
  decode (key) {
337
347
  // Set the entries in buffer's [[ArrayBufferData]] to those in `value`
338
348
  const k = key.slice(2);
339
- const arr = k.length ? k.split(',').map((s) => Number.parseInt(s)) : [];
349
+ const arr = k.length ? k.split(',').map(Number) : [];
340
350
  const buffer = new ArrayBuffer(arr.length);
341
351
  const uint8 = new Uint8Array(buffer);
342
352
  uint8.set(arr);
@@ -417,7 +427,7 @@ function pow32 (mantissa, exponent) {
417
427
  * @returns {Float}
418
428
  */
419
429
  function roundToPrecision (num, precision = 16) {
420
- return Number.parseFloat(num.toPrecision(precision));
430
+ return Number(num.toPrecision(precision));
421
431
  }
422
432
 
423
433
  /**
@@ -481,7 +491,7 @@ function convertValueToMultiEntryKey (input) {
481
491
  */
482
492
  function getCopyBytesHeldByBufferSource (O) {
483
493
  let offset = 0;
484
- let length = 0;
494
+ let length;
485
495
  if (ArrayBuffer.isView(O)) { // Has [[ViewedArrayBuffer]] internal slot
486
496
  const arrayBuffer = O.buffer;
487
497
  if (arrayBuffer === undefined) {
@@ -518,7 +528,7 @@ function getCopyBytesHeldByBufferSource (O) {
518
528
  * @returns {KeyValueObject}
519
529
  */
520
530
  function convertValueToKeyValueDecoded (input, seen, multiEntry, fullKeys) {
521
- seen = seen || [];
531
+ seen ||= [];
522
532
  if (seen.includes(input)) {
523
533
  return {
524
534
  type: 'array',
@@ -868,7 +878,6 @@ function findMultiEntryMatches (keyEntry, range) {
868
878
  continue;
869
879
  }
870
880
  if (key.length === 1) {
871
- // eslint-disable-next-line sonarjs/updated-loop-counter -- Convenient
872
881
  key = key[0];
873
882
  } else {
874
883
  const nested = findMultiEntryMatches(key, range);
@@ -1041,9 +1050,14 @@ function assignCurrentNumber (tx, store, num, successCb, failCb) {
1041
1050
  * @returns {void}
1042
1051
  */
1043
1052
  function setCurrentNumber (tx, store, num, successCb, failCb) {
1044
- num = num === MAX_ALLOWED_CURRENT_NUMBER
1045
- ? num + 2 // Since incrementing by one will have no effect in JavaScript on this unsafe max, we represent the max as a number incremented by two. The getting of the current number is never returned to the user and is only used in safe comparisons, so it is safe for us to represent it in this manner
1046
- : num + 1;
1053
+ num = 1 + (num === MAX_ALLOWED_CURRENT_NUMBER
1054
+ // Since incrementing by one will have no effect in JavaScript on this
1055
+ // unsafe max, we represent the max as a number incremented by two.
1056
+ // The getting of the current number is never returned to the user and
1057
+ // is only used in safe comparisons, so it is safe for us to represent
1058
+ // it in this manner
1059
+ ? num + 1
1060
+ : num);
1047
1061
  return assignCurrentNumber(tx, store, num, successCb, failCb);
1048
1062
  }
1049
1063
 
package/src/Sca.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
 
5
5
  import {createDOMException, ShimDOMException} from './DOMException.js';
6
6
 
7
- // See: http://stackoverflow.com/questions/42170826/categories-for-rejection-by-the-structured-cloning-algorithm
7
+ // See: https://stackoverflow.com/questions/42170826/categories-for-rejection-by-the-structured-cloning-algorithm
8
8
 
9
9
  let typeson = new Typeson().register(structuredCloningThrowing);
10
10
 
@@ -14,6 +14,7 @@ let typeson = new Typeson().register(structuredCloningThrowing);
14
14
  * @returns {void}
15
15
  */
16
16
  function register (func) {
17
+ // eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Should be one-time cache
17
18
  typeson = new Typeson().register(func(structuredCloningThrowing));
18
19
  }
19
20