From 328b962572e4decb5280541c6d01495af440799d Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Fri, 10 Apr 2026 00:13:45 +0900 Subject: better debug info --- src/lib/cache/imageCache.ts | 27 +++++++++++++++-- src/lib/components/CacheDebug.svelte | 59 ++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/src/lib/cache/imageCache.ts b/src/lib/cache/imageCache.ts index 2326974..5ff7393 100644 --- a/src/lib/cache/imageCache.ts +++ b/src/lib/cache/imageCache.ts @@ -109,6 +109,10 @@ async function idbGet(key: CacheKey): Promise { }); } +/** Last write error (if any) — exposed via getStats() for diagnostics. */ +let lastWriteError: string | undefined; +let writeErrorCount = 0; + /** Write a record to IndexedDB (best-effort). */ async function idbPut(record: StoredRecord): Promise { const db = await openDb(); @@ -119,9 +123,22 @@ async function idbPut(record: StoredRecord): Promise { const tx = db.transaction(STORE_NAME, 'readwrite'); const store = tx.objectStore(STORE_NAME); store.put(record); - tx.oncomplete = () => resolve(); - tx.onerror = () => resolve(); - } catch { + tx.oncomplete = () => { + lastWriteError = undefined; + resolve(); + }; + tx.onerror = () => { + const msg = tx.error?.message ?? 'unknown write error'; + lastWriteError = msg; + writeErrorCount++; + console.warn(`[imageCache] IDB write failed: ${msg}`); + resolve(); + }; + } catch (e) { + const msg = e instanceof Error ? e.message : String(e); + lastWriteError = msg; + writeErrorCount++; + console.warn(`[imageCache] IDB write exception: ${msg}`); resolve(); } }); @@ -280,6 +297,8 @@ export const imageCache = { idbEntries: number; idbBytes: number; idbError: string | undefined; + idbLastWriteError: string | undefined; + idbWriteErrorCount: number; }> { let fullCount = 0; let thumbCount = 0; @@ -332,6 +351,8 @@ export const imageCache = { idbEntries, idbBytes, idbError, + idbLastWriteError: lastWriteError, + idbWriteErrorCount: writeErrorCount, }; }, diff --git a/src/lib/components/CacheDebug.svelte b/src/lib/components/CacheDebug.svelte index 293ff62..09e859d 100644 --- a/src/lib/components/CacheDebug.svelte +++ b/src/lib/components/CacheDebug.svelte @@ -9,6 +9,8 @@ idbEntries: number; idbBytes: number; idbError: string | undefined; + idbLastWriteError: string | undefined; + idbWriteErrorCount: number; } let stats = $state(undefined); @@ -24,11 +26,44 @@ return `${val.toFixed(1)} ${sizes[i]}`; } + let storageEstimate = $state<{ usage: number; quota: number } | undefined>(undefined); + let storageError = $state(undefined); + async function refresh() { refreshing = true; try { stats = await imageCache.getStats(); } catch { /* ignore */ } + + // Try standard Storage API first, then webkit fallback + storageEstimate = undefined; + storageError = undefined; + try { + if (navigator.storage && navigator.storage.estimate) { + const est = await navigator.storage.estimate(); + storageEstimate = { usage: est.usage ?? 0, quota: est.quota ?? 0 }; + } else if ('webkitTemporaryStorage' in navigator) { + // Chrome HTTP fallback + const wk = (navigator as Record)['webkitTemporaryStorage'] as + { queryUsageAndQuota: (ok: (u: number, q: number) => void, err: (e: unknown) => void) => void } | undefined; + if (wk !== undefined) { + const result = await new Promise<{ usage: number; quota: number }>((resolve, reject) => { + wk.queryUsageAndQuota( + (usage, quota) => resolve({ usage, quota }), + (err) => reject(err), + ); + }); + storageEstimate = result; + } else { + storageError = 'Storage API not available (HTTP origin)'; + } + } else { + storageError = 'Storage API not available'; + } + } catch (e) { + storageError = e instanceof Error ? e.message : String(e); + } + refreshing = false; } @@ -65,6 +100,12 @@ {:else}
Entries: {stats.idbEntries}
Size: {formatBytes(stats.idbBytes)}
+ {#if stats.idbWriteErrorCount > 0} +
❌ {stats.idbWriteErrorCount} write errors
+ {#if stats.idbLastWriteError !== undefined} +
{stats.idbLastWriteError}
+ {/if} + {/if}
{#if stats.idbEntries === stats.entries} ✅ In sync with memory @@ -76,6 +117,24 @@
{/if} + +
+
Storage Quota
+ {#if storageEstimate !== undefined} +
Used: {formatBytes(storageEstimate.usage)} / {formatBytes(storageEstimate.quota)}
+ {#if storageEstimate.quota > 0} + {@const pct = (storageEstimate.usage / storageEstimate.quota * 100)} +
+ + 90} class:text-warning={pct > 70 && pct <= 90}>{pct.toFixed(1)}% +
+ {/if} + {:else if storageError !== undefined} +
{storageError}
+ {:else} +
Querying…
+ {/if} +
{:else if !collapsed}
-- cgit v1.2.3