offline = function () {
console.log("Service worker exec");
self.importScripts(
"https://cdnjs.cloudflare.com/ajax/libs/pako/2.0.3/pako.es5.min.js",
"./untar.js"
);
self.addEventListener("install", function (event) {
console.log("service worker has been installed");
});
function mime(name) {
if (name.endsWith(".js")) return "text/javascript";
if (name.endsWith(".html")) return "text/html";
if (name.endsWith(".css")) return "text/css";
if (name.endsWith(".jpg")) return "image/jpeg";
if (name.endsWith(".jpeg")) return "image/jpeg";
if (name.endsWith(".png")) return "image/png";
return "application/octet-stream";
}
self.addEventListener("fetch", function (event) {
let match = undefined;
async function answer() {
debugger;
if (
(match = event.request.url.match(
/observablehq\.com\/@[^/]*\/offline\/(.*\.tgz(?:[?]v=\d)?)(\/[^?#]*)?$/
))
) {
let archiveURL = match[1];
if (
archiveURL.startsWith("https:/") &&
!archiveURL.startsWith("https://")
) {
archiveURL = archiveURL.replace("https:/", "https://");
}
if (!match[2])
return new Response("", {
status: 301,
headers: {
Location: `${event.request.url}/index.html`
}
});
const path = "." + match[2];
const archiveRequest = new Request(archiveURL);
const cache = await caches.open("archives");
const cachedResponse = await cache.match(event.request);
const archiveResponse =
cachedResponse ||
(await fetch(archiveRequest).then((response) => {
if (response.status >= 200 && response.status < 400)
cache.put(archiveRequest, response.clone());
return response;
}));
if (archiveResponse.status !== 200) {
return archiveResponse;
}
const buffer = new Uint8Array(await archiveResponse.arrayBuffer());
const uncompressed = await pako.ungzip(buffer);
const reader = new UntarFileStream(uncompressed.buffer);
const contents = {};
while (reader.hasNext()) {
const file = reader.next();
contents[file.name] = file;
}
if (contents[path]) {
const type = mime(path);
return new Response(contents[path].buffer, {
headers: {
"content-type": type
}
});
} else {
return new Response(`Not found: ${path}`, {
status: 404
});
}
} else {
// Normal events response but cache, and use network if we are offline
const cache = await caches.open("offline");
try {
const response = await fetch(event.request);
if (event.request.method == "GET") {
cache.put(event.request, response.clone());
}
return response;
} catch (err) {
// we are offline!
const cachedReponse = cache.match(event.request);
return cachedReponse;
}
return fetch(event.request);
}
}
event.respondWith(answer());
});
}