// MessageChannel for WASM communication let wasmChannel; let wasmPort; async function initWasmChannel() { wasmChannel = new MessageChannel(); wasmPort = wasmChannel.port1; // Setup message handling from WASM wasmPort.onmessage = (event) => { const { type, data } = event.data; switch (type) { case "WASM_READY": console.log("WASM is ready"); document.dispatchEvent(new CustomEvent("wasm-ready")); break; case "RESPONSE": handleWasmResponse(data); break; case "SYNC_COMPLETE": handleSyncComplete(data); break; } }; } // Initialize WebAssembly and Service Worker async function init() { try { // Register service worker if ("serviceWorker" in navigator) { const registration = await navigator.serviceWorker.register("./sw.js"); console.log("ServiceWorker registered"); // Wait for the service worker to be ready await navigator.serviceWorker.ready; // Initialize MessageChannel await initWasmChannel(); // Send the MessageChannel port to the service worker navigator.serviceWorker.controller.postMessage( { type: "PORT_INITIALIZATION", port: wasmChannel.port2, }, [wasmChannel.port2], ); // Register for periodic sync if available if ("periodicSync" in registration) { try { await registration.periodicSync.register("wasm-sync", { minInterval: 24 * 60 * 60 * 1000, // 24 hours }); } catch (error) { console.log("Periodic sync could not be registered:", error); } } } // Initialize HTMX with custom config htmx.config.withCredentials = true; htmx.config.wsReconnectDelay = "full-jitter"; // Override HTMX's internal request handling htmx.config.beforeRequest = function (config) { // Add request ID for tracking const requestId = "req_" + Date.now(); config.headers["X-Wasm-Request-ID"] = requestId; // If offline, handle through service worker if (!navigator.onLine) { return false; // Let service worker handle it } return true; }; // Handle HTMX after request htmx.config.afterRequest = function (config) { // Additional processing after request if needed }; // Handle HTMX errors htmx.config.errorHandler = function (error) { console.error("HTMX Error:", error); }; } catch (error) { console.error("Initialization failed:", error); } } function handleWasmResponse(data) { const { requestId, response } = data; // Process the WASM response // This might update the UI or trigger HTMX swaps const targetElement = document.querySelector( `[data-request-id="${requestId}"]`, ); if (targetElement) { htmx.process(targetElement); } } function handleSyncComplete(data) { const { url } = data; // Handle successful sync // Maybe refresh the relevant part of the UI htmx.trigger("body", "sync:complete", { url }); } // Handle offline status changes window.addEventListener("online", () => { document.body.classList.remove("offline"); // Trigger sync when back online if (wasmPort) { wasmPort.postMessage({ type: "SYNC_REQUEST" }); } }); window.addEventListener("offline", () => { document.body.classList.add("offline"); }); // Custom event handlers for HTMX document.addEventListener("htmx:beforeRequest", (event) => { const { elt, xhr } = event.detail; // Add request tracking const requestId = xhr.headers["X-Wasm-Request-ID"]; elt.setAttribute("data-request-id", requestId); }); document.addEventListener("htmx:afterRequest", (event) => { const { elt, successful } = event.detail; if (successful) { elt.removeAttribute("data-request-id"); } }); // Initialize everything when the page loads document.addEventListener("DOMContentLoaded", init); // Export functions that might be needed by WASM window.wasmBridge = { triggerUIUpdate: function (selector, content) { const target = document.querySelector(selector); if (target) { htmx.process( htmx.parse(content).forEach((node) => target.appendChild(node)), ); } }, showNotification: function (message, type = "info") { // Implement notification system console.log(`${type}: ${message}`); }, };