aicodeswitch 1.10.2 → 2.0.1
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/CHANGELOG.md +2 -0
- package/bin/cli.js +7 -9
- package/bin/restart.js +7 -229
- package/bin/restore.js +1 -1
- package/bin/start.js +75 -87
- package/bin/stop.js +77 -14
- package/bin/ui.js +19 -134
- package/bin/update.js +1 -1
- package/bin/utils/get-server.js +58 -0
- package/bin/utils/port-utils.js +118 -0
- package/bin/version.js +1 -1
- package/dist/server/database.js +196 -116
- package/dist/server/main.js +116 -22
- package/dist/server/proxy-server.js +334 -158
- package/dist/server/transformers/claude-openai.js +86 -3
- package/dist/server/transformers/streaming.js +4 -1
- package/dist/server/utils.js +16 -0
- package/dist/ui/assets/index-BLqGemLn.js +423 -0
- package/dist/ui/assets/index-IVPeH7yC.css +1 -0
- package/dist/ui/index.html +2 -2
- package/dist/ui/migration.md +7 -0
- package/package.json +3 -2
- package/public/migration.md +7 -0
- package/dist/ui/assets/index-D6RrKKB5.js +0 -391
- package/dist/ui/assets/index-DU8EG0kT.css +0 -1
package/dist/server/database.js
CHANGED
|
@@ -39,12 +39,6 @@ class DatabaseManager {
|
|
|
39
39
|
writable: true,
|
|
40
40
|
value: void 0
|
|
41
41
|
});
|
|
42
|
-
Object.defineProperty(this, "accessLogDb", {
|
|
43
|
-
enumerable: true,
|
|
44
|
-
configurable: true,
|
|
45
|
-
writable: true,
|
|
46
|
-
value: void 0
|
|
47
|
-
});
|
|
48
42
|
Object.defineProperty(this, "errorLogDb", {
|
|
49
43
|
enumerable: true,
|
|
50
44
|
configurable: true,
|
|
@@ -64,12 +58,6 @@ class DatabaseManager {
|
|
|
64
58
|
writable: true,
|
|
65
59
|
value: null
|
|
66
60
|
});
|
|
67
|
-
Object.defineProperty(this, "accessLogsCountCache", {
|
|
68
|
-
enumerable: true,
|
|
69
|
-
configurable: true,
|
|
70
|
-
writable: true,
|
|
71
|
-
value: null
|
|
72
|
-
});
|
|
73
61
|
Object.defineProperty(this, "errorLogsCountCache", {
|
|
74
62
|
enumerable: true,
|
|
75
63
|
configurable: true,
|
|
@@ -94,7 +82,6 @@ class DatabaseManager {
|
|
|
94
82
|
// 设置 read_uncommitted = 0 确保读取最新提交的数据
|
|
95
83
|
this.db.pragma('read_uncommitted = 0');
|
|
96
84
|
this.logDb = new level_1.Level(path_1.default.join(dataPath, 'logs'), { valueEncoding: 'json' });
|
|
97
|
-
this.accessLogDb = new level_1.Level(path_1.default.join(dataPath, 'access-logs'), { valueEncoding: 'json' });
|
|
98
85
|
this.errorLogDb = new level_1.Level(path_1.default.join(dataPath, 'error-logs'), { valueEncoding: 'json' });
|
|
99
86
|
this.blacklistDb = new level_1.Level(path_1.default.join(dataPath, 'service-blacklist'), { valueEncoding: 'json' });
|
|
100
87
|
}
|
|
@@ -270,6 +257,13 @@ class DatabaseManager {
|
|
|
270
257
|
this.db.exec('ALTER TABLE api_services ADD COLUMN request_reset_base_time INTEGER;');
|
|
271
258
|
console.log('[DB] Migration completed: request_reset_base_time column added');
|
|
272
259
|
}
|
|
260
|
+
// 检查api_services表是否有auth_type字段
|
|
261
|
+
const hasAuthType = columns.some((col) => col.name === 'auth_type');
|
|
262
|
+
if (!hasAuthType) {
|
|
263
|
+
console.log('[DB] Running migration: Adding auth_type column to api_services table');
|
|
264
|
+
this.db.exec('ALTER TABLE api_services ADD COLUMN auth_type TEXT DEFAULT NULL;');
|
|
265
|
+
console.log('[DB] Migration completed: auth_type column added');
|
|
266
|
+
}
|
|
273
267
|
});
|
|
274
268
|
}
|
|
275
269
|
migrateMaxOutputTokensToModelLimits() {
|
|
@@ -398,6 +392,21 @@ class DatabaseManager {
|
|
|
398
392
|
key TEXT PRIMARY KEY,
|
|
399
393
|
value TEXT NOT NULL
|
|
400
394
|
);
|
|
395
|
+
|
|
396
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
397
|
+
id TEXT PRIMARY KEY,
|
|
398
|
+
target_type TEXT NOT NULL CHECK(target_type IN ('claude-code', 'codex')),
|
|
399
|
+
title TEXT,
|
|
400
|
+
first_request_at INTEGER NOT NULL,
|
|
401
|
+
last_request_at INTEGER NOT NULL,
|
|
402
|
+
request_count INTEGER DEFAULT 1,
|
|
403
|
+
total_tokens INTEGER DEFAULT 0,
|
|
404
|
+
vendor_id TEXT,
|
|
405
|
+
vendor_name TEXT,
|
|
406
|
+
service_id TEXT,
|
|
407
|
+
service_name TEXT,
|
|
408
|
+
model TEXT
|
|
409
|
+
);
|
|
401
410
|
`);
|
|
402
411
|
}
|
|
403
412
|
ensureDefaultConfig() {
|
|
@@ -466,6 +475,7 @@ class DatabaseManager {
|
|
|
466
475
|
apiUrl: row.api_url,
|
|
467
476
|
apiKey: row.api_key,
|
|
468
477
|
sourceType: row.source_type,
|
|
478
|
+
authType: row.auth_type,
|
|
469
479
|
supportedModels: row.supported_models ? row.supported_models.split(',').map((model) => model.trim()).filter((model) => model.length > 0) : undefined,
|
|
470
480
|
modelLimits: row.model_limits ? JSON.parse(row.model_limits) : undefined,
|
|
471
481
|
enableProxy: row.enable_proxy === 1,
|
|
@@ -492,15 +502,15 @@ class DatabaseManager {
|
|
|
492
502
|
const id = crypto_1.default.randomUUID();
|
|
493
503
|
const now = Date.now();
|
|
494
504
|
this.db
|
|
495
|
-
.prepare('INSERT INTO api_services (id, vendor_id, name, api_url, api_key, source_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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
|
|
496
|
-
.run(id, service.vendorId, service.name, service.apiUrl, service.apiKey, service.sourceType || 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);
|
|
505
|
+
.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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
|
|
506
|
+
.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);
|
|
497
507
|
return Object.assign(Object.assign({}, service), { id, createdAt: now, updatedAt: now });
|
|
498
508
|
}
|
|
499
509
|
updateAPIService(id, service) {
|
|
500
510
|
const now = Date.now();
|
|
501
511
|
const result = this.db
|
|
502
|
-
.prepare('UPDATE api_services SET vendor_id = ?, name = ?, api_url = ?, api_key = ?, source_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 = ?')
|
|
503
|
-
.run(service.vendorId, service.name, service.apiUrl, service.apiKey, service.sourceType || 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);
|
|
512
|
+
.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 = ?')
|
|
513
|
+
.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);
|
|
504
514
|
// 调试日志: 记录更新操作
|
|
505
515
|
if (result.changes > 0 && process.env.NODE_ENV === 'development') {
|
|
506
516
|
console.log(`[DB] Updated service ${id}: ${service.name} -> ${service.apiUrl}`);
|
|
@@ -829,55 +839,6 @@ class DatabaseManager {
|
|
|
829
839
|
this.logsCountCache = null;
|
|
830
840
|
});
|
|
831
841
|
}
|
|
832
|
-
// Access log operations
|
|
833
|
-
addAccessLog(log) {
|
|
834
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
835
|
-
const id = crypto_1.default.randomUUID();
|
|
836
|
-
yield this.accessLogDb.put(id, JSON.stringify(Object.assign(Object.assign({}, log), { id })));
|
|
837
|
-
// 清除缓存
|
|
838
|
-
this.accessLogsCountCache = null;
|
|
839
|
-
return id;
|
|
840
|
-
});
|
|
841
|
-
}
|
|
842
|
-
updateAccessLog(id, data) {
|
|
843
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
844
|
-
const log = yield this.accessLogDb.get(id);
|
|
845
|
-
const updatedLog = Object.assign(Object.assign({}, JSON.parse(log)), data);
|
|
846
|
-
yield this.accessLogDb.put(id, JSON.stringify(updatedLog));
|
|
847
|
-
});
|
|
848
|
-
}
|
|
849
|
-
getAccessLogs() {
|
|
850
|
-
return __awaiter(this, arguments, void 0, function* (limit = 100, offset = 0) {
|
|
851
|
-
var _a, e_2, _b, _c;
|
|
852
|
-
const allLogs = [];
|
|
853
|
-
try {
|
|
854
|
-
for (var _d = true, _e = __asyncValues(this.accessLogDb.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
855
|
-
_c = _f.value;
|
|
856
|
-
_d = false;
|
|
857
|
-
const [, value] = _c;
|
|
858
|
-
allLogs.push(JSON.parse(value));
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
862
|
-
finally {
|
|
863
|
-
try {
|
|
864
|
-
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
865
|
-
}
|
|
866
|
-
finally { if (e_2) throw e_2.error; }
|
|
867
|
-
}
|
|
868
|
-
// Sort by timestamp in descending order (newest first)
|
|
869
|
-
allLogs.sort((a, b) => b.timestamp - a.timestamp);
|
|
870
|
-
// Apply offset and limit
|
|
871
|
-
return allLogs.slice(offset, offset + limit);
|
|
872
|
-
});
|
|
873
|
-
}
|
|
874
|
-
clearAccessLogs() {
|
|
875
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
876
|
-
yield this.accessLogDb.clear();
|
|
877
|
-
// 清除缓存
|
|
878
|
-
this.accessLogsCountCache = null;
|
|
879
|
-
});
|
|
880
|
-
}
|
|
881
842
|
// Error log operations
|
|
882
843
|
addErrorLog(log) {
|
|
883
844
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -889,7 +850,7 @@ class DatabaseManager {
|
|
|
889
850
|
}
|
|
890
851
|
getErrorLogs() {
|
|
891
852
|
return __awaiter(this, arguments, void 0, function* (limit = 100, offset = 0) {
|
|
892
|
-
var _a,
|
|
853
|
+
var _a, e_2, _b, _c;
|
|
893
854
|
const allLogs = [];
|
|
894
855
|
try {
|
|
895
856
|
for (var _d = true, _e = __asyncValues(this.errorLogDb.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
@@ -899,12 +860,12 @@ class DatabaseManager {
|
|
|
899
860
|
allLogs.push(JSON.parse(value));
|
|
900
861
|
}
|
|
901
862
|
}
|
|
902
|
-
catch (
|
|
863
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
903
864
|
finally {
|
|
904
865
|
try {
|
|
905
866
|
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
906
867
|
}
|
|
907
|
-
finally { if (
|
|
868
|
+
finally { if (e_2) throw e_2.error; }
|
|
908
869
|
}
|
|
909
870
|
// Sort by timestamp in descending order (newest first)
|
|
910
871
|
allLogs.sort((a, b) => b.timestamp - a.timestamp);
|
|
@@ -924,7 +885,7 @@ class DatabaseManager {
|
|
|
924
885
|
*/
|
|
925
886
|
getLogsCount() {
|
|
926
887
|
return __awaiter(this, void 0, void 0, function* () {
|
|
927
|
-
var _a,
|
|
888
|
+
var _a, e_3, _b, _c;
|
|
928
889
|
const now = Date.now();
|
|
929
890
|
if (this.logsCountCache && now - this.logsCountCache.timestamp < this.CACHE_TTL) {
|
|
930
891
|
return this.logsCountCache.count;
|
|
@@ -938,53 +899,23 @@ class DatabaseManager {
|
|
|
938
899
|
count++;
|
|
939
900
|
}
|
|
940
901
|
}
|
|
941
|
-
catch (
|
|
902
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
942
903
|
finally {
|
|
943
904
|
try {
|
|
944
905
|
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
945
906
|
}
|
|
946
|
-
finally { if (
|
|
907
|
+
finally { if (e_3) throw e_3.error; }
|
|
947
908
|
}
|
|
948
909
|
this.logsCountCache = { count, timestamp: now };
|
|
949
910
|
return count;
|
|
950
911
|
});
|
|
951
912
|
}
|
|
952
|
-
/**
|
|
953
|
-
* 获取访问日志总数(带缓存)
|
|
954
|
-
*/
|
|
955
|
-
getAccessLogsCount() {
|
|
956
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
957
|
-
var _a, e_5, _b, _c;
|
|
958
|
-
const now = Date.now();
|
|
959
|
-
if (this.accessLogsCountCache && now - this.accessLogsCountCache.timestamp < this.CACHE_TTL) {
|
|
960
|
-
return this.accessLogsCountCache.count;
|
|
961
|
-
}
|
|
962
|
-
let count = 0;
|
|
963
|
-
try {
|
|
964
|
-
for (var _d = true, _e = __asyncValues(this.accessLogDb.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
965
|
-
_c = _f.value;
|
|
966
|
-
_d = false;
|
|
967
|
-
const _ = _c;
|
|
968
|
-
count++;
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
972
|
-
finally {
|
|
973
|
-
try {
|
|
974
|
-
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
975
|
-
}
|
|
976
|
-
finally { if (e_5) throw e_5.error; }
|
|
977
|
-
}
|
|
978
|
-
this.accessLogsCountCache = { count, timestamp: now };
|
|
979
|
-
return count;
|
|
980
|
-
});
|
|
981
|
-
}
|
|
982
913
|
/**
|
|
983
914
|
* 获取错误日志总数(带缓存)
|
|
984
915
|
*/
|
|
985
916
|
getErrorLogsCount() {
|
|
986
917
|
return __awaiter(this, void 0, void 0, function* () {
|
|
987
|
-
var _a,
|
|
918
|
+
var _a, e_4, _b, _c;
|
|
988
919
|
const now = Date.now();
|
|
989
920
|
if (this.errorLogsCountCache && now - this.errorLogsCountCache.timestamp < this.CACHE_TTL) {
|
|
990
921
|
return this.errorLogsCountCache.count;
|
|
@@ -998,12 +929,12 @@ class DatabaseManager {
|
|
|
998
929
|
count++;
|
|
999
930
|
}
|
|
1000
931
|
}
|
|
1001
|
-
catch (
|
|
932
|
+
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
1002
933
|
finally {
|
|
1003
934
|
try {
|
|
1004
935
|
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
1005
936
|
}
|
|
1006
|
-
finally { if (
|
|
937
|
+
finally { if (e_4) throw e_4.error; }
|
|
1007
938
|
}
|
|
1008
939
|
this.errorLogsCountCache = { count, timestamp: now };
|
|
1009
940
|
return count;
|
|
@@ -1079,7 +1010,7 @@ class DatabaseManager {
|
|
|
1079
1010
|
}
|
|
1080
1011
|
cleanupExpiredBlacklist() {
|
|
1081
1012
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1082
|
-
var _a,
|
|
1013
|
+
var _a, e_5, _b, _c;
|
|
1083
1014
|
const now = Date.now();
|
|
1084
1015
|
let count = 0;
|
|
1085
1016
|
try {
|
|
@@ -1094,12 +1025,12 @@ class DatabaseManager {
|
|
|
1094
1025
|
}
|
|
1095
1026
|
}
|
|
1096
1027
|
}
|
|
1097
|
-
catch (
|
|
1028
|
+
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
1098
1029
|
finally {
|
|
1099
1030
|
try {
|
|
1100
1031
|
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
1101
1032
|
}
|
|
1102
|
-
finally { if (
|
|
1033
|
+
finally { if (e_5) throw e_5.error; }
|
|
1103
1034
|
}
|
|
1104
1035
|
return count;
|
|
1105
1036
|
});
|
|
@@ -1152,8 +1083,8 @@ class DatabaseManager {
|
|
|
1152
1083
|
// Import API services
|
|
1153
1084
|
for (const service of importData.apiServices) {
|
|
1154
1085
|
this.db
|
|
1155
|
-
.prepare('INSERT INTO api_services (id, vendor_id, name, api_url, api_key, source_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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
|
|
1156
|
-
.run(service.id, service.vendorId, service.name, service.apiUrl, service.apiKey, service.sourceType || 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);
|
|
1086
|
+
.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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
|
|
1087
|
+
.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);
|
|
1157
1088
|
}
|
|
1158
1089
|
// Import routes
|
|
1159
1090
|
for (const route of importData.routes) {
|
|
@@ -1180,7 +1111,7 @@ class DatabaseManager {
|
|
|
1180
1111
|
// Statistics operations
|
|
1181
1112
|
getStatistics() {
|
|
1182
1113
|
return __awaiter(this, arguments, void 0, function* (days = 30) {
|
|
1183
|
-
var _a,
|
|
1114
|
+
var _a, e_6, _b, _c, _d, e_7, _e, _f;
|
|
1184
1115
|
var _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
|
|
1185
1116
|
const now = Date.now();
|
|
1186
1117
|
const startTime = now - days * 24 * 60 * 60 * 1000;
|
|
@@ -1197,12 +1128,12 @@ class DatabaseManager {
|
|
|
1197
1128
|
}
|
|
1198
1129
|
}
|
|
1199
1130
|
}
|
|
1200
|
-
catch (
|
|
1131
|
+
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
|
1201
1132
|
finally {
|
|
1202
1133
|
try {
|
|
1203
1134
|
if (!_z && !_a && (_b = _0.return)) yield _b.call(_0);
|
|
1204
1135
|
}
|
|
1205
|
-
finally { if (
|
|
1136
|
+
finally { if (e_6) throw e_6.error; }
|
|
1206
1137
|
}
|
|
1207
1138
|
// Get all error logs
|
|
1208
1139
|
const errorLogs = [];
|
|
@@ -1220,12 +1151,12 @@ class DatabaseManager {
|
|
|
1220
1151
|
}
|
|
1221
1152
|
}
|
|
1222
1153
|
}
|
|
1223
|
-
catch (
|
|
1154
|
+
catch (e_7_1) { e_7 = { error: e_7_1 }; }
|
|
1224
1155
|
finally {
|
|
1225
1156
|
try {
|
|
1226
1157
|
if (!_2 && !_d && (_e = _3.return)) yield _e.call(_3);
|
|
1227
1158
|
}
|
|
1228
|
-
finally { if (
|
|
1159
|
+
finally { if (e_7) throw e_7.error; }
|
|
1229
1160
|
}
|
|
1230
1161
|
// Get vendors and services for mapping
|
|
1231
1162
|
const vendors = this.getVendors();
|
|
@@ -1421,10 +1352,159 @@ class DatabaseManager {
|
|
|
1421
1352
|
}
|
|
1422
1353
|
});
|
|
1423
1354
|
}
|
|
1355
|
+
// Session operations
|
|
1356
|
+
/**
|
|
1357
|
+
* 创建或更新 session
|
|
1358
|
+
* 当有新的请求日志时调用此方法来更新 session 信息
|
|
1359
|
+
*/
|
|
1360
|
+
upsertSession(session) {
|
|
1361
|
+
const now = Date.now();
|
|
1362
|
+
const existing = this.db.prepare('SELECT * FROM sessions WHERE id = ?').get(session.id);
|
|
1363
|
+
if (existing) {
|
|
1364
|
+
// 更新现有 session
|
|
1365
|
+
this.db.prepare(`
|
|
1366
|
+
UPDATE sessions SET
|
|
1367
|
+
last_request_at = ?,
|
|
1368
|
+
request_count = request_count + 1,
|
|
1369
|
+
total_tokens = total_tokens + ?,
|
|
1370
|
+
vendor_id = ?,
|
|
1371
|
+
vendor_name = ?,
|
|
1372
|
+
service_id = ?,
|
|
1373
|
+
service_name = ?,
|
|
1374
|
+
model = ?
|
|
1375
|
+
WHERE id = ?
|
|
1376
|
+
`).run(now, session.totalTokens || 0, session.vendorId || null, session.vendorName || null, session.serviceId || null, session.serviceName || null, session.model || null, session.id);
|
|
1377
|
+
}
|
|
1378
|
+
else {
|
|
1379
|
+
// 创建新 session
|
|
1380
|
+
this.db.prepare(`
|
|
1381
|
+
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)
|
|
1382
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1383
|
+
`).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);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
/**
|
|
1387
|
+
* 获取所有 sessions
|
|
1388
|
+
*/
|
|
1389
|
+
getSessions(limit = 100, offset = 0) {
|
|
1390
|
+
const rows = this.db.prepare('SELECT * FROM sessions ORDER BY last_request_at DESC LIMIT ? OFFSET ?').all(limit, offset);
|
|
1391
|
+
return rows.map((row) => ({
|
|
1392
|
+
id: row.id,
|
|
1393
|
+
targetType: row.target_type,
|
|
1394
|
+
title: row.title,
|
|
1395
|
+
firstRequestAt: row.first_request_at,
|
|
1396
|
+
lastRequestAt: row.last_request_at,
|
|
1397
|
+
requestCount: row.request_count,
|
|
1398
|
+
totalTokens: row.total_tokens,
|
|
1399
|
+
vendorId: row.vendor_id,
|
|
1400
|
+
vendorName: row.vendor_name,
|
|
1401
|
+
serviceId: row.service_id,
|
|
1402
|
+
serviceName: row.service_name,
|
|
1403
|
+
model: row.model,
|
|
1404
|
+
}));
|
|
1405
|
+
}
|
|
1406
|
+
/**
|
|
1407
|
+
* 根据 session ID 获取 session
|
|
1408
|
+
*/
|
|
1409
|
+
getSession(id) {
|
|
1410
|
+
const row = this.db.prepare('SELECT * FROM sessions WHERE id = ?').get(id);
|
|
1411
|
+
if (!row)
|
|
1412
|
+
return null;
|
|
1413
|
+
return {
|
|
1414
|
+
id: row.id,
|
|
1415
|
+
targetType: row.target_type,
|
|
1416
|
+
title: row.title,
|
|
1417
|
+
firstRequestAt: row.first_request_at,
|
|
1418
|
+
lastRequestAt: row.last_request_at,
|
|
1419
|
+
requestCount: row.request_count,
|
|
1420
|
+
totalTokens: row.total_tokens,
|
|
1421
|
+
vendorId: row.vendor_id,
|
|
1422
|
+
vendorName: row.vendor_name,
|
|
1423
|
+
serviceId: row.service_id,
|
|
1424
|
+
serviceName: row.service_name,
|
|
1425
|
+
model: row.model,
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* 获取 sessions 总数
|
|
1430
|
+
*/
|
|
1431
|
+
getSessionsCount() {
|
|
1432
|
+
const result = this.db.prepare('SELECT COUNT(*) as count FROM sessions').get();
|
|
1433
|
+
return result.count;
|
|
1434
|
+
}
|
|
1435
|
+
/**
|
|
1436
|
+
* 删除指定 session
|
|
1437
|
+
*/
|
|
1438
|
+
deleteSession(id) {
|
|
1439
|
+
const result = this.db.prepare('DELETE FROM sessions WHERE id = ?').run(id);
|
|
1440
|
+
return result.changes > 0;
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* 清空所有 sessions
|
|
1444
|
+
*/
|
|
1445
|
+
clearSessions() {
|
|
1446
|
+
this.db.prepare('DELETE FROM sessions').run();
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* 获取指定 session 的请求日志
|
|
1450
|
+
* @param sessionId session ID
|
|
1451
|
+
* @param limit 限制数量
|
|
1452
|
+
*/
|
|
1453
|
+
getLogsBySessionId(sessionId_1) {
|
|
1454
|
+
return __awaiter(this, arguments, void 0, function* (sessionId, limit = 100) {
|
|
1455
|
+
var _a, e_8, _b, _c;
|
|
1456
|
+
// 从 LevelDB 中读取所有日志
|
|
1457
|
+
const allLogs = [];
|
|
1458
|
+
try {
|
|
1459
|
+
for (var _d = true, _e = __asyncValues(this.logDb.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
1460
|
+
_c = _f.value;
|
|
1461
|
+
_d = false;
|
|
1462
|
+
const [, value] = _c;
|
|
1463
|
+
const log = JSON.parse(value);
|
|
1464
|
+
// 检查日志是否属于该 session(通过 headers 中的 session_id 或 body 中的 metadata.user_id)
|
|
1465
|
+
if (this.isLogBelongsToSession(log, sessionId)) {
|
|
1466
|
+
allLogs.push(log);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
catch (e_8_1) { e_8 = { error: e_8_1 }; }
|
|
1471
|
+
finally {
|
|
1472
|
+
try {
|
|
1473
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
1474
|
+
}
|
|
1475
|
+
finally { if (e_8) throw e_8.error; }
|
|
1476
|
+
}
|
|
1477
|
+
// 按时间倒序排序并限制数量
|
|
1478
|
+
allLogs.sort((a, b) => b.timestamp - a.timestamp);
|
|
1479
|
+
return allLogs.slice(0, limit);
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
/**
|
|
1483
|
+
* 检查日志是否属于指定 session
|
|
1484
|
+
*/
|
|
1485
|
+
isLogBelongsToSession(log, sessionId) {
|
|
1486
|
+
var _a, _b;
|
|
1487
|
+
// 检查 headers 中的 session_id(Codex)
|
|
1488
|
+
if (((_a = log.headers) === null || _a === void 0 ? void 0 : _a['session_id']) === sessionId) {
|
|
1489
|
+
return true;
|
|
1490
|
+
}
|
|
1491
|
+
// 检查 body 中的 metadata.user_id(Claude Code)
|
|
1492
|
+
if (log.body) {
|
|
1493
|
+
try {
|
|
1494
|
+
const body = JSON.parse(log.body);
|
|
1495
|
+
if (((_b = body.metadata) === null || _b === void 0 ? void 0 : _b.user_id) === sessionId) {
|
|
1496
|
+
return true;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
catch (_c) {
|
|
1500
|
+
// 忽略解析错误
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
return false;
|
|
1504
|
+
}
|
|
1424
1505
|
close() {
|
|
1425
1506
|
this.db.close();
|
|
1426
1507
|
this.logDb.close();
|
|
1427
|
-
this.accessLogDb.close();
|
|
1428
1508
|
this.errorLogDb.close();
|
|
1429
1509
|
this.blacklistDb.close();
|
|
1430
1510
|
}
|