Files
2026-01-16 19:04:48 +02:00

112 lines
2.8 KiB
JavaScript

// Service Worker for Wedding App PWA
const CACHE_NAME = "wedding-app-v1";
const STATIC_CACHE = "wedding-static-v1";
const DYNAMIC_CACHE = "wedding-dynamic-v1";
// Assets to cache on install
const STATIC_ASSETS = [
"/",
"/dashboard",
"/wedding",
"/offline",
"/favicon.ico",
"/apple-touch-icon.png",
];
// Install event - cache static assets
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(STATIC_CACHE).then((cache) => {
return cache.addAll(STATIC_ASSETS);
})
);
self.skipWaiting();
});
// Activate event - clean up old caches
self.addEventListener("activate", (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames
.filter((name) => name !== STATIC_CACHE && name !== DYNAMIC_CACHE)
.map((name) => caches.delete(name))
);
})
);
self.clients.claim();
});
// Fetch event - serve from cache, fallback to network
self.addEventListener("fetch", (event) => {
const { request } = event;
const url = new URL(request.url);
// Skip non-GET requests and external URLs
if (request.method !== "GET" || !url.origin.includes(self.location.origin)) {
return;
}
// NEVER cache audio files - stream only (Apple T&C compliance)
if (
url.pathname.match(/\.(mp3|m4a|aac|ogg|wav|flac|webm|opus)$/i) ||
request.url.includes('audio-ssl.itunes.apple.com') ||
request.url.includes('preview') ||
request.url.includes('_stream=')
) {
// Stream audio directly without caching
event.respondWith(
fetch(request, {
cache: 'no-store',
mode: 'cors',
}).catch(() => {
// If fetch fails, don't return cached version
return new Response('Audio streaming failed', { status: 503 });
})
);
return;
}
// API routes - network first, cache fallback
if (url.pathname.startsWith("/api/")) {
event.respondWith(
fetch(request)
.then((response) => {
const clone = response.clone();
caches.open(DYNAMIC_CACHE).then((cache) => {
cache.put(request, clone);
});
return response;
})
.catch(() => {
return caches.match(request);
})
);
return;
}
// Static assets - cache first, network fallback
event.respondWith(
caches.match(request).then((cachedResponse) => {
if (cachedResponse) {
return cachedResponse;
}
return fetch(request).then((response) => {
// Don't cache non-successful responses
if (!response || response.status !== 200 || response.type !== "basic") {
return response;
}
const clone = response.clone();
caches.open(DYNAMIC_CACHE).then((cache) => {
cache.put(request, clone);
});
return response;
});
})
);
});