/** * LEAF_AI Service Worker (PWA Offline Support) * Cho phép nông dân mở app và tra cứu cẩm nang/thư viện ngay tại vườn khi không có mạng 4G/Wifi. */ const CACHE_NAME = 'leaf-ai-v1.0.0'; const STATIC_ASSETS = [ './', './index.html', './manifest.json', './assets/css/style.css', './assets/js/disease_data.js', './assets/js/canvas_render.js', './assets/js/camera.js', './assets/js/api.js', './assets/js/three_leaf.js', './assets/js/app.js' ]; // Install: Cache các tài nguyên tĩnh cần thiết self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_NAME).then((cache) => { console.log('[LEAF_AI SW] Caching offline assets...'); return cache.addAll(STATIC_ASSETS).catch(err => { console.warn('[LEAF_AI SW] Cache addAll warning:', err); }); }).then(() => self.skipWaiting()) ); }); // Activate: Xóa cache cũ nếu nâng cấp phiên bản self.addEventListener('activate', (event) => { event.waitUntil( caches.keys().then((keys) => { return Promise.all( keys.map((key) => { if (key !== CACHE_NAME) { console.log('[LEAF_AI SW] Removing old cache:', key); return caches.delete(key); } }) ); }).then(() => self.clients.claim()) ); }); // Fetch: Chiến lược Network First, Fallback to Cache self.addEventListener('fetch', (event) => { // Chỉ cache các request HTTP/HTTPS và GET if (event.request.method !== 'GET') return; event.respondWith( fetch(event.request) .then((networkResponse) => { if (networkResponse && networkResponse.status === 200) { const responseClone = networkResponse.clone(); caches.open(CACHE_NAME).then((cache) => { cache.put(event.request, responseClone); }); } return networkResponse; }) .catch(() => { // Nếu offline, lấy từ cache return caches.match(event.request).then((cachedResponse) => { if (cachedResponse) { return cachedResponse; } if (event.request.mode === 'navigate') { return caches.match('./index.html'); } }); }) ); });