claude-connect 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +175 -0
- package/bin/claude-connect.js +40 -0
- package/package.json +43 -0
- package/src/data/catalog-store.js +482 -0
- package/src/gateway/constants.js +4 -0
- package/src/gateway/messages.js +362 -0
- package/src/gateway/server.js +481 -0
- package/src/gateway/state.js +104 -0
- package/src/index.js +61 -0
- package/src/lib/app-paths.js +269 -0
- package/src/lib/claude-settings.js +364 -0
- package/src/lib/oauth.js +485 -0
- package/src/lib/profile.js +104 -0
- package/src/lib/secrets.js +45 -0
- package/src/lib/terminal.js +350 -0
- package/src/lib/theme.js +44 -0
- package/src/wizard.js +887 -0
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
4
|
+
|
|
5
|
+
export const defaultCatalogDbPath = path.join(process.cwd(), 'storage', 'claude-connect.sqlite');
|
|
6
|
+
|
|
7
|
+
const schemaSql = `
|
|
8
|
+
PRAGMA foreign_keys = ON;
|
|
9
|
+
|
|
10
|
+
CREATE TABLE IF NOT EXISTS providers (
|
|
11
|
+
id TEXT PRIMARY KEY,
|
|
12
|
+
name TEXT NOT NULL,
|
|
13
|
+
vendor TEXT NOT NULL,
|
|
14
|
+
description TEXT NOT NULL,
|
|
15
|
+
docs_url TEXT,
|
|
16
|
+
docs_verified_at TEXT,
|
|
17
|
+
base_url TEXT NOT NULL,
|
|
18
|
+
default_model_id TEXT,
|
|
19
|
+
default_auth_method_id TEXT,
|
|
20
|
+
default_api_key_env_var TEXT NOT NULL
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
CREATE TABLE IF NOT EXISTS models (
|
|
24
|
+
id TEXT PRIMARY KEY,
|
|
25
|
+
provider_id TEXT NOT NULL REFERENCES providers(id) ON DELETE CASCADE,
|
|
26
|
+
name TEXT NOT NULL,
|
|
27
|
+
category TEXT NOT NULL,
|
|
28
|
+
context_window TEXT NOT NULL,
|
|
29
|
+
summary TEXT NOT NULL,
|
|
30
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
31
|
+
is_default INTEGER NOT NULL DEFAULT 0
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
CREATE TABLE IF NOT EXISTS auth_methods (
|
|
35
|
+
id TEXT PRIMARY KEY,
|
|
36
|
+
name TEXT NOT NULL,
|
|
37
|
+
description TEXT NOT NULL,
|
|
38
|
+
credential_kind TEXT NOT NULL
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
CREATE TABLE IF NOT EXISTS provider_auth_methods (
|
|
42
|
+
provider_id TEXT NOT NULL REFERENCES providers(id) ON DELETE CASCADE,
|
|
43
|
+
auth_method_id TEXT NOT NULL REFERENCES auth_methods(id) ON DELETE CASCADE,
|
|
44
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
45
|
+
is_default INTEGER NOT NULL DEFAULT 0,
|
|
46
|
+
PRIMARY KEY (provider_id, auth_method_id)
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
CREATE TABLE IF NOT EXISTS provider_oauth_configs (
|
|
50
|
+
provider_id TEXT PRIMARY KEY REFERENCES providers(id) ON DELETE CASCADE,
|
|
51
|
+
authorize_url TEXT NOT NULL,
|
|
52
|
+
token_url TEXT NOT NULL,
|
|
53
|
+
callback_url TEXT NOT NULL,
|
|
54
|
+
access_type TEXT NOT NULL,
|
|
55
|
+
scope TEXT,
|
|
56
|
+
client_id TEXT,
|
|
57
|
+
app_secret_id TEXT
|
|
58
|
+
);
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
const seedProviders = [
|
|
62
|
+
{
|
|
63
|
+
id: 'kimi',
|
|
64
|
+
name: 'Kimi',
|
|
65
|
+
vendor: 'Moonshot AI',
|
|
66
|
+
description: 'Kimi Code para Claude Code usando el endpoint Anthropic oficial de Kimi.',
|
|
67
|
+
docsUrl: 'https://www.kimi.com/code/docs/en/more/third-party-agents.html',
|
|
68
|
+
docsVerifiedAt: '2026-04-01',
|
|
69
|
+
baseUrl: 'https://api.kimi.com/coding/',
|
|
70
|
+
defaultModelId: 'kimi-for-coding',
|
|
71
|
+
defaultAuthMethodId: 'token',
|
|
72
|
+
defaultApiKeyEnvVar: 'KIMI_API_KEY',
|
|
73
|
+
models: [
|
|
74
|
+
{
|
|
75
|
+
id: 'kimi-for-coding',
|
|
76
|
+
name: 'Kimi For Coding',
|
|
77
|
+
category: 'Coding',
|
|
78
|
+
contextWindow: '262144',
|
|
79
|
+
summary: 'Modelo oficial de Kimi Code para Claude Code. El modo thinking se conmuta con Tab dentro de Claude Code.',
|
|
80
|
+
sortOrder: 1,
|
|
81
|
+
isDefault: 1
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
authMethods: [
|
|
85
|
+
{
|
|
86
|
+
id: 'token',
|
|
87
|
+
name: 'Token',
|
|
88
|
+
description: 'Conexion por API key contra el endpoint Anthropic oficial del proveedor.',
|
|
89
|
+
credentialKind: 'env_var',
|
|
90
|
+
sortOrder: 1,
|
|
91
|
+
isDefault: 1
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: 'deepseek',
|
|
97
|
+
name: 'DeepSeek',
|
|
98
|
+
vendor: 'DeepSeek',
|
|
99
|
+
description: 'DeepSeek API compatible con OpenAI usando API key y modelos chat/reasoner.',
|
|
100
|
+
docsUrl: 'https://api-docs.deepseek.com/',
|
|
101
|
+
docsVerifiedAt: '2026-03-31',
|
|
102
|
+
baseUrl: 'https://api.deepseek.com',
|
|
103
|
+
defaultModelId: 'deepseek-chat',
|
|
104
|
+
defaultAuthMethodId: 'token',
|
|
105
|
+
defaultApiKeyEnvVar: 'DEEPSEEK_API_KEY',
|
|
106
|
+
models: [
|
|
107
|
+
{
|
|
108
|
+
id: 'deepseek-chat',
|
|
109
|
+
name: 'DeepSeek Chat',
|
|
110
|
+
category: 'General',
|
|
111
|
+
contextWindow: '128K',
|
|
112
|
+
summary: 'Modo no razonador de DeepSeek V3.2, apto como opcion base para Claude Code.',
|
|
113
|
+
sortOrder: 1,
|
|
114
|
+
isDefault: 1
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: 'deepseek-reasoner',
|
|
118
|
+
name: 'DeepSeek Reasoner',
|
|
119
|
+
category: 'Reasoning',
|
|
120
|
+
contextWindow: '128K',
|
|
121
|
+
summary: 'Modo razonador de DeepSeek V3.2 con soporte de Tool Calls segun la documentacion oficial.',
|
|
122
|
+
sortOrder: 2,
|
|
123
|
+
isDefault: 0
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
authMethods: [
|
|
127
|
+
{
|
|
128
|
+
id: 'token',
|
|
129
|
+
name: 'Token',
|
|
130
|
+
description: 'Conexion por API key contra el endpoint Anthropic oficial del proveedor.',
|
|
131
|
+
credentialKind: 'env_var',
|
|
132
|
+
sortOrder: 1,
|
|
133
|
+
isDefault: 1
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
id: 'qwen',
|
|
139
|
+
name: 'Qwen',
|
|
140
|
+
vendor: 'Qwen',
|
|
141
|
+
description: 'Qwen Code con OAuth propio de qwen.ai y modo token compatible con OpenAI.',
|
|
142
|
+
docsUrl: 'https://github.com/QwenLM/qwen-code',
|
|
143
|
+
docsVerifiedAt: '2026-03-31',
|
|
144
|
+
baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
|
|
145
|
+
defaultModelId: 'qwen3-coder-plus',
|
|
146
|
+
defaultAuthMethodId: 'token',
|
|
147
|
+
defaultApiKeyEnvVar: 'DASHSCOPE_API_KEY',
|
|
148
|
+
models: [
|
|
149
|
+
{
|
|
150
|
+
id: 'qwen3-coder-plus',
|
|
151
|
+
name: 'Qwen Coder',
|
|
152
|
+
category: 'Coding',
|
|
153
|
+
contextWindow: 'Auto',
|
|
154
|
+
summary: 'Modelo fijo para esta primera version, siguiendo el flujo de Qwen Code.',
|
|
155
|
+
sortOrder: 1,
|
|
156
|
+
isDefault: 1
|
|
157
|
+
}
|
|
158
|
+
],
|
|
159
|
+
authMethods: [
|
|
160
|
+
{
|
|
161
|
+
id: 'token',
|
|
162
|
+
name: 'Token',
|
|
163
|
+
description: 'Conexion por API key contra el endpoint compatible con OpenAI del proveedor.',
|
|
164
|
+
credentialKind: 'env_var',
|
|
165
|
+
sortOrder: 1,
|
|
166
|
+
isDefault: 1
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: 'oauth',
|
|
170
|
+
name: 'OAuth',
|
|
171
|
+
description: 'Login de Qwen Code mediante device flow en qwen.ai.',
|
|
172
|
+
credentialKind: 'oauth',
|
|
173
|
+
sortOrder: 2,
|
|
174
|
+
isDefault: 0
|
|
175
|
+
}
|
|
176
|
+
],
|
|
177
|
+
oauth: {
|
|
178
|
+
authorizeUrl: 'https://chat.qwen.ai/api/v1/oauth2/device/code',
|
|
179
|
+
tokenUrl: 'https://chat.qwen.ai/api/v1/oauth2/token',
|
|
180
|
+
callbackUrl: 'https://chat.qwen.ai/auth',
|
|
181
|
+
accessType: 'device_code',
|
|
182
|
+
scope: 'openid profile email model.completion',
|
|
183
|
+
clientId: 'f0304373b74a44d2b584a3fb70ca9e56',
|
|
184
|
+
appSecretId: ''
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
];
|
|
188
|
+
|
|
189
|
+
function seedCatalog(db) {
|
|
190
|
+
const insertProvider = db.prepare(`
|
|
191
|
+
INSERT INTO providers (
|
|
192
|
+
id, name, vendor, description, docs_url, docs_verified_at, base_url,
|
|
193
|
+
default_model_id, default_auth_method_id, default_api_key_env_var
|
|
194
|
+
)
|
|
195
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
196
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
197
|
+
name = excluded.name,
|
|
198
|
+
vendor = excluded.vendor,
|
|
199
|
+
description = excluded.description,
|
|
200
|
+
docs_url = excluded.docs_url,
|
|
201
|
+
docs_verified_at = excluded.docs_verified_at,
|
|
202
|
+
base_url = excluded.base_url,
|
|
203
|
+
default_model_id = excluded.default_model_id,
|
|
204
|
+
default_auth_method_id = excluded.default_auth_method_id,
|
|
205
|
+
default_api_key_env_var = excluded.default_api_key_env_var
|
|
206
|
+
`);
|
|
207
|
+
|
|
208
|
+
const insertModel = db.prepare(`
|
|
209
|
+
INSERT INTO models (
|
|
210
|
+
id, provider_id, name, category, context_window, summary, sort_order, is_default
|
|
211
|
+
)
|
|
212
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
213
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
214
|
+
provider_id = excluded.provider_id,
|
|
215
|
+
name = excluded.name,
|
|
216
|
+
category = excluded.category,
|
|
217
|
+
context_window = excluded.context_window,
|
|
218
|
+
summary = excluded.summary,
|
|
219
|
+
sort_order = excluded.sort_order,
|
|
220
|
+
is_default = excluded.is_default
|
|
221
|
+
`);
|
|
222
|
+
|
|
223
|
+
const insertAuthMethod = db.prepare(`
|
|
224
|
+
INSERT INTO auth_methods (id, name, description, credential_kind)
|
|
225
|
+
VALUES (?, ?, ?, ?)
|
|
226
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
227
|
+
name = excluded.name,
|
|
228
|
+
description = excluded.description,
|
|
229
|
+
credential_kind = excluded.credential_kind
|
|
230
|
+
`);
|
|
231
|
+
|
|
232
|
+
const insertProviderAuthMethod = db.prepare(`
|
|
233
|
+
INSERT INTO provider_auth_methods (provider_id, auth_method_id, sort_order, is_default)
|
|
234
|
+
VALUES (?, ?, ?, ?)
|
|
235
|
+
ON CONFLICT(provider_id, auth_method_id) DO UPDATE SET
|
|
236
|
+
sort_order = excluded.sort_order,
|
|
237
|
+
is_default = excluded.is_default
|
|
238
|
+
`);
|
|
239
|
+
|
|
240
|
+
const insertOAuthConfig = db.prepare(`
|
|
241
|
+
INSERT INTO provider_oauth_configs (
|
|
242
|
+
provider_id, authorize_url, token_url, callback_url, access_type, scope, client_id, app_secret_id
|
|
243
|
+
)
|
|
244
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
245
|
+
ON CONFLICT(provider_id) DO UPDATE SET
|
|
246
|
+
authorize_url = excluded.authorize_url,
|
|
247
|
+
token_url = excluded.token_url,
|
|
248
|
+
callback_url = excluded.callback_url,
|
|
249
|
+
access_type = excluded.access_type,
|
|
250
|
+
scope = excluded.scope,
|
|
251
|
+
client_id = excluded.client_id,
|
|
252
|
+
app_secret_id = excluded.app_secret_id
|
|
253
|
+
`);
|
|
254
|
+
|
|
255
|
+
db.exec('BEGIN');
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
for (const seedProvider of seedProviders) {
|
|
259
|
+
db.prepare('DELETE FROM models WHERE provider_id = ?').run(seedProvider.id);
|
|
260
|
+
db.prepare('DELETE FROM provider_auth_methods WHERE provider_id = ?').run(seedProvider.id);
|
|
261
|
+
|
|
262
|
+
insertProvider.run(
|
|
263
|
+
seedProvider.id,
|
|
264
|
+
seedProvider.name,
|
|
265
|
+
seedProvider.vendor,
|
|
266
|
+
seedProvider.description,
|
|
267
|
+
seedProvider.docsUrl,
|
|
268
|
+
seedProvider.docsVerifiedAt,
|
|
269
|
+
seedProvider.baseUrl,
|
|
270
|
+
seedProvider.defaultModelId,
|
|
271
|
+
seedProvider.defaultAuthMethodId,
|
|
272
|
+
seedProvider.defaultApiKeyEnvVar
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
for (const model of seedProvider.models) {
|
|
276
|
+
insertModel.run(
|
|
277
|
+
model.id,
|
|
278
|
+
seedProvider.id,
|
|
279
|
+
model.name,
|
|
280
|
+
model.category,
|
|
281
|
+
model.contextWindow,
|
|
282
|
+
model.summary,
|
|
283
|
+
model.sortOrder,
|
|
284
|
+
model.isDefault
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
for (const authMethod of seedProvider.authMethods) {
|
|
289
|
+
insertAuthMethod.run(
|
|
290
|
+
authMethod.id,
|
|
291
|
+
authMethod.name,
|
|
292
|
+
authMethod.description,
|
|
293
|
+
authMethod.credentialKind
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
insertProviderAuthMethod.run(
|
|
297
|
+
seedProvider.id,
|
|
298
|
+
authMethod.id,
|
|
299
|
+
authMethod.sortOrder,
|
|
300
|
+
authMethod.isDefault
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (seedProvider.oauth) {
|
|
305
|
+
insertOAuthConfig.run(
|
|
306
|
+
seedProvider.id,
|
|
307
|
+
seedProvider.oauth.authorizeUrl,
|
|
308
|
+
seedProvider.oauth.tokenUrl,
|
|
309
|
+
seedProvider.oauth.callbackUrl,
|
|
310
|
+
seedProvider.oauth.accessType,
|
|
311
|
+
seedProvider.oauth.scope,
|
|
312
|
+
seedProvider.oauth.clientId,
|
|
313
|
+
seedProvider.oauth.appSecretId
|
|
314
|
+
);
|
|
315
|
+
} else {
|
|
316
|
+
db.prepare('DELETE FROM provider_oauth_configs WHERE provider_id = ?').run(seedProvider.id);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
db.exec('COMMIT');
|
|
321
|
+
} catch (error) {
|
|
322
|
+
db.exec('ROLLBACK');
|
|
323
|
+
throw error;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function mapProviderRow(row) {
|
|
328
|
+
return {
|
|
329
|
+
id: row.id,
|
|
330
|
+
name: row.name,
|
|
331
|
+
vendor: row.vendor,
|
|
332
|
+
description: row.description,
|
|
333
|
+
docsUrl: row.docs_url,
|
|
334
|
+
docsVerifiedAt: row.docs_verified_at,
|
|
335
|
+
baseUrl: row.base_url,
|
|
336
|
+
defaultModelId: row.default_model_id,
|
|
337
|
+
defaultAuthMethodId: row.default_auth_method_id,
|
|
338
|
+
defaultApiKeyEnvVar: row.default_api_key_env_var,
|
|
339
|
+
modelCount: Number(row.model_count ?? 0),
|
|
340
|
+
authCount: Number(row.auth_count ?? 0)
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function mapModelRow(row) {
|
|
345
|
+
return {
|
|
346
|
+
id: row.id,
|
|
347
|
+
providerId: row.provider_id,
|
|
348
|
+
name: row.name,
|
|
349
|
+
category: row.category,
|
|
350
|
+
contextWindow: row.context_window,
|
|
351
|
+
summary: row.summary,
|
|
352
|
+
sortOrder: Number(row.sort_order),
|
|
353
|
+
isDefault: Boolean(row.is_default)
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function mapAuthRow(row) {
|
|
358
|
+
return {
|
|
359
|
+
id: row.id,
|
|
360
|
+
name: row.name,
|
|
361
|
+
description: row.description,
|
|
362
|
+
credentialKind: row.credential_kind,
|
|
363
|
+
sortOrder: Number(row.sort_order),
|
|
364
|
+
isDefault: Boolean(row.is_default)
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function mapOAuthRow(row) {
|
|
369
|
+
return {
|
|
370
|
+
providerId: row.provider_id,
|
|
371
|
+
deviceCodeUrl: row.authorize_url,
|
|
372
|
+
tokenUrl: row.token_url,
|
|
373
|
+
browserAuthUrl: row.callback_url,
|
|
374
|
+
flowType: row.access_type,
|
|
375
|
+
scope: row.scope ?? '',
|
|
376
|
+
clientId: row.client_id ?? '',
|
|
377
|
+
appSecretId: row.app_secret_id ?? ''
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export function createCatalogStore({ filename = defaultCatalogDbPath } = {}) {
|
|
382
|
+
if (filename !== ':memory:') {
|
|
383
|
+
fs.mkdirSync(path.dirname(filename), { recursive: true });
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const db = new DatabaseSync(filename);
|
|
387
|
+
db.exec(schemaSql);
|
|
388
|
+
seedCatalog(db);
|
|
389
|
+
|
|
390
|
+
const providerListStatement = db.prepare(`
|
|
391
|
+
SELECT
|
|
392
|
+
p.*,
|
|
393
|
+
COUNT(DISTINCT m.id) AS model_count,
|
|
394
|
+
COUNT(DISTINCT pam.auth_method_id) AS auth_count
|
|
395
|
+
FROM providers p
|
|
396
|
+
LEFT JOIN models m ON m.provider_id = p.id
|
|
397
|
+
LEFT JOIN provider_auth_methods pam ON pam.provider_id = p.id
|
|
398
|
+
GROUP BY p.id
|
|
399
|
+
ORDER BY p.name ASC
|
|
400
|
+
`);
|
|
401
|
+
|
|
402
|
+
const providerStatement = db.prepare(`
|
|
403
|
+
SELECT *
|
|
404
|
+
FROM providers
|
|
405
|
+
WHERE id = ?
|
|
406
|
+
`);
|
|
407
|
+
|
|
408
|
+
const modelListStatement = db.prepare(`
|
|
409
|
+
SELECT *
|
|
410
|
+
FROM models
|
|
411
|
+
WHERE provider_id = ?
|
|
412
|
+
ORDER BY is_default DESC, sort_order ASC, name ASC
|
|
413
|
+
`);
|
|
414
|
+
|
|
415
|
+
const authListStatement = db.prepare(`
|
|
416
|
+
SELECT am.*, pam.sort_order, pam.is_default
|
|
417
|
+
FROM provider_auth_methods pam
|
|
418
|
+
JOIN auth_methods am ON am.id = pam.auth_method_id
|
|
419
|
+
WHERE pam.provider_id = ?
|
|
420
|
+
ORDER BY pam.is_default DESC, pam.sort_order ASC, am.name ASC
|
|
421
|
+
`);
|
|
422
|
+
|
|
423
|
+
const oauthConfigStatement = db.prepare(`
|
|
424
|
+
SELECT *
|
|
425
|
+
FROM provider_oauth_configs
|
|
426
|
+
WHERE provider_id = ?
|
|
427
|
+
`);
|
|
428
|
+
|
|
429
|
+
return {
|
|
430
|
+
filename,
|
|
431
|
+
close() {
|
|
432
|
+
db.close();
|
|
433
|
+
},
|
|
434
|
+
getProviders() {
|
|
435
|
+
return providerListStatement.all().map(mapProviderRow);
|
|
436
|
+
},
|
|
437
|
+
getProviderById(providerId) {
|
|
438
|
+
const row = providerStatement.get(providerId);
|
|
439
|
+
return row ? mapProviderRow(row) : null;
|
|
440
|
+
},
|
|
441
|
+
getModelsByProviderId(providerId) {
|
|
442
|
+
return modelListStatement.all(providerId).map(mapModelRow);
|
|
443
|
+
},
|
|
444
|
+
getAuthMethodsByProviderId(providerId) {
|
|
445
|
+
return authListStatement.all(providerId).map(mapAuthRow);
|
|
446
|
+
},
|
|
447
|
+
getOAuthConfigByProviderId(providerId) {
|
|
448
|
+
const row = oauthConfigStatement.get(providerId);
|
|
449
|
+
return row ? mapOAuthRow(row) : null;
|
|
450
|
+
},
|
|
451
|
+
getProviderCatalog(providerId) {
|
|
452
|
+
const provider = this.getProviderById(providerId);
|
|
453
|
+
|
|
454
|
+
if (!provider) {
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const models = this.getModelsByProviderId(providerId);
|
|
459
|
+
const authMethods = this.getAuthMethodsByProviderId(providerId);
|
|
460
|
+
const oauth = this.getOAuthConfigByProviderId(providerId);
|
|
461
|
+
|
|
462
|
+
return {
|
|
463
|
+
...provider,
|
|
464
|
+
modelCount: models.length,
|
|
465
|
+
authCount: authMethods.length,
|
|
466
|
+
models,
|
|
467
|
+
authMethods,
|
|
468
|
+
oauth
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
let catalogStore;
|
|
475
|
+
|
|
476
|
+
export function getCatalogStore() {
|
|
477
|
+
if (!catalogStore) {
|
|
478
|
+
catalogStore = createCatalogStore();
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return catalogStore;
|
|
482
|
+
}
|