Files
2026-10-31 14:43:15 +08:00

44 lines
2.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 统一处理,不在提交之前返回成功。
});
}