{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "use-axios",
  "title": "UseAxios",
  "description": "A customizable hook for making HTTP requests with Axios",
  "files": [
    {
      "path": "registry/hooks/use-axios.tsx",
      "content": "'use client';\n\nimport {\n  createContext,\n  useCallback,\n  useContext,\n  useEffect,\n  useRef,\n  useState,\n  type ReactNode,\n} from 'react';\n\nimport axios, {\n  AxiosError,\n  AxiosInstance,\n  AxiosRequestConfig,\n  AxiosResponse,\n} from 'axios';\n\n// #region Types & Interfaces\n\nexport interface AxiosConfig extends AxiosRequestConfig {\n  retries?: number;\n  retryDelay?: number;\n}\n\nexport interface AxiosOptions extends AxiosRequestConfig {\n  retries?: number;\n  retryDelay?: number;\n  immediate?: boolean;\n}\n\nexport interface AxiosResult<T> {\n  data: T | null;\n  error: AxiosError | null;\n  loading: boolean;\n  refetch: () => Promise<T | null>;\n  abort: () => void;\n  aborted: boolean;\n}\n\nexport interface AxiosContextValue {\n  config: AxiosConfig;\n  updateConfig: (newConfig: Partial<AxiosConfig>) => void;\n  instance: AxiosInstance;\n  request: <T = any>(config: AxiosRequestConfig) => Promise<AxiosResponse<T>>;\n}\n\nexport interface AxiosProviderProps {\n  config?: AxiosConfig;\n  children: ReactNode;\n}\n\n// #endregion\n\nconst AxiosContext = createContext<AxiosContextValue | null>(null);\n\nexport function AxiosProvider({ config = {}, children }: AxiosProviderProps) {\n  const [currentConfig, setCurrentConfig] = useState<AxiosConfig>(config);\n  const instanceRef = useRef<AxiosInstance | null>(axios.create(config));\n\n  const updateConfig = useCallback((newConfig: Partial<AxiosConfig>) => {\n    setCurrentConfig((prev) => ({ ...prev, ...newConfig }));\n  }, []);\n\n  // Create or update axios instance when config changes\n  useEffect(() => {\n    const { retries, retryDelay, ...axiosConfig } = currentConfig;\n\n    instanceRef.current = axios.create(axiosConfig);\n\n    // Add request interceptor for retry logic\n    instanceRef.current.interceptors.request.use(\n      (config) => config,\n      (error) => Promise.reject(error),\n    );\n\n    // Add response interceptor for error handling\n    instanceRef.current.interceptors.response.use(\n      (response) => response,\n      (error) => Promise.reject(error),\n    );\n\n    return () => {\n      instanceRef.current = null;\n    };\n  }, [currentConfig]);\n\n  const enhancedRequest = useCallback(\n    async <T = any,>(\n      requestConfig: AxiosRequestConfig,\n    ): Promise<AxiosResponse<T>> => {\n      const {\n        retries = currentConfig.retries ?? 0,\n        retryDelay = currentConfig.retryDelay ?? 1000,\n        ...axiosConfig\n      } = requestConfig as AxiosRequestConfig & {\n        retries?: number;\n        retryDelay?: number;\n      };\n\n      if (!instanceRef.current) {\n        throw new Error('Axios instance not initialized');\n      }\n\n      let lastError: AxiosError | null = null;\n\n      for (let attempt = 0; attempt <= retries; attempt++) {\n        try {\n          const response = await instanceRef.current.request<T>(axiosConfig);\n          return response;\n        } catch (error) {\n          lastError = error as AxiosError;\n\n          // Don't retry on abort or client errors (4xx)\n          if (\n            axios.isCancel(error) ||\n            ((error as AxiosError).response?.status &&\n              (error as AxiosError).response!.status >= 400 &&\n              (error as AxiosError).response!.status < 500)\n          ) {\n            throw error;\n          }\n\n          // If this is the last attempt, throw the error\n          if (attempt === retries) {\n            throw error;\n          }\n\n          // Wait before retry\n          await new Promise((resolve) => setTimeout(resolve, retryDelay));\n        }\n      }\n\n      throw lastError || new Error('Unknown axios error');\n    },\n    [currentConfig],\n  );\n\n  const contextValue: AxiosContextValue = {\n    config: currentConfig,\n    updateConfig,\n    instance: instanceRef.current!,\n    request: enhancedRequest,\n  };\n\n  return (\n    <AxiosContext.Provider value={contextValue}>\n      {children}\n    </AxiosContext.Provider>\n  );\n}\n\nexport function useAxiosContext(): AxiosContextValue {\n  const context = useContext(AxiosContext);\n  if (!context) {\n    throw new Error('useAxios must be used within an AxiosProvider');\n  }\n  return context;\n}\n\n// Main hook for single requests\nexport function useAxios<T = any>(\n  config: AxiosRequestConfig & { immediate?: boolean } = {},\n): AxiosResult<T> {\n  const { immediate = true, ...requestConfig } = config;\n  const { request: contextRequest } = useAxiosContext();\n\n  const [data, setData] = useState<T | null>(null);\n  const [error, setError] = useState<AxiosError | null>(null);\n  const [loading, setLoading] = useState<boolean>(false);\n  const [aborted, setAborted] = useState<boolean>(false);\n\n  const abortController = useRef<AbortController | null>(null);\n  const isMounted = useRef(true);\n\n  useEffect(() => {\n    return () => {\n      isMounted.current = false;\n      abortController.current?.abort();\n    };\n  }, []);\n\n  const executeRequest = useCallback(async (): Promise<T | null> => {\n    // Abort previous request\n    abortController.current?.abort();\n    const controller = new AbortController();\n    abortController.current = controller;\n\n    if (!isMounted.current) return null;\n\n    setLoading(true);\n    setError(null);\n    setAborted(false);\n\n    try {\n      const response = await contextRequest<T>({\n        ...requestConfig,\n        signal: controller.signal,\n      });\n\n      if (!isMounted.current) return null;\n\n      if (isMounted.current) {\n        setData(response.data);\n      }\n\n      return response.data;\n    } catch (err) {\n      if (!isMounted.current) return null;\n\n      if (axios.isCancel(err)) {\n        setAborted(true);\n      } else {\n        setError(err as AxiosError);\n        setData(null);\n      }\n      return null;\n    } finally {\n      if (isMounted.current) {\n        setLoading(false);\n      }\n    }\n  }, [contextRequest, JSON.stringify(requestConfig)]);\n\n  useEffect(() => {\n    if (!immediate) return;\n    executeRequest();\n  }, [executeRequest, immediate]);\n\n  const abort = useCallback(() => {\n    abortController.current?.abort();\n    if (isMounted.current) {\n      setAborted(true);\n      setLoading(false);\n    }\n  }, []);\n\n  return {\n    data,\n    error,\n    loading,\n    refetch: executeRequest,\n    abort,\n    aborted,\n  };\n}\n\n// Convenience hooks for HTTP methods\nexport function useAxiosGet<T = any>(\n  url: string,\n  config: AxiosOptions = {},\n): AxiosResult<T> {\n  return useAxios<T>({ ...config, method: 'GET', url });\n}\n\nexport function useAxiosPost<T = any>(\n  url: string,\n  data?: any,\n  config: AxiosOptions = {},\n): AxiosResult<T> {\n  return useAxios<T>({ ...config, method: 'POST', url, data });\n}\n\nexport function useAxiosPut<T = any>(\n  url: string,\n  data?: any,\n  config: AxiosOptions = {},\n): AxiosResult<T> {\n  return useAxios<T>({ ...config, method: 'PUT', url, data });\n}\n\nexport function useAxiosDelete<T = any>(\n  url: string,\n  config: AxiosOptions = {},\n): AxiosResult<T> {\n  return useAxios<T>({ ...config, method: 'DELETE', url });\n}\n\nexport function useAxiosPatch<T = any>(\n  url: string,\n  data?: any,\n  config: AxiosOptions = {},\n): AxiosResult<T> {\n  return useAxios<T>({ ...config, method: 'PATCH', url, data });\n}\n\n// Hook for multiple requests without state management\nexport function useAxiosInstance() {\n  const { instance, request } = useAxiosContext();\n\n  const get = useCallback(\n    <T = any,>(url: string, config?: AxiosRequestConfig) =>\n      request<T>({ ...config, method: 'GET', url }),\n    [request],\n  );\n\n  const post = useCallback(\n    <T = any,>(url: string, data?: any, config?: AxiosRequestConfig) =>\n      request<T>({ ...config, method: 'POST', url, data }),\n    [request],\n  );\n\n  const put = useCallback(\n    <T = any,>(url: string, data?: any, config?: AxiosRequestConfig) =>\n      request<T>({ ...config, method: 'PUT', url, data }),\n    [request],\n  );\n\n  const del = useCallback(\n    <T = any,>(url: string, config?: AxiosRequestConfig) =>\n      request<T>({ ...config, method: 'DELETE', url }),\n    [request],\n  );\n\n  const patch = useCallback(\n    <T = any,>(url: string, data?: any, config?: AxiosRequestConfig) =>\n      request<T>({ ...config, method: 'PATCH', url, data }),\n    [request],\n  );\n\n  return {\n    instance,\n    request,\n    get,\n    post,\n    put,\n    delete: del,\n    patch,\n  };\n}\n",
      "type": "registry:hook",
      "target": "hooks/guarahooks/use-axios.tsx"
    }
  ],
  "categories": [
    "data-fetching"
  ],
  "type": "registry:hook"
}