offline puzzle cache

This commit is contained in:
2025-12-31 20:08:59 +02:00
parent 2f685f29e3
commit 315ef9def0
+73
View File
@@ -0,0 +1,73 @@
import type { GenerateResponse } from './types'
const DB_NAME = 'cruciverb-offline'
const DB_VERSION = 1
function openDB(): Promise<IDBDatabase> {
return new Promise((resolve, reject) => {
const req = indexedDB.open(DB_NAME, DB_VERSION)
req.onupgradeneeded = () => {
const db = req.result
if (!db.objectStoreNames.contains('puzzles')) {
db.createObjectStore('puzzles', { keyPath: 'id' })
}
if (!db.objectStoreNames.contains('progress')) {
db.createObjectStore('progress', { keyPath: 'puzzleId' })
}
if (!db.objectStoreNames.contains('pending')) {
db.createObjectStore('pending', { keyPath: 'id', autoIncrement: true })
}
}
req.onsuccess = () => resolve(req.result)
req.onerror = () => reject(req.error)
})
}
export async function cachePuzzle(id: string, data: GenerateResponse): Promise<void> {
const db = await openDB()
const tx = db.transaction('puzzles', 'readwrite')
tx.objectStore('puzzles').put({ id, data, cached_at: Date.now() })
return new Promise((resolve, reject) => { tx.oncomplete = () => resolve(); tx.onerror = () => reject(tx.error) })
}
export async function getCachedPuzzle(id: string): Promise<GenerateResponse | null> {
const db = await openDB()
return new Promise((resolve, reject) => {
const tx = db.transaction('puzzles', 'readonly')
const req = tx.objectStore('puzzles').get(id)
req.onsuccess = () => resolve(req.result?.data || null)
req.onerror = () => reject(req.error)
})
}
export async function saveProgress(puzzleId: string, entries: string[][]): Promise<void> {
const db = await openDB()
const tx = db.transaction('progress', 'readwrite')
tx.objectStore('progress').put({ puzzleId, entries, saved_at: Date.now() })
return new Promise((resolve, reject) => { tx.oncomplete = () => resolve(); tx.onerror = () => reject(tx.error) })
}
export async function getProgress(puzzleId: string): Promise<string[][] | null> {
const db = await openDB()
return new Promise((resolve, reject) => {
const tx = db.transaction('progress', 'readonly')
const req = tx.objectStore('progress').get(puzzleId)
req.onsuccess = () => resolve(req.result?.entries || null)
req.onerror = () => reject(req.error)
})
}
export function isOnline(): boolean {
return navigator.onLine
}
export function onOnlineChange(callback: (online: boolean) => void): () => void {
const onOnline = () => callback(true)
const onOffline = () => callback(false)
window.addEventListener('online', onOnline)
window.addEventListener('offline', onOffline)
return () => {
window.removeEventListener('online', onOnline)
window.removeEventListener('offline', onOffline)
}
}