Web: IndexedDB puts and deletes resolve when their transaction commits (#1242)

This commit is contained in:
tylerjenningsw
2026-10-13 21:38:54 -04:00
parent 549e9d8251
commit fa6c9ffccd
2 changed files with 202 additions and 2 deletions
+22 -2
View File
@@ -57,6 +57,26 @@ function req(r) {
return new Promise((res, rej) => { r.onsuccess = () => res(r.result); r.onerror = () => rej(r.error); });
}
// Run `op` on `store` in a readwrite transaction of its own; resolves once the transaction has
// committed. A request's success doesn't mean the write is stored: the transaction can still
// abort afterwards (quota at commit, the browser closing), rolling it back, and a write
// reported as saved then is never retried (#1242). A failed request aborts the transaction
// with its error; an explicit abort leaves no error, hence the AbortError.
function write(db, store, op) {
return new Promise((res, rej) => {
let tx = null;
try {
tx = db.transaction(store, "readwrite");
tx.oncomplete = () => res();
tx.onabort = () => rej(tx.error ?? new DOMException("the storage transaction was aborted", "AbortError"));
op(tx.objectStore(store));
} catch (e) {
try { tx?.abort(); } catch {}
rej(e);
}
});
}
async function idb() {
if (!self.indexedDB) throw new Error("no IndexedDB");
const open = indexedDB.open(DB, 1);
@@ -70,10 +90,10 @@ async function idb() {
return all.map((r) => ({ key: r.key, data: new Uint8Array(r.data), modified: r.modified }));
},
async put(key, data, modified) {
await req(tx("readwrite").put({ key, data: data.slice().buffer, modified }));
await write(db, STORE, (s) => s.put({ key, data: data.slice().buffer, modified }));
},
async del(key) {
await req(tx("readwrite").delete(key));
await write(db, STORE, (s) => s.delete(key));
},
};
}