diff --git a/src/lib/client/pwa.svelte.ts b/src/lib/client/pwa.svelte.ts index a5eb10e..d61bed9 100644 --- a/src/lib/client/pwa.svelte.ts +++ b/src/lib/client/pwa.svelte.ts @@ -1,3 +1,5 @@ +import { SW_UPDATE_POLL_INTERVAL_MS, SW_VERSION_QUERY_TIMEOUT_MS } from '$lib/constants'; + // Service-Worker-Update-Pattern: Workbox-Style Handshake (kein // skipWaiting im install-Handler, User bestätigt via Toast) mit // zusätzlichem Zombie-Schutz. @@ -39,7 +41,7 @@ class PwaStore { // mitbekommt, wenn er die Seite lange offen lässt ohne zu navigieren. this.pollTimer = setInterval(() => { void this.registration?.update().catch(() => {}); - }, 30 * 60_000); + }, SW_UPDATE_POLL_INTERVAL_MS); } private onUpdateFound(): void { @@ -97,7 +99,7 @@ class PwaStore { function queryVersion(sw: ServiceWorker): Promise { return new Promise((resolve) => { const channel = new MessageChannel(); - const timer = setTimeout(() => resolve(null), 1500); + const timer = setTimeout(() => resolve(null), SW_VERSION_QUERY_TIMEOUT_MS); channel.port1.onmessage = (e) => { clearTimeout(timer); const v = (e.data as { version?: unknown } | null)?.version; diff --git a/src/lib/constants.ts b/src/lib/constants.ts new file mode 100644 index 0000000..ba30530 --- /dev/null +++ b/src/lib/constants.ts @@ -0,0 +1,11 @@ +// Shared timing constants. Keep magic numbers here so callers stay readable +// and the rationale lives next to the value. + +// How long to wait for a Service Worker to answer GET_VERSION before +// treating the response as missing. Short on purpose — SWs that take this +// long are likely the Chromium zombie case (see pwa.svelte.ts). +export const SW_VERSION_QUERY_TIMEOUT_MS = 1500; + +// Active update check while the page sits open in a tab. 30 minutes is a +// trade-off between being timely and not hammering the server. +export const SW_UPDATE_POLL_INTERVAL_MS = 30 * 60_000; diff --git a/src/lib/sw/cache-strategy.ts b/src/lib/sw/cache-strategy.ts index a1de20a..6454ae9 100644 --- a/src/lib/sw/cache-strategy.ts +++ b/src/lib/sw/cache-strategy.ts @@ -1,6 +1,6 @@ export type CacheStrategy = 'shell' | 'swr' | 'images' | 'network-only'; -export type RequestShape = { url: string; method: string }; +type RequestShape = { url: string; method: string }; // Pure function — sole decision-maker for "which strategy for this request?". // Called by the service worker for every fetch event. diff --git a/src/lib/sw/diff-manifest.ts b/src/lib/sw/diff-manifest.ts index 28a53b2..8f77d20 100644 --- a/src/lib/sw/diff-manifest.ts +++ b/src/lib/sw/diff-manifest.ts @@ -1,7 +1,7 @@ // Vergleicht die aktuelle Rezept-ID-Liste (vom Server) mit dem, was // der Cache schon hat. Der SW nutzt das Delta, um nur Neue zu laden // und Gelöschte abzuräumen. -export type ManifestDiff = { toAdd: number[]; toRemove: number[] }; +type ManifestDiff = { toAdd: number[]; toRemove: number[] }; export function diffManifest(currentIds: number[], cachedIds: number[]): ManifestDiff { const current = new Set(currentIds); diff --git a/src/routes/api/recipes/[id]/image/+server.ts b/src/routes/api/recipes/[id]/image/+server.ts index f056b13..4927dd9 100644 --- a/src/routes/api/recipes/[id]/image/+server.ts +++ b/src/routes/api/recipes/[id]/image/+server.ts @@ -32,13 +32,13 @@ export const POST: RequestHandler = async ({ params, request }) => { const form = await request.formData().catch(() => null); const file = form?.get('file'); - if (!(file instanceof File)) error(400, { message: 'Feld "file" fehlt' }); - if (file.size === 0) error(400, { message: 'Leere Datei' }); - if (file.size > MAX_BYTES) error(413, { message: 'Bild zu groß (max. 10 MB)' }); + if (!(file instanceof File)) error(400, { message: 'Field "file" missing' }); + if (file.size === 0) error(400, { message: 'Empty file' }); + if (file.size > MAX_BYTES) error(413, { message: 'Image too large (max 10 MB)' }); const mime = file.type.toLowerCase(); const ext = EXT_BY_MIME[mime]; - if (!ext) error(415, { message: `Bildformat ${file.type || 'unbekannt'} nicht unterstützt` }); + if (!ext) error(415, { message: `Image format ${file.type || 'unknown'} not supported` }); const buf = Buffer.from(await file.arrayBuffer()); const hash = createHash('sha256').update(buf).digest('hex');