indexeddbshim 17.3.2 → 17.3.3
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.map +1 -1
- package/dist/indexeddbshim-Key.js +1 -1
- package/dist/indexeddbshim-Key.min.js +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs +344 -88
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.js +169 -25
- 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 +344 -88
- package/dist/indexeddbshim-node.cjs.map +1 -1
- package/dist/indexeddbshim-noninvasive.js +169 -25
- 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 +169 -25
- 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 +2 -2
- package/src/IDBCursor.js +34 -4
- package/src/IDBFactory.js +119 -21
- package/src/IDBTransaction.js +16 -2
- package/src/nodeSQLiteDatabase.js +92 -26
- package/src/nodeWebSQL.js +8 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! indexeddbshim - v17.3.
|
|
1
|
+
/*! indexeddbshim - v17.3.3 - 8/25/2026 */
|
|
2
2
|
|
|
3
3
|
(function (factory) {
|
|
4
4
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
@@ -6161,9 +6161,15 @@
|
|
|
6161
6161
|
if (err !== null) {
|
|
6162
6162
|
me.__error = err;
|
|
6163
6163
|
}
|
|
6164
|
-
if (me.__requestsFinished) {
|
|
6164
|
+
if (me.__requestsFinished && err !== null) {
|
|
6165
6165
|
// The transaction has already completed, so we can't call "onerror" or "onabort".
|
|
6166
|
-
// So throw the error instead.
|
|
6166
|
+
// So throw the error instead. `err` is only ever `null` here via
|
|
6167
|
+
// `IDBTransaction.prototype.abort`'s own `__abortTransaction(null)`
|
|
6168
|
+
// call, which now checks `__requestsFinished` itself first and
|
|
6169
|
+
// throws `InvalidStateError` synchronously before ever reaching
|
|
6170
|
+
// this point -- so this guard is just defense in depth against
|
|
6171
|
+
// `err` somehow being `null` some other way, not something this
|
|
6172
|
+
// path should see in practice.
|
|
6167
6173
|
setTimeout(function () {
|
|
6168
6174
|
throw err;
|
|
6169
6175
|
}, 0);
|
|
@@ -6283,6 +6289,14 @@
|
|
|
6283
6289
|
if (me.__committed) {
|
|
6284
6290
|
throw createDOMException('InvalidStateError', 'The transaction has already been committed');
|
|
6285
6291
|
}
|
|
6292
|
+
if (me.__requestsFinished) {
|
|
6293
|
+
// All requests have already finished and the transaction is
|
|
6294
|
+
// auto-committing (the async SQL commit round trip just hasn't
|
|
6295
|
+
// resolved yet) -- too late to abort per spec, even though
|
|
6296
|
+
// `__committed` itself isn't set until that round trip actually
|
|
6297
|
+
// finishes.
|
|
6298
|
+
throw createDOMException('InvalidStateError', 'The transaction is already committing');
|
|
6299
|
+
}
|
|
6286
6300
|
me.__abortTransaction(null);
|
|
6287
6301
|
};
|
|
6288
6302
|
|
|
@@ -11097,7 +11111,29 @@
|
|
|
11097
11111
|
return new SyncPromise(function (resolve) {
|
|
11098
11112
|
setTimeout(function () {
|
|
11099
11113
|
entry.dispatchEvent(e); // No need to catch errors
|
|
11100
|
-
|
|
11114
|
+
// Unlike a native `Promise`, `SyncPromise#then` chains
|
|
11115
|
+
// synchronously off `resolve()` (verified directly:
|
|
11116
|
+
// `SyncPromise.resolve().then(cb)` runs `cb` before
|
|
11117
|
+
// even the calling code below it finishes) -- so
|
|
11118
|
+
// resolving immediately here would let the
|
|
11119
|
+
// `connectionsClosed()` check below run before a
|
|
11120
|
+
// same-task-but-microtask-later continuation of a
|
|
11121
|
+
// `versionchange` listener above (e.g. an `await`-
|
|
11122
|
+
// based one that then calls `db.close()`, as in
|
|
11123
|
+
// `transaction-lifetime.any.js`) ever gets a turn,
|
|
11124
|
+
// incorrectly firing `blocked` even though the
|
|
11125
|
+
// connection was about to close in time. Give real
|
|
11126
|
+
// microtask-deferred continuations a small, bounded
|
|
11127
|
+
// number of turns first -- same pattern as
|
|
11128
|
+
// `IDBTransaction.js`'s `checkQueueEntry`.
|
|
11129
|
+
var attemptsLeft = 10;
|
|
11130
|
+
(function wait() {
|
|
11131
|
+
if (attemptsLeft-- <= 0) {
|
|
11132
|
+
resolve(undefined);
|
|
11133
|
+
return;
|
|
11134
|
+
}
|
|
11135
|
+
queueMicrotask(wait);
|
|
11136
|
+
})();
|
|
11101
11137
|
}, 0);
|
|
11102
11138
|
});
|
|
11103
11139
|
});
|
|
@@ -11157,6 +11193,23 @@
|
|
|
11157
11193
|
*/
|
|
11158
11194
|
var websqlDBCache = {};
|
|
11159
11195
|
|
|
11196
|
+
/**
|
|
11197
|
+
* Tracks databases with a creation/upgrade currently in flight but not yet
|
|
11198
|
+
* committed or aborted -- keyed by (unescaped) database name. The
|
|
11199
|
+
* `dbVersions` row in `sysdb` these entries shadow is written *before*
|
|
11200
|
+
* `upgradeneeded` is even dispatched to user code (as the success
|
|
11201
|
+
* callback of that very `INSERT`/`UPDATE`), on the same shared `sysdb`
|
|
11202
|
+
* connection `databases()` itself reads from -- so, absent this, a
|
|
11203
|
+
* `databases()` call made while an upgrade is still pending would see
|
|
11204
|
+
* the new row (or new version) immediately, rather than only once the
|
|
11205
|
+
* corresponding `versionchange` transaction has genuinely committed, as
|
|
11206
|
+
* required by `get-databases.any.js`'s "doesn't pick up changes that
|
|
11207
|
+
* haven't committed" test. `IDBFactory.prototype.databases` filters
|
|
11208
|
+
* its SQL results against this map.
|
|
11209
|
+
* @type {Map<string, {oldVersion: Integer, newVersion: Integer}>}
|
|
11210
|
+
*/
|
|
11211
|
+
var pendingVersionChanges = new Map();
|
|
11212
|
+
|
|
11160
11213
|
/** @type {import('websql-configurable/lib/websql/WebSQLDatabase.js').default} */
|
|
11161
11214
|
var sysdb;
|
|
11162
11215
|
var nameCounter = 0;
|
|
@@ -11459,6 +11512,19 @@
|
|
|
11459
11512
|
if (calledDbCreateError) {
|
|
11460
11513
|
return false;
|
|
11461
11514
|
}
|
|
11515
|
+
// Defensive cleanup: `pendingVersionChanges.set(name, ...)` (see
|
|
11516
|
+
// below) runs *before* the `dbVersions` `INSERT`/`UPDATE` it
|
|
11517
|
+
// guards is even attempted, but only `versionSet`'s own
|
|
11518
|
+
// `on__beforecomplete`/`on__preabort` handlers ever clear it --
|
|
11519
|
+
// and `versionSet` never runs at all if that `INSERT`/`UPDATE`,
|
|
11520
|
+
// or an earlier step in this same `open()` flow, fails first.
|
|
11521
|
+
// Without this, such a failure would leave the entry orphaned
|
|
11522
|
+
// forever, silently corrupting `databases()` for any *other*,
|
|
11523
|
+
// unrelated later `open()` call that happens to reuse the same
|
|
11524
|
+
// database name (common in WPT tests, e.g. generic names like
|
|
11525
|
+
// "DB1"/"TestDatabase" reused across different test files in
|
|
11526
|
+
// the same process). A no-op if no entry was ever set.
|
|
11527
|
+
pendingVersionChanges.delete(name);
|
|
11462
11528
|
var er = err ? webSQLErrback(err) : (/** @type {Error} */tx);
|
|
11463
11529
|
calledDbCreateError = true;
|
|
11464
11530
|
// Re: why bubbling here (and how cancelable is only really relevant for `window.onerror`) see: https://github.com/w3c/IndexedDB/issues/86
|
|
@@ -11570,22 +11636,43 @@
|
|
|
11570
11636
|
// open/close the transaction's active-handler window itself.
|
|
11571
11637
|
req.transaction.__handlerActive = true;
|
|
11572
11638
|
req.dispatchEvent(e);
|
|
11573
|
-
// Give any
|
|
11639
|
+
// Give any microtask-scheduled continuation of the
|
|
11574
11640
|
// `upgradeneeded` handler (e.g. a plain
|
|
11575
|
-
// `Promise.resolve().then(...)
|
|
11576
|
-
//
|
|
11577
|
-
//
|
|
11578
|
-
//
|
|
11579
|
-
//
|
|
11580
|
-
//
|
|
11581
|
-
//
|
|
11582
|
-
//
|
|
11583
|
-
//
|
|
11584
|
-
//
|
|
11585
|
-
//
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
|
|
11641
|
+
// `Promise.resolve().then(...)`, or an `await`-based
|
|
11642
|
+
// continuation of a promise resolved from within the handler,
|
|
11643
|
+
// such as testharness.js's own `EventWatcher`) a chance to
|
|
11644
|
+
// run -- and still observe the transaction as active -- before
|
|
11645
|
+
// we deactivate it again, per
|
|
11646
|
+
// https://github.com/w3c/IndexedDB/issues/87. A single deferred
|
|
11647
|
+
// tick isn't always enough: an `await`-based continuation can
|
|
11648
|
+
// take more than one microtask turn to resume (e.g.
|
|
11649
|
+
// `transaction-lifetime.any.js`'s `EventWatcher`-based
|
|
11650
|
+
// `await eventWatcher.wait_for('upgradeneeded')`), so retry a
|
|
11651
|
+
// small, bounded number of times first -- same pattern as
|
|
11652
|
+
// `IDBTransaction.js`'s `checkQueueEntry` -- rather than
|
|
11653
|
+
// resetting after only one. Only the flag reset itself is
|
|
11654
|
+
// deferred here -- unlike `IDBTransaction.js`'s
|
|
11655
|
+
// `advanceAfterDispatch`, `finished()` (this transaction's own
|
|
11656
|
+
// queue-advancement/completion signal) still runs
|
|
11657
|
+
// synchronously, at exactly its previous timing: an earlier
|
|
11658
|
+
// attempt at deferring `finished()` too raced against unrelated
|
|
11659
|
+
// test setup that assumed a freshly deleted/created database's
|
|
11660
|
+
// upgrade transaction had already fully completed by the time
|
|
11661
|
+
// this function returns.
|
|
11662
|
+
/**
|
|
11663
|
+
* @param {Integer} attemptsLeft
|
|
11664
|
+
* @returns {void}
|
|
11665
|
+
*/
|
|
11666
|
+
function deferHandlerActiveReset(attemptsLeft) {
|
|
11667
|
+
if (attemptsLeft <= 0) {
|
|
11668
|
+
req.transaction.__handlerActive = false;
|
|
11669
|
+
return;
|
|
11670
|
+
}
|
|
11671
|
+
queueMicrotask(function () {
|
|
11672
|
+
deferHandlerActiveReset(attemptsLeft - 1);
|
|
11673
|
+
});
|
|
11674
|
+
}
|
|
11675
|
+
deferHandlerActiveReset(10);
|
|
11589
11676
|
if (e.__legacyOutputDidListenersThrowError) {
|
|
11590
11677
|
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
|
|
11591
11678
|
req.transaction.__abortTransaction(createDOMException('AbortError', 'A request was aborted.'));
|
|
@@ -11601,6 +11688,7 @@
|
|
|
11601
11688
|
* @returns {void}
|
|
11602
11689
|
*/
|
|
11603
11690
|
function (ev) {
|
|
11691
|
+
pendingVersionChanges.delete(name);
|
|
11604
11692
|
connection.__upgradeTransaction = null;
|
|
11605
11693
|
/** @type {import('./IDBDatabase.js').IDBDatabaseFull} */
|
|
11606
11694
|
req.__result.__versionTransaction = null;
|
|
@@ -11615,6 +11703,7 @@
|
|
|
11615
11703
|
|
|
11616
11704
|
// eslint-disable-next-line camelcase -- Clear API
|
|
11617
11705
|
req.transaction.on__preabort = function () {
|
|
11706
|
+
pendingVersionChanges.delete(name);
|
|
11618
11707
|
connection.__upgradeTransaction = null;
|
|
11619
11708
|
// We ensure any cache is deleted before any request error events fire and try to reopen
|
|
11620
11709
|
if (useDatabaseCache) {
|
|
@@ -11677,6 +11766,10 @@
|
|
|
11677
11766
|
// });
|
|
11678
11767
|
};
|
|
11679
11768
|
}
|
|
11769
|
+
pendingVersionChanges.set(name, {
|
|
11770
|
+
oldVersion: oldVersion,
|
|
11771
|
+
newVersion: version
|
|
11772
|
+
});
|
|
11680
11773
|
if (oldVersion === 0) {
|
|
11681
11774
|
systx.executeSql('INSERT INTO dbVersions VALUES (?,?)', [sqlSafeName, version], versionSet, dbCreateError);
|
|
11682
11775
|
} else {
|
|
@@ -11979,6 +12072,15 @@
|
|
|
11979
12072
|
IDBFactory.prototype.databases = function () {
|
|
11980
12073
|
var me = this;
|
|
11981
12074
|
var calledDbCreateError = false;
|
|
12075
|
+
// Snapshotted *now*, synchronously, at call time -- not read later
|
|
12076
|
+
// from inside the SQL query's callback below, which runs on a
|
|
12077
|
+
// deferred macrotask (see `nodeSQLiteDatabase.js`'s `exec`) and so
|
|
12078
|
+
// could otherwise race against (and lose to) an in-flight upgrade's
|
|
12079
|
+
// own commit/abort handler clearing its `pendingVersionChanges`
|
|
12080
|
+
// entry in the meantime -- which would make this method incorrectly
|
|
12081
|
+
// reflect a since-committed change that hadn't committed yet when
|
|
12082
|
+
// it was actually called.
|
|
12083
|
+
var pendingVersionChangesSnapshot = new Map(pendingVersionChanges);
|
|
11982
12084
|
return new Promise(function (resolve, reject) {
|
|
11983
12085
|
// eslint-disable-line promise/avoid-new -- Own polyfill
|
|
11984
12086
|
if (!(me instanceof IDBFactory)) {
|
|
@@ -12008,10 +12110,29 @@
|
|
|
12008
12110
|
var dbNames = [];
|
|
12009
12111
|
for (var i = 0; i < data.rows.length; i++) {
|
|
12010
12112
|
var _data$rows$item2 = /** @type {{name: string, version: Integer}} */data.rows.item(i),
|
|
12011
|
-
|
|
12113
|
+
encodedName = _data$rows$item2.name,
|
|
12012
12114
|
version = _data$rows$item2.version;
|
|
12115
|
+
var name = unescapeSQLiteResponse(encodedName);
|
|
12116
|
+
// A row for a database whose creation/upgrade hasn't
|
|
12117
|
+
// committed yet (see `pendingVersionChanges`) must
|
|
12118
|
+
// not reflect that in-flight change: a brand new
|
|
12119
|
+
// database (`oldVersion === 0`) isn't reported at
|
|
12120
|
+
// all until its creation commits, and an existing
|
|
12121
|
+
// database being upgraded is still reported, but
|
|
12122
|
+
// with its pre-upgrade version.
|
|
12123
|
+
var pending = pendingVersionChangesSnapshot.get(name);
|
|
12124
|
+
if (pending) {
|
|
12125
|
+
if (pending.oldVersion === 0) {
|
|
12126
|
+
continue;
|
|
12127
|
+
}
|
|
12128
|
+
dbNames.push({
|
|
12129
|
+
name: name,
|
|
12130
|
+
version: pending.oldVersion
|
|
12131
|
+
});
|
|
12132
|
+
continue;
|
|
12133
|
+
}
|
|
12013
12134
|
dbNames.push({
|
|
12014
|
-
name:
|
|
12135
|
+
name: name,
|
|
12015
12136
|
version: version
|
|
12016
12137
|
});
|
|
12017
12138
|
}
|
|
@@ -12431,9 +12552,26 @@
|
|
|
12431
12552
|
// Key.convertValueToKey(key); // Already checked by `continue` or `continuePrimaryKey`
|
|
12432
12553
|
sqlValues.push(/** @type {string} */_encode(key));
|
|
12433
12554
|
} else if (continueCall && me.__key !== undefined) {
|
|
12434
|
-
sql.push('AND', quotedKeyColumnName, op + ' ?');
|
|
12435
12555
|
// Key.convertValueToKey(me.__key); // Already checked when stored
|
|
12436
|
-
|
|
12556
|
+
if (!me.__unique && me.__keyColumnName !== 'key' && me.__primaryKey !== undefined) {
|
|
12557
|
+
// A plain `continue()` on a non-unique index cursor must find
|
|
12558
|
+
// the next record strictly after the (key, primaryKey) pair
|
|
12559
|
+
// this cursor last returned -- a scalar `key > lastKey` alone
|
|
12560
|
+
// would wrongly exclude a *different*, not-yet-visited record
|
|
12561
|
+
// that's still tied on key with the last one (e.g. another
|
|
12562
|
+
// record that always had that same indexed value), and would
|
|
12563
|
+
// also wrongly re-admit the *same* record forever if a
|
|
12564
|
+
// same-transaction `update()` bumped its own key back above
|
|
12565
|
+
// the threshold, since a scalar comparison can't distinguish
|
|
12566
|
+
// "some other record newly tied" from "this record moved
|
|
12567
|
+
// past its own last position." Comparing the full tuple (via
|
|
12568
|
+
// this OR) against both key and primary key resolves both.
|
|
12569
|
+
sql.push('AND (', quotedKeyColumnName, op, '?', 'OR (', quotedKeyColumnName, '= ?', 'AND', quotedKey, op, '?))');
|
|
12570
|
+
sqlValues.push(/** @type {string} */_encode(me.__key), /** @type {string} */_encode(me.__key), /** @type {string} */_encode(me.__primaryKey));
|
|
12571
|
+
} else {
|
|
12572
|
+
sql.push('AND', quotedKeyColumnName, op + ' ?');
|
|
12573
|
+
sqlValues.push(/** @type {string} */_encode(me.__key));
|
|
12574
|
+
}
|
|
12437
12575
|
}
|
|
12438
12576
|
if (!me.__count) {
|
|
12439
12577
|
// 1. Sort by key
|
|
@@ -13063,9 +13201,15 @@
|
|
|
13063
13201
|
* @returns {void}
|
|
13064
13202
|
*/
|
|
13065
13203
|
function addToQueue(clonedValue) {
|
|
13066
|
-
//
|
|
13204
|
+
// `invalidateCache: true` so any cursor on this store (including
|
|
13205
|
+
// this one) drops its prefetched row batch, forcing its next
|
|
13206
|
+
// `continue()` to re-query live rather than serve rows snapshotted
|
|
13207
|
+
// before this update -- needed for the compound-tuple
|
|
13208
|
+
// continuation logic in `__findBasic` to see this update's
|
|
13209
|
+
// effect on ordering (see "Modify records during cursor
|
|
13210
|
+
// iteration" in idbcursor_update_index.any.js).
|
|
13067
13211
|
// @ts-ignore -- API (not erring in TS 6)
|
|
13068
|
-
IDBObjectStore.__storingRecordObjectStore(request, me.__store,
|
|
13212
|
+
IDBObjectStore.__storingRecordObjectStore(request, me.__store, true, clonedValue, false, key);
|
|
13069
13213
|
}
|
|
13070
13214
|
if (me.__store.keyPath !== null) {
|
|
13071
13215
|
var _me$__store$__validat = me.__store.__validateKeyAndValueAndCloneValue(valueToUpdate, undefined, true),
|