- Created complete documentation in docs/ directory - Added PROJECT_OVERVIEW.md with feature highlights and getting started guide - Added ARCHITECTURE.md with system design and technical details - Added SECURITY.md with comprehensive security implementation guide - Added DEVELOPMENT.md with development workflows and best practices - Added DEPLOYMENT.md with production deployment instructions - Added API.md with complete REST API documentation - Added CONTRIBUTING.md with contribution guidelines - Added CHANGELOG.md with version history and migration notes - Reorganized all documentation files into docs/ directory for better organization - Updated README.md with proper documentation links and quick navigation - Enhanced project structure with professional documentation standards
60 lines
1.9 KiB
JavaScript
60 lines
1.9 KiB
JavaScript
// EasyStream Service Worker (lightweight, safe defaults)
|
|
const CACHE_VERSION = 'es-v1';
|
|
const STATIC_CACHE = `${CACHE_VERSION}-static`;
|
|
const PRECACHE = [
|
|
'/index.js',
|
|
'/manifest.json'
|
|
];
|
|
|
|
self.addEventListener('install', (event) => {
|
|
event.waitUntil((async () => {
|
|
const cache = await caches.open(STATIC_CACHE);
|
|
await cache.addAll(PRECACHE);
|
|
self.skipWaiting();
|
|
})());
|
|
});
|
|
|
|
self.addEventListener('activate', (event) => {
|
|
event.waitUntil((async () => {
|
|
const keys = await caches.keys();
|
|
await Promise.all(keys.filter(k => !k.startsWith(CACHE_VERSION)).map(k => caches.delete(k)));
|
|
self.clients.claim();
|
|
})());
|
|
});
|
|
|
|
self.addEventListener('fetch', (event) => {
|
|
const url = event.request.url;
|
|
// never cache uploads or HLS segments/manifests
|
|
if (url.includes('upload') || url.includes('uploader') || url.includes('index.m3u8') || url.includes('.ts')) {
|
|
return; // bypass SW
|
|
}
|
|
|
|
// Navigation requests: network-first with cache fallback for basic offline shell
|
|
if (event.request.mode === 'navigate') {
|
|
event.respondWith((async () => {
|
|
try {
|
|
const fresh = await fetch(event.request);
|
|
return fresh;
|
|
} catch (e) {
|
|
const cache = await caches.open(STATIC_CACHE);
|
|
const shell = await cache.match('/index.js');
|
|
return shell || Response.error();
|
|
}
|
|
})());
|
|
return;
|
|
}
|
|
|
|
// Others: stale-while-revalidate
|
|
event.respondWith((async () => {
|
|
const cached = await caches.match(event.request);
|
|
const fetchPromise = fetch(event.request).then((networkResponse) => {
|
|
if (networkResponse && networkResponse.ok && event.request.method === 'GET') {
|
|
const copy = networkResponse.clone();
|
|
caches.open(STATIC_CACHE).then((cache) => cache.put(event.request, copy)).catch(() => {});
|
|
}
|
|
return networkResponse;
|
|
}).catch(() => cached);
|
|
return cached || fetchPromise;
|
|
})());
|
|
});
|