Files
claude-code-router/ui/src/lib/api.ts
2025-08-02 22:56:18 +08:00

189 lines
5.1 KiB
TypeScript

import type { Config, Provider, Transformer } from '@/types';
// API Client Class for handling requests with baseUrl and apikey authentication
class ApiClient {
private baseUrl: string;
private apiKey: string;
constructor(baseUrl: string = '/api', apiKey: string = '') {
this.baseUrl = baseUrl;
// Load API key from localStorage if available
this.apiKey = apiKey || localStorage.getItem('apiKey') || '';
}
// Update base URL
setBaseUrl(url: string) {
this.baseUrl = url;
}
// Update API key
setApiKey(apiKey: string) {
this.apiKey = apiKey;
// Save API key to localStorage
if (apiKey) {
localStorage.setItem('apiKey', apiKey);
} else {
localStorage.removeItem('apiKey');
}
}
// Create headers with API key authentication
private createHeaders(contentType: string = 'application/json'): HeadersInit {
const headers: Record<string, string> = {
'X-API-Key': this.apiKey,
'Accept': 'application/json',
};
if (contentType) {
headers['Content-Type'] = contentType;
}
return headers;
}
// Generic fetch wrapper with base URL and authentication
private async apiFetch<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const url = `${this.baseUrl}${endpoint}`;
const config: RequestInit = {
...options,
headers: {
...this.createHeaders(),
...options.headers,
},
};
try {
const response = await fetch(url, config);
// Handle 401 Unauthorized responses
if (response.status === 401) {
// Remove API key when it's invalid
localStorage.removeItem('apiKey');
// Redirect to login page if not already there
// For memory router, we need to use the router instance
// We'll dispatch a custom event that the app can listen to
window.dispatchEvent(new CustomEvent('unauthorized'));
// Return a promise that never resolves to prevent further execution
return new Promise(() => {}) as Promise<T>;
}
if (!response.ok) {
throw new Error(`API request failed: ${response.status} ${response.statusText}`);
}
if (response.status === 204) {
return {} as T;
}
const text = await response.text();
return text ? JSON.parse(text) : ({} as T);
} catch (error) {
console.error('API request error:', error);
throw error;
}
}
// GET request
async get<T>(endpoint: string): Promise<T> {
return this.apiFetch<T>(endpoint, {
method: 'GET',
});
}
// POST request
async post<T>(endpoint: string, data: unknown): Promise<T> {
return this.apiFetch<T>(endpoint, {
method: 'POST',
body: JSON.stringify(data),
});
}
// PUT request
async put<T>(endpoint: string, data: unknown): Promise<T> {
return this.apiFetch<T>(endpoint, {
method: 'PUT',
body: JSON.stringify(data),
});
}
// DELETE request
async delete<T>(endpoint: string): Promise<T> {
return this.apiFetch<T>(endpoint, {
method: 'DELETE',
});
}
// API methods for configuration
// Get current configuration
async getConfig(): Promise<Config> {
return this.get<Config>('/config');
}
// Update entire configuration
async updateConfig(config: Config): Promise<Config> {
return this.post<Config>('/config', config);
}
// Get providers
async getProviders(): Promise<Provider[]> {
return this.get<Provider[]>('/api/providers');
}
// Add a new provider
async addProvider(provider: Provider): Promise<Provider> {
return this.post<Provider>('/api/providers', provider);
}
// Update a provider
async updateProvider(index: number, provider: Provider): Promise<Provider> {
return this.post<Provider>(`/api/providers/${index}`, provider);
}
// Delete a provider
async deleteProvider(index: number): Promise<void> {
return this.delete<void>(`/api/providers/${index}`);
}
// Get transformers
async getTransformers(): Promise<Transformer[]> {
return this.get<Transformer[]>('/api/transformers');
}
// Add a new transformer
async addTransformer(transformer: Transformer): Promise<Transformer> {
return this.post<Transformer>('/api/transformers', transformer);
}
// Update a transformer
async updateTransformer(index: number, transformer: Transformer): Promise<Transformer> {
return this.post<Transformer>(`/api/transformers/${index}`, transformer);
}
// Delete a transformer
async deleteTransformer(index: number): Promise<void> {
return this.delete<void>(`/api/transformers/${index}`);
}
// Get configuration (new endpoint)
async getConfigNew(): Promise<Config> {
return this.get<Config>('/config');
}
// Save configuration (new endpoint)
async saveConfig(config: Config): Promise<unknown> {
return this.post<Config>('/config', config);
}
// Restart service
async restartService(): Promise<unknown> {
return this.post<void>('/restart', {});
}
}
// Create a default instance of the API client
export const api = new ApiClient();
// Export the class for creating custom instances
export default ApiClient;