77 lines
2.8 KiB
JavaScript
77 lines
2.8 KiB
JavaScript
|
|
// TeeCup service worker (ADR-028) -- håndskrevet, ingen next-pwa/workbox-
|
||
|
|
// avhengighet. To ansvar, begge begrenset med vilje:
|
||
|
|
//
|
||
|
|
// 1) Cache side-NAVIGASJON (nettverk først, cache som fallback, offline.html
|
||
|
|
// som siste utvei) -- en tidligere besøkt side kan åpnes på nytt uten
|
||
|
|
// nett.
|
||
|
|
// 2) Cache GET-kall under /orgs/* (nettverk først, cache som fallback) --
|
||
|
|
// slik at data for en allerede åpnet side (f.eks. et scorekort) fortsatt
|
||
|
|
// er LESBAR offline. Bevisst IKKE stale-while-revalidate: scorekortet
|
||
|
|
// leses på nytt rett etter hver innsending, og må da alltid prøve ekte
|
||
|
|
// fersk data først -- en umiddelbart utdatert cache ville vist feil
|
||
|
|
// matchstatus/hull-tall rett etter en vellykket innsending.
|
||
|
|
//
|
||
|
|
// Selve SKRIVINGEN (hole-scores/hole-results) fanges ALDRI her -- det
|
||
|
|
// håndteres i lib/offline-queue.ts, med en egen IndexedDB-kø i klientkoden,
|
||
|
|
// hvor UI-et kan gi umiddelbar, presis tilbakemelding ("lagret lokalt,
|
||
|
|
// venter på synk"). /auth/* og /public/* caches bevisst ikke -- caching er
|
||
|
|
// begrenset til akkurat det scoreregistrerings-flyten trenger.
|
||
|
|
//
|
||
|
|
// Kjent, akseptert begrensning: Cache Storage er nøklet på URL, ikke på
|
||
|
|
// innlogget bruker/sesjon -- deler flere kontoer samme enhet/nettleser,
|
||
|
|
// kan en offline-fallback vise data cachet av en TIDLIGERE innlogget
|
||
|
|
// bruker på samme enhet. Ikke løst i v1 (samme tillitsnivå som resten av
|
||
|
|
// appen, se team_authz.py sin trusselmodell-begrunnelse), ingen
|
||
|
|
// cache-tømming ved utlogging bygget ennå.
|
||
|
|
|
||
|
|
const RUNTIME_CACHE = "teecup-runtime-v1"
|
||
|
|
const OFFLINE_URL = "/offline.html"
|
||
|
|
|
||
|
|
self.addEventListener("install", (event) => {
|
||
|
|
event.waitUntil(
|
||
|
|
caches
|
||
|
|
.open(RUNTIME_CACHE)
|
||
|
|
.then((cache) => cache.add(OFFLINE_URL))
|
||
|
|
.then(() => self.skipWaiting()),
|
||
|
|
)
|
||
|
|
})
|
||
|
|
|
||
|
|
self.addEventListener("activate", (event) => {
|
||
|
|
event.waitUntil(
|
||
|
|
caches
|
||
|
|
.keys()
|
||
|
|
.then((keys) => Promise.all(keys.filter((k) => k !== RUNTIME_CACHE).map((k) => caches.delete(k))))
|
||
|
|
.then(() => self.clients.claim()),
|
||
|
|
)
|
||
|
|
})
|
||
|
|
|
||
|
|
self.addEventListener("fetch", (event) => {
|
||
|
|
const req = event.request
|
||
|
|
if (req.method !== "GET") return // skriving går aldri via SW-en
|
||
|
|
|
||
|
|
if (req.mode === "navigate") {
|
||
|
|
event.respondWith(
|
||
|
|
fetch(req)
|
||
|
|
.then((res) => {
|
||
|
|
const copy = res.clone()
|
||
|
|
caches.open(RUNTIME_CACHE).then((cache) => cache.put(req, copy))
|
||
|
|
return res
|
||
|
|
})
|
||
|
|
.catch(async () => (await caches.match(req)) || (await caches.match(OFFLINE_URL))),
|
||
|
|
)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
const url = new URL(req.url)
|
||
|
|
if (url.origin === self.location.origin && url.pathname.startsWith("/orgs/")) {
|
||
|
|
event.respondWith(
|
||
|
|
fetch(req)
|
||
|
|
.then((res) => {
|
||
|
|
if (res.ok) caches.open(RUNTIME_CACHE).then((cache) => cache.put(req, res.clone()))
|
||
|
|
return res
|
||
|
|
})
|
||
|
|
.catch(() => caches.match(req)),
|
||
|
|
)
|
||
|
|
}
|
||
|
|
})
|