import { AIProviderError, AIErrorType } from '../types/index.js'; import { DEFAULT_TIMEOUT_MS } from '../constants.js'; export interface OpenWebUIHttpOptions { baseUrl: string; apiKey?: string; timeout?: number; dangerouslyAllowInsecureConnections?: boolean; } /** * Thin HTTP client shared by OpenWebUI strategies. * Handles auth header, request body serialization, and timeout-to-AIProviderError translation. */ export class OpenWebUIHttpClient { readonly baseUrl: string; private readonly apiKey: string | undefined; private readonly timeout: number; private readonly dangerouslyAllowInsecureConnections: boolean; constructor(options: OpenWebUIHttpOptions) { this.baseUrl = options.baseUrl; this.apiKey = options.apiKey; this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS; this.dangerouslyAllowInsecureConnections = options.dangerouslyAllowInsecureConnections ?? true; } async request(path: string, method: string, body?: unknown): Promise { const headers: Record = { 'Content-Type': 'application/json', 'User-Agent': 'simple-ai-provider/2.0.0' }; if (this.apiKey) { headers['Authorization'] = `Bearer ${this.apiKey}`; } const requestOptions: RequestInit = { method, headers, body: body !== undefined ? JSON.stringify(body) : undefined, signal: AbortSignal.timeout(this.timeout) }; try { return await fetch(`${this.baseUrl}${path}`, requestOptions); } catch (error: any) { if (error.name === 'AbortError') { throw new AIProviderError( 'Request timed out', AIErrorType.TIMEOUT, undefined, error ); } throw error; } } }