{"version":3,"sources":["../src/lib/error-adapter.ts","../src/lib/http-client.ts","../src/lib/stream-handler.ts","../src/lib/client.ts"],"names":["OpenRouterErrorAdapter","error","status","data","code","message","metadata","baseMessage","HttpClient","baseURL","headers","axios","url","config","StreamHandler","stream","eventEmitter","EventEmitter","buffer","chunk","lines","line","parsed","choice","content","role","tool_calls","OpenRouterClient","apiKey","defaultConfig","httpClient","streamHandler","options","response","generationId"],"mappings":"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","file":"index.mjs","sourcesContent":["import { AxiosError } from \"axios\";\n\nexport interface ErrorResponse {\n  error: {\n    code: number;\n    message: string;\n    metadata?: ModerationErrorMetadata | ProviderErrorMetadata;\n  };\n}\n\ninterface ModerationErrorMetadata {\n  reasons: string[];\n  flagged_input: string;\n  provider_name: string;\n  model_slug: string;\n}\n\ninterface ProviderErrorMetadata {\n  provider_name: string;\n  raw: unknown;\n}\n\nexport class OpenRouterErrorAdapter {\n  private static readonly ERROR_MESSAGES = {\n    400: \"Bad Request: Invalid or missing parameters, or CORS issue\",\n    401: \"Invalid credentials: OAuth session expired or disabled/invalid API key\",\n    402: \"Insufficient credits: Add more credits and retry the request\",\n    403: \"Content moderation: Your input was flagged\",\n    408: \"Request timeout: Your request took too long to process\",\n    429: \"Rate limited: You are sending too many requests\",\n    502: \"Provider error: Model is down or invalid response received\",\n    503: \"No provider: No available model provider meets your routing requirements\",\n  } as const;\n\n  static handleError(error: unknown): never {\n    if (this.isAxiosError(error)) {\n      throw this.handleAxiosError(error);\n    }\n\n    throw new Error(\n      `Unexpected error: ${error instanceof Error ? error.message : String(error)}`,\n    );\n  }\n\n  private static isAxiosError(\n    error: unknown,\n  ): error is AxiosError<ErrorResponse> {\n    return error instanceof Error && \"isAxiosError\" in error;\n  }\n\n  private static handleAxiosError(error: AxiosError<ErrorResponse>): Error {\n    if (error.response) {\n      const { status, data } = error.response;\n\n      if (this.isOpenRouterError(data)) {\n        return this.createDetailedError(data.error);\n      }\n\n      return new Error(\n        `HTTP ${status}: ${this.ERROR_MESSAGES[status as keyof typeof this.ERROR_MESSAGES] || \"Unknown error\"}`,\n      );\n    }\n\n    if (error.request) {\n      return new Error(\"No response received from OpenRouter API\");\n    }\n\n    return new Error(`Failed to make request: ${error.message}`);\n  }\n\n  private static isOpenRouterError(data: unknown): data is ErrorResponse {\n    return (\n      typeof data === \"object\" &&\n      data !== null &&\n      \"error\" in data &&\n      typeof (data as ErrorResponse).error.code === \"number\" &&\n      typeof (data as ErrorResponse).error.message === \"string\"\n    );\n  }\n\n  private static createDetailedError({\n    code,\n    message,\n    metadata,\n  }: ErrorResponse[\"error\"]): Error {\n    const baseMessage = `${this.ERROR_MESSAGES[code as keyof typeof this.ERROR_MESSAGES] || \"Unknown error\"}: ${message}`;\n\n    if (!metadata) {\n      return new Error(baseMessage);\n    }\n\n    if (this.isModerationError(metadata)) {\n      return new Error(\n        `${baseMessage}\\nFlagged by ${metadata.provider_name} for: ${metadata.reasons.join(\", \")}\\n` +\n          `Flagged content: \"${metadata.flagged_input}\"`,\n      );\n    }\n\n    if (this.isProviderError(metadata)) {\n      return new Error(\n        `${baseMessage}\\nProvider ${metadata.provider_name} error: ${JSON.stringify(metadata.raw)}`,\n      );\n    }\n\n    return new Error(baseMessage);\n  }\n\n  private static isModerationError(\n    metadata: unknown,\n  ): metadata is ModerationErrorMetadata {\n    return (\n      typeof metadata === \"object\" &&\n      metadata !== null &&\n      \"reasons\" in metadata &&\n      \"flagged_input\" in metadata &&\n      \"provider_name\" in metadata &&\n      \"model_slug\" in metadata\n    );\n  }\n\n  private static isProviderError(\n    metadata: unknown,\n  ): metadata is ProviderErrorMetadata {\n    return (\n      typeof metadata === \"object\" &&\n      metadata !== null &&\n      \"provider_name\" in metadata &&\n      \"raw\" in metadata\n    );\n  }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport axios, { AxiosInstance } from \"axios\";\nimport { IHttpClient } from \"../types\";\n\nexport class HttpClient implements IHttpClient {\n  private client: AxiosInstance;\n\n  constructor(baseURL: string, headers: Record<string, string>) {\n    this.client = axios.create({\n      baseURL,\n      headers,\n    });\n  }\n\n  async post(url: string, data: any, config?: any) {\n    return this.client.post(url, data, config);\n  }\n\n  async get(url: string) {\n    return this.client.get(url);\n  }\n}\n","import { EventEmitter } from \"events\";\nimport type * as Event from \"events\";\nimport { IStreamHandler } from \"../types\";\nimport { OpenRouterErrorAdapter } from \"./error-adapter\";\n\nexport class StreamHandler implements IStreamHandler {\n  handleStream(stream: Event): EventEmitter {\n    const eventEmitter = new EventEmitter();\n    let buffer = \"\";\n\n    stream.on(\"data\", (chunk: Buffer) => {\n      buffer += chunk.toString();\n      const lines = buffer.split(\"\\n\");\n      buffer = lines.pop() || \"\";\n\n      for (const line of lines) {\n        if (line.trim() === \"\" || line.startsWith(\":\")) {\n          // Handle SSE comments (OpenRouter processing messages)\n          if (line.includes(\"OPENROUTER PROCESSING\")) {\n            eventEmitter.emit(\"processing\");\n          }\n          continue;\n        }\n\n        try {\n          const message = line.replace(/^data: /, \"\");\n          if (message === \"[DONE]\") {\n            eventEmitter.emit(\"done\");\n            continue;\n          }\n\n          const parsed = JSON.parse(message);\n\n          // Emit the full chunk for raw access\n          eventEmitter.emit(\"chunk\", parsed);\n\n          // Handle the standardized response format\n          if (parsed.choices?.[0]) {\n            const choice = parsed.choices[0];\n\n            // For streaming responses, we'll get delta updates\n            if (choice.delta) {\n              // Extract the delta components\n              const { content, role, tool_calls } = choice.delta;\n\n              // Emit specific events for different delta types\n              if (content) {\n                // Emit both for backwards compatibility\n                eventEmitter.emit(\"token\", content);\n                eventEmitter.emit(\"content\", content);\n              }\n              if (role) {\n                eventEmitter.emit(\"role\", role);\n              }\n              if (tool_calls) {\n                eventEmitter.emit(\"tool_calls\", tool_calls);\n              }\n            }\n\n            // Handle finish reason if present\n            if (choice.finish_reason) {\n              eventEmitter.emit(\"finish\", choice.finish_reason);\n            }\n          }\n\n          // Handle usage statistics in the final message\n          if (parsed.usage) {\n            eventEmitter.emit(\"usage\", parsed.usage);\n          }\n        } catch (error) {\n          eventEmitter.emit(\"error\", OpenRouterErrorAdapter.handleError(error));\n        }\n      }\n    });\n\n    stream.on(\"end\", () => eventEmitter.emit(\"done\"));\n    stream.on(\"error\", (error: Error) => {\n      eventEmitter.emit(\"error\", OpenRouterErrorAdapter.handleError(error));\n    });\n\n    return eventEmitter;\n  }\n}\n","import { RouterModel } from \"../models\";\nimport {\n  ChatCompletionResult,\n  GenerationStats,\n  IHttpClient,\n  IStreamHandler,\n  Message,\n  QueryResponseModel,\n  Request,\n} from \"../types\";\nimport { OpenRouterErrorAdapter } from \"./error-adapter\";\nimport { HttpClient } from \"./http-client\";\nimport { StreamHandler } from \"./stream-handler\";\n\ntype BaseRequest = Omit<Request, \"messages\" | \"prompt\">;\n\ntype MessagesRequest = BaseRequest & {\n  messages: Message[];\n  prompt?: never;\n};\n\ntype PromptRequest = BaseRequest & {\n  prompt: string;\n  messages?: never;\n};\n\ntype CompletionRequest = MessagesRequest | PromptRequest;\n\nexport class OpenRouterClient {\n  private readonly baseURL = \"https://openrouter.ai/api/v1\";\n  private httpClient: IHttpClient;\n  private streamHandler: IStreamHandler;\n\n  constructor(\n    private readonly apiKey: string,\n    private readonly defaultConfig: {\n      siteUrl?: string;\n      siteName?: string;\n      model?: RouterModel;\n    } = {},\n    httpClient?: IHttpClient,\n    streamHandler?: IStreamHandler,\n  ) {\n    this.httpClient =\n      httpClient || new HttpClient(this.baseURL, this.getDefaultHeaders());\n    this.streamHandler = streamHandler || new StreamHandler();\n  }\n\n  private getDefaultHeaders() {\n    const headers: Record<string, string> = {\n      Authorization: `Bearer ${this.apiKey}`,\n      \"Content-Type\": \"application/json\",\n    };\n\n    if (this.defaultConfig.siteUrl) {\n      headers[\"HTTP-Referer\"] = this.defaultConfig.siteUrl;\n    }\n    if (this.defaultConfig.siteName) {\n      headers[\"X-Title\"] = this.defaultConfig.siteName;\n    }\n\n    return headers;\n  }\n\n  async chatCompletion<\n    TStreaming extends boolean = false,\n    TRequest extends CompletionRequest = CompletionRequest,\n  >(\n    options: TRequest & { stream?: TStreaming },\n  ): Promise<ChatCompletionResult<TStreaming, TRequest>> {\n    try {\n      const data = {\n        ...options,\n        model: options.model || this.defaultConfig.model,\n        stream: options.stream,\n      };\n\n      if (options.stream) {\n        const response = await this.httpClient.post(\"/chat/completions\", data, {\n          responseType: \"stream\",\n          signal: options.signal,\n        });\n        // We know it's an EventEmitter if streaming is true\n        return this.streamHandler.handleStream(\n          response.data,\n        ) as ChatCompletionResult<TStreaming, TRequest>;\n      }\n\n      const response = await this.httpClient.post(\"/chat/completions\", data);\n      // TypeScript will infer the correct type based on the request shape\n      return response.data as ChatCompletionResult<TStreaming, TRequest>;\n    } catch (error) {\n      throw OpenRouterErrorAdapter.handleError(error);\n    }\n  }\n\n  async getGenerationStats(generationId: string): Promise<GenerationStats> {\n    try {\n      const response = await this.httpClient.get(\n        `/generation?id=${generationId}`,\n      );\n      return response.data.data; // i shit you not\n    } catch (error) {\n      throw OpenRouterErrorAdapter.handleError(error);\n    }\n  }\n\n  async getModels(): Promise<QueryResponseModel[]> {\n    try {\n      const response = await this.httpClient.get(\"/models\");\n      return response.data.data; // yep\n    } catch (error) {\n      throw OpenRouterErrorAdapter.handleError(error);\n    }\n  }\n}\n"]}