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)