{"version":3,"file":"index.cjs","sources":["../src/hooks/useServiceStatus.ts","../src/utils/statusMapper.ts","../src/components/StatusPopover.tsx","../src/components/ServiceStatusBadge.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useRef } from 'react';\nimport type {\n  ServiceStatusData,\n  BetterstackApiResponse,\n  ServiceStatus,\n} from '../types';\n\nexport interface UseServiceStatusOptions {\n  serviceName: string;\n  apiUrl: string;\n  refreshInterval: number;\n  onStatusChange?: (status: ServiceStatus) => void;\n}\n\n/**\n * Custom hook to fetch and monitor service status from Betterstack API\n */\nexport function useServiceStatus({\n  serviceName,\n  apiUrl,\n  refreshInterval,\n  onStatusChange,\n}: UseServiceStatusOptions): ServiceStatusData {\n  const [status, setStatus] = useState<ServiceStatus>('operational');\n  const [availability, setAvailability] = useState<number>(1);\n  const [lastUpdated, setLastUpdated] = useState<Date>(new Date());\n  const [isLoading, setIsLoading] = useState<boolean>(true);\n  const [error, setError] = useState<string | null>(null);\n\n  const previousStatusRef = useRef<ServiceStatus>('operational');\n  const intervalRef = useRef<NodeJS.Timeout | null>(null);\n\n  const fetchStatus = useCallback(async () => {\n    try {\n      setError(null);\n      const response = await fetch(apiUrl);\n\n      if (!response.ok) {\n        throw new Error(`HTTP error! status: ${response.status}`);\n      }\n\n      const data: BetterstackApiResponse = await response.json();\n\n      // Find the service by name in the included array\n      const service = data.included.find(\n        (item) =>\n          item.type === 'status_page_resource' &&\n          item.attributes.public_name === serviceName\n      );\n\n      if (!service) {\n        throw new Error(`Service \"${serviceName}\" not found in API response`);\n      }\n\n      const newStatus = service.attributes.status;\n      const newAvailability = service.attributes.availability;\n\n      setStatus(newStatus);\n      setAvailability(newAvailability);\n      setLastUpdated(new Date());\n      setIsLoading(false);\n\n      // Trigger status change callback if status has changed\n      if (previousStatusRef.current !== newStatus && onStatusChange) {\n        onStatusChange(newStatus);\n      }\n      previousStatusRef.current = newStatus;\n    } catch (err) {\n      const errorMessage =\n        err instanceof Error ? err.message : 'Failed to fetch service status';\n      setError(errorMessage);\n      setIsLoading(false);\n      console.error('[useServiceStatus] Error:', errorMessage);\n    }\n  }, [apiUrl, serviceName, onStatusChange]);\n\n  // Initial fetch\n  useEffect(() => {\n    fetchStatus();\n  }, [fetchStatus]);\n\n  // Setup auto-refresh interval\n  useEffect(() => {\n    if (refreshInterval > 0) {\n      intervalRef.current = setInterval(() => {\n        fetchStatus();\n      }, refreshInterval * 1000);\n\n      return () => {\n        if (intervalRef.current) {\n          clearInterval(intervalRef.current);\n        }\n      };\n    }\n  }, [refreshInterval, fetchStatus]);\n\n  return {\n    status,\n    availability,\n    serviceName,\n    lastUpdated,\n    isLoading,\n    error,\n    refresh: fetchStatus,\n  };\n}\n","import type { ServiceStatus, StatusColor } from '../types';\n\n/**\n * Maps service status to color\n */\nexport function getStatusColor(status: ServiceStatus): StatusColor {\n  const colorMap: Record<ServiceStatus, StatusColor> = {\n    operational: 'green',\n    degraded: 'yellow',\n    downtime: 'red',\n    maintenance: 'gray',\n  };\n  return colorMap[status];\n}\n\n/**\n * Maps service status to hex color code\n */\nexport function getStatusColorHex(status: ServiceStatus): string {\n  const hexMap: Record<ServiceStatus, string> = {\n    operational: '#10b981', // green-500\n    degraded: '#f59e0b', // yellow-500\n    downtime: '#ef4444', // red-500\n    maintenance: '#6b7280', // gray-500\n  };\n  return hexMap[status];\n}\n\n/**\n * Maps service status to display text\n */\nexport function getStatusText(status: ServiceStatus): string {\n  const textMap: Record<ServiceStatus, string> = {\n    operational: 'Operational',\n    degraded: 'Degraded',\n    downtime: 'Down',\n    maintenance: 'Maintenance',\n  };\n  return textMap[status];\n}\n\n/**\n * Formats availability percentage\n */\nexport function formatAvailability(availability: number): string {\n  return `${(availability * 100).toFixed(2)}%`;\n}\n\n/**\n * Formats timestamp to readable string\n */\nexport function formatTimestamp(date: Date): string {\n  return new Intl.DateTimeFormat('en-US', {\n    month: 'short',\n    day: 'numeric',\n    year: 'numeric',\n    hour: '2-digit',\n    minute: '2-digit',\n    second: '2-digit',\n  }).format(date);\n}\n","import React from 'react';\nimport type { ServiceStatusData } from '../types';\nimport {\n  getStatusText,\n  formatAvailability,\n  formatTimestamp,\n  getStatusColorHex,\n} from '../utils/statusMapper';\n\nexport interface StatusPopoverProps {\n  statusData: ServiceStatusData;\n  onClose: () => void;\n}\n\nexport const StatusPopover: React.FC<StatusPopoverProps> = ({\n  statusData,\n  onClose,\n}) => {\n  const { status, availability, serviceName, lastUpdated, isLoading, error, refresh } =\n    statusData;\n\n  const handleRefresh = async (e: React.MouseEvent) => {\n    e.stopPropagation();\n    await refresh();\n  };\n\n  const handleBackdropClick = (e: React.MouseEvent) => {\n    if (e.target === e.currentTarget) {\n      onClose();\n    }\n  };\n\n  return (\n    <div className=\"zss-popover-backdrop\" onClick={handleBackdropClick}>\n      <div className=\"zss-popover\">\n        <div className=\"zss-popover-header\">\n          <h3 className=\"zss-popover-title\">Service Status</h3>\n          <button\n            className=\"zss-popover-close\"\n            onClick={onClose}\n            aria-label=\"Close\"\n          >\n            ×\n          </button>\n        </div>\n\n        <div className=\"zss-popover-content\">\n          {error ? (\n            <div className=\"zss-error\">\n              <div className=\"zss-error-icon\">⚠️</div>\n              <p className=\"zss-error-message\">{error}</p>\n              <button className=\"zss-refresh-button\" onClick={handleRefresh}>\n                Retry\n              </button>\n            </div>\n          ) : (\n            <>\n              <div className=\"zss-status-row\">\n                <span className=\"zss-label\">Service:</span>\n                <span className=\"zss-value\">{serviceName}</span>\n              </div>\n\n              <div className=\"zss-status-row\">\n                <span className=\"zss-label\">Status:</span>\n                <div className=\"zss-status-badge\">\n                  <span\n                    className=\"zss-status-indicator\"\n                    style={{ backgroundColor: getStatusColorHex(status) }}\n                  />\n                  <span className=\"zss-status-text\">{getStatusText(status)}</span>\n                </div>\n              </div>\n\n              <div className=\"zss-status-row\">\n                <span className=\"zss-label\">Uptime (30d):</span>\n                <span className=\"zss-value zss-availability\">\n                  {formatAvailability(availability)}\n                </span>\n              </div>\n\n              <div className=\"zss-status-row\">\n                <span className=\"zss-label\">Last Updated:</span>\n                <span className=\"zss-value zss-timestamp\">\n                  {formatTimestamp(lastUpdated)}\n                </span>\n              </div>\n\n              <button\n                className=\"zss-refresh-button\"\n                onClick={handleRefresh}\n                disabled={isLoading}\n              >\n                {isLoading ? 'Refreshing...' : 'Refresh Now'}\n              </button>\n            </>\n          )}\n        </div>\n      </div>\n    </div>\n  );\n};\n","import React, { useState } from 'react';\nimport type { ServiceStatusBadgeProps } from '../types';\nimport { useServiceStatus } from '../hooks/useServiceStatus';\nimport { StatusPopover } from './StatusPopover';\nimport { getStatusColorHex } from '../utils/statusMapper';\n\nconst DEFAULT_SERVICE_NAME = 'Relayer - Testnet';\nconst DEFAULT_API_URL = 'https://zama-relay-service-monitor-example.vercel.app/api/status';\nconst DEFAULT_REFRESH_INTERVAL = 60; // seconds\nconst DEFAULT_POSITION = 'bottom-right';\n\n/**\n * ServiceStatusBadge - Main component to display service status badge\n */\nexport const ServiceStatusBadge: React.FC<ServiceStatusBadgeProps> = ({\n  serviceName = DEFAULT_SERVICE_NAME,\n  apiUrl = DEFAULT_API_URL,\n  refreshInterval = DEFAULT_REFRESH_INTERVAL,\n  position = DEFAULT_POSITION,\n  className = '',\n  style = {},\n  onStatusChange,\n}) => {\n  const [isPopoverOpen, setIsPopoverOpen] = useState(false);\n\n  // Validate refresh interval\n  const validatedInterval = Math.max(30, Math.min(300, refreshInterval));\n\n  const statusData = useServiceStatus({\n    serviceName,\n    apiUrl,\n    refreshInterval: validatedInterval,\n    onStatusChange,\n  });\n\n  const { status, isLoading } = statusData;\n\n  const handleBadgeClick = () => {\n    setIsPopoverOpen(!isPopoverOpen);\n  };\n\n  const handleClosePopover = () => {\n    setIsPopoverOpen(false);\n  };\n\n  const positionClass = `zss-position-${position}`;\n  const statusColor = getStatusColorHex(status);\n\n  return (\n    <>\n      <div\n        className={`zss-badge ${positionClass} ${className}`}\n        onClick={handleBadgeClick}\n        style={style}\n        role=\"button\"\n        tabIndex={0}\n        aria-label={`Service status: ${status}`}\n        onKeyDown={(e) => {\n          if (e.key === 'Enter' || e.key === ' ') {\n            e.preventDefault();\n            handleBadgeClick();\n          }\n        }}\n      >\n        <div className=\"zss-badge-content\">\n          <span\n            className={`zss-indicator ${isLoading ? 'zss-pulse' : ''}`}\n            style={{ backgroundColor: statusColor }}\n            aria-hidden=\"true\"\n          />\n          <span className=\"zss-badge-text\">Zama Status</span>\n        </div>\n      </div>\n\n      {isPopoverOpen && (\n        <StatusPopover statusData={statusData} onClose={handleClosePopover} />\n      )}\n    </>\n  );\n};\n\n// Default export\nexport default ServiceStatusBadge;\n"],"names":["useServiceStatus","serviceName","apiUrl","refreshInterval","onStatusChange","status","setStatus","useState","availability","setAvailability","lastUpdated","setLastUpdated","Date","isLoading","setIsLoading","error","setError","previousStatusRef","useRef","intervalRef","fetchStatus","useCallback","async","response","fetch","ok","Error","service","json","included","find","item","type","attributes","public_name","newStatus","newAvailability","current","err","errorMessage","message","console","useEffect","setInterval","clearInterval","refresh","getStatusColorHex","operational","degraded","downtime","maintenance","getStatusText","formatAvailability","toFixed","formatTimestamp","date","Intl","DateTimeFormat","month","day","year","hour","minute","second","format","StatusPopover","statusData","onClose","handleRefresh","e","stopPropagation","jsx","className","onClick","target","currentTarget","children","jsxs","Fragment","style","backgroundColor","disabled","ServiceStatusBadge","position","isPopoverOpen","setIsPopoverOpen","Math","max","min","handleBadgeClick","positionClass","statusColor","role","tabIndex","onKeyDown","key","preventDefault"],"mappings":"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"}