{"version":3,"file":"withErrorBoundary.mjs","sources":["../../../src/lib/monitoring/withErrorBoundary.tsx"],"sourcesContent":["/* @refresh reset */\n/**\n * @file With Error Boundary HOC\n * @description HOC to wrap any component with local try/catch UI\n */\n\nimport React, {\n  Component,\n  useRef,\n  type ErrorInfo,\n  type ReactNode,\n  type ComponentType,\n} from 'react';\nimport { ErrorReporter } from './ErrorReporter';\nimport type { AppError } from './errorTypes';\nimport { normalizeError, getUserFriendlyMessage } from './errorTypes';\n\n/**\n * Error boundary options\n */\nexport interface WithErrorBoundaryOptions {\n  fallback?: ReactNode | ((error: AppError, reset: () => void) => ReactNode);\n  onError?: (error: AppError, errorInfo: ErrorInfo) => void;\n  componentName?: string;\n  showReset?: boolean;\n}\n\n/**\n * Error boundary state\n */\ninterface ErrorBoundaryState {\n  hasError: boolean;\n  error: AppError | null;\n}\n\n/**\n * Minimal inline error fallback\n */\nfunction InlineErrorFallback({\n  error,\n  onReset,\n  showReset,\n}: {\n  error: AppError;\n  onReset: () => void;\n  showReset?: boolean;\n}): React.ReactElement {\n  return (\n    <div\n      role=\"alert\"\n      style={{\n        padding: '1rem',\n        backgroundColor: '#fef2f2',\n        border: '1px solid #fecaca',\n        borderRadius: '0.375rem',\n      }}\n    >\n      <div\n        style={{\n          display: 'flex',\n          alignItems: 'center',\n          gap: '0.5rem',\n          color: '#dc2626',\n          fontSize: '0.875rem',\n        }}\n      >\n        <svg\n          style={{ width: '1rem', height: '1rem', flexShrink: 0 }}\n          fill=\"currentColor\"\n          viewBox=\"0 0 20 20\"\n        >\n          <path\n            fillRule=\"evenodd\"\n            d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\"\n            clipRule=\"evenodd\"\n          />\n        </svg>\n        <span>{getUserFriendlyMessage(error)}</span>\n        {showReset && (\n          <button\n            onClick={onReset}\n            style={{\n              marginLeft: 'auto',\n              padding: '0.25rem 0.5rem',\n              fontSize: '0.75rem',\n              color: '#dc2626',\n              backgroundColor: 'transparent',\n              border: '1px solid #fecaca',\n              borderRadius: '0.25rem',\n              cursor: 'pointer',\n            }}\n          >\n            Retry\n          </button>\n        )}\n      </div>\n    </div>\n  );\n}\n\n/**\n * Create an error boundary class for a specific component\n */\nfunction createErrorBoundary(\n  options: WithErrorBoundaryOptions\n): ComponentType<{ children: ReactNode }> {\n  return class extends Component<{ children: ReactNode }, ErrorBoundaryState> {\n    constructor(props: { children: ReactNode }) {\n      super(props);\n      this.state = { hasError: false, error: null };\n    }\n\n    static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n      return { hasError: true, error: normalizeError(error) };\n    }\n\n    override componentDidCatch(error: Error, errorInfo: ErrorInfo): void {\n      const appError = normalizeError(error);\n\n      ErrorReporter.reportError(error, {\n        component: options.componentName,\n        metadata: {\n          componentStack: errorInfo.componentStack,\n        },\n      });\n\n      options.onError?.(appError, errorInfo);\n    }\n\n    handleReset = (): void => {\n      this.setState({ hasError: false, error: null });\n    };\n\n    override render(): ReactNode {\n      const { hasError, error } = this.state;\n      const { children } = this.props;\n\n      if (hasError && error) {\n        if (typeof options.fallback === 'function') {\n          return options.fallback(error, this.handleReset);\n        }\n\n        if (options.fallback != null) {\n          return options.fallback;\n        }\n\n        return (\n          <InlineErrorFallback\n            error={error}\n            onReset={this.handleReset}\n            showReset={options.showReset !== false}\n          />\n        );\n      }\n\n      return children;\n    }\n  };\n}\n\n/**\n * Higher-order component to wrap any component with error boundary\n */\n// eslint-disable-next-line react-refresh/only-export-components -- HOC export is valid\nexport function withErrorBoundary<P extends object>(\n  WrappedComponent: ComponentType<P>,\n  options: WithErrorBoundaryOptions = {}\n): ComponentType<P> {\n  const componentName =\n    options.componentName ?? WrappedComponent.displayName ?? WrappedComponent.name ?? 'Component';\n\n  const ErrorBoundary = createErrorBoundary({\n    ...options,\n    componentName,\n  });\n\n  const WithErrorBoundary: React.FC<P> = (props: P) => (\n    <ErrorBoundary>\n      <WrappedComponent {...props} />\n    </ErrorBoundary>\n  );\n\n  WithErrorBoundary.displayName = `withErrorBoundary(${componentName})`;\n\n  return WithErrorBoundary;\n}\n\n// Pre-created error boundary components\nconst boundaryCache = new Map<string, ComponentType<{ children: ReactNode }>>();\n\nfunction getCachedBoundary(\n  options: WithErrorBoundaryOptions\n): ComponentType<{ children: ReactNode }> {\n  const cacheKey = JSON.stringify(options);\n  let boundary = boundaryCache.get(cacheKey);\n  if (!boundary) {\n    boundary = createErrorBoundary(options);\n    boundaryCache.set(cacheKey, boundary);\n  }\n  return boundary;\n}\n\n/**\n * Component version for declarative usage\n */\nexport function ErrorBoundary({\n  children,\n  fallback,\n  onError,\n  showReset = true,\n}: {\n  children: ReactNode;\n  fallback?: ReactNode | ((error: AppError, reset: () => void) => ReactNode);\n  onError?: (error: AppError, errorInfo: ErrorInfo) => void;\n  showReset?: boolean;\n}): React.JSX.Element {\n  const boundaryRef = useRef<ComponentType<{ children: ReactNode }> | null>(null);\n\n  // Initialize boundary component once\n  boundaryRef.current ??= getCachedBoundary({ fallback, onError, showReset });\n\n  const BoundaryComponent = boundaryRef.current;\n\n  return <BoundaryComponent>{children}</BoundaryComponent>;\n}\n"],"names":["InlineErrorFallback","error","onReset","showReset","jsx","jsxs","getUserFriendlyMessage","createErrorBoundary","options","Component","props","normalizeError","errorInfo","appError","ErrorReporter","hasError","children","withErrorBoundary","WrappedComponent","componentName","ErrorBoundary","WithErrorBoundary","boundaryCache","getCachedBoundary","cacheKey","boundary","fallback","onError","boundaryRef","useRef","BoundaryComponent"],"mappings":"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"}