const DB_NAME = 'dww11-account-switch-v3'; let opening; export function openDB() { if (!opening) opening = new Promise((resolve, reject) => { const req = indexedDB.open(DB_NAME, 1); req.onupgradeneeded = () => { req.result.createObjectStore('accounts', { keyPath: 'username' }); req.result.createObjectStore('meta'); }; req.onsuccess = () => { const db = req.result; db.onversionchange = () => { db.close(); opening = null; }; db.onclose = () => { opening = null; }; resolve(db); }; req.onerror = () => { opening = null; reject(new Error('无法打开 IndexedDB:' + req.error?.message)); }; req.onblocked = () => { opening = null; reject(new Error('数据库升级被阻塞,请关闭扩展管理页后重试。')); }; }); return opening; } // 所有状态变更跨 accounts/meta 使用同一事务。回调必须同步,避免 await 使事务自动提交。 export async function transact(reducer, write = true) { const db = await openDB(); return new Promise((resolve, reject) => { const tx = db.transaction(['accounts', 'meta'], write ? 'readwrite' : 'readonly', write ? { durability: 'strict' } : undefined); const accountsStore = tx.objectStore('accounts'), metaStore = tx.objectStore('meta'); const a = accountsStore.getAll(), m = metaStore.get('state'); let output, failure, ready = 0; const loaded = () => { if (++ready !== 2) return; try { const state = m.result || { schedule: null, flow: null }; output = reducer(a.result, state, accountsStore); if (write) metaStore.put(state, 'state'); } catch (e) { failure = e; tx.abort(); } }; a.onsuccess = loaded; m.onsuccess = loaded; tx.oncomplete = () => resolve(output); tx.onabort = () => reject(failure || new Error('数据库事务未提交:' + (tx.error?.message || '已中止'))); tx.onerror = () => {}; // 由 onabort 统一处理,不在提交之前返回成功。 }); }