managarten/games/mana-games/apps/web/public/sw.js
Till-JS 23f8950318 feat(games): add mana-games - AI-powered browser games platform
New project with 22+ browser games and AI game generation capabilities:
- Astro PWA web app with game catalog and player
- NestJS backend with AI game generator (Gemini, Claude, GPT-4o)
- Community game submission via GitHub API
- postMessage integration for score tracking
- PWA support with offline capabilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 20:13:14 +01:00

170 lines
No EOL
4 KiB
JavaScript

const CACHE_NAME = 'mana-games-v1';
const OFFLINE_URL = '/offline.html';
// Assets, die immer gecacht werden sollen
const STATIC_CACHE_URLS = [
'/',
'/offline.html',
'/favicon.svg',
'/manifest.json'
];
// Cache-Strategien für verschiedene Ressourcen
const CACHE_STRATEGIES = {
// Netzwerk zuerst, dann Cache (für HTML)
networkFirst: [
/\/$/,
/\.html$/,
/\.astro$/
],
// Cache zuerst, dann Netzwerk (für Assets)
cacheFirst: [
/\.css$/,
/\.js$/,
/\.woff2?$/,
/\.ttf$/,
/\.otf$/,
/\.svg$/,
/\.png$/,
/\.jpg$/,
/\.jpeg$/,
/\.webp$/,
/\.ico$/
],
// Nur Netzwerk (für API-Calls)
networkOnly: [
/\/api\//,
/\.json$/
]
};
// Service Worker Installation
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
console.log('Service Worker: Caching static assets');
return cache.addAll(STATIC_CACHE_URLS);
})
.then(() => self.skipWaiting())
);
});
// Service Worker Aktivierung
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys()
.then(cacheNames => {
return Promise.all(
cacheNames
.filter(cacheName => cacheName !== CACHE_NAME)
.map(cacheName => caches.delete(cacheName))
);
})
.then(() => self.clients.claim())
);
});
// Fetch-Event Handler
self.addEventListener('fetch', event => {
const { request } = event;
const url = new URL(request.url);
// Ignoriere Chrome Extension Requests
if (url.protocol === 'chrome-extension:') {
return;
}
// Bestimme die Cache-Strategie
const strategy = getStrategy(url.pathname);
if (strategy === 'networkFirst') {
event.respondWith(networkFirst(request));
} else if (strategy === 'cacheFirst') {
event.respondWith(cacheFirst(request));
} else if (strategy === 'networkOnly') {
event.respondWith(networkOnly(request));
} else {
// Standard: Network First
event.respondWith(networkFirst(request));
}
});
// Cache-Strategien Implementierung
async function networkFirst(request) {
try {
const networkResponse = await fetch(request);
if (networkResponse.ok) {
const cache = await caches.open(CACHE_NAME);
cache.put(request, networkResponse.clone());
}
return networkResponse;
} catch (error) {
const cachedResponse = await caches.match(request);
if (cachedResponse) {
return cachedResponse;
}
// Wenn es eine Navigation ist und wir offline sind, zeige die Offline-Seite
if (request.mode === 'navigate') {
const offlineResponse = await caches.match(OFFLINE_URL);
if (offlineResponse) {
return offlineResponse;
}
}
throw error;
}
}
async function cacheFirst(request) {
const cachedResponse = await caches.match(request);
if (cachedResponse) {
return cachedResponse;
}
try {
const networkResponse = await fetch(request);
if (networkResponse.ok) {
const cache = await caches.open(CACHE_NAME);
cache.put(request, networkResponse.clone());
}
return networkResponse;
} catch (error) {
console.error('Fetch failed:', error);
throw error;
}
}
async function networkOnly(request) {
return fetch(request);
}
// Hilfsfunktion zur Bestimmung der Cache-Strategie
function getStrategy(pathname) {
for (const [strategy, patterns] of Object.entries(CACHE_STRATEGIES)) {
if (patterns.some(pattern => pattern.test(pathname))) {
return strategy;
}
}
return 'networkFirst';
}
// Message Handler für Cache-Updates
self.addEventListener('message', event => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
if (event.data && event.data.type === 'CACHE_GAME') {
const gameUrl = event.data.url;
caches.open(CACHE_NAME)
.then(cache => cache.add(gameUrl))
.then(() => {
event.ports[0].postMessage({ cached: true });
})
.catch(error => {
event.ports[0].postMessage({ cached: false, error: error.message });
});
}
});