{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "client",
  "title": "CodeRabbit API Client",
  "author": "Ray <hello@ramonclaudio.com>",
  "description": "Framework-agnostic CodeRabbit API client. Works in Node.js, Deno, Bun, Edge runtimes, and browsers. Single endpoint for generating developer activity reports with 10-minute timeout support.",
  "registryDependencies": [
    "https://coderabbit-shadcn-registry.vercel.app/r/types.json"
  ],
  "files": [
    {
      "path": "registry/default/lib/client.ts",
      "content": "/**\n * CodeRabbit API Client\n * Framework-agnostic client that works in Node.js, Deno, Bun, Edge runtimes, and browsers\n */\n\nimport type {\n  ReportGenerateRequest,\n  ReportResult,\n} from '@/registry/default/lib/types'\n\nconst API_BASE_URL = 'https://api.coderabbit.ai/api'\nconst API_VERSION = 'v1'\nconst API_TIMEOUT_MS = 600_000 // 10 minutes\n\n/**\n * CodeRabbit client configuration\n */\nexport interface CodeRabbitClientConfig {\n  apiKey?: string\n  baseUrl?: string\n  timeout?: number\n}\n\n/**\n * User-friendly error messages for known API error codes\n * Codes from: https://docs.coderabbit.ai\n */\nconst ERROR_MESSAGES: Record<string, string> = {\n  UNAUTHORIZED:\n    'Invalid or missing API key. Get your key from https://app.coderabbit.ai/settings/api-keys',\n  FORBIDDEN:\n    'API access requires a Pro plan subscription. Upgrade at https://coderabbit.ai',\n  RATE_LIMITED:\n    'Rate limit exceeded. Please wait a few minutes before trying again.',\n  INVALID_PARAMETER:\n    'Invalid request parameters. Please check your report configuration.',\n}\n\n/**\n * HTTP status to API error code mapping\n */\nconst STATUS_CODE_MAP: Record<number, string> = {\n  400: 'INVALID_PARAMETER',\n  401: 'UNAUTHORIZED',\n  403: 'FORBIDDEN',\n  429: 'RATE_LIMITED',\n}\n\n/**\n * Parse error response from the CodeRabbit API\n *\n * The API returns errors in multiple formats:\n * - OpenAPI documented: { errors: [{ code, message }] }\n * - Flat: { message, code }\n * - tRPC: { error: { message, code, data: { code } } }\n */\nfunction parseErrorResponse(\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  data: any,\n  status: number,\n): string {\n  // Format: { errors: [{ code, message }] } (OpenAPI spec)\n  if (Array.isArray(data?.errors) && data.errors.length > 0) {\n    const first = data.errors[0]\n    if (first.code && ERROR_MESSAGES[first.code]) {\n      return ERROR_MESSAGES[first.code]\n    }\n    return data.errors.map((e: { message: string }) => e.message).join(', ')\n  }\n\n  // Format: { error: { message, code, data } } (tRPC)\n  if (data?.error) {\n    const errorCode = data.error.data?.code\n    if (errorCode && ERROR_MESSAGES[errorCode]) {\n      return ERROR_MESSAGES[errorCode]\n    }\n    if (data.error.message) return data.error.message\n  }\n\n  // Format: { message, code } (flat)\n  if (data?.code && ERROR_MESSAGES[data.code]) {\n    return ERROR_MESSAGES[data.code]\n  }\n  if (data?.message) return data.message\n\n  // Fall back to HTTP status mapping\n  const mappedCode = STATUS_CODE_MAP[status]\n  if (mappedCode && ERROR_MESSAGES[mappedCode]) {\n    return ERROR_MESSAGES[mappedCode]\n  }\n\n  return `API request failed with status ${status}`\n}\n\n/**\n * CodeRabbit API client\n */\nexport class CodeRabbitClient {\n  private apiKey: string | null\n  private baseUrl: string\n  private timeout: number\n\n  constructor(config?: CodeRabbitClientConfig) {\n    this.apiKey = config?.apiKey ?? this.getApiKeyFromEnv()\n    this.baseUrl = config?.baseUrl ?? API_BASE_URL\n    this.timeout = config?.timeout ?? API_TIMEOUT_MS\n  }\n\n  /**\n   * Get API key from environment (works across runtimes)\n   */\n  private getApiKeyFromEnv(): string | null {\n    if (typeof process !== 'undefined' && process.env) {\n      return process.env.CODERABBIT_API_KEY ?? null\n    }\n    return null\n  }\n\n  /**\n   * Check if CodeRabbit is configured\n   */\n  isConfigured(): boolean {\n    return this.apiKey !== null && this.apiKey.length > 0\n  }\n\n  /**\n   * Generate developer activity report\n   *\n   * This endpoint may take up to 10 minutes to respond depending on data volume.\n   *\n   * @param request Report generation parameters\n   * @returns Array of report groups with markdown content\n   * @throws Error if API key not configured or request fails\n   */\n  async generateReport(\n    request: ReportGenerateRequest,\n  ): Promise<ReportResult[]> {\n    if (!this.isConfigured()) {\n      throw new Error(\n        'CODERABBIT_API_KEY not configured. Set environment variable or pass apiKey in config.',\n      )\n    }\n\n    const controller = new AbortController()\n    const timeoutId = setTimeout(() => controller.abort(), this.timeout)\n\n    try {\n      const requestBody = {\n        from: request.from,\n        to: request.to,\n        scheduleRange: request.scheduleRange ?? 'Dates',\n        parameters: request.parameters ?? [],\n        ...(request.prompt && { prompt: request.prompt }),\n        ...(request.promptTemplate && { promptTemplate: request.promptTemplate }),\n        ...(request.groupBy && { groupBy: request.groupBy }),\n        ...(request.subgroupBy && { subgroupBy: request.subgroupBy }),\n        ...(request.orgId && { orgId: request.orgId }),\n      }\n\n      const response = await fetch(\n        `${this.baseUrl}/${API_VERSION}/report.generate`,\n        {\n          method: 'POST',\n          headers: {\n            'Content-Type': 'application/json',\n            'x-coderabbitai-api-key': this.apiKey!,\n          },\n          body: JSON.stringify(requestBody),\n          signal: controller.signal,\n        },\n      )\n\n      clearTimeout(timeoutId)\n\n      if (!response.ok) {\n        const errorData = await response.json().catch(() => null)\n        throw new Error(parseErrorResponse(errorData, response.status))\n      }\n\n      const responseData = await response.json()\n\n      // Handle both direct array (OpenAPI spec) and tRPC-wrapped response\n      if (Array.isArray(responseData)) {\n        return responseData as ReportResult[]\n      }\n\n      // tRPC wrapper: { result: { data: [] } }\n      if (responseData?.result?.data) {\n        return responseData.result.data as ReportResult[]\n      }\n\n      throw new Error('Unexpected response format from CodeRabbit API')\n    } catch (error) {\n      clearTimeout(timeoutId)\n\n      if (error instanceof Error && error.name === 'AbortError') {\n        throw new Error(\n          `CodeRabbit report generation timed out after ${this.timeout / 1000}s`,\n        )\n      }\n\n      throw error\n    }\n  }\n}\n\n/**\n * Create a new CodeRabbit client instance\n *\n * @example\n * ```ts\n * const client = createCodeRabbitClient({ apiKey: 'your-key' })\n * const results = await client.generateReport({\n *   from: '2024-01-01',\n *   to: '2024-01-31',\n *   promptTemplate: 'Sprint Report'\n * })\n * ```\n */\nexport function createCodeRabbitClient(\n  config?: CodeRabbitClientConfig,\n): CodeRabbitClient {\n  return new CodeRabbitClient(config)\n}\n",
      "type": "registry:lib"
    }
  ],
  "envVars": {
    "CODERABBIT_API_KEY": ""
  },
  "docs": "Set CODERABBIT_API_KEY environment variable or pass apiKey in config. Get API key from https://app.coderabbit.ai/settings/api-keys (requires Pro plan subscription).",
  "categories": [
    "api-client",
    "developer-tools"
  ],
  "type": "registry:lib"
}