const DB_NAME = 'shine-ui-messages-v1'; const DB_VERSION = 1; const STORE_MESSAGES = 'messages'; function openDb() { return new Promise((resolve, reject) => { const request = indexedDB.open(DB_NAME, DB_VERSION); request.onupgradeneeded = () => { const db = request.result; if (!db.objectStoreNames.contains(STORE_MESSAGES)) { const store = db.createObjectStore(STORE_MESSAGES, { keyPath: 'messageKey' }); store.createIndex('by_chat', 'chatId', { unique: false }); store.createIndex('by_ts', 'ts', { unique: false }); } }; request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error || new Error('IndexedDB open failed')); }); } async function withStore(mode, callback) { const db = await openDb(); try { return await new Promise((resolve, reject) => { const tx = db.transaction(STORE_MESSAGES, mode); const store = tx.objectStore(STORE_MESSAGES); const result = callback(store, tx); tx.oncomplete = () => resolve(result); tx.onerror = () => reject(tx.error || new Error('IndexedDB transaction failed')); tx.onabort = () => reject(tx.error || new Error('IndexedDB transaction aborted')); }); } finally { db.close(); } } export async function putStoredMessage(record) { if (!record || !record.messageKey) return; await withStore('readwrite', (store) => { store.put(record); }); } export async function deleteStoredMessage(messageKey) { if (!messageKey) return; await withStore('readwrite', (store) => { store.delete(messageKey); }); } export async function listStoredMessages() { return withStore('readonly', (store) => new Promise((resolve, reject) => { const req = store.getAll(); req.onsuccess = () => resolve(Array.isArray(req.result) ? req.result : []); req.onerror = () => reject(req.error || new Error('IndexedDB getAll failed')); })); } export async function clearStoredMessages() { await new Promise((resolve, reject) => { const request = indexedDB.deleteDatabase(DB_NAME); request.onsuccess = () => resolve(); request.onerror = () => reject(request.error || new Error('IndexedDB delete failed')); request.onblocked = () => reject(new Error('IndexedDB delete blocked')); }); }