UNPKG

@tokenrouter/sdk

Version:

TypeScript/JavaScript SDK for TokenRouter - Intelligent LLM Routing API

304 lines 11.2 kB
"use strict"; /** * TokenRouter SDK Client */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TokenRouterAsyncClient = exports.TokenRouterClient = void 0; const axios_1 = __importDefault(require("axios")); const errors_1 = require("./errors"); const version_1 = require("./version"); class TokenRouterClient { constructor(options = {}) { // Removed utilities per Request_1 /** * OpenAI-compatible chat namespace */ this.chat = { completions: { create: (request) => this.createChatCompletion(request), }, }; this.completions = { create: async (request) => { const payload = { model: request.model || 'auto', // prompt: request.prompt, mode: request.mode, model_preferences: request.model_preferences, ...request, }; if (payload.stream) return this.streamCompletions(payload); return this.request('POST', '/v1/completions', payload); }, }; this.apiKey = options.apiKey || process.env.TOKENROUTER_API_KEY || ''; if (!this.apiKey) { throw new errors_1.AuthenticationError('API key is required. Set TOKENROUTER_API_KEY environment variable or pass apiKey parameter.'); } this.baseUrl = (options.baseUrl || process.env.TOKENROUTER_BASE_URL || 'https://api.tokenrouter.io').replace(/\/$/, ''); this.timeout = options.timeout || 60000; this.maxRetries = options.maxRetries || 3; const headers = { Authorization: `Bearer ${this.apiKey}`, 'Content-Type': 'application/json', 'User-Agent': `tokenrouter-node/${version_1.VERSION}`, ...options.headers, }; this.client = axios_1.default.create({ baseURL: this.baseUrl, timeout: this.timeout, headers, }); this.setupInterceptors(); } setupInterceptors() { this.client.interceptors.response.use((response) => response, async (error) => { if (error.response) { this.handleResponseError(error.response); } else if (error.request) { throw new errors_1.APIConnectionError('Connection failed: ' + error.message); } else { throw new errors_1.TokenRouterError('Request failed: ' + error.message); } }); } /** * Convert axios headers to Record<string, string> */ convertHeaders(headers) { if (!headers) return undefined; const result = {}; for (const [key, value] of Object.entries(headers)) { if (typeof value === 'string') { result[key] = value; } else if (value != null) { result[key] = String(value); } } return result; } handleResponseError(response) { const status = response.status; const data = response.data; const message = data?.detail || data?.error || response.statusText; const headers = this.convertHeaders(response.headers); switch (status) { case 401: throw new errors_1.AuthenticationError(message, status, data, headers); case 429: const retryAfter = response.headers['retry-after']; throw new errors_1.RateLimitError(message, status, data, headers, retryAfter ? parseInt(retryAfter) : undefined); case 400: throw new errors_1.InvalidRequestError(message, status, data, headers); case 403: if (message.toLowerCase().includes('quota')) { throw new errors_1.QuotaExceededError(message, status, data, headers); } throw new errors_1.AuthenticationError(message, status, data, headers); default: if (status >= 500) { throw new errors_1.APIStatusError(message, status, data, headers); } throw new errors_1.TokenRouterError(message, status, data, headers); } } async request(method, path, data, params, retryCount = 0) { try { const response = await this.client.request({ method, url: path, data, params, }); return response.data; } catch (error) { if (retryCount < this.maxRetries && error instanceof errors_1.APIStatusError && error.statusCode && error.statusCode >= 500) { await new Promise((resolve) => setTimeout(resolve, Math.pow(2, retryCount) * 1000)); return this.request(method, path, data, params, retryCount + 1); } throw error; } } /** Create chat completion (POST /v1/chat/completions) */ async createChatCompletion(request) { const payload = { ...request, model: request.model || 'auto' }; if (payload.stream) return this.streamChatCompletion(payload); return this.request('POST', '/v1/chat/completions', payload); } /** Native TokenRouter create (POST /route) */ async create(request) { const payload = { ...request, model: request.model || 'auto' }; if (payload.stream) return this.streamCreate(payload); return this.request('POST', '/route', payload); } /** * Stream a chat completion */ async *streamChatCompletion(request) { const url = `${this.baseUrl}/v1/chat/completions`; const headers = { Authorization: `Bearer ${this.apiKey}`, 'Content-Type': 'application/json', Accept: 'text/event-stream', }; const response = await fetch(url, { method: 'POST', headers, body: JSON.stringify({ ...request, stream: true }), }); if (!response.ok) { const error = await response.text(); throw new errors_1.APIStatusError(error, response.status); } const reader = response.body?.getReader(); if (!reader) { throw new errors_1.TokenRouterError('Failed to get response reader'); } const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop() || ''; for (const line of lines) { if (line.startsWith('data: ')) { const data = line.slice(6); if (data === '[DONE]') { return; } try { const chunk = JSON.parse(data); yield chunk; } catch (e) { // Ignore parsing errors } } } } } /** * Stream native create (/route) */ async *streamCreate(request) { const url = `${this.baseUrl}/route`; const headers = { Authorization: `Bearer ${this.apiKey}`, 'Content-Type': 'application/json', Accept: 'text/event-stream', }; const response = await fetch(url, { method: 'POST', headers, body: JSON.stringify({ ...request, stream: true }), }); if (!response.ok) { const error = await response.text(); throw new errors_1.APIStatusError(error, response.status); } const reader = response.body?.getReader(); if (!reader) { throw new errors_1.TokenRouterError('Failed to get response reader'); } const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop() || ''; for (const line of lines) { if (line.startsWith('data: ')) { const data = line.slice(6); if (data === '[DONE]') { return; } try { const chunk = JSON.parse(data); yield chunk; } catch (e) { // Ignore parsing errors } } } } } // Removed shorthand helpers per Request_1 /** * OpenAI legacy completions: client.completions.create */ async *streamCompletions(payload) { const url = `${this.baseUrl}/v1/completions`; const headers = { Authorization: `Bearer ${this.apiKey}`, 'Content-Type': 'application/json', Accept: 'text/event-stream', }; const response = await fetch(url, { method: 'POST', headers, body: JSON.stringify({ ...payload, stream: true }), }); if (!response.ok) { const error = await response.text(); throw new errors_1.APIStatusError(error, response.status); } const reader = response.body?.getReader(); if (!reader) { throw new errors_1.TokenRouterError('Failed to get response reader'); } const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop() || ''; for (const line of lines) { if (line.startsWith('data: ')) { const data = line.slice(6); if (data === '[DONE]') return; try { yield JSON.parse(data); } catch (e) { // ignore } } } } } } exports.TokenRouterClient = TokenRouterClient; /** * Async client (alias for compatibility) */ class TokenRouterAsyncClient extends TokenRouterClient { } exports.TokenRouterAsyncClient = TokenRouterAsyncClient; //# sourceMappingURL=client.js.map