Files
bible/books/sw.js
T
2026-09-02 18:24:01 -04:00

187 lines
4.6 KiB
JavaScript

// Generated by render_books.py -- do not edit by hand.
//
// STRATEGY decides what a same-origin GET does:
//
// network-first ask the network, fall back to the cache when it fails.
// Offline, fetch rejects immediately, so the fallback is
// effectively instant -- the only cost is one round trip
// while online, and you never see a stale page.
// cache-first answer from the cache the moment there is a hit. Fastest
// possible load, but a rebuild needs two reloads to appear.
//
// Either way every response that arrives is written back to the cache, so the
// offline copy stays current, and a new build changes VERSION, dropping the
// caches belonging to older builds.
const STRATEGY = 'network-first';
const NETWORK_TIMEOUT_MS = 3000;
const VERSION = 'c5d29c3cdf15';
const CACHE = 'bible-' + VERSION;
const ASSETS = [
"./",
"./1CH.html",
"./1CO.html",
"./1ES.html",
"./1JN.html",
"./1KI.html",
"./1MA.html",
"./1PE.html",
"./1SA.html",
"./1TH.html",
"./1TI.html",
"./2CH.html",
"./2CO.html",
"./2ES.html",
"./2JN.html",
"./2KI.html",
"./2MA.html",
"./2PE.html",
"./2SA.html",
"./2TH.html",
"./2TI.html",
"./3JN.html",
"./3MA.html",
"./4MA.html",
"./ACT.html",
"./AMO.html",
"./BAR.html",
"./COL.html",
"./DAG.html",
"./DAN.html",
"./DEU.html",
"./ECC.html",
"./EPH.html",
"./ESG.html",
"./EST.html",
"./EXO.html",
"./EZK.html",
"./EZR.html",
"./FRT.html",
"./GAL.html",
"./GEN.html",
"./GLO.html",
"./HAB.html",
"./HAG.html",
"./HEB.html",
"./HOS.html",
"./ISA.html",
"./JAS.html",
"./JDG.html",
"./JDT.html",
"./JER.html",
"./JHN.html",
"./JOB.html",
"./JOL.html",
"./JON.html",
"./JOS.html",
"./JUD.html",
"./LAM.html",
"./LEV.html",
"./LUK.html",
"./MAL.html",
"./MAN.html",
"./MAT.html",
"./MIC.html",
"./MRK.html",
"./NAM.html",
"./NEH.html",
"./NUM.html",
"./OBA.html",
"./PHM.html",
"./PHP.html",
"./PRO.html",
"./PS2.html",
"./PSA.html",
"./REV.html",
"./ROM.html",
"./RUT.html",
"./SIR.html",
"./SNG.html",
"./TIT.html",
"./TOB.html",
"./WIS.html",
"./ZEC.html",
"./ZEP.html",
"./app.js",
"./bible.css",
"./icons/apple-touch-icon.png",
"./icons/icon-192.png",
"./icons/icon-512.png",
"./index.html",
"./manifest.webmanifest"
];
self.addEventListener('install', (event) => {
event.waitUntil((async () => {
const cache = await caches.open(CACHE);
// Added one at a time rather than addAll(): addAll is atomic, so a single
// failed asset would leave the app with no offline copy at all.
let failed = 0;
await Promise.all(ASSETS.map((url) =>
cache.add(new Request(url, { cache: 'reload' })).catch(() => { failed++; })));
if (failed) console.warn('precache: ' + failed + ' of ' + ASSETS.length + ' failed');
await self.skipWaiting();
})());
});
self.addEventListener('activate', (event) => {
event.waitUntil((async () => {
const keys = await caches.keys();
await Promise.all(keys
.filter((k) => k.startsWith('bible-') && k !== CACHE)
.map((k) => caches.delete(k)));
await self.clients.claim();
})());
});
self.addEventListener('fetch', (event) => {
const req = event.request;
if (req.method !== 'GET') return;
if (new URL(req.url).origin !== location.origin) return;
event.respondWith(respond(event));
});
// Aborted rather than raced, so a hung request is actually torn down instead
// of leaking while the cache answers.
async function fromNetwork(req) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), NETWORK_TIMEOUT_MS);
try {
return await fetch(req, { signal: controller.signal });
} finally {
clearTimeout(timer);
}
}
function cached(req) {
return caches.match(req, { ignoreSearch: true });
}
async function respond(event) {
const req = event.request;
if (STRATEGY === 'cache-first') {
const hit = await cached(req);
if (hit) return hit;
}
try {
const res = await fromNetwork(req);
if (res && res.ok && res.type === 'basic') {
const copy = res.clone();
// Not awaited: the response should not wait on the cache write.
event.waitUntil(caches.open(CACHE).then((c) => c.put(req, copy)));
}
return res;
} catch (err) {
const hit = await cached(req);
if (hit) return hit;
// Offline and never cached. Navigations get the index rather than the
// browser's error page; anything else genuinely fails.
if (req.mode === 'navigate') {
const index = await cached('./index.html');
if (index) return index;
}
throw err;
}
}