aicodeswitch 3.9.3 → 4.0.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.
@@ -1,1609 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __rest = (this && this.__rest) || function (s, e) {
12
- var t = {};
13
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
- t[p] = s[p];
15
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
- t[p[i]] = s[p[i]];
19
- }
20
- return t;
21
- };
22
- var __asyncValues = (this && this.__asyncValues) || function (o) {
23
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
24
- var m = o[Symbol.asyncIterator], i;
25
- return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
26
- function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
27
- function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
28
- };
29
- var __importDefault = (this && this.__importDefault) || function (mod) {
30
- return (mod && mod.__esModule) ? mod : { "default": mod };
31
- };
32
- Object.defineProperty(exports, "__esModule", { value: true });
33
- exports.DatabaseManager = void 0;
34
- const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
35
- const level_1 = require("level");
36
- const path_1 = __importDefault(require("path"));
37
- const crypto_1 = __importDefault(require("crypto"));
38
- const crypto_js_1 = __importDefault(require("crypto-js"));
39
- class DatabaseManager {
40
- constructor(dataPath) {
41
- Object.defineProperty(this, "db", {
42
- enumerable: true,
43
- configurable: true,
44
- writable: true,
45
- value: void 0
46
- });
47
- Object.defineProperty(this, "logDb", {
48
- enumerable: true,
49
- configurable: true,
50
- writable: true,
51
- value: void 0
52
- });
53
- Object.defineProperty(this, "errorLogDb", {
54
- enumerable: true,
55
- configurable: true,
56
- writable: true,
57
- value: void 0
58
- });
59
- Object.defineProperty(this, "blacklistDb", {
60
- enumerable: true,
61
- configurable: true,
62
- writable: true,
63
- value: void 0
64
- });
65
- // 缓存机制:总数查询缓存
66
- Object.defineProperty(this, "logsCountCache", {
67
- enumerable: true,
68
- configurable: true,
69
- writable: true,
70
- value: null
71
- });
72
- Object.defineProperty(this, "errorLogsCountCache", {
73
- enumerable: true,
74
- configurable: true,
75
- writable: true,
76
- value: null
77
- });
78
- Object.defineProperty(this, "CACHE_TTL", {
79
- enumerable: true,
80
- configurable: true,
81
- writable: true,
82
- value: 1000
83
- }); // 1秒缓存TTL
84
- this.db = new better_sqlite3_1.default(path_1.default.join(dataPath, 'app.db'));
85
- // 启用外键约束(SQLite 默认禁用,必须手动启用才能使 ON DELETE CASCADE 生效)
86
- this.db.pragma('foreign_keys = ON');
87
- // 配置数据库以确保实时读取最新数据
88
- // WAL 模式 + normal 同步模式: 提供最佳的并发性和实时性
89
- this.db.pragma('journal_mode = WAL');
90
- this.db.pragma('synchronous = NORMAL');
91
- // 确保读取操作不会看到旧的数据快照
92
- // 在 WAL 模式下,默认情况下读取操作不会阻塞写入操作
93
- // 设置 read_uncommitted = 0 确保读取最新提交的数据
94
- this.db.pragma('read_uncommitted = 0');
95
- this.logDb = new level_1.Level(path_1.default.join(dataPath, 'logs'), { valueEncoding: 'json' });
96
- this.errorLogDb = new level_1.Level(path_1.default.join(dataPath, 'error-logs'), { valueEncoding: 'json' });
97
- this.blacklistDb = new level_1.Level(path_1.default.join(dataPath, 'service-blacklist'), { valueEncoding: 'json' });
98
- }
99
- initialize() {
100
- return __awaiter(this, void 0, void 0, function* () {
101
- this.createTables();
102
- yield this.runMigrations();
103
- yield this.ensureDefaultConfig();
104
- });
105
- }
106
- runMigrations() {
107
- return __awaiter(this, void 0, void 0, function* () {
108
- const columns = this.db.pragma('table_info(api_services)');
109
- // 检查是否有旧的 max_output_tokens 字段(单值版本)
110
- const hasOldMaxOutputTokens = columns.some((col) => col.name === 'max_output_tokens');
111
- // 检查是否已经有新的 model_limits 字段(JSON 版本)
112
- const hasModelLimits = columns.some((col) => col.name === 'model_limits');
113
- if (!hasModelLimits) {
114
- if (hasOldMaxOutputTokens) {
115
- // 如果有旧字段,先删除旧字段(SQLite 不支持 ALTER TABLE DROP COLUMN,需要重建表)
116
- console.log('[DB] Running migration: Replacing max_output_tokens with model_limits');
117
- yield this.migrateMaxOutputTokensToModelLimits();
118
- }
119
- else {
120
- // 直接添加新字段
121
- console.log('[DB] Running migration: Adding model_limits column to api_services table');
122
- this.db.exec('ALTER TABLE api_services ADD COLUMN model_limits TEXT;');
123
- console.log('[DB] Migration completed: model_limits column added');
124
- }
125
- }
126
- // 检查vendors表是否有sort_order字段
127
- const vendorsColumns = this.db.pragma('table_info(vendors)');
128
- const hasSortOrder = vendorsColumns.some((col) => col.name === 'sort_order');
129
- if (!hasSortOrder) {
130
- console.log('[DB] Running migration: Adding sort_order column to vendors table');
131
- this.db.exec('ALTER TABLE vendors ADD COLUMN sort_order INTEGER DEFAULT 0;');
132
- console.log('[DB] Migration completed: sort_order column added to vendors');
133
- }
134
- // 检查rules表是否有token相关字段
135
- const rulesColumns = this.db.pragma('table_info(rules)');
136
- const hasTokenLimit = rulesColumns.some((col) => col.name === 'token_limit');
137
- const hasTotalTokensUsed = rulesColumns.some((col) => col.name === 'total_tokens_used');
138
- const hasResetInterval = rulesColumns.some((col) => col.name === 'reset_interval');
139
- const hasLastResetAt = rulesColumns.some((col) => col.name === 'last_reset_at');
140
- if (!hasTokenLimit) {
141
- console.log('[DB] Running migration: Adding token_limit column to rules table');
142
- this.db.exec('ALTER TABLE rules ADD COLUMN token_limit INTEGER;');
143
- console.log('[DB] Migration completed: token_limit column added');
144
- }
145
- if (!hasTotalTokensUsed) {
146
- console.log('[DB] Running migration: Adding total_tokens_used column to rules table');
147
- this.db.exec('ALTER TABLE rules ADD COLUMN total_tokens_used INTEGER DEFAULT 0;');
148
- console.log('[DB] Migration completed: total_tokens_used column added');
149
- }
150
- if (!hasResetInterval) {
151
- console.log('[DB] Running migration: Adding reset_interval column to rules table');
152
- this.db.exec('ALTER TABLE rules ADD COLUMN reset_interval INTEGER;');
153
- console.log('[DB] Migration completed: reset_interval column added');
154
- }
155
- if (!hasLastResetAt) {
156
- console.log('[DB] Running migration: Adding last_reset_at column to rules table');
157
- this.db.exec('ALTER TABLE rules ADD COLUMN last_reset_at INTEGER;');
158
- console.log('[DB] Migration completed: last_reset_at column added');
159
- }
160
- // 检查rules表是否有timeout字段
161
- const hasRuleTimeout = rulesColumns.some((col) => col.name === 'timeout');
162
- if (!hasRuleTimeout) {
163
- console.log('[DB] Running migration: Adding timeout column to rules table');
164
- this.db.exec('ALTER TABLE rules ADD COLUMN timeout INTEGER;');
165
- console.log('[DB] Migration completed: timeout column added to rules');
166
- }
167
- // 检查api_services表是否有timeout字段,如果有则移除
168
- const hasServiceTimeout = columns.some((col) => col.name === 'timeout');
169
- if (hasServiceTimeout) {
170
- console.log('[DB] Running migration: Removing timeout column from api_services table');
171
- yield this.migrateRemoveServiceTimeout();
172
- console.log('[DB] Migration completed: timeout column removed from api_services');
173
- }
174
- // 检查api_services表是否有enable_proxy字段
175
- const hasEnableProxy = columns.some((col) => col.name === 'enable_proxy');
176
- if (!hasEnableProxy) {
177
- console.log('[DB] Running migration: Adding enable_proxy column to api_services table');
178
- this.db.exec('ALTER TABLE api_services ADD COLUMN enable_proxy INTEGER DEFAULT 0;');
179
- console.log('[DB] Migration completed: enable_proxy column added');
180
- }
181
- // 检查rules表是否有请求次数相关字段
182
- const hasRequestCountLimit = rulesColumns.some((col) => col.name === 'request_count_limit');
183
- const hasTotalRequestsUsed = rulesColumns.some((col) => col.name === 'total_requests_used');
184
- const hasRequestResetInterval = rulesColumns.some((col) => col.name === 'request_reset_interval');
185
- const hasRequestLastResetAt = rulesColumns.some((col) => col.name === 'request_last_reset_at');
186
- if (!hasRequestCountLimit) {
187
- console.log('[DB] Running migration: Adding request_count_limit column to rules table');
188
- this.db.exec('ALTER TABLE rules ADD COLUMN request_count_limit INTEGER;');
189
- console.log('[DB] Migration completed: request_count_limit column added');
190
- }
191
- if (!hasTotalRequestsUsed) {
192
- console.log('[DB] Running migration: Adding total_requests_used column to rules table');
193
- this.db.exec('ALTER TABLE rules ADD COLUMN total_requests_used INTEGER DEFAULT 0;');
194
- console.log('[DB] Migration completed: total_requests_used column added');
195
- }
196
- if (!hasRequestResetInterval) {
197
- console.log('[DB] Running migration: Adding request_reset_interval column to rules table');
198
- this.db.exec('ALTER TABLE rules ADD COLUMN request_reset_interval INTEGER;');
199
- console.log('[DB] Migration completed: request_reset_interval column added');
200
- }
201
- if (!hasRequestLastResetAt) {
202
- console.log('[DB] Running migration: Adding request_last_reset_at column to rules table');
203
- this.db.exec('ALTER TABLE rules ADD COLUMN request_last_reset_at INTEGER;');
204
- console.log('[DB] Migration completed: request_last_reset_at column added');
205
- }
206
- // 检查rules表是否有request_reset_base_time字段
207
- const hasRequestResetBaseTime = rulesColumns.some((col) => col.name === 'request_reset_base_time');
208
- if (!hasRequestResetBaseTime) {
209
- console.log('[DB] Running migration: Adding request_reset_base_time column to rules table');
210
- this.db.exec('ALTER TABLE rules ADD COLUMN request_reset_base_time INTEGER;');
211
- console.log('[DB] Migration completed: request_reset_base_time column added');
212
- }
213
- // 检查rules表是否有token_reset_base_time字段
214
- const hasTokenResetBaseTime = rulesColumns.some((col) => col.name === 'token_reset_base_time');
215
- if (!hasTokenResetBaseTime) {
216
- console.log('[DB] Running migration: Adding token_reset_base_time column to rules table');
217
- this.db.exec('ALTER TABLE rules ADD COLUMN token_reset_base_time INTEGER;');
218
- console.log('[DB] Migration completed: token_reset_base_time column added');
219
- }
220
- // 检查api_services表是否有超量配置相关字段
221
- // Token超量配置
222
- const hasEnableTokenLimit = columns.some((col) => col.name === 'enable_token_limit');
223
- if (!hasEnableTokenLimit) {
224
- console.log('[DB] Running migration: Adding enable_token_limit column to api_services table');
225
- this.db.exec('ALTER TABLE api_services ADD COLUMN enable_token_limit INTEGER DEFAULT 0;');
226
- console.log('[DB] Migration completed: enable_token_limit column added');
227
- }
228
- const hasServiceTokenLimit = columns.some((col) => col.name === 'token_limit');
229
- if (!hasServiceTokenLimit) {
230
- console.log('[DB] Running migration: Adding token_limit column to api_services table');
231
- this.db.exec('ALTER TABLE api_services ADD COLUMN token_limit INTEGER;');
232
- console.log('[DB] Migration completed: token_limit column added');
233
- }
234
- const hasTokenResetInterval = columns.some((col) => col.name === 'token_reset_interval');
235
- if (!hasTokenResetInterval) {
236
- console.log('[DB] Running migration: Adding token_reset_interval column to api_services table');
237
- this.db.exec('ALTER TABLE api_services ADD COLUMN token_reset_interval INTEGER;');
238
- console.log('[DB] Migration completed: token_reset_interval column added');
239
- }
240
- const hasServiceTokenResetBaseTime = columns.some((col) => col.name === 'token_reset_base_time');
241
- if (!hasServiceTokenResetBaseTime) {
242
- console.log('[DB] Running migration: Adding token_reset_base_time column to api_services table');
243
- this.db.exec('ALTER TABLE api_services ADD COLUMN token_reset_base_time INTEGER;');
244
- console.log('[DB] Migration completed: token_reset_base_time column added');
245
- }
246
- // 请求次数超量配置
247
- const hasEnableRequestLimit = columns.some((col) => col.name === 'enable_request_limit');
248
- if (!hasEnableRequestLimit) {
249
- console.log('[DB] Running migration: Adding enable_request_limit column to api_services table');
250
- this.db.exec('ALTER TABLE api_services ADD COLUMN enable_request_limit INTEGER DEFAULT 0;');
251
- console.log('[DB] Migration completed: enable_request_limit column added');
252
- }
253
- const hasServiceRequestCountLimit = columns.some((col) => col.name === 'request_count_limit');
254
- if (!hasServiceRequestCountLimit) {
255
- console.log('[DB] Running migration: Adding request_count_limit column to api_services table');
256
- this.db.exec('ALTER TABLE api_services ADD COLUMN request_count_limit INTEGER;');
257
- console.log('[DB] Migration completed: request_count_limit column added');
258
- }
259
- const hasServiceRequestResetInterval = columns.some((col) => col.name === 'request_reset_interval');
260
- if (!hasServiceRequestResetInterval) {
261
- console.log('[DB] Running migration: Adding request_reset_interval column to api_services table');
262
- this.db.exec('ALTER TABLE api_services ADD COLUMN request_reset_interval INTEGER;');
263
- console.log('[DB] Migration completed: request_reset_interval column added');
264
- }
265
- const hasServiceRequestResetBaseTime = columns.some((col) => col.name === 'request_reset_base_time');
266
- if (!hasServiceRequestResetBaseTime) {
267
- console.log('[DB] Running migration: Adding request_reset_base_time column to api_services table');
268
- this.db.exec('ALTER TABLE api_services ADD COLUMN request_reset_base_time INTEGER;');
269
- console.log('[DB] Migration completed: request_reset_base_time column added');
270
- }
271
- // 检查api_services表是否有auth_type字段
272
- const hasAuthType = columns.some((col) => col.name === 'auth_type');
273
- if (!hasAuthType) {
274
- console.log('[DB] Running migration: Adding auth_type column to api_services table');
275
- this.db.exec('ALTER TABLE api_services ADD COLUMN auth_type TEXT DEFAULT NULL;');
276
- console.log('[DB] Migration completed: auth_type column added');
277
- }
278
- // 检查rules表是否有is_disabled字段(临时屏蔽功能)
279
- const hasIsDisabled = rulesColumns.some((col) => col.name === 'is_disabled');
280
- if (!hasIsDisabled) {
281
- console.log('[DB] Running migration: Adding is_disabled column to rules table');
282
- this.db.exec('ALTER TABLE rules ADD COLUMN is_disabled INTEGER DEFAULT 0;');
283
- console.log('[DB] Migration completed: is_disabled column added');
284
- }
285
- });
286
- }
287
- migrateMaxOutputTokensToModelLimits() {
288
- return __awaiter(this, void 0, void 0, function* () {
289
- // SQLite 不支持直接删除列,需要重建表
290
- // 先临时禁用外键约束
291
- this.db.pragma('foreign_keys = OFF');
292
- this.db.exec(`
293
- CREATE TABLE api_services_new (
294
- id TEXT PRIMARY KEY,
295
- vendor_id TEXT NOT NULL,
296
- name TEXT NOT NULL,
297
- api_url TEXT NOT NULL,
298
- api_key TEXT NOT NULL,
299
- timeout INTEGER,
300
- source_type TEXT,
301
- supported_models TEXT,
302
- model_limits TEXT,
303
- created_at INTEGER NOT NULL,
304
- updated_at INTEGER NOT NULL,
305
- FOREIGN KEY (vendor_id) REFERENCES vendors(id) ON DELETE CASCADE
306
- );
307
-
308
- INSERT INTO api_services_new
309
- SELECT
310
- id, vendor_id, name, api_url, api_key, timeout, source_type, supported_models,
311
- NULL, -- model_limits 设为 NULL,旧数据需要手动配置
312
- created_at, updated_at
313
- FROM api_services;
314
-
315
- DROP TABLE api_services;
316
- ALTER TABLE api_services_new RENAME TO api_services;
317
- `);
318
- // 重新启用外键约束
319
- this.db.pragma('foreign_keys = ON');
320
- console.log('[DB] Migration completed: Replaced max_output_tokens with model_limits');
321
- });
322
- }
323
- migrateRemoveServiceTimeout() {
324
- return __awaiter(this, void 0, void 0, function* () {
325
- // SQLite 不支持直接删除列,需要重建表
326
- this.db.pragma('foreign_keys = OFF');
327
- this.db.exec(`
328
- CREATE TABLE api_services_new (
329
- id TEXT PRIMARY KEY,
330
- vendor_id TEXT NOT NULL,
331
- name TEXT NOT NULL,
332
- api_url TEXT NOT NULL,
333
- api_key TEXT NOT NULL,
334
- source_type TEXT,
335
- supported_models TEXT,
336
- model_limits TEXT,
337
- created_at INTEGER NOT NULL,
338
- updated_at INTEGER NOT NULL,
339
- FOREIGN KEY (vendor_id) REFERENCES vendors(id) ON DELETE CASCADE
340
- );
341
-
342
- INSERT INTO api_services_new (id, vendor_id, name, api_url, api_key, source_type, supported_models, model_limits, created_at, updated_at)
343
- SELECT id, vendor_id, name, api_url, api_key, source_type, supported_models, model_limits, created_at, updated_at
344
- FROM api_services;
345
-
346
- DROP TABLE api_services;
347
- ALTER TABLE api_services_new RENAME TO api_services;
348
- `);
349
- this.db.pragma('foreign_keys = ON');
350
- });
351
- }
352
- createTables() {
353
- this.db.exec(`
354
- CREATE TABLE IF NOT EXISTS vendors (
355
- id TEXT PRIMARY KEY,
356
- name TEXT NOT NULL,
357
- description TEXT,
358
- sort_order INTEGER DEFAULT 0,
359
- created_at INTEGER NOT NULL,
360
- updated_at INTEGER NOT NULL
361
- );
362
-
363
- CREATE TABLE IF NOT EXISTS api_services (
364
- id TEXT PRIMARY KEY,
365
- vendor_id TEXT NOT NULL,
366
- name TEXT NOT NULL,
367
- api_url TEXT NOT NULL,
368
- api_key TEXT NOT NULL,
369
- source_type TEXT,
370
- supported_models TEXT,
371
- created_at INTEGER NOT NULL,
372
- updated_at INTEGER NOT NULL,
373
- FOREIGN KEY (vendor_id) REFERENCES vendors(id) ON DELETE CASCADE
374
- );
375
-
376
- CREATE TABLE IF NOT EXISTS routes (
377
- id TEXT PRIMARY KEY,
378
- name TEXT NOT NULL,
379
- description TEXT,
380
- target_type TEXT NOT NULL CHECK(target_type IN ('claude-code', 'codex')),
381
- is_active INTEGER DEFAULT 0,
382
- created_at INTEGER NOT NULL,
383
- updated_at INTEGER NOT NULL
384
- );
385
-
386
- CREATE TABLE IF NOT EXISTS rules (
387
- id TEXT PRIMARY KEY,
388
- route_id TEXT NOT NULL,
389
- content_type TEXT NOT NULL CHECK(content_type IN ('default', 'background', 'thinking', 'long-context', 'image-understanding', 'model-mapping', 'high-iq')),
390
- target_service_id TEXT NOT NULL,
391
- target_model TEXT,
392
- replaced_model TEXT,
393
- sort_order INTEGER DEFAULT 0,
394
- timeout INTEGER,
395
- token_limit INTEGER,
396
- total_tokens_used INTEGER DEFAULT 0,
397
- reset_interval INTEGER,
398
- last_reset_at INTEGER,
399
- token_reset_base_time INTEGER,
400
- request_count_limit INTEGER,
401
- total_requests_used INTEGER DEFAULT 0,
402
- request_reset_interval INTEGER,
403
- request_last_reset_at INTEGER,
404
- request_reset_base_time INTEGER,
405
- is_disabled INTEGER DEFAULT 0,
406
- created_at INTEGER NOT NULL,
407
- updated_at INTEGER NOT NULL,
408
- FOREIGN KEY (route_id) REFERENCES routes(id) ON DELETE CASCADE,
409
- FOREIGN KEY (target_service_id) REFERENCES api_services(id) ON DELETE CASCADE
410
- );
411
-
412
- CREATE TABLE IF NOT EXISTS config (
413
- key TEXT PRIMARY KEY,
414
- value TEXT NOT NULL
415
- );
416
-
417
- CREATE TABLE IF NOT EXISTS sessions (
418
- id TEXT PRIMARY KEY,
419
- target_type TEXT NOT NULL CHECK(target_type IN ('claude-code', 'codex')),
420
- title TEXT,
421
- first_request_at INTEGER NOT NULL,
422
- last_request_at INTEGER NOT NULL,
423
- request_count INTEGER DEFAULT 1,
424
- total_tokens INTEGER DEFAULT 0,
425
- vendor_id TEXT,
426
- vendor_name TEXT,
427
- service_id TEXT,
428
- service_name TEXT,
429
- model TEXT
430
- );
431
- `);
432
- }
433
- ensureDefaultConfig() {
434
- return __awaiter(this, void 0, void 0, function* () {
435
- const config = this.db.prepare('SELECT * FROM config WHERE key = ?').get('app_config');
436
- if (!config) {
437
- const defaultConfig = {
438
- enableLogging: true,
439
- logRetentionDays: 30,
440
- maxLogSize: 100000,
441
- apiKey: '',
442
- enableFailover: true, // 默认启用智能故障切换
443
- proxyEnabled: false, // 默认不启用代理
444
- proxyUrl: '',
445
- proxyUsername: '',
446
- proxyPassword: '',
447
- };
448
- this.db.prepare('INSERT INTO config (key, value) VALUES (?, ?)').run('app_config', JSON.stringify(defaultConfig));
449
- }
450
- });
451
- }
452
- // Vendor operations
453
- getVendors() {
454
- const rows = this.db.prepare('SELECT * FROM vendors ORDER BY sort_order DESC, created_at DESC').all();
455
- return rows.map((row) => {
456
- const vendorId = row.id;
457
- // 获取该供应商的所有服务
458
- const services = this.getAPIServices(vendorId);
459
- // 移除服务中的 vendorId 字段
460
- const servicesWithoutVendorId = services.map((_a) => {
461
- var { vendorId } = _a, service = __rest(_a, ["vendorId"]);
462
- return service;
463
- });
464
- return {
465
- id: row.id,
466
- name: row.name,
467
- description: row.description,
468
- sortOrder: row.sort_order,
469
- services: servicesWithoutVendorId, // 添加嵌套的 services 数组
470
- createdAt: row.created_at,
471
- updatedAt: row.updated_at,
472
- };
473
- });
474
- }
475
- createVendor(vendor) {
476
- const id = crypto_1.default.randomUUID();
477
- const now = Date.now();
478
- this.db
479
- .prepare('INSERT INTO vendors (id, name, description, sort_order, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)')
480
- .run(id, vendor.name, vendor.description || null, vendor.sortOrder || 0, now, now);
481
- return Object.assign(Object.assign({}, vendor), { id, createdAt: now, updatedAt: now });
482
- }
483
- updateVendor(id, vendor) {
484
- const now = Date.now();
485
- const result = this.db
486
- .prepare('UPDATE vendors SET name = ?, description = ?, sort_order = ?, updated_at = ? WHERE id = ?')
487
- .run(vendor.name, vendor.description || null, vendor.sortOrder !== undefined ? vendor.sortOrder : 0, now, id);
488
- return result.changes > 0;
489
- }
490
- deleteVendor(id) {
491
- const result = this.db.prepare('DELETE FROM vendors WHERE id = ?').run(id);
492
- return result.changes > 0;
493
- }
494
- // API Service operations
495
- getAPIServices(vendorId) {
496
- // 每次都重新准备语句以确保获取最新数据
497
- const query = vendorId
498
- ? 'SELECT * FROM api_services WHERE vendor_id = ? ORDER BY created_at DESC'
499
- : 'SELECT * FROM api_services ORDER BY created_at DESC';
500
- // 不缓存 prepared statement,每次重新创建以确保读取最新数据
501
- const stmt = this.db.prepare(query);
502
- const rows = vendorId ? stmt.all(vendorId) : stmt.all();
503
- const services = rows.map((row) => ({
504
- id: row.id,
505
- vendorId: row.vendor_id,
506
- name: row.name,
507
- apiUrl: row.api_url,
508
- apiKey: row.api_key,
509
- sourceType: row.source_type,
510
- authType: row.auth_type,
511
- supportedModels: row.supported_models ? row.supported_models.split(',').map((model) => model.trim()).filter((model) => model.length > 0) : undefined,
512
- modelLimits: row.model_limits ? JSON.parse(row.model_limits) : undefined,
513
- enableProxy: row.enable_proxy === 1,
514
- // Token超量配置
515
- enableTokenLimit: row.enable_token_limit === 1,
516
- tokenLimit: row.token_limit,
517
- tokenResetInterval: row.token_reset_interval,
518
- tokenResetBaseTime: row.token_reset_base_time,
519
- // 请求次数超量配置
520
- enableRequestLimit: row.enable_request_limit === 1,
521
- requestCountLimit: row.request_count_limit,
522
- requestResetInterval: row.request_reset_interval,
523
- requestResetBaseTime: row.request_reset_base_time,
524
- createdAt: row.created_at,
525
- updatedAt: row.updated_at,
526
- }));
527
- // 调试日志: 记录读取的服务信息
528
- if (process.env.NODE_ENV === 'development' && services.length > 0) {
529
- console.log(`[DB] Read ${services.length} services from database, first service: ${services[0].name} -> ${services[0].apiUrl}`);
530
- }
531
- return services;
532
- }
533
- createAPIService(service) {
534
- const id = crypto_1.default.randomUUID();
535
- const now = Date.now();
536
- this.db
537
- .prepare('INSERT INTO api_services (id, vendor_id, name, api_url, api_key, source_type, auth_type, supported_models, model_limits, enable_proxy, enable_token_limit, token_limit, token_reset_interval, token_reset_base_time, enable_request_limit, request_count_limit, request_reset_interval, request_reset_base_time, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
538
- .run(id, service.vendorId, service.name, service.apiUrl, service.apiKey, service.sourceType || null, service.authType || null, service.supportedModels ? service.supportedModels.join(',') : null, service.modelLimits ? JSON.stringify(service.modelLimits) : null, service.enableProxy ? 1 : 0, service.enableTokenLimit ? 1 : 0, service.tokenLimit || null, service.tokenResetInterval || null, service.tokenResetBaseTime || null, service.enableRequestLimit ? 1 : 0, service.requestCountLimit || null, service.requestResetInterval || null, service.requestResetBaseTime || null, now, now);
539
- return Object.assign(Object.assign({}, service), { id, createdAt: now, updatedAt: now });
540
- }
541
- updateAPIService(id, service) {
542
- const now = Date.now();
543
- const result = this.db
544
- .prepare('UPDATE api_services SET vendor_id = ?, name = ?, api_url = ?, api_key = ?, source_type = ?, auth_type = ?, supported_models = ?, model_limits = ?, enable_proxy = ?, enable_token_limit = ?, token_limit = ?, token_reset_interval = ?, token_reset_base_time = ?, enable_request_limit = ?, request_count_limit = ?, request_reset_interval = ?, request_reset_base_time = ?, updated_at = ? WHERE id = ?')
545
- .run(service.vendorId, service.name, service.apiUrl, service.apiKey, service.sourceType || null, service.authType || null, service.supportedModels ? service.supportedModels.join(',') : null, service.modelLimits ? JSON.stringify(service.modelLimits) : null, service.enableProxy !== undefined ? (service.enableProxy ? 1 : 0) : null, service.enableTokenLimit !== undefined ? (service.enableTokenLimit ? 1 : 0) : null, service.tokenLimit !== undefined ? service.tokenLimit : null, service.tokenResetInterval !== undefined ? service.tokenResetInterval : null, service.tokenResetBaseTime !== undefined ? service.tokenResetBaseTime : null, service.enableRequestLimit !== undefined ? (service.enableRequestLimit ? 1 : 0) : null, service.requestCountLimit !== undefined ? service.requestCountLimit : null, service.requestResetInterval !== undefined ? service.requestResetInterval : null, service.requestResetBaseTime !== undefined ? service.requestResetBaseTime : null, now, id);
546
- // 调试日志: 记录更新操作
547
- if (result.changes > 0 && process.env.NODE_ENV === 'development') {
548
- console.log(`[DB] Updated service ${id}: ${service.name} -> ${service.apiUrl}`);
549
- }
550
- // 如果更新成功,检查是否需要同步更新关联规则的超量限制
551
- if (result.changes > 0) {
552
- this.syncRulesWithServiceLimits(id, service);
553
- }
554
- return result.changes > 0;
555
- }
556
- /**
557
- * 同步更新使用该服务的规则的超量限制
558
- * 当API服务的超量限制修改时,自动更新所有使用该服务的规则
559
- */
560
- syncRulesWithServiceLimits(serviceId, service) {
561
- // 获取所有使用该服务的规则
562
- const rules = this.db.prepare('SELECT id FROM rules WHERE target_service_id = ?').all(serviceId);
563
- if (rules.length === 0) {
564
- return; // 没有规则使用此服务,无需同步
565
- }
566
- const now = Date.now();
567
- const ruleIds = rules.map(r => r.id);
568
- // Token超量限制同步
569
- if (service.enableTokenLimit !== undefined || service.tokenLimit !== undefined ||
570
- service.tokenResetInterval !== undefined || service.tokenResetBaseTime !== undefined) {
571
- // 获取当前服务的最新配置
572
- const currentService = this.db.prepare('SELECT enable_token_limit, token_limit, token_reset_interval, token_reset_base_time FROM api_services WHERE id = ?').get(serviceId);
573
- if (currentService && currentService.enable_token_limit === 1) {
574
- // 启用了Token超量限制,同步到所有规则
575
- this.db.prepare('UPDATE rules SET token_limit = ?, reset_interval = ?, token_reset_base_time = ?, updated_at = ? WHERE target_service_id = ?').run(currentService.token_limit, currentService.token_reset_interval, currentService.token_reset_base_time, now, serviceId);
576
- console.log(`[DB] Synced token limits for ${ruleIds.length} rule(s) using service ${serviceId}`);
577
- }
578
- }
579
- // 请求次数超量限制同步
580
- if (service.enableRequestLimit !== undefined || service.requestCountLimit !== undefined ||
581
- service.requestResetInterval !== undefined || service.requestResetBaseTime !== undefined) {
582
- // 获取当前服务的最新配置
583
- const currentService = this.db.prepare('SELECT enable_request_limit, request_count_limit, request_reset_interval, request_reset_base_time FROM api_services WHERE id = ?').get(serviceId);
584
- if (currentService && currentService.enable_request_limit === 1) {
585
- // 启用了请求次数超量限制,同步到所有规则
586
- this.db.prepare('UPDATE rules SET request_count_limit = ?, request_reset_interval = ?, request_reset_base_time = ?, updated_at = ? WHERE target_service_id = ?').run(currentService.request_count_limit, currentService.request_reset_interval, currentService.request_reset_base_time, now, serviceId);
587
- console.log(`[DB] Synced request count limits for ${ruleIds.length} rule(s) using service ${serviceId}`);
588
- }
589
- }
590
- }
591
- deleteAPIService(id) {
592
- const result = this.db.prepare('DELETE FROM api_services WHERE id = ?').run(id);
593
- return result.changes > 0;
594
- }
595
- // Route operations
596
- getRoutes() {
597
- const rows = this.db.prepare('SELECT * FROM routes ORDER BY created_at DESC').all();
598
- return rows.map((row) => ({
599
- id: row.id,
600
- name: row.name,
601
- description: row.description,
602
- targetType: row.target_type,
603
- isActive: row.is_active === 1,
604
- createdAt: row.created_at,
605
- updatedAt: row.updated_at,
606
- }));
607
- }
608
- createRoute(route) {
609
- const id = crypto_1.default.randomUUID();
610
- const now = Date.now();
611
- this.db
612
- .prepare('INSERT INTO routes (id, name, description, target_type, is_active, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)')
613
- .run(id, route.name, route.description || null, route.targetType, route.isActive ? 1 : 0, now, now);
614
- return Object.assign(Object.assign({}, route), { id, createdAt: now, updatedAt: now });
615
- }
616
- updateRoute(id, route) {
617
- const now = Date.now();
618
- const result = this.db
619
- .prepare('UPDATE routes SET name = ?, description = ?, target_type = ?, updated_at = ? WHERE id = ?')
620
- .run(route.name, route.description || null, route.targetType, now, id);
621
- return result.changes > 0;
622
- }
623
- deleteRoute(id) {
624
- const result = this.db.prepare('DELETE FROM routes WHERE id = ?').run(id);
625
- return result.changes > 0;
626
- }
627
- activateRoute(id) {
628
- const route = this.getRoutes().find(r => r.id === id);
629
- if (route) {
630
- this.db.prepare('UPDATE routes SET is_active = 0 WHERE target_type = ?').run(route.targetType);
631
- const result = this.db.prepare('UPDATE routes SET is_active = 1 WHERE id = ?').run(id);
632
- return result.changes > 0;
633
- }
634
- return false;
635
- }
636
- deactivateRoute(id) {
637
- const result = this.db.prepare('UPDATE routes SET is_active = 0 WHERE id = ?').run(id);
638
- return result.changes > 0;
639
- }
640
- deactivateAllRoutes() {
641
- const result = this.db.prepare('UPDATE routes SET is_active = 0 WHERE is_active = 1').run();
642
- return result.changes;
643
- }
644
- // Rule operations
645
- getRules(routeId) {
646
- const query = routeId
647
- ? 'SELECT * FROM rules WHERE route_id = ? ORDER BY sort_order DESC, created_at DESC'
648
- : 'SELECT * FROM rules ORDER BY sort_order DESC, created_at DESC';
649
- const stmt = routeId ? this.db.prepare(query).bind(routeId) : this.db.prepare(query);
650
- const rows = stmt.all();
651
- return rows.map((row) => ({
652
- id: row.id,
653
- routeId: row.route_id,
654
- contentType: row.content_type,
655
- targetServiceId: row.target_service_id,
656
- targetModel: row.target_model,
657
- replacedModel: row.replaced_model,
658
- sortOrder: row.sort_order,
659
- timeout: row.timeout,
660
- tokenLimit: row.token_limit,
661
- totalTokensUsed: row.total_tokens_used,
662
- resetInterval: row.reset_interval,
663
- lastResetAt: row.last_reset_at,
664
- tokenResetBaseTime: row.token_reset_base_time,
665
- requestCountLimit: row.request_count_limit,
666
- totalRequestsUsed: row.total_requests_used,
667
- requestResetInterval: row.request_reset_interval,
668
- requestLastResetAt: row.request_last_reset_at,
669
- requestResetBaseTime: row.request_reset_base_time,
670
- isDisabled: row.is_disabled === 1,
671
- createdAt: row.created_at,
672
- updatedAt: row.updated_at,
673
- }));
674
- }
675
- getRule(id) {
676
- const row = this.db.prepare('SELECT * FROM rules WHERE id = ?').get(id);
677
- if (!row)
678
- return undefined;
679
- return {
680
- id: row.id,
681
- routeId: row.route_id,
682
- contentType: row.content_type,
683
- targetServiceId: row.target_service_id,
684
- targetModel: row.target_model,
685
- replacedModel: row.replaced_model,
686
- sortOrder: row.sort_order,
687
- timeout: row.timeout,
688
- tokenLimit: row.token_limit,
689
- totalTokensUsed: row.total_tokens_used,
690
- resetInterval: row.reset_interval,
691
- lastResetAt: row.last_reset_at,
692
- tokenResetBaseTime: row.token_reset_base_time,
693
- requestCountLimit: row.request_count_limit,
694
- totalRequestsUsed: row.total_requests_used,
695
- requestResetInterval: row.request_reset_interval,
696
- requestLastResetAt: row.request_last_reset_at,
697
- requestResetBaseTime: row.request_reset_base_time,
698
- isDisabled: row.is_disabled === 1,
699
- createdAt: row.created_at,
700
- updatedAt: row.updated_at,
701
- };
702
- }
703
- createRule(route) {
704
- const id = crypto_1.default.randomUUID();
705
- const now = Date.now();
706
- this.db
707
- .prepare('INSERT INTO rules (id, route_id, content_type, target_service_id, target_model, replaced_model, sort_order, timeout, token_limit, total_tokens_used, reset_interval, last_reset_at, token_reset_base_time, request_count_limit, total_requests_used, request_reset_interval, request_last_reset_at, request_reset_base_time, is_disabled, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
708
- .run(id, route.routeId, route.contentType, route.targetServiceId, route.targetModel || null, route.replacedModel || null, route.sortOrder || 0, route.timeout || null, route.tokenLimit || null, route.totalTokensUsed || 0, route.resetInterval || null, route.lastResetAt || null, route.tokenResetBaseTime || null, route.requestCountLimit || null, route.totalRequestsUsed || 0, route.requestResetInterval || null, route.requestLastResetAt || null, route.requestResetBaseTime || null, route.isDisabled ? 1 : 0, now, now);
709
- return Object.assign(Object.assign({}, route), { id, createdAt: now, updatedAt: now });
710
- }
711
- updateRule(id, route) {
712
- const now = Date.now();
713
- const result = this.db
714
- .prepare('UPDATE rules SET content_type = ?, target_service_id = ?, target_model = ?, replaced_model = ?, sort_order = ?, timeout = ?, token_limit = ?, reset_interval = ?, token_reset_base_time = ?, request_count_limit = ?, request_reset_interval = ?, request_reset_base_time = ?, is_disabled = ?, updated_at = ? WHERE id = ?')
715
- .run(route.contentType, route.targetServiceId, route.targetModel || null, route.replacedModel || null, route.sortOrder || 0, route.timeout !== undefined ? route.timeout : null, route.tokenLimit !== undefined ? route.tokenLimit : null, route.resetInterval !== undefined ? route.resetInterval : null, route.tokenResetBaseTime !== undefined ? route.tokenResetBaseTime : null, route.requestCountLimit !== undefined ? route.requestCountLimit : null, route.requestResetInterval !== undefined ? route.requestResetInterval : null, route.requestResetBaseTime !== undefined ? route.requestResetBaseTime : null, route.isDisabled !== undefined ? (route.isDisabled ? 1 : 0) : null, now, id);
716
- return result.changes > 0;
717
- }
718
- deleteRule(id) {
719
- const result = this.db.prepare('DELETE FROM rules WHERE id = ?').run(id);
720
- return result.changes > 0;
721
- }
722
- /**
723
- * 切换规则的临时屏蔽状态
724
- * @param ruleId 规则ID
725
- * @returns 是否成功
726
- */
727
- toggleRuleDisabled(ruleId) {
728
- const rule = this.getRule(ruleId);
729
- if (!rule) {
730
- return { success: false, isDisabled: false };
731
- }
732
- const now = Date.now();
733
- const newDisabledState = !rule.isDisabled;
734
- const result = this.db
735
- .prepare('UPDATE rules SET is_disabled = ?, updated_at = ? WHERE id = ?')
736
- .run(newDisabledState ? 1 : 0, now, ruleId);
737
- return {
738
- success: result.changes > 0,
739
- isDisabled: newDisabledState
740
- };
741
- }
742
- /**
743
- * 增加规则的token使用量
744
- * @param ruleId 规则ID
745
- * @param tokensUsed 使用的token数量
746
- * @returns 是否成功
747
- */
748
- incrementRuleTokenUsage(ruleId, tokensUsed) {
749
- const result = this.db
750
- .prepare('UPDATE rules SET total_tokens_used = total_tokens_used + ? WHERE id = ?')
751
- .run(tokensUsed, ruleId);
752
- return result.changes > 0;
753
- }
754
- /**
755
- * 重置规则的token使用量
756
- * @param ruleId 规则ID
757
- * @returns 是否成功
758
- */
759
- resetRuleTokenUsage(ruleId) {
760
- const now = Date.now();
761
- const result = this.db
762
- .prepare('UPDATE rules SET total_tokens_used = 0, last_reset_at = ? WHERE id = ?')
763
- .run(now, ruleId);
764
- return result.changes > 0;
765
- }
766
- /**
767
- * 检查并重置到期的规则
768
- * 如果规则设置了reset_interval且已经到了重置时间,则自动重置token使用量
769
- * @param ruleId 规则ID
770
- * @returns 是否进行了重置
771
- */
772
- checkAndResetRuleIfNeeded(ruleId) {
773
- const rule = this.db
774
- .prepare('SELECT reset_interval, last_reset_at, token_reset_base_time FROM rules WHERE id = ?')
775
- .get(ruleId);
776
- if (!rule || !rule.reset_interval) {
777
- return false; // 没有设置重置间隔
778
- }
779
- const now = Date.now();
780
- const resetIntervalMs = rule.reset_interval * 60 * 60 * 1000; // 小时转毫秒
781
- const baseTime = rule.token_reset_base_time;
782
- const lastResetAt = rule.last_reset_at || 0;
783
- // 场景1: 设置了时间基点
784
- if (baseTime) {
785
- if (now >= baseTime) {
786
- this.resetRuleTokenUsageWithBaseTime(ruleId, baseTime);
787
- return true;
788
- }
789
- return false;
790
- }
791
- // 场景2: 未设置时间基点,使用原始逻辑(向后兼容)
792
- if (now - lastResetAt >= resetIntervalMs) {
793
- this.resetRuleTokenUsage(ruleId);
794
- return true;
795
- }
796
- return false;
797
- }
798
- /**
799
- * 重置规则的Token使用量(带时间基点更新)
800
- */
801
- resetRuleTokenUsageWithBaseTime(ruleId, currentBaseTime) {
802
- const now = Date.now();
803
- const rule = this.db
804
- .prepare('SELECT reset_interval FROM rules WHERE id = ?')
805
- .get(ruleId);
806
- if (!rule || !rule.reset_interval) {
807
- return false;
808
- }
809
- const resetIntervalMs = rule.reset_interval * 60 * 60 * 1000;
810
- // 计算下一个时间基点
811
- let nextBaseTime = currentBaseTime;
812
- while (nextBaseTime <= now) {
813
- nextBaseTime += resetIntervalMs;
814
- }
815
- const result = this.db
816
- .prepare('UPDATE rules SET total_tokens_used = 0, last_reset_at = ?, token_reset_base_time = ? WHERE id = ?')
817
- .run(now, nextBaseTime, ruleId);
818
- return result.changes > 0;
819
- }
820
- /**
821
- * 增加规则的请求次数
822
- * @param ruleId 规则ID
823
- * @param count 增加的次数
824
- * @returns 是否成功
825
- */
826
- incrementRuleRequestCount(ruleId, count) {
827
- const result = this.db
828
- .prepare('UPDATE rules SET total_requests_used = total_requests_used + ? WHERE id = ?')
829
- .run(count, ruleId);
830
- return result.changes > 0;
831
- }
832
- /**
833
- * 重置规则的请求次数
834
- * @param ruleId 规则ID
835
- * @returns 是否成功
836
- */
837
- resetRuleRequestCount(ruleId) {
838
- const now = Date.now();
839
- const result = this.db
840
- .prepare('UPDATE rules SET total_requests_used = 0, request_last_reset_at = ? WHERE id = ?')
841
- .run(now, ruleId);
842
- return result.changes > 0;
843
- }
844
- /**
845
- * 检查并重置到期的规则(请求次数)
846
- * 如果规则设置了request_reset_interval且已经到了重置时间,则自动重置请求次数
847
- * @param ruleId 规则ID
848
- * @returns 是否进行了重置
849
- */
850
- checkAndResetRequestCountIfNeeded(ruleId) {
851
- const rule = this.db
852
- .prepare('SELECT request_reset_interval, request_last_reset_at, request_reset_base_time FROM rules WHERE id = ?')
853
- .get(ruleId);
854
- if (!rule || !rule.request_reset_interval) {
855
- return false; // 没有设置重置间隔
856
- }
857
- const now = Date.now();
858
- const resetIntervalMs = rule.request_reset_interval * 60 * 60 * 1000; // 小时转毫秒
859
- const baseTime = rule.request_reset_base_time;
860
- const lastResetAt = rule.request_last_reset_at || 0;
861
- // 场景1: 设置了时间基点
862
- if (baseTime) {
863
- if (now >= baseTime) {
864
- this.resetRuleRequestCountWithBaseTime(ruleId, baseTime);
865
- return true;
866
- }
867
- return false;
868
- }
869
- // 场景2: 未设置时间基点,使用原始逻辑(向后兼容)
870
- if (now - lastResetAt >= resetIntervalMs) {
871
- this.resetRuleRequestCount(ruleId);
872
- return true;
873
- }
874
- return false;
875
- }
876
- /**
877
- * 重置规则的请求次数(带时间基点更新)
878
- */
879
- resetRuleRequestCountWithBaseTime(ruleId, currentBaseTime) {
880
- const now = Date.now();
881
- const rule = this.db
882
- .prepare('SELECT request_reset_interval FROM rules WHERE id = ?')
883
- .get(ruleId);
884
- if (!rule || !rule.request_reset_interval) {
885
- return false;
886
- }
887
- const resetIntervalMs = rule.request_reset_interval * 60 * 60 * 1000;
888
- // 计算下一个时间基点
889
- let nextBaseTime = currentBaseTime;
890
- while (nextBaseTime <= now) {
891
- nextBaseTime += resetIntervalMs;
892
- }
893
- const result = this.db
894
- .prepare('UPDATE rules SET total_requests_used = 0, request_last_reset_at = ?, request_reset_base_time = ? WHERE id = ?')
895
- .run(now, nextBaseTime, ruleId);
896
- return result.changes > 0;
897
- }
898
- // Log operations
899
- addLog(log) {
900
- return __awaiter(this, void 0, void 0, function* () {
901
- const id = crypto_1.default.randomUUID();
902
- yield this.logDb.put(id, JSON.stringify(Object.assign(Object.assign({}, log), { id })));
903
- // 清除缓存
904
- this.logsCountCache = null;
905
- });
906
- }
907
- getLogs() {
908
- return __awaiter(this, arguments, void 0, function* (limit = 100, offset = 0) {
909
- var _a, e_1, _b, _c;
910
- const allLogs = [];
911
- try {
912
- for (var _d = true, _e = __asyncValues(this.logDb.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
913
- _c = _f.value;
914
- _d = false;
915
- const [, value] = _c;
916
- allLogs.push(JSON.parse(value));
917
- }
918
- }
919
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
920
- finally {
921
- try {
922
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
923
- }
924
- finally { if (e_1) throw e_1.error; }
925
- }
926
- // Sort by timestamp in descending order (newest first)
927
- allLogs.sort((a, b) => b.timestamp - a.timestamp);
928
- // Apply offset and limit
929
- return allLogs.slice(offset, offset + limit);
930
- });
931
- }
932
- clearLogs() {
933
- return __awaiter(this, void 0, void 0, function* () {
934
- yield this.logDb.clear();
935
- // 清除缓存
936
- this.logsCountCache = null;
937
- });
938
- }
939
- // Error log operations
940
- addErrorLog(log) {
941
- return __awaiter(this, void 0, void 0, function* () {
942
- const id = crypto_1.default.randomUUID();
943
- yield this.errorLogDb.put(id, JSON.stringify(Object.assign(Object.assign({}, log), { id })));
944
- // 清除缓存
945
- this.errorLogsCountCache = null;
946
- });
947
- }
948
- getErrorLogs() {
949
- return __awaiter(this, arguments, void 0, function* (limit = 100, offset = 0) {
950
- var _a, e_2, _b, _c;
951
- const allLogs = [];
952
- try {
953
- for (var _d = true, _e = __asyncValues(this.errorLogDb.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
954
- _c = _f.value;
955
- _d = false;
956
- const [, value] = _c;
957
- allLogs.push(JSON.parse(value));
958
- }
959
- }
960
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
961
- finally {
962
- try {
963
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
964
- }
965
- finally { if (e_2) throw e_2.error; }
966
- }
967
- // Sort by timestamp in descending order (newest first)
968
- allLogs.sort((a, b) => b.timestamp - a.timestamp);
969
- // Apply offset and limit
970
- return allLogs.slice(offset, offset + limit);
971
- });
972
- }
973
- clearErrorLogs() {
974
- return __awaiter(this, void 0, void 0, function* () {
975
- yield this.errorLogDb.clear();
976
- // 清除缓存
977
- this.errorLogsCountCache = null;
978
- });
979
- }
980
- /**
981
- * 获取请求日志总数(带缓存)
982
- */
983
- getLogsCount() {
984
- return __awaiter(this, void 0, void 0, function* () {
985
- var _a, e_3, _b, _c;
986
- const now = Date.now();
987
- if (this.logsCountCache && now - this.logsCountCache.timestamp < this.CACHE_TTL) {
988
- return this.logsCountCache.count;
989
- }
990
- let count = 0;
991
- try {
992
- for (var _d = true, _e = __asyncValues(this.logDb.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
993
- _c = _f.value;
994
- _d = false;
995
- const _ = _c;
996
- count++;
997
- }
998
- }
999
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
1000
- finally {
1001
- try {
1002
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
1003
- }
1004
- finally { if (e_3) throw e_3.error; }
1005
- }
1006
- this.logsCountCache = { count, timestamp: now };
1007
- return count;
1008
- });
1009
- }
1010
- /**
1011
- * 获取错误日志总数(带缓存)
1012
- */
1013
- getErrorLogsCount() {
1014
- return __awaiter(this, void 0, void 0, function* () {
1015
- var _a, e_4, _b, _c;
1016
- const now = Date.now();
1017
- if (this.errorLogsCountCache && now - this.errorLogsCountCache.timestamp < this.CACHE_TTL) {
1018
- return this.errorLogsCountCache.count;
1019
- }
1020
- let count = 0;
1021
- try {
1022
- for (var _d = true, _e = __asyncValues(this.errorLogDb.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
1023
- _c = _f.value;
1024
- _d = false;
1025
- const _ = _c;
1026
- count++;
1027
- }
1028
- }
1029
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
1030
- finally {
1031
- try {
1032
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
1033
- }
1034
- finally { if (e_4) throw e_4.error; }
1035
- }
1036
- this.errorLogsCountCache = { count, timestamp: now };
1037
- return count;
1038
- });
1039
- }
1040
- // Service blacklist operations
1041
- isServiceBlacklisted(serviceId, routeId, contentType) {
1042
- return __awaiter(this, void 0, void 0, function* () {
1043
- const key = `${routeId}:${contentType}:${serviceId}`;
1044
- try {
1045
- const value = yield this.blacklistDb.get(key);
1046
- const entry = JSON.parse(value);
1047
- // 检查是否过期
1048
- if (Date.now() > entry.expiresAt) {
1049
- // 已过期,删除记录
1050
- yield this.blacklistDb.del(key);
1051
- return false;
1052
- }
1053
- return true;
1054
- }
1055
- catch (error) {
1056
- if (error.code === 'LEVEL_NOT_FOUND') {
1057
- return false;
1058
- }
1059
- throw error;
1060
- }
1061
- });
1062
- }
1063
- addToBlacklist(serviceId, routeId, contentType, errorMessage, statusCode, errorType) {
1064
- return __awaiter(this, void 0, void 0, function* () {
1065
- const key = `${routeId}:${contentType}:${serviceId}`;
1066
- const now = Date.now();
1067
- try {
1068
- // 尝试读取现有记录
1069
- const existing = yield this.blacklistDb.get(key);
1070
- const entry = JSON.parse(existing);
1071
- // 更新现有记录
1072
- entry.blacklistedAt = now;
1073
- entry.expiresAt = now + 10 * 60 * 1000; // 10分钟
1074
- entry.errorCount++;
1075
- entry.lastError = errorMessage;
1076
- entry.lastStatusCode = statusCode;
1077
- entry.errorType = errorType;
1078
- yield this.blacklistDb.put(key, JSON.stringify(entry));
1079
- }
1080
- catch (error) {
1081
- if (error.code === 'LEVEL_NOT_FOUND') {
1082
- // 创建新记录
1083
- const entry = {
1084
- serviceId,
1085
- routeId,
1086
- contentType,
1087
- blacklistedAt: now,
1088
- expiresAt: now + 10 * 60 * 1000,
1089
- errorCount: 1,
1090
- lastError: errorMessage,
1091
- lastStatusCode: statusCode,
1092
- errorType,
1093
- };
1094
- yield this.blacklistDb.put(key, JSON.stringify(entry));
1095
- }
1096
- else {
1097
- throw error;
1098
- }
1099
- }
1100
- });
1101
- }
1102
- removeFromBlacklist(serviceId, routeId, contentType) {
1103
- return __awaiter(this, void 0, void 0, function* () {
1104
- const key = `${routeId}:${contentType}:${serviceId}`;
1105
- yield this.blacklistDb.del(key);
1106
- });
1107
- }
1108
- cleanupExpiredBlacklist() {
1109
- return __awaiter(this, void 0, void 0, function* () {
1110
- var _a, e_5, _b, _c;
1111
- const now = Date.now();
1112
- let count = 0;
1113
- try {
1114
- for (var _d = true, _e = __asyncValues(this.blacklistDb.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
1115
- _c = _f.value;
1116
- _d = false;
1117
- const [key, value] = _c;
1118
- const entry = JSON.parse(value);
1119
- if (now > entry.expiresAt) {
1120
- yield this.blacklistDb.del(key);
1121
- count++;
1122
- }
1123
- }
1124
- }
1125
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
1126
- finally {
1127
- try {
1128
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
1129
- }
1130
- finally { if (e_5) throw e_5.error; }
1131
- }
1132
- return count;
1133
- });
1134
- }
1135
- // Config operations
1136
- getConfig() {
1137
- const row = this.db.prepare('SELECT value FROM config WHERE key = ?').get('app_config');
1138
- return row ? JSON.parse(row.value) : null;
1139
- }
1140
- updateConfig(config) {
1141
- const result = this.db
1142
- .prepare('UPDATE config SET value = ? WHERE key = ?')
1143
- .run(JSON.stringify(config), 'app_config');
1144
- return result.changes > 0;
1145
- }
1146
- // Export/Import operations
1147
- exportData(password) {
1148
- return __awaiter(this, void 0, void 0, function* () {
1149
- const exportData = {
1150
- version: '1.0.0',
1151
- exportDate: Date.now(),
1152
- vendors: this.getVendors(),
1153
- apiServices: this.getAPIServices(),
1154
- routes: this.getRoutes(),
1155
- rules: this.getRules(),
1156
- config: this.getConfig(),
1157
- };
1158
- const jsonData = JSON.stringify(exportData);
1159
- const encrypted = crypto_js_1.default.AES.encrypt(jsonData, password).toString();
1160
- return encrypted;
1161
- });
1162
- }
1163
- importData(encryptedData, password) {
1164
- return __awaiter(this, void 0, void 0, function* () {
1165
- try {
1166
- const decrypted = crypto_js_1.default.AES.decrypt(encryptedData, password);
1167
- const jsonData = decrypted.toString(crypto_js_1.default.enc.Utf8);
1168
- const importData = JSON.parse(jsonData);
1169
- // Clear existing data
1170
- this.db.prepare('DELETE FROM rules').run();
1171
- this.db.prepare('DELETE FROM routes').run();
1172
- this.db.prepare('DELETE FROM api_services').run();
1173
- this.db.prepare('DELETE FROM vendors').run();
1174
- // Import vendors
1175
- for (const vendor of importData.vendors) {
1176
- this.db
1177
- .prepare('INSERT INTO vendors (id, name, description, sort_order, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)')
1178
- .run(vendor.id, vendor.name, vendor.description || null, vendor.sortOrder || 0, vendor.createdAt, vendor.updatedAt);
1179
- }
1180
- // Import API services
1181
- for (const service of importData.apiServices) {
1182
- this.db
1183
- .prepare('INSERT INTO api_services (id, vendor_id, name, api_url, api_key, source_type, auth_type, supported_models, model_limits, enable_proxy, enable_token_limit, token_limit, token_reset_interval, token_reset_base_time, enable_request_limit, request_count_limit, request_reset_interval, request_reset_base_time, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
1184
- .run(service.id, service.vendorId, service.name, service.apiUrl, service.apiKey, service.sourceType || null, service.authType || null, service.supportedModels ? service.supportedModels.join(',') : null, service.modelLimits ? JSON.stringify(service.modelLimits) : null, service.enableProxy ? 1 : 0, service.enableTokenLimit ? 1 : 0, service.tokenLimit || null, service.tokenResetInterval || null, service.tokenResetBaseTime || null, service.enableRequestLimit ? 1 : 0, service.requestCountLimit || null, service.requestResetInterval || null, service.requestResetBaseTime || null, service.createdAt, service.updatedAt);
1185
- }
1186
- // Import routes
1187
- for (const route of importData.routes) {
1188
- this.db
1189
- .prepare('INSERT INTO routes (id, name, description, target_type, is_active, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)')
1190
- .run(route.id, route.name, route.description || null, route.targetType, route.isActive ? 1 : 0, route.createdAt, route.updatedAt);
1191
- }
1192
- // Import rules
1193
- for (const rule of importData.rules) {
1194
- this.db
1195
- .prepare('INSERT INTO rules (id, route_id, content_type, target_service_id, target_model, replaced_model, sort_order, timeout, token_limit, total_tokens_used, reset_interval, last_reset_at, token_reset_base_time, request_count_limit, total_requests_used, request_reset_interval, request_last_reset_at, request_reset_base_time, is_disabled, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
1196
- .run(rule.id, rule.routeId, rule.contentType || 'default', rule.targetServiceId, rule.targetModel || null, rule.replacedModel || null, rule.sortOrder || 0, rule.timeout || null, rule.tokenLimit || null, rule.totalTokensUsed || 0, rule.resetInterval || null, rule.lastResetAt || null, rule.tokenResetBaseTime || null, rule.requestCountLimit || null, rule.totalRequestsUsed || 0, rule.requestResetInterval || null, rule.requestLastResetAt || null, rule.requestResetBaseTime || null, rule.isDisabled ? 1 : 0, rule.createdAt, rule.updatedAt);
1197
- }
1198
- // Update config
1199
- this.updateConfig(importData.config);
1200
- return true;
1201
- }
1202
- catch (error) {
1203
- console.error('Import error:', error);
1204
- return false;
1205
- }
1206
- });
1207
- }
1208
- // Statistics operations
1209
- getStatistics() {
1210
- return __awaiter(this, arguments, void 0, function* (days = 30) {
1211
- var _a, e_6, _b, _c, _d, e_7, _e, _f;
1212
- var _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
1213
- const now = Date.now();
1214
- const startTime = now - days * 24 * 60 * 60 * 1000;
1215
- // Get all logs within the time period
1216
- const allLogs = [];
1217
- try {
1218
- for (var _z = true, _0 = __asyncValues(this.logDb.iterator()), _1; _1 = yield _0.next(), _a = _1.done, !_a; _z = true) {
1219
- _c = _1.value;
1220
- _z = false;
1221
- const [, value] = _c;
1222
- const log = JSON.parse(value);
1223
- if (log.timestamp >= startTime) {
1224
- allLogs.push(log);
1225
- }
1226
- }
1227
- }
1228
- catch (e_6_1) { e_6 = { error: e_6_1 }; }
1229
- finally {
1230
- try {
1231
- if (!_z && !_a && (_b = _0.return)) yield _b.call(_0);
1232
- }
1233
- finally { if (e_6) throw e_6.error; }
1234
- }
1235
- // Get all error logs
1236
- const errorLogs = [];
1237
- const recentErrorLogs = [];
1238
- const recentTime = now - 24 * 60 * 60 * 1000; // 24 hours ago
1239
- try {
1240
- for (var _2 = true, _3 = __asyncValues(this.errorLogDb.iterator()), _4; _4 = yield _3.next(), _d = _4.done, !_d; _2 = true) {
1241
- _f = _4.value;
1242
- _2 = false;
1243
- const [, value] = _f;
1244
- const log = JSON.parse(value);
1245
- errorLogs.push(log);
1246
- if (log.timestamp >= recentTime) {
1247
- recentErrorLogs.push(log);
1248
- }
1249
- }
1250
- }
1251
- catch (e_7_1) { e_7 = { error: e_7_1 }; }
1252
- finally {
1253
- try {
1254
- if (!_2 && !_d && (_e = _3.return)) yield _e.call(_3);
1255
- }
1256
- finally { if (e_7) throw e_7.error; }
1257
- }
1258
- // Get vendors and services for mapping
1259
- const vendors = this.getVendors();
1260
- const vendorMap = new Map(vendors.map(v => [v.id, v.name]));
1261
- const services = this.getAPIServices();
1262
- const serviceMap = new Map(services.map(s => [s.id, { name: s.name, vendorId: s.vendorId }]));
1263
- // Calculate overview
1264
- const totalRequests = allLogs.length;
1265
- const successRequests = allLogs.filter(log => log.statusCode && log.statusCode >= 200 && log.statusCode < 400).length;
1266
- const totalInputTokens = allLogs.reduce((sum, log) => { var _a; return sum + (((_a = log.usage) === null || _a === void 0 ? void 0 : _a.inputTokens) || 0); }, 0);
1267
- const totalOutputTokens = allLogs.reduce((sum, log) => { var _a; return sum + (((_a = log.usage) === null || _a === void 0 ? void 0 : _a.outputTokens) || 0); }, 0);
1268
- const totalCacheReadTokens = allLogs.reduce((sum, log) => { var _a; return sum + (((_a = log.usage) === null || _a === void 0 ? void 0 : _a.cacheReadInputTokens) || 0); }, 0);
1269
- const totalTokens = allLogs.reduce((sum, log) => {
1270
- var _a, _b, _c;
1271
- if ((_a = log.usage) === null || _a === void 0 ? void 0 : _a.totalTokens)
1272
- return sum + log.usage.totalTokens;
1273
- return sum + (((_b = log.usage) === null || _b === void 0 ? void 0 : _b.inputTokens) || 0) + (((_c = log.usage) === null || _c === void 0 ? void 0 : _c.outputTokens) || 0);
1274
- }, 0);
1275
- const avgResponseTime = allLogs.length > 0
1276
- ? allLogs.reduce((sum, log) => sum + (log.responseTime || 0), 0) / allLogs.length
1277
- : 0;
1278
- const successRate = totalRequests > 0 ? (successRequests / totalRequests) * 100 : 0;
1279
- // Calculate coding time (estimate based on tokens and requests)
1280
- // Assume average reading speed: 250 tokens/minute, coding speed: 100 tokens/minute
1281
- const totalCodingTime = Math.round(totalInputTokens / 250 + totalOutputTokens / 100);
1282
- // Group by target type
1283
- const byTargetTypeMap = new Map();
1284
- for (const log of allLogs) {
1285
- const key = log.targetType || 'unknown';
1286
- if (!byTargetTypeMap.has(key)) {
1287
- byTargetTypeMap.set(key, { requests: 0, tokens: 0, responseTime: 0 });
1288
- }
1289
- const stats = byTargetTypeMap.get(key);
1290
- stats.requests++;
1291
- stats.tokens += ((_g = log.usage) === null || _g === void 0 ? void 0 : _g.totalTokens) || (((_h = log.usage) === null || _h === void 0 ? void 0 : _h.inputTokens) || 0) + (((_j = log.usage) === null || _j === void 0 ? void 0 : _j.outputTokens) || 0);
1292
- stats.responseTime += log.responseTime || 0;
1293
- }
1294
- const byTargetType = Array.from(byTargetTypeMap.entries()).map(([targetType, stats]) => ({
1295
- targetType: targetType,
1296
- totalRequests: stats.requests,
1297
- totalTokens: stats.tokens,
1298
- avgResponseTime: stats.requests > 0 ? Math.round(stats.responseTime / stats.requests) : 0,
1299
- }));
1300
- // Group by vendor
1301
- const byVendorMap = new Map();
1302
- for (const log of allLogs) {
1303
- const key = log.vendorId || 'unknown';
1304
- if (!byVendorMap.has(key)) {
1305
- byVendorMap.set(key, { requests: 0, tokens: 0, responseTime: 0 });
1306
- }
1307
- const stats = byVendorMap.get(key);
1308
- stats.requests++;
1309
- stats.tokens += ((_k = log.usage) === null || _k === void 0 ? void 0 : _k.totalTokens) || (((_l = log.usage) === null || _l === void 0 ? void 0 : _l.inputTokens) || 0) + (((_m = log.usage) === null || _m === void 0 ? void 0 : _m.outputTokens) || 0);
1310
- stats.responseTime += log.responseTime || 0;
1311
- }
1312
- const byVendor = Array.from(byVendorMap.entries()).map(([vendorId, stats]) => ({
1313
- vendorId,
1314
- vendorName: vendorMap.get(vendorId) || 'Unknown',
1315
- totalRequests: stats.requests,
1316
- totalTokens: stats.tokens,
1317
- avgResponseTime: stats.requests > 0 ? Math.round(stats.responseTime / stats.requests) : 0,
1318
- }));
1319
- // Group by service
1320
- const byServiceMap = new Map();
1321
- for (const log of allLogs) {
1322
- const key = log.targetServiceId || 'unknown';
1323
- if (!byServiceMap.has(key)) {
1324
- byServiceMap.set(key, { requests: 0, tokens: 0, responseTime: 0 });
1325
- }
1326
- const stats = byServiceMap.get(key);
1327
- stats.requests++;
1328
- stats.tokens += ((_o = log.usage) === null || _o === void 0 ? void 0 : _o.totalTokens) || (((_p = log.usage) === null || _p === void 0 ? void 0 : _p.inputTokens) || 0) + (((_q = log.usage) === null || _q === void 0 ? void 0 : _q.outputTokens) || 0);
1329
- stats.responseTime += log.responseTime || 0;
1330
- }
1331
- const byService = Array.from(byServiceMap.entries()).map(([serviceId, stats]) => {
1332
- const serviceInfo = serviceMap.get(serviceId);
1333
- return {
1334
- serviceId,
1335
- serviceName: (serviceInfo === null || serviceInfo === void 0 ? void 0 : serviceInfo.name) || 'Unknown',
1336
- vendorName: serviceInfo && serviceInfo.vendorId ? (vendorMap.get(serviceInfo.vendorId) || 'Unknown') : 'Unknown',
1337
- totalRequests: stats.requests,
1338
- totalTokens: stats.tokens,
1339
- avgResponseTime: stats.requests > 0 ? Math.round(stats.responseTime / stats.requests) : 0,
1340
- };
1341
- });
1342
- // Group by model
1343
- const byModelMap = new Map();
1344
- for (const log of allLogs) {
1345
- const key = log.targetModel || 'unknown';
1346
- if (!byModelMap.has(key)) {
1347
- byModelMap.set(key, { requests: 0, tokens: 0, responseTime: 0 });
1348
- }
1349
- const stats = byModelMap.get(key);
1350
- stats.requests++;
1351
- stats.tokens += ((_r = log.usage) === null || _r === void 0 ? void 0 : _r.totalTokens) || (((_s = log.usage) === null || _s === void 0 ? void 0 : _s.inputTokens) || 0) + (((_t = log.usage) === null || _t === void 0 ? void 0 : _t.outputTokens) || 0);
1352
- stats.responseTime += log.responseTime || 0;
1353
- }
1354
- const byModel = Array.from(byModelMap.entries()).map(([modelName, stats]) => ({
1355
- modelName,
1356
- totalRequests: stats.requests,
1357
- totalTokens: stats.tokens,
1358
- avgResponseTime: stats.requests > 0 ? Math.round(stats.responseTime / stats.requests) : 0,
1359
- }));
1360
- // Timeline data (by day)
1361
- const timelineMap = new Map();
1362
- for (const log of allLogs) {
1363
- const date = new Date(log.timestamp).toISOString().split('T')[0];
1364
- if (!timelineMap.has(date)) {
1365
- timelineMap.set(date, { requests: 0, tokens: 0, inputTokens: 0, outputTokens: 0 });
1366
- }
1367
- const stats = timelineMap.get(date);
1368
- stats.requests++;
1369
- stats.inputTokens += ((_u = log.usage) === null || _u === void 0 ? void 0 : _u.inputTokens) || 0;
1370
- stats.outputTokens += ((_v = log.usage) === null || _v === void 0 ? void 0 : _v.outputTokens) || 0;
1371
- stats.tokens += ((_w = log.usage) === null || _w === void 0 ? void 0 : _w.totalTokens) || (((_x = log.usage) === null || _x === void 0 ? void 0 : _x.inputTokens) || 0) + (((_y = log.usage) === null || _y === void 0 ? void 0 : _y.outputTokens) || 0);
1372
- }
1373
- const timeline = Array.from(timelineMap.entries())
1374
- .map(([date, stats]) => ({
1375
- date,
1376
- totalRequests: stats.requests,
1377
- totalTokens: stats.tokens,
1378
- totalInputTokens: stats.inputTokens,
1379
- totalOutputTokens: stats.outputTokens,
1380
- }))
1381
- .sort((a, b) => a.date.localeCompare(b.date));
1382
- // Content type distribution (infer from request patterns)
1383
- const contentTypeMap = new Map();
1384
- for (const log of allLogs) {
1385
- // Infer content type from request characteristics
1386
- let contentType = 'default';
1387
- if (log.body && (log.body.includes('image') || log.body.includes('base64'))) {
1388
- contentType = 'image-understanding';
1389
- }
1390
- else if (log.requestModel && log.requestModel.toLowerCase().includes('think')) {
1391
- contentType = 'thinking';
1392
- }
1393
- else if (log.usage && log.usage.inputTokens > 12000) {
1394
- contentType = 'long-context';
1395
- }
1396
- contentTypeMap.set(contentType, (contentTypeMap.get(contentType) || 0) + 1);
1397
- }
1398
- const contentTypeDistribution = Array.from(contentTypeMap.entries()).map(([contentType, count]) => ({
1399
- contentType,
1400
- count,
1401
- percentage: totalRequests > 0 ? Math.round((count / totalRequests) * 100) : 0,
1402
- }));
1403
- return {
1404
- overview: {
1405
- totalRequests,
1406
- totalTokens,
1407
- totalInputTokens,
1408
- totalOutputTokens,
1409
- totalCacheReadTokens,
1410
- totalVendors: vendors.length,
1411
- totalServices: services.length,
1412
- totalRoutes: this.getRoutes().length,
1413
- totalRules: this.getRules().length,
1414
- avgResponseTime: Math.round(avgResponseTime),
1415
- successRate: Math.round(successRate * 10) / 10,
1416
- totalCodingTime,
1417
- },
1418
- byTargetType,
1419
- byVendor,
1420
- byService,
1421
- byModel,
1422
- timeline,
1423
- contentTypeDistribution,
1424
- errors: {
1425
- totalErrors: errorLogs.length,
1426
- recentErrors: recentErrorLogs.length,
1427
- },
1428
- };
1429
- });
1430
- }
1431
- getRuleBlacklistStatus(serviceId, routeId, contentType) {
1432
- return __awaiter(this, void 0, void 0, function* () {
1433
- const key = `${routeId}:${contentType}:${serviceId}`;
1434
- try {
1435
- const value = yield this.blacklistDb.get(key);
1436
- const entry = JSON.parse(value);
1437
- // 检查是否过期
1438
- if (Date.now() > entry.expiresAt) {
1439
- yield this.blacklistDb.del(key);
1440
- return null;
1441
- }
1442
- return entry;
1443
- }
1444
- catch (error) {
1445
- if (error.code === 'LEVEL_NOT_FOUND') {
1446
- return null;
1447
- }
1448
- throw error;
1449
- }
1450
- });
1451
- }
1452
- // Session operations
1453
- /**
1454
- * 创建或更新 session
1455
- * 当有新的请求日志时调用此方法来更新 session 信息
1456
- */
1457
- upsertSession(session) {
1458
- const now = Date.now();
1459
- const existing = this.db.prepare('SELECT * FROM sessions WHERE id = ?').get(session.id);
1460
- if (existing) {
1461
- // 更新现有 session
1462
- this.db.prepare(`
1463
- UPDATE sessions SET
1464
- last_request_at = ?,
1465
- request_count = request_count + 1,
1466
- total_tokens = total_tokens + ?,
1467
- vendor_id = ?,
1468
- vendor_name = ?,
1469
- service_id = ?,
1470
- service_name = ?,
1471
- model = ?
1472
- WHERE id = ?
1473
- `).run(now, session.totalTokens || 0, session.vendorId || null, session.vendorName || null, session.serviceId || null, session.serviceName || null, session.model || null, session.id);
1474
- }
1475
- else {
1476
- // 创建新 session
1477
- this.db.prepare(`
1478
- INSERT INTO sessions (id, target_type, title, first_request_at, last_request_at, request_count, total_tokens, vendor_id, vendor_name, service_id, service_name, model)
1479
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1480
- `).run(session.id, session.targetType, session.title || null, session.firstRequestAt, now, 1, session.totalTokens || 0, session.vendorId || null, session.vendorName || null, session.serviceId || null, session.serviceName || null, session.model || null);
1481
- }
1482
- }
1483
- /**
1484
- * 获取所有 sessions
1485
- */
1486
- getSessions(limit = 100, offset = 0) {
1487
- const rows = this.db.prepare('SELECT * FROM sessions ORDER BY last_request_at DESC LIMIT ? OFFSET ?').all(limit, offset);
1488
- return rows.map((row) => ({
1489
- id: row.id,
1490
- targetType: row.target_type,
1491
- title: row.title,
1492
- firstRequestAt: row.first_request_at,
1493
- lastRequestAt: row.last_request_at,
1494
- requestCount: row.request_count,
1495
- totalTokens: row.total_tokens,
1496
- vendorId: row.vendor_id,
1497
- vendorName: row.vendor_name,
1498
- serviceId: row.service_id,
1499
- serviceName: row.service_name,
1500
- model: row.model,
1501
- }));
1502
- }
1503
- /**
1504
- * 根据 session ID 获取 session
1505
- */
1506
- getSession(id) {
1507
- const row = this.db.prepare('SELECT * FROM sessions WHERE id = ?').get(id);
1508
- if (!row)
1509
- return null;
1510
- return {
1511
- id: row.id,
1512
- targetType: row.target_type,
1513
- title: row.title,
1514
- firstRequestAt: row.first_request_at,
1515
- lastRequestAt: row.last_request_at,
1516
- requestCount: row.request_count,
1517
- totalTokens: row.total_tokens,
1518
- vendorId: row.vendor_id,
1519
- vendorName: row.vendor_name,
1520
- serviceId: row.service_id,
1521
- serviceName: row.service_name,
1522
- model: row.model,
1523
- };
1524
- }
1525
- /**
1526
- * 获取 sessions 总数
1527
- */
1528
- getSessionsCount() {
1529
- const result = this.db.prepare('SELECT COUNT(*) as count FROM sessions').get();
1530
- return result.count;
1531
- }
1532
- /**
1533
- * 删除指定 session
1534
- */
1535
- deleteSession(id) {
1536
- const result = this.db.prepare('DELETE FROM sessions WHERE id = ?').run(id);
1537
- return result.changes > 0;
1538
- }
1539
- /**
1540
- * 清空所有 sessions
1541
- */
1542
- clearSessions() {
1543
- this.db.prepare('DELETE FROM sessions').run();
1544
- }
1545
- /**
1546
- * 获取指定 session 的请求日志
1547
- * @param sessionId session ID
1548
- * @param limit 限制数量
1549
- */
1550
- getLogsBySessionId(sessionId_1) {
1551
- return __awaiter(this, arguments, void 0, function* (sessionId, limit = 100) {
1552
- var _a, e_8, _b, _c;
1553
- // 从 LevelDB 中读取所有日志
1554
- const allLogs = [];
1555
- try {
1556
- for (var _d = true, _e = __asyncValues(this.logDb.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
1557
- _c = _f.value;
1558
- _d = false;
1559
- const [, value] = _c;
1560
- const log = JSON.parse(value);
1561
- // 检查日志是否属于该 session(通过 headers 中的 session_id 或 body 中的 metadata.user_id)
1562
- if (this.isLogBelongsToSession(log, sessionId)) {
1563
- allLogs.push(log);
1564
- }
1565
- }
1566
- }
1567
- catch (e_8_1) { e_8 = { error: e_8_1 }; }
1568
- finally {
1569
- try {
1570
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
1571
- }
1572
- finally { if (e_8) throw e_8.error; }
1573
- }
1574
- // 按时间倒序排序并限制数量
1575
- allLogs.sort((a, b) => b.timestamp - a.timestamp);
1576
- return allLogs.slice(0, limit);
1577
- });
1578
- }
1579
- /**
1580
- * 检查日志是否属于指定 session
1581
- */
1582
- isLogBelongsToSession(log, sessionId) {
1583
- var _a, _b;
1584
- // 检查 headers 中的 session_id(Codex)
1585
- if (((_a = log.headers) === null || _a === void 0 ? void 0 : _a['session_id']) === sessionId) {
1586
- return true;
1587
- }
1588
- // 检查 body 中的 metadata.user_id(Claude Code)
1589
- if (log.body) {
1590
- try {
1591
- const body = JSON.parse(log.body);
1592
- if (((_b = body.metadata) === null || _b === void 0 ? void 0 : _b.user_id) === sessionId) {
1593
- return true;
1594
- }
1595
- }
1596
- catch (_c) {
1597
- // 忽略解析错误
1598
- }
1599
- }
1600
- return false;
1601
- }
1602
- close() {
1603
- this.db.close();
1604
- this.logDb.close();
1605
- this.errorLogDb.close();
1606
- this.blacklistDb.close();
1607
- }
1608
- }
1609
- exports.DatabaseManager = DatabaseManager;