// Memory leak prevention utilities class RequestTracker { private activeRequests = new Set(); addRequest(controller: AbortController) { this.activeRequests.add(controller); } removeRequest(controller: AbortController) { this.activeRequests.delete(controller); } cancelAllRequests() { this.activeRequests.forEach(controller => { try { controller.abort(); } catch (error) { console.warn('Failed to abort request:', error); } }); this.activeRequests.clear(); } getActiveRequestCount(): number { return this.activeRequests.size; } } export const requestTracker = new RequestTracker(); // Enhanced fetch with automatic tracking export function trackedFetch(input: RequestInfo | URL, init?: RequestInit): Promise { const controller = new AbortController(); const timeoutId = setTimeout(() => { controller.abort(); }, 30000); // 30 second timeout // Merge abort signals if (init?.signal) { init.signal.addEventListener('abort', () => { controller.abort(); }); } const trackedInit = { ...init, signal: controller.signal, }; requestTracker.addRequest(controller); return fetch(input, trackedInit).finally(() => { clearTimeout(timeoutId); requestTracker.removeRequest(controller); }); } // Cleanup utility for components export function useCleanup() { const cleanupFunctions = new Set<() => void>(); const addCleanup = (cleanup: () => void) => { cleanupFunctions.add(cleanup); }; const executeCleanup = () => { cleanupFunctions.forEach(cleanup => { try { cleanup(); } catch (error) { console.warn('Cleanup function failed:', error); } }); cleanupFunctions.clear(); }; return { addCleanup, executeCleanup }; } // Memory monitoring for development export function startMemoryMonitoring() { if (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') { setInterval(() => { if ('memory' in performance) { const memory = (performance as Performance & { memory?: { usedJSHeapSize: number; totalJSHeapSize: number; jsHeapSizeLimit: number } }).memory; if (!memory) return; const usedMB = Math.round(memory.usedJSHeapSize / 1048576); const limitMB = Math.round(memory.jsHeapSizeLimit / 1048576); // Log memory usage every 30 seconds if (usedMB > limitMB * 0.9) { console.warn(`High memory usage: ${usedMB}MB / ${limitMB}MB`); } } }, 30000); } } // Debounced function with cleanup export function debounceWithCleanup unknown>( func: T, wait: number ): { debouncedFn: (...args: Parameters) => void; cancel: () => void } { let timeoutId: NodeJS.Timeout | null = null; const debouncedFn = (...args: Parameters) => { if (timeoutId) { clearTimeout(timeoutId); } timeoutId = setTimeout(() => { func(...args); timeoutId = null; }, wait); }; const cancel = () => { if (timeoutId) { clearTimeout(timeoutId); timeoutId = null; } }; return { debouncedFn, cancel }; }