import { EMBED_MODE_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM, } from "../shared/embed-auth.js"; /** * Synchronous dev-only browser recovery for Vite optimized-dependency races. * * Keep this script dependency-free and non-module-safe: React Router SSR roots * inline it before ``, and the Vite plugin injects it at * `head-prepend` for HTML that does pass through transformIndexHtml. */ export function getViteDevRecoveryScript(): string { const embedModeParam = JSON.stringify(EMBED_MODE_QUERY_PARAM); const embedTokenParam = JSON.stringify(EMBED_TOKEN_QUERY_PARAM); return ` (function() { try { var params = new URLSearchParams(window.location.search || ""); var embedded = params.get(${embedModeParam}); if (params.has(${embedTokenParam}) || embedded === "1" || embedded === "true") return; } catch (e) {} var INSTALL_KEY = "__agentNativeViteDevRecoveryInstalled"; if (window[INSTALL_KEY]) return; window[INSTALL_KEY] = true; var RELOAD_KEY = "__an_optimize_reload"; var MAX_RELOADS = 3; var MIN_RELOAD_INTERVAL_MS = 2000; var RESET_AFTER_MS = 8000; var reloadTimer = null; var overlayShown = false; // Track recent reloads in sessionStorage. If we reload too many times // in a short window, stop and show a manual-refresh message instead of // looping forever. function readReloadHistory() { try { var raw = sessionStorage.getItem(RELOAD_KEY); if (!raw) return []; var arr = JSON.parse(raw); var cutoff = Date.now() - 30000; return Array.isArray(arr) ? arr.filter(function(t) { return t > cutoff; }) : []; } catch (e) { return []; } } function recordReload() { try { var history = readReloadHistory(); history.push(Date.now()); sessionStorage.setItem(RELOAD_KEY, JSON.stringify(history)); } catch (e) {} } // Reset the counter after a stable period (page didn't fail again). setTimeout(function() { try { sessionStorage.removeItem(RELOAD_KEY); } catch (e) {} }, RESET_AFTER_MS); function showOverlay(title, subtitle) { if (overlayShown) return; overlayShown = true; var mount = function() { if (!document.body) { setTimeout(mount, 16); return; } var el = document.createElement("div"); el.id = "__an-reload-overlay"; el.style.cssText = [ "position:fixed","inset:0","z-index:2147483647", "display:flex","align-items:center","justify-content:center", "background:rgba(0,0,0,0.6)","backdrop-filter:blur(8px)", "-webkit-backdrop-filter:blur(8px)", "font-family:-apple-system,BlinkMacSystemFont,system-ui,sans-serif", "color:#fff","font-size:14px" ].join(";"); el.innerHTML = '
' + '
' + title + '
' + '
' + subtitle + '
' + '
'; document.body.appendChild(el); }; mount(); } function scheduleReload(reason) { if (reloadTimer) return; var history = readReloadHistory(); if (history.length >= MAX_RELOADS) { console.warn("[agent-native] Dev server keeps re-bundling. Manual refresh needed.", reason); showOverlay( "Dev server out of sync", "Auto-reload gave up after " + MAX_RELOADS + " tries. Refresh the page (\\u2318R / Ctrl+R)." ); return; } console.log("[agent-native] Vite re-bundled deps (" + reason + "), reloading\\u2026"); recordReload(); // First reload is silent. One refresh almost always fixes it and the // overlay flash is more disruptive than the reload itself. Only show // the overlay starting on the second attempt, when something is clearly // taking longer than expected. if (history.length >= 1) { showOverlay("Updating dev server\\u2026", "Reloading the page"); } var lastReloadAt = history.length ? history[history.length - 1] : 0; var delay = Math.max( 300, MIN_RELOAD_INTERVAL_MS - Math.max(0, Date.now() - lastReloadAt), ); reloadTimer = setTimeout(function() { window.location.reload(); }, delay); } window.addEventListener("vite:beforeFullReload", function() { if (reloadTimer) { clearTimeout(reloadTimer); reloadTimer = null; } }); function looksLikeViteFailureMessage(message) { if (!message) return false; return message.indexOf("Failed to fetch dynamically imported module") !== -1 || message.indexOf("error loading dynamically imported module") !== -1 || message.indexOf("Importing a module script failed") !== -1 || message.indexOf("Outdated Optimize Dep") !== -1 || message.indexOf("Optimize Deps Processing Error") !== -1 || (message.indexOf("504") !== -1 && ( message.indexOf(".vite/deps") !== -1 || message.indexOf("/node_modules/.vite/deps/") !== -1 )); } function looksLikeViteDep(url) { if (!url) return false; // Only treat same-origin URLs as Vite deps. Do not reload the page // because some third-party CDN script 404'd. try { var u = new URL(url, window.location.href); if (u.origin !== window.location.origin) return false; } catch (e) { return false; } return url.indexOf("/node_modules/.vite/deps/") !== -1 || url.indexOf("/@fs/") !== -1 || url.indexOf("/@id/") !== -1 || url.indexOf("?v=") !== -1 || url.indexOf("?import") !== -1 || /\\.(m?js|ts|tsx|jsx)(\\?|$)/.test(url); } // 1)