import { Component, type ReactNode } from 'react' interface Props { children: ReactNode; fallback?: ReactNode } interface State { error: Error | null } // Auto-reload config for transient dep-optimization errors. // Shares the same key as entry-client's cold-start guard so reload // attempts are counted together, preventing double reload loops. const RELOAD_KEY = '__dep_reload' const MAX_RELOADS = 6 // If the last reload was more than this many ms ago, reset the counter. // This prevents stale counters from blocking legitimate retries on a // later visit, while still capping rapid reload loops. const RELOAD_WINDOW_MS = 60_000 // Patterns that indicate React modules loaded as stubs (dep optimization in progress) const DEP_OPT_PATTERNS = [ "reading 'useState'", "reading 'useEffect'", "reading 'useRef'", "reading 'useCallback'", "reading 'useMemo'", "reading 'useContext'", "reading 'useReducer'", ] function isDepOptError(msg: string): boolean { return DEP_OPT_PATTERNS.some((p) => msg.includes(p)) } // Shared format with entry-client: { c: count, t: timestamp } function getReloadState(): { c: number; t: number } { try { const raw = sessionStorage.getItem(RELOAD_KEY) if (raw) return JSON.parse(raw) } catch { /* ignore parse errors */ } return { c: 0, t: 0 } } export default class ErrorBoundary extends Component { state: State = { error: null } static getDerivedStateFromError(error: Error) { return { error } } componentDidCatch(error: Error) { if (!isDepOptError(error.message)) return // Vite dep optimization may serve React stubs during cold start. // Auto-reload so the browser fetches the real modules once ready. const prev = getReloadState() // Reset counter if outside the rapid-reload window (stale from earlier visit) const count = (Date.now() - prev.t > RELOAD_WINDOW_MS) ? 0 : prev.c if (count < MAX_RELOADS) { sessionStorage.setItem(RELOAD_KEY, JSON.stringify({ c: count + 1, t: Date.now() })) setTimeout(() => location.reload(), 3000) } } render() { if (this.state.error) { if (this.props.fallback) return this.props.fallback // Show a friendlier message for dep optimization errors that will auto-reload if (isDepOptError(this.state.error.message)) { const { c, t } = getReloadState() const fresh = (Date.now() - t <= RELOAD_WINDOW_MS) if (!fresh || c < MAX_RELOADS) { return (

Loading dependencies...

Reloading automatically

) } } return (

Component Error

{this.state.error.message}

) } return this.props.children } }