@wener/mcps 1.0.2 → 1.0.5
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/README.md +144 -0
- package/dist/index.mjs +213076 -1
- package/dist/mcps-cli.mjs +102632 -59429
- package/lib/audit/AuditContract.js.map +1 -0
- package/lib/{chat/audit.js → audit/chat.js} +1 -1
- package/lib/audit/chat.js.map +1 -0
- package/lib/audit/entities/ChatRequestEntity.js.map +1 -0
- package/lib/audit/entities/McpRequestEntity.js.map +1 -0
- package/lib/audit/entities/RequestLogEntity.js.map +1 -0
- package/lib/audit/entities/ResponseEntity.js.map +1 -0
- package/lib/audit/entities/index.js +6 -0
- package/lib/audit/entities/index.js.map +1 -0
- package/lib/audit/server/db.js +64 -0
- package/lib/audit/server/db.js.map +1 -0
- package/lib/audit/server/index.js +2 -0
- package/lib/audit/server/index.js.map +1 -0
- package/lib/{server/audit.js → audit/server/plugin.js} +73 -127
- package/lib/audit/server/plugin.js.map +1 -0
- package/lib/audit/types.js.map +1 -0
- package/lib/chat/handler.js +5 -5
- package/lib/chat/handler.js.map +1 -1
- package/lib/chat/index.js +1 -1
- package/lib/chat/index.js.map +1 -1
- package/lib/cli-start.js +36 -0
- package/lib/cli-start.js.map +1 -0
- package/lib/cli.js +19 -0
- package/lib/cli.js.map +1 -0
- package/lib/contracts/index.js +1 -1
- package/lib/contracts/index.js.map +1 -1
- package/lib/dev.server.js +7 -1
- package/lib/dev.server.js.map +1 -1
- package/lib/entities/index.js +2 -10
- package/lib/entities/index.js.map +1 -1
- package/lib/index.js +21 -3
- package/lib/index.js.map +1 -1
- package/lib/mcps-cli.js +6 -35
- package/lib/mcps-cli.js.map +1 -1
- package/lib/providers/feishu/def.js +35 -0
- package/lib/providers/feishu/def.js.map +1 -0
- package/lib/providers/findMcpServerDef.js +1 -0
- package/lib/providers/findMcpServerDef.js.map +1 -1
- package/lib/scripts/bundle.js +7 -1
- package/lib/scripts/bundle.js.map +1 -1
- package/lib/server/api-routes.js +7 -8
- package/lib/server/api-routes.js.map +1 -1
- package/lib/server/events.js +13 -0
- package/lib/server/events.js.map +1 -0
- package/lib/server/mcp-routes.js +31 -60
- package/lib/server/mcp-routes.js.map +1 -1
- package/lib/server/mcps-router.js +19 -24
- package/lib/server/mcps-router.js.map +1 -1
- package/lib/server/schema.js +22 -2
- package/lib/server/schema.js.map +1 -1
- package/lib/server/server.js +142 -87
- package/lib/server/server.js.map +1 -1
- package/package.json +145 -85
- package/src/{chat/audit.ts → audit/chat.ts} +3 -3
- package/src/audit/entities/index.ts +6 -0
- package/src/audit/server/db.ts +65 -0
- package/src/audit/server/index.ts +8 -0
- package/src/{server/audit.ts → audit/server/plugin.ts} +71 -144
- package/src/chat/handler.ts +5 -5
- package/src/chat/index.ts +1 -1
- package/src/cli-start.ts +43 -0
- package/src/cli.ts +45 -0
- package/src/contracts/index.ts +1 -1
- package/src/dev.server.ts +8 -1
- package/src/entities/index.ts +2 -12
- package/src/index.ts +47 -1
- package/src/mcps-cli.ts +6 -48
- package/src/providers/feishu/def.ts +37 -0
- package/src/providers/findMcpServerDef.ts +1 -0
- package/src/scripts/bundle.ts +12 -1
- package/src/server/api-routes.ts +11 -8
- package/src/server/events.ts +29 -0
- package/src/server/mcp-routes.ts +30 -58
- package/src/server/mcps-router.ts +21 -29
- package/src/server/schema.ts +23 -2
- package/src/server/server.ts +149 -81
- package/LICENSE +0 -21
- package/lib/chat/audit.js.map +0 -1
- package/lib/contracts/AuditContract.js.map +0 -1
- package/lib/entities/ChatRequestEntity.js.map +0 -1
- package/lib/entities/McpRequestEntity.js.map +0 -1
- package/lib/entities/RequestLogEntity.js.map +0 -1
- package/lib/entities/ResponseEntity.js.map +0 -1
- package/lib/entities/types.js.map +0 -1
- package/lib/server/audit.js.map +0 -1
- package/lib/server/db.js +0 -97
- package/lib/server/db.js.map +0 -1
- package/src/server/db.ts +0 -115
- /package/lib/{contracts → audit}/AuditContract.js +0 -0
- /package/lib/{entities → audit/entities}/ChatRequestEntity.js +0 -0
- /package/lib/{entities → audit/entities}/McpRequestEntity.js +0 -0
- /package/lib/{entities → audit/entities}/RequestLogEntity.js +0 -0
- /package/lib/{entities → audit/entities}/ResponseEntity.js +0 -0
- /package/lib/{entities → audit}/types.js +0 -0
- /package/src/{contracts → audit}/AuditContract.ts +0 -0
- /package/src/{entities → audit/entities}/ChatRequestEntity.ts +0 -0
- /package/src/{entities → audit/entities}/McpRequestEntity.ts +0 -0
- /package/src/{entities → audit/entities}/RequestLogEntity.ts +0 -0
- /package/src/{entities → audit/entities}/ResponseEntity.ts +0 -0
- /package/src/{entities → audit}/types.ts +0 -0
package/src/server/server.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import consola from 'consola';
|
|
2
|
+
import type { Context, Next } from 'hono';
|
|
2
3
|
import { Hono } from 'hono';
|
|
3
4
|
import { logger } from 'hono/logger';
|
|
4
5
|
import { LRUCache } from 'lru-cache';
|
|
@@ -6,24 +7,53 @@ import { isDevelopment } from 'std-env';
|
|
|
6
7
|
import type { McpServerInstance } from '@wener/ai/mcp';
|
|
7
8
|
import { findMcpServerDef } from '../providers/findMcpServerDef';
|
|
8
9
|
import { registerApiRoutes } from './api-routes';
|
|
9
|
-
import { auditMiddleware, configureAudit } from './audit';
|
|
10
10
|
import { registerChatRoutes } from './chat-routes';
|
|
11
11
|
import { loadConfig, loadEnvFiles, substituteEnvVars } from './config';
|
|
12
|
+
import { createMcpsEmitter, McpsEventType, type McpsEmitter } from './events';
|
|
12
13
|
import { registerMcpRoutes } from './mcp-routes';
|
|
13
14
|
|
|
14
15
|
const log = consola.withTag('mcps');
|
|
15
16
|
|
|
17
|
+
export interface McpsServerContext {
|
|
18
|
+
app: Hono;
|
|
19
|
+
config: import('./schema').McpsConfig;
|
|
20
|
+
emitter: McpsEmitter;
|
|
21
|
+
serverCache: LRUCache<string, McpServerInstance>;
|
|
22
|
+
/** Plugins can register additional oRPC routers here */
|
|
23
|
+
apiRouters: Record<string, any>;
|
|
24
|
+
/** Plugins can register stats providers here */
|
|
25
|
+
statsProvider?: StatsProvider;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface StatsProvider {
|
|
29
|
+
getStats(options: { from?: string | null; to?: string | null }): {
|
|
30
|
+
totalRequests: number;
|
|
31
|
+
totalErrors: number;
|
|
32
|
+
avgDurationMs: number;
|
|
33
|
+
byServer: Array<{ name: string; count: number }>;
|
|
34
|
+
byMethod: Array<{ method: string; count: number }>;
|
|
35
|
+
};
|
|
36
|
+
queryEvents(options: { limit?: number }): { events: Array<{ path: string }>; total: number };
|
|
37
|
+
}
|
|
38
|
+
|
|
16
39
|
export interface CreateServerOptions {
|
|
17
40
|
cwd?: string;
|
|
18
41
|
port?: number;
|
|
19
42
|
/** Enable server config discovery endpoints (default: false) */
|
|
20
43
|
discoveryConfig?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Called after core server is created but before routes are registered.
|
|
46
|
+
* Use this to set up optional plugins like audit via the emitter.
|
|
47
|
+
*/
|
|
48
|
+
setup?: (ctx: McpsServerContext) => void | Promise<void>;
|
|
21
49
|
}
|
|
22
50
|
|
|
23
51
|
export function createServer(options: CreateServerOptions = {}) {
|
|
24
|
-
const { cwd = process.cwd(), discoveryConfig: discoveryConfigOption } = options;
|
|
52
|
+
const { cwd = process.cwd(), discoveryConfig: discoveryConfigOption, setup } = options;
|
|
25
53
|
|
|
26
54
|
const app = new Hono();
|
|
55
|
+
const emitter = createMcpsEmitter();
|
|
56
|
+
const apiRouters: Record<string, any> = {};
|
|
27
57
|
|
|
28
58
|
// Request logging
|
|
29
59
|
app.use(
|
|
@@ -32,15 +62,14 @@ export function createServer(options: CreateServerOptions = {}) {
|
|
|
32
62
|
}),
|
|
33
63
|
);
|
|
34
64
|
|
|
35
|
-
//
|
|
36
|
-
app.use(
|
|
65
|
+
// Request event middleware - emits events for subscribers (audit, monitoring, etc.)
|
|
66
|
+
app.use(requestEventMiddleware(emitter));
|
|
37
67
|
|
|
38
68
|
// Load .env files first
|
|
39
69
|
loadEnvFiles(cwd);
|
|
40
70
|
|
|
41
71
|
// Load config (with env var substitution)
|
|
42
72
|
const config = substituteEnvVars(loadConfig(cwd));
|
|
43
|
-
// discoveryConfig: CLI option overrides config file, defaults to false
|
|
44
73
|
const discoveryConfig = discoveryConfigOption ?? config.discoveryConfig ?? false;
|
|
45
74
|
|
|
46
75
|
// Log available server types from registry
|
|
@@ -48,15 +77,7 @@ export function createServer(options: CreateServerOptions = {}) {
|
|
|
48
77
|
log.info(`Available server types: ${serverDefs.map((d) => d.name).join(', ')}`);
|
|
49
78
|
log.info(`Loaded ${Object.keys(config.servers).length} servers from config (discoveryConfig: ${discoveryConfig})`);
|
|
50
79
|
|
|
51
|
-
//
|
|
52
|
-
// DB will only be initialized when the first audit event needs persistence
|
|
53
|
-
configureAudit(config.audit, config.db);
|
|
54
|
-
const auditEnabled = config.audit?.enabled !== false;
|
|
55
|
-
const auditDbPath = config.audit?.db?.path ?? config.db?.path ?? '.mcps.db';
|
|
56
|
-
log.info(`Audit configured: enabled=${auditEnabled}, db=${auditDbPath} (lazy init)`);
|
|
57
|
-
|
|
58
|
-
// Unified cache for all MCP servers (both pre-configured and dynamic)
|
|
59
|
-
// Keyed by cache key from def.getCacheKey() or `config::${name}` for pre-configured
|
|
80
|
+
// Unified cache for all MCP servers
|
|
60
81
|
const serverCache = new LRUCache<string, McpServerInstance>({
|
|
61
82
|
max: 100,
|
|
62
83
|
dispose: (value, key) => {
|
|
@@ -65,65 +86,61 @@ export function createServer(options: CreateServerOptions = {}) {
|
|
|
65
86
|
},
|
|
66
87
|
});
|
|
67
88
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
},
|
|
89
|
+
const ctx: McpsServerContext = { app, config, emitter, serverCache, apiRouters };
|
|
90
|
+
|
|
91
|
+
const finalize = async () => {
|
|
92
|
+
// Allow plugins to set up before routes are registered
|
|
93
|
+
await setup?.(ctx);
|
|
94
|
+
|
|
95
|
+
// =========================================================================
|
|
96
|
+
// Register MCP routes (pre-configured and dynamic endpoints)
|
|
97
|
+
// =========================================================================
|
|
98
|
+
registerMcpRoutes({ app, config, serverCache });
|
|
99
|
+
|
|
100
|
+
// =========================================================================
|
|
101
|
+
// Register Chat/LLM Gateway routes
|
|
102
|
+
// =========================================================================
|
|
103
|
+
registerChatRoutes({ app, config });
|
|
104
|
+
|
|
105
|
+
// =========================================================================
|
|
106
|
+
// Health and info endpoints
|
|
107
|
+
// =========================================================================
|
|
108
|
+
app.get('/health', (c) => c.json({ status: 'ok' }));
|
|
109
|
+
app.get('/', (c) => c.json({ message: 'hello' }));
|
|
110
|
+
|
|
111
|
+
if (isDevelopment || discoveryConfig) {
|
|
112
|
+
app.get('/info', (c) => {
|
|
113
|
+
const routes = app.routes
|
|
114
|
+
.map((r) => ({ method: r.method, path: r.path }))
|
|
115
|
+
.filter((r) => r.method !== 'ALL' || r.path.startsWith('/mcp/'))
|
|
116
|
+
.sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method));
|
|
117
|
+
|
|
118
|
+
const mcpRoutes = routes.filter((r) => r.path.startsWith('/mcp/')).map((r) => r.path);
|
|
119
|
+
const apiRoutes = routes.filter((r) => r.path.startsWith('/api/')).map((r) => `${r.method} ${r.path}`);
|
|
120
|
+
const chatRoutes = routes.filter((r) => r.path.startsWith('/v1/')).map((r) => `${r.method} ${r.path}`);
|
|
121
|
+
const uniqueMcpPaths = [...new Set(mcpRoutes)];
|
|
122
|
+
|
|
123
|
+
return c.json({
|
|
124
|
+
name: '@wener/mcps',
|
|
125
|
+
version: '0.1.0',
|
|
126
|
+
servers: Object.keys(config.servers),
|
|
127
|
+
serverTypes: findMcpServerDef().map((d) => d.name),
|
|
128
|
+
models: config.models ? config.models.map((m) => m.name) : [],
|
|
129
|
+
endpoints: {
|
|
130
|
+
mcp: uniqueMcpPaths,
|
|
131
|
+
api: [...new Set(apiRoutes)],
|
|
132
|
+
chat: [...new Set(chatRoutes)],
|
|
133
|
+
},
|
|
134
|
+
});
|
|
115
135
|
});
|
|
116
|
-
}
|
|
117
|
-
}
|
|
136
|
+
}
|
|
118
137
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
138
|
+
// =========================================================================
|
|
139
|
+
// Register oRPC API routes (with any plugin-provided routers)
|
|
140
|
+
// =========================================================================
|
|
141
|
+
registerApiRoutes({ app, config, apiRouters, statsProvider: ctx.statsProvider });
|
|
142
|
+
};
|
|
123
143
|
|
|
124
|
-
/**
|
|
125
|
-
* Print available endpoints grouped by category
|
|
126
|
-
*/
|
|
127
144
|
const printEndpoints = () => {
|
|
128
145
|
const routes = app.routes;
|
|
129
146
|
const mcpPaths = new Set<string>();
|
|
@@ -145,19 +162,70 @@ export function createServer(options: CreateServerOptions = {}) {
|
|
|
145
162
|
}
|
|
146
163
|
|
|
147
164
|
log.info('Available endpoints:');
|
|
148
|
-
if (mcpPaths.size > 0) {
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
if (
|
|
152
|
-
|
|
165
|
+
if (mcpPaths.size > 0) log.info(` MCP: ${[...mcpPaths].sort().join(', ')}`);
|
|
166
|
+
if (chatPaths.size > 0) log.info(` Chat: ${[...chatPaths].sort().join(', ')}`);
|
|
167
|
+
if (apiPaths.size > 0) log.info(` API: ${[...apiPaths].sort().join(', ')}`);
|
|
168
|
+
if (otherPaths.size > 0) log.info(` Other: ${[...otherPaths].sort().join(', ')}`);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
return { app, config, emitter, serverCache, printEndpoints, finalize };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function headersToRecord(headers: Headers): Record<string, string> {
|
|
175
|
+
const record: Record<string, string> = {};
|
|
176
|
+
headers.forEach((value, key) => {
|
|
177
|
+
record[key] = value;
|
|
178
|
+
});
|
|
179
|
+
return record;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Middleware that emits request events via the emitter.
|
|
184
|
+
* Subscribers (like audit plugin) can listen and handle these events.
|
|
185
|
+
*/
|
|
186
|
+
function requestEventMiddleware(emitter: McpsEmitter) {
|
|
187
|
+
return async (c: Context, next: Next) => {
|
|
188
|
+
const startTime = Date.now();
|
|
189
|
+
const path = c.req.path;
|
|
190
|
+
|
|
191
|
+
let serverName: string | undefined;
|
|
192
|
+
let serverType: string | undefined;
|
|
193
|
+
|
|
194
|
+
const mcpMatch = path.match(/^\/mcp\/([^/]+)/);
|
|
195
|
+
if (mcpMatch) {
|
|
196
|
+
serverName = mcpMatch[1];
|
|
197
|
+
if (['tencent-cls', 'sql', 'prometheus', 'relay'].includes(serverName)) {
|
|
198
|
+
serverType = serverName;
|
|
199
|
+
} else {
|
|
200
|
+
serverType = 'custom';
|
|
201
|
+
}
|
|
153
202
|
}
|
|
154
|
-
|
|
155
|
-
|
|
203
|
+
|
|
204
|
+
if (path.startsWith('/v1/')) {
|
|
205
|
+
serverType = 'chat';
|
|
156
206
|
}
|
|
157
|
-
|
|
158
|
-
|
|
207
|
+
|
|
208
|
+
let error: string | undefined;
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
await next();
|
|
212
|
+
} catch (e) {
|
|
213
|
+
error = e instanceof Error ? e.message : String(e);
|
|
214
|
+
throw e;
|
|
215
|
+
} finally {
|
|
216
|
+
const durationMs = Date.now() - startTime;
|
|
217
|
+
|
|
218
|
+
emitter.emit(McpsEventType.Request, {
|
|
219
|
+
timestamp: new Date().toISOString(),
|
|
220
|
+
method: c.req.method,
|
|
221
|
+
path,
|
|
222
|
+
serverName,
|
|
223
|
+
serverType,
|
|
224
|
+
status: c.res.status,
|
|
225
|
+
durationMs,
|
|
226
|
+
error,
|
|
227
|
+
requestHeaders: headersToRecord(c.req.raw.headers),
|
|
228
|
+
});
|
|
159
229
|
}
|
|
160
230
|
};
|
|
161
|
-
|
|
162
|
-
return { app, config, serverCache, printEndpoints };
|
|
163
231
|
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2020 陈杨文
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/lib/chat/audit.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/chat/audit.ts"],"sourcesContent":["/**\n * Chat Request Audit Service\n * Records all chat/LLM API requests for auditing and metering\n */\nimport type { Context } from 'hono';\nimport consola from 'consola';\nimport type { ChatProtocolType, RequestStatus as RequestStatusType, ChatAuditStats } from '../entities/types';\n\nconst log = consola.withTag('chat-audit');\n\n/**\n * Re-export protocol and status constants for convenience\n */\nexport const ChatProtocol = {\n\tOPENAI: 'openai' as ChatProtocolType,\n\tANTHROPIC: 'anthropic' as ChatProtocolType,\n\tGEMINI: 'gemini' as ChatProtocolType,\n};\n\nexport const RequestStatus = {\n\tPENDING: 'pending' as RequestStatusType,\n\tSUCCESS: 'success' as RequestStatusType,\n\tERROR: 'error' as RequestStatusType,\n\tTIMEOUT: 'timeout' as RequestStatusType,\n};\n\n/**\n * Chat audit record (in-memory representation)\n */\nexport interface ChatAuditRecord {\n\trequestId: string;\n\trequestedAt: Date;\n\tcompletedAt?: Date;\n\tstatus: RequestStatusType;\n\tmethod: string;\n\tendpoint: string;\n\tinputProtocol: ChatProtocolType;\n\toutputProtocol: ChatProtocolType;\n\tmodel: string;\n\tresolvedModel?: string;\n\tprovider?: string;\n\tupstreamUrl?: string;\n\tstreaming: boolean;\n\tinputTokens?: number;\n\toutputTokens?: number;\n\ttotalTokens?: number;\n\tdurationMs?: number;\n\tttftMs?: number;\n\thttpStatus?: number;\n\terrorMessage?: string;\n\terrorCode?: string;\n\tclientIp?: string;\n\tuserAgent?: string;\n\tuserId?: string;\n\torgId?: string;\n\tapiKeyId?: string;\n\trequestMeta?: Record<string, unknown>;\n\tresponseMeta?: Record<string, unknown>;\n\tcost?: string;\n\tcurrency?: string;\n}\n\n/**\n * Audit store interface\n */\nexport interface ChatAuditStore {\n\t/**\n\t * Save a chat audit record\n\t */\n\tsave(record: ChatAuditRecord): Promise<void>;\n\n\t/**\n\t * Query audit records\n\t */\n\tquery(options: ChatAuditQueryOptions): Promise<{ records: ChatAuditRecord[]; total: number }>;\n\n\t/**\n\t * Get aggregate statistics\n\t */\n\tgetStats(options: { from?: Date; to?: Date }): Promise<import('../entities/types').ChatAuditStats>;\n}\n\nexport interface ChatAuditQueryOptions {\n\tlimit?: number;\n\toffset?: number;\n\tmodel?: string;\n\tprovider?: string;\n\tstatus?: RequestStatusType;\n\tfrom?: Date;\n\tto?: Date;\n\tuserId?: string;\n\torgId?: string;\n}\n\n// Re-export ChatAuditStats from entities\nexport type { ChatAuditStats } from '../entities/types';\n\n/**\n * In-memory audit store implementation\n */\nexport class InMemoryChatAuditStore implements ChatAuditStore {\n\tprivate records: ChatAuditRecord[] = [];\n\tprivate maxSize: number;\n\n\tconstructor(maxSize = 10000) {\n\t\tthis.maxSize = maxSize;\n\t}\n\n\tasync save(record: ChatAuditRecord): Promise<void> {\n\t\tthis.records.unshift(record);\n\n\t\t// Trim to max size\n\t\tif (this.records.length > this.maxSize) {\n\t\t\tthis.records = this.records.slice(0, this.maxSize);\n\t\t}\n\n\t\tlog.debug(`Saved audit record: ${record.requestId} model=${record.model} status=${record.status}`);\n\t}\n\n\tasync query(options: ChatAuditQueryOptions): Promise<{ records: ChatAuditRecord[]; total: number }> {\n\t\tlet filtered = [...this.records];\n\n\t\tif (options.model) {\n\t\t\tfiltered = filtered.filter((r) => r.model === options.model);\n\t\t}\n\t\tif (options.provider) {\n\t\t\tfiltered = filtered.filter((r) => r.provider === options.provider);\n\t\t}\n\t\tif (options.status) {\n\t\t\tfiltered = filtered.filter((r) => r.status === options.status);\n\t\t}\n\t\tif (options.userId) {\n\t\t\tfiltered = filtered.filter((r) => r.userId === options.userId);\n\t\t}\n\t\tif (options.orgId) {\n\t\t\tfiltered = filtered.filter((r) => r.orgId === options.orgId);\n\t\t}\n\t\tif (options.from) {\n\t\t\tconst from = options.from;\n\t\t\tfiltered = filtered.filter((r) => r.requestedAt >= from);\n\t\t}\n\t\tif (options.to) {\n\t\t\tconst to = options.to;\n\t\t\tfiltered = filtered.filter((r) => r.requestedAt <= to);\n\t\t}\n\n\t\tconst total = filtered.length;\n\t\tconst offset = options.offset || 0;\n\t\tconst limit = options.limit || 50;\n\n\t\treturn {\n\t\t\trecords: filtered.slice(offset, offset + limit),\n\t\t\ttotal,\n\t\t};\n\t}\n\n\tasync getStats(options: { from?: Date; to?: Date }): Promise<ChatAuditStats> {\n\t\tlet filtered = [...this.records];\n\n\t\tif (options.from) {\n\t\t\tconst from = options.from;\n\t\t\tfiltered = filtered.filter((r) => r.requestedAt >= from);\n\t\t}\n\t\tif (options.to) {\n\t\t\tconst to = options.to;\n\t\t\tfiltered = filtered.filter((r) => r.requestedAt <= to);\n\t\t}\n\n\t\tconst totalRequests = filtered.length;\n\t\tconst successfulRequests = filtered.filter((r) => r.status === RequestStatus.SUCCESS).length;\n\t\tconst failedRequests = filtered.filter((r) => r.status === RequestStatus.ERROR).length;\n\n\t\tconst totalInputTokens = filtered.reduce((sum, r) => sum + (r.inputTokens || 0), 0);\n\t\tconst totalOutputTokens = filtered.reduce((sum, r) => sum + (r.outputTokens || 0), 0);\n\n\t\tconst durations = filtered.map((r) => r.durationMs).filter((d): d is number => d != null);\n\t\tconst avgDurationMs = durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0;\n\n\t\t// Group by model\n\t\tconst modelMap = new Map<string, { count: number; tokens: number }>();\n\t\tfor (const r of filtered) {\n\t\t\tconst existing = modelMap.get(r.model) || { count: 0, tokens: 0 };\n\t\t\texisting.count++;\n\t\t\texisting.tokens += (r.inputTokens || 0) + (r.outputTokens || 0);\n\t\t\tmodelMap.set(r.model, existing);\n\t\t}\n\t\tconst byModel = Array.from(modelMap.entries())\n\t\t\t.map(([model, data]) => ({ model, ...data }))\n\t\t\t.sort((a, b) => b.count - a.count);\n\n\t\t// Group by provider\n\t\tconst providerMap = new Map<string, { count: number; tokens: number }>();\n\t\tfor (const r of filtered) {\n\t\t\tconst provider = r.provider || 'unknown';\n\t\t\tconst existing = providerMap.get(provider) || { count: 0, tokens: 0 };\n\t\t\texisting.count++;\n\t\t\texisting.tokens += (r.inputTokens || 0) + (r.outputTokens || 0);\n\t\t\tproviderMap.set(provider, existing);\n\t\t}\n\t\tconst byProvider = Array.from(providerMap.entries())\n\t\t\t.map(([provider, data]) => ({ provider, ...data }))\n\t\t\t.sort((a, b) => b.count - a.count);\n\n\t\treturn {\n\t\t\ttotalRequests,\n\t\t\tsuccessfulRequests,\n\t\t\tfailedRequests,\n\t\t\ttotalInputTokens,\n\t\t\ttotalOutputTokens,\n\t\t\tavgDurationMs,\n\t\t\tbyModel,\n\t\t\tbyProvider,\n\t\t};\n\t}\n}\n\n// Global audit store instance\nlet auditStore: ChatAuditStore = new InMemoryChatAuditStore();\n\n/**\n * Set the audit store implementation\n */\nexport function setChatAuditStore(store: ChatAuditStore) {\n\tauditStore = store;\n}\n\n/**\n * Get the current audit store\n */\nexport function getChatAuditStore(): ChatAuditStore {\n\treturn auditStore;\n}\n\n/**\n * Generate a unique request ID\n */\nexport function generateRequestId(): string {\n\treturn `chat-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * Create an audit context for tracking a request\n */\nexport function createAuditContext(options: {\n\tmethod: string;\n\tendpoint: string;\n\tmodel: string;\n\tinputProtocol: ChatProtocolType;\n\toutputProtocol: ChatProtocolType;\n\tstreaming: boolean;\n\tclientIp?: string;\n\tuserAgent?: string;\n\tuserId?: string;\n\trequestMeta?: Record<string, unknown>;\n}): ChatAuditContext {\n\treturn new ChatAuditContext(options);\n}\n\n/**\n * Audit context for tracking a single request lifecycle\n */\nexport class ChatAuditContext {\n\tprivate record: ChatAuditRecord;\n\tprivate startTime: number;\n\tprivate firstTokenTime?: number;\n\n\tconstructor(options: {\n\t\tmethod: string;\n\t\tendpoint: string;\n\t\tmodel: string;\n\t\tinputProtocol: ChatProtocolType;\n\t\toutputProtocol: ChatProtocolType;\n\t\tstreaming: boolean;\n\t\tclientIp?: string;\n\t\tuserAgent?: string;\n\t\tuserId?: string;\n\t\trequestMeta?: Record<string, unknown>;\n\t}) {\n\t\tthis.startTime = Date.now();\n\t\tthis.record = {\n\t\t\trequestId: generateRequestId(),\n\t\t\trequestedAt: new Date(),\n\t\t\tstatus: RequestStatus.PENDING,\n\t\t\tmethod: options.method,\n\t\t\tendpoint: options.endpoint,\n\t\t\tinputProtocol: options.inputProtocol,\n\t\t\toutputProtocol: options.outputProtocol,\n\t\t\tmodel: options.model,\n\t\t\tstreaming: options.streaming,\n\t\t\tclientIp: options.clientIp,\n\t\t\tuserAgent: options.userAgent,\n\t\t\tuserId: options.userId,\n\t\t\trequestMeta: options.requestMeta,\n\t\t};\n\t}\n\n\tget requestId(): string {\n\t\treturn this.record.requestId;\n\t}\n\n\t/**\n\t * Set the resolved model and provider info\n\t */\n\tsetProvider(options: { resolvedModel?: string; provider?: string; upstreamUrl?: string }) {\n\t\tObject.assign(this.record, options);\n\t}\n\n\t/**\n\t * Record first token received (for TTFT)\n\t */\n\trecordFirstToken() {\n\t\tif (!this.firstTokenTime) {\n\t\t\tthis.firstTokenTime = Date.now();\n\t\t\tthis.record.ttftMs = this.firstTokenTime - this.startTime;\n\t\t}\n\t}\n\n\t/**\n\t * Record token usage\n\t */\n\tsetTokenUsage(input: number, output: number) {\n\t\tthis.record.inputTokens = input;\n\t\tthis.record.outputTokens = output;\n\t\tthis.record.totalTokens = input + output;\n\t}\n\n\t/**\n\t * Set response metadata\n\t */\n\tsetResponseMeta(meta: Record<string, unknown>) {\n\t\tthis.record.responseMeta = meta;\n\t}\n\n\t/**\n\t * Get current duration in ms\n\t */\n\tgetDuration(): number {\n\t\treturn Date.now() - this.startTime;\n\t}\n\n\t/**\n\t * Complete the request successfully\n\t */\n\tasync complete(httpStatus: number = 200) {\n\t\tthis.record.status = RequestStatus.SUCCESS;\n\t\tthis.record.httpStatus = httpStatus;\n\t\tthis.record.completedAt = new Date();\n\t\tthis.record.durationMs = Date.now() - this.startTime;\n\n\t\tawait auditStore.save(this.record);\n\t}\n\n\t/**\n\t * Complete the request with an error\n\t */\n\tasync error(errorMessage: string, errorCode?: string, httpStatus: number = 500) {\n\t\tthis.record.status = RequestStatus.ERROR;\n\t\tthis.record.httpStatus = httpStatus;\n\t\tthis.record.errorMessage = errorMessage;\n\t\tthis.record.errorCode = errorCode;\n\t\tthis.record.completedAt = new Date();\n\t\tthis.record.durationMs = Date.now() - this.startTime;\n\n\t\tawait auditStore.save(this.record);\n\t}\n}\n\n/**\n * Extract client IP from Hono context\n */\nexport function extractClientIp(c: Context): string | undefined {\n\treturn (\n\t\tc.req.header('x-forwarded-for')?.split(',')[0]?.trim() ||\n\t\tc.req.header('x-real-ip') ||\n\t\tc.req.header('cf-connecting-ip')\n\t);\n}\n"],"names":["consola","log","withTag","ChatProtocol","OPENAI","ANTHROPIC","GEMINI","RequestStatus","PENDING","SUCCESS","ERROR","TIMEOUT","InMemoryChatAuditStore","records","maxSize","save","record","unshift","length","slice","debug","requestId","model","status","query","options","filtered","filter","r","provider","userId","orgId","from","requestedAt","to","total","offset","limit","getStats","totalRequests","successfulRequests","failedRequests","totalInputTokens","reduce","sum","inputTokens","totalOutputTokens","outputTokens","durations","map","durationMs","d","avgDurationMs","a","b","modelMap","Map","existing","get","count","tokens","set","byModel","Array","entries","data","sort","providerMap","byProvider","auditStore","setChatAuditStore","store","getChatAuditStore","generateRequestId","Date","now","Math","random","toString","substring","createAuditContext","ChatAuditContext","startTime","firstTokenTime","method","endpoint","inputProtocol","outputProtocol","streaming","clientIp","userAgent","requestMeta","setProvider","Object","assign","recordFirstToken","ttftMs","setTokenUsage","input","output","totalTokens","setResponseMeta","meta","responseMeta","getDuration","complete","httpStatus","completedAt","error","errorMessage","errorCode","extractClientIp","c","req","header","split","trim"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/contracts/AuditContract.ts"],"sourcesContent":["import { oc } from '@orpc/contract';\nimport { z } from 'zod';\n\n// Audit event schema\nexport const AuditEventSchema = z.object({\n\tid: z.string(),\n\ttimestamp: z.string(),\n\tmethod: z.string(),\n\tpath: z.string(),\n\tserverName: z.string().nullish(),\n\tserverType: z.string().nullish(),\n\tstatus: z.number().nullish(),\n\tdurationMs: z.number().nullish(),\n\trequestHeaders: z.record(z.string(), z.string()).nullish(),\n\tresponseHeaders: z.record(z.string(), z.string()).nullish(),\n\trequestBody: z.unknown().nullish(),\n\tresponseBody: z.unknown().nullish(),\n\terror: z.string().nullish(),\n\ttoolName: z.string().nullish(),\n\ttoolArgs: z.unknown().nullish(),\n});\nexport type AuditEvent = z.infer<typeof AuditEventSchema>;\n\n// Query params\nexport const AuditQuerySchema = z.object({\n\tlimit: z.coerce.number().default(50),\n\toffset: z.coerce.number().default(0),\n\tserverName: z.string().nullish(),\n\tserverType: z.string().nullish(),\n\tmethod: z.string().nullish(),\n\tfrom: z.string().nullish(),\n\tto: z.string().nullish(),\n});\n\n// Audit stats\nexport const AuditStatsSchema = z.object({\n\ttotalRequests: z.number(),\n\ttotalErrors: z.number(),\n\tavgDurationMs: z.number(),\n\tbyServer: z.array(\n\t\tz.object({\n\t\t\tname: z.string(),\n\t\t\tcount: z.number(),\n\t\t}),\n\t),\n\tbyMethod: z.array(\n\t\tz.object({\n\t\t\tmethod: z.string(),\n\t\t\tcount: z.number(),\n\t\t}),\n\t),\n});\n\n// Contract definition\nexport const AuditContract = oc.prefix('/audit').router({\n\t// List audit events\n\tlist: oc\n\t\t.input(AuditQuerySchema)\n\t\t.output(\n\t\t\tz.object({\n\t\t\t\tevents: z.array(AuditEventSchema),\n\t\t\t\ttotal: z.number(),\n\t\t\t}),\n\t\t)\n\t\t.route({ method: 'GET', path: '/', summary: 'List audit events' }),\n\n\t// Get single event\n\tget: oc\n\t\t.input(z.object({ id: z.string() }))\n\t\t.output(AuditEventSchema.nullable())\n\t\t.route({ method: 'GET', path: '/{id}', summary: 'Get audit event by ID' }),\n\n\t// Get stats\n\tstats: oc\n\t\t.input(\n\t\t\tz.object({\n\t\t\t\tfrom: z.string().nullish(),\n\t\t\t\tto: z.string().nullish(),\n\t\t\t}),\n\t\t)\n\t\t.output(AuditStatsSchema)\n\t\t.route({ method: 'GET', path: '/stats', summary: 'Get audit statistics' }),\n\n\t// Clear old events\n\tclear: oc\n\t\t.input(\n\t\t\tz.object({\n\t\t\t\tbefore: z.string().describe('Clear events before this timestamp'),\n\t\t\t}),\n\t\t)\n\t\t.output(z.object({ deleted: z.number() }))\n\t\t.route({ method: 'DELETE', path: '/', summary: 'Clear audit events' }),\n});\n"],"names":["oc","z","AuditEventSchema","object","id","string","timestamp","method","path","serverName","nullish","serverType","status","number","durationMs","requestHeaders","record","responseHeaders","requestBody","unknown","responseBody","error","toolName","toolArgs","AuditQuerySchema","limit","coerce","default","offset","from","to","AuditStatsSchema","totalRequests","totalErrors","avgDurationMs","byServer","array","name","count","byMethod","AuditContract","prefix","router","list","input","output","events","total","route","summary","get","nullable","stats","clear","before","describe","deleted"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/entities/ChatRequestEntity.ts"],"sourcesContent":["import { Entity, Enum, PrimaryKey, Property } from '@mikro-orm/decorators/es';\n\n/**\n * Chat protocol type\n */\nexport const ChatProtocolType = Object.freeze({\n\tOpenAI: 'openai',\n\tAnthropic: 'anthropic',\n\tGemini: 'gemini',\n} as const);\nexport type ChatProtocolType = (typeof ChatProtocolType)[keyof typeof ChatProtocolType];\n\n/**\n * Request status\n */\nexport const RequestStatus = Object.freeze({\n\tPending: 'pending',\n\tSuccess: 'success',\n\tError: 'error',\n\tTimeout: 'timeout',\n} as const);\nexport type RequestStatus = (typeof RequestStatus)[keyof typeof RequestStatus];\n\n/**\n * Chat Request Entity for auditing and metering\n */\n@Entity({ tableName: 'chat_request' })\nexport class ChatRequestEntity {\n\t@PrimaryKey({ type: 'integer' })\n\tid!: number;\n\n\t/** Unique request ID for tracing */\n\t@Property({ type: 'string', unique: true })\n\trequestId!: string;\n\n\t/** Request timestamp */\n\t@Property({ type: 'datetime' })\n\trequestedAt: Date = new Date();\n\n\t/** Response timestamp */\n\t@Property({ type: 'datetime', nullable: true })\n\tcompletedAt?: Date;\n\n\t/** Request status */\n\t@Enum(() => RequestStatus)\n\tstatus: RequestStatus = RequestStatus.Pending;\n\n\t/** HTTP method */\n\t@Property({ type: 'string' })\n\tmethod!: string;\n\n\t/** Request path/endpoint */\n\t@Property({ type: 'string' })\n\tendpoint!: string;\n\n\t/** Input protocol (client-facing) */\n\t@Enum(() => ChatProtocolType)\n\tinputProtocol!: ChatProtocolType;\n\n\t/** Output protocol (upstream provider) */\n\t@Enum(() => ChatProtocolType)\n\toutputProtocol!: ChatProtocolType;\n\n\t/** Model name requested */\n\t@Property({ type: 'string' })\n\tmodel!: string;\n\n\t/** Resolved model name */\n\t@Property({ type: 'string', nullable: true })\n\tresolvedModel?: string;\n\n\t/** Provider name */\n\t@Property({ type: 'string', nullable: true })\n\tprovider?: string;\n\n\t/** Upstream base URL */\n\t@Property({ type: 'string', nullable: true })\n\tupstreamUrl?: string;\n\n\t/** Whether request was streaming */\n\t@Property({ type: 'boolean', default: false })\n\tstreaming: boolean = false;\n\n\t/** Input token count */\n\t@Property({ type: 'integer', nullable: true })\n\tinputTokens?: number;\n\n\t/** Output token count */\n\t@Property({ type: 'integer', nullable: true })\n\toutputTokens?: number;\n\n\t/** Total token count */\n\t@Property({ type: 'integer', nullable: true })\n\ttotalTokens?: number;\n\n\t/** Request duration in ms */\n\t@Property({ type: 'integer', nullable: true })\n\tdurationMs?: number;\n\n\t/** Time to first token in ms */\n\t@Property({ type: 'integer', nullable: true })\n\tttftMs?: number;\n\n\t/** HTTP status code */\n\t@Property({ type: 'integer', nullable: true })\n\thttpStatus?: number;\n\n\t/** Error message */\n\t@Property({ type: 'text', nullable: true })\n\terrorMessage?: string;\n\n\t/** Error code */\n\t@Property({ type: 'string', nullable: true })\n\terrorCode?: string;\n\n\t/** Client IP */\n\t@Property({ type: 'string', nullable: true })\n\tclientIp?: string;\n\n\t/** User agent */\n\t@Property({ type: 'string', nullable: true })\n\tuserAgent?: string;\n\n\t/** User ID */\n\t@Property({ type: 'string', nullable: true })\n\tuserId?: string;\n\n\t/** Organization ID */\n\t@Property({ type: 'string', nullable: true })\n\torgId?: string;\n\n\t/** API key ID (not the actual key) */\n\t@Property({ type: 'string', nullable: true })\n\tapiKeyId?: string;\n\n\t/** Request metadata (JSON) */\n\t@Property({ type: 'json', nullable: true })\n\trequestMeta?: Record<string, unknown>;\n\n\t/** Response metadata (JSON) */\n\t@Property({ type: 'json', nullable: true })\n\tresponseMeta?: Record<string, unknown>;\n\n\t/** Cost in credits (decimal string) */\n\t@Property({ type: 'string', nullable: true })\n\tcost?: string;\n\n\t/** Currency */\n\t@Property({ type: 'string', nullable: true })\n\tcurrency?: string;\n\n\t@Property({ type: 'datetime' })\n\tcreatedAt: Date = new Date();\n\n\t@Property({ type: 'datetime', onUpdate: () => new Date() })\n\tupdatedAt: Date = new Date();\n}\n"],"names":["id","requestId","requestedAt","completedAt","status","method","endpoint","inputProtocol","outputProtocol","model","resolvedModel","provider","upstreamUrl","streaming","inputTokens","outputTokens","totalTokens","durationMs","ttftMs","httpStatus","errorMessage","errorCode","clientIp","userAgent","userId","orgId","apiKeyId","requestMeta","responseMeta","cost","currency","createdAt","updatedAt","Entity","Enum","PrimaryKey","Property","ChatProtocolType","Object","freeze","OpenAI","Anthropic","Gemini","RequestStatus","Pending","Success","Error","Timeout","tableName","type","unique","nullable","default","onUpdate","Date","ChatRequestEntity"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/entities/McpRequestEntity.ts"],"sourcesContent":["import { Entity, Enum, PrimaryKey, Property } from '@mikro-orm/decorators/es';\n\n/**\n * MCP server type\n */\nexport const McpServerType = Object.freeze({\n\tTencentCls: 'tencent-cls',\n\tSql: 'sql',\n\tPrometheus: 'prometheus',\n\tRelay: 'relay',\n\tCustom: 'custom',\n} as const);\nexport type McpServerType = (typeof McpServerType)[keyof typeof McpServerType];\n\n/**\n * MCP request type (JSON-RPC method)\n */\nexport const McpRequestType = Object.freeze({\n\tInitialize: 'initialize',\n\tToolsList: 'tools/list',\n\tToolsCall: 'tools/call',\n\tResourcesList: 'resources/list',\n\tResourcesRead: 'resources/read',\n\tPromptsList: 'prompts/list',\n\tPromptsGet: 'prompts/get',\n\tCompletionComplete: 'completion/complete',\n\tLoggingSetLevel: 'logging/setLevel',\n\tPing: 'ping',\n\tOther: 'other',\n} as const);\nexport type McpRequestType = (typeof McpRequestType)[keyof typeof McpRequestType];\n\n/**\n * Request status\n */\nexport const RequestStatus = Object.freeze({\n\tPending: 'pending',\n\tSuccess: 'success',\n\tError: 'error',\n\tTimeout: 'timeout',\n} as const);\nexport type RequestStatus = (typeof RequestStatus)[keyof typeof RequestStatus];\n\n/**\n * MCP Request Entity for auditing\n */\n@Entity({ tableName: 'mcp_request' })\nexport class McpRequestEntity {\n\t@PrimaryKey({ type: 'integer' })\n\tid!: number;\n\n\t/** Unique request ID */\n\t@Property({ type: 'string' })\n\trequestId!: string;\n\n\t/** MCP session ID */\n\t@Property({ type: 'string', nullable: true })\n\tsessionId?: string;\n\n\t/** Request timestamp */\n\t@Property({ type: 'datetime' })\n\trequestedAt: Date = new Date();\n\n\t/** Response timestamp */\n\t@Property({ type: 'datetime', nullable: true })\n\tcompletedAt?: Date;\n\n\t/** Request status */\n\t@Enum(() => RequestStatus)\n\tstatus: RequestStatus = RequestStatus.Pending;\n\n\t/** HTTP method */\n\t@Property({ type: 'string' })\n\tmethod!: string;\n\n\t/** Request path */\n\t@Property({ type: 'string' })\n\tpath!: string;\n\n\t/** MCP server name */\n\t@Property({ type: 'string' })\n\tserverName!: string;\n\n\t/** MCP server type */\n\t@Enum(() => McpServerType)\n\tserverType: McpServerType = McpServerType.Custom;\n\n\t/** MCP request type (JSON-RPC method) */\n\t@Enum(() => McpRequestType)\n\tmcpMethod: McpRequestType = McpRequestType.Other;\n\n\t/** Tool name (for tools/call) */\n\t@Property({ type: 'string', nullable: true })\n\ttoolName?: string;\n\n\t/** Resource URI (for resources/read) */\n\t@Property({ type: 'string', nullable: true })\n\tresourceUri?: string;\n\n\t/** Prompt name (for prompts/get) */\n\t@Property({ type: 'string', nullable: true })\n\tpromptName?: string;\n\n\t/** Request duration in ms */\n\t@Property({ type: 'integer', nullable: true })\n\tdurationMs?: number;\n\n\t/** HTTP status code */\n\t@Property({ type: 'integer', nullable: true })\n\thttpStatus?: number;\n\n\t/** Error message */\n\t@Property({ type: 'text', nullable: true })\n\terrorMessage?: string;\n\n\t/** Error code */\n\t@Property({ type: 'string', nullable: true })\n\terrorCode?: string;\n\n\t/** Client IP */\n\t@Property({ type: 'string', nullable: true })\n\tclientIp?: string;\n\n\t/** User agent */\n\t@Property({ type: 'string', nullable: true })\n\tuserAgent?: string;\n\n\t/** User ID */\n\t@Property({ type: 'string', nullable: true })\n\tuserId?: string;\n\n\t/** Request headers (JSON) */\n\t@Property({ type: 'json', nullable: true })\n\trequestHeaders?: Record<string, string>;\n\n\t/** Request body (JSON) */\n\t@Property({ type: 'json', nullable: true })\n\trequestBody?: Record<string, unknown>;\n\n\t/** Response metadata (JSON) */\n\t@Property({ type: 'json', nullable: true })\n\tresponseMeta?: Record<string, unknown>;\n\n\t@Property({ type: 'datetime' })\n\tcreatedAt: Date = new Date();\n\n\t@Property({ type: 'datetime', onUpdate: () => new Date() })\n\tupdatedAt: Date = new Date();\n}\n"],"names":["id","requestId","sessionId","requestedAt","completedAt","status","method","path","serverName","serverType","mcpMethod","toolName","resourceUri","promptName","durationMs","httpStatus","errorMessage","errorCode","clientIp","userAgent","userId","requestHeaders","requestBody","responseMeta","createdAt","updatedAt","Entity","Enum","PrimaryKey","Property","McpServerType","Object","freeze","TencentCls","Sql","Prometheus","Relay","Custom","McpRequestType","Initialize","ToolsList","ToolsCall","ResourcesList","ResourcesRead","PromptsList","PromptsGet","CompletionComplete","LoggingSetLevel","Ping","Other","RequestStatus","Pending","Success","Error","Timeout","tableName","type","nullable","onUpdate","Date","McpRequestEntity"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/entities/RequestLogEntity.ts"],"sourcesContent":["import { Entity, PrimaryKey, Property } from '@mikro-orm/decorators/es';\n\n/**\n * Generic HTTP Request Log Entity\n * For general request auditing\n */\n@Entity({ tableName: 'request_log' })\nexport class RequestLogEntity {\n\t@PrimaryKey({ type: 'integer' })\n\tid!: number;\n\n\t/** Unique request ID */\n\t@Property({ type: 'string' })\n\trequestId!: string;\n\n\t/** Request timestamp */\n\t@Property({ type: 'datetime' })\n\ttimestamp: Date = new Date();\n\n\t/** HTTP method */\n\t@Property({ type: 'string' })\n\tmethod!: string;\n\n\t/** Request path */\n\t@Property({ type: 'string' })\n\tpath!: string;\n\n\t/** Request type (chat, mcp, api, etc) */\n\t@Property({ type: 'string', nullable: true })\n\trequestType?: string;\n\n\t/** Server name (for MCP) or model (for Chat) */\n\t@Property({ type: 'string', nullable: true })\n\tserverName?: string;\n\n\t/** Server type */\n\t@Property({ type: 'string', nullable: true })\n\tserverType?: string;\n\n\t/** HTTP status code */\n\t@Property({ type: 'integer', nullable: true })\n\tstatus?: number;\n\n\t/** Request duration in ms */\n\t@Property({ type: 'integer', nullable: true })\n\tdurationMs?: number;\n\n\t/** Error message */\n\t@Property({ type: 'text', nullable: true })\n\terror?: string;\n\n\t/** Client IP */\n\t@Property({ type: 'string', nullable: true })\n\tclientIp?: string;\n\n\t/** User agent */\n\t@Property({ type: 'string', nullable: true })\n\tuserAgent?: string;\n\n\t/** Request headers (JSON) */\n\t@Property({ type: 'json', nullable: true })\n\trequestHeaders?: Record<string, string>;\n\n\t/** Request body summary (JSON) */\n\t@Property({ type: 'json', nullable: true })\n\trequestBody?: Record<string, unknown>;\n\n\t/** Response body summary (JSON) */\n\t@Property({ type: 'json', nullable: true })\n\tresponseBody?: Record<string, unknown>;\n\n\t/** Additional metadata (JSON) */\n\t@Property({ type: 'json', nullable: true })\n\tmetadata?: Record<string, unknown>;\n\n\t@Property({ type: 'datetime' })\n\tcreatedAt: Date = new Date();\n}\n"],"names":["id","requestId","timestamp","method","path","requestType","serverName","serverType","status","durationMs","error","clientIp","userAgent","requestHeaders","requestBody","responseBody","metadata","createdAt","Entity","PrimaryKey","Property","tableName","type","nullable","RequestLogEntity","Date"],"mappings":";6JAQC,AACAA,UAEA,sBAAsB,GACtB,AACAC,iBAEA,sBAAsB,GACtB,AACAC,iBAEA,gBAAgB,GAChB,AACAC,cAEA,iBAAiB,GACjB,AACAC,YAEA,uCAAuC,GACvC,AACAC,mBAEA,8CAA8C,GAC9C,AACAC,kBAEA,gBAAgB,GAChB,AACAC,kBAEA,qBAAqB,GACrB,AACAC,cAEA,2BAA2B,GAC3B,AACAC,kBAEA,kBAAkB,GAClB,AACAC,aAEA,cAAc,GACd,AACAC,gBAEA,eAAe,GACf,AACAC,iBAEA,2BAA2B,GAC3B,AACAC,sBAEA,gCAAgC,GAChC,AACAC,mBAEA,iCAAiC,GACjC,AACAC,oBAEA,+BAA+B,GAC/B,AACAC,gBAEA,AACAC;AA5ED,SAASC,MAAM,EAAEC,UAAU,EAAEC,QAAQ,QAAQ,2BAA2B;;OAMvEF,OAAO;IAAEG,WAAW;AAAc,YAEjCF,WAAW;IAAEG,MAAM;AAAU,YAI7BF,SAAS;IAAEE,MAAM;AAAS,YAI1BF,SAAS;IAAEE,MAAM;AAAW,YAI5BF,SAAS;IAAEE,MAAM;AAAS,YAI1BF,SAAS;IAAEE,MAAM;AAAS,YAI1BF,SAAS;IAAEE,MAAM;IAAUC,UAAU;AAAK,YAI1CH,SAAS;IAAEE,MAAM;IAAUC,UAAU;AAAK,YAI1CH,SAAS;IAAEE,MAAM;IAAUC,UAAU;AAAK,YAI1CH,SAAS;IAAEE,MAAM;IAAWC,UAAU;AAAK,aAI3CH,SAAS;IAAEE,MAAM;IAAWC,UAAU;AAAK,aAI3CH,SAAS;IAAEE,MAAM;IAAQC,UAAU;AAAK,aAIxCH,SAAS;IAAEE,MAAM;IAAUC,UAAU;AAAK,aAI1CH,SAAS;IAAEE,MAAM;IAAUC,UAAU;AAAK,aAI1CH,SAAS;IAAEE,MAAM;IAAQC,UAAU;AAAK,aAIxCH,SAAS;IAAEE,MAAM;IAAQC,UAAU;AAAK,aAIxCH,SAAS;IAAEE,MAAM;IAAQC,UAAU;AAAK,aAIxCH,SAAS;IAAEE,MAAM;IAAQC,UAAU;AAAK,aAGxCH,SAAS;IAAEE,MAAM;AAAW;AApEvB,IAAA,AAAME,mBAAN,MAAMA;;eAEZxB,UAIAC,iBAIAC,iBAIAC,cAIAC,YAIAC,mBAIAC,kBAIAC,kBAIAC,cAIAC,kBAIAC,aAIAC,gBAIAC,iBAIAC,sBAIAC,mBAIAC,oBAIAC,gBAGAC;;;;gBAnEAjB;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAGAC;;;;;;IAnEAjB,wBAAAA,gBAAY;IAIZC,YAAAA,sBAAmB;IAInBC,YAAAA,sBAAkB,IAAIuB,QAAO;IAI7BtB,SAAAA,mBAAgB;IAIhBC,OAAAA,iBAAc;IAIdC,cAAAA,wBAAqB;IAIrBC,aAAAA,uBAAoB;IAIpBC,aAAAA,uBAAoB;IAIpBC,SAAAA,mBAAgB;IAIhBC,aAAAA,uBAAoB;IAIpBC,QAAAA,kBAAe;IAIfC,WAAAA,qBAAkB;IAIlBC,YAAAA,sBAAmB;IAInBC,iBAAAA,2BAAwC;IAIxCC,cAAAA,wBAAsC;IAItCC,eAAAA,yBAAuC;IAIvCC,WAAAA,qBAAmC;IAGnCC,YAAAA,sBAAkB,IAAIQ,QAAO;;;;AAC9B;SAtEA,AAAaD,qBAAAA,gBAsEZ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/entities/ResponseEntity.ts"],"sourcesContent":["import { Entity, PrimaryKey, Property } from '@mikro-orm/decorators/es';\n\n/**\n * Response Entity for storing Responses API responses\n * Enables previous_response_id support\n */\n@Entity({ tableName: 'response' })\nexport class ResponseEntity {\n\t@PrimaryKey({ type: 'integer' })\n\tid!: number;\n\n\t/** Response ID (e.g., resp_xxx) */\n\t@Property({ type: 'string', unique: true })\n\tresponseId!: string;\n\n\t/** Model name */\n\t@Property({ type: 'string' })\n\tmodel!: string;\n\n\t/** Response status */\n\t@Property({ type: 'string' })\n\tstatus!: string;\n\n\t/** Input (request) - stored as JSON */\n\t@Property({ type: 'json' })\n\tinput!: unknown;\n\n\t/** Output items - stored as JSON */\n\t@Property({ type: 'json' })\n\toutput!: unknown[];\n\n\t/** Usage statistics */\n\t@Property({ type: 'json', nullable: true })\n\tusage?: {\n\t\tprompt_tokens?: number;\n\t\tcompletion_tokens?: number;\n\t\ttotal_tokens?: number;\n\t};\n\n\t/** Instructions/system prompt */\n\t@Property({ type: 'text', nullable: true })\n\tinstructions?: string;\n\n\t/** Previous response ID for conversation chaining */\n\t@Property({ type: 'string', nullable: true })\n\tpreviousResponseId?: string;\n\n\t/** Tools configuration */\n\t@Property({ type: 'json', nullable: true })\n\ttools?: unknown[];\n\n\t/** Tool choice */\n\t@Property({ type: 'json', nullable: true })\n\ttoolChoice?: unknown;\n\n\t/** Metadata */\n\t@Property({ type: 'json', nullable: true })\n\tmetadata?: Record<string, unknown>;\n\n\t/** Error information */\n\t@Property({ type: 'json', nullable: true })\n\terror?: {\n\t\ttype?: string;\n\t\tmessage?: string;\n\t\tcode?: string;\n\t};\n\n\t/** Created timestamp */\n\t@Property({ type: 'datetime' })\n\tcreatedAt: Date = new Date();\n\n\t/** Request duration in ms */\n\t@Property({ type: 'integer', nullable: true })\n\tdurationMs?: number;\n}\n"],"names":["id","responseId","model","status","input","output","usage","instructions","previousResponseId","tools","toolChoice","metadata","error","createdAt","durationMs","Entity","PrimaryKey","Property","tableName","type","unique","nullable","ResponseEntity","Date"],"mappings":";qIAQC,AACAA,UAEA,iCAAiC,GACjC,AACAC,kBAEA,eAAe,GACf,AACAC,aAEA,oBAAoB,GACpB,AACAC,cAEA,qCAAqC,GACrC,AACAC,aAEA,kCAAkC,GAClC,AACAC,cAEA,qBAAqB,GACrB,AACAC,aAMA,+BAA+B,GAC/B,AACAC,oBAEA,mDAAmD,GACnD,AACAC,0BAEA,wBAAwB,GACxB,AACAC,aAEA,gBAAgB,GAChB,AACAC,kBAEA,aAAa,GACb,AACAC,gBAEA,sBAAsB,GACtB,AACAC,aAMA,sBAAsB,GACtB,AACAC,iBAEA,2BAA2B,GAC3B,AACAC;AAzED,SAASC,MAAM,EAAEC,UAAU,EAAEC,QAAQ,QAAQ,2BAA2B;;OAMvEF,OAAO;IAAEG,WAAW;AAAW,YAE9BF,WAAW;IAAEG,MAAM;AAAU,YAI7BF,SAAS;IAAEE,MAAM;IAAUC,QAAQ;AAAK,YAIxCH,SAAS;IAAEE,MAAM;AAAS,YAI1BF,SAAS;IAAEE,MAAM;AAAS,YAI1BF,SAAS;IAAEE,MAAM;AAAO,YAIxBF,SAAS;IAAEE,MAAM;AAAO,YAIxBF,SAAS;IAAEE,MAAM;IAAQE,UAAU;AAAK,YAQxCJ,SAAS;IAAEE,MAAM;IAAQE,UAAU;AAAK,YAIxCJ,SAAS;IAAEE,MAAM;IAAUE,UAAU;AAAK,aAI1CJ,SAAS;IAAEE,MAAM;IAAQE,UAAU;AAAK,aAIxCJ,SAAS;IAAEE,MAAM;IAAQE,UAAU;AAAK,aAIxCJ,SAAS;IAAEE,MAAM;IAAQE,UAAU;AAAK,aAIxCJ,SAAS;IAAEE,MAAM;IAAQE,UAAU;AAAK,aAQxCJ,SAAS;IAAEE,MAAM;AAAW,aAI5BF,SAAS;IAAEE,MAAM;IAAWE,UAAU;AAAK;AAjEtC,IAAA,AAAMC,iBAAN,MAAMA;;eAEZtB,UAIAC,kBAIAC,aAIAC,cAIAC,aAIAC,cAIAC,aAQAC,oBAIAC,0BAIAC,aAIAC,kBAIAC,gBAIAC,aAQAC,iBAIAC;;;;gBAhEAd;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAQAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAIAC;;;;;gBAQAC;;;;;gBAIAC;;;;;;IAhEAd,wBAAAA,gBAAY;IAIZC,aAAAA,uBAAoB;IAIpBC,QAAAA,kBAAe;IAIfC,SAAAA,mBAAgB;IAIhBC,QAAAA,kBAAgB;IAIhBC,SAAAA,mBAAmB;IAInBC,QAAAA,kBAIE;IAIFC,eAAAA,yBAAsB;IAItBC,qBAAAA,+BAA4B;IAI5BC,QAAAA,kBAAkB;IAIlBC,aAAAA,uBAAqB;IAIrBC,WAAAA,qBAAmC;IAInCC,QAAAA,kBAIE;IAIFC,YAAAA,sBAAkB,IAAIU,QAAO;IAI7BT,aAAAA,uBAAoB;;;;AACrB;SAnEA,AAAaQ,mBAAAA,cAmEZ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/entities/types.ts"],"sourcesContent":["/**\n * Entity Type Definitions\n * These types can be used with MikroORM or other ORMs\n * Avoids decorator issues in test environments\n */\n\n/**\n * Base entity fields\n */\nexport interface BaseEntity {\n\tid: number;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n}\n\n/**\n * Request status\n */\nexport type RequestStatus = 'pending' | 'success' | 'error' | 'timeout';\n\n/**\n * Chat protocol type\n */\nexport type ChatProtocolType = 'openai' | 'anthropic' | 'gemini';\n\n/**\n * MCP server type\n */\nexport type McpServerType = 'tencent-cls' | 'sql' | 'prometheus' | 'relay' | 'custom';\n\n/**\n * MCP request type\n */\nexport type McpRequestType =\n\t| 'initialize'\n\t| 'tools/list'\n\t| 'tools/call'\n\t| 'resources/list'\n\t| 'resources/read'\n\t| 'prompts/list'\n\t| 'prompts/get'\n\t| 'completion/complete'\n\t| 'logging/setLevel'\n\t| 'ping'\n\t| 'other';\n\n/**\n * Chat request entity for auditing and metering\n */\nexport interface ChatRequest extends BaseEntity {\n\t/** Unique request ID for tracing */\n\trequestId: string;\n\t/** Request timestamp */\n\trequestedAt: Date;\n\t/** Response timestamp */\n\tcompletedAt?: Date;\n\t/** Request status */\n\tstatus: RequestStatus;\n\t/** HTTP method */\n\tmethod: string;\n\t/** Request path/endpoint */\n\tendpoint: string;\n\t/** Input protocol (client-facing) */\n\tinputProtocol: ChatProtocolType;\n\t/** Output protocol (upstream provider) */\n\toutputProtocol: ChatProtocolType;\n\t/** Model name requested */\n\tmodel: string;\n\t/** Resolved model name */\n\tresolvedModel?: string;\n\t/** Provider name */\n\tprovider?: string;\n\t/** Upstream base URL */\n\tupstreamUrl?: string;\n\t/** Whether request was streaming */\n\tstreaming: boolean;\n\t/** Input token count */\n\tinputTokens?: number;\n\t/** Output token count */\n\toutputTokens?: number;\n\t/** Total token count */\n\ttotalTokens?: number;\n\t/** Request duration in ms */\n\tdurationMs?: number;\n\t/** Time to first token in ms */\n\tttftMs?: number;\n\t/** HTTP status code */\n\thttpStatus?: number;\n\t/** Error message */\n\terrorMessage?: string;\n\t/** Error code */\n\terrorCode?: string;\n\t/** Client IP */\n\tclientIp?: string;\n\t/** User agent */\n\tuserAgent?: string;\n\t/** User ID */\n\tuserId?: string;\n\t/** Organization ID */\n\torgId?: string;\n\t/** API key ID (not the actual key) */\n\tapiKeyId?: string;\n\t/** Request metadata */\n\trequestMeta?: Record<string, unknown>;\n\t/** Response metadata */\n\tresponseMeta?: Record<string, unknown>;\n\t/** Cost in credits */\n\tcost?: string;\n\t/** Currency */\n\tcurrency?: string;\n}\n\n/**\n * MCP request entity for auditing\n */\nexport interface McpRequest extends BaseEntity {\n\t/** Unique request ID */\n\trequestId: string;\n\t/** MCP session ID */\n\tsessionId?: string;\n\t/** Request timestamp */\n\trequestedAt: Date;\n\t/** Response timestamp */\n\tcompletedAt?: Date;\n\t/** Request status */\n\tstatus: RequestStatus;\n\t/** HTTP method */\n\tmethod: string;\n\t/** Request path */\n\tpath: string;\n\t/** MCP server name */\n\tserverName: string;\n\t/** MCP server type */\n\tserverType: McpServerType;\n\t/** MCP request type */\n\tmcpMethod: McpRequestType;\n\t/** Tool name (for tools/call) */\n\ttoolName?: string;\n\t/** Resource URI (for resources/read) */\n\tresourceUri?: string;\n\t/** Prompt name (for prompts/get) */\n\tpromptName?: string;\n\t/** Request duration in ms */\n\tdurationMs?: number;\n\t/** HTTP status code */\n\thttpStatus?: number;\n\t/** Error message */\n\terrorMessage?: string;\n\t/** Error code */\n\terrorCode?: string;\n\t/** Client IP */\n\tclientIp?: string;\n\t/** User agent */\n\tuserAgent?: string;\n\t/** User ID */\n\tuserId?: string;\n\t/** Request headers */\n\trequestHeaders?: Record<string, string>;\n\t/** Request body */\n\trequestBody?: Record<string, unknown>;\n\t/** Response metadata */\n\tresponseMeta?: Record<string, unknown>;\n}\n\n/**\n * Chat audit statistics\n */\nexport interface ChatAuditStats {\n\ttotalRequests: number;\n\tsuccessfulRequests: number;\n\tfailedRequests: number;\n\ttotalInputTokens: number;\n\ttotalOutputTokens: number;\n\tavgDurationMs: number;\n\tbyModel: { model: string; count: number; tokens: number }[];\n\tbyProvider: { provider: string; count: number; tokens: number }[];\n}\n\n/**\n * MCP audit statistics\n */\nexport interface McpAuditStats {\n\ttotalRequests: number;\n\ttotalErrors: number;\n\tavgDurationMs: number;\n\tbyServer: { name: string; count: number }[];\n\tbyMethod: { method: string; count: number }[];\n}\n"],"names":[],"mappings":"AAAA;;;;CAIC,GAED;;CAEC,GA0KD;;CAEC,GACD,WAMC"}
|
package/lib/server/audit.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/audit.ts"],"sourcesContent":["import { implement } from '@orpc/server';\nimport type { Context, Next } from 'hono';\nimport { LRUCache } from 'lru-cache';\nimport { AuditContract, type AuditEvent } from '../contracts';\nimport { RequestLogEntity } from '../entities';\nimport { ensureDbInitialized, configureDb } from './db';\nimport type { AuditConfig, DbConfig } from './schema';\n\n/**\n * Convert Headers to a plain record\n */\nfunction headersToRecord(headers: Headers): Record<string, string> {\n\tconst record: Record<string, string> = {};\n\theaders.forEach((value, key) => {\n\t\trecord[key] = value;\n\t});\n\treturn record;\n}\n\n// In-memory audit store using LRU cache\nconst auditStore = new LRUCache<string, AuditEvent>({\n\tmax: 10000, // Keep last 10k events\n\tttl: 1000 * 60 * 60 * 24, // 24 hours\n});\n\n// Counter for IDs\nlet eventCounter = 0;\n\n// Audit configuration state\nlet auditEnabled = true; // default to enabled\nlet dbConfigured = false;\n\n/**\n * Configure audit module with settings\n * Call this before using audit features\n *\n * @param auditConfig - Audit config section\n * @param fallbackDbConfig - Fallback db config from root config\n */\nexport function configureAudit(auditConfig?: AuditConfig, fallbackDbConfig?: DbConfig): void {\n\t// Determine if audit is enabled (default: true)\n\tauditEnabled = auditConfig?.enabled !== false;\n\n\tif (auditEnabled) {\n\t\t// Use audit.db config if present, otherwise fallback to root db config\n\t\tconst dbConfig = auditConfig?.db ?? fallbackDbConfig;\n\t\tconfigureDb(dbConfig);\n\t\tdbConfigured = true;\n\t}\n}\n\n/**\n * Check if audit is enabled\n */\nexport function isAuditEnabled(): boolean {\n\treturn auditEnabled;\n}\n\n/**\n * Persist audit event to database (lazy init)\n */\nasync function persistToDb(event: AuditEvent, id: string): Promise<void> {\n\tif (!auditEnabled || !dbConfigured) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\t// Lazy initialize DB on first persist\n\t\tconst orm = await ensureDbInitialized();\n\t\tconst em = orm.em.fork();\n\n\t\tconst logEntry = new RequestLogEntity();\n\t\tlogEntry.requestId = id;\n\t\tlogEntry.timestamp = new Date(event.timestamp);\n\t\tlogEntry.method = event.method;\n\t\tlogEntry.path = event.path;\n\t\tlogEntry.serverName = event.serverName ?? undefined;\n\t\tlogEntry.serverType = event.serverType ?? undefined;\n\t\tlogEntry.status = event.status ?? undefined;\n\t\tlogEntry.durationMs = event.durationMs ?? undefined;\n\t\tlogEntry.error = event.error ?? undefined;\n\t\tlogEntry.requestHeaders = event.requestHeaders ?? undefined;\n\t\t// Determine request type\n\t\tif (event.path.startsWith('/mcp/')) {\n\t\t\tlogEntry.requestType = 'mcp';\n\t\t} else if (event.path.startsWith('/v1/')) {\n\t\t\tlogEntry.requestType = 'chat';\n\t\t} else {\n\t\t\tlogEntry.requestType = 'api';\n\t\t}\n\t\tem.persist(logEntry);\n\t\tawait em.flush();\n\t} catch (e) {\n\t\t// Log persistence errors but don't throw - in-memory store is the primary\n\t\tconsole.error('Failed to persist audit log:', e);\n\t}\n}\n\n/**\n * Add an audit event\n */\nexport function addAuditEvent(event: Omit<AuditEvent, 'id'>): AuditEvent {\n\tconst id = `${Date.now()}-${++eventCounter}`;\n\tconst fullEvent: AuditEvent = { ...event, id };\n\tauditStore.set(id, fullEvent);\n\n\t// Persist to database asynchronously (lazy init)\n\tpersistToDb(fullEvent, id).catch(() => {\n\t\t// Already logged in persistToDb\n\t});\n\n\treturn fullEvent;\n}\n\n/**\n * Query audit events\n */\nexport function queryAuditEvents(options: {\n\tlimit?: number;\n\toffset?: number;\n\tserverName?: string | null;\n\tserverType?: string | null;\n\tmethod?: string | null;\n\tfrom?: string | null;\n\tto?: string | null;\n}): { events: AuditEvent[]; total: number } {\n\tconst { limit = 50, offset = 0, serverName, serverType, method, from, to } = options;\n\n\t// Get all events as array\n\tlet events: AuditEvent[] = [];\n\tfor (const [, event] of auditStore.entries()) {\n\t\tevents.push(event);\n\t}\n\n\t// Sort by timestamp desc\n\tevents.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());\n\n\t// Apply filters\n\tif (serverName) {\n\t\tevents = events.filter((e) => e.serverName === serverName);\n\t}\n\tif (serverType) {\n\t\tevents = events.filter((e) => e.serverType === serverType);\n\t}\n\tif (method) {\n\t\tevents = events.filter((e) => e.method === method);\n\t}\n\tif (from) {\n\t\tconst fromTime = new Date(from).getTime();\n\t\tevents = events.filter((e) => new Date(e.timestamp).getTime() >= fromTime);\n\t}\n\tif (to) {\n\t\tconst toTime = new Date(to).getTime();\n\t\tevents = events.filter((e) => new Date(e.timestamp).getTime() <= toTime);\n\t}\n\n\tconst total = events.length;\n\n\t// Paginate\n\tevents = events.slice(offset, offset + limit);\n\n\treturn { events, total };\n}\n\n/**\n * Get audit statistics\n */\nexport function getAuditStats(options: { from?: string | null; to?: string | null }) {\n\tlet events: AuditEvent[] = [];\n\tfor (const [, event] of auditStore.entries()) {\n\t\tevents.push(event);\n\t}\n\n\t// Apply time filters\n\tif (options.from) {\n\t\tconst fromTime = new Date(options.from).getTime();\n\t\tevents = events.filter((e) => new Date(e.timestamp).getTime() >= fromTime);\n\t}\n\tif (options.to) {\n\t\tconst toTime = new Date(options.to).getTime();\n\t\tevents = events.filter((e) => new Date(e.timestamp).getTime() <= toTime);\n\t}\n\n\t// Calculate stats\n\tconst totalRequests = events.length;\n\tconst totalErrors = events.filter((e) => e.error || (e.status && e.status >= 400)).length;\n\n\tconst durations = events.map((e) => e.durationMs).filter((d): d is number => d != null);\n\tconst avgDurationMs = durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0;\n\n\t// Group by server\n\tconst serverCounts = new Map<string, number>();\n\tfor (const event of events) {\n\t\tconst name = event.serverName || 'unknown';\n\t\tserverCounts.set(name, (serverCounts.get(name) || 0) + 1);\n\t}\n\tconst byServer = Array.from(serverCounts.entries())\n\t\t.map(([name, count]) => ({ name, count }))\n\t\t.sort((a, b) => b.count - a.count);\n\n\t// Group by method\n\tconst methodCounts = new Map<string, number>();\n\tfor (const event of events) {\n\t\tconst method = event.method || 'unknown';\n\t\tmethodCounts.set(method, (methodCounts.get(method) || 0) + 1);\n\t}\n\tconst byMethod = Array.from(methodCounts.entries())\n\t\t.map(([method, count]) => ({ method, count }))\n\t\t.sort((a, b) => b.count - a.count);\n\n\treturn { totalRequests, totalErrors, avgDurationMs, byServer, byMethod };\n}\n\n/**\n * Clear audit events before a timestamp\n */\nexport function clearAuditEvents(before: string): number {\n\tconst beforeTime = new Date(before).getTime();\n\tlet deleted = 0;\n\n\tfor (const [id, event] of auditStore.entries()) {\n\t\tif (new Date(event.timestamp).getTime() < beforeTime) {\n\t\t\tauditStore.delete(id);\n\t\t\tdeleted++;\n\t\t}\n\t}\n\n\treturn deleted;\n}\n\n/**\n * Audit Router implementation\n */\nexport const AuditRouter = implement(AuditContract).router({\n\tlist: implement(AuditContract.list).handler(async ({ input }) => {\n\t\treturn queryAuditEvents(input);\n\t}),\n\n\tget: implement(AuditContract.get).handler(async ({ input }) => {\n\t\treturn auditStore.get(input.id) ?? null;\n\t}),\n\n\tstats: implement(AuditContract.stats).handler(async ({ input }) => {\n\t\treturn getAuditStats(input);\n\t}),\n\n\tclear: implement(AuditContract.clear).handler(async ({ input }) => {\n\t\tconst deleted = clearAuditEvents(input.before);\n\t\treturn { deleted };\n\t}),\n});\n\n/**\n * Hono middleware for audit logging\n */\nexport function auditMiddleware() {\n\treturn async (c: Context, next: Next) => {\n\t\tconst startTime = Date.now();\n\t\tconst path = c.req.path;\n\n\t\t// Extract server info from path\n\t\tlet serverName: string | undefined;\n\t\tlet serverType: string | undefined;\n\n\t\tconst mcpMatch = path.match(/^\\/mcp\\/([^/]+)/);\n\t\tif (mcpMatch) {\n\t\t\tserverName = mcpMatch[1];\n\t\t\t// Infer type from well-known paths\n\t\t\tif (serverName === 'tencent-cls') serverType = 'tencent-cls';\n\t\t\telse if (serverName === 'sql') serverType = 'sql';\n\t\t\telse if (serverName === 'prometheus') serverType = 'prometheus';\n\t\t\telse if (serverName === 'relay') serverType = 'relay';\n\t\t\telse serverType = 'custom';\n\t\t}\n\n\t\t// Extract model info from chat requests\n\t\tif (path.startsWith('/v1/')) {\n\t\t\tserverType = 'chat';\n\t\t}\n\n\t\tlet error: string | undefined;\n\n\t\ttry {\n\t\t\tawait next();\n\t\t} catch (e) {\n\t\t\terror = e instanceof Error ? e.message : String(e);\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tconst durationMs = Date.now() - startTime;\n\n\t\t\t// Audit MCP requests, Chat API requests, and other API requests\n\t\t\tconst shouldAudit =\n\t\t\t\tpath.startsWith('/mcp/') || path.startsWith('/v1/') || (path.startsWith('/api/') && c.req.method !== 'GET');\n\n\t\t\tif (shouldAudit) {\n\t\t\t\taddAuditEvent({\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tmethod: c.req.method,\n\t\t\t\t\tpath,\n\t\t\t\t\tserverName,\n\t\t\t\t\tserverType,\n\t\t\t\t\tstatus: c.res.status,\n\t\t\t\t\tdurationMs,\n\t\t\t\t\terror,\n\t\t\t\t\trequestHeaders: headersToRecord(c.req.raw.headers),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t};\n}\n"],"names":["implement","LRUCache","AuditContract","RequestLogEntity","ensureDbInitialized","configureDb","headersToRecord","headers","record","forEach","value","key","auditStore","max","ttl","eventCounter","auditEnabled","dbConfigured","configureAudit","auditConfig","fallbackDbConfig","enabled","dbConfig","db","isAuditEnabled","persistToDb","event","id","orm","em","fork","logEntry","requestId","timestamp","Date","method","path","serverName","undefined","serverType","status","durationMs","error","requestHeaders","startsWith","requestType","persist","flush","e","console","addAuditEvent","now","fullEvent","set","catch","queryAuditEvents","options","limit","offset","from","to","events","entries","push","sort","a","b","getTime","filter","fromTime","toTime","total","length","slice","getAuditStats","totalRequests","totalErrors","durations","map","d","avgDurationMs","reduce","serverCounts","Map","name","get","byServer","Array","count","methodCounts","byMethod","clearAuditEvents","before","beforeTime","deleted","delete","AuditRouter","router","list","handler","input","stats","clear","auditMiddleware","c","next","startTime","req","mcpMatch","match","Error","message","String","shouldAudit","toISOString","res","raw"],"mappings":"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"}
|
package/lib/server/db.js
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { MikroORM } from "@mikro-orm/core";
|
|
2
|
-
import { SqliteDriver } from "@mikro-orm/sqlite";
|
|
3
|
-
import { ChatRequestEntity } from "../entities/ChatRequestEntity.js";
|
|
4
|
-
import { McpRequestEntity } from "../entities/McpRequestEntity.js";
|
|
5
|
-
import { RequestLogEntity } from "../entities/RequestLogEntity.js";
|
|
6
|
-
import { ResponseEntity } from "../entities/ResponseEntity.js";
|
|
7
|
-
let orm = null;
|
|
8
|
-
let initPromise = null;
|
|
9
|
-
let storedDbConfig;
|
|
10
|
-
/**
|
|
11
|
-
* Get MikroORM configuration
|
|
12
|
-
*/ export function getOrmConfig(dbConfig) {
|
|
13
|
-
const dbPath = dbConfig?.path || ".mcps.db";
|
|
14
|
-
return {
|
|
15
|
-
driver: SqliteDriver,
|
|
16
|
-
dbName: dbPath,
|
|
17
|
-
entities: [
|
|
18
|
-
ChatRequestEntity,
|
|
19
|
-
McpRequestEntity,
|
|
20
|
-
RequestLogEntity,
|
|
21
|
-
ResponseEntity
|
|
22
|
-
],
|
|
23
|
-
// Enable debug in development
|
|
24
|
-
debug: process.env.NODE_ENV === "development",
|
|
25
|
-
// Allow global context for simpler usage
|
|
26
|
-
allowGlobalContext: true
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Initialize MikroORM and sync schema
|
|
31
|
-
*/ export async function initializeDb(dbConfig) {
|
|
32
|
-
if (orm) {
|
|
33
|
-
return orm;
|
|
34
|
-
}
|
|
35
|
-
// If already initializing, wait for the existing promise
|
|
36
|
-
if (initPromise) {
|
|
37
|
-
return initPromise;
|
|
38
|
-
}
|
|
39
|
-
storedDbConfig = dbConfig;
|
|
40
|
-
initPromise = (async () => {
|
|
41
|
-
const config = getOrmConfig(dbConfig);
|
|
42
|
-
orm = await MikroORM.init(config);
|
|
43
|
-
// Sync schema (create tables if not exist)
|
|
44
|
-
await orm.schema.update();
|
|
45
|
-
return orm;
|
|
46
|
-
})();
|
|
47
|
-
try {
|
|
48
|
-
return await initPromise;
|
|
49
|
-
}
|
|
50
|
-
catch (e) {
|
|
51
|
-
// Reset on failure so retry is possible
|
|
52
|
-
initPromise = null;
|
|
53
|
-
throw e;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Configure DB for lazy initialization (stores config without initializing)
|
|
58
|
-
*/ export function configureDb(dbConfig) {
|
|
59
|
-
storedDbConfig = dbConfig;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Ensure DB is initialized (lazy init on first call)
|
|
63
|
-
* Returns the ORM instance, initializing if needed
|
|
64
|
-
*/ export async function ensureDbInitialized() {
|
|
65
|
-
if (orm) {
|
|
66
|
-
return orm;
|
|
67
|
-
}
|
|
68
|
-
return initializeDb(storedDbConfig);
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Get MikroORM instance (must be initialized first)
|
|
72
|
-
*/ export function getOrm() {
|
|
73
|
-
if (!orm) {
|
|
74
|
-
throw new Error("Database not initialized. Call initializeDb() first.");
|
|
75
|
-
}
|
|
76
|
-
return orm;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Get EntityManager
|
|
80
|
-
*/ export function getEntityManager() {
|
|
81
|
-
return getOrm().em;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Close database connection
|
|
85
|
-
*/ export async function closeDb() {
|
|
86
|
-
if (orm) {
|
|
87
|
-
await orm.close();
|
|
88
|
-
orm = null;
|
|
89
|
-
initPromise = null;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Check if database is initialized
|
|
94
|
-
*/ export function isDbInitialized() {
|
|
95
|
-
return orm !== null;
|
|
96
|
-
}
|
|
97
|
-
//# sourceMappingURL=db.js.map
|
package/lib/server/db.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/db.ts"],"sourcesContent":["import { MikroORM, type Options } from '@mikro-orm/core';\nimport { SqliteDriver } from '@mikro-orm/sqlite';\nimport { ChatRequestEntity } from '../entities/ChatRequestEntity';\nimport { McpRequestEntity } from '../entities/McpRequestEntity';\nimport { RequestLogEntity } from '../entities/RequestLogEntity';\nimport { ResponseEntity } from '../entities/ResponseEntity';\nimport type { DbConfig } from './schema';\n\nlet orm: MikroORM<SqliteDriver> | null = null;\nlet initPromise: Promise<MikroORM<SqliteDriver>> | null = null;\nlet storedDbConfig: DbConfig | undefined;\n\n/**\n * Get MikroORM configuration\n */\nexport function getOrmConfig(dbConfig?: DbConfig): Options<SqliteDriver> {\n\tconst dbPath = dbConfig?.path || '.mcps.db';\n\n\treturn {\n\t\tdriver: SqliteDriver,\n\t\tdbName: dbPath,\n\t\tentities: [ChatRequestEntity, McpRequestEntity, RequestLogEntity, ResponseEntity],\n\t\t// Enable debug in development\n\t\tdebug: process.env.NODE_ENV === 'development',\n\t\t// Allow global context for simpler usage\n\t\tallowGlobalContext: true,\n\t};\n}\n\n/**\n * Initialize MikroORM and sync schema\n */\nexport async function initializeDb(dbConfig?: DbConfig): Promise<MikroORM<SqliteDriver>> {\n\tif (orm) {\n\t\treturn orm;\n\t}\n\n\t// If already initializing, wait for the existing promise\n\tif (initPromise) {\n\t\treturn initPromise;\n\t}\n\n\tstoredDbConfig = dbConfig;\n\n\tinitPromise = (async () => {\n\t\tconst config = getOrmConfig(dbConfig);\n\t\torm = await MikroORM.init(config);\n\n\t\t// Sync schema (create tables if not exist)\n\t\tawait orm.schema.update();\n\n\t\treturn orm;\n\t})();\n\n\ttry {\n\t\treturn await initPromise;\n\t} catch (e) {\n\t\t// Reset on failure so retry is possible\n\t\tinitPromise = null;\n\t\tthrow e;\n\t}\n}\n\n/**\n * Configure DB for lazy initialization (stores config without initializing)\n */\nexport function configureDb(dbConfig?: DbConfig): void {\n\tstoredDbConfig = dbConfig;\n}\n\n/**\n * Ensure DB is initialized (lazy init on first call)\n * Returns the ORM instance, initializing if needed\n */\nexport async function ensureDbInitialized(): Promise<MikroORM<SqliteDriver>> {\n\tif (orm) {\n\t\treturn orm;\n\t}\n\treturn initializeDb(storedDbConfig);\n}\n\n/**\n * Get MikroORM instance (must be initialized first)\n */\nexport function getOrm(): MikroORM<SqliteDriver> {\n\tif (!orm) {\n\t\tthrow new Error('Database not initialized. Call initializeDb() first.');\n\t}\n\treturn orm;\n}\n\n/**\n * Get EntityManager\n */\nexport function getEntityManager() {\n\treturn getOrm().em;\n}\n\n/**\n * Close database connection\n */\nexport async function closeDb(): Promise<void> {\n\tif (orm) {\n\t\tawait orm.close();\n\t\torm = null;\n\t\tinitPromise = null;\n\t}\n}\n\n/**\n * Check if database is initialized\n */\nexport function isDbInitialized(): boolean {\n\treturn orm !== null;\n}\n"],"names":["MikroORM","SqliteDriver","ChatRequestEntity","McpRequestEntity","RequestLogEntity","ResponseEntity","orm","initPromise","storedDbConfig","getOrmConfig","dbConfig","dbPath","path","driver","dbName","entities","debug","process","env","NODE_ENV","allowGlobalContext","initializeDb","config","init","schema","update","e","configureDb","ensureDbInitialized","getOrm","Error","getEntityManager","em","closeDb","close","isDbInitialized"],"mappings":"AAAA,SAASA,QAAQ,QAAsB,kBAAkB;AACzD,SAASC,YAAY,QAAQ,oBAAoB;AACjD,SAASC,iBAAiB,QAAQ,gCAAgC;AAClE,SAASC,gBAAgB,QAAQ,+BAA+B;AAChE,SAASC,gBAAgB,QAAQ,+BAA+B;AAChE,SAASC,cAAc,QAAQ,6BAA6B;AAG5D,IAAIC,MAAqC;AACzC,IAAIC,cAAsD;AAC1D,IAAIC;AAEJ;;CAEC,GACD,OAAO,SAASC,aAAaC,QAAmB;IAC/C,MAAMC,SAASD,UAAUE,QAAQ;IAEjC,OAAO;QACNC,QAAQZ;QACRa,QAAQH;QACRI,UAAU;YAACb;YAAmBC;YAAkBC;YAAkBC;SAAe;QACjF,8BAA8B;QAC9BW,OAAOC,QAAQC,GAAG,CAACC,QAAQ,KAAK;QAChC,yCAAyC;QACzCC,oBAAoB;IACrB;AACD;AAEA;;CAEC,GACD,OAAO,eAAeC,aAAaX,QAAmB;IACrD,IAAIJ,KAAK;QACR,OAAOA;IACR;IAEA,yDAAyD;IACzD,IAAIC,aAAa;QAChB,OAAOA;IACR;IAEAC,iBAAiBE;IAEjBH,cAAc,AAAC,CAAA;QACd,MAAMe,SAASb,aAAaC;QAC5BJ,MAAM,MAAMN,SAASuB,IAAI,CAACD;QAE1B,2CAA2C;QAC3C,MAAMhB,IAAIkB,MAAM,CAACC,MAAM;QAEvB,OAAOnB;IACR,CAAA;IAEA,IAAI;QACH,OAAO,MAAMC;IACd,EAAE,OAAOmB,GAAG;QACX,wCAAwC;QACxCnB,cAAc;QACd,MAAMmB;IACP;AACD;AAEA;;CAEC,GACD,OAAO,SAASC,YAAYjB,QAAmB;IAC9CF,iBAAiBE;AAClB;AAEA;;;CAGC,GACD,OAAO,eAAekB;IACrB,IAAItB,KAAK;QACR,OAAOA;IACR;IACA,OAAOe,aAAab;AACrB;AAEA;;CAEC,GACD,OAAO,SAASqB;IACf,IAAI,CAACvB,KAAK;QACT,MAAM,IAAIwB,MAAM;IACjB;IACA,OAAOxB;AACR;AAEA;;CAEC,GACD,OAAO,SAASyB;IACf,OAAOF,SAASG,EAAE;AACnB;AAEA;;CAEC,GACD,OAAO,eAAeC;IACrB,IAAI3B,KAAK;QACR,MAAMA,IAAI4B,KAAK;QACf5B,MAAM;QACNC,cAAc;IACf;AACD;AAEA;;CAEC,GACD,OAAO,SAAS4B;IACf,OAAO7B,QAAQ;AAChB"}
|