SPB Git

Repository Public

sw.js 2.7 KB 55 lines javascript

1/*2 * Claude Remote service worker — caches the STATIC APP SHELL only.3 *   cached:      /_next/static/*, fonts, icons, the manifest and the HTML shells of the routes4 *   never:       /api/* (not even looked at), WebSockets (not interceptable anyway), anything5 *                non-GET or cross-origin. No terminal data, API response or credential is stored.6 * Offline: navigations fall back to the cached shell, which renders the "Offline" state.7 */8const VERSION = 'cr-shell-v2';9const SHELLS = ['/', '/login/', '/setup/', '/home/', '/terminal/', '/sessions/', '/projects/', '/files/', '/tasks/', '/cluster/', '/skills/', '/mcp/', '/system/', '/settings/'];10const PRECACHE = [...SHELLS, '/theme-init.js', '/manifest.webmanifest', '/icons/icon-192.png', '/icons/apple-touch-icon.png'];1112self.addEventListener('install', (event) => {13  event.waitUntil(14    caches.open(VERSION).then((cache) => Promise.all(PRECACHE.map((u) => cache.add(new Request(u, { cache: 'reload' })).catch(() => undefined)))).then(() => self.skipWaiting()),15  );16});17self.addEventListener('activate', (event) => {18  event.waitUntil(19    caches.keys().then((keys) => Promise.all(keys.filter((k) => k !== VERSION).map((k) => caches.delete(k)))).then(() => self.clients.claim()),20  );21});2223function isStaticAsset(url) {24  return url.pathname.startsWith('/_next/static/') || url.pathname.startsWith('/icons/') || url.pathname === '/manifest.webmanifest' || url.pathname === '/theme-init.js' || /\.(woff2?|ttf)$/.test(url.pathname);25}2627self.addEventListener('fetch', (event) => {28  const req = event.request;29  if (req.method !== 'GET') return;30  const url = new URL(req.url);31  if (url.origin !== self.location.origin) return;32  if (url.pathname.startsWith('/api/')) return; // never handled, never cached3334  if (isStaticAsset(url)) {35    // content-hashed: cache first36    event.respondWith(37      caches.match(req).then((hit) => hit || fetch(req).then((res) => {38        if (res.ok) { const copy = res.clone(); caches.open(VERSION).then((c) => c.put(req, copy)); }39        return res;40      })),41    );42    return;43  }44  if (req.mode === 'navigate' || url.pathname.endsWith('.txt')) {45    // HTML shells and RSC payloads: network first (always fresh when online), cache as fallback46    const key = url.origin + url.pathname; // ignore ?s=… so one shell serves every query47    event.respondWith(48      fetch(req).then((res) => {49        if (res.ok && res.status === 200) { const copy = res.clone(); caches.open(VERSION).then((c) => c.put(key, copy)); }50        return res;51      }).catch(() => caches.match(key).then((hit) => hit || (req.mode === 'navigate' ? caches.match(url.origin + '/terminal/') : undefined)).then((hit) => hit || Response.error())),52    );53  }54});55
Files main
Menu

Theme