UNPKG

mcp-omnisearch

Version:

MCP server for integrating Omnisearch with LLMs

153 lines (152 loc) 6.29 kB
import { ErrorType, ProviderError } from './types.js'; import { retry_with_backoff } from './utils.js'; export class HttpClient { constructor(options = {}) { this.options = options; this.default_timeout = 30000; // 30 seconds this.default_max_retries = 3; this.default_initial_delay = 1000; } async make_request(url, init, provider_name) { const timeout = this.options.timeout || this.default_timeout; const controller = new AbortController(); const timeout_id = setTimeout(() => controller.abort(), timeout); try { const response = await fetch(url, { ...init, signal: controller.signal, headers: { ...this.options.headers, ...init.headers, }, }); clearTimeout(timeout_id); const data = await response.json(); if (!response.ok) { this.handle_http_error(response, data, provider_name); } return { data, status: response.status, status_text: response.statusText, headers: response.headers, }; } catch (error) { clearTimeout(timeout_id); if (error instanceof ProviderError) { throw error; } if (controller.signal.aborted) { throw new ProviderError(ErrorType.API_ERROR, `Request timeout after ${timeout}ms`, provider_name); } throw new ProviderError(ErrorType.API_ERROR, `Network error: ${error instanceof Error ? error.message : 'Unknown error'}`, provider_name); } } handle_http_error(response, data, provider_name) { const error_message = data.message || data.error || response.statusText; switch (response.status) { case 401: throw new ProviderError(ErrorType.API_ERROR, 'Invalid API key', provider_name); case 403: throw new ProviderError(ErrorType.API_ERROR, 'API key does not have access to this endpoint', provider_name); case 429: const reset_time = response.headers.get('x-ratelimit-reset'); const reset_date = reset_time ? new Date(reset_time) : undefined; throw new ProviderError(ErrorType.RATE_LIMIT, `Rate limit exceeded for ${provider_name}${reset_date ? `. Reset at ${reset_date.toISOString()}` : ''}`, provider_name, { reset_time: reset_date }); case 500: case 502: case 503: case 504: throw new ProviderError(ErrorType.PROVIDER_ERROR, `${provider_name} API internal error`, provider_name); default: throw new ProviderError(ErrorType.API_ERROR, `Unexpected error: ${error_message}`, provider_name); } } async get(url, provider_name, options = {}) { const max_retries = options.max_retries || this.default_max_retries; const initial_delay = options.initial_delay || this.default_initial_delay; return retry_with_backoff(() => this.make_request(url, { method: 'GET' }, provider_name), max_retries, initial_delay); } async post(url, body, provider_name, options = {}) { const max_retries = options.max_retries || this.default_max_retries; const initial_delay = options.initial_delay || this.default_initial_delay; return retry_with_backoff(() => this.make_request(url, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(body), }, provider_name), max_retries, initial_delay); } async put(url, body, provider_name, options = {}) { const max_retries = options.max_retries || this.default_max_retries; const initial_delay = options.initial_delay || this.default_initial_delay; return retry_with_backoff(() => this.make_request(url, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(body), }, provider_name), max_retries, initial_delay); } async patch(url, body, provider_name, options = {}) { const max_retries = options.max_retries || this.default_max_retries; const initial_delay = options.initial_delay || this.default_initial_delay; return retry_with_backoff(() => this.make_request(url, { method: 'PATCH', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(body), }, provider_name), max_retries, initial_delay); } async delete(url, provider_name, options = {}) { const max_retries = options.max_retries || this.default_max_retries; const initial_delay = options.initial_delay || this.default_initial_delay; return retry_with_backoff(() => this.make_request(url, { method: 'DELETE' }, provider_name), max_retries, initial_delay); } with_auth(api_key, auth_type = 'bearer') { const auth_headers = {}; if (auth_type === 'bearer') { auth_headers['Authorization'] = `Bearer ${api_key}`; } else { auth_headers['X-API-Key'] = api_key; } return new HttpClient({ ...this.options, headers: { ...this.options.headers, ...auth_headers, }, }); } with_headers(headers) { return new HttpClient({ ...this.options, headers: { ...this.options.headers, ...headers, }, }); } with_timeout(timeout) { return new HttpClient({ ...this.options, timeout, }); } with_retry(max_retries, initial_delay) { return new HttpClient({ ...this.options, max_retries, initial_delay: initial_delay || this.default_initial_delay, }); } } export const create_http_client = (options) => { return new HttpClient(options); };