From 209562bccf3a4be934b77762c93e12ce50269ee2 Mon Sep 17 00:00:00 2001 From: Jeremie Poisson Date: Tue, 28 Apr 2026 13:58:12 -0700 Subject: [PATCH 1/3] Eagerly create multi-entry/fulltext index object stores in transaction constructor --- src/IndexedDbProvider.ts | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/IndexedDbProvider.ts b/src/IndexedDbProvider.ts index 7a2541f..b68dab1 100644 --- a/src/IndexedDbProvider.ts +++ b/src/IndexedDbProvider.ts @@ -746,6 +746,7 @@ export class IndexedDbProvider extends DbProvider { // DbTransaction implementation for the IndexedDB DbProvider. export class IndexedDbTransaction implements DbTransaction { private _stores: IDBObjectStore[]; + private _indexStoreMap: Map; constructor( private _trans: IDBTransaction, @@ -760,6 +761,28 @@ export class IndexedDbTransaction implements DbTransaction { this._trans.objectStore(storeName) ); + // Eagerly capture multi-entry/fullText index object stores while the transaction is still + // in "active" state. Deferring this to getStore() risks an InvalidStateError if the event + // loop runs between openTransaction() and the first getStore() call, causing the IDB + // transaction to auto-commit before the objectStore() call. + this._indexStoreMap = new Map(); + if (_fakeComplicatedKeys) { + each(this._transToken.storeNames, (storeName) => { + const storeSchema = find(_schema.stores, (s) => s.name === storeName); + if (storeSchema?.indexes) { + each(storeSchema.indexes, (indexSchema) => { + if (indexSchema.multiEntry || indexSchema.fullText) { + const indexStoreName = storeSchema.name + "_" + indexSchema.name; + this._indexStoreMap.set( + indexStoreName, + this._trans.objectStore(indexStoreName) + ); + } + }); + } + }); + } + if (lockHelper) { // Chromium seems to have a bug in their indexeddb implementation that lets it start a timeout // while the app is in the middle of a commit (it does a two-phase commit). It can then finish @@ -847,12 +870,17 @@ export class IndexedDbTransaction implements DbTransaction { const indexStores: IDBObjectStore[] = []; if (this._fakeComplicatedKeys && storeSchema.indexes) { - // Pull the alternate multientry stores in as well + // Pull the alternate multientry stores in as well, using the map populated eagerly in the + // constructor to avoid calling objectStore() after an async yield (which would throw + // InvalidStateError if the transaction has already auto-committed). each(storeSchema.indexes, (indexSchema) => { if (indexSchema.multiEntry || indexSchema.fullText) { - indexStores.push( - this._trans.objectStore(storeSchema.name + "_" + indexSchema.name) - ); + const indexStoreName = storeSchema.name + "_" + indexSchema.name; + const indexStore = this._indexStoreMap.get(indexStoreName); + if (!indexStore) { + throw new Error("Index store not found in transaction: " + indexStoreName); + } + indexStores.push(indexStore); } }); } From 503febe64bb1c68d6224c1f4f48c0f7913b5053f Mon Sep 17 00:00:00 2001 From: Jeremie Poisson Date: Tue, 28 Apr 2026 14:34:21 -0700 Subject: [PATCH 2/3] prettier --- src/IndexedDbProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IndexedDbProvider.ts b/src/IndexedDbProvider.ts index b68dab1..846992d 100644 --- a/src/IndexedDbProvider.ts +++ b/src/IndexedDbProvider.ts @@ -825,7 +825,7 @@ export class IndexedDbTransaction implements DbTransaction { errorDetail + ", History: " + history.join(",") - ) + ) ); }; From 4c1ed4b54eef8ff6dac3c99a1117b701451dee11 Mon Sep 17 00:00:00 2001 From: Jeremie Poisson Date: Tue, 28 Apr 2026 14:47:10 -0700 Subject: [PATCH 3/3] fix prettier --- src/IndexedDbProvider.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/IndexedDbProvider.ts b/src/IndexedDbProvider.ts index 846992d..bee0bbe 100644 --- a/src/IndexedDbProvider.ts +++ b/src/IndexedDbProvider.ts @@ -825,7 +825,7 @@ export class IndexedDbTransaction implements DbTransaction { errorDetail + ", History: " + history.join(",") - ) + ) ); }; @@ -878,7 +878,9 @@ export class IndexedDbTransaction implements DbTransaction { const indexStoreName = storeSchema.name + "_" + indexSchema.name; const indexStore = this._indexStoreMap.get(indexStoreName); if (!indexStore) { - throw new Error("Index store not found in transaction: " + indexStoreName); + throw new Error( + "Index store not found in transaction: " + indexStoreName + ); } indexStores.push(indexStore); }