1// Service Worker for GROBID Tools 2// Version 2.0.0 3// - Pages (navigations): network-first, so content updates reach visitors; cached copy used offline. 4// - Same-origin static assets: stale-while-revalidate. 5// - jsDelivr CDN (PDF.js, docx): network-first with cache fallback, so the extractor works offline. 6// - Analytics and other cross-origin requests are never cached. 7 8const CACHE_NAME = 'grobid-tools-v2'; 9const RUNTIME_CACHE = 'grobid-runtime-v2'; 10 11// App shell and key pages to cache on install (extensionless URLs, as served by Cloudflare Pages) 12const PRECACHE_URLS = [ 13 '/', 14 '/js/app.js', 15 '/css/site.css', 16 '/manifest.json', 17 '/guides/', 18 '/formats/' 19]; 20 21self.addEventListener('install', (event) => { 22 event.waitUntil( 23 caches.open(CACHE_NAME) 24 .then(cache => cache.addAll(PRECACHE_URLS)) 25 .then(() => self.skipWaiting()) 26 ); 27}); 28 29self.addEventListener('activate', (event) => { 30 event.waitUntil( 31 caches.keys().then(cacheNames => Promise.all( 32 cacheNames 33 .filter(name => name !== CACHE_NAME && name !== RUNTIME_CACHE) 34 .map(name => caches.delete(name)) 35 )).then(() => self.clients.claim()) 36 ); 37}); 38 39self.addEventListener('fetch', (event) => { 40 const { request } = event; 41 if (request.method !== 'GET') return; 42 43 const url = new URL(request.url); 44 45 // Cross-origin: only the jsDelivr CDN is cached; everything else (e.g. analytics) goes straight to the network. 46 if (url.origin !== location.origin) { 47 if (url.hostname === 'cdn.jsdelivr.net') { 48 event.respondWith( 49 caches.open(RUNTIME_CACHE).then(cache => 50 fetch(request) 51 .then(response => { 52 if (response.ok) cache.put(request, response.clone()); 53 return response; 54 }) 55 .catch(() => cache.match(request)) 56 ) 57 ); 58 } 59 return; 60 } 61 62 // Page navigations: network-first, fall back to cache, then to the home page. 63 if (request.mode === 'navigate') { 64 event.respondWith( 65 fetch(request) 66 .then(response => { 67 if (response.ok) { 68 const copy = response.clone(); 69 caches.open(RUNTIME_CACHE).then(cache => cache.put(request, copy)); 70 } 71 return response; 72 }) 73 .catch(() => caches.match(request).then(cached => cached || caches.match('/'))) 74 ); 75 return; 76 } 77 78 // Other same-origin assets: stale-while-revalidate. 79 event.respondWith( 80 caches.match(request).then(cached => { 81 const network = fetch(request) 82 .then(response => { 83 if (response.ok) { 84 const copy = response.clone(); 85 caches.open(RUNTIME_CACHE).then(cache => cache.put(request, copy)); 86 } 87 return response; 88 }) 89 .catch(() => cached); 90 return cached || network; 91 }) 92 ); 93}); 94 95self.addEventListener('message', (event) => { 96 if (event.data && event.data.type === 'SKIP_WAITING') { 97 self.skipWaiting(); 98 } 99 if (event.data && event.data.type === 'CLEAR_CACHE') { 100 event.waitUntil( 101 caches.keys().then(names => Promise.all(names.map(name => caches.delete(name)))) 102 ); 103 } 104});
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.