53 lines
2.5 KiB
JavaScript
53 lines
2.5 KiB
JavaScript
// Omnigent installability / update-only service worker (hand-rolled).
|
|
//
|
|
// Omnigent is a cloud app with NO offline mode, so this worker deliberately:
|
|
// - does NOT precache or serve the app shell, and
|
|
// - does NOT intercept navigations — every navigation hits the network, so a
|
|
// deploy is never masked behind a stale cached shell.
|
|
// It exists only to (a) make the app installable and (b) drive the in-app
|
|
// "new version → Reload" prompt (see src/components/pwa/useServiceWorkerUpdate).
|
|
//
|
|
// BUILD_VERSION is replaced at build time (vite.config.ts → emitPwaAssets) with
|
|
// a fingerprint of the hashed JS/CSS outputs, so this file's bytes change on
|
|
// every code/style deploy. That byte change is what the browser's update
|
|
// algorithm (via workbox-window in the page) detects to fire the prompt.
|
|
const BUILD_VERSION = "__BUILD_VERSION__";
|
|
const CACHE_NAME = `omnigent-pwa-${BUILD_VERSION}`;
|
|
|
|
self.addEventListener("install", (event) => {
|
|
// Precache ONLY version.json. Two reasons: it gives the worker a real
|
|
// (non-empty) fetch handler — Chrome's automatic install prompt ignores
|
|
// no-op handlers — and the per-build cache name means each deploy starts a
|
|
// fresh cache. We do NOT call skipWaiting(): a new build waits in the
|
|
// background until the user accepts the prompt.
|
|
event.waitUntil(caches.open(CACHE_NAME).then((cache) => cache.add("/version.json")));
|
|
});
|
|
|
|
self.addEventListener("activate", (event) => {
|
|
// Drop caches from prior builds. No clients.claim(): in prompt mode the new
|
|
// worker must not take control of open pages until the user accepts.
|
|
event.waitUntil(
|
|
caches
|
|
.keys()
|
|
.then((keys) =>
|
|
Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key))),
|
|
),
|
|
);
|
|
});
|
|
|
|
self.addEventListener("message", (event) => {
|
|
// workbox-window's messageSkipWaiting() posts this when the user clicks Reload.
|
|
if (event.data && event.data.type === "SKIP_WAITING") self.skipWaiting();
|
|
});
|
|
|
|
self.addEventListener("fetch", (event) => {
|
|
// Respond ONLY for the version sentinel (cache-first, network fallback).
|
|
// Everything else — navigations, hashed assets, everything — falls through
|
|
// with no respondWith(), i.e. straight to the network. This keeps a real
|
|
// fetch handler without ever serving a stale app shell.
|
|
const url = new URL(event.request.url);
|
|
if (url.pathname === "/version.json") {
|
|
event.respondWith(caches.match(event.request).then((cached) => cached || fetch(event.request)));
|
|
}
|
|
});
|