@usefy/use-memory-monitor 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/useMemoryMonitor.ts","../src/constants.ts","../src/utils/detection.ts","../src/store.ts","../src/utils/formatting.ts","../src/utils/circularBuffer.ts","../src/utils/leakDetection.ts"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport type {\n AvailableMetric,\n FormattedMemory,\n LeakAnalysis,\n MemoryCritical,\n MemoryInfo,\n MemorySnapshot,\n MemoryWarning,\n Severity,\n SnapshotDiff,\n SupportLevel,\n Trend,\n UseMemoryMonitorOptions,\n UseMemoryMonitorReturn,\n} from \"./types\";\nimport {\n DEFAULT_OPTIONS,\n DEFAULT_SEVERITY,\n DEFAULT_TREND,\n SSR_FORMATTED_MEMORY,\n} from \"./constants\";\nimport {\n createStore,\n readMemoryFromAPI,\n countDOMNodes,\n estimateEventListeners,\n type MemoryStore,\n} from \"./store\";\nimport {\n isServer,\n detectSupport,\n createUnsupportedInfo,\n hasLegacyMemoryAPI,\n} from \"./utils/detection\";\nimport {\n createFormattedMemory,\n calculateUsagePercentage,\n} from \"./utils/formatting\";\nimport { CircularBuffer } from \"./utils/circularBuffer\";\nimport { analyzeLeakProbability, calculateTrend } from \"./utils/leakDetection\";\n\n/**\n * A React hook for monitoring browser memory usage in real-time.\n * Detects memory leaks, provides threshold alerts, and supports snapshot comparison.\n *\n * Features:\n * - Real-time memory tracking (JS Heap, DOM Nodes)\n * - Memory leak detection with configurable sensitivity\n * - Threshold-based warnings (warning/critical levels)\n * - Memory snapshot comparison\n * - SSR compatible\n * - Graceful degradation for unsupported browsers\n *\n * @param options - Configuration options\n * @returns Memory monitoring state and control functions\n *\n * @example\n * ```tsx\n * // Basic usage\n * function MemoryDisplay() {\n * const { heapUsed, formatted, isSupported } = useMemoryMonitor();\n *\n * if (!isSupported) {\n * return <p>Memory monitoring not available</p>;\n * }\n *\n * return <p>Memory: {formatted.heapUsed}</p>;\n * }\n * ```\n *\n * @example\n * ```tsx\n * // With leak detection\n * const monitor = useMemoryMonitor({\n * enableHistory: true,\n * leakDetection: { enabled: true, sensitivity: 'medium' },\n * onLeakDetected: (analysis) => {\n * console.warn('Leak detected:', analysis);\n * },\n * });\n * ```\n *\n * @example\n * ```tsx\n * // With threshold alerts\n * const monitor = useMemoryMonitor({\n * thresholds: { warning: 70, critical: 90 },\n * onWarning: (data) => console.warn('Memory warning:', data),\n * onCritical: (data) => console.error('Memory critical:', data),\n * });\n * ```\n */\nexport function useMemoryMonitor(\n options: UseMemoryMonitorOptions = {}\n): UseMemoryMonitorReturn {\n // Merge options with defaults\n const mergedOptions = useMemo(\n () => ({\n ...DEFAULT_OPTIONS,\n ...options,\n thresholds: {\n ...DEFAULT_OPTIONS.thresholds,\n ...options.thresholds,\n },\n leakDetection: {\n ...DEFAULT_OPTIONS.leakDetection,\n ...options.leakDetection,\n },\n }),\n [options]\n );\n\n const {\n interval,\n autoStart,\n enabled,\n enableHistory,\n historySize,\n thresholds,\n leakDetection,\n devMode,\n trackDOMNodes,\n trackEventListeners,\n logToConsole,\n disableInProduction,\n fallbackStrategy,\n } = mergedOptions;\n\n // Check if we should disable in production\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const shouldDisable = disableInProduction && typeof (globalThis as any).process !== \"undefined\" && (globalThis as any).process?.env?.NODE_ENV === \"production\";\n\n // Store refs for callbacks to avoid re-renders\n const onUpdateRef = useRef(options.onUpdate);\n const onWarningRef = useRef(options.onWarning);\n const onCriticalRef = useRef(options.onCritical);\n const onLeakDetectedRef = useRef(options.onLeakDetected);\n const onUnsupportedRef = useRef(options.onUnsupported);\n\n // Update refs when callbacks change\n useEffect(() => {\n onUpdateRef.current = options.onUpdate;\n onWarningRef.current = options.onWarning;\n onCriticalRef.current = options.onCritical;\n onLeakDetectedRef.current = options.onLeakDetected;\n onUnsupportedRef.current = options.onUnsupported;\n }, [options.onUpdate, options.onWarning, options.onCritical, options.onLeakDetected, options.onUnsupported]);\n\n // Detect browser support\n const browserSupport = useMemo(() => detectSupport(), []);\n\n // Create store instance (persists across renders)\n const storeRef = useRef<MemoryStore | null>(null);\n if (!storeRef.current) {\n storeRef.current = createStore();\n }\n const store = storeRef.current;\n\n // Subscribe to store using useSyncExternalStore\n const storeState = useSyncExternalStore(\n store.subscribe,\n store.getSnapshot,\n store.getServerSnapshot\n );\n\n // History buffer\n const historyBufferRef = useRef<CircularBuffer<MemoryInfo> | null>(null);\n if (enableHistory && !historyBufferRef.current) {\n historyBufferRef.current = new CircularBuffer<MemoryInfo>(historySize);\n }\n\n // Snapshot storage\n const snapshotsRef = useRef<Map<string, MemorySnapshot>>(new Map());\n\n // Interval ID ref\n const intervalIdRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n // Previous severity for callback deduplication\n const prevSeverityRef = useRef<Severity>(DEFAULT_SEVERITY);\n\n // Previous leak status for callback deduplication\n const prevLeakDetectedRef = useRef<boolean>(false);\n\n // Monitoring state ref\n const isMonitoringRef = useRef<boolean>(false);\n\n // Determine if monitoring is supported\n const isSupported = useMemo(() => {\n if (isServer()) return false;\n if (shouldDisable) return false;\n\n if (fallbackStrategy === \"none\") {\n return hasLegacyMemoryAPI();\n }\n\n // With fallback strategies, we can always provide some monitoring\n return true;\n }, [shouldDisable, fallbackStrategy]);\n\n // Determine support level\n const supportLevel: SupportLevel = useMemo(() => {\n if (!isSupported) return \"none\";\n return browserSupport.level;\n }, [isSupported, browserSupport.level]);\n\n // Available metrics\n const availableMetrics: AvailableMetric[] = useMemo(() => {\n if (!isSupported) return [];\n return browserSupport.availableMetrics;\n }, [isSupported, browserSupport.availableMetrics]);\n\n // Calculate derived values\n const memory = storeState.memory;\n const heapUsed = memory?.heapUsed ?? null;\n const heapTotal = memory?.heapTotal ?? null;\n const heapLimit = memory?.heapLimit ?? null;\n const usagePercentage = calculateUsagePercentage(heapUsed, heapLimit);\n const domNodes = storeState.domNodes;\n const eventListeners = storeState.eventListeners;\n\n // Calculate severity based on thresholds\n const severity = useMemo((): Severity => {\n if (usagePercentage === null) return DEFAULT_SEVERITY;\n\n if (usagePercentage >= (thresholds.critical ?? 90)) {\n return \"critical\";\n }\n\n if (usagePercentage >= (thresholds.warning ?? 70)) {\n return \"warning\";\n }\n\n return \"normal\";\n }, [usagePercentage, thresholds.critical, thresholds.warning]);\n\n // Calculate history and trend\n const history = useMemo(() => {\n if (!enableHistory || !historyBufferRef.current) return [];\n return historyBufferRef.current.toArray();\n }, [enableHistory, storeState.lastUpdated]);\n\n const trend: Trend = useMemo(() => {\n if (!enableHistory || history.length < 3) return DEFAULT_TREND;\n return calculateTrend(history);\n }, [enableHistory, history]);\n\n // Leak analysis\n const leakAnalysis = useMemo((): LeakAnalysis | null => {\n if (!leakDetection.enabled || !enableHistory) return null;\n\n const windowSize = leakDetection.windowSize ?? 10;\n const samples = historyBufferRef.current?.getRecent(windowSize) ?? [];\n\n if (samples.length < 5) return null;\n\n return analyzeLeakProbability(\n samples,\n leakDetection.sensitivity ?? \"medium\",\n leakDetection.threshold\n );\n }, [\n leakDetection.enabled,\n leakDetection.sensitivity,\n leakDetection.windowSize,\n leakDetection.threshold,\n enableHistory,\n history,\n ]);\n\n const isLeakDetected = leakAnalysis?.isLeaking ?? false;\n const leakProbability = leakAnalysis?.probability ?? 0;\n\n // Formatted values\n const formatted: FormattedMemory = useMemo(() => {\n if (!isSupported) return SSR_FORMATTED_MEMORY;\n return createFormattedMemory(memory, domNodes, eventListeners);\n }, [isSupported, memory, domNodes, eventListeners]);\n\n // Poll function\n const poll = useCallback(() => {\n if (!isSupported || !enabled) return;\n\n // Read memory\n const newMemory = readMemoryFromAPI();\n\n if (newMemory) {\n store.updateMemory(newMemory);\n\n // Add to history\n if (enableHistory && historyBufferRef.current) {\n historyBufferRef.current.push(newMemory);\n }\n\n // Call onUpdate callback\n onUpdateRef.current?.(newMemory);\n\n // Log to console in dev mode\n if (logToConsole && devMode) {\n console.log(\"[useMemoryMonitor]\", {\n heapUsed: newMemory.heapUsed,\n heapTotal: newMemory.heapTotal,\n heapLimit: newMemory.heapLimit,\n });\n }\n }\n\n // Track DOM nodes if enabled\n if (trackDOMNodes) {\n const nodeCount = countDOMNodes();\n store.updateDOMNodes(nodeCount);\n }\n\n // Track event listeners if enabled\n if (trackEventListeners) {\n const listenerCount = estimateEventListeners();\n store.updateEventListeners(listenerCount);\n }\n }, [\n isSupported,\n enabled,\n store,\n enableHistory,\n trackDOMNodes,\n trackEventListeners,\n logToConsole,\n devMode,\n ]);\n\n // Start monitoring\n const start = useCallback(() => {\n if (!isSupported || !enabled || isMonitoringRef.current) return;\n\n isMonitoringRef.current = true;\n store.updateMonitoringStatus(true);\n\n // Initial poll\n poll();\n\n // Set up interval\n intervalIdRef.current = setInterval(poll, interval);\n\n if (devMode && logToConsole) {\n console.log(\"[useMemoryMonitor] Monitoring started\");\n }\n }, [isSupported, enabled, store, poll, interval, devMode, logToConsole]);\n\n // Stop monitoring\n const stop = useCallback(() => {\n if (!isMonitoringRef.current) return;\n\n isMonitoringRef.current = false;\n store.updateMonitoringStatus(false);\n\n if (intervalIdRef.current) {\n clearInterval(intervalIdRef.current);\n intervalIdRef.current = null;\n }\n\n if (devMode && logToConsole) {\n console.log(\"[useMemoryMonitor] Monitoring stopped\");\n }\n }, [store, devMode, logToConsole]);\n\n // Take snapshot\n const takeSnapshot = useCallback(\n (id: string): MemorySnapshot | null => {\n if (!isSupported || !memory) return null;\n\n const snapshot: MemorySnapshot = {\n id,\n memory: { ...memory },\n domNodes: domNodes ?? undefined,\n eventListeners: eventListeners ?? undefined,\n timestamp: Date.now(),\n };\n\n snapshotsRef.current.set(id, snapshot);\n return snapshot;\n },\n [isSupported, memory, domNodes, eventListeners]\n );\n\n // Compare snapshots\n const compareSnapshots = useCallback(\n (id1: string, id2: string): SnapshotDiff | null => {\n const snapshot1 = snapshotsRef.current.get(id1);\n const snapshot2 = snapshotsRef.current.get(id2);\n\n if (!snapshot1 || !snapshot2) return null;\n\n return {\n heapDelta: snapshot2.memory.heapUsed - snapshot1.memory.heapUsed,\n heapPercentChange:\n snapshot1.memory.heapUsed > 0\n ? ((snapshot2.memory.heapUsed - snapshot1.memory.heapUsed) /\n snapshot1.memory.heapUsed) *\n 100\n : 0,\n domNodesDelta:\n snapshot1.domNodes != null && snapshot2.domNodes != null\n ? snapshot2.domNodes - snapshot1.domNodes\n : undefined,\n eventListenersDelta:\n snapshot1.eventListeners != null && snapshot2.eventListeners != null\n ? snapshot2.eventListeners - snapshot1.eventListeners\n : undefined,\n timeDelta: snapshot2.timestamp - snapshot1.timestamp,\n };\n },\n []\n );\n\n // Clear history\n const clearHistory = useCallback(() => {\n if (historyBufferRef.current) {\n historyBufferRef.current.clear();\n }\n }, []);\n\n // Request GC (hint only, not guaranteed)\n const requestGC = useCallback(() => {\n if (isServer()) return;\n\n // Try to trigger GC through memory pressure\n // This is a hint only and may not work in all browsers\n try {\n // Create and immediately release large array to suggest GC\n const pressure = new Array(1000000).fill(0);\n pressure.length = 0;\n } catch {\n // Ignore errors\n }\n\n if (devMode && logToConsole) {\n console.log(\"[useMemoryMonitor] GC hint requested\");\n }\n }, [devMode, logToConsole]);\n\n // Auto-start effect\n useEffect(() => {\n if (autoStart && isSupported && enabled && !shouldDisable) {\n start();\n }\n\n return () => {\n stop();\n };\n }, [autoStart, isSupported, enabled, shouldDisable, start, stop]);\n\n // Visibility change effect (pause when tab is hidden)\n useEffect(() => {\n if (isServer()) return;\n\n const handleVisibilityChange = () => {\n if (document.hidden) {\n stop();\n } else if (autoStart && isSupported && enabled) {\n start();\n }\n };\n\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n\n return () => {\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n };\n }, [autoStart, isSupported, enabled, start, stop]);\n\n // Severity change callback effect\n useEffect(() => {\n if (severity === prevSeverityRef.current) return;\n\n const prevSeverity = prevSeverityRef.current;\n prevSeverityRef.current = severity;\n\n if (!memory || !usagePercentage) return;\n\n const callbackData = {\n memory,\n usagePercentage,\n threshold: severity === \"critical\" ? (thresholds.critical ?? 90) : (thresholds.warning ?? 70),\n timestamp: Date.now(),\n };\n\n // Only call callback when severity increases\n if (severity === \"warning\" && prevSeverity === \"normal\") {\n onWarningRef.current?.(callbackData as MemoryWarning);\n } else if (severity === \"critical\") {\n onCriticalRef.current?.(callbackData as MemoryCritical);\n }\n }, [severity, memory, usagePercentage, thresholds.warning, thresholds.critical]);\n\n // Leak detection callback effect\n useEffect(() => {\n if (!leakAnalysis) return;\n\n if (isLeakDetected && !prevLeakDetectedRef.current) {\n onLeakDetectedRef.current?.(leakAnalysis);\n }\n\n prevLeakDetectedRef.current = isLeakDetected;\n }, [isLeakDetected, leakAnalysis]);\n\n // Unsupported callback effect\n useEffect(() => {\n if (!isSupported && onUnsupportedRef.current) {\n const unsupportedInfo = createUnsupportedInfo();\n onUnsupportedRef.current(unsupportedInfo);\n }\n }, [isSupported]);\n\n // SSR early return\n if (isServer()) {\n return {\n memory: null,\n heapUsed: null,\n heapTotal: null,\n heapLimit: null,\n usagePercentage: null,\n domNodes: null,\n eventListeners: null,\n isSupported: false,\n isMonitoring: false,\n isLeakDetected: false,\n severity: DEFAULT_SEVERITY,\n supportLevel: \"none\",\n availableMetrics: [],\n history: [],\n trend: DEFAULT_TREND,\n leakProbability: 0,\n start: () => {},\n stop: () => {},\n takeSnapshot: () => null,\n compareSnapshots: () => null,\n clearHistory: () => {},\n requestGC: () => {},\n formatted: SSR_FORMATTED_MEMORY,\n };\n }\n\n return {\n // Current State\n memory,\n heapUsed,\n heapTotal,\n heapLimit,\n usagePercentage,\n\n // DOM Related\n domNodes,\n eventListeners,\n\n // Status Flags\n isSupported,\n isMonitoring: storeState.isMonitoring,\n isLeakDetected,\n severity,\n\n // Support Details\n supportLevel,\n availableMetrics,\n\n // Analysis Data\n history,\n trend,\n leakProbability,\n\n // Actions\n start,\n stop,\n takeSnapshot,\n compareSnapshots,\n clearHistory,\n requestGC,\n\n // Formatting\n formatted,\n };\n}\n","import type {\n LeakSensitivity,\n Severity,\n Trend,\n UseMemoryMonitorOptions,\n FormattedMemory,\n MemoryStoreState,\n} from \"./types\";\n\n/**\n * Default monitoring interval in milliseconds\n */\nexport const DEFAULT_INTERVAL = 5000;\n\n/**\n * Default history buffer size\n */\nexport const DEFAULT_HISTORY_SIZE = 50;\n\n/**\n * Default warning threshold percentage\n */\nexport const DEFAULT_WARNING_THRESHOLD = 70;\n\n/**\n * Default critical threshold percentage\n */\nexport const DEFAULT_CRITICAL_THRESHOLD = 90;\n\n/**\n * Default leak detection window size\n */\nexport const DEFAULT_LEAK_WINDOW_SIZE = 10;\n\n/**\n * Minimum samples required for leak detection\n */\nexport const MIN_LEAK_DETECTION_SAMPLES = 5;\n\n/**\n * Sensitivity configuration for leak detection\n * - minSlope: Minimum slope (bytes/sample) to consider a leak\n * - minR2: Minimum R-squared value for regression fit quality\n */\nexport const LEAK_SENSITIVITY_CONFIG: Record<\n LeakSensitivity,\n { minSlope: number; minR2: number; probabilityMultiplier: number }\n> = {\n low: {\n minSlope: 100000, // 100KB/sample\n minR2: 0.7,\n probabilityMultiplier: 0.8,\n },\n medium: {\n minSlope: 50000, // 50KB/sample\n minR2: 0.6,\n probabilityMultiplier: 1.0,\n },\n high: {\n minSlope: 10000, // 10KB/sample\n minR2: 0.5,\n probabilityMultiplier: 1.2,\n },\n};\n\n/**\n * Trend thresholds (slope values)\n */\nexport const TREND_THRESHOLDS = {\n increasing: 0.01, // Slope > 0.01 = increasing\n decreasing: -0.01, // Slope < -0.01 = decreasing\n};\n\n/**\n * Default options for useMemoryMonitor\n */\nexport const DEFAULT_OPTIONS: Required<\n Omit<\n UseMemoryMonitorOptions,\n | \"onUpdate\"\n | \"onWarning\"\n | \"onCritical\"\n | \"onLeakDetected\"\n | \"onUnsupported\"\n >\n> = {\n interval: DEFAULT_INTERVAL,\n autoStart: true,\n enabled: true,\n enableHistory: false,\n historySize: DEFAULT_HISTORY_SIZE,\n thresholds: {\n warning: DEFAULT_WARNING_THRESHOLD,\n critical: DEFAULT_CRITICAL_THRESHOLD,\n },\n leakDetection: {\n enabled: false,\n sensitivity: \"medium\",\n windowSize: DEFAULT_LEAK_WINDOW_SIZE,\n threshold: undefined,\n },\n devMode: false,\n trackDOMNodes: false,\n trackEventListeners: false,\n logToConsole: false,\n disableInProduction: false,\n fallbackStrategy: \"dom-only\",\n};\n\n/**\n * Default severity\n */\nexport const DEFAULT_SEVERITY: Severity = \"normal\";\n\n/**\n * Default trend\n */\nexport const DEFAULT_TREND: Trend = \"stable\";\n\n/**\n * SSR-safe initial store state\n */\nexport const SSR_INITIAL_STATE: MemoryStoreState = {\n memory: null,\n domNodes: null,\n eventListeners: null,\n isMonitoring: false,\n severity: DEFAULT_SEVERITY,\n lastUpdated: 0,\n};\n\n/**\n * SSR-safe formatted memory values\n */\nexport const SSR_FORMATTED_MEMORY: FormattedMemory = {\n heapUsed: \"N/A\",\n heapTotal: \"N/A\",\n heapLimit: \"N/A\",\n domNodes: undefined,\n eventListeners: undefined,\n};\n\n/**\n * Byte units for formatting\n */\nexport const BYTE_UNITS = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\"] as const;\n\n/**\n * Bytes per unit (1024)\n */\nexport const BYTES_PER_UNIT = 1024;\n","import type {\n BrowserSupport,\n SupportLevel,\n AvailableMetric,\n UnsupportedInfo,\n UnsupportedReason,\n FallbackStrategy,\n} from \"../types\";\n\n/**\n * Check if running in a server-side environment\n */\nexport function isServer(): boolean {\n return typeof window === \"undefined\";\n}\n\n/**\n * Check if running in a client-side environment\n */\nexport function isClient(): boolean {\n return typeof window !== \"undefined\";\n}\n\n/**\n * Check if the legacy performance.memory API is available (Chrome/Edge)\n */\nexport function hasLegacyMemoryAPI(): boolean {\n if (isServer()) return false;\n return \"memory\" in performance;\n}\n\n/**\n * Check if the modern measureUserAgentSpecificMemory API is available\n */\nexport function hasPreciseMemoryAPI(): boolean {\n if (isServer()) return false;\n return \"measureUserAgentSpecificMemory\" in performance;\n}\n\n/**\n * Check if running in a secure context (HTTPS or localhost)\n */\nexport function isSecureContext(): boolean {\n if (isServer()) return false;\n return window.isSecureContext ?? false;\n}\n\n/**\n * Check if cross-origin isolated (required for precise memory API)\n */\nexport function isCrossOriginIsolated(): boolean {\n if (isServer()) return false;\n return window.crossOriginIsolated ?? false;\n}\n\n/**\n * Check if MutationObserver is available for DOM tracking\n */\nexport function hasMutationObserver(): boolean {\n if (isServer()) return false;\n return \"MutationObserver\" in window;\n}\n\n/**\n * Attempt to detect the browser name\n */\nexport function detectBrowser(): string | undefined {\n if (isServer()) return undefined;\n\n const userAgent = navigator.userAgent;\n\n if (userAgent.includes(\"Chrome\") && !userAgent.includes(\"Edg\")) {\n return \"Chrome\";\n }\n if (userAgent.includes(\"Edg\")) {\n return \"Edge\";\n }\n if (userAgent.includes(\"Firefox\")) {\n return \"Firefox\";\n }\n if (userAgent.includes(\"Safari\") && !userAgent.includes(\"Chrome\")) {\n return \"Safari\";\n }\n\n return undefined;\n}\n\n/**\n * Determine the support level based on available APIs\n */\nexport function determineSupportLevel(): SupportLevel {\n if (isServer()) return \"none\";\n\n if (hasLegacyMemoryAPI()) {\n return \"full\";\n }\n\n // DOM-only tracking is always available in browser\n return \"partial\";\n}\n\n/**\n * Get the list of available metrics based on browser support\n */\nexport function getAvailableMetrics(): AvailableMetric[] {\n if (isServer()) return [];\n\n const metrics: AvailableMetric[] = [];\n\n if (hasLegacyMemoryAPI()) {\n metrics.push(\"heapUsed\", \"heapTotal\", \"heapLimit\");\n }\n\n // DOM tracking is always available in browser\n metrics.push(\"domNodes\");\n\n // Event listener estimation is always available\n metrics.push(\"eventListeners\");\n\n return metrics;\n}\n\n/**\n * Get limitations based on current browser/context\n */\nexport function getLimitations(): string[] {\n const limitations: string[] = [];\n\n if (isServer()) {\n limitations.push(\"Running in server-side environment\");\n return limitations;\n }\n\n if (!hasLegacyMemoryAPI()) {\n limitations.push(\"performance.memory API not available (not Chrome/Edge)\");\n }\n\n if (!isSecureContext()) {\n limitations.push(\"Not running in secure context (HTTPS required for precise API)\");\n }\n\n if (!isCrossOriginIsolated()) {\n limitations.push(\n \"Not cross-origin isolated (COOP/COEP headers required for precise API)\"\n );\n }\n\n return limitations;\n}\n\n/**\n * Comprehensive browser support detection\n */\nexport function detectSupport(): BrowserSupport {\n return {\n level: determineSupportLevel(),\n availableMetrics: getAvailableMetrics(),\n limitations: getLimitations(),\n isSecureContext: isSecureContext(),\n isCrossOriginIsolated: isCrossOriginIsolated(),\n hasPreciseMemoryAPI: hasPreciseMemoryAPI(),\n };\n}\n\n/**\n * Determine the reason why memory monitoring is not supported\n */\nexport function getUnsupportedReason(): UnsupportedReason {\n if (isServer()) {\n return \"server-side\";\n }\n\n if (!isSecureContext() && hasPreciseMemoryAPI()) {\n return \"insecure-context\";\n }\n\n if (!hasLegacyMemoryAPI() && !hasPreciseMemoryAPI()) {\n return \"no-api\";\n }\n\n return \"browser-restriction\";\n}\n\n/**\n * Get available fallback strategies based on support\n */\nexport function getAvailableFallbacks(): FallbackStrategy[] {\n if (isServer()) {\n return [\"none\"];\n }\n\n const fallbacks: FallbackStrategy[] = [\"none\"];\n\n // DOM-only is always available in browser\n fallbacks.push(\"dom-only\");\n\n // Estimation can work in any browser\n fallbacks.push(\"estimation\");\n\n return fallbacks;\n}\n\n/**\n * Create UnsupportedInfo object for callbacks\n */\nexport function createUnsupportedInfo(): UnsupportedInfo {\n return {\n reason: getUnsupportedReason(),\n browser: detectBrowser(),\n availableFallbacks: getAvailableFallbacks(),\n };\n}\n\n/**\n * Check if the precise memory API can be used\n * Requires secure context AND cross-origin isolation\n */\nexport function canUsePreciseMemoryAPI(): boolean {\n return hasPreciseMemoryAPI() && isSecureContext() && isCrossOriginIsolated();\n}\n\n/**\n * Check if any memory monitoring is possible\n */\nexport function canMonitorMemory(): boolean {\n return isClient() && (hasLegacyMemoryAPI() || hasPreciseMemoryAPI());\n}\n","import type { MemoryInfo, MemoryStoreState, Severity } from \"./types\";\nimport { SSR_INITIAL_STATE } from \"./constants\";\nimport { isServer } from \"./utils/detection\";\n\ntype Listener = () => void;\n\n/**\n * Creates an external store for memory state management.\n * Compatible with useSyncExternalStore for React 18+ concurrent rendering.\n */\nfunction createMemoryStore() {\n let state: MemoryStoreState = { ...SSR_INITIAL_STATE };\n const listeners = new Set<Listener>();\n\n /**\n * Subscribe to store updates\n */\n function subscribe(listener: Listener): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n }\n\n /**\n * Get current state snapshot\n */\n function getSnapshot(): MemoryStoreState {\n return state;\n }\n\n /**\n * Get SSR-safe server snapshot\n */\n function getServerSnapshot(): MemoryStoreState {\n return SSR_INITIAL_STATE;\n }\n\n /**\n * Notify all listeners of state change\n */\n function notify(): void {\n listeners.forEach((listener) => listener());\n }\n\n /**\n * Update memory info in store\n */\n function updateMemory(memory: MemoryInfo | null): void {\n if (state.memory === memory) return;\n\n state = {\n ...state,\n memory,\n lastUpdated: Date.now(),\n };\n notify();\n }\n\n /**\n * Update DOM node count\n */\n function updateDOMNodes(count: number | null): void {\n if (state.domNodes === count) return;\n\n state = {\n ...state,\n domNodes: count,\n lastUpdated: Date.now(),\n };\n notify();\n }\n\n /**\n * Update event listener count\n */\n function updateEventListeners(count: number | null): void {\n if (state.eventListeners === count) return;\n\n state = {\n ...state,\n eventListeners: count,\n lastUpdated: Date.now(),\n };\n notify();\n }\n\n /**\n * Update monitoring status\n */\n function updateMonitoringStatus(isMonitoring: boolean): void {\n if (state.isMonitoring === isMonitoring) return;\n\n state = {\n ...state,\n isMonitoring,\n lastUpdated: Date.now(),\n };\n notify();\n }\n\n /**\n * Update severity level\n */\n function updateSeverity(severity: Severity): void {\n if (state.severity === severity) return;\n\n state = {\n ...state,\n severity,\n lastUpdated: Date.now(),\n };\n notify();\n }\n\n /**\n * Batch update multiple state properties\n */\n function batchUpdate(updates: Partial<MemoryStoreState>): void {\n const newState = { ...state, ...updates, lastUpdated: Date.now() };\n\n // Check if anything actually changed\n const hasChanges = Object.keys(updates).some(\n (key) => state[key as keyof MemoryStoreState] !== updates[key as keyof MemoryStoreState]\n );\n\n if (!hasChanges) return;\n\n state = newState;\n notify();\n }\n\n /**\n * Reset store to initial state\n */\n function reset(): void {\n state = { ...SSR_INITIAL_STATE };\n notify();\n }\n\n /**\n * Get current subscriber count (for debugging)\n */\n function getSubscriberCount(): number {\n return listeners.size;\n }\n\n return {\n subscribe,\n getSnapshot,\n getServerSnapshot,\n updateMemory,\n updateDOMNodes,\n updateEventListeners,\n updateMonitoringStatus,\n updateSeverity,\n batchUpdate,\n reset,\n getSubscriberCount,\n };\n}\n\n// Export store type\nexport type MemoryStore = ReturnType<typeof createMemoryStore>;\n\n/**\n * Creates a new memory store instance.\n * Each hook instance should create its own store to maintain isolation.\n */\nexport function createStore(): MemoryStore {\n return createMemoryStore();\n}\n\n/**\n * Creates an SSR-safe store that returns static values on the server.\n */\nexport function createSSRSafeStore(): MemoryStore {\n if (isServer()) {\n // Return a no-op store for SSR\n return {\n subscribe: () => () => {},\n getSnapshot: () => SSR_INITIAL_STATE,\n getServerSnapshot: () => SSR_INITIAL_STATE,\n updateMemory: () => {},\n updateDOMNodes: () => {},\n updateEventListeners: () => {},\n updateMonitoringStatus: () => {},\n updateSeverity: () => {},\n batchUpdate: () => {},\n reset: () => {},\n getSubscriberCount: () => 0,\n };\n }\n\n return createMemoryStore();\n}\n\n/**\n * Read current memory from performance.memory API\n */\nexport function readMemoryFromAPI(): MemoryInfo | null {\n if (isServer()) return null;\n\n const memory = (performance as { memory?: {\n usedJSHeapSize: number;\n totalJSHeapSize: number;\n jsHeapSizeLimit: number;\n } }).memory;\n\n if (!memory) return null;\n\n return {\n heapUsed: Math.max(0, memory.usedJSHeapSize),\n heapTotal: Math.max(0, memory.totalJSHeapSize),\n heapLimit: Math.max(0, memory.jsHeapSizeLimit),\n timestamp: Date.now(),\n };\n}\n\n/**\n * Count DOM nodes in the document\n */\nexport function countDOMNodes(): number | null {\n if (isServer()) return null;\n\n try {\n return document.querySelectorAll(\"*\").length;\n } catch {\n return null;\n }\n}\n\n/**\n * Estimate event listener count based on interactive elements.\n * This is an approximation since there's no direct API to count listeners.\n */\nexport function estimateEventListeners(): number | null {\n if (isServer()) return null;\n\n try {\n // Count elements that commonly have event listeners\n const interactiveElements = document.querySelectorAll(\n 'button, a, input, select, textarea, [onclick], [onchange], [onkeydown], [onkeyup], [onmouseover], [onmouseout], [onfocus], [onblur], [tabindex]'\n );\n\n // Rough estimate: each interactive element has ~1.5 listeners on average\n return Math.round(interactiveElements.length * 1.5);\n } catch {\n return null;\n }\n}\n","import { BYTE_UNITS, BYTES_PER_UNIT } from \"../constants\";\nimport type { FormattedMemory, MemoryInfo } from \"../types\";\n\n/**\n * Format bytes to human-readable string (e.g., \"45.2 MB\")\n *\n * @param bytes - Number of bytes to format\n * @param decimals - Number of decimal places (default: 2)\n * @returns Formatted string with unit\n */\nexport function formatBytes(bytes: number | null | undefined, decimals: number = 2): string {\n if (bytes === null || bytes === undefined) {\n return \"N/A\";\n }\n\n if (bytes === 0) {\n return \"0 B\";\n }\n\n if (bytes < 0) {\n return `-${formatBytes(Math.abs(bytes), decimals)}`;\n }\n\n const unitIndex = Math.max(\n 0,\n Math.min(\n Math.floor(Math.log(bytes) / Math.log(BYTES_PER_UNIT)),\n BYTE_UNITS.length - 1\n )\n );\n\n const value = bytes / Math.pow(BYTES_PER_UNIT, unitIndex);\n const unit = BYTE_UNITS[unitIndex];\n\n // Remove unnecessary trailing zeros\n const formatted = value.toFixed(decimals);\n const trimmed = parseFloat(formatted).toString();\n\n return `${trimmed} ${unit}`;\n}\n\n/**\n * Format a percentage value\n *\n * @param percentage - Percentage value (0-100)\n * @param decimals - Number of decimal places (default: 1)\n * @returns Formatted percentage string\n */\nexport function formatPercentage(\n percentage: number | null | undefined,\n decimals: number = 1\n): string {\n if (percentage === null || percentage === undefined) {\n return \"N/A\";\n }\n\n return `${percentage.toFixed(decimals)}%`;\n}\n\n/**\n * Format a number with thousand separators\n *\n * @param value - Number to format\n * @returns Formatted string with thousand separators\n */\nexport function formatNumber(value: number | null | undefined): string {\n if (value === null || value === undefined) {\n return \"N/A\";\n }\n\n return value.toLocaleString();\n}\n\n/**\n * Create formatted memory object for display\n *\n * @param memory - Memory info object\n * @param domNodes - DOM node count (optional)\n * @param eventListeners - Event listener count (optional)\n * @returns FormattedMemory object with human-readable strings\n */\nexport function createFormattedMemory(\n memory: MemoryInfo | null,\n domNodes?: number | null,\n eventListeners?: number | null\n): FormattedMemory {\n return {\n heapUsed: formatBytes(memory?.heapUsed),\n heapTotal: formatBytes(memory?.heapTotal),\n heapLimit: formatBytes(memory?.heapLimit),\n domNodes: domNodes != null ? formatNumber(domNodes) : undefined,\n eventListeners: eventListeners != null ? formatNumber(eventListeners) : undefined,\n };\n}\n\n/**\n * Calculate usage percentage from memory info\n *\n * @param heapUsed - Used heap size in bytes\n * @param heapLimit - Heap limit in bytes\n * @returns Usage percentage (0-100) or null if invalid\n */\nexport function calculateUsagePercentage(\n heapUsed: number | null | undefined,\n heapLimit: number | null | undefined\n): number | null {\n if (heapUsed == null || heapLimit == null || heapLimit <= 0) {\n return null;\n }\n\n const percentage = (heapUsed / heapLimit) * 100;\n return Math.min(100, Math.max(0, percentage));\n}\n\n/**\n * Format time duration in milliseconds to human-readable string\n *\n * @param ms - Duration in milliseconds\n * @returns Formatted duration string\n */\nexport function formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${ms}ms`;\n }\n\n if (ms < 60000) {\n return `${(ms / 1000).toFixed(1)}s`;\n }\n\n if (ms < 3600000) {\n return `${(ms / 60000).toFixed(1)}m`;\n }\n\n return `${(ms / 3600000).toFixed(1)}h`;\n}\n","/**\n * A fixed-size circular buffer (ring buffer) for efficient history storage.\n * Provides O(1) push operations and automatically overwrites oldest entries\n * when capacity is reached.\n *\n * @template T - Type of items stored in the buffer\n */\nexport class CircularBuffer<T> {\n private buffer: (T | undefined)[];\n private head: number = 0;\n private tail: number = 0;\n private _size: number = 0;\n private readonly _capacity: number;\n\n /**\n * Create a new circular buffer with the specified capacity\n *\n * @param capacity - Maximum number of items the buffer can hold\n * @throws Error if capacity is less than 1\n */\n constructor(capacity: number) {\n if (capacity < 1) {\n throw new Error(\"CircularBuffer capacity must be at least 1\");\n }\n\n this._capacity = capacity;\n this.buffer = new Array(capacity);\n }\n\n /**\n * Add an item to the buffer.\n * If the buffer is full, the oldest item will be overwritten.\n *\n * @param item - Item to add\n */\n push(item: T): void {\n this.buffer[this.tail] = item;\n this.tail = (this.tail + 1) % this._capacity;\n\n if (this._size < this._capacity) {\n this._size++;\n } else {\n // Buffer is full, move head forward (overwrite oldest)\n this.head = (this.head + 1) % this._capacity;\n }\n }\n\n /**\n * Get all items in the buffer as an array, from oldest to newest.\n *\n * @returns Array of items in insertion order (oldest first)\n */\n toArray(): T[] {\n const result: T[] = [];\n\n for (let i = 0; i < this._size; i++) {\n const index = (this.head + i) % this._capacity;\n result.push(this.buffer[index] as T);\n }\n\n return result;\n }\n\n /**\n * Get the most recent N items from the buffer.\n *\n * @param count - Number of items to retrieve\n * @returns Array of most recent items (oldest first within the slice)\n */\n getRecent(count: number): T[] {\n const actualCount = Math.min(count, this._size);\n const result: T[] = [];\n\n const startOffset = this._size - actualCount;\n for (let i = 0; i < actualCount; i++) {\n const index = (this.head + startOffset + i) % this._capacity;\n result.push(this.buffer[index] as T);\n }\n\n return result;\n }\n\n /**\n * Get the most recently added item.\n *\n * @returns The most recent item, or undefined if buffer is empty\n */\n get last(): T | undefined {\n if (this._size === 0) {\n return undefined;\n }\n\n const lastIndex = (this.tail - 1 + this._capacity) % this._capacity;\n return this.buffer[lastIndex];\n }\n\n /**\n * Get the oldest item in the buffer.\n *\n * @returns The oldest item, or undefined if buffer is empty\n */\n get first(): T | undefined {\n if (this._size === 0) {\n return undefined;\n }\n\n return this.buffer[this.head];\n }\n\n /**\n * Get an item at a specific index (0 = oldest).\n *\n * @param index - Index of the item to retrieve\n * @returns The item at the index, or undefined if out of bounds\n */\n at(index: number): T | undefined {\n if (index < 0 || index >= this._size) {\n return undefined;\n }\n\n const bufferIndex = (this.head + index) % this._capacity;\n return this.buffer[bufferIndex];\n }\n\n /**\n * Current number of items in the buffer.\n */\n get size(): number {\n return this._size;\n }\n\n /**\n * Maximum capacity of the buffer.\n */\n get capacity(): number {\n return this._capacity;\n }\n\n /**\n * Check if the buffer is empty.\n */\n get isEmpty(): boolean {\n return this._size === 0;\n }\n\n /**\n * Check if the buffer is full.\n */\n get isFull(): boolean {\n return this._size === this._capacity;\n }\n\n /**\n * Clear all items from the buffer.\n */\n clear(): void {\n this.buffer = new Array(this._capacity);\n this.head = 0;\n this.tail = 0;\n this._size = 0;\n }\n\n /**\n * Iterate over all items in the buffer (oldest to newest).\n */\n *[Symbol.iterator](): Iterator<T> {\n for (let i = 0; i < this._size; i++) {\n const index = (this.head + i) % this._capacity;\n yield this.buffer[index] as T;\n }\n }\n\n /**\n * Apply a function to each item in the buffer.\n *\n * @param callback - Function to call for each item\n */\n forEach(callback: (item: T, index: number) => void): void {\n for (let i = 0; i < this._size; i++) {\n const bufferIndex = (this.head + i) % this._capacity;\n callback(this.buffer[bufferIndex] as T, i);\n }\n }\n\n /**\n * Map items to a new array.\n *\n * @param callback - Function to transform each item\n * @returns Array of transformed items\n */\n map<U>(callback: (item: T, index: number) => U): U[] {\n const result: U[] = [];\n\n for (let i = 0; i < this._size; i++) {\n const bufferIndex = (this.head + i) % this._capacity;\n result.push(callback(this.buffer[bufferIndex] as T, i));\n }\n\n return result;\n }\n\n /**\n * Filter items based on a predicate.\n *\n * @param predicate - Function to test each item\n * @returns Array of items that pass the test\n */\n filter(predicate: (item: T, index: number) => boolean): T[] {\n const result: T[] = [];\n\n for (let i = 0; i < this._size; i++) {\n const bufferIndex = (this.head + i) % this._capacity;\n const item = this.buffer[bufferIndex] as T;\n\n if (predicate(item, i)) {\n result.push(item);\n }\n }\n\n return result;\n }\n}\n","import type {\n LeakAnalysis,\n LeakSensitivity,\n MemoryInfo,\n Trend,\n} from \"../types\";\nimport {\n LEAK_SENSITIVITY_CONFIG,\n MIN_LEAK_DETECTION_SAMPLES,\n TREND_THRESHOLDS,\n} from \"../constants\";\n\n/**\n * Result of linear regression analysis\n */\nexport interface RegressionResult {\n /** Slope of the regression line (bytes per sample) */\n slope: number;\n /** Y-intercept of the regression line */\n intercept: number;\n /** R-squared value (coefficient of determination, 0-1) */\n rSquared: number;\n}\n\n/**\n * Perform simple linear regression on a set of points.\n * Uses the least squares method.\n *\n * @param points - Array of [x, y] coordinate pairs\n * @returns Regression result with slope, intercept, and R-squared\n */\nexport function linearRegression(points: [number, number][]): RegressionResult {\n const n = points.length;\n\n if (n < 2) {\n return { slope: 0, intercept: 0, rSquared: 0 };\n }\n\n // Calculate sums\n let sumX = 0;\n let sumY = 0;\n let sumXY = 0;\n let sumX2 = 0;\n let sumY2 = 0;\n\n for (const [x, y] of points) {\n sumX += x;\n sumY += y;\n sumXY += x * y;\n sumX2 += x * x;\n sumY2 += y * y;\n }\n\n // Calculate slope and intercept\n const denominator = n * sumX2 - sumX * sumX;\n\n if (denominator === 0) {\n return { slope: 0, intercept: sumY / n, rSquared: 0 };\n }\n\n const slope = (n * sumXY - sumX * sumY) / denominator;\n const intercept = (sumY - slope * sumX) / n;\n\n // Calculate R-squared (coefficient of determination)\n const meanY = sumY / n;\n let ssTotal = 0; // Total sum of squares\n let ssResidual = 0; // Residual sum of squares\n\n for (const [x, y] of points) {\n const predicted = slope * x + intercept;\n ssTotal += Math.pow(y - meanY, 2);\n ssResidual += Math.pow(y - predicted, 2);\n }\n\n const rSquared = ssTotal === 0 ? 0 : 1 - ssResidual / ssTotal;\n\n return {\n slope,\n intercept,\n rSquared: Math.max(0, Math.min(1, rSquared)), // Clamp to [0, 1]\n };\n}\n\n/**\n * Calculate the memory trend from samples.\n *\n * @param samples - Array of memory info samples\n * @returns Trend direction\n */\nexport function calculateTrend(samples: MemoryInfo[]): Trend {\n if (samples.length < 2) {\n return \"stable\";\n }\n\n // Convert samples to [index, heapUsed] points\n const points: [number, number][] = samples.map((s, i) => [i, s.heapUsed]);\n const { slope } = linearRegression(points);\n\n // Normalize slope by average heap size for relative comparison\n const avgHeap = samples.reduce((sum, s) => sum + s.heapUsed, 0) / samples.length;\n const normalizedSlope = avgHeap > 0 ? slope / avgHeap : 0;\n\n if (normalizedSlope > TREND_THRESHOLDS.increasing) {\n return \"increasing\";\n }\n\n if (normalizedSlope < TREND_THRESHOLDS.decreasing) {\n return \"decreasing\";\n }\n\n return \"stable\";\n}\n\n/**\n * Calculate average growth rate (bytes per sample).\n *\n * @param samples - Array of memory info samples\n * @returns Average growth rate in bytes per sample\n */\nexport function calculateAverageGrowth(samples: MemoryInfo[]): number {\n if (samples.length < 2) {\n return 0;\n }\n\n const points: [number, number][] = samples.map((s, i) => [i, s.heapUsed]);\n const { slope } = linearRegression(points);\n\n return slope;\n}\n\n/**\n * Generate a human-readable recommendation based on leak analysis.\n *\n * @param probability - Leak probability (0-100)\n * @param trend - Memory trend\n * @param averageGrowth - Average growth rate in bytes\n * @returns Recommendation string\n */\nexport function generateRecommendation(\n probability: number,\n trend: Trend,\n averageGrowth: number\n): string | undefined {\n if (probability < 30) {\n return undefined;\n }\n\n if (probability >= 80) {\n return `Critical: High probability of memory leak detected. Memory is growing at ${formatGrowthRate(averageGrowth)} per sample. Consider profiling with browser DevTools.`;\n }\n\n if (probability >= 60) {\n return `Warning: Possible memory leak detected. Memory trend is ${trend}. Monitor closely and check for retained references.`;\n }\n\n if (probability >= 30 && trend === \"increasing\") {\n return `Note: Memory usage is trending upward. This may be normal for your application, but consider monitoring.`;\n }\n\n return undefined;\n}\n\n/**\n * Format growth rate for display.\n *\n * @param bytesPerSample - Growth rate in bytes per sample\n * @returns Formatted string\n */\nfunction formatGrowthRate(bytesPerSample: number): string {\n const absBytes = Math.abs(bytesPerSample);\n\n if (absBytes >= 1024 * 1024) {\n return `${(bytesPerSample / (1024 * 1024)).toFixed(2)} MB`;\n }\n\n if (absBytes >= 1024) {\n return `${(bytesPerSample / 1024).toFixed(2)} KB`;\n }\n\n return `${bytesPerSample.toFixed(0)} bytes`;\n}\n\n/**\n * Analyze memory samples for potential leaks.\n *\n * @param samples - Array of memory info samples (minimum 5 recommended)\n * @param sensitivity - Detection sensitivity level\n * @param customThreshold - Optional custom growth threshold (bytes/sample)\n * @returns Leak analysis result\n */\nexport function analyzeLeakProbability(\n samples: MemoryInfo[],\n sensitivity: LeakSensitivity = \"medium\",\n customThreshold?: number\n): LeakAnalysis {\n // Not enough samples for reliable analysis\n if (samples.length < MIN_LEAK_DETECTION_SAMPLES) {\n return {\n isLeaking: false,\n probability: 0,\n trend: calculateTrend(samples),\n averageGrowth: calculateAverageGrowth(samples),\n rSquared: 0,\n samples,\n recommendation: undefined,\n };\n }\n\n const config = LEAK_SENSITIVITY_CONFIG[sensitivity];\n const threshold = customThreshold ?? config.minSlope;\n\n // Convert samples to points for regression\n const points: [number, number][] = samples.map((s, i) => [i, s.heapUsed]);\n const { slope, rSquared } = linearRegression(points);\n\n // Calculate probability based on slope and fit quality\n let probability = 0;\n\n if (slope > 0 && rSquared >= config.minR2) {\n // Base probability from slope exceeding threshold\n const slopeRatio = slope / threshold;\n probability = Math.min(100, slopeRatio * 50 * rSquared * config.probabilityMultiplier);\n }\n\n const trend = calculateTrend(samples);\n const averageGrowth = slope;\n\n // Boost probability if trend is clearly increasing and R² is good\n if (trend === \"increasing\" && rSquared > 0.7 && probability < 60) {\n probability = Math.max(probability, 40);\n }\n\n // Cap probability\n probability = Math.min(100, Math.max(0, probability));\n\n const isLeaking = probability > 50;\n\n return {\n isLeaking,\n probability: Math.round(probability),\n trend,\n averageGrowth,\n rSquared,\n samples,\n recommendation: generateRecommendation(probability, trend, averageGrowth),\n };\n}\n\n/**\n * Quick check if memory is trending upward (without full analysis).\n *\n * @param samples - Array of memory info samples\n * @returns True if memory appears to be growing\n */\nexport function isMemoryGrowing(samples: MemoryInfo[]): boolean {\n if (samples.length < 3) {\n return false;\n }\n\n const trend = calculateTrend(samples);\n return trend === \"increasing\";\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@usefy/use-memory-monitor",
3
+ "version": "0.0.1",
4
+ "description": "A React hook for real-time browser memory monitoring with leak detection",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "sideEffects": false,
19
+ "peerDependencies": {
20
+ "react": "^18.0.0 || ^19.0.0"
21
+ },
22
+ "devDependencies": {
23
+ "@testing-library/jest-dom": "^6.9.1",
24
+ "@testing-library/react": "^16.3.1",
25
+ "@types/react": "^19.0.0",
26
+ "jsdom": "^27.3.0",
27
+ "react": "^19.0.0",
28
+ "rimraf": "^6.0.1",
29
+ "tsup": "^8.0.0",
30
+ "typescript": "^5.0.0",
31
+ "vitest": "^4.0.16"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/mirunamu00/usefy.git",
39
+ "directory": "packages/use-memory-monitor"
40
+ },
41
+ "license": "MIT",
42
+ "keywords": [
43
+ "react",
44
+ "hooks",
45
+ "memory",
46
+ "monitoring",
47
+ "performance",
48
+ "leak-detection",
49
+ "useMemoryMonitor",
50
+ "heap",
51
+ "profiling"
52
+ ],
53
+ "scripts": {
54
+ "build": "tsup",
55
+ "dev": "tsup --watch",
56
+ "test": "vitest run",
57
+ "test:watch": "vitest",
58
+ "test:coverage": "vitest run --coverage",
59
+ "typecheck": "tsc --noEmit",
60
+ "clean": "rimraf dist"
61
+ }
62
+ }