UNPKG

@trailstash/ultra

Version:

A web based tool for making MapLibre GL maps with data from sources such as Overpass, GeoJSON, GPX, KML, TCX, etc

163 lines (149 loc) 4.34 kB
const sandboxInit = async (sandboxId, p) => { const workerInit = (workerId) => { self.addEventListener( "message", async (event) => { console.debug("worker recived msg from sandbox", event); let id; try { const msg = JSON.parse(event.data); id = msg.id; console.debug("parsed message", msg); const module = await import( `data:text/javascript;base64,${btoa(msg.module)}` ); const data = await Promise.resolve(module[msg.exportName](msg.data)); self.postMessage(JSON.stringify({ id, data })); } catch (e) { self.postMessage(JSON.stringify({ id, error: e.toString() })); } }, false, ); self.postMessage(JSON.stringify({ id: workerId })); }; const workerBlob = new Blob([`(${workerInit.toString()})("${sandboxId}");`], { type: "module", }); const worker = new Worker(URL.createObjectURL(workerBlob)); const waitForWorkerReady = () => new Promise((resolve, reject) => { const listener = (event) => { worker.removeEventListener("message", listener, false); console.debug("sandbox recived msg from worker", event); try { const msg = JSON.parse(event.data); if (msg.id === sandboxId) { resolve(); return; } console.warn("unexpected msg!"); } catch (e) { reject(e); return; } }; worker.addEventListener("message", listener, false); }); // wait for ready msg from worker await waitForWorkerReady(); console.log("worker ready"); // Relay messages from parent to worker window.addEventListener( "message", (event) => { console.debug("sandbox recieved msg from parent", event); worker.postMessage(event.data); }, false, ); // Relay messages from worker to parent worker.addEventListener( "message", (event) => { console.debug("sandbox recieved msg from worker", event); window.parent.postMessage(event.data, p); }, false, ); window.parent.postMessage(JSON.stringify({ id: sandboxId }), p); }; const makeSandbox = () => { const iframe = window.document.createElement("iframe"); const sandboxId = crypto.randomUUID(); iframe.style.display = "none"; const sandboxBlob = new Blob( [ ` <!DOCTYPE html> <script type="module"> (${sandboxInit.toString()})("${sandboxId}", "${window.location.origin}"); </script> `, ], { type: "text/html", }, ); iframe.src = URL.createObjectURL(sandboxBlob); const run = (exportName, module, data) => { const messageID = crypto.randomUUID(); return new Promise((resolve, reject) => { const listener = (event) => { console.debug("parent recieved msg from sandbox", event); try { const msg = JSON.parse(event.data); if (msg.id === messageID) { window.removeEventListener("message", listener, false); if (msg.error) { reject(msg.error); } else { resolve(msg.data); } } else { console.warn("unexpected msg!"); } } catch (e) { console.error(e); return; } }; window.addEventListener("message", listener, false); iframe.contentWindow.postMessage( JSON.stringify({ id: messageID, exportName, module, data, }), "*", ); }); }; return new Promise((resolve) => { const listener = (event) => { window.removeEventListener("message", listener, false); console.debug("parent recieved msg from sandbox", event); try { const msg = JSON.parse(event.data); if (msg.id === sandboxId) { console.log("sandbox ready"); resolve(run); return; } console.warn("unexpected msg!"); } catch (e) { console.error(e); return; } }; window.addEventListener("message", listener, false); window.document.body.appendChild(iframe); }); }; export default makeSandbox; let sandbox; try { sandbox = await makeSandbox(); } catch {} export { sandbox };