@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/audit/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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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/audit/chat.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 './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<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 './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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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/audit/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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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/audit/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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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/audit/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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/audit/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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export * from "../types.js";
|
|
2
|
+
export { ChatRequestEntity, ChatProtocolType, RequestStatus } from "./ChatRequestEntity.js";
|
|
3
|
+
export { McpRequestEntity, McpServerType, McpRequestType } from "./McpRequestEntity.js";
|
|
4
|
+
export { RequestLogEntity } from "./RequestLogEntity.js";
|
|
5
|
+
export { ResponseEntity } from "./ResponseEntity.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/audit/entities/index.ts"],"sourcesContent":["export * from '../types';\n\nexport { ChatRequestEntity, ChatProtocolType, RequestStatus } from './ChatRequestEntity';\nexport { McpRequestEntity, McpServerType, McpRequestType } from './McpRequestEntity';\nexport { RequestLogEntity } from './RequestLogEntity';\nexport { ResponseEntity } from './ResponseEntity';\n"],"names":["ChatRequestEntity","ChatProtocolType","RequestStatus","McpRequestEntity","McpServerType","McpRequestType","RequestLogEntity","ResponseEntity"],"mappings":"AAAA,cAAc,WAAW;AAEzB,SAASA,iBAAiB,EAAEC,gBAAgB,EAAEC,aAAa,QAAQ,sBAAsB;AACzF,SAASC,gBAAgB,EAAEC,aAAa,EAAEC,cAAc,QAAQ,qBAAqB;AACrF,SAASC,gBAAgB,QAAQ,qBAAqB;AACtD,SAASC,cAAc,QAAQ,mBAAmB"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { MikroORM } from "@mikro-orm/core";
|
|
2
|
+
import { SqliteDriver } from "@mikro-orm/sql";
|
|
3
|
+
import { createSqliteDialect } from "@wener/server/mikro-orm";
|
|
4
|
+
import { ChatRequestEntity } from "../entities/ChatRequestEntity.js";
|
|
5
|
+
import { McpRequestEntity } from "../entities/McpRequestEntity.js";
|
|
6
|
+
import { RequestLogEntity } from "../entities/RequestLogEntity.js";
|
|
7
|
+
import { ResponseEntity } from "../entities/ResponseEntity.js";
|
|
8
|
+
export { RequestLogEntity };
|
|
9
|
+
let orm = null;
|
|
10
|
+
let initPromise = null;
|
|
11
|
+
async function getOrmConfig(dbConfig) {
|
|
12
|
+
const dbPath = dbConfig?.path || ".mcps.db";
|
|
13
|
+
return {
|
|
14
|
+
driver: SqliteDriver,
|
|
15
|
+
dbName: dbPath,
|
|
16
|
+
entities: [
|
|
17
|
+
ChatRequestEntity,
|
|
18
|
+
McpRequestEntity,
|
|
19
|
+
RequestLogEntity,
|
|
20
|
+
ResponseEntity
|
|
21
|
+
],
|
|
22
|
+
driverOptions: await createSqliteDialect(dbPath),
|
|
23
|
+
debug: process.env.NODE_ENV === "development",
|
|
24
|
+
allowGlobalContext: true
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export async function ensureDbInitialized(dbConfig) {
|
|
28
|
+
if (orm)
|
|
29
|
+
return orm;
|
|
30
|
+
if (initPromise)
|
|
31
|
+
return initPromise;
|
|
32
|
+
initPromise = (async () => {
|
|
33
|
+
const config = await getOrmConfig(dbConfig);
|
|
34
|
+
orm = await MikroORM.init(config);
|
|
35
|
+
await orm.schema.update();
|
|
36
|
+
return orm;
|
|
37
|
+
})();
|
|
38
|
+
try {
|
|
39
|
+
return await initPromise;
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
initPromise = null;
|
|
43
|
+
throw e;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function getOrm() {
|
|
47
|
+
if (!orm)
|
|
48
|
+
throw new Error("Database not initialized");
|
|
49
|
+
return orm;
|
|
50
|
+
}
|
|
51
|
+
export function getEntityManager() {
|
|
52
|
+
return getOrm().em;
|
|
53
|
+
}
|
|
54
|
+
export async function closeDb() {
|
|
55
|
+
if (orm) {
|
|
56
|
+
await orm.close();
|
|
57
|
+
orm = null;
|
|
58
|
+
initPromise = null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function isDbInitialized() {
|
|
62
|
+
return orm !== null;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/audit/server/db.ts"],"sourcesContent":["import { MikroORM, type Options } from '@mikro-orm/core';\nimport { SqliteDriver } from '@mikro-orm/sql';\nimport { createSqliteDialect } from '@wener/server/mikro-orm';\nimport type { DbConfig } from '../../server/schema';\nimport { ChatRequestEntity } from '../entities/ChatRequestEntity';\nimport { McpRequestEntity } from '../entities/McpRequestEntity';\nimport { RequestLogEntity } from '../entities/RequestLogEntity';\nimport { ResponseEntity } from '../entities/ResponseEntity';\n\nexport { RequestLogEntity };\n\nlet orm: MikroORM<SqliteDriver> | null = null;\nlet initPromise: Promise<MikroORM<SqliteDriver>> | null = null;\n\nasync function getOrmConfig(dbConfig?: DbConfig): Promise<Options<SqliteDriver>> {\n\tconst dbPath = dbConfig?.path || '.mcps.db';\n\treturn {\n\t\tdriver: SqliteDriver,\n\t\tdbName: dbPath,\n\t\tentities: [ChatRequestEntity, McpRequestEntity, RequestLogEntity, ResponseEntity],\n\t\tdriverOptions: await createSqliteDialect(dbPath),\n\t\tdebug: process.env.NODE_ENV === 'development',\n\t\tallowGlobalContext: true,\n\t};\n}\n\nexport async function ensureDbInitialized(dbConfig?: DbConfig): Promise<MikroORM<SqliteDriver>> {\n\tif (orm) return orm;\n\tif (initPromise) return initPromise;\n\n\tinitPromise = (async () => {\n\t\tconst config = await getOrmConfig(dbConfig);\n\t\torm = await MikroORM.init(config);\n\t\tawait orm.schema.update();\n\t\treturn orm;\n\t})();\n\n\ttry {\n\t\treturn await initPromise;\n\t} catch (e) {\n\t\tinitPromise = null;\n\t\tthrow e;\n\t}\n}\n\nexport function getOrm(): MikroORM<SqliteDriver> {\n\tif (!orm) throw new Error('Database not initialized');\n\treturn orm;\n}\n\nexport function getEntityManager() {\n\treturn getOrm().em;\n}\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\nexport function isDbInitialized(): boolean {\n\treturn orm !== null;\n}\n"],"names":["MikroORM","SqliteDriver","createSqliteDialect","ChatRequestEntity","McpRequestEntity","RequestLogEntity","ResponseEntity","orm","initPromise","getOrmConfig","dbConfig","dbPath","path","driver","dbName","entities","driverOptions","debug","process","env","NODE_ENV","allowGlobalContext","ensureDbInitialized","config","init","schema","update","e","getOrm","Error","getEntityManager","em","closeDb","close","isDbInitialized"],"mappings":"AAAA,SAASA,QAAQ,QAAsB,kBAAkB;AACzD,SAASC,YAAY,QAAQ,iBAAiB;AAC9C,SAASC,mBAAmB,QAAQ,0BAA0B;AAE9D,SAASC,iBAAiB,QAAQ,gCAAgC;AAClE,SAASC,gBAAgB,QAAQ,+BAA+B;AAChE,SAASC,gBAAgB,QAAQ,+BAA+B;AAChE,SAASC,cAAc,QAAQ,6BAA6B;AAE5D,SAASD,gBAAgB,GAAG;AAE5B,IAAIE,MAAqC;AACzC,IAAIC,cAAsD;AAE1D,eAAeC,aAAaC,QAAmB;IAC9C,MAAMC,SAASD,UAAUE,QAAQ;IACjC,OAAO;QACNC,QAAQZ;QACRa,QAAQH;QACRI,UAAU;YAACZ;YAAmBC;YAAkBC;YAAkBC;SAAe;QACjFU,eAAe,MAAMd,oBAAoBS;QACzCM,OAAOC,QAAQC,GAAG,CAACC,QAAQ,KAAK;QAChCC,oBAAoB;IACrB;AACD;AAEA,OAAO,eAAeC,oBAAoBZ,QAAmB;IAC5D,IAAIH,KAAK,OAAOA;IAChB,IAAIC,aAAa,OAAOA;IAExBA,cAAc,AAAC,CAAA;QACd,MAAMe,SAAS,MAAMd,aAAaC;QAClCH,MAAM,MAAMP,SAASwB,IAAI,CAACD;QAC1B,MAAMhB,IAAIkB,MAAM,CAACC,MAAM;QACvB,OAAOnB;IACR,CAAA;IAEA,IAAI;QACH,OAAO,MAAMC;IACd,EAAE,OAAOmB,GAAG;QACXnB,cAAc;QACd,MAAMmB;IACP;AACD;AAEA,OAAO,SAASC;IACf,IAAI,CAACrB,KAAK,MAAM,IAAIsB,MAAM;IAC1B,OAAOtB;AACR;AAEA,OAAO,SAASuB;IACf,OAAOF,SAASG,EAAE;AACnB;AAEA,OAAO,eAAeC;IACrB,IAAIzB,KAAK;QACR,MAAMA,IAAI0B,KAAK;QACf1B,MAAM;QACNC,cAAc;IACf;AACD;AAEA,OAAO,SAAS0B;IACf,OAAO3B,QAAQ;AAChB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/audit/server/index.ts"],"sourcesContent":["export {\n\tsetupAudit,\n\tAuditRouter,\n\taddAuditEvent,\n\tqueryAuditEvents,\n\tgetAuditStats,\n\tclearAuditEvents,\n} from './plugin';\n"],"names":["setupAudit","AuditRouter","addAuditEvent","queryAuditEvents","getAuditStats","clearAuditEvents"],"mappings":"AAAA,SACCA,UAAU,EACVC,WAAW,EACXC,aAAa,EACbC,gBAAgB,EAChBC,aAAa,EACbC,gBAAgB,QACV,WAAW"}
|
|
@@ -1,57 +1,28 @@
|
|
|
1
1
|
import { implement } from "@orpc/server";
|
|
2
2
|
import { LRUCache } from "lru-cache";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Convert Headers to a plain record
|
|
8
|
-
*/ function headersToRecord(headers) {
|
|
3
|
+
import { McpsEventType } from "../../server/events.js";
|
|
4
|
+
import { AuditContract } from "../AuditContract.js";
|
|
5
|
+
function headersToRecord(headers) {
|
|
9
6
|
const record = {};
|
|
10
7
|
headers.forEach((value, key) => {
|
|
11
8
|
record[key] = value;
|
|
12
9
|
});
|
|
13
10
|
return record;
|
|
14
11
|
}
|
|
15
|
-
// In-memory audit store using LRU cache
|
|
16
12
|
const auditStore = new LRUCache({
|
|
17
13
|
max: 10000,
|
|
18
14
|
ttl: 1000 * 60 * 60 * 24
|
|
19
15
|
});
|
|
20
|
-
// Counter for IDs
|
|
21
16
|
let eventCounter = 0;
|
|
22
|
-
// Audit configuration state
|
|
23
|
-
let auditEnabled = true; // default to enabled
|
|
24
17
|
let dbConfigured = false;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* @param auditConfig - Audit config section
|
|
30
|
-
* @param fallbackDbConfig - Fallback db config from root config
|
|
31
|
-
*/ export function configureAudit(auditConfig, fallbackDbConfig) {
|
|
32
|
-
// Determine if audit is enabled (default: true)
|
|
33
|
-
auditEnabled = auditConfig?.enabled !== false;
|
|
34
|
-
if (auditEnabled) {
|
|
35
|
-
// Use audit.db config if present, otherwise fallback to root db config
|
|
36
|
-
const dbConfig = auditConfig?.db ?? fallbackDbConfig;
|
|
37
|
-
configureDb(dbConfig);
|
|
38
|
-
dbConfigured = true;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Check if audit is enabled
|
|
43
|
-
*/ export function isAuditEnabled() {
|
|
44
|
-
return auditEnabled;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Persist audit event to database (lazy init)
|
|
48
|
-
*/ async function persistToDb(event, id) {
|
|
49
|
-
if (!auditEnabled || !dbConfigured) {
|
|
18
|
+
let storedAuditConfig;
|
|
19
|
+
let storedDbConfig;
|
|
20
|
+
async function persistToDb(event, id) {
|
|
21
|
+
if (!dbConfigured)
|
|
50
22
|
return;
|
|
51
|
-
}
|
|
52
23
|
try {
|
|
53
|
-
|
|
54
|
-
const orm = await ensureDbInitialized();
|
|
24
|
+
const { ensureDbInitialized, RequestLogEntity } = await import("./db.js");
|
|
25
|
+
const orm = await ensureDbInitialized(storedDbConfig);
|
|
55
26
|
const em = orm.em.fork();
|
|
56
27
|
const logEntry = new RequestLogEntity();
|
|
57
28
|
logEntry.requestId = id;
|
|
@@ -64,7 +35,6 @@ let dbConfigured = false;
|
|
|
64
35
|
logEntry.durationMs = event.durationMs ?? undefined;
|
|
65
36
|
logEntry.error = event.error ?? undefined;
|
|
66
37
|
logEntry.requestHeaders = event.requestHeaders ?? undefined;
|
|
67
|
-
// Determine request type
|
|
68
38
|
if (event.path.startsWith("/mcp/")) {
|
|
69
39
|
logEntry.requestType = "mcp";
|
|
70
40
|
}
|
|
@@ -78,46 +48,32 @@ let dbConfigured = false;
|
|
|
78
48
|
await em.flush();
|
|
79
49
|
}
|
|
80
50
|
catch (e) {
|
|
81
|
-
// Log persistence errors but don't throw - in-memory store is the primary
|
|
82
51
|
console.error("Failed to persist audit log:", e);
|
|
83
52
|
}
|
|
84
53
|
}
|
|
85
|
-
|
|
86
|
-
* Add an audit event
|
|
87
|
-
*/ export function addAuditEvent(event) {
|
|
54
|
+
export function addAuditEvent(event) {
|
|
88
55
|
const id = `${Date.now()}-${++eventCounter}`;
|
|
89
56
|
const fullEvent = {
|
|
90
57
|
...event,
|
|
91
58
|
id
|
|
92
59
|
};
|
|
93
60
|
auditStore.set(id, fullEvent);
|
|
94
|
-
|
|
95
|
-
persistToDb(fullEvent, id).catch(() => {
|
|
96
|
-
// Already logged in persistToDb
|
|
97
|
-
});
|
|
61
|
+
persistToDb(fullEvent, id).catch(() => { });
|
|
98
62
|
return fullEvent;
|
|
99
63
|
}
|
|
100
|
-
|
|
101
|
-
* Query audit events
|
|
102
|
-
*/ export function queryAuditEvents(options) {
|
|
64
|
+
export function queryAuditEvents(options) {
|
|
103
65
|
const { limit = 50, offset = 0, serverName, serverType, method, from, to } = options;
|
|
104
|
-
// Get all events as array
|
|
105
66
|
let events = [];
|
|
106
67
|
for (const [, event] of auditStore.entries()) {
|
|
107
68
|
events.push(event);
|
|
108
69
|
}
|
|
109
|
-
// Sort by timestamp desc
|
|
110
70
|
events.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
111
|
-
|
|
112
|
-
if (serverName) {
|
|
71
|
+
if (serverName)
|
|
113
72
|
events = events.filter((e) => e.serverName === serverName);
|
|
114
|
-
|
|
115
|
-
if (serverType) {
|
|
73
|
+
if (serverType)
|
|
116
74
|
events = events.filter((e) => e.serverType === serverType);
|
|
117
|
-
|
|
118
|
-
if (method) {
|
|
75
|
+
if (method)
|
|
119
76
|
events = events.filter((e) => e.method === method);
|
|
120
|
-
}
|
|
121
77
|
if (from) {
|
|
122
78
|
const fromTime = new Date(from).getTime();
|
|
123
79
|
events = events.filter((e) => new Date(e.timestamp).getTime() >= fromTime);
|
|
@@ -127,21 +83,17 @@ let dbConfigured = false;
|
|
|
127
83
|
events = events.filter((e) => new Date(e.timestamp).getTime() <= toTime);
|
|
128
84
|
}
|
|
129
85
|
const total = events.length;
|
|
130
|
-
// Paginate
|
|
131
86
|
events = events.slice(offset, offset + limit);
|
|
132
87
|
return {
|
|
133
88
|
events,
|
|
134
89
|
total
|
|
135
90
|
};
|
|
136
91
|
}
|
|
137
|
-
|
|
138
|
-
* Get audit statistics
|
|
139
|
-
*/ export function getAuditStats(options) {
|
|
92
|
+
export function getAuditStats(options) {
|
|
140
93
|
let events = [];
|
|
141
94
|
for (const [, event] of auditStore.entries()) {
|
|
142
95
|
events.push(event);
|
|
143
96
|
}
|
|
144
|
-
// Apply time filters
|
|
145
97
|
if (options.from) {
|
|
146
98
|
const fromTime = new Date(options.from).getTime();
|
|
147
99
|
events = events.filter((e) => new Date(e.timestamp).getTime() >= fromTime);
|
|
@@ -150,12 +102,10 @@ let dbConfigured = false;
|
|
|
150
102
|
const toTime = new Date(options.to).getTime();
|
|
151
103
|
events = events.filter((e) => new Date(e.timestamp).getTime() <= toTime);
|
|
152
104
|
}
|
|
153
|
-
// Calculate stats
|
|
154
105
|
const totalRequests = events.length;
|
|
155
106
|
const totalErrors = events.filter((e) => e.error || e.status && e.status >= 400).length;
|
|
156
107
|
const durations = events.map((e) => e.durationMs).filter((d) => d != null);
|
|
157
108
|
const avgDurationMs = durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0;
|
|
158
|
-
// Group by server
|
|
159
109
|
const serverCounts = new Map();
|
|
160
110
|
for (const event of events) {
|
|
161
111
|
const name = event.serverName || "unknown";
|
|
@@ -165,11 +115,10 @@ let dbConfigured = false;
|
|
|
165
115
|
name,
|
|
166
116
|
count
|
|
167
117
|
})).sort((a, b) => b.count - a.count);
|
|
168
|
-
// Group by method
|
|
169
118
|
const methodCounts = new Map();
|
|
170
119
|
for (const event of events) {
|
|
171
|
-
const
|
|
172
|
-
methodCounts.set(
|
|
120
|
+
const m = event.method || "unknown";
|
|
121
|
+
methodCounts.set(m, (methodCounts.get(m) || 0) + 1);
|
|
173
122
|
}
|
|
174
123
|
const byMethod = Array.from(methodCounts.entries()).map(([method, count]) => ({
|
|
175
124
|
method,
|
|
@@ -183,9 +132,7 @@ let dbConfigured = false;
|
|
|
183
132
|
byMethod
|
|
184
133
|
};
|
|
185
134
|
}
|
|
186
|
-
|
|
187
|
-
* Clear audit events before a timestamp
|
|
188
|
-
*/ export function clearAuditEvents(before) {
|
|
135
|
+
export function clearAuditEvents(before) {
|
|
189
136
|
const beforeTime = new Date(before).getTime();
|
|
190
137
|
let deleted = 0;
|
|
191
138
|
for (const [id, event] of auditStore.entries()) {
|
|
@@ -196,9 +143,7 @@ let dbConfigured = false;
|
|
|
196
143
|
}
|
|
197
144
|
return deleted;
|
|
198
145
|
}
|
|
199
|
-
|
|
200
|
-
* Audit Router implementation
|
|
201
|
-
*/ export const AuditRouter = implement(AuditContract).router({
|
|
146
|
+
export const AuditRouter = implement(AuditContract).router({
|
|
202
147
|
list: implement(AuditContract.list).handler(async ({ input }) => {
|
|
203
148
|
return queryAuditEvents(input);
|
|
204
149
|
}),
|
|
@@ -216,59 +161,60 @@ let dbConfigured = false;
|
|
|
216
161
|
})
|
|
217
162
|
});
|
|
218
163
|
/**
|
|
219
|
-
*
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
164
|
+
* Set up audit by subscribing to the server emitter.
|
|
165
|
+
* Call this from the `setup` callback of `createServer` to opt in to audit.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* createServer({
|
|
170
|
+
* setup: (ctx) => {
|
|
171
|
+
* setupAudit(ctx);
|
|
172
|
+
* },
|
|
173
|
+
* });
|
|
174
|
+
* ```
|
|
175
|
+
*/ export function setupAudit(ctx, options) {
|
|
176
|
+
const auditConfig = options?.auditConfig ?? ctx.config.audit;
|
|
177
|
+
const dbConfig = options?.dbConfig ?? ctx.config.db;
|
|
178
|
+
const enabled = auditConfig?.enabled !== false;
|
|
179
|
+
if (!enabled)
|
|
180
|
+
return;
|
|
181
|
+
const auditDbConfig = auditConfig?.db ?? dbConfig;
|
|
182
|
+
if (auditDbConfig) {
|
|
183
|
+
storedDbConfig = auditDbConfig;
|
|
184
|
+
dbConfigured = true;
|
|
185
|
+
}
|
|
186
|
+
storedAuditConfig = auditConfig;
|
|
187
|
+
// Subscribe to request events
|
|
188
|
+
ctx.emitter.on(McpsEventType.Request, (event) => {
|
|
189
|
+
const shouldAudit = event.path.startsWith("/mcp/") || event.path.startsWith("/v1/") || event.path.startsWith("/api/") && event.method !== "GET";
|
|
190
|
+
if (shouldAudit) {
|
|
191
|
+
addAuditEvent({
|
|
192
|
+
timestamp: event.timestamp,
|
|
193
|
+
method: event.method,
|
|
194
|
+
path: event.path,
|
|
195
|
+
serverName: event.serverName,
|
|
196
|
+
serverType: event.serverType,
|
|
197
|
+
status: event.status,
|
|
198
|
+
durationMs: event.durationMs,
|
|
199
|
+
error: event.error,
|
|
200
|
+
requestHeaders: event.requestHeaders
|
|
201
|
+
});
|
|
253
202
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
requestHeaders: headersToRecord(c.req.raw.headers)
|
|
269
|
-
});
|
|
270
|
-
}
|
|
203
|
+
});
|
|
204
|
+
// Register audit API router
|
|
205
|
+
ctx.apiRouters.audit = AuditRouter;
|
|
206
|
+
// Register stats provider so mcps-router can access stats
|
|
207
|
+
ctx.statsProvider = {
|
|
208
|
+
getStats: getAuditStats,
|
|
209
|
+
queryEvents: (opts) => {
|
|
210
|
+
const result = queryAuditEvents(opts);
|
|
211
|
+
return {
|
|
212
|
+
events: result.events.map((e) => ({
|
|
213
|
+
path: e.path
|
|
214
|
+
})),
|
|
215
|
+
total: result.total
|
|
216
|
+
};
|
|
271
217
|
}
|
|
272
218
|
};
|
|
273
219
|
}
|
|
274
|
-
//# sourceMappingURL=
|
|
220
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/audit/server/plugin.ts"],"sourcesContent":["import { implement } from '@orpc/server';\nimport { LRUCache } from 'lru-cache';\nimport { McpsEventType } from '../../server/events';\nimport type { AuditConfig, DbConfig } from '../../server/schema';\nimport type { McpsServerContext } from '../../server/server';\nimport { AuditContract, type AuditEvent } from '../AuditContract';\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\nconst auditStore = new LRUCache<string, AuditEvent>({\n\tmax: 10000,\n\tttl: 1000 * 60 * 60 * 24,\n});\n\nlet eventCounter = 0;\nlet dbConfigured = false;\nlet storedAuditConfig: AuditConfig | undefined;\nlet storedDbConfig: DbConfig | undefined;\n\nasync function persistToDb(event: AuditEvent, id: string): Promise<void> {\n\tif (!dbConfigured) return;\n\n\ttry {\n\t\tconst { ensureDbInitialized, RequestLogEntity } = await import('./db.js');\n\t\tconst orm = await ensureDbInitialized(storedDbConfig);\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\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\tconsole.error('Failed to persist audit log:', e);\n\t}\n}\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\tpersistToDb(fullEvent, id).catch(() => {});\n\n\treturn fullEvent;\n}\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\tlet events: AuditEvent[] = [];\n\tfor (const [, event] of auditStore.entries()) {\n\t\tevents.push(event);\n\t}\n\n\tevents.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());\n\n\tif (serverName) events = events.filter((e) => e.serverName === serverName);\n\tif (serverType) events = events.filter((e) => e.serverType === serverType);\n\tif (method) events = events.filter((e) => e.method === method);\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\tevents = events.slice(offset, offset + limit);\n\n\treturn { events, total };\n}\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\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\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\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\tconst methodCounts = new Map<string, number>();\n\tfor (const event of events) {\n\t\tconst m = event.method || 'unknown';\n\t\tmethodCounts.set(m, (methodCounts.get(m) || 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\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\nexport const AuditRouter = implement(AuditContract).router({\n\tlist: implement(AuditContract.list).handler(async ({ input }) => {\n\t\treturn queryAuditEvents(input);\n\t}),\n\tget: implement(AuditContract.get).handler(async ({ input }) => {\n\t\treturn auditStore.get(input.id) ?? null;\n\t}),\n\tstats: implement(AuditContract.stats).handler(async ({ input }) => {\n\t\treturn getAuditStats(input);\n\t}),\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 * Set up audit by subscribing to the server emitter.\n * Call this from the `setup` callback of `createServer` to opt in to audit.\n *\n * @example\n * ```ts\n * createServer({\n * setup: (ctx) => {\n * setupAudit(ctx);\n * },\n * });\n * ```\n */\nexport function setupAudit(ctx: McpsServerContext, options?: { auditConfig?: AuditConfig; dbConfig?: DbConfig }) {\n\tconst auditConfig = options?.auditConfig ?? ctx.config.audit;\n\tconst dbConfig = options?.dbConfig ?? ctx.config.db;\n\n\tconst enabled = auditConfig?.enabled !== false;\n\tif (!enabled) return;\n\n\tconst auditDbConfig = auditConfig?.db ?? dbConfig;\n\tif (auditDbConfig) {\n\t\tstoredDbConfig = auditDbConfig;\n\t\tdbConfigured = true;\n\t}\n\tstoredAuditConfig = auditConfig;\n\n\t// Subscribe to request events\n\tctx.emitter.on(McpsEventType.Request, (event) => {\n\t\tconst shouldAudit =\n\t\t\tevent.path.startsWith('/mcp/') ||\n\t\t\tevent.path.startsWith('/v1/') ||\n\t\t\t(event.path.startsWith('/api/') && event.method !== 'GET');\n\n\t\tif (shouldAudit) {\n\t\t\taddAuditEvent({\n\t\t\t\ttimestamp: event.timestamp,\n\t\t\t\tmethod: event.method,\n\t\t\t\tpath: event.path,\n\t\t\t\tserverName: event.serverName,\n\t\t\t\tserverType: event.serverType,\n\t\t\t\tstatus: event.status,\n\t\t\t\tdurationMs: event.durationMs,\n\t\t\t\terror: event.error,\n\t\t\t\trequestHeaders: event.requestHeaders,\n\t\t\t});\n\t\t}\n\t});\n\n\t// Register audit API router\n\tctx.apiRouters.audit = AuditRouter;\n\n\t// Register stats provider so mcps-router can access stats\n\tctx.statsProvider = {\n\t\tgetStats: getAuditStats,\n\t\tqueryEvents: (opts) => {\n\t\t\tconst result = queryAuditEvents(opts);\n\t\t\treturn { events: result.events.map((e) => ({ path: e.path })), total: result.total };\n\t\t},\n\t};\n}\n"],"names":["implement","LRUCache","McpsEventType","AuditContract","headersToRecord","headers","record","forEach","value","key","auditStore","max","ttl","eventCounter","dbConfigured","storedAuditConfig","storedDbConfig","persistToDb","event","id","ensureDbInitialized","RequestLogEntity","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","m","byMethod","clearAuditEvents","before","beforeTime","deleted","delete","AuditRouter","router","list","handler","input","stats","clear","setupAudit","ctx","auditConfig","config","audit","dbConfig","db","enabled","auditDbConfig","emitter","on","Request","shouldAudit","apiRouters","statsProvider","getStats","queryEvents","opts","result"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/audit/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"}
|