40 lines
2.0 KiB
JavaScript
40 lines
2.0 KiB
JavaScript
'use strict';
|
|
// Serve app files and individually selected route snapshots independently (v2).
|
|
importScripts('/js/offline-storage.js');
|
|
|
|
globalThis.addEventListener('install', event => event.waitUntil(globalThis.skipWaiting()));
|
|
globalThis.addEventListener('activate', event => event.waitUntil(globalThis.clients.claim()));
|
|
|
|
/** Audio seeks need partial responses even when the entire file is stored locally. */
|
|
async function rangedResponse(response, range) {
|
|
const bytes = await response.arrayBuffer();
|
|
const match = /^bytes=(\d*)-(\d*)$/.exec(range);
|
|
if (!match || (!match[1] && !match[2])) return new Response(null, { status: 416, headers: { 'Content-Range': `bytes */${bytes.byteLength}` } });
|
|
const start = match[1] ? Number(match[1]) : Math.max(0, bytes.byteLength - Number(match[2]));
|
|
let end = bytes.byteLength - 1;
|
|
if (match[1] && match[2]) end = Math.min(Number(match[2]), end);
|
|
if (start > end || start >= bytes.byteLength) return new Response(null, { status: 416, headers: { 'Content-Range': `bytes */${bytes.byteLength}` } });
|
|
const headers = new Headers(response.headers);
|
|
headers.set('Content-Range', `bytes ${start}-${end}/${bytes.byteLength}`);
|
|
headers.set('Content-Length', String(end - start + 1));
|
|
headers.set('Accept-Ranges', 'bytes');
|
|
return new Response(bytes.slice(start, end + 1), { status: 206, headers });
|
|
}
|
|
|
|
globalThis.addEventListener('fetch', event => {
|
|
const request = event.request;
|
|
const url = new URL(request.url);
|
|
if (request.method !== 'GET' || url.origin !== globalThis.location.origin
|
|
|| request.headers.has('X-Wegwichtel-Offline-Download')
|
|
|| url.pathname === '/api/offline-manifest') return;
|
|
event.respondWith((async () => {
|
|
// A complete snapshot is cache-first, avoiding any wait for a failing mobile network.
|
|
const cached = await globalThis.Wegwichtel.OfflineStore.match(request.url).catch(() => null);
|
|
if (cached) {
|
|
const range = request.headers.get('Range');
|
|
return range ? rangedResponse(cached, range) : cached;
|
|
}
|
|
return fetch(request);
|
|
})());
|
|
});
|