{"version":3,"file":"useApiHealth.mjs","sources":["../../../../src/lib/api/hooks/useApiHealth.ts"],"sourcesContent":["/**\n * @file useApiHealth Hook\n * @description React hook for monitoring API health and connectivity status\n * with automatic health checks, circuit breaker patterns, and status notifications.\n *\n * @example\n * ```typescript\n * import { useApiHealth } from '@/lib/api';\n *\n * function ApiStatusIndicator() {\n *   const { status, latency, lastCheck, checkNow } = useApiHealth({\n *     endpoint: '/health',\n *     interval: 30000,\n *   });\n *\n *   return (\n *     <div>\n *       <StatusBadge status={status} />\n *       <span>Latency: {latency}ms</span>\n *       <button onClick={checkNow}>Check Now</button>\n *     </div>\n *   );\n * }\n * ```\n */\n\nimport { useState, useEffect, useCallback, useRef, useMemo } from 'react';\nimport { useLatestRef } from '../../hooks/shared/useLatestRef';\nimport { useApiClient } from './useApiClient';\nimport type { HealthStatus, HealthCheckResult } from '../types';\nimport { API_CONFIG, TIMING } from '@/config';\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\n/**\n * Health check configuration\n */\nexport interface UseApiHealthConfig {\n  /** Health check endpoint (default: /health) */\n  endpoint?: string;\n  /** Check interval in milliseconds (default: 30000) */\n  interval?: number;\n  /** Request timeout in milliseconds (default: 5000) */\n  timeout?: number;\n  /** Number of failures before marking unhealthy (default: 3) */\n  failureThreshold?: number;\n  /** Number of successes before marking healthy (default: 1) */\n  successThreshold?: number;\n  /** Enable automatic health checks (default: true) */\n  autoCheck?: boolean;\n  /** Callback on status change */\n  onStatusChange?: (status: HealthStatus, previous: HealthStatus) => void;\n  /** Callback on health check complete */\n  onCheck?: (result: HealthCheckResult) => void;\n  /** Custom health check function */\n  healthCheckFn?: () => Promise<HealthCheckResult>;\n}\n\n/**\n * Return type for useApiHealth\n */\nexport interface UseApiHealthResult {\n  /** Current health status */\n  status: HealthStatus;\n  /** Whether API is currently healthy */\n  isHealthy: boolean;\n  /** Whether API is degraded */\n  isDegraded: boolean;\n  /** Whether API is unhealthy */\n  isUnhealthy: boolean;\n  /** Last recorded latency in ms */\n  latency: number | null;\n  /** Average latency over recent checks */\n  averageLatency: number | null;\n  /** Last check timestamp */\n  lastCheck: number | null;\n  /** Last check error (if any) */\n  lastError: string | null;\n  /** Number of consecutive failures */\n  consecutiveFailures: number;\n  /** Number of consecutive successes */\n  consecutiveSuccesses: number;\n  /** Whether currently checking */\n  isChecking: boolean;\n  /** Trigger manual health check */\n  checkNow: () => Promise<HealthCheckResult>;\n  /** Start automatic health checks */\n  startMonitoring: () => void;\n  /** Stop automatic health checks */\n  stopMonitoring: () => void;\n  /** Whether monitoring is active */\n  isMonitoring: boolean;\n  /** Full health check history */\n  history: HealthCheckResult[];\n  /** Reset health state */\n  reset: () => void;\n}\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\nconst DEFAULT_CONFIG: Required<\n  Omit<UseApiHealthConfig, 'onStatusChange' | 'onCheck' | 'healthCheckFn'>\n> = {\n  endpoint: API_CONFIG.ENDPOINTS.HEALTH.CHECK,\n  interval: TIMING.BACKGROUND.POLL.STANDARD,\n  timeout: API_CONFIG.TIMEOUT.HEALTH,\n  failureThreshold: 3,\n  successThreshold: 1,\n  autoCheck: true,\n};\n\nconst MAX_HISTORY_SIZE = 50;\n\n// =============================================================================\n// HOOK IMPLEMENTATION\n// =============================================================================\n\n/**\n * Hook for monitoring API health and connectivity\n *\n * @param config - Health check configuration\n * @returns Health monitoring utilities and status\n *\n * @example\n * ```typescript\n * // Basic usage\n * const { status, isHealthy, latency } = useApiHealth();\n *\n * // With configuration\n * const { status, checkNow, stopMonitoring } = useApiHealth({\n *   endpoint: '/api/health',\n *   interval: 60000,\n *   failureThreshold: 5,\n *   onStatusChange: (newStatus, oldStatus) => {\n *     if (newStatus === 'unhealthy') {\n *       showErrorToast('API is currently unavailable');\n *     }\n *   },\n * });\n *\n * // Manual checks only\n * const { checkNow } = useApiHealth({\n *   autoCheck: false,\n * });\n * ```\n */\nexport function useApiHealth(config?: UseApiHealthConfig): UseApiHealthResult {\n  const { client } = useApiClient();\n\n  // Merge config with defaults\n  const mergedConfig = useMemo(\n    () => ({\n      ...DEFAULT_CONFIG,\n      ...config,\n    }),\n    [config]\n  );\n\n  // State\n  const [status, setStatus] = useState<HealthStatus>('unknown');\n  const [latency, setLatency] = useState<number | null>(null);\n  const [lastCheck, setLastCheck] = useState<number | null>(null);\n  const [lastError, setLastError] = useState<string | null>(null);\n  const [consecutiveFailures, setConsecutiveFailures] = useState(0);\n  const [consecutiveSuccesses, setConsecutiveSuccesses] = useState(0);\n  const [isChecking, setIsChecking] = useState(false);\n  const [isMonitoring, setIsMonitoring] = useState(mergedConfig.autoCheck);\n  const [history, setHistory] = useState<HealthCheckResult[]>([]);\n\n  // Refs for callbacks and interval\n  const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n  const latencyHistory = useRef<number[]>([]);\n  const previousStatus = useRef<HealthStatus>('unknown');\n\n  // Refs to track consecutive counts for immediate reads (avoiding stale closure)\n  // These are updated synchronously while state is updated asynchronously\n  const consecutiveSuccessesRef = useRef(0);\n  const consecutiveFailuresRef = useRef(0);\n\n  // Calculate average latency\n  // Using state instead of ref access during render to avoid React rules violation\n  const [averageLatency, setAverageLatency] = useState<number | null>(null);\n\n  const calculateAverageLatency = useCallback((): number | null => {\n    if (latencyHistory.current.length === 0) return null;\n    const sum = latencyHistory.current.reduce((a, b) => a + b, 0);\n    return Math.round(sum / latencyHistory.current.length);\n  }, []);\n\n  // Health check function\n  const performHealthCheck = useCallback(async (): Promise<HealthCheckResult> => {\n    setIsChecking(true);\n    const startTime = Date.now();\n\n    try {\n      // Use custom health check function if provided\n      if (config?.healthCheckFn) {\n        const result = await config.healthCheckFn();\n        setIsChecking(false);\n        return result;\n      }\n\n      // Default health check\n      const response = await client.get<{ status?: string; checks?: Record<string, unknown> }>(\n        mergedConfig.endpoint,\n        {\n          timeout: mergedConfig.timeout,\n          meta: { skipRetry: true, skipAuth: true },\n        }\n      );\n\n      const endTime = Date.now();\n      const checkLatency = endTime - startTime;\n\n      // Update latency history\n      latencyHistory.current.push(checkLatency);\n      if (latencyHistory.current.length > 10) {\n        latencyHistory.current.shift();\n      }\n\n      // Update average latency\n      setAverageLatency(calculateAverageLatency());\n\n      const result: HealthCheckResult = {\n        status: 'healthy',\n        timestamp: endTime,\n        latency: checkLatency,\n        checks: response.data.checks as Record<\n          string,\n          { status: HealthStatus; message?: string; latency?: number }\n        >,\n      };\n\n      // Check for degraded status based on latency threshold\n      if (checkLatency > mergedConfig.timeout / 2) {\n        result.status = 'degraded';\n      }\n\n      setLatency(checkLatency);\n      setLastCheck(endTime);\n      setLastError(null);\n\n      // Update refs synchronously for immediate threshold check\n      consecutiveFailuresRef.current = 0;\n      consecutiveSuccessesRef.current = consecutiveSuccessesRef.current + 1;\n\n      // Update state for rendering\n      setConsecutiveFailures(0);\n      setConsecutiveSuccesses(consecutiveSuccessesRef.current);\n\n      // Update status - use ref for immediate check (avoids stale closure)\n      if (consecutiveSuccessesRef.current >= mergedConfig.successThreshold) {\n        setStatus(result.status);\n      }\n\n      // Add to history\n      setHistory((prev) => {\n        const updated = [...prev, result];\n        return updated.slice(-MAX_HISTORY_SIZE);\n      });\n\n      setIsChecking(false);\n\n      // Notify\n      config?.onCheck?.(result);\n\n      return result;\n    } catch (error) {\n      const endTime = Date.now();\n      const checkLatency = endTime - startTime;\n\n      const errorMessage = error instanceof Error ? error.message : 'Health check failed';\n\n      const result: HealthCheckResult = {\n        status: 'unhealthy',\n        timestamp: endTime,\n        latency: checkLatency,\n        error: errorMessage,\n      };\n\n      setLatency(checkLatency);\n      setLastCheck(endTime);\n      setLastError(errorMessage);\n\n      // Update refs synchronously for immediate threshold check\n      consecutiveSuccessesRef.current = 0;\n      consecutiveFailuresRef.current = consecutiveFailuresRef.current + 1;\n\n      // Update state for rendering\n      setConsecutiveSuccesses(0);\n      setConsecutiveFailures(consecutiveFailuresRef.current);\n\n      // Update status - use ref for immediate check (avoids stale closure)\n      if (consecutiveFailuresRef.current >= mergedConfig.failureThreshold) {\n        setStatus('unhealthy');\n      } else if (status === 'healthy') {\n        setStatus('degraded');\n      }\n\n      // Add to history\n      setHistory((prev) => {\n        const updated = [...prev, result];\n        return updated.slice(-MAX_HISTORY_SIZE);\n      });\n\n      setIsChecking(false);\n\n      // Notify\n      config?.onCheck?.(result);\n\n      return result;\n    }\n    // Dependencies reduced: consecutiveSuccesses/Failures now use refs for immediate reads\n    // status is still needed for degraded fallback logic\n  }, [client, mergedConfig, config, status, calculateAverageLatency]);\n\n  // Use useLatestRef to avoid interval thrashing when performHealthCheck changes\n  const performHealthCheckRef = useLatestRef(performHealthCheck);\n\n  // Status change notification\n  useEffect(() => {\n    if (status !== previousStatus.current) {\n      config?.onStatusChange?.(status, previousStatus.current);\n      previousStatus.current = status;\n    }\n  }, [status, config]);\n\n  // Start monitoring\n  const startMonitoring = useCallback(() => {\n    setIsMonitoring(true);\n  }, []);\n\n  // Stop monitoring\n  const stopMonitoring = useCallback(() => {\n    setIsMonitoring(false);\n    if (intervalRef.current) {\n      clearInterval(intervalRef.current);\n      intervalRef.current = null;\n    }\n  }, []);\n\n  // Reset state\n  const reset = useCallback(() => {\n    setStatus('unknown');\n    setLatency(null);\n    setLastCheck(null);\n    setLastError(null);\n    setConsecutiveFailures(0);\n    setConsecutiveSuccesses(0);\n    setHistory([]);\n    latencyHistory.current = [];\n    // Also reset refs\n    consecutiveSuccessesRef.current = 0;\n    consecutiveFailuresRef.current = 0;\n  }, []);\n\n  // Manual check - uses ref to get latest performHealthCheck without causing recreation\n  const checkNow = useCallback(async (): Promise<HealthCheckResult> => {\n    return performHealthCheckRef.current();\n  }, [performHealthCheckRef]); // Empty deps - ref always has latest function\n\n  // Set up interval\n  // Uses ref for performHealthCheck to avoid interval thrashing when the callback changes\n  useEffect(() => {\n    if (isMonitoring) {\n      // Initial check\n      void performHealthCheckRef.current();\n\n      // Set up interval - use wrapper function to call ref\n      intervalRef.current = setInterval(() => {\n        void performHealthCheckRef.current();\n      }, mergedConfig.interval);\n\n      return () => {\n        if (intervalRef.current) {\n          clearInterval(intervalRef.current);\n          intervalRef.current = null;\n        }\n      };\n    }\n    return undefined;\n  }, [isMonitoring, mergedConfig.interval, performHealthCheckRef]); // Removed performHealthCheck - using ref instead\n\n  // Cleanup on unmount\n  useEffect(() => {\n    return () => {\n      if (intervalRef.current) {\n        clearInterval(intervalRef.current);\n      }\n    };\n  }, []);\n\n  return useMemo(\n    () => ({\n      status,\n      isHealthy: status === 'healthy',\n      isDegraded: status === 'degraded',\n      isUnhealthy: status === 'unhealthy',\n      latency,\n      averageLatency,\n      lastCheck,\n      lastError,\n      consecutiveFailures,\n      consecutiveSuccesses,\n      isChecking,\n      checkNow,\n      startMonitoring,\n      stopMonitoring,\n      isMonitoring,\n      history,\n      reset,\n    }),\n    [\n      status,\n      latency,\n      averageLatency,\n      lastCheck,\n      lastError,\n      consecutiveFailures,\n      consecutiveSuccesses,\n      isChecking,\n      checkNow,\n      startMonitoring,\n      stopMonitoring,\n      isMonitoring,\n      history,\n      reset,\n    ]\n  );\n}\n\n// =============================================================================\n// SPECIALIZED HOOKS\n// =============================================================================\n\n/**\n * Hook for simple connectivity check\n *\n * @example\n * ```typescript\n * const isOnline = useApiConnectivity();\n *\n * if (!isOnline) {\n *   return <OfflineIndicator />;\n * }\n * ```\n */\nexport function useApiConnectivity(): boolean {\n  const { isHealthy, isDegraded } = useApiHealth({\n    interval: TIMING.BACKGROUND.POLL.SLOW,\n    failureThreshold: 2,\n  });\n\n  return isHealthy || isDegraded;\n}\n\n/**\n * Hook for network-aware operations\n *\n * @example\n * ```typescript\n * const { canMakeRequest, waitForConnectivity } = useNetworkAware();\n *\n * const handleSubmit = async () => {\n *   if (!canMakeRequest) {\n *     await waitForConnectivity();\n *   }\n *   // Proceed with request\n * };\n * ```\n */\nexport function useNetworkAware(): {\n  canMakeRequest: boolean;\n  isOnline: boolean;\n  isBrowserOnline: boolean;\n  waitForConnectivity: (timeout?: number) => Promise<void>;\n} {\n  const [isBrowserOnline, setIsBrowserOnline] = useState(\n    typeof navigator !== 'undefined' ? navigator.onLine : true\n  );\n  const { isHealthy, isDegraded, checkNow } = useApiHealth({\n    autoCheck: false,\n  });\n\n  // Listen for browser online/offline events\n  useEffect(() => {\n    const handleOnline = (): void => setIsBrowserOnline(true);\n    const handleOffline = (): void => setIsBrowserOnline(false);\n\n    window.addEventListener('online', handleOnline);\n    window.addEventListener('offline', handleOffline);\n\n    return () => {\n      window.removeEventListener('online', handleOnline);\n      window.removeEventListener('offline', handleOffline);\n    };\n  }, []);\n\n  const canMakeRequest = isBrowserOnline && (isHealthy || isDegraded);\n\n  const waitForConnectivity = useCallback(\n    async (timeout = 30000): Promise<void> => {\n      const startTime = Date.now();\n\n      while (Date.now() - startTime < timeout) {\n        if (isBrowserOnline) {\n          const result = await checkNow();\n          if (result.status === 'healthy' || result.status === 'degraded') {\n            return;\n          }\n        }\n        await new Promise((resolve) => setTimeout(resolve, 1000));\n      }\n\n      throw new Error('Connectivity timeout');\n    },\n    [isBrowserOnline, checkNow]\n  );\n\n  return {\n    canMakeRequest,\n    isOnline: isHealthy || isDegraded,\n    isBrowserOnline,\n    waitForConnectivity,\n  };\n}\n\n/**\n * Hook for monitoring multiple API endpoints\n *\n * @example\n * ```typescript\n * const services = useMultiApiHealth([\n *   { name: 'Main API', endpoint: '/health' },\n *   { name: 'Auth Service', endpoint: '/auth/health' },\n *   { name: 'File Service', endpoint: '/files/health' },\n * ]);\n *\n * return (\n *   <ul>\n *     {services.map(s => (\n *       <li key={s.name}>\n *         {s.name}: {s.status} ({s.latency}ms)\n *       </li>\n *     ))}\n *   </ul>\n * );\n * ```\n */\nexport function useMultiApiHealth(\n  endpoints: Array<{ name: string; endpoint: string; interval?: number }>\n): Array<{\n  name: string;\n  endpoint: string;\n  status: HealthStatus;\n  latency: number | null;\n  isHealthy: boolean;\n}> {\n  const [results, setResults] = useState<\n    Map<string, { status: HealthStatus; latency: number | null }>\n  >(new Map());\n\n  const { client } = useApiClient();\n\n  useEffect(() => {\n    const intervals: Array<ReturnType<typeof setInterval>> = [];\n\n    for (const { name, endpoint, interval = TIMING.BACKGROUND.POLL.STANDARD } of endpoints) {\n      const check = async (): Promise<void> => {\n        const startTime = Date.now();\n\n        try {\n          await client.get(endpoint, {\n            timeout: API_CONFIG.TIMEOUT.HEALTH,\n            meta: { skipRetry: true, skipAuth: true },\n          });\n\n          const latency = Date.now() - startTime;\n          setResults((prev) => {\n            const next = new Map(prev);\n            next.set(name, { status: 'healthy', latency });\n            return next;\n          });\n        } catch {\n          const latency = Date.now() - startTime;\n          setResults((prev) => {\n            const next = new Map(prev);\n            next.set(name, { status: 'unhealthy', latency });\n            return next;\n          });\n        }\n      };\n\n      // Initial check\n      void check();\n\n      // Set up interval - wrap to avoid no-misused-promises\n      intervals.push(\n        setInterval(() => {\n          void check();\n        }, interval)\n      );\n    }\n\n    return () => {\n      intervals.forEach(clearInterval);\n    };\n  }, [client, endpoints]);\n\n  return endpoints.map(({ name, endpoint }) => {\n    const result = results.get(name) ?? { status: 'unknown' as HealthStatus, latency: null };\n    return {\n      name,\n      endpoint,\n      status: result.status,\n      latency: result.latency,\n      isHealthy: result.status === 'healthy',\n    };\n  });\n}\n"],"names":["DEFAULT_CONFIG","API_CONFIG","TIMING","MAX_HISTORY_SIZE","useApiHealth","config","client","useApiClient","mergedConfig","useMemo","status","setStatus","useState","latency","setLatency","lastCheck","setLastCheck","lastError","setLastError","consecutiveFailures","setConsecutiveFailures","consecutiveSuccesses","setConsecutiveSuccesses","isChecking","setIsChecking","isMonitoring","setIsMonitoring","history","setHistory","intervalRef","useRef","latencyHistory","previousStatus","consecutiveSuccessesRef","consecutiveFailuresRef","averageLatency","setAverageLatency","calculateAverageLatency","useCallback","sum","a","b","performHealthCheck","startTime","result","response","endTime","checkLatency","prev","error","errorMessage","performHealthCheckRef","useLatestRef","useEffect","startMonitoring","stopMonitoring","reset","checkNow","useApiConnectivity","isHealthy","isDegraded","useNetworkAware","isBrowserOnline","setIsBrowserOnline","handleOnline","handleOffline","canMakeRequest","waitForConnectivity","timeout","resolve","useMultiApiHealth","endpoints","results","setResults","intervals","name","endpoint","interval","check","next"],"mappings":"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"}