indexeddbshim 17.3.2 → 17.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/IDBCursor.d.ts.map +1 -1
- package/dist/IDBFactory.d.ts.map +1 -1
- package/dist/IDBTransaction.d.ts +8 -6
- package/dist/IDBTransaction.d.ts.map +1 -1
- package/dist/Key.d.ts.map +1 -1
- package/dist/Sca.d.ts.map +1 -1
- package/dist/indexeddbshim-Key.js +52 -13
- package/dist/indexeddbshim-Key.js.map +1 -1
- package/dist/indexeddbshim-Key.min.js +2 -2
- package/dist/indexeddbshim-Key.min.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs +508 -134
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.js +337 -71
- package/dist/indexeddbshim-UnicodeIdentifiers.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js +3 -3
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js.map +1 -1
- package/dist/indexeddbshim-node.cjs +508 -134
- package/dist/indexeddbshim-node.cjs.map +1 -1
- package/dist/indexeddbshim-noninvasive.js +337 -71
- package/dist/indexeddbshim-noninvasive.js.map +1 -1
- package/dist/indexeddbshim-noninvasive.min.js +3 -3
- package/dist/indexeddbshim-noninvasive.min.js.map +1 -1
- package/dist/indexeddbshim.js +337 -71
- package/dist/indexeddbshim.js.map +1 -1
- package/dist/indexeddbshim.min.js +3 -3
- package/dist/indexeddbshim.min.js.map +1 -1
- package/dist/nodeSQLiteDatabase.d.ts.map +1 -1
- package/dist/nodeWebSQL.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/IDBCursor.js +34 -4
- package/src/IDBFactory.js +207 -60
- package/src/IDBTransaction.js +23 -3
- package/src/Key.js +34 -12
- package/src/Sca.js +53 -3
- package/src/nodeSQLiteDatabase.js +92 -26
- package/src/nodeWebSQL.js +8 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! indexeddbshim - v17.3.
|
|
1
|
+
/*! indexeddbshim - v17.3.4 - 8/25/2026 */
|
|
2
2
|
|
|
3
3
|
(function (global, factory) {
|
|
4
4
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
@@ -3549,6 +3549,32 @@
|
|
|
3549
3549
|
}
|
|
3550
3550
|
|
|
3551
3551
|
var _templateObject, _templateObject2;
|
|
3552
|
+
/**
|
|
3553
|
+
* @param {unknown[]} arr
|
|
3554
|
+
* @param {number} index
|
|
3555
|
+
* @param {unknown} val
|
|
3556
|
+
* @returns {void}
|
|
3557
|
+
*/
|
|
3558
|
+
var setArrayValue = function setArrayValue(arr, index, val) {
|
|
3559
|
+
if (Reflect.has(Array.prototype, index)) {
|
|
3560
|
+
Object.defineProperty(arr, index, {
|
|
3561
|
+
value: val,
|
|
3562
|
+
enumerable: true,
|
|
3563
|
+
writable: true,
|
|
3564
|
+
configurable: true
|
|
3565
|
+
});
|
|
3566
|
+
} else {
|
|
3567
|
+
arr[index] = val;
|
|
3568
|
+
}
|
|
3569
|
+
};
|
|
3570
|
+
/**
|
|
3571
|
+
* @param {unknown[]} arr
|
|
3572
|
+
* @param {unknown} val
|
|
3573
|
+
* @returns {void}
|
|
3574
|
+
*/
|
|
3575
|
+
var safePush = function safePush(arr, val) {
|
|
3576
|
+
return setArrayValue(arr, arr.length, val);
|
|
3577
|
+
};
|
|
3552
3578
|
|
|
3553
3579
|
/**
|
|
3554
3580
|
* @typedef {NodeJS.TypedArray|DataView} ArrayBufferView
|
|
@@ -3812,6 +3838,7 @@
|
|
|
3812
3838
|
* @returns {string}
|
|
3813
3839
|
*/
|
|
3814
3840
|
encode: function encode(key) {
|
|
3841
|
+
/** @type {(string|null)[]} */
|
|
3815
3842
|
var encoded = [];
|
|
3816
3843
|
var _iterator = _createForOfIteratorHelper(key.entries()),
|
|
3817
3844
|
_step;
|
|
@@ -3821,14 +3848,14 @@
|
|
|
3821
3848
|
i = _step$value[0],
|
|
3822
3849
|
item = _step$value[1];
|
|
3823
3850
|
var encodedItem = _encode(item, true); // encode the array item
|
|
3824
|
-
encoded
|
|
3851
|
+
setArrayValue(encoded, i, encodedItem);
|
|
3825
3852
|
}
|
|
3826
3853
|
} catch (err) {
|
|
3827
3854
|
_iterator.e(err);
|
|
3828
3855
|
} finally {
|
|
3829
3856
|
_iterator.f();
|
|
3830
3857
|
}
|
|
3831
|
-
encoded
|
|
3858
|
+
safePush(encoded, keyTypeToEncodedChar.invalid + '-'); // append an extra item, so empty arrays sort correctly
|
|
3832
3859
|
var encodedKey = JSON.stringify(encoded);
|
|
3833
3860
|
if (CFG.escapeNULForSQLiteStatements === false) {
|
|
3834
3861
|
encodedKey = encodedKey.replaceAll(String.raw(_templateObject || (_templateObject = _taggedTemplateLiteral(["\0"], ["\\u0000"]))), '\0');
|
|
@@ -3849,7 +3876,7 @@
|
|
|
3849
3876
|
for (var i = 0; i < decoded.length; i++) {
|
|
3850
3877
|
var item = decoded[i];
|
|
3851
3878
|
var decodedItem = _decode(item, true); // decode the item
|
|
3852
|
-
decoded
|
|
3879
|
+
setArrayValue(decoded, i, decodedItem);
|
|
3853
3880
|
}
|
|
3854
3881
|
return decoded;
|
|
3855
3882
|
}
|
|
@@ -4147,7 +4174,7 @@
|
|
|
4147
4174
|
// May throw (from binary)
|
|
4148
4175
|
var arr = /** @type {Array<any>} */input;
|
|
4149
4176
|
var len = arr.length;
|
|
4150
|
-
seen
|
|
4177
|
+
safePush(seen, input);
|
|
4151
4178
|
|
|
4152
4179
|
/** @type {(KeyValueObject|Value)[]} */
|
|
4153
4180
|
var keys = [];
|
|
@@ -4182,7 +4209,7 @@
|
|
|
4182
4209
|
}) || fullKeys && keys.every(function (k) {
|
|
4183
4210
|
return cmp(k, key) !== 0;
|
|
4184
4211
|
})) {
|
|
4185
|
-
keys
|
|
4212
|
+
safePush(keys, fullKeys ? key : key.value);
|
|
4186
4213
|
}
|
|
4187
4214
|
} catch (err) {
|
|
4188
4215
|
if (!multiEntry) {
|
|
@@ -4342,7 +4369,7 @@
|
|
|
4342
4369
|
if (key.failure) {
|
|
4343
4370
|
return true;
|
|
4344
4371
|
}
|
|
4345
|
-
result
|
|
4372
|
+
safePush(result, key.value);
|
|
4346
4373
|
return false;
|
|
4347
4374
|
}) ? {
|
|
4348
4375
|
failure: true
|
|
@@ -4403,11 +4430,21 @@
|
|
|
4403
4430
|
identifiers.forEach(function (identifier) {
|
|
4404
4431
|
var hop = Object.hasOwn(value, identifier);
|
|
4405
4432
|
if (!hop) {
|
|
4406
|
-
value
|
|
4433
|
+
Object.defineProperty(value, identifier, {
|
|
4434
|
+
value: {},
|
|
4435
|
+
enumerable: true,
|
|
4436
|
+
writable: true,
|
|
4437
|
+
configurable: true
|
|
4438
|
+
});
|
|
4407
4439
|
}
|
|
4408
4440
|
value = value[identifier];
|
|
4409
4441
|
});
|
|
4410
|
-
value
|
|
4442
|
+
Object.defineProperty(value, /** @type {string} */last, {
|
|
4443
|
+
value: key,
|
|
4444
|
+
enumerable: true,
|
|
4445
|
+
writable: true,
|
|
4446
|
+
configurable: true
|
|
4447
|
+
}); // key is already a `keyValue` in our processing so no need to convert
|
|
4411
4448
|
}
|
|
4412
4449
|
|
|
4413
4450
|
/**
|
|
@@ -4485,6 +4522,7 @@
|
|
|
4485
4522
|
* @returns {Key[]}
|
|
4486
4523
|
*/
|
|
4487
4524
|
function findMultiEntryMatches(keyEntry, range) {
|
|
4525
|
+
/** @type {unknown[]} */
|
|
4488
4526
|
var matches = [];
|
|
4489
4527
|
if (Array.isArray(keyEntry)) {
|
|
4490
4528
|
var _iterator4 = _createForOfIteratorHelper(keyEntry),
|
|
@@ -4501,13 +4539,13 @@
|
|
|
4501
4539
|
} else {
|
|
4502
4540
|
var nested = findMultiEntryMatches(key, range);
|
|
4503
4541
|
if (nested.length > 0) {
|
|
4504
|
-
matches
|
|
4542
|
+
safePush(matches, key);
|
|
4505
4543
|
}
|
|
4506
4544
|
continue;
|
|
4507
4545
|
}
|
|
4508
4546
|
}
|
|
4509
4547
|
if (isNullish(range) || isKeyInRange(key, range, true)) {
|
|
4510
|
-
matches
|
|
4548
|
+
safePush(matches, key);
|
|
4511
4549
|
}
|
|
4512
4550
|
}
|
|
4513
4551
|
} catch (err) {
|
|
@@ -4516,7 +4554,7 @@
|
|
|
4516
4554
|
_iterator4.f();
|
|
4517
4555
|
}
|
|
4518
4556
|
} else if (isNullish(range) || isKeyInRange(keyEntry, range, true)) {
|
|
4519
|
-
matches
|
|
4557
|
+
safePush(matches, keyEntry);
|
|
4520
4558
|
}
|
|
4521
4559
|
return matches;
|
|
4522
4560
|
}
|
|
@@ -4538,12 +4576,13 @@
|
|
|
4538
4576
|
}
|
|
4539
4577
|
case 'array':
|
|
4540
4578
|
{
|
|
4579
|
+
/** @type {ValueType[]} */
|
|
4541
4580
|
var array = [];
|
|
4542
4581
|
var len = value.length;
|
|
4543
4582
|
var index = 0;
|
|
4544
4583
|
while (index < len) {
|
|
4545
4584
|
var entry = convertKeyToValue(value[index]);
|
|
4546
|
-
array
|
|
4585
|
+
setArrayValue(array, index, entry);
|
|
4547
4586
|
index++;
|
|
4548
4587
|
}
|
|
4549
4588
|
return array;
|
|
@@ -5303,6 +5342,7 @@
|
|
|
5303
5342
|
}
|
|
5304
5343
|
|
|
5305
5344
|
var uniqueID = 0;
|
|
5345
|
+
var activeTransactions = new Set();
|
|
5306
5346
|
var listeners$1 = ['onabort', 'oncomplete', 'onerror'];
|
|
5307
5347
|
var readonlyProperties$4 = ['objectStoreNames', 'mode', 'durability', 'db', 'error'];
|
|
5308
5348
|
|
|
@@ -5434,6 +5474,7 @@
|
|
|
5434
5474
|
me.__mode = mode;
|
|
5435
5475
|
me.__durability = durability;
|
|
5436
5476
|
me.__db = db;
|
|
5477
|
+
activeTransactions.add(me);
|
|
5437
5478
|
me.__error = null;
|
|
5438
5479
|
// @ts-expect-error Part of `ShimEventTarget`
|
|
5439
5480
|
me.__setOptions({
|
|
@@ -5946,6 +5987,7 @@
|
|
|
5946
5987
|
me.__errored = true;
|
|
5947
5988
|
throw e;
|
|
5948
5989
|
} finally {
|
|
5990
|
+
activeTransactions.delete(me);
|
|
5949
5991
|
me.__storeHandles = {};
|
|
5950
5992
|
}
|
|
5951
5993
|
}
|
|
@@ -6152,13 +6194,19 @@
|
|
|
6152
6194
|
});
|
|
6153
6195
|
}
|
|
6154
6196
|
me.__active = false; // Setting here and in requestsFinished for https://github.com/w3c/IndexedDB/issues/87
|
|
6155
|
-
|
|
6197
|
+
activeTransactions.delete(me);
|
|
6156
6198
|
if (err !== null) {
|
|
6157
6199
|
me.__error = err;
|
|
6158
6200
|
}
|
|
6159
|
-
if (me.__requestsFinished) {
|
|
6201
|
+
if (me.__requestsFinished && err !== null) {
|
|
6160
6202
|
// The transaction has already completed, so we can't call "onerror" or "onabort".
|
|
6161
|
-
// So throw the error instead.
|
|
6203
|
+
// So throw the error instead. `err` is only ever `null` here via
|
|
6204
|
+
// `IDBTransaction.prototype.abort`'s own `__abortTransaction(null)`
|
|
6205
|
+
// call, which now checks `__requestsFinished` itself first and
|
|
6206
|
+
// throws `InvalidStateError` synchronously before ever reaching
|
|
6207
|
+
// this point -- so this guard is just defense in depth against
|
|
6208
|
+
// `err` somehow being `null` some other way, not something this
|
|
6209
|
+
// path should see in practice.
|
|
6162
6210
|
setTimeout(function () {
|
|
6163
6211
|
throw err;
|
|
6164
6212
|
}, 0);
|
|
@@ -6278,6 +6326,14 @@
|
|
|
6278
6326
|
if (me.__committed) {
|
|
6279
6327
|
throw createDOMException('InvalidStateError', 'The transaction has already been committed');
|
|
6280
6328
|
}
|
|
6329
|
+
if (me.__requestsFinished) {
|
|
6330
|
+
// All requests have already finished and the transaction is
|
|
6331
|
+
// auto-committing (the async SQL commit round trip just hasn't
|
|
6332
|
+
// resolved yet) -- too late to abort per spec, even though
|
|
6333
|
+
// `__committed` itself isn't set until that round trip actually
|
|
6334
|
+
// finishes.
|
|
6335
|
+
throw createDOMException('InvalidStateError', 'The transaction is already committing');
|
|
6336
|
+
}
|
|
6281
6337
|
me.__abortTransaction(null);
|
|
6282
6338
|
};
|
|
6283
6339
|
|
|
@@ -6359,7 +6415,7 @@
|
|
|
6359
6415
|
* @returns {void}
|
|
6360
6416
|
*/
|
|
6361
6417
|
IDBTransaction.__assertActive = function (tx) {
|
|
6362
|
-
if (!tx || !tx.__active || tx.__committed) {
|
|
6418
|
+
if (!tx || !tx.__active || !tx.__handlerActive || tx.__committed) {
|
|
6363
6419
|
throw createDOMException('TransactionInactiveError', 'A request was placed against a transaction which is currently not active, or which is finished');
|
|
6364
6420
|
}
|
|
6365
6421
|
};
|
|
@@ -6386,6 +6442,9 @@
|
|
|
6386
6442
|
Object.defineProperty(IDBTransaction, 'prototype', {
|
|
6387
6443
|
writable: false
|
|
6388
6444
|
});
|
|
6445
|
+
/* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
|
|
6446
|
+
|
|
6447
|
+
IDBTransaction.activeTransactions = activeTransactions;
|
|
6389
6448
|
|
|
6390
6449
|
var TypesonPromise = /*#__PURE__*/_createClass(function TypesonPromise(e) {
|
|
6391
6450
|
_classCallCheck(this, TypesonPromise);
|
|
@@ -7772,7 +7831,7 @@
|
|
|
7772
7831
|
}
|
|
7773
7832
|
}
|
|
7774
7833
|
},
|
|
7775
|
-
|
|
7834
|
+
D = {
|
|
7776
7835
|
map: {
|
|
7777
7836
|
test: function test(e) {
|
|
7778
7837
|
return "Map" === toStringTag(e);
|
|
@@ -7785,7 +7844,7 @@
|
|
|
7785
7844
|
}
|
|
7786
7845
|
}
|
|
7787
7846
|
},
|
|
7788
|
-
|
|
7847
|
+
R = {
|
|
7789
7848
|
nan: {
|
|
7790
7849
|
test: function test(e) {
|
|
7791
7850
|
return Number.isNaN(e);
|
|
@@ -8134,8 +8193,8 @@
|
|
|
8134
8193
|
revive: function revive() {}
|
|
8135
8194
|
}
|
|
8136
8195
|
}],
|
|
8137
|
-
ne = [
|
|
8138
|
-
ce = [Z, Y, re, K, ne, O, z, U, _, B, I, h, N, C].concat("function" == typeof Map ?
|
|
8196
|
+
ne = [R, M, L, F],
|
|
8197
|
+
ce = [Z, Y, re, K, ne, O, z, U, _, B, I, h, N, C].concat("function" == typeof Map ? D : [], "function" == typeof Set ? H : [], "function" == typeof ArrayBuffer ? p : [], "function" == typeof Uint8Array ? X : [], "function" == typeof DataView ? w : [], "undefined" != typeof crypto ? v : [], "undefined" != typeof BigInt ? [m, d] : [], "undefined" != typeof DOMException ? A : [], "undefined" != typeof QuotaExceededError ? W : [], "undefined" != typeof WebTransportError ? te : [], "undefined" != typeof DOMRect ? x : [], "undefined" != typeof DOMPoint ? S : [], "undefined" != typeof DOMQuad ? P : [], "undefined" != typeof DOMMatrix ? T : [], "undefined" != typeof AudioData ? f : [], "undefined" != typeof EncodedAudioChunk ? E : [], "undefined" != typeof EncodedVideoChunk ? j : [], "undefined" != typeof VideoFrame ? ee : []);
|
|
8139
8198
|
var ue = ce.concat({
|
|
8140
8199
|
checkDataCloneException: {
|
|
8141
8200
|
test: function test(e) {
|
|
@@ -8152,11 +8211,56 @@
|
|
|
8152
8211
|
return false;
|
|
8153
8212
|
}
|
|
8154
8213
|
}
|
|
8214
|
+
}),
|
|
8215
|
+
ye = ue.concat({
|
|
8216
|
+
checkSharedArrayBufferException: {
|
|
8217
|
+
test: function test(e) {
|
|
8218
|
+
if ("SharedArrayBuffer" === {}.toString.call(e).slice(8, -1)) throw new DOMException("The object cannot be cloned.", "DataCloneError");
|
|
8219
|
+
return false;
|
|
8220
|
+
}
|
|
8221
|
+
}
|
|
8155
8222
|
});
|
|
8156
8223
|
|
|
8157
8224
|
// See: https://stackoverflow.com/questions/42170826/categories-for-rejection-by-the-structured-cloning-algorithm
|
|
8158
8225
|
|
|
8159
|
-
|
|
8226
|
+
// Although typeson-registry already has a FileList type in its structured cloning presets,
|
|
8227
|
+
// we need to override it so it works with our tests
|
|
8228
|
+
|
|
8229
|
+
var specSet = ye.flatMap(function (preset) {
|
|
8230
|
+
return Array.isArray(preset) ? preset : [preset];
|
|
8231
|
+
}).find(function (preset) {
|
|
8232
|
+
return preset && !Array.isArray(preset) && 'filelist' in preset;
|
|
8233
|
+
});
|
|
8234
|
+
var origFileList = specSet && !Array.isArray(specSet) && 'filelist' in specSet ? specSet.filelist : undefined;
|
|
8235
|
+
var origTest = origFileList && _typeof(origFileList) === 'object' && 'test' in origFileList && typeof origFileList.test === 'function' ? origFileList.test : undefined;
|
|
8236
|
+
var origRevive = origFileList && _typeof(origFileList) === 'object' && 'revive' in origFileList && typeof origFileList.revive === 'function' ? origFileList.revive : undefined;
|
|
8237
|
+
var customFileList = origFileList ? _objectSpread2(_objectSpread2({}, origFileList), {}, {
|
|
8238
|
+
/**
|
|
8239
|
+
* @param {unknown} x
|
|
8240
|
+
* @param {import('typeson').StateObject} state
|
|
8241
|
+
* @returns {boolean}
|
|
8242
|
+
*/
|
|
8243
|
+
test: function test(x, state) {
|
|
8244
|
+
if (typeof FileList !== 'undefined') {
|
|
8245
|
+
return x instanceof FileList;
|
|
8246
|
+
}
|
|
8247
|
+
return typeof origTest === 'function' ? origTest(x, state) : false;
|
|
8248
|
+
},
|
|
8249
|
+
/**
|
|
8250
|
+
* @param {unknown} x
|
|
8251
|
+
* @param {import('typeson').StateObject} state
|
|
8252
|
+
* @returns {unknown}
|
|
8253
|
+
*/
|
|
8254
|
+
revive: function revive(x, state) {
|
|
8255
|
+
if (typeof FileList !== 'undefined') {
|
|
8256
|
+
return Reflect.construct(FileList, [x]);
|
|
8257
|
+
}
|
|
8258
|
+
return typeof origRevive === 'function' ? origRevive(x, state) : undefined;
|
|
8259
|
+
}
|
|
8260
|
+
}) : undefined;
|
|
8261
|
+
var typeson = new Typeson().register([ye, customFileList ? {
|
|
8262
|
+
filelist: customFileList
|
|
8263
|
+
} : {}]);
|
|
8160
8264
|
|
|
8161
8265
|
/**
|
|
8162
8266
|
* @param {(preset: import('typeson-registry').Preset) =>
|
|
@@ -8165,7 +8269,7 @@
|
|
|
8165
8269
|
*/
|
|
8166
8270
|
function register(func) {
|
|
8167
8271
|
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Should be one-time cache
|
|
8168
|
-
typeson = new Typeson().register(func(
|
|
8272
|
+
typeson = new Typeson().register(func(ye));
|
|
8169
8273
|
}
|
|
8170
8274
|
|
|
8171
8275
|
/**
|
|
@@ -11092,7 +11196,29 @@
|
|
|
11092
11196
|
return new SyncPromise(function (resolve) {
|
|
11093
11197
|
setTimeout(function () {
|
|
11094
11198
|
entry.dispatchEvent(e); // No need to catch errors
|
|
11095
|
-
|
|
11199
|
+
// Unlike a native `Promise`, `SyncPromise#then` chains
|
|
11200
|
+
// synchronously off `resolve()` (verified directly:
|
|
11201
|
+
// `SyncPromise.resolve().then(cb)` runs `cb` before
|
|
11202
|
+
// even the calling code below it finishes) -- so
|
|
11203
|
+
// resolving immediately here would let the
|
|
11204
|
+
// `connectionsClosed()` check below run before a
|
|
11205
|
+
// same-task-but-microtask-later continuation of a
|
|
11206
|
+
// `versionchange` listener above (e.g. an `await`-
|
|
11207
|
+
// based one that then calls `db.close()`, as in
|
|
11208
|
+
// `transaction-lifetime.any.js`) ever gets a turn,
|
|
11209
|
+
// incorrectly firing `blocked` even though the
|
|
11210
|
+
// connection was about to close in time. Give real
|
|
11211
|
+
// microtask-deferred continuations a small, bounded
|
|
11212
|
+
// number of turns first -- same pattern as
|
|
11213
|
+
// `IDBTransaction.js`'s `checkQueueEntry`.
|
|
11214
|
+
var attemptsLeft = 10;
|
|
11215
|
+
(function wait() {
|
|
11216
|
+
if (attemptsLeft-- <= 0) {
|
|
11217
|
+
resolve(undefined);
|
|
11218
|
+
return;
|
|
11219
|
+
}
|
|
11220
|
+
queueMicrotask(wait);
|
|
11221
|
+
})();
|
|
11096
11222
|
}, 0);
|
|
11097
11223
|
});
|
|
11098
11224
|
});
|
|
@@ -11152,6 +11278,23 @@
|
|
|
11152
11278
|
*/
|
|
11153
11279
|
var websqlDBCache = {};
|
|
11154
11280
|
|
|
11281
|
+
/**
|
|
11282
|
+
* Tracks databases with a creation/upgrade currently in flight but not yet
|
|
11283
|
+
* committed or aborted -- keyed by (unescaped) database name. The
|
|
11284
|
+
* `dbVersions` row in `sysdb` these entries shadow is written *before*
|
|
11285
|
+
* `upgradeneeded` is even dispatched to user code (as the success
|
|
11286
|
+
* callback of that very `INSERT`/`UPDATE`), on the same shared `sysdb`
|
|
11287
|
+
* connection `databases()` itself reads from -- so, absent this, a
|
|
11288
|
+
* `databases()` call made while an upgrade is still pending would see
|
|
11289
|
+
* the new row (or new version) immediately, rather than only once the
|
|
11290
|
+
* corresponding `versionchange` transaction has genuinely committed, as
|
|
11291
|
+
* required by `get-databases.any.js`'s "doesn't pick up changes that
|
|
11292
|
+
* haven't committed" test. `IDBFactory.prototype.databases` filters
|
|
11293
|
+
* its SQL results against this map.
|
|
11294
|
+
* @type {Map<string, {oldVersion: Integer, newVersion: Integer}>}
|
|
11295
|
+
*/
|
|
11296
|
+
var pendingVersionChanges = new Map();
|
|
11297
|
+
|
|
11155
11298
|
/** @type {import('websql-configurable/lib/websql/WebSQLDatabase.js').default} */
|
|
11156
11299
|
var sysdb;
|
|
11157
11300
|
var nameCounter = 0;
|
|
@@ -11425,6 +11568,7 @@
|
|
|
11425
11568
|
}
|
|
11426
11569
|
var req = IDBOpenDBRequest.__createInstance();
|
|
11427
11570
|
var calledDbCreateError = false;
|
|
11571
|
+
var isRevertingSysdb = false;
|
|
11428
11572
|
if (CFG.autoName && name === '') {
|
|
11429
11573
|
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Necessary?
|
|
11430
11574
|
name = 'autoNamedDatabase_' + nameCounter++;
|
|
@@ -11451,9 +11595,22 @@
|
|
|
11451
11595
|
* @returns {boolean}
|
|
11452
11596
|
*/
|
|
11453
11597
|
function dbCreateError(tx, err) {
|
|
11454
|
-
if (calledDbCreateError) {
|
|
11598
|
+
if (calledDbCreateError || isRevertingSysdb) {
|
|
11455
11599
|
return false;
|
|
11456
11600
|
}
|
|
11601
|
+
// Defensive cleanup: `pendingVersionChanges.set(name, ...)` (see
|
|
11602
|
+
// below) runs *before* the `dbVersions` `INSERT`/`UPDATE` it
|
|
11603
|
+
// guards is even attempted, but only `versionSet`'s own
|
|
11604
|
+
// `on__beforecomplete`/`on__preabort` handlers ever clear it --
|
|
11605
|
+
// and `versionSet` never runs at all if that `INSERT`/`UPDATE`,
|
|
11606
|
+
// or an earlier step in this same `open()` flow, fails first.
|
|
11607
|
+
// Without this, such a failure would leave the entry orphaned
|
|
11608
|
+
// forever, silently corrupting `databases()` for any *other*,
|
|
11609
|
+
// unrelated later `open()` call that happens to reuse the same
|
|
11610
|
+
// database name (common in WPT tests, e.g. generic names like
|
|
11611
|
+
// "DB1"/"TestDatabase" reused across different test files in
|
|
11612
|
+
// the same process). A no-op if no entry was ever set.
|
|
11613
|
+
pendingVersionChanges.delete(name);
|
|
11457
11614
|
var er = err ? webSQLErrback(err) : (/** @type {Error} */tx);
|
|
11458
11615
|
calledDbCreateError = true;
|
|
11459
11616
|
// Re: why bubbling here (and how cancelable is only really relevant for `window.onerror`) see: https://github.com/w3c/IndexedDB/issues/86
|
|
@@ -11502,36 +11659,46 @@
|
|
|
11502
11659
|
*/
|
|
11503
11660
|
var sysdbFinishedCb = function sysdbFinishedCb(systx, err, cb) {
|
|
11504
11661
|
if (err) {
|
|
11505
|
-
|
|
11506
|
-
|
|
11507
|
-
|
|
11508
|
-
|
|
11509
|
-
|
|
11662
|
+
/**
|
|
11663
|
+
* @param {any} [errorToShow]
|
|
11664
|
+
* @returns {void}
|
|
11665
|
+
*/
|
|
11666
|
+
var manualRevert = function manualRevert(errorToShow) {
|
|
11667
|
+
/**
|
|
11668
|
+
* @param {string} [msg]
|
|
11669
|
+
* @throws {Error}
|
|
11670
|
+
* @returns {never}
|
|
11671
|
+
*/
|
|
11672
|
+
function reportError(msg) {
|
|
11673
|
+
throw new Error('Unable to roll back upgrade transaction!' + (msg || ''));
|
|
11674
|
+
}
|
|
11510
11675
|
sysdb.transaction(function (systx) {
|
|
11511
|
-
/**
|
|
11512
|
-
*
|
|
11513
|
-
* @param {string} msg
|
|
11514
|
-
* @throws {Error}
|
|
11515
|
-
* @returns {never}
|
|
11516
|
-
*/
|
|
11517
|
-
function reportError(msg) {
|
|
11518
|
-
throw new Error('Unable to roll back upgrade transaction!' + (msg || ''));
|
|
11519
|
-
}
|
|
11520
|
-
|
|
11521
11676
|
// Attempt to revert
|
|
11522
11677
|
if (oldVersion === 0) {
|
|
11523
|
-
systx.executeSql('DELETE FROM dbVersions WHERE "name" = ?', [sqlSafeName]
|
|
11524
|
-
// @ts-expect-error Force to work
|
|
11525
|
-
cb(reportError); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11526
|
-
},
|
|
11527
|
-
// @ts-expect-error Force to work
|
|
11528
|
-
reportError);
|
|
11678
|
+
systx.executeSql('DELETE FROM dbVersions WHERE "name" = ?', [sqlSafeName]);
|
|
11529
11679
|
} else {
|
|
11530
|
-
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [oldVersion, sqlSafeName]
|
|
11531
|
-
// @ts-expect-error Force to work
|
|
11532
|
-
reportError);
|
|
11680
|
+
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [oldVersion, sqlSafeName]);
|
|
11533
11681
|
}
|
|
11682
|
+
}, function (sqlErr) {
|
|
11683
|
+
isRevertingSysdb = false;
|
|
11684
|
+
cb(sqlErr); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11685
|
+
}, function () {
|
|
11686
|
+
isRevertingSysdb = false;
|
|
11687
|
+
cb(errorToShow || reportError); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11534
11688
|
});
|
|
11689
|
+
};
|
|
11690
|
+
try {
|
|
11691
|
+
systx.executeSql('ROLLBACK', [], function () {
|
|
11692
|
+
cb(); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11693
|
+
}, function (tx, sqlErr) {
|
|
11694
|
+
// Browser/Node may fail with expired transaction, so manually revert
|
|
11695
|
+
manualRevert(sqlErr);
|
|
11696
|
+
return false;
|
|
11697
|
+
});
|
|
11698
|
+
} catch (e) {
|
|
11699
|
+
// Browser may fail with expired transaction above so
|
|
11700
|
+
// no choice but to manually revert
|
|
11701
|
+
manualRevert(e);
|
|
11535
11702
|
}
|
|
11536
11703
|
return;
|
|
11537
11704
|
}
|
|
@@ -11565,22 +11732,43 @@
|
|
|
11565
11732
|
// open/close the transaction's active-handler window itself.
|
|
11566
11733
|
req.transaction.__handlerActive = true;
|
|
11567
11734
|
req.dispatchEvent(e);
|
|
11568
|
-
// Give any
|
|
11735
|
+
// Give any microtask-scheduled continuation of the
|
|
11569
11736
|
// `upgradeneeded` handler (e.g. a plain
|
|
11570
|
-
// `Promise.resolve().then(...)
|
|
11571
|
-
//
|
|
11572
|
-
//
|
|
11573
|
-
//
|
|
11574
|
-
//
|
|
11575
|
-
//
|
|
11576
|
-
//
|
|
11577
|
-
//
|
|
11578
|
-
//
|
|
11579
|
-
//
|
|
11580
|
-
//
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11737
|
+
// `Promise.resolve().then(...)`, or an `await`-based
|
|
11738
|
+
// continuation of a promise resolved from within the handler,
|
|
11739
|
+
// such as testharness.js's own `EventWatcher`) a chance to
|
|
11740
|
+
// run -- and still observe the transaction as active -- before
|
|
11741
|
+
// we deactivate it again, per
|
|
11742
|
+
// https://github.com/w3c/IndexedDB/issues/87. A single deferred
|
|
11743
|
+
// tick isn't always enough: an `await`-based continuation can
|
|
11744
|
+
// take more than one microtask turn to resume (e.g.
|
|
11745
|
+
// `transaction-lifetime.any.js`'s `EventWatcher`-based
|
|
11746
|
+
// `await eventWatcher.wait_for('upgradeneeded')`), so retry a
|
|
11747
|
+
// small, bounded number of times first -- same pattern as
|
|
11748
|
+
// `IDBTransaction.js`'s `checkQueueEntry` -- rather than
|
|
11749
|
+
// resetting after only one. Only the flag reset itself is
|
|
11750
|
+
// deferred here -- unlike `IDBTransaction.js`'s
|
|
11751
|
+
// `advanceAfterDispatch`, `finished()` (this transaction's own
|
|
11752
|
+
// queue-advancement/completion signal) still runs
|
|
11753
|
+
// synchronously, at exactly its previous timing: an earlier
|
|
11754
|
+
// attempt at deferring `finished()` too raced against unrelated
|
|
11755
|
+
// test setup that assumed a freshly deleted/created database's
|
|
11756
|
+
// upgrade transaction had already fully completed by the time
|
|
11757
|
+
// this function returns.
|
|
11758
|
+
/**
|
|
11759
|
+
* @param {Integer} attemptsLeft
|
|
11760
|
+
* @returns {void}
|
|
11761
|
+
*/
|
|
11762
|
+
function deferHandlerActiveReset(attemptsLeft) {
|
|
11763
|
+
if (attemptsLeft <= 0) {
|
|
11764
|
+
req.transaction.__handlerActive = false;
|
|
11765
|
+
return;
|
|
11766
|
+
}
|
|
11767
|
+
queueMicrotask(function () {
|
|
11768
|
+
deferHandlerActiveReset(attemptsLeft - 1);
|
|
11769
|
+
});
|
|
11770
|
+
}
|
|
11771
|
+
deferHandlerActiveReset(10);
|
|
11584
11772
|
if (e.__legacyOutputDidListenersThrowError) {
|
|
11585
11773
|
logError('Error', 'An error occurred in an upgradeneeded handler attached to request chain', /** @type {Error} */e.__legacyOutputDidListenersThrowError); // We do nothing else with this error as per spec
|
|
11586
11774
|
req.transaction.__abortTransaction(createDOMException('AbortError', 'A request was aborted.'));
|
|
@@ -11596,6 +11784,7 @@
|
|
|
11596
11784
|
* @returns {void}
|
|
11597
11785
|
*/
|
|
11598
11786
|
function (ev) {
|
|
11787
|
+
pendingVersionChanges.delete(name);
|
|
11599
11788
|
connection.__upgradeTransaction = null;
|
|
11600
11789
|
/** @type {import('./IDBDatabase.js').IDBDatabaseFull} */
|
|
11601
11790
|
req.__result.__versionTransaction = null;
|
|
@@ -11610,6 +11799,8 @@
|
|
|
11610
11799
|
|
|
11611
11800
|
// eslint-disable-next-line camelcase -- Clear API
|
|
11612
11801
|
req.transaction.on__preabort = function () {
|
|
11802
|
+
isRevertingSysdb = true;
|
|
11803
|
+
pendingVersionChanges.delete(name);
|
|
11613
11804
|
connection.__upgradeTransaction = null;
|
|
11614
11805
|
// We ensure any cache is deleted before any request error events fire and try to reopen
|
|
11615
11806
|
if (useDatabaseCache) {
|
|
@@ -11626,6 +11817,7 @@
|
|
|
11626
11817
|
req.__result = undefined;
|
|
11627
11818
|
req.__done = false;
|
|
11628
11819
|
connection.close();
|
|
11820
|
+
isRevertingSysdb = true;
|
|
11629
11821
|
setTimeout(function () {
|
|
11630
11822
|
var err = createDOMException('AbortError', 'The upgrade transaction was aborted.');
|
|
11631
11823
|
sysdbFinishedCb(systx, err, function (reportError) {
|
|
@@ -11672,6 +11864,10 @@
|
|
|
11672
11864
|
// });
|
|
11673
11865
|
};
|
|
11674
11866
|
}
|
|
11867
|
+
pendingVersionChanges.set(name, {
|
|
11868
|
+
oldVersion: oldVersion,
|
|
11869
|
+
newVersion: version
|
|
11870
|
+
});
|
|
11675
11871
|
if (oldVersion === 0) {
|
|
11676
11872
|
systx.executeSql('INSERT INTO dbVersions VALUES (?,?)', [sqlSafeName, version], versionSet, dbCreateError);
|
|
11677
11873
|
} else {
|
|
@@ -11683,7 +11879,26 @@
|
|
|
11683
11879
|
}
|
|
11684
11880
|
sysdbFinishedCb = function sysdbFinishedCb(systx, err, cb) {
|
|
11685
11881
|
if (err) {
|
|
11686
|
-
rollback(err,
|
|
11882
|
+
rollback(err,
|
|
11883
|
+
/**
|
|
11884
|
+
* @param {Error} [reportError]
|
|
11885
|
+
* @returns {void}
|
|
11886
|
+
*/
|
|
11887
|
+
function (reportError) {
|
|
11888
|
+
sysdb.transaction(function (systx) {
|
|
11889
|
+
if (oldVersion === 0) {
|
|
11890
|
+
systx.executeSql('DELETE FROM dbVersions WHERE "name" = ?', [sqlSafeName]);
|
|
11891
|
+
} else {
|
|
11892
|
+
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [oldVersion, sqlSafeName]);
|
|
11893
|
+
}
|
|
11894
|
+
}, function (sqlErr) {
|
|
11895
|
+
isRevertingSysdb = false;
|
|
11896
|
+
cb(sqlErr); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11897
|
+
}, function () {
|
|
11898
|
+
isRevertingSysdb = false;
|
|
11899
|
+
cb(reportError); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
11900
|
+
});
|
|
11901
|
+
});
|
|
11687
11902
|
} else {
|
|
11688
11903
|
commit(cb);
|
|
11689
11904
|
}
|
|
@@ -11974,6 +12189,15 @@
|
|
|
11974
12189
|
IDBFactory.prototype.databases = function () {
|
|
11975
12190
|
var me = this;
|
|
11976
12191
|
var calledDbCreateError = false;
|
|
12192
|
+
// Snapshotted *now*, synchronously, at call time -- not read later
|
|
12193
|
+
// from inside the SQL query's callback below, which runs on a
|
|
12194
|
+
// deferred macrotask (see `nodeSQLiteDatabase.js`'s `exec`) and so
|
|
12195
|
+
// could otherwise race against (and lose to) an in-flight upgrade's
|
|
12196
|
+
// own commit/abort handler clearing its `pendingVersionChanges`
|
|
12197
|
+
// entry in the meantime -- which would make this method incorrectly
|
|
12198
|
+
// reflect a since-committed change that hadn't committed yet when
|
|
12199
|
+
// it was actually called.
|
|
12200
|
+
var pendingVersionChangesSnapshot = new Map(pendingVersionChanges);
|
|
11977
12201
|
return new Promise(function (resolve, reject) {
|
|
11978
12202
|
// eslint-disable-line promise/avoid-new -- Own polyfill
|
|
11979
12203
|
if (!(me instanceof IDBFactory)) {
|
|
@@ -12003,10 +12227,29 @@
|
|
|
12003
12227
|
var dbNames = [];
|
|
12004
12228
|
for (var i = 0; i < data.rows.length; i++) {
|
|
12005
12229
|
var _data$rows$item2 = /** @type {{name: string, version: Integer}} */data.rows.item(i),
|
|
12006
|
-
|
|
12230
|
+
encodedName = _data$rows$item2.name,
|
|
12007
12231
|
version = _data$rows$item2.version;
|
|
12232
|
+
var name = unescapeSQLiteResponse(encodedName);
|
|
12233
|
+
// A row for a database whose creation/upgrade hasn't
|
|
12234
|
+
// committed yet (see `pendingVersionChanges`) must
|
|
12235
|
+
// not reflect that in-flight change: a brand new
|
|
12236
|
+
// database (`oldVersion === 0`) isn't reported at
|
|
12237
|
+
// all until its creation commits, and an existing
|
|
12238
|
+
// database being upgraded is still reported, but
|
|
12239
|
+
// with its pre-upgrade version.
|
|
12240
|
+
var pending = pendingVersionChangesSnapshot.get(name);
|
|
12241
|
+
if (pending) {
|
|
12242
|
+
if (pending.oldVersion === 0) {
|
|
12243
|
+
continue;
|
|
12244
|
+
}
|
|
12245
|
+
dbNames.push({
|
|
12246
|
+
name: name,
|
|
12247
|
+
version: pending.oldVersion
|
|
12248
|
+
});
|
|
12249
|
+
continue;
|
|
12250
|
+
}
|
|
12008
12251
|
dbNames.push({
|
|
12009
|
-
name:
|
|
12252
|
+
name: name,
|
|
12010
12253
|
version: version
|
|
12011
12254
|
});
|
|
12012
12255
|
}
|
|
@@ -12426,9 +12669,26 @@
|
|
|
12426
12669
|
// Key.convertValueToKey(key); // Already checked by `continue` or `continuePrimaryKey`
|
|
12427
12670
|
sqlValues.push(/** @type {string} */_encode(key));
|
|
12428
12671
|
} else if (continueCall && me.__key !== undefined) {
|
|
12429
|
-
sql.push('AND', quotedKeyColumnName, op + ' ?');
|
|
12430
12672
|
// Key.convertValueToKey(me.__key); // Already checked when stored
|
|
12431
|
-
|
|
12673
|
+
if (!me.__unique && me.__keyColumnName !== 'key' && me.__primaryKey !== undefined) {
|
|
12674
|
+
// A plain `continue()` on a non-unique index cursor must find
|
|
12675
|
+
// the next record strictly after the (key, primaryKey) pair
|
|
12676
|
+
// this cursor last returned -- a scalar `key > lastKey` alone
|
|
12677
|
+
// would wrongly exclude a *different*, not-yet-visited record
|
|
12678
|
+
// that's still tied on key with the last one (e.g. another
|
|
12679
|
+
// record that always had that same indexed value), and would
|
|
12680
|
+
// also wrongly re-admit the *same* record forever if a
|
|
12681
|
+
// same-transaction `update()` bumped its own key back above
|
|
12682
|
+
// the threshold, since a scalar comparison can't distinguish
|
|
12683
|
+
// "some other record newly tied" from "this record moved
|
|
12684
|
+
// past its own last position." Comparing the full tuple (via
|
|
12685
|
+
// this OR) against both key and primary key resolves both.
|
|
12686
|
+
sql.push('AND (', quotedKeyColumnName, op, '?', 'OR (', quotedKeyColumnName, '= ?', 'AND', quotedKey, op, '?))');
|
|
12687
|
+
sqlValues.push(/** @type {string} */_encode(me.__key), /** @type {string} */_encode(me.__key), /** @type {string} */_encode(me.__primaryKey));
|
|
12688
|
+
} else {
|
|
12689
|
+
sql.push('AND', quotedKeyColumnName, op + ' ?');
|
|
12690
|
+
sqlValues.push(/** @type {string} */_encode(me.__key));
|
|
12691
|
+
}
|
|
12432
12692
|
}
|
|
12433
12693
|
if (!me.__count) {
|
|
12434
12694
|
// 1. Sort by key
|
|
@@ -13058,9 +13318,15 @@
|
|
|
13058
13318
|
* @returns {void}
|
|
13059
13319
|
*/
|
|
13060
13320
|
function addToQueue(clonedValue) {
|
|
13061
|
-
//
|
|
13321
|
+
// `invalidateCache: true` so any cursor on this store (including
|
|
13322
|
+
// this one) drops its prefetched row batch, forcing its next
|
|
13323
|
+
// `continue()` to re-query live rather than serve rows snapshotted
|
|
13324
|
+
// before this update -- needed for the compound-tuple
|
|
13325
|
+
// continuation logic in `__findBasic` to see this update's
|
|
13326
|
+
// effect on ordering (see "Modify records during cursor
|
|
13327
|
+
// iteration" in idbcursor_update_index.any.js).
|
|
13062
13328
|
// @ts-ignore -- API (not erring in TS 6)
|
|
13063
|
-
IDBObjectStore.__storingRecordObjectStore(request, me.__store,
|
|
13329
|
+
IDBObjectStore.__storingRecordObjectStore(request, me.__store, true, clonedValue, false, key);
|
|
13064
13330
|
}
|
|
13065
13331
|
if (me.__store.keyPath !== null) {
|
|
13066
13332
|
var _me$__store$__validat = me.__store.__validateKeyAndValueAndCloneValue(valueToUpdate, undefined, true),
|