1// Service Worker - PWA ì¤íë¼ì¸ ì§ì 2const CACHE_NAME = 'blackall-ai-v3'; 3const urlsToCache = [ 4 '/', 5 '/manifest.json', 6 '/192.png', 7 '/512.png', 8]; 9 10// ì¤ì¹ - ìºì ìì± 11self.addEventListener('install', (event) => { 12 event.waitUntil( 13 caches.open(CACHE_NAME).then((cache) => { 14 console.log('â Cache opened'); 15 return cache.addAll(urlsToCache); 16 }) 17 ); 18 self.skipWaiting(); 19}); 20 21// ì¹ í¸ì ìì - ì¤ì OS/ë¸ë¼ì°ì ì림 íì (push-send ì£ì§íì ì´ ë°ì¡) 22self.addEventListener('push', (event) => { 23 let data = {}; 24 try { 25 data = event.data ? event.data.json() : {}; 26 } catch (e) { 27 data = { title: 'BlackAll', body: event.data ? event.data.text() : '' }; 28 } 29 30 const title = data.title || 'BlackAll'; 31 const options = { 32 body: data.body || '', 33 icon: data.icon || '/192.png', 34 badge: '/192.png', 35 data: { url: data.url || '/' }, 36 }; 37 38 event.waitUntil(self.registration.showNotification(title, options)); 39}); 40 41// ì림 í´ë¦ - í´ë¹ URL íì´ ì´ë ¤ìì¼ë©´ í¬ì»¤ì¤, ìì¼ë©´ ì í 42self.addEventListener('notificationclick', (event) => { 43 event.notification.close(); 44 const url = event.notification.data?.url || '/'; 45 46 event.waitUntil( 47 self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clients) => { 48 for (const client of clients) {
49 if (client.url.includes(url) && 'focus' in client) return client.focus(); 50 } 51 if (self.clients.openWindow) return self.clients.openWindow(url); 52 }) 53 ); 54}); 55 56// íì±í - ì´ì ìºì ìì 57self.addEventListener('activate', (event) => { 58 event.waitUntil( 59 caches.keys().then((cacheNames) => { 60 return Promise.all( 61 cacheNames.map((cacheName) => { 62 if (cacheName !== CACHE_NAME) { 63 console.log('ðï¸ Deleting old cache:', cacheName); 64 return caches.delete(cacheName); 65 } 66 }) 67 ); 68 }) 69 ); 70 self.clients.claim(); 71}); 72 73// Fetch - ë¤í¸ìí¬ ì°ì , ì¤í¨ ì ìºì 74self.addEventListener('fetch', (event) => { 75 // POST ë± non-GET ìì²ì ìºì ë¶ê° â ê·¸ëë¡ íµê³¼ 76 if (event.request.method !== 'GET') { 77 return; 78 } 79 80 const url = event.request.url; 81 82 // http(s) ì¸ ì¤í´ì ìºì ë¶ê° (chrome-extension://, data:, blob: ë±) 83 if (!url.startsWith('http://') && !url.startsWith('https://')) { 84 return; 85 } 86 87 // anatomy-real.html(1.77MB 3D ë·°ì´)ì SW ìºì ì ì¸ â ì ë²ì ì´ êµ³ì´ë²ë¦¬ë ê² ë°©ì§. 88 // ë²ì ì iframe ?v= ì¿¼ë¦¬ë¡ ê´ë¦¬. ë¤í¸ìí¬ ì§íµ. 89 if (url.includes('anatomy-real.html')) { 90 return; 91 } 92 93 // Supabase API ìì²ì ìºìíì§ ìì (ì¸ì¦/ì¸ì ê´ë ¨ stale ìëµ ë°©ì§) 94 if (url.includes('supabase.co')) { 95 return; 96 } 97 98 event.respondWith( 99 fetch(event.request) 100 .then((response) => { 101 // GET 200 ìëµë§ ìºìì ì ì¥ (basic/cors íì ë§ â opaque ìëµ ì ì¸) 102 if (response.status === 200 && (response.type === 'basic' || response.type === 'cors')) { 103 const responseClone = response.clone(); 104 caches.open(CACHE_NAME).then((cache) => { 105 cache.put(event.request, responseClone).catch(() => {}); 106 }); 107 } 108 return response; 109 }) 110 .catch(async () => { 111 // ë¤í¸ìí¬ ì¤í¨ ì ìºììì ë°í, ìì¼ë©´ 503 112 const cached = await caches.match(event.request); 113 return cached || new Response('Network unavailable', { status: 503, statusText: 'Service Unavailable' }); 114 }) 115 ); 116});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.