{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "use-ky",
  "title": "UseKy",
  "description": "A customizable hook for making HTTP requests using Ky",
  "files": [
    {
      "path": "registry/hooks/use-ky.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 ky, {\n  HTTPError,\n  KyInstance,\n  KyResponse,\n  Options,\n  TimeoutError,\n} from 'ky';\n\n// #region Types & Interfaces\n\nexport interface KyPlugin {\n  beforeRequest?: (url: string, options: Options) => void | Promise<void>;\n  afterResponse?: (response: KyResponse) => void | Promise<void>;\n  onError?: (error: HTTPError | TimeoutError | Error) => void | Promise<void>;\n}\n\nexport interface KyConfig extends Options {\n  retries?: number;\n  timeout?: number;\n}\n\nexport interface KyOptions extends Options {\n  retries?: number;\n  timeout?: number;\n  immediate?: boolean;\n  plugins?: KyPlugin[];\n}\n\nexport interface KyResult<T> {\n  data: T | null;\n  error: HTTPError | TimeoutError | Error | null;\n  loading: boolean;\n  refetch: () => Promise<T | null>;\n  abort: () => void;\n  aborted: boolean;\n}\n\nexport interface KyContextValue {\n  config: KyConfig;\n  updateConfig: (newConfig: Partial<KyConfig>) => void;\n  instance: KyInstance;\n  request: (url: string, options?: Options) => Promise<KyResponse>;\n}\n\nexport interface KyProviderProps {\n  config?: KyConfig;\n  children: ReactNode;\n}\n\n// #endregion\n\n// #region Context\n\nconst KyContext = createContext<KyContextValue | null>(null);\n\nexport function KyProvider({ config = {}, children }: KyProviderProps) {\n  const [currentConfig, setCurrentConfig] = useState<KyConfig>(config);\n  const instanceRef = useRef<KyInstance | null>(ky.create(config));\n\n  const updateConfig = useCallback((newConfig: Partial<KyConfig>) => {\n    setCurrentConfig((prev) => ({ ...prev, ...newConfig }));\n  }, []);\n\n  // Create or update ky instance when config changes\n  useEffect(() => {\n    instanceRef.current = ky.create(currentConfig);\n  }, [currentConfig]);\n\n  const enhancedRequest = useCallback(\n    async (url: string, options: Options = {}): Promise<KyResponse> => {\n      if (!instanceRef.current) {\n        throw new Error('Ky instance not initialized');\n      }\n\n      return instanceRef.current(url, options);\n    },\n    [],\n  );\n\n  const contextValue: KyContextValue = {\n    config: currentConfig,\n    updateConfig,\n    instance: instanceRef.current!,\n    request: enhancedRequest,\n  };\n\n  return (\n    <KyContext.Provider value={contextValue}>{children}</KyContext.Provider>\n  );\n}\n\nexport function useKyContext(): KyContextValue {\n  const context = useContext(KyContext);\n  if (!context) {\n    throw new Error('useKy must be used within a KyProvider');\n  }\n  return context;\n}\n\n// #endregion\n\n// Main hook for single requests\nexport function useKy<T = any>(\n  url: string,\n  options: KyOptions = {},\n): KyResult<T> {\n  const {\n    immediate = true,\n    retries,\n    timeout,\n    plugins = [],\n    ...requestOptions\n  } = options;\n  const { request: contextRequest } = useKyContext();\n\n  const [data, setData] = useState<T | null>(null);\n  const [error, setError] = useState<HTTPError | TimeoutError | Error | null>(\n    null,\n  );\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    const finalOptions = {\n      ...requestOptions,\n      retry: retries,\n      timeout,\n      signal: controller.signal,\n    };\n\n    // Run beforeRequest plugins\n    for (const plugin of plugins) {\n      if (plugin.beforeRequest) await plugin.beforeRequest(url, finalOptions);\n    }\n\n    try {\n      const response = await contextRequest(url, finalOptions);\n\n      if (!isMounted.current) return null;\n\n      // Run afterResponse plugins\n      for (const plugin of plugins) {\n        if (plugin.afterResponse) await plugin.afterResponse(response);\n      }\n\n      const result = await response.json<T>();\n\n      if (isMounted.current) {\n        setData(result);\n      }\n\n      return result;\n    } catch (err) {\n      if (!isMounted.current) return null;\n\n      const error = err as HTTPError | TimeoutError | Error;\n\n      // Run onError plugins\n      for (const plugin of plugins) {\n        if (plugin.onError) await plugin.onError(error);\n      }\n\n      if (err instanceof DOMException && err.name === 'AbortError') {\n        setAborted(true);\n      } else {\n        setError(error);\n        setData(null);\n      }\n      return null;\n    } finally {\n      if (isMounted.current) {\n        setLoading(false);\n      }\n    }\n  }, [url, JSON.stringify(requestOptions), retries, timeout, contextRequest]);\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// #region Convenience hooks for HTTP methods\n\nexport function useKyGet<T = any>(\n  url: string,\n  options: KyOptions = {},\n): KyResult<T> {\n  return useKy<T>(url, { ...options, method: 'GET' });\n}\n\nexport function useKyPost<T = any>(\n  url: string,\n  data?: any,\n  options: KyOptions = {},\n): KyResult<T> {\n  return useKy<T>(url, { ...options, method: 'POST', json: data });\n}\n\nexport function useKyPut<T = any>(\n  url: string,\n  data?: any,\n  options: KyOptions = {},\n): KyResult<T> {\n  return useKy<T>(url, { ...options, method: 'PUT', json: data });\n}\n\nexport function useKyDelete<T = any>(\n  url: string,\n  options: KyOptions = {},\n): KyResult<T> {\n  return useKy<T>(url, { ...options, method: 'DELETE' });\n}\n\nexport function useKyPatch<T = any>(\n  url: string,\n  data?: any,\n  options: KyOptions = {},\n): KyResult<T> {\n  return useKy<T>(url, { ...options, method: 'PATCH', json: data });\n}\n\n// #endregion\n\n// Hook for multiple requests without state management\nexport function useKyInstance() {\n  const { instance, request } = useKyContext();\n\n  const get = useCallback(\n    <T = any,>(url: string, options?: Options) =>\n      request(url, { ...options, method: 'GET' }).then((res) => res.json<T>()),\n    [request],\n  );\n\n  const post = useCallback(\n    <T = any,>(url: string, data?: any, options?: Options) =>\n      request(url, { ...options, method: 'POST', json: data }).then((res) =>\n        res.json<T>(),\n      ),\n    [request],\n  );\n\n  const put = useCallback(\n    <T = any,>(url: string, data?: any, options?: Options) =>\n      request(url, { ...options, method: 'PUT', json: data }).then((res) =>\n        res.json<T>(),\n      ),\n    [request],\n  );\n\n  const del = useCallback(\n    <T = any,>(url: string, options?: Options) =>\n      request(url, { ...options, method: 'DELETE' }).then((res) =>\n        res.json<T>(),\n      ),\n    [request],\n  );\n\n  const patch = useCallback(\n    <T = any,>(url: string, data?: any, options?: Options) =>\n      request(url, { ...options, method: 'PATCH', json: data }).then((res) =>\n        res.json<T>(),\n      ),\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-ky.tsx"
    }
  ],
  "categories": [
    "data-fetching"
  ],
  "type": "registry:hook"
}