112 lines
2.8 KiB
JavaScript
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;
|
|
});
|
|
})
|
|
);
|
|
});
|
|
|