mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-03-10 14:13:19 +00:00
122 lines
3.4 KiB
TypeScript
122 lines
3.4 KiB
TypeScript
import type { ProviderConfig, StatusCheckResult, ApiResponse } from './types';
|
|
|
|
export abstract class BaseProviderChecker {
|
|
protected config: ProviderConfig;
|
|
|
|
constructor(config: ProviderConfig) {
|
|
this.config = config;
|
|
}
|
|
|
|
protected async checkApiEndpoint(
|
|
url: string,
|
|
headers?: Record<string, string>,
|
|
testModel?: string,
|
|
): Promise<{ ok: boolean; status: number | string; message?: string; responseTime: number }> {
|
|
try {
|
|
const controller = new AbortController();
|
|
const timeoutId = setTimeout(() => controller.abort(), 10000);
|
|
|
|
const startTime = performance.now();
|
|
|
|
// Add common headers
|
|
const processedHeaders = {
|
|
'Content-Type': 'application/json',
|
|
...headers,
|
|
};
|
|
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: processedHeaders,
|
|
signal: controller.signal,
|
|
});
|
|
|
|
const endTime = performance.now();
|
|
const responseTime = endTime - startTime;
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
const data = (await response.json()) as ApiResponse;
|
|
|
|
if (!response.ok) {
|
|
let errorMessage = `API returned status: ${response.status}`;
|
|
|
|
if (data.error?.message) {
|
|
errorMessage = data.error.message;
|
|
} else if (data.message) {
|
|
errorMessage = data.message;
|
|
}
|
|
|
|
return {
|
|
ok: false,
|
|
status: response.status,
|
|
message: errorMessage,
|
|
responseTime,
|
|
};
|
|
}
|
|
|
|
// Different providers have different model list formats
|
|
let models: string[] = [];
|
|
|
|
if (Array.isArray(data)) {
|
|
models = data.map((model: { id?: string; name?: string }) => model.id || model.name || '');
|
|
} else if (data.data && Array.isArray(data.data)) {
|
|
models = data.data.map((model) => model.id || model.name || '');
|
|
} else if (data.models && Array.isArray(data.models)) {
|
|
models = data.models.map((model) => model.id || model.name || '');
|
|
} else if (data.model) {
|
|
models = [data.model];
|
|
}
|
|
|
|
if (!testModel || models.length > 0) {
|
|
return {
|
|
ok: true,
|
|
status: response.status,
|
|
responseTime,
|
|
message: 'API key is valid',
|
|
};
|
|
}
|
|
|
|
if (testModel && !models.includes(testModel)) {
|
|
return {
|
|
ok: true,
|
|
status: 'model_not_found',
|
|
message: `API key is valid (test model ${testModel} not found in ${models.length} available models)`,
|
|
responseTime,
|
|
};
|
|
}
|
|
|
|
return {
|
|
ok: true,
|
|
status: response.status,
|
|
message: 'API key is valid',
|
|
responseTime,
|
|
};
|
|
} catch (error) {
|
|
console.error(`Error checking API endpoint ${url}:`, error);
|
|
return {
|
|
ok: false,
|
|
status: error instanceof Error ? error.message : 'Unknown error',
|
|
message: error instanceof Error ? `Connection failed: ${error.message}` : 'Connection failed',
|
|
responseTime: 0,
|
|
};
|
|
}
|
|
}
|
|
|
|
protected async checkEndpoint(url: string): Promise<'reachable' | 'unreachable'> {
|
|
try {
|
|
const response = await fetch(url, {
|
|
mode: 'no-cors',
|
|
headers: {
|
|
Accept: 'text/html',
|
|
},
|
|
});
|
|
return response.type === 'opaque' ? 'reachable' : 'unreachable';
|
|
} catch (error) {
|
|
console.error(`Error checking ${url}:`, error);
|
|
return 'unreachable';
|
|
}
|
|
}
|
|
|
|
abstract checkStatus(): Promise<StatusCheckResult>;
|
|
}
|