// IndexedDB cache management import { BibleChapter, CacheEntry } from '@/types' const DB_NAME = 'BibleReaderDB' const DB_VERSION = 1 const STORE_NAME = 'chapters' const CACHE_DURATION_MS = 30 * 24 * 60 * 60 * 1000 // 30 days const MAX_CACHE_SIZE = 50 // keep last 50 chapters let db: IDBDatabase | null = null export async function initDatabase(): Promise { return new Promise((resolve, reject) => { const request = indexedDB.open(DB_NAME, DB_VERSION) request.onerror = () => reject(request.error) request.onsuccess = () => { db = request.result resolve(db) } request.onupgradeneeded = (event) => { const database = (event.target as IDBOpenDBRequest).result if (!database.objectStoreNames.contains(STORE_NAME)) { const store = database.createObjectStore(STORE_NAME, { keyPath: 'chapterId' }) store.createIndex('timestamp', 'timestamp', { unique: false }) } } }) } export async function cacheChapter(chapter: BibleChapter): Promise { if (!db) await initDatabase() const entry: CacheEntry = { chapterId: chapter.id, data: chapter, timestamp: Date.now(), expiresAt: Date.now() + CACHE_DURATION_MS } return new Promise((resolve, reject) => { const transaction = db!.transaction([STORE_NAME], 'readwrite') const store = transaction.objectStore(STORE_NAME) // Delete oldest entries if over limit const countRequest = store.count() countRequest.onsuccess = () => { if (countRequest.result >= MAX_CACHE_SIZE) { const index = store.index('timestamp') const oldestRequest = index.openCursor() oldestRequest.onsuccess = (event) => { const cursor = (event.target as IDBRequest).result if (cursor) { cursor.delete() } } } } const request = store.put(entry) request.onerror = () => reject(request.error) request.onsuccess = () => resolve() }) } export async function getCachedChapter(chapterId: string): Promise { if (!db) await initDatabase() return new Promise((resolve, reject) => { const transaction = db!.transaction([STORE_NAME], 'readonly') const store = transaction.objectStore(STORE_NAME) const request = store.get(chapterId) request.onerror = () => reject(request.error) request.onsuccess = () => { const entry = request.result as CacheEntry | undefined if (entry && entry.expiresAt > Date.now()) { resolve(entry.data) } else { resolve(null) } } }) } export async function clearExpiredCache(): Promise { if (!db) await initDatabase() return new Promise((resolve, reject) => { const transaction = db!.transaction([STORE_NAME], 'readwrite') const store = transaction.objectStore(STORE_NAME) const index = store.index('timestamp') const range = IDBKeyRange.upperBound(Date.now() - CACHE_DURATION_MS) const request = index.openCursor(range) request.onsuccess = (event) => { const cursor = (event.target as IDBRequest).result if (cursor) { cursor.delete() cursor.continue() } else { resolve() } } request.onerror = () => reject(request.error) }) }