integratedhub/static/fetch_sw.js
2026-01-20 09:02:26 -06:00

134 lines
4.1 KiB
JavaScript

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
});