#!/bin/sh set -eu CONTAINER="${1:-reactive-resume-reactive-resume-1}" docker exec -u root -i "$CONTAINER" sh <<'SH' set -eu SSR_FILE="/app/apps/web/.output/server/_ssr/pdf-document-COfeOLVC.mjs" SW_FILE="/app/apps/web/.output/public/sw.js" SERVER_INDEX_FILE="/app/apps/web/.output/server/index.mjs" SSR_RENDERER_FILE="/app/apps/web/.output/server/_chunks/ssr-renderer.mjs" test -f "$SSR_FILE.bak-sw-cache" || cp "$SSR_FILE" "$SSR_FILE.bak-sw-cache" 2>/dev/null || true test -f "$SW_FILE.bak-sw-cache" || cp "$SW_FILE" "$SW_FILE.bak-sw-cache" 2>/dev/null || true test -f "$SERVER_INDEX_FILE.bak-sw-cache" || cp "$SERVER_INDEX_FILE" "$SERVER_INDEX_FILE.bak-sw-cache" 2>/dev/null || true test -f "$SSR_RENDERER_FILE.bak-sw-cache" || cp "$SSR_RENDERER_FILE" "$SSR_RENDERER_FILE.bak-sw-cache" 2>/dev/null || true node - <<'NODE' const fs = require("fs"); const crypto = require("crypto"); const ssrFile = "/app/apps/web/.output/server/_ssr/pdf-document-COfeOLVC.mjs"; const swFile = "/app/apps/web/.output/public/sw.js"; const serverIndexFile = "/app/apps/web/.output/server/index.mjs"; const ssrRendererFile = "/app/apps/web/.output/server/_chunks/ssr-renderer.mjs"; const registrationScript = ` \t(() => { \t\tif (!("serviceWorker" in navigator)) return; \t\twindow.addEventListener("load", () => { \t\t\tconst clearReactiveResumeCaches = async () => { \t\t\t\tif ("caches" in window) { \t\t\t\t\tconst keys = await caches.keys(); \t\t\t\t\tawait Promise.all(keys.map((key) => caches.delete(key))); \t\t\t\t} \t\t\t\tif (navigator.serviceWorker.getRegistrations) { \t\t\t\t\tconst registrations = await navigator.serviceWorker.getRegistrations(); \t\t\t\t\tawait Promise.all(registrations.map((registration) => registration.unregister())); \t\t\t\t} \t\t\t}; \t\t\tclearReactiveResumeCaches().catch(console.error); \t\t}); \t})(); `; let ssr = fs.readFileSync(ssrFile, "utf8"); const start = "var pwaServiceWorkerRegistrationScript = `"; const end = "`;\nvar src_default ="; const startIndex = ssr.indexOf(start); if (startIndex === -1) { throw new Error("Service worker registration script start marker not found"); } const endIndex = ssr.indexOf(end, startIndex + start.length); if (endIndex === -1) { throw new Error("Service worker registration script end marker not found"); } ssr = ssr.slice(0, startIndex) + start + registrationScript + ssr.slice(endIndex); fs.writeFileSync(ssrFile, ssr); const sw = `self.addEventListener("install", () => { self.skipWaiting(); }); self.addEventListener("activate", (event) => { event.waitUntil((async () => { const keys = await caches.keys(); await Promise.all(keys.map((key) => caches.delete(key))); await self.registration.unregister(); await self.clients.claim(); const clients = await self.clients.matchAll({ type: "window", includeUncontrolled: true, }); for (const client of clients) { client.postMessage({ type: "RR_SW_CACHE_CLEARED" }); } })()); }); self.addEventListener("fetch", () => {}); `; fs.writeFileSync(swFile, sw); function makeEtag(buffer) { const digest = crypto.createHash("sha1").update(buffer).digest("base64").replace(/=+$/g, ""); return `"${buffer.length.toString(16)}-${digest}"`; } function patchStaticManifestEntry(source, urlPath, filePath) { const buffer = fs.readFileSync(filePath); const startMarker = `"${urlPath}": {`; const start = source.indexOf(startMarker); if (start === -1) { throw new Error(`Static manifest entry not found for ${urlPath}`); } const end = source.indexOf("\n\t},", start); if (end === -1) { throw new Error(`Static manifest entry end not found for ${urlPath}`); } let entry = source.slice(start, end); entry = entry .replace(/"etag": "(?:\\.|[^"\\])*"/, `"etag": ${JSON.stringify(makeEtag(buffer))}`) .replace(/"mtime": "(?:\\.|[^"\\])*"/, `"mtime": ${JSON.stringify(new Date().toISOString())}`) .replace(/"size": \d+/, `"size": ${buffer.length}`); return source.slice(0, start) + entry + source.slice(end); } let serverIndex = fs.readFileSync(serverIndexFile, "utf8"); serverIndex = patchStaticManifestEntry(serverIndex, "/sw.js", swFile); fs.writeFileSync(serverIndexFile, serverIndex); let ssrRenderer = fs.readFileSync(ssrRendererFile, "utf8"); const ssrRendererOriginal = `function ssrRenderer({ req }) { \treturn fetchViteEnv("ssr", req); }`; const ssrRendererPatched = `async function ssrRenderer(event) { \tconst response = await fetchViteEnv("ssr", event.req); \tconst headers = new Headers(response.headers); \tconst accept = event.req.headers.get("accept") || ""; \tif (accept.includes("text/html")) { \t\theaders.set("Cache-Control", "no-store, max-age=0"); \t\theaders.set("Pragma", "no-cache"); \t\theaders.set("Expires", "0"); \t} \treturn new Response(response.body, { \t\tstatus: response.status, \t\tstatusText: response.statusText, \t\theaders, \t}); }`; if (!ssrRenderer.includes(ssrRendererPatched)) { if (!ssrRenderer.includes(ssrRendererOriginal)) { throw new Error("SSR renderer marker not found"); } ssrRenderer = ssrRenderer.replace(ssrRendererOriginal, ssrRendererPatched); fs.writeFileSync(ssrRendererFile, ssrRenderer); } NODE node --check "$SSR_FILE" >/dev/null node --check "$SW_FILE" >/dev/null node --check "$SERVER_INDEX_FILE" >/dev/null node --check "$SSR_RENDERER_FILE" >/dev/null SH