From 2cb68b7432b7a3624cdb8c9041863f3740303f2e Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:41:53 -0800 Subject: [PATCH] Reusable IDB transaction configuration + update - Use standard DOMException when rejecting --- javascript/indexdb.js | 51 ++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/javascript/indexdb.js b/javascript/indexdb.js index ace3d5843..17d79b93b 100644 --- a/javascript/indexdb.js +++ b/javascript/indexdb.js @@ -36,6 +36,37 @@ async function initIndexDB() { if (!db) await createDB(); } +/** + * Reusable setup for handling IDB transactions. + * @param {Object} resources - Required resources for implementation + * @param {IDBTransaction} resources.transaction + * @param {AbortSignal} resources.signal + * @param {Function} resources.resolve + * @param {Function} resources.reject + * @param {*} resolveValue - Value to resolve the outer Promise with + * @returns {() => void} - Function for manually aborting the transaction + */ +function configureTransactionAbort({ transaction, signal, resolve, reject }, resolveValue) { + function abortTransaction() { + signal.removeEventListener('abort', abortTransaction); + transaction.abort(); + } + signal.addEventListener('abort', abortTransaction); + transaction.onabort = () => { + signal.removeEventListener('abort', abortTransaction); + reject(new DOMException(`Aborting database transaction. ${signal.reason}`, 'AbortError')); + }; + transaction.onerror = (e) => { + signal.removeEventListener('abort', abortTransaction); + reject(new Error('Database transaction error.', e)); + }; + transaction.oncomplete = () => { + signal.removeEventListener('abort', abortTransaction); + resolve(resolveValue); + }; + return abortTransaction; +} + async function add(record) { if (!db) return null; return new Promise((resolve, reject) => { @@ -161,24 +192,8 @@ async function idbFolderCleanup(keepSet, folder, signal) { } return new Promise((resolve, reject) => { const transaction = db.transaction('thumbs', 'readwrite'); - function abortTransaction() { - signal.removeEventListener('abort', abortTransaction); - transaction.abort(); - } - signal.addEventListener('abort', abortTransaction); - transaction.onabort = () => { - signal.removeEventListener('abort', abortTransaction); - reject(`Aborting. ${signal.reason}`); // eslint-disable-line prefer-promise-reject-errors - }; - transaction.onerror = () => { - signal.removeEventListener('abort', abortTransaction); - reject(new Error('Database transaction error')); - }; - transaction.oncomplete = async () => { - signal.removeEventListener('abort', abortTransaction); - resolve(totalRemovals); - }; - + const props = { transaction, signal, resolve, reject }; + const abortTransaction = configureTransactionAbort(props, totalRemovals); try { const store = transaction.objectStore('thumbs'); removals.forEach((entry) => { store.delete(entry); });