Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kentcdodds/lineage

src/ui/sw-script.ts

65 lines · 2.0 KB · TypeScript
import { scopedAssetPath } from './app-url.ts'

export function serviceWorkerScript(scope: string) {
	const root = scope.endsWith('/') ? scope : `${scope}/`
	const shell = [
		scopedAssetPath(root, 'manifest.webmanifest'),
		scopedAssetPath(root, 'favicon.png'),
		scopedAssetPath(root, 'apple-touch-icon.png'),
		scopedAssetPath(root, 'pwa-192.png'),
		scopedAssetPath(root, 'icon.svg'),
	]
	return `const SCOPE = ${JSON.stringify(root)};
const VERSION = 'lineage-v8';
const SHELL = ${JSON.stringify(shell)};

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(VERSION).then((cache) =>
      Promise.all(SHELL.map((url) => cache.add(url).catch(() => undefined))),
    ).then(() => {
      if (!self.registration.active) return self.skipWaiting();
    }),
  );
});

self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches.keys().then((keys) =>
      Promise.all(keys.filter((key) => key !== VERSION).map((key) => caches.delete(key))),
    ).then(() => self.clients.claim()),
  );
});

self.addEventListener('message', (event) => {
  if (event.data === 'SKIP_WAITING') self.skipWaiting();
});

self.addEventListener('fetch', (event) => {
  const request = event.request;
  if (request.method !== 'GET') return;
  const url = new URL(request.url);
  const isApi = url.pathname.includes('/api/');
  const isDocument = request.mode === 'navigate' || url.pathname === SCOPE || url.pathname === SCOPE.slice(0, -1);
  if (isApi || isDocument) {
    event.respondWith(
      fetch(request).then((response) => {
        if (isApi && response.ok) {
          const copy = response.clone();
          caches.open(VERSION).then((cache) => cache.put(request, copy));
        }
        return response;
      }).catch(() => caches.match(request)),
    );
    return;
  }
  event.respondWith(
    caches.match(request).then((cached) => cached || fetch(request).then((response) => {
      const copy = response.clone();
      caches.open(VERSION).then((cache) => cache.put(request, copy));
      return response;
    })),
  );
});
`
}