const CACHE_NAME = "page-cache"; // JavaScript equivalent of TypeScript hashText function async function hashText(text) { const encoder = new TextEncoder(); const data = encoder.encode(text); const hashBuffer = await crypto.subtle.digest("SHA-256", data); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join( "", ); return hashHex; } // Listen for postMessage to prefetch-and-cache any specified URL self.addEventListener("message", async (event) => { const data = event.data; if (data && data.type === "prefetch" && data.url) { let prefectchSuccess = false; const cache = await caches.open(CACHE_NAME); const cachedResponse = await cache.match(data.url); if (cachedResponse) { const originalUrl = new URL(cachedResponse.url); const data1Url = originalUrl.toString().replace( "portal.cyberhybridhub.com", "data1.cyberhybridhub.com", ); const checkData1Url = new URL(data1Url); checkData1Url.searchParams.set("naunce", await hashText(data.naunce)); const checkRequest = new Request(checkData1Url, { method: cachedResponse.method, headers: cachedResponse.headers, credentials: "include", body: cachedResponse.body, }); const checkResponse = await fetch(checkRequest); if (checkResponse.ok) { const cloneResponse = checkResponse.clone(); const cloneText = await cloneResponse.text(); if (cloneText && cloneText.length > 0) { await cache.put(data.url, checkResponse); } prefectchSuccess = true; } else { console.warn( `[Prefetch] Failed to fetch from data1: ${response.status} ${response.statusText}`, ); } } else { const networkResponse = await fetch(event.request, { credentials: "include", }); if (networkResponse.ok) { prefectchSuccess = true; await cache.put(event.request, networkResponse); } } if (prefectchSuccess) { const clients = await self.clients.matchAll(); clients.forEach((client) => client.postMessage({ type: "prefetch-complete", url: data.url }) ); } else { const clients = await self.clients.matchAll(); clients.forEach((client) => client.postMessage({ type: "prefetch-failed", url: data.url, error: "Failed to fetch from data1", }) ); } } }); self.addEventListener("fetch", (event) => { const url = new URL(event.request.url); if (event.request.method === "GET" && url.pathname === "/api/sync-pin/get") { event.respondWith( (async () => { const cache = await caches.open(CACHE_NAME); const cachedResponse = await cache.match(event.request); if (cachedResponse) { const clonedCache = cachedResponse.clone(); const cachedText = await clonedCache.text(); const cachedHash = await hashText(cachedText); // Create a new URL with naunce parameter (don't modify the original) const checkUrl = new URL(event.request.url); checkUrl.searchParams.set("naunce", cachedHash); const checkResponse = await fetch(checkUrl.toString(), { credentials: "include", }); if (checkResponse.ok) { const cloneResponse = checkResponse.clone(); const cloneText = await cloneResponse.text(); if (cloneText && cloneText.length > 0) { await cache.put(event.request, checkResponse.clone()); return checkResponse; } } return cachedResponse; } const networkResponse = await fetch(event.request, { credentials: "include", }); if (networkResponse.ok) { await cache.put(event.request, networkResponse.clone()); } return networkResponse; })(), ); } // For all other requests, fall back to the network without cloning the body event.respondWith(fetch(event.request)); // For all other non-API requests, let them handle by default browser behavior });