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";
if (name.endsWith(".wasm")) return "application/wasm";
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 (
// Express mangles the URL
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 pyodideMap = {
"./files/ea24ebecc9c0d5d4cca8ecda987dbcd493f1333bb061bd7b9edc7b3f51ee1b247b2f832762b756fa13e56203967b12053600db03c92c3db8acd3ab31d44c5b64.js":
"./pyodide.asm.js",
"./files/3f9e8867ec7101174202e358daaf8b58463662da2264f1196fd0229b28b149ec79a2dde5a32c4b2ad3b5e7a3cf356535cd96a04e4bc5f1ece0cdc63ce1fff0c1.tar":
"./distutils.tar",
"./files/7f25a40b29b600e90f212521d1d456a0ab78158153ed1eefcce567eaf4c061665d88452b2f49e6c1e4f995ae7948fa4bb2cebb79f5cd6d559551d42612766326.json":
"./pyodide.mjs.map",
"./files/015c0cd4adada3a1c09657f251efa246ac29ee65e91cea6debed2812e17b12b127e446148efd549680464759acb4909170272620797a290d47a923ce86ce1991.zip":
"./mgrs-1.4.5-cp310-cp310-emscripten_wasm32.whl",
"./files/22f8441bb22f41bc926bd010c5a6bf09be1b384a21c4e63f4594d1a7a686fbfbd366f3c7a05d0e62d75814dcfd0bebb63c8fad634fe264cb24fbc1fa1ad07955.js":
"./pyodide.js",
"./files/33f0adcf4d0447af1edbc118b1e5f26e4260a87a7bf5db6699074d9d7c86319a6e519d927c0536fed0b05f126d9890c13f3efcebee27a0eff19bc6eec09e9b11.js":
"./pyodide.mjs",
"./files/87bf3316d7c70a45bb72ef0e78d6c4255280290b7509535973b08374c1f8110bb88fe26a3cd01484a6682a986abd57bcd375d258d87b11437e450847104b7066.js":
"./webworker.js",
"./files/89e2e1ef1bc9ec4af52a7b6579b6cd979c8c81129d42b14deb560036e1dc60ce7cc1e49af5f53aadf8aafd3ccac54748d1e9963c89fbc850e062f7918dd9de62.ts":
"./pyodide.d.ts",
"./files/284a4f51b43101d33529dc435c47b651b2dc1164b1c867c0a15d794cca8ada4768401ed19bc2087a65957d23f3a9793ed65cef4e0d082eda3a0c09ebd556e1ea.wasm":
"./pyodide.asm.wasm",
"./files/397fbc22a7b2c2a422f8017464c18eb19768d3ed4137100a453275107555aec7636fbf57669f22bc3b830942b340c0dfdf4ce6f4b7a3f4c3d2c884b2c37896c2.json":
"./pyodide.js.map",
"./files/538cd97abbcc619f2dd393f51e2c0f06140da0d1782c68b3a0914186a98741753a7defa95c19cdae56448c134bc9a3c7c70fcdcf1cca23c55d70edbbc8af7356.bin":
"./pyodide.asm.data",
"./files/66451e86272209b9989c741be39152365517579b1ef568c7b7cf8a9f8dbe6070cec1cfa905171cd042f16be245fe70405b62bfafb96e6f8e26e205b5393097aa.zip":
"./packaging-21.3-py3-none-any.whl",
"./files/a9ee34bb6a6d4cd52c808dcd23e0e6bd7f01d9e29f75c5f6b76914e7c5d5fd81103aba14c1dabb8a115fd652eb040b822d1ff6460c92158887755ac7cc74269f.zip":
"./pyparsing-3.0.7-py3-none-any.whl",
"./files/c7daa306a70e9bdd76b0baffe8469d24ce14b4607114959aeb4881a243cdf2249b774c9daf0cc5b7db593f3fd4fbb5e350989dba709319b4ff73231332c3e435.zip":
"./numpy-1.22.3-cp310-cp310-emscripten_wasm32.whl",
"./files/c051fbc024553912e31968b35e537d4ad3592201b5f8e7bd13fd9d02e38599c5d541a704d0858c676328babb3e5c9c35dd7c6d67240090d094882a1cad8eece4.gif":
"./bl.gif",
"./files/c1905ed7800dd6a24f83c61f610b02729dd093158a973c434f4c7a88dcbb526bf14c8da98cb6d3faeacab7c77d06ff234dde0430cd2b4b6de15d6f15e8fdfe6e.tar":
"./pyodide_py.tar",
"./files/3c411fa2cd5d5a6f14b551a034ddcf9221455013f1943f202c878cd67840034717febf7e90f909f0b7273a514951d294cbdbf443e86912e706002f06702a9d62.json":
"./packages.json"
};
const contents = {};
while (reader.hasNext()) {
const file = reader.next();
const hasFileNameReplace = Object.entries(pyodideMap).find(
(n) => n[0] === file.name
);
if (hasFileNameReplace !== undefined) {
contents[hasFileNameReplace[1]] = file;
}
contents[file.name] = file;
}
console.log(path, contents);
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());
});
}