/** * Config Cache Initialization Plugin with Advanced Reload Loop Prevention * Comprehensive mobile Safari reload loop prevention system * Integrates with reload-loop-prevention utility for maximum protection */ import { initReloadLoopPrevention, applyMobileSafariReloadLoopFixes } from '~/utils/reload-loop-prevention'; export default defineNuxtPlugin({ name: 'config-cache-init', enforce: 'pre', // Run before other plugins async setup() { console.log('[config-cache-init] Initializing comprehensive config cache and reload prevention plugin'); // Only run on client side if (typeof window === 'undefined') { return; } // Emergency reload loop prevention - check immediately const canLoad = initReloadLoopPrevention('config-cache-init'); if (!canLoad) { console.error('[config-cache-init] Plugin load blocked by reload loop prevention'); return; } // Initialize a flag to prevent multiple initializations if ((window as any).__configCacheInitialized) { console.log('[config-cache-init] Config cache already initialized'); return; } // Mark as initialized (window as any).__configCacheInitialized = true; // Apply mobile Safari specific fixes first applyMobileSafariReloadLoopFixes(); // Initialize the config cache structure if not already present if (!(window as any).__configCache) { (window as any).__configCache = { recaptcha: null, registration: null, recaptchaLoading: false, registrationLoading: false, recaptchaError: null, registrationError: null }; console.log('[config-cache-init] Config cache structure initialized'); } // Initialize call history for circuit breaker if (!(window as any).__configCallHistory) { (window as any).__configCallHistory = {}; console.log('[config-cache-init] Call history initialized'); } // Enhanced error handler with reload loop detection const originalError = window.onerror; window.onerror = function(msg, url, lineNo, columnNo, error) { // Check for common reload loop patterns if (typeof msg === 'string') { const isReloadLoop = ( msg.includes('Maximum call stack') || msg.includes('too much recursion') || msg.includes('RangeError') || msg.includes('Script error') || msg.includes('ResizeObserver loop limit exceeded') || msg.includes('Non-Error promise rejection captured') ); if (isReloadLoop) { console.error('[config-cache-init] Potential reload loop detected:', { message: msg, url, lineNo, columnNo, userAgent: navigator.userAgent, timestamp: new Date().toISOString() }); // Record this as a potential reload trigger initReloadLoopPrevention('error-handler'); // Prevent default error handling which might cause reload return true; } // Check for config-related errors if (msg.includes('config') || msg.includes('fetch') || msg.includes('load')) { console.warn('[config-cache-init] Config-related error detected:', msg); } } // Call original error handler if it exists if (originalError) { return originalError(msg, url, lineNo, columnNo, error); } return false; }; // Enhanced unhandled rejection handler window.addEventListener('unhandledrejection', (event) => { const reason = event.reason; const isConfigRelated = ( reason?.message?.includes('config') || reason?.message?.includes('reload') || reason?.message?.includes('fetch') || reason?.message?.includes('/api/') ); if (isConfigRelated) { console.error('[config-cache-init] Unhandled config-related rejection:', { reason, stack: reason?.stack, timestamp: new Date().toISOString() }); // Record potential reload trigger initReloadLoopPrevention('promise-rejection'); // Prevent default which might cause reload event.preventDefault(); } }); // Add performance monitoring for mobile Safari if ('performance' in window && 'navigation' in window.performance) { const navTiming = performance.navigation; if (navTiming.type === 1) { // TYPE_RELOAD console.warn('[config-cache-init] Page was reloaded - checking for reload loops'); const canContinue = initReloadLoopPrevention('page-reload'); if (!canContinue) { return; } } } // Monitor for rapid API calls that could indicate loops const originalFetch = window.fetch; let apiCallCount = 0; let apiCallWindow = Date.now(); window.fetch = function(input: RequestInfo | URL, init?: RequestInit) { const now = Date.now(); // Reset counter every 5 seconds if (now - apiCallWindow > 5000) { apiCallCount = 0; apiCallWindow = now; } apiCallCount++; // Check for excessive API calls if (apiCallCount > 10) { const url = typeof input === 'string' ? input : input.toString(); console.warn(`[config-cache-init] Excessive API calls detected: ${apiCallCount} calls in 5s`, url); // Check if this could be a config-related loop if (url.includes('/api/recaptcha-config') || url.includes('/api/registration-config')) { console.error('[config-cache-init] Config API loop detected!', url); initReloadLoopPrevention('config-api-loop'); } } return originalFetch.call(this, input, init); }; // Add visibility change handler for mobile Safari document.addEventListener('visibilitychange', () => { if (!document.hidden) { // Page became visible - might be returning from background console.log('[config-cache-init] Page visibility restored'); setTimeout(() => { // Verify cache is still intact after visibility change const cache = (window as any).__configCache; if (!cache) { console.warn('[config-cache-init] Config cache lost after visibility change - reinitializing'); (window as any).__configCache = { recaptcha: null, registration: null, recaptchaLoading: false, registrationLoading: false, recaptchaError: null, registrationError: null }; } }, 100); } }); console.log('[config-cache-init] Comprehensive config cache and reload prevention plugin initialized successfully'); } });