refactor(constants): zentrale SW-Timing-Konstanten + minor cleanups
- src/lib/constants.ts: SW_VERSION_QUERY_TIMEOUT_MS, SW_UPDATE_POLL_INTERVAL_MS - pwa.svelte.ts: nutzt die Konstanten statt 1500/30*60_000 - cache-strategy.ts / diff-manifest.ts: RequestShape/ManifestDiff entkapselt (intern statt export, da nirgends extern importiert) - recipes/[id]/image: deutsche Fehlermeldungen auf Englisch (Konsistenz mit allen anderen Endpoints) Findings aus REVIEW-2026-04-18.md (Quick-Wins 6+7) und dead-code.md
This commit is contained in:
@@ -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<string | null> {
|
||||
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;
|
||||
|
||||
11
src/lib/constants.ts
Normal file
11
src/lib/constants.ts
Normal file
@@ -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;
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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');
|
||||
|
||||
Reference in New Issue
Block a user