prasi-bun/app/web/src/sworker.ts

118 lines
2.6 KiB
TypeScript

import { manifest } from "@parcel/service-worker";
import { RadixRouter, createRouter } from "radix3";
import { version } from "../timestamp";
import { files } from "../public_files";
const g = {
router: null as null | RadixRouter<any>,
offline: false,
broadcast(msg: any) {
// @ts-ignore
const c: Clients = self.clients;
c.matchAll({ includeUncontrolled: true }).then((clients) => {
clients.forEach((client) => {
client.postMessage(msg);
});
});
},
};
async function install() {
const cache = await caches.open(version);
const entries = [...manifest, ...files];
if (entries.length > 0) {
await cache.addAll(entries);
g.broadcast({ type: "installed" });
}
}
addEventListener("install", (e) => (e as ExtendableEvent).waitUntil(install()));
async function activate() {
let shouldRefresh = false;
if (!g.offline) {
const keys = await caches.keys();
await Promise.all(
keys.map(async (key) => {
if (key !== version) {
await caches.delete(key);
shouldRefresh = true;
}
})
);
g.broadcast({ type: "activated", shouldRefresh, version });
}
}
addEventListener("activate", (e) =>
(e as ExtendableEvent).waitUntil(activate())
);
addEventListener("fetch", async (evt) => {
const e = evt as FetchEvent;
const url = new URL(e.request.url);
if (url.pathname.startsWith("_proxy")) return;
if (g.router) {
const found = g.router.lookup(url.pathname);
if (found) {
return;
}
}
e.respondWith(
(async () => {
const r = await caches.match(e.request);
if (r) {
return r;
}
try {
g.offline = false;
return await fetch(e.request);
} catch (e) {
g.offline = true;
g.broadcast({ type: "offline" });
return new Response();
}
})()
);
});
addEventListener("message", async (e) => {
const type = e.data.type;
const cache = await caches.open(version);
switch (type) {
case "add-cache":
{
const cached = await cache.match(e.data.url);
if (!cached) {
await cache.add(e.data.url);
}
}
break;
case "define-route":
g.router = createRouter({ strictTrailingSlash: false });
for (const route of e.data.routes) {
g.router.insert(route.url, route);
}
await activate();
break;
case "force-update":
{
const keys = await caches.keys();
await Promise.all(
keys.map(async (key) => {
if (key !== version) {
await caches.delete(key);
}
})
);
await install();
}
break;
}
});