silverbullet/webapp/src/plugbox_sw.ts

109 lines
3.0 KiB
TypeScript

import { Manifest } from "../../plugbox/src/types";
import { openDB } from "idb";
const rootUrl = location.origin + "/plugin";
// Storing manifests in IndexedDB, y'all
const db = openDB("manifests-store", undefined, {
upgrade(db) {
db.createObjectStore("manifests");
},
});
async function saveManifest(name: string, manifest: Manifest) {
await (await db).put("manifests", manifest, name);
}
async function getManifest(name: string): Promise<Manifest | undefined> {
return (await (await db).get("manifests", name)) as Manifest | undefined;
}
self.addEventListener("install", (event) => {
console.log("Installing");
// @ts-ignore
self.skipWaiting();
});
async function handlePut(req: Request, path: string) {
console.log("Got manifest load for", path);
let manifest = (await req.json()) as Manifest;
await saveManifest(path, manifest);
// loadedBundles.set(path, manifest);
return new Response("ok");
}
function wrapScript(functionName: string, code: string): string {
return `const mod = ${code}
self.addEventListener('invoke-function', async e => {
try {
let result = await mod['${functionName}'](...e.detail.args);
self.dispatchEvent(new CustomEvent('result', {detail: result}));
} catch(e) {
console.error(\`Error while running ${functionName}\`, e);
self.dispatchEvent(new CustomEvent('app-error', {detail: e.message}));
}
});
`;
}
self.addEventListener("fetch", (event: any) => {
const req = event.request;
if (req.url.startsWith(rootUrl)) {
let path = req.url.substring(rootUrl.length + 1);
event.respondWith(
(async () => {
// console.log("Service worker is serving", path);
if (path === `$ping`) {
// console.log("Got ping");
return new Response("ok");
}
if (req.method === "PUT") {
return await handlePut(req, path);
}
let [pluginName, resourceType, functionName] = path.split("/");
let manifest = await getManifest(pluginName);
if (!manifest) {
// console.log("Ain't got", pluginName);
return new Response(`Plugin not loaded: ${pluginName}`, {
status: 404,
});
}
if (resourceType === "$manifest") {
return new Response(JSON.stringify(manifest));
}
if (resourceType === "function") {
let func = manifest.functions[functionName];
// console.log("Serving function", functionName, func);
if (!func) {
return new Response("Not found", {
status: 404,
});
}
return new Response(wrapScript(func.functionName!, func.code!), {
status: 200,
headers: {
"Content-type": "application/javascript",
},
});
}
})()
);
}
});
self.addEventListener("activate", (event) => {
// console.log("Now ready to pick up fetches");
// @ts-ignore
event.waitUntil(self.clients.claim());
});
// console.log("I'm a service worker, look at me!", location.href);