// Service Worker for Memos offline support const CACHE_NAME = "memos-cache-v1"; const RUNTIME_CACHE = "memos-runtime-cache-v1"; // Assets to cache on install const PRECACHE_ASSETS = [ "/", "/logo.webp", "/apple-touch-icon.png", "/android-chrome-192x192.png", "/android-chrome-512x512.png", ]; // Install event - cache essential assets self.addEventListener("install", (event) => { event.waitUntil( caches.open(CACHE_NAME).then((cache) => { return cache.addAll(PRECACHE_ASSETS).catch((error) => { console.error("Failed to cache assets during install:", error); }); }) ); self.skipWaiting(); }); // Activate event - cleanup old caches self.addEventListener("activate", (event) => { event.waitUntil( caches.keys().then((cacheNames) => { return Promise.all( cacheNames.map((cacheName) => { if (cacheName !== CACHE_NAME && cacheName !== RUNTIME_CACHE) { return caches.delete(cacheName); } }) ); }) ); self.clients.claim(); }); // Fetch event - network first, fallback to cache self.addEventListener("fetch", (event) => { // Skip cross-origin requests if (!event.request.url.startsWith(self.location.origin)) { return; } // Skip non-GET requests if (event.request.method !== "GET") { return; } event.respondWith( fetch(event.request) .then((response) => { // Don't cache if not a valid response if (!response || response.status !== 200 || response.type === "error") { return response; } // Clone the response const responseToCache = response.clone(); // Cache the fetched response caches.open(RUNTIME_CACHE).then((cache) => { cache.put(event.request, responseToCache); }); return response; }) .catch(() => { // Network failed, try cache return caches.match(event.request).then((response) => { if (response) { return response; } // If not in cache and offline, return a basic offline page for navigation requests if (event.request.mode === "navigate") { return caches.match("/"); } return new Response("Offline - resource not available", { status: 503, statusText: "Service Unavailable", headers: new Headers({ "Content-Type": "text/plain", }), }); }); }) ); });