@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.
Files changed (103) hide show
  1. package/README.md +144 -0
  2. package/dist/index.mjs +213076 -1
  3. package/dist/mcps-cli.mjs +102632 -59429
  4. package/lib/audit/AuditContract.js.map +1 -0
  5. package/lib/{chat/audit.js → audit/chat.js} +1 -1
  6. package/lib/audit/chat.js.map +1 -0
  7. package/lib/audit/entities/ChatRequestEntity.js.map +1 -0
  8. package/lib/audit/entities/McpRequestEntity.js.map +1 -0
  9. package/lib/audit/entities/RequestLogEntity.js.map +1 -0
  10. package/lib/audit/entities/ResponseEntity.js.map +1 -0
  11. package/lib/audit/entities/index.js +6 -0
  12. package/lib/audit/entities/index.js.map +1 -0
  13. package/lib/audit/server/db.js +64 -0
  14. package/lib/audit/server/db.js.map +1 -0
  15. package/lib/audit/server/index.js +2 -0
  16. package/lib/audit/server/index.js.map +1 -0
  17. package/lib/{server/audit.js → audit/server/plugin.js} +73 -127
  18. package/lib/audit/server/plugin.js.map +1 -0
  19. package/lib/audit/types.js.map +1 -0
  20. package/lib/chat/handler.js +5 -5
  21. package/lib/chat/handler.js.map +1 -1
  22. package/lib/chat/index.js +1 -1
  23. package/lib/chat/index.js.map +1 -1
  24. package/lib/cli-start.js +36 -0
  25. package/lib/cli-start.js.map +1 -0
  26. package/lib/cli.js +19 -0
  27. package/lib/cli.js.map +1 -0
  28. package/lib/contracts/index.js +1 -1
  29. package/lib/contracts/index.js.map +1 -1
  30. package/lib/dev.server.js +7 -1
  31. package/lib/dev.server.js.map +1 -1
  32. package/lib/entities/index.js +2 -10
  33. package/lib/entities/index.js.map +1 -1
  34. package/lib/index.js +21 -3
  35. package/lib/index.js.map +1 -1
  36. package/lib/mcps-cli.js +6 -35
  37. package/lib/mcps-cli.js.map +1 -1
  38. package/lib/providers/feishu/def.js +35 -0
  39. package/lib/providers/feishu/def.js.map +1 -0
  40. package/lib/providers/findMcpServerDef.js +1 -0
  41. package/lib/providers/findMcpServerDef.js.map +1 -1
  42. package/lib/scripts/bundle.js +7 -1
  43. package/lib/scripts/bundle.js.map +1 -1
  44. package/lib/server/api-routes.js +7 -8
  45. package/lib/server/api-routes.js.map +1 -1
  46. package/lib/server/events.js +13 -0
  47. package/lib/server/events.js.map +1 -0
  48. package/lib/server/mcp-routes.js +31 -60
  49. package/lib/server/mcp-routes.js.map +1 -1
  50. package/lib/server/mcps-router.js +19 -24
  51. package/lib/server/mcps-router.js.map +1 -1
  52. package/lib/server/schema.js +22 -2
  53. package/lib/server/schema.js.map +1 -1
  54. package/lib/server/server.js +142 -87
  55. package/lib/server/server.js.map +1 -1
  56. package/package.json +145 -85
  57. package/src/{chat/audit.ts → audit/chat.ts} +3 -3
  58. package/src/audit/entities/index.ts +6 -0
  59. package/src/audit/server/db.ts +65 -0
  60. package/src/audit/server/index.ts +8 -0
  61. package/src/{server/audit.ts → audit/server/plugin.ts} +71 -144
  62. package/src/chat/handler.ts +5 -5
  63. package/src/chat/index.ts +1 -1
  64. package/src/cli-start.ts +43 -0
  65. package/src/cli.ts +45 -0
  66. package/src/contracts/index.ts +1 -1
  67. package/src/dev.server.ts +8 -1
  68. package/src/entities/index.ts +2 -12
  69. package/src/index.ts +47 -1
  70. package/src/mcps-cli.ts +6 -48
  71. package/src/providers/feishu/def.ts +37 -0
  72. package/src/providers/findMcpServerDef.ts +1 -0
  73. package/src/scripts/bundle.ts +12 -1
  74. package/src/server/api-routes.ts +11 -8
  75. package/src/server/events.ts +29 -0
  76. package/src/server/mcp-routes.ts +30 -58
  77. package/src/server/mcps-router.ts +21 -29
  78. package/src/server/schema.ts +23 -2
  79. package/src/server/server.ts +149 -81
  80. package/LICENSE +0 -21
  81. package/lib/chat/audit.js.map +0 -1
  82. package/lib/contracts/AuditContract.js.map +0 -1
  83. package/lib/entities/ChatRequestEntity.js.map +0 -1
  84. package/lib/entities/McpRequestEntity.js.map +0 -1
  85. package/lib/entities/RequestLogEntity.js.map +0 -1
  86. package/lib/entities/ResponseEntity.js.map +0 -1
  87. package/lib/entities/types.js.map +0 -1
  88. package/lib/server/audit.js.map +0 -1
  89. package/lib/server/db.js +0 -97
  90. package/lib/server/db.js.map +0 -1
  91. package/src/server/db.ts +0 -115
  92. /package/lib/{contracts → audit}/AuditContract.js +0 -0
  93. /package/lib/{entities → audit/entities}/ChatRequestEntity.js +0 -0
  94. /package/lib/{entities → audit/entities}/McpRequestEntity.js +0 -0
  95. /package/lib/{entities → audit/entities}/RequestLogEntity.js +0 -0
  96. /package/lib/{entities → audit/entities}/ResponseEntity.js +0 -0
  97. /package/lib/{entities → audit}/types.js +0 -0
  98. /package/src/{contracts → audit}/AuditContract.ts +0 -0
  99. /package/src/{entities → audit/entities}/ChatRequestEntity.ts +0 -0
  100. /package/src/{entities → audit/entities}/McpRequestEntity.ts +0 -0
  101. /package/src/{entities → audit/entities}/RequestLogEntity.ts +0 -0
  102. /package/src/{entities → audit/entities}/ResponseEntity.ts +0 -0
  103. /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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"}
@@ -235,4 +235,4 @@ let auditStore = new InMemoryChatAuditStore();
235
235
  return c.req.header('x-forwarded-for')?.split(',')[0]?.trim() || c.req.header('x-real-ip') || c.req.header('cf-connecting-ip');
236
236
  }
237
237
 
238
- //# sourceMappingURL=audit.js.map
238
+ //# sourceMappingURL=chat.js.map
@@ -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,2 @@
1
+ export { setupAudit, AuditRouter, addAuditEvent, queryAuditEvents, getAuditStats, clearAuditEvents } from "./plugin.js";
2
+ //# sourceMappingURL=index.js.map
@@ -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 { AuditContract } from "../contracts/index.js";
4
- import { RequestLogEntity } from "../entities/index.js";
5
- import { ensureDbInitialized, configureDb } from "./db.js";
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
- * Configure audit module with settings
27
- * Call this before using audit features
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
- // Lazy initialize DB on first persist
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
- // Persist to database asynchronously (lazy init)
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
- // Apply filters
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 method = event.method || "unknown";
172
- methodCounts.set(method, (methodCounts.get(method) || 0) + 1);
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
- * Hono middleware for audit logging
220
- */ export function auditMiddleware() {
221
- return async (c, next) => {
222
- const startTime = Date.now();
223
- const path = c.req.path;
224
- // Extract server info from path
225
- let serverName;
226
- let serverType;
227
- const mcpMatch = path.match(/^\/mcp\/([^/]+)/);
228
- if (mcpMatch) {
229
- serverName = mcpMatch[1];
230
- // Infer type from well-known paths
231
- if (serverName === "tencent-cls")
232
- serverType = "tencent-cls";
233
- else if (serverName === "sql")
234
- serverType = "sql";
235
- else if (serverName === "prometheus")
236
- serverType = "prometheus";
237
- else if (serverName === "relay")
238
- serverType = "relay";
239
- else
240
- serverType = "custom";
241
- }
242
- // Extract model info from chat requests
243
- if (path.startsWith("/v1/")) {
244
- serverType = "chat";
245
- }
246
- let error;
247
- try {
248
- await next();
249
- }
250
- catch (e) {
251
- error = e instanceof Error ? e.message : String(e);
252
- throw e;
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
- finally {
255
- const durationMs = Date.now() - startTime;
256
- // Audit MCP requests, Chat API requests, and other API requests
257
- const shouldAudit = path.startsWith("/mcp/") || path.startsWith("/v1/") || path.startsWith("/api/") && c.req.method !== "GET";
258
- if (shouldAudit) {
259
- addAuditEvent({
260
- timestamp: new Date().toISOString(),
261
- method: c.req.method,
262
- path,
263
- serverName,
264
- serverType,
265
- status: c.res.status,
266
- durationMs,
267
- error,
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=audit.js.map
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":"AAAA,SAASA,SAAS,QAAQ,eAAe;AACzC,SAASC,QAAQ,QAAQ,YAAY;AACrC,SAASC,aAAa,QAAQ,sBAAsB;AAGpD,SAASC,aAAa,QAAyB,mBAAmB;AAElE,SAASC,gBAAgBC,OAAgB;IACxC,MAAMC,SAAiC,CAAC;IACxCD,QAAQE,OAAO,CAAC,CAACC,OAAOC;QACvBH,MAAM,CAACG,IAAI,GAAGD;IACf;IACA,OAAOF;AACR;AAEA,MAAMI,aAAa,IAAIT,SAA6B;IACnDU,KAAK;IACLC,KAAK,OAAO,KAAK,KAAK;AACvB;AAEA,IAAIC,eAAe;AACnB,IAAIC,eAAe;AACnB,IAAIC;AACJ,IAAIC;AAEJ,eAAeC,YAAYC,KAAiB,EAAEC,EAAU;IACvD,IAAI,CAACL,cAAc;IAEnB,IAAI;QACH,MAAM,EAAEM,mBAAmB,EAAEC,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC;QAC/D,MAAMC,MAAM,MAAMF,oBAAoBJ;QACtC,MAAMO,KAAKD,IAAIC,EAAE,CAACC,IAAI;QAEtB,MAAMC,WAAW,IAAIJ;QACrBI,SAASC,SAAS,GAAGP;QACrBM,SAASE,SAAS,GAAG,IAAIC,KAAKV,MAAMS,SAAS;QAC7CF,SAASI,MAAM,GAAGX,MAAMW,MAAM;QAC9BJ,SAASK,IAAI,GAAGZ,MAAMY,IAAI;QAC1BL,SAASM,UAAU,GAAGb,MAAMa,UAAU,IAAIC;QAC1CP,SAASQ,UAAU,GAAGf,MAAMe,UAAU,IAAID;QAC1CP,SAASS,MAAM,GAAGhB,MAAMgB,MAAM,IAAIF;QAClCP,SAASU,UAAU,GAAGjB,MAAMiB,UAAU,IAAIH;QAC1CP,SAASW,KAAK,GAAGlB,MAAMkB,KAAK,IAAIJ;QAChCP,SAASY,cAAc,GAAGnB,MAAMmB,cAAc,IAAIL;QAClD,IAAId,MAAMY,IAAI,CAACQ,UAAU,CAAC,UAAU;YACnCb,SAASc,WAAW,GAAG;QACxB,OAAO,IAAIrB,MAAMY,IAAI,CAACQ,UAAU,CAAC,SAAS;YACzCb,SAASc,WAAW,GAAG;QACxB,OAAO;YACNd,SAASc,WAAW,GAAG;QACxB;QACAhB,GAAGiB,OAAO,CAACf;QACX,MAAMF,GAAGkB,KAAK;IACf,EAAE,OAAOC,GAAG;QACXC,QAAQP,KAAK,CAAC,gCAAgCM;IAC/C;AACD;AAEA,OAAO,SAASE,cAAc1B,KAA6B;IAC1D,MAAMC,KAAK,GAAGS,KAAKiB,GAAG,GAAG,CAAC,EAAE,EAAEhC,cAAc;IAC5C,MAAMiC,YAAwB;QAAE,GAAG5B,KAAK;QAAEC;IAAG;IAC7CT,WAAWqC,GAAG,CAAC5B,IAAI2B;IAEnB7B,YAAY6B,WAAW3B,IAAI6B,KAAK,CAAC,KAAO;IAExC,OAAOF;AACR;AAEA,OAAO,SAASG,iBAAiBC,OAQhC;IACA,MAAM,EAAEC,QAAQ,EAAE,EAAEC,SAAS,CAAC,EAAErB,UAAU,EAAEE,UAAU,EAAEJ,MAAM,EAAEwB,IAAI,EAAEC,EAAE,EAAE,GAAGJ;IAE7E,IAAIK,SAAuB,EAAE;IAC7B,KAAK,MAAM,GAAGrC,MAAM,IAAIR,WAAW8C,OAAO,GAAI;QAC7CD,OAAOE,IAAI,CAACvC;IACb;IAEAqC,OAAOG,IAAI,CAAC,CAACC,GAAGC,IAAM,IAAIhC,KAAKgC,EAAEjC,SAAS,EAAEkC,OAAO,KAAK,IAAIjC,KAAK+B,EAAEhC,SAAS,EAAEkC,OAAO;IAErF,IAAI9B,YAAYwB,SAASA,OAAOO,MAAM,CAAC,CAACpB,IAAMA,EAAEX,UAAU,KAAKA;IAC/D,IAAIE,YAAYsB,SAASA,OAAOO,MAAM,CAAC,CAACpB,IAAMA,EAAET,UAAU,KAAKA;IAC/D,IAAIJ,QAAQ0B,SAASA,OAAOO,MAAM,CAAC,CAACpB,IAAMA,EAAEb,MAAM,KAAKA;IACvD,IAAIwB,MAAM;QACT,MAAMU,WAAW,IAAInC,KAAKyB,MAAMQ,OAAO;QACvCN,SAASA,OAAOO,MAAM,CAAC,CAACpB,IAAM,IAAId,KAAKc,EAAEf,SAAS,EAAEkC,OAAO,MAAME;IAClE;IACA,IAAIT,IAAI;QACP,MAAMU,SAAS,IAAIpC,KAAK0B,IAAIO,OAAO;QACnCN,SAASA,OAAOO,MAAM,CAAC,CAACpB,IAAM,IAAId,KAAKc,EAAEf,SAAS,EAAEkC,OAAO,MAAMG;IAClE;IAEA,MAAMC,QAAQV,OAAOW,MAAM;IAC3BX,SAASA,OAAOY,KAAK,CAACf,QAAQA,SAASD;IAEvC,OAAO;QAAEI;QAAQU;IAAM;AACxB;AAEA,OAAO,SAASG,cAAclB,OAAqD;IAClF,IAAIK,SAAuB,EAAE;IAC7B,KAAK,MAAM,GAAGrC,MAAM,IAAIR,WAAW8C,OAAO,GAAI;QAC7CD,OAAOE,IAAI,CAACvC;IACb;IAEA,IAAIgC,QAAQG,IAAI,EAAE;QACjB,MAAMU,WAAW,IAAInC,KAAKsB,QAAQG,IAAI,EAAEQ,OAAO;QAC/CN,SAASA,OAAOO,MAAM,CAAC,CAACpB,IAAM,IAAId,KAAKc,EAAEf,SAAS,EAAEkC,OAAO,MAAME;IAClE;IACA,IAAIb,QAAQI,EAAE,EAAE;QACf,MAAMU,SAAS,IAAIpC,KAAKsB,QAAQI,EAAE,EAAEO,OAAO;QAC3CN,SAASA,OAAOO,MAAM,CAAC,CAACpB,IAAM,IAAId,KAAKc,EAAEf,SAAS,EAAEkC,OAAO,MAAMG;IAClE;IAEA,MAAMK,gBAAgBd,OAAOW,MAAM;IACnC,MAAMI,cAAcf,OAAOO,MAAM,CAAC,CAACpB,IAAMA,EAAEN,KAAK,IAAKM,EAAER,MAAM,IAAIQ,EAAER,MAAM,IAAI,KAAMgC,MAAM;IAEzF,MAAMK,YAAYhB,OAAOiB,GAAG,CAAC,CAAC9B,IAAMA,EAAEP,UAAU,EAAE2B,MAAM,CAAC,CAACW,IAAmBA,KAAK;IAClF,MAAMC,gBAAgBH,UAAUL,MAAM,GAAG,IAAIK,UAAUI,MAAM,CAAC,CAAChB,GAAGC,IAAMD,IAAIC,GAAG,KAAKW,UAAUL,MAAM,GAAG;IAEvG,MAAMU,eAAe,IAAIC;IACzB,KAAK,MAAM3D,SAASqC,OAAQ;QAC3B,MAAMuB,OAAO5D,MAAMa,UAAU,IAAI;QACjC6C,aAAa7B,GAAG,CAAC+B,MAAM,AAACF,CAAAA,aAAaG,GAAG,CAACD,SAAS,CAAA,IAAK;IACxD;IACA,MAAME,WAAWC,MAAM5B,IAAI,CAACuB,aAAapB,OAAO,IAC9CgB,GAAG,CAAC,CAAC,CAACM,MAAMI,MAAM,GAAM,CAAA;YAAEJ;YAAMI;QAAM,CAAA,GACtCxB,IAAI,CAAC,CAACC,GAAGC,IAAMA,EAAEsB,KAAK,GAAGvB,EAAEuB,KAAK;IAElC,MAAMC,eAAe,IAAIN;IACzB,KAAK,MAAM3D,SAASqC,OAAQ;QAC3B,MAAM6B,IAAIlE,MAAMW,MAAM,IAAI;QAC1BsD,aAAapC,GAAG,CAACqC,GAAG,AAACD,CAAAA,aAAaJ,GAAG,CAACK,MAAM,CAAA,IAAK;IAClD;IACA,MAAMC,WAAWJ,MAAM5B,IAAI,CAAC8B,aAAa3B,OAAO,IAC9CgB,GAAG,CAAC,CAAC,CAAC3C,QAAQqD,MAAM,GAAM,CAAA;YAAErD;YAAQqD;QAAM,CAAA,GAC1CxB,IAAI,CAAC,CAACC,GAAGC,IAAMA,EAAEsB,KAAK,GAAGvB,EAAEuB,KAAK;IAElC,OAAO;QAAEb;QAAeC;QAAaI;QAAeM;QAAUK;IAAS;AACxE;AAEA,OAAO,SAASC,iBAAiBC,MAAc;IAC9C,MAAMC,aAAa,IAAI5D,KAAK2D,QAAQ1B,OAAO;IAC3C,IAAI4B,UAAU;IAEd,KAAK,MAAM,CAACtE,IAAID,MAAM,IAAIR,WAAW8C,OAAO,GAAI;QAC/C,IAAI,IAAI5B,KAAKV,MAAMS,SAAS,EAAEkC,OAAO,KAAK2B,YAAY;YACrD9E,WAAWgF,MAAM,CAACvE;YAClBsE;QACD;IACD;IAEA,OAAOA;AACR;AAEA,OAAO,MAAME,cAAc3F,UAAUG,eAAeyF,MAAM,CAAC;IAC1DC,MAAM7F,UAAUG,cAAc0F,IAAI,EAAEC,OAAO,CAAC,OAAO,EAAEC,KAAK,EAAE;QAC3D,OAAO9C,iBAAiB8C;IACzB;IACAhB,KAAK/E,UAAUG,cAAc4E,GAAG,EAAEe,OAAO,CAAC,OAAO,EAAEC,KAAK,EAAE;QACzD,OAAOrF,WAAWqE,GAAG,CAACgB,MAAM5E,EAAE,KAAK;IACpC;IACA6E,OAAOhG,UAAUG,cAAc6F,KAAK,EAAEF,OAAO,CAAC,OAAO,EAAEC,KAAK,EAAE;QAC7D,OAAO3B,cAAc2B;IACtB;IACAE,OAAOjG,UAAUG,cAAc8F,KAAK,EAAEH,OAAO,CAAC,OAAO,EAAEC,KAAK,EAAE;QAC7D,MAAMN,UAAUH,iBAAiBS,MAAMR,MAAM;QAC7C,OAAO;YAAEE;QAAQ;IAClB;AACD,GAAG;AAEH;;;;;;;;;;;;CAYC,GACD,OAAO,SAASS,WAAWC,GAAsB,EAAEjD,OAA4D;IAC9G,MAAMkD,cAAclD,SAASkD,eAAeD,IAAIE,MAAM,CAACC,KAAK;IAC5D,MAAMC,WAAWrD,SAASqD,YAAYJ,IAAIE,MAAM,CAACG,EAAE;IAEnD,MAAMC,UAAUL,aAAaK,YAAY;IACzC,IAAI,CAACA,SAAS;IAEd,MAAMC,gBAAgBN,aAAaI,MAAMD;IACzC,IAAIG,eAAe;QAClB1F,iBAAiB0F;QACjB5F,eAAe;IAChB;IACAC,oBAAoBqF;IAEpB,8BAA8B;IAC9BD,IAAIQ,OAAO,CAACC,EAAE,CAAC1G,cAAc2G,OAAO,EAAE,CAAC3F;QACtC,MAAM4F,cACL5F,MAAMY,IAAI,CAACQ,UAAU,CAAC,YACtBpB,MAAMY,IAAI,CAACQ,UAAU,CAAC,WACrBpB,MAAMY,IAAI,CAACQ,UAAU,CAAC,YAAYpB,MAAMW,MAAM,KAAK;QAErD,IAAIiF,aAAa;YAChBlE,cAAc;gBACbjB,WAAWT,MAAMS,SAAS;gBAC1BE,QAAQX,MAAMW,MAAM;gBACpBC,MAAMZ,MAAMY,IAAI;gBAChBC,YAAYb,MAAMa,UAAU;gBAC5BE,YAAYf,MAAMe,UAAU;gBAC5BC,QAAQhB,MAAMgB,MAAM;gBACpBC,YAAYjB,MAAMiB,UAAU;gBAC5BC,OAAOlB,MAAMkB,KAAK;gBAClBC,gBAAgBnB,MAAMmB,cAAc;YACrC;QACD;IACD;IAEA,4BAA4B;IAC5B8D,IAAIY,UAAU,CAACT,KAAK,GAAGX;IAEvB,0DAA0D;IAC1DQ,IAAIa,aAAa,GAAG;QACnBC,UAAU7C;QACV8C,aAAa,CAACC;YACb,MAAMC,SAASnE,iBAAiBkE;YAChC,OAAO;gBAAE5D,QAAQ6D,OAAO7D,MAAM,CAACiB,GAAG,CAAC,CAAC9B,IAAO,CAAA;wBAAEZ,MAAMY,EAAEZ,IAAI;oBAAC,CAAA;gBAAKmC,OAAOmD,OAAOnD,KAAK;YAAC;QACpF;IACD;AACD"}
@@ -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"}