/// const CACHE_NAME: string = 'sukisu-ultra-v2.0' const STATIC_CACHE: string = 'sukisu-static-v2.0' const RUNTIME_CACHE: string = 'sukisu-runtime-v2.0' const IMAGE_CACHE: string = 'sukisu-images-v2.0' const CRITICAL_ASSETS: string[] = [ '/', '/guide/', '/guide/installation', '/guide/compatibility', '/zh/', '/zh/guide/', '/logo.svg', '/favicon.ico', '/offline.html', ] const CACHE_STRATEGIES: { static: string[] images: string[] documents: string[] } = { static: ['.css', '.js', '.woff2', '.woff', '.ttf', '.otf'], images: ['.png', '.jpg', '.jpeg', '.svg', '.webp', '.avif', '.gif', '.ico'], documents: ['.html', '.json', '.xml'], } self.addEventListener('install', (event: ExtendableEvent) => { event.waitUntil( (async (): Promise => { const cache: Cache = await caches.open(STATIC_CACHE) try { await cache.addAll(CRITICAL_ASSETS) } catch (error) { console.warn('Failed to cache some assets:', error) } ;(self as any).skipWaiting() })() ) }) self.addEventListener('activate', (event: ExtendableEvent) => { event.waitUntil( (async (): Promise => { const cacheNames: string[] = await caches.keys() const validCaches: string[] = [STATIC_CACHE, RUNTIME_CACHE, IMAGE_CACHE, CACHE_NAME] await Promise.all( cacheNames .filter((name: string) => !validCaches.includes(name)) .map((name: string) => caches.delete(name)) ) ;(self as any).clients.claim() })() ) }) self.addEventListener('fetch', (event: FetchEvent) => { const { request } = event const url: URL = new URL(request.url) if (request.method !== 'GET' || url.origin !== location.origin) return if (url.pathname.startsWith('/api/')) return event.respondWith(handleRequest(request, url)) }) async function handleRequest(request: Request, url: URL): Promise { const isStatic: boolean = CACHE_STRATEGIES.static.some((ext: string) => url.pathname.endsWith(ext) ) const isImage: boolean = CACHE_STRATEGIES.images.some((ext: string) => url.pathname.endsWith(ext)) const isDocument: boolean = CACHE_STRATEGIES.documents.some((ext: string) => url.pathname.endsWith(ext)) || url.pathname.endsWith('/') try { if (isStatic) { return await handleStatic(request) } else if (isImage) { return await handleImage(request) } else if (isDocument) { return await handleDocument(request) } else { return await handleDefault(request) } } catch (error) { return await handleOffline(request) } } async function handleStatic(request: Request): Promise { const cache: Cache = await caches.open(STATIC_CACHE) const cached: Response | undefined = await cache.match(request) if (cached) { fetch(request) .then((response: Response) => { if (response.ok) cache.put(request, response.clone()) }) .catch(() => {}) return cached } const response: Response = await fetch(request) if (response.ok) { cache.put(request, response.clone()) } return response } async function handleImage(request: Request): Promise { const cache: Cache = await caches.open(IMAGE_CACHE) const cached: Response | undefined = await cache.match(request) if (cached) return cached const response: Response = await fetch(request) if (response.ok) { cache.put(request, response.clone()) } return response } async function handleDocument(request: Request): Promise { const cache: Cache = await caches.open(RUNTIME_CACHE) try { const response: Response = await fetch(request) if (response.ok) { cache.put(request, response.clone()) } return response } catch (error) { const cached: Response | undefined = await cache.match(request) if (cached) return cached if (request.mode === 'navigate') { const offlinePage: Response | undefined = await caches.match('/offline.html') if (offlinePage) return offlinePage } throw error } } async function handleDefault(request: Request): Promise { const cache: Cache = await caches.open(RUNTIME_CACHE) try { const response: Response = await fetch(request) if (response.ok) { cache.put(request, response.clone()) } return response } catch (error) { const cached: Response | undefined = await cache.match(request) if (cached) return cached throw error } } async function handleOffline(request: Request): Promise { const cache: Cache = await caches.open(STATIC_CACHE) if (request.mode === 'navigate') { const offlinePage: Response | undefined = await caches.match('/offline.html') if (offlinePage) return offlinePage } return new Response('Offline', { status: 503, statusText: 'Service Unavailable', headers: new Headers({ 'Content-Type': 'text/plain', }), }) } self.addEventListener('sync', (event: any) => { if (event.tag === 'data-sync') { event.waitUntil(syncData()) } }) async function syncData(): Promise { try { console.log('Syncing application data...') } catch (error) { console.error('Data sync failed:', error) } } interface PerformanceMessage { type: string name: string } self.addEventListener('message', (event: MessageEvent) => { const data = event.data as PerformanceMessage if (data && data.type === 'PERFORMANCE_MARK') { performance.mark(data.name) } })