ai.libx.js
Version:
Unified API bridge for various AI models (LLMs, image/video generation, TTS, STT) - stateless, edge-compatible
92 lines (76 loc) • 2.34 kB
text/typescript
import { IProviderAdapter } from '../../types/provider';
import { ChatOptions, ChatResponse, StreamChunk, ProviderConfig } from '../../types';
import { validateApiKey } from '../../utils/validation';
/**
* Base adapter class with shared functionality for all providers
*/
export abstract class BaseAdapter implements IProviderAdapter {
protected config: ProviderConfig;
constructor(config: ProviderConfig = {}) {
this.config = config;
}
abstract get name(): string;
abstract chat(options: ChatOptions): Promise<ChatResponse | AsyncIterable<StreamChunk>>;
/**
* Get API key from options or config
*/
protected getApiKey(options: ChatOptions): string {
const apiKey = options.apiKey || this.config.apiKey;
return validateApiKey(apiKey, this.name);
}
/**
* Get base URL from options or config, with default fallback
*/
protected getBaseUrl(defaultUrl: string): string {
return this.config.baseUrl || defaultUrl;
}
/**
* Create headers for API request
*/
protected createHeaders(apiKey: string, additionalHeaders: Record<string, string> = {}): Record<string, string> {
return {
'Content-Type': 'application/json',
...additionalHeaders,
};
}
/**
* Handle fetch errors consistently
*/
protected async handleFetchError(response: Response, provider: string): Promise<never> {
let errorData: any;
let errorMessage: string;
try {
errorData = await response.json();
errorMessage = errorData.error?.message || errorData.message || response.statusText;
} catch {
errorMessage = response.statusText || 'Unknown error';
errorData = {};
}
const error: any = new Error(errorMessage);
error.status = response.status;
error.statusCode = response.status;
error.error = errorData.error || errorData;
// Extract retry-after header for rate limits
if (response.status === 429) {
const retryAfter = response.headers.get('retry-after');
if (retryAfter) {
error.retryAfter = parseInt(retryAfter, 10);
}
}
throw error;
}
/**
* Make a fetch request with error handling
*/
protected async fetchWithErrorHandling(
url: string,
options: RequestInit,
provider: string
): Promise<Response> {
const response = await fetch(url, options);
if (!response.ok) {
await this.handleFetchError(response, provider);
}
return response;
}
}