File size: 3,498 Bytes
c0a9bce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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>;
}