@wener/mcps 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.mjs +15 -0
- package/dist/mcps-cli.mjs +174727 -0
- package/lib/chat/agent.js +187 -0
- package/lib/chat/agent.js.map +1 -0
- package/lib/chat/audit.js +238 -0
- package/lib/chat/audit.js.map +1 -0
- package/lib/chat/converters.js +467 -0
- package/lib/chat/converters.js.map +1 -0
- package/lib/chat/handler.js +1068 -0
- package/lib/chat/handler.js.map +1 -0
- package/lib/chat/index.js +12 -0
- package/lib/chat/index.js.map +1 -0
- package/lib/chat/types.js +35 -0
- package/lib/chat/types.js.map +1 -0
- package/lib/contracts/AuditContract.js +85 -0
- package/lib/contracts/AuditContract.js.map +1 -0
- package/lib/contracts/McpsContract.js +113 -0
- package/lib/contracts/McpsContract.js.map +1 -0
- package/lib/contracts/index.js +3 -0
- package/lib/contracts/index.js.map +1 -0
- package/lib/dev.server.js +7 -0
- package/lib/dev.server.js.map +1 -0
- package/lib/entities/ChatRequestEntity.js +318 -0
- package/lib/entities/ChatRequestEntity.js.map +1 -0
- package/lib/entities/McpRequestEntity.js +271 -0
- package/lib/entities/McpRequestEntity.js.map +1 -0
- package/lib/entities/RequestLogEntity.js +177 -0
- package/lib/entities/RequestLogEntity.js.map +1 -0
- package/lib/entities/ResponseEntity.js +150 -0
- package/lib/entities/ResponseEntity.js.map +1 -0
- package/lib/entities/index.js +11 -0
- package/lib/entities/index.js.map +1 -0
- package/lib/entities/types.js +11 -0
- package/lib/entities/types.js.map +1 -0
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -0
- package/lib/mcps-cli.js +44 -0
- package/lib/mcps-cli.js.map +1 -0
- package/lib/providers/McpServerHandlerDef.js +40 -0
- package/lib/providers/McpServerHandlerDef.js.map +1 -0
- package/lib/providers/findMcpServerDef.js +26 -0
- package/lib/providers/findMcpServerDef.js.map +1 -0
- package/lib/providers/prometheus/def.js +24 -0
- package/lib/providers/prometheus/def.js.map +1 -0
- package/lib/providers/prometheus/index.js +2 -0
- package/lib/providers/prometheus/index.js.map +1 -0
- package/lib/providers/relay/def.js +32 -0
- package/lib/providers/relay/def.js.map +1 -0
- package/lib/providers/relay/index.js +2 -0
- package/lib/providers/relay/index.js.map +1 -0
- package/lib/providers/sql/def.js +31 -0
- package/lib/providers/sql/def.js.map +1 -0
- package/lib/providers/sql/index.js +2 -0
- package/lib/providers/sql/index.js.map +1 -0
- package/lib/providers/tencent-cls/def.js +44 -0
- package/lib/providers/tencent-cls/def.js.map +1 -0
- package/lib/providers/tencent-cls/index.js +2 -0
- package/lib/providers/tencent-cls/index.js.map +1 -0
- package/lib/scripts/bundle.js +90 -0
- package/lib/scripts/bundle.js.map +1 -0
- package/lib/server/api-routes.js +96 -0
- package/lib/server/api-routes.js.map +1 -0
- package/lib/server/audit.js +274 -0
- package/lib/server/audit.js.map +1 -0
- package/lib/server/chat-routes.js +82 -0
- package/lib/server/chat-routes.js.map +1 -0
- package/lib/server/config.js +223 -0
- package/lib/server/config.js.map +1 -0
- package/lib/server/db.js +97 -0
- package/lib/server/db.js.map +1 -0
- package/lib/server/index.js +2 -0
- package/lib/server/index.js.map +1 -0
- package/lib/server/mcp-handler.js +167 -0
- package/lib/server/mcp-handler.js.map +1 -0
- package/lib/server/mcp-routes.js +112 -0
- package/lib/server/mcp-routes.js.map +1 -0
- package/lib/server/mcps-router.js +119 -0
- package/lib/server/mcps-router.js.map +1 -0
- package/lib/server/schema.js +129 -0
- package/lib/server/schema.js.map +1 -0
- package/lib/server/server.js +166 -0
- package/lib/server/server.js.map +1 -0
- package/lib/web/ChatPage.js +827 -0
- package/lib/web/ChatPage.js.map +1 -0
- package/lib/web/McpInspectorPage.js +214 -0
- package/lib/web/McpInspectorPage.js.map +1 -0
- package/lib/web/ServersPage.js +93 -0
- package/lib/web/ServersPage.js.map +1 -0
- package/lib/web/main.js +541 -0
- package/lib/web/main.js.map +1 -0
- package/package.json +83 -0
- package/src/chat/agent.ts +240 -0
- package/src/chat/audit.ts +377 -0
- package/src/chat/converters.test.ts +325 -0
- package/src/chat/converters.ts +459 -0
- package/src/chat/handler.test.ts +137 -0
- package/src/chat/handler.ts +1233 -0
- package/src/chat/index.ts +16 -0
- package/src/chat/types.ts +72 -0
- package/src/contracts/AuditContract.ts +93 -0
- package/src/contracts/McpsContract.ts +141 -0
- package/src/contracts/index.ts +18 -0
- package/src/dev.server.ts +7 -0
- package/src/entities/ChatRequestEntity.ts +157 -0
- package/src/entities/McpRequestEntity.ts +149 -0
- package/src/entities/RequestLogEntity.ts +78 -0
- package/src/entities/ResponseEntity.ts +75 -0
- package/src/entities/index.ts +12 -0
- package/src/entities/types.ts +188 -0
- package/src/index.ts +1 -0
- package/src/mcps-cli.ts +59 -0
- package/src/providers/McpServerHandlerDef.ts +105 -0
- package/src/providers/findMcpServerDef.ts +31 -0
- package/src/providers/prometheus/def.ts +21 -0
- package/src/providers/prometheus/index.ts +1 -0
- package/src/providers/relay/def.ts +31 -0
- package/src/providers/relay/index.ts +1 -0
- package/src/providers/relay/relay.test.ts +47 -0
- package/src/providers/sql/def.ts +33 -0
- package/src/providers/sql/index.ts +1 -0
- package/src/providers/tencent-cls/def.ts +38 -0
- package/src/providers/tencent-cls/index.ts +1 -0
- package/src/scripts/bundle.ts +82 -0
- package/src/server/api-routes.ts +98 -0
- package/src/server/audit.ts +310 -0
- package/src/server/chat-routes.ts +95 -0
- package/src/server/config.test.ts +162 -0
- package/src/server/config.ts +198 -0
- package/src/server/db.ts +115 -0
- package/src/server/index.ts +1 -0
- package/src/server/mcp-handler.ts +209 -0
- package/src/server/mcp-routes.ts +133 -0
- package/src/server/mcps-router.ts +133 -0
- package/src/server/schema.ts +175 -0
- package/src/server/server.ts +163 -0
- package/src/web/ChatPage.tsx +1005 -0
- package/src/web/McpInspectorPage.tsx +254 -0
- package/src/web/ServersPage.tsx +139 -0
- package/src/web/main.tsx +600 -0
- package/src/web/styles.css +15 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SqlMcpServerDef } from "@wener/ai/mcp/sql";
|
|
2
|
+
import { HeaderNames } from "../../server/schema.js";
|
|
3
|
+
import { defineMcpServerHandler, registerMcpServerHandler } from "../McpServerHandlerDef.js";
|
|
4
|
+
export const SqlMcpServerHandlerDef = defineMcpServerHandler(SqlMcpServerDef, {
|
|
5
|
+
headerMappings: [
|
|
6
|
+
{
|
|
7
|
+
header: HeaderNames.DB_URL,
|
|
8
|
+
property: "url"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
header: HeaderNames.DB_READ_URL,
|
|
12
|
+
property: "readUrl"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
header: HeaderNames.DB_WRITE_URL,
|
|
16
|
+
property: "writeUrl"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
resolveConfig(config, headers) {
|
|
20
|
+
const url = config.dbUrl || config.dbReadUrl || config.dbWriteUrl || headers?.get(HeaderNames.DB_URL) || headers?.get(HeaderNames.DB_READ_URL) || headers?.get(HeaderNames.DB_WRITE_URL) || config.headers?.[HeaderNames.DB_URL] || config.headers?.[HeaderNames.DB_READ_URL] || config.headers?.[HeaderNames.DB_WRITE_URL];
|
|
21
|
+
if (!url)
|
|
22
|
+
return null;
|
|
23
|
+
return {
|
|
24
|
+
url
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
registerMcpServerHandler(SqlMcpServerHandlerDef);
|
|
29
|
+
// backward compatibility
|
|
30
|
+
export { SqlMcpServerHandlerDef as SqlMcpServerDef };
|
|
31
|
+
//# sourceMappingURL=def.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/providers/sql/def.ts"],"sourcesContent":["import { SqlMcpServerDef, type CreateSqlMcpServerOptions } from '@wener/ai/mcp/sql';\nimport { HeaderNames, type SqlConfig } from '../../server/schema';\nimport { defineMcpServerHandler, registerMcpServerHandler } from '../McpServerHandlerDef';\n\nexport const SqlMcpServerHandlerDef = defineMcpServerHandler<CreateSqlMcpServerOptions, SqlConfig>(SqlMcpServerDef, {\n\theaderMappings: [\n\t\t{ header: HeaderNames.DB_URL, property: 'url' },\n\t\t{ header: HeaderNames.DB_READ_URL, property: 'readUrl' },\n\t\t{ header: HeaderNames.DB_WRITE_URL, property: 'writeUrl' },\n\t],\n\n\tresolveConfig(config, headers) {\n\t\tconst url =\n\t\t\tconfig.dbUrl ||\n\t\t\tconfig.dbReadUrl ||\n\t\t\tconfig.dbWriteUrl ||\n\t\t\theaders?.get(HeaderNames.DB_URL) ||\n\t\t\theaders?.get(HeaderNames.DB_READ_URL) ||\n\t\t\theaders?.get(HeaderNames.DB_WRITE_URL) ||\n\t\t\tconfig.headers?.[HeaderNames.DB_URL] ||\n\t\t\tconfig.headers?.[HeaderNames.DB_READ_URL] ||\n\t\t\tconfig.headers?.[HeaderNames.DB_WRITE_URL];\n\n\t\tif (!url) return null;\n\n\t\treturn { url };\n\t},\n});\n\nregisterMcpServerHandler(SqlMcpServerHandlerDef);\n\n// backward compatibility\nexport { SqlMcpServerHandlerDef as SqlMcpServerDef };\n"],"names":["SqlMcpServerDef","HeaderNames","defineMcpServerHandler","registerMcpServerHandler","SqlMcpServerHandlerDef","headerMappings","header","DB_URL","property","DB_READ_URL","DB_WRITE_URL","resolveConfig","config","headers","url","dbUrl","dbReadUrl","dbWriteUrl","get"],"mappings":"AAAA,SAASA,eAAe,QAAwC,oBAAoB;AACpF,SAASC,WAAW,QAAwB,sBAAsB;AAClE,SAASC,sBAAsB,EAAEC,wBAAwB,QAAQ,yBAAyB;AAE1F,OAAO,MAAMC,yBAAyBF,uBAA6DF,iBAAiB;IACnHK,gBAAgB;QACf;YAAEC,QAAQL,YAAYM,MAAM;YAAEC,UAAU;QAAM;QAC9C;YAAEF,QAAQL,YAAYQ,WAAW;YAAED,UAAU;QAAU;QACvD;YAAEF,QAAQL,YAAYS,YAAY;YAAEF,UAAU;QAAW;KACzD;IAEDG,eAAcC,MAAM,EAAEC,OAAO;QAC5B,MAAMC,MACLF,OAAOG,KAAK,IACZH,OAAOI,SAAS,IAChBJ,OAAOK,UAAU,IACjBJ,SAASK,IAAIjB,YAAYM,MAAM,KAC/BM,SAASK,IAAIjB,YAAYQ,WAAW,KACpCI,SAASK,IAAIjB,YAAYS,YAAY,KACrCE,OAAOC,OAAO,EAAE,CAACZ,YAAYM,MAAM,CAAC,IACpCK,OAAOC,OAAO,EAAE,CAACZ,YAAYQ,WAAW,CAAC,IACzCG,OAAOC,OAAO,EAAE,CAACZ,YAAYS,YAAY,CAAC;QAE3C,IAAI,CAACI,KAAK,OAAO;QAEjB,OAAO;YAAEA;QAAI;IACd;AACD,GAAG;AAEHX,yBAAyBC;AAEzB,yBAAyB;AACzB,SAASA,0BAA0BJ,eAAe,GAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/providers/sql/index.ts"],"sourcesContent":["export { SqlMcpServerDef, SqlMcpServerHandlerDef } from './def';\n"],"names":["SqlMcpServerDef","SqlMcpServerHandlerDef"],"mappings":"AAAA,SAASA,eAAe,EAAEC,sBAAsB,QAAQ,QAAQ"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { TencentClsMcpServerDef } from "@wener/ai/mcp/tencent-cls";
|
|
2
|
+
import { HeaderNames } from "../../server/schema.js";
|
|
3
|
+
import { defineMcpServerHandler, registerMcpServerHandler } from "../McpServerHandlerDef.js";
|
|
4
|
+
export const TencentClsMcpServerHandlerDef = defineMcpServerHandler(TencentClsMcpServerDef, {
|
|
5
|
+
headerMappings: [
|
|
6
|
+
{
|
|
7
|
+
header: HeaderNames.CLS_SECRET_ID,
|
|
8
|
+
property: "clientId",
|
|
9
|
+
required: true
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
header: HeaderNames.CLS_SECRET_KEY,
|
|
13
|
+
property: "clientSecret",
|
|
14
|
+
required: true
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
header: HeaderNames.CLS_REGION,
|
|
18
|
+
property: "region",
|
|
19
|
+
default: "ap-shanghai"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
header: HeaderNames.CLS_ENDPOINT,
|
|
23
|
+
property: "endpoint"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
resolveConfig(config, headers) {
|
|
27
|
+
const clientId = config.clientId || headers?.get(HeaderNames.CLS_SECRET_ID) || config.headers?.[HeaderNames.CLS_SECRET_ID];
|
|
28
|
+
const clientSecret = config.clientSecret || headers?.get(HeaderNames.CLS_SECRET_KEY) || config.headers?.[HeaderNames.CLS_SECRET_KEY];
|
|
29
|
+
const region = config.region || headers?.get(HeaderNames.CLS_REGION) || config.headers?.[HeaderNames.CLS_REGION] || "ap-shanghai";
|
|
30
|
+
const endpoint = config.endpoint || headers?.get(HeaderNames.CLS_ENDPOINT) || config.headers?.[HeaderNames.CLS_ENDPOINT];
|
|
31
|
+
if (!clientId || !clientSecret)
|
|
32
|
+
return null;
|
|
33
|
+
return {
|
|
34
|
+
clientId,
|
|
35
|
+
clientSecret,
|
|
36
|
+
region,
|
|
37
|
+
endpoint
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
registerMcpServerHandler(TencentClsMcpServerHandlerDef);
|
|
42
|
+
// backward compatibility
|
|
43
|
+
export { TencentClsMcpServerHandlerDef as TencentClsMcpServerDef };
|
|
44
|
+
//# sourceMappingURL=def.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/providers/tencent-cls/def.ts"],"sourcesContent":["import { TencentClsMcpServerDef, type CreateTencentClsMcpServerOptions } from '@wener/ai/mcp/tencent-cls';\nimport { HeaderNames, type TencentClsConfig } from '../../server/schema';\nimport { defineMcpServerHandler, registerMcpServerHandler } from '../McpServerHandlerDef';\n\nexport const TencentClsMcpServerHandlerDef = defineMcpServerHandler<\n\tCreateTencentClsMcpServerOptions,\n\tTencentClsConfig\n>(TencentClsMcpServerDef, {\n\theaderMappings: [\n\t\t{ header: HeaderNames.CLS_SECRET_ID, property: 'clientId', required: true },\n\t\t{ header: HeaderNames.CLS_SECRET_KEY, property: 'clientSecret', required: true },\n\t\t{ header: HeaderNames.CLS_REGION, property: 'region', default: 'ap-shanghai' },\n\t\t{ header: HeaderNames.CLS_ENDPOINT, property: 'endpoint' },\n\t],\n\n\tresolveConfig(config, headers) {\n\t\tconst clientId =\n\t\t\tconfig.clientId || headers?.get(HeaderNames.CLS_SECRET_ID) || config.headers?.[HeaderNames.CLS_SECRET_ID];\n\t\tconst clientSecret =\n\t\t\tconfig.clientSecret || headers?.get(HeaderNames.CLS_SECRET_KEY) || config.headers?.[HeaderNames.CLS_SECRET_KEY];\n\t\tconst region =\n\t\t\tconfig.region ||\n\t\t\theaders?.get(HeaderNames.CLS_REGION) ||\n\t\t\tconfig.headers?.[HeaderNames.CLS_REGION] ||\n\t\t\t'ap-shanghai';\n\t\tconst endpoint =\n\t\t\tconfig.endpoint || headers?.get(HeaderNames.CLS_ENDPOINT) || config.headers?.[HeaderNames.CLS_ENDPOINT];\n\n\t\tif (!clientId || !clientSecret) return null;\n\n\t\treturn { clientId, clientSecret, region, endpoint };\n\t},\n});\n\nregisterMcpServerHandler(TencentClsMcpServerHandlerDef);\n\n// backward compatibility\nexport { TencentClsMcpServerHandlerDef as TencentClsMcpServerDef };\n"],"names":["TencentClsMcpServerDef","HeaderNames","defineMcpServerHandler","registerMcpServerHandler","TencentClsMcpServerHandlerDef","headerMappings","header","CLS_SECRET_ID","property","required","CLS_SECRET_KEY","CLS_REGION","default","CLS_ENDPOINT","resolveConfig","config","headers","clientId","get","clientSecret","region","endpoint"],"mappings":"AAAA,SAASA,sBAAsB,QAA+C,4BAA4B;AAC1G,SAASC,WAAW,QAA+B,sBAAsB;AACzE,SAASC,sBAAsB,EAAEC,wBAAwB,QAAQ,yBAAyB;AAE1F,OAAO,MAAMC,gCAAgCF,uBAG3CF,wBAAwB;IACzBK,gBAAgB;QACf;YAAEC,QAAQL,YAAYM,aAAa;YAAEC,UAAU;YAAYC,UAAU;QAAK;QAC1E;YAAEH,QAAQL,YAAYS,cAAc;YAAEF,UAAU;YAAgBC,UAAU;QAAK;QAC/E;YAAEH,QAAQL,YAAYU,UAAU;YAAEH,UAAU;YAAUI,SAAS;QAAc;QAC7E;YAAEN,QAAQL,YAAYY,YAAY;YAAEL,UAAU;QAAW;KACzD;IAEDM,eAAcC,MAAM,EAAEC,OAAO;QAC5B,MAAMC,WACLF,OAAOE,QAAQ,IAAID,SAASE,IAAIjB,YAAYM,aAAa,KAAKQ,OAAOC,OAAO,EAAE,CAACf,YAAYM,aAAa,CAAC;QAC1G,MAAMY,eACLJ,OAAOI,YAAY,IAAIH,SAASE,IAAIjB,YAAYS,cAAc,KAAKK,OAAOC,OAAO,EAAE,CAACf,YAAYS,cAAc,CAAC;QAChH,MAAMU,SACLL,OAAOK,MAAM,IACbJ,SAASE,IAAIjB,YAAYU,UAAU,KACnCI,OAAOC,OAAO,EAAE,CAACf,YAAYU,UAAU,CAAC,IACxC;QACD,MAAMU,WACLN,OAAOM,QAAQ,IAAIL,SAASE,IAAIjB,YAAYY,YAAY,KAAKE,OAAOC,OAAO,EAAE,CAACf,YAAYY,YAAY,CAAC;QAExG,IAAI,CAACI,YAAY,CAACE,cAAc,OAAO;QAEvC,OAAO;YAAEF;YAAUE;YAAcC;YAAQC;QAAS;IACnD;AACD,GAAG;AAEHlB,yBAAyBC;AAEzB,yBAAyB;AACzB,SAASA,iCAAiCJ,sBAAsB,GAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/providers/tencent-cls/index.ts"],"sourcesContent":["export { TencentClsMcpServerDef, TencentClsMcpServerHandlerDef } from './def';\n"],"names":["TencentClsMcpServerDef","TencentClsMcpServerHandlerDef"],"mappings":"AAAA,SAASA,sBAAsB,EAAEC,6BAA6B,QAAQ,QAAQ"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import * as esbuild from 'esbuild';
|
|
4
|
+
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
|
|
5
|
+
const banner = `// Bundled with esbuild
|
|
6
|
+
// ${pkg.name}@${pkg.version}
|
|
7
|
+
|
|
8
|
+
var require,__filename,__dirname;
|
|
9
|
+
{
|
|
10
|
+
const {createRequire} = await import('node:module');
|
|
11
|
+
require ||= createRequire(import.meta.url);
|
|
12
|
+
}
|
|
13
|
+
{
|
|
14
|
+
const {fileURLToPath} = await import('node:url');
|
|
15
|
+
const {dirname} = await import('node:path');
|
|
16
|
+
__filename ||= fileURLToPath(import.meta.url);
|
|
17
|
+
__dirname ||= dirname(__filename)
|
|
18
|
+
};
|
|
19
|
+
`;
|
|
20
|
+
const commonOptions = {
|
|
21
|
+
bundle: true,
|
|
22
|
+
logLevel: 'info',
|
|
23
|
+
banner: {
|
|
24
|
+
js: banner
|
|
25
|
+
},
|
|
26
|
+
define: {
|
|
27
|
+
NODE_ENV: JSON.stringify('production'),
|
|
28
|
+
__DEV__: JSON.stringify(false),
|
|
29
|
+
'process.env.NODE_ENV': JSON.stringify('production')
|
|
30
|
+
},
|
|
31
|
+
keepNames: true,
|
|
32
|
+
treeShaking: true,
|
|
33
|
+
minifySyntax: true,
|
|
34
|
+
format: 'esm',
|
|
35
|
+
platform: 'node',
|
|
36
|
+
charset: 'utf8',
|
|
37
|
+
target: 'node18',
|
|
38
|
+
sourcemap: false,
|
|
39
|
+
legalComments: 'none',
|
|
40
|
+
// External native modules
|
|
41
|
+
external: [
|
|
42
|
+
'better-sqlite3',
|
|
43
|
+
'oracledb',
|
|
44
|
+
'mariadb/callback',
|
|
45
|
+
'mysql'
|
|
46
|
+
]
|
|
47
|
+
};
|
|
48
|
+
// Ensure dist directory exists
|
|
49
|
+
fs.mkdirSync('dist', {
|
|
50
|
+
recursive: true
|
|
51
|
+
});
|
|
52
|
+
console.log('Building MCPS...');
|
|
53
|
+
// Build library entry (index.ts)
|
|
54
|
+
const libResult = await esbuild.build({
|
|
55
|
+
...commonOptions,
|
|
56
|
+
entryPoints: [
|
|
57
|
+
'src/index.ts'
|
|
58
|
+
],
|
|
59
|
+
outfile: 'dist/index.mjs'
|
|
60
|
+
});
|
|
61
|
+
// Build CLI entry (mcps-cli.ts)
|
|
62
|
+
const cliResult = await esbuild.build({
|
|
63
|
+
...commonOptions,
|
|
64
|
+
entryPoints: [
|
|
65
|
+
'src/mcps-cli.ts'
|
|
66
|
+
],
|
|
67
|
+
outfile: 'dist/mcps-cli.mjs'
|
|
68
|
+
});
|
|
69
|
+
if (libResult.errors.length === 0 && cliResult.errors.length === 0) {
|
|
70
|
+
// Process CLI output - add shebang
|
|
71
|
+
const cliOutfile = 'dist/mcps-cli.mjs';
|
|
72
|
+
let content = fs.readFileSync(cliOutfile, 'utf-8');
|
|
73
|
+
content = content.replace(/^#!.*\n/gm, '');
|
|
74
|
+
fs.writeFileSync(cliOutfile, `#!/usr/bin/env node\n${content}`);
|
|
75
|
+
fs.chmodSync(cliOutfile, 493);
|
|
76
|
+
const libStats = fs.statSync('dist/index.mjs');
|
|
77
|
+
const cliStats = fs.statSync(cliOutfile);
|
|
78
|
+
console.log(`✅ Build successful!`);
|
|
79
|
+
console.log(`📦 Library: dist/index.mjs (${(libStats.size / 1024).toFixed(1)}KB)`);
|
|
80
|
+
console.log(`📦 CLI: ${cliOutfile} (${(cliStats.size / 1024).toFixed(1)}KB)`);
|
|
81
|
+
console.log(`🚀 Ready for npm publish and npx usage`);
|
|
82
|
+
} else {
|
|
83
|
+
console.error('❌ Build failed:', [
|
|
84
|
+
...libResult.errors,
|
|
85
|
+
...cliResult.errors
|
|
86
|
+
]);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
//# sourceMappingURL=bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/scripts/bundle.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'node:fs';\nimport * as esbuild from 'esbuild';\n\nconst pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8'));\n\nconst banner = `// Bundled with esbuild\n// ${pkg.name}@${pkg.version}\n\nvar require,__filename,__dirname;\n{\n const {createRequire} = await import('node:module');\n require ||= createRequire(import.meta.url);\n}\n{\n const {fileURLToPath} = await import('node:url');\n const {dirname} = await import('node:path');\n __filename ||= fileURLToPath(import.meta.url);\n __dirname ||= dirname(__filename)\n};\n`;\n\nconst commonOptions: esbuild.BuildOptions = {\n\tbundle: true,\n\tlogLevel: 'info',\n\tbanner: { js: banner },\n\tdefine: {\n\t\tNODE_ENV: JSON.stringify('production'),\n\t\t__DEV__: JSON.stringify(false),\n\t\t'process.env.NODE_ENV': JSON.stringify('production'),\n\t},\n\tkeepNames: true,\n\ttreeShaking: true,\n\tminifySyntax: true,\n\tformat: 'esm',\n\tplatform: 'node',\n\tcharset: 'utf8',\n\ttarget: 'node18',\n\tsourcemap: false,\n\tlegalComments: 'none',\n\t// External native modules\n\texternal: ['better-sqlite3', 'oracledb', 'mariadb/callback', 'mysql'],\n};\n\n// Ensure dist directory exists\nfs.mkdirSync('dist', { recursive: true });\n\nconsole.log('Building MCPS...');\n\n// Build library entry (index.ts)\nconst libResult = await esbuild.build({\n\t...commonOptions,\n\tentryPoints: ['src/index.ts'],\n\toutfile: 'dist/index.mjs',\n});\n\n// Build CLI entry (mcps-cli.ts)\nconst cliResult = await esbuild.build({\n\t...commonOptions,\n\tentryPoints: ['src/mcps-cli.ts'],\n\toutfile: 'dist/mcps-cli.mjs',\n});\n\nif (libResult.errors.length === 0 && cliResult.errors.length === 0) {\n\t// Process CLI output - add shebang\n\tconst cliOutfile = 'dist/mcps-cli.mjs';\n\tlet content = fs.readFileSync(cliOutfile, 'utf-8');\n\tcontent = content.replace(/^#!.*\\n/gm, '');\n\tfs.writeFileSync(cliOutfile, `#!/usr/bin/env node\\n${content}`);\n\tfs.chmodSync(cliOutfile, 0o755);\n\n\tconst libStats = fs.statSync('dist/index.mjs');\n\tconst cliStats = fs.statSync(cliOutfile);\n\n\tconsole.log(`✅ Build successful!`);\n\tconsole.log(`📦 Library: dist/index.mjs (${(libStats.size / 1024).toFixed(1)}KB)`);\n\tconsole.log(`📦 CLI: ${cliOutfile} (${(cliStats.size / 1024).toFixed(1)}KB)`);\n\tconsole.log(`🚀 Ready for npm publish and npx usage`);\n} else {\n\tconsole.error('❌ Build failed:', [...libResult.errors, ...cliResult.errors]);\n\tprocess.exit(1);\n}\n"],"names":["fs","esbuild","pkg","JSON","parse","readFileSync","banner","name","version","commonOptions","bundle","logLevel","js","define","NODE_ENV","stringify","__DEV__","keepNames","treeShaking","minifySyntax","format","platform","charset","target","sourcemap","legalComments","external","mkdirSync","recursive","console","log","libResult","build","entryPoints","outfile","cliResult","errors","length","cliOutfile","content","replace","writeFileSync","chmodSync","libStats","statSync","cliStats","size","toFixed","error","process","exit"],"mappings":";AACA,OAAOA,QAAQ,UAAU;AACzB,YAAYC,aAAa,UAAU;AAEnC,MAAMC,MAAMC,KAAKC,KAAK,CAACJ,GAAGK,YAAY,CAAC,gBAAgB;AAEvD,MAAMC,SAAS,CAAC;GACb,EAAEJ,IAAIK,IAAI,CAAC,CAAC,EAAEL,IAAIM,OAAO,CAAC;;;;;;;;;;;;;AAa7B,CAAC;AAED,MAAMC,gBAAsC;IAC3CC,QAAQ;IACRC,UAAU;IACVL,QAAQ;QAAEM,IAAIN;IAAO;IACrBO,QAAQ;QACPC,UAAUX,KAAKY,SAAS,CAAC;QACzBC,SAASb,KAAKY,SAAS,CAAC;QACxB,wBAAwBZ,KAAKY,SAAS,CAAC;IACxC;IACAE,WAAW;IACXC,aAAa;IACbC,cAAc;IACdC,QAAQ;IACRC,UAAU;IACVC,SAAS;IACTC,QAAQ;IACRC,WAAW;IACXC,eAAe;IACf,0BAA0B;IAC1BC,UAAU;QAAC;QAAkB;QAAY;QAAoB;KAAQ;AACtE;AAEA,+BAA+B;AAC/B1B,GAAG2B,SAAS,CAAC,QAAQ;IAAEC,WAAW;AAAK;AAEvCC,QAAQC,GAAG,CAAC;AAEZ,iCAAiC;AACjC,MAAMC,YAAY,MAAM9B,QAAQ+B,KAAK,CAAC;IACrC,GAAGvB,aAAa;IAChBwB,aAAa;QAAC;KAAe;IAC7BC,SAAS;AACV;AAEA,gCAAgC;AAChC,MAAMC,YAAY,MAAMlC,QAAQ+B,KAAK,CAAC;IACrC,GAAGvB,aAAa;IAChBwB,aAAa;QAAC;KAAkB;IAChCC,SAAS;AACV;AAEA,IAAIH,UAAUK,MAAM,CAACC,MAAM,KAAK,KAAKF,UAAUC,MAAM,CAACC,MAAM,KAAK,GAAG;IACnE,mCAAmC;IACnC,MAAMC,aAAa;IACnB,IAAIC,UAAUvC,GAAGK,YAAY,CAACiC,YAAY;IAC1CC,UAAUA,QAAQC,OAAO,CAAC,aAAa;IACvCxC,GAAGyC,aAAa,CAACH,YAAY,CAAC,qBAAqB,EAAEC,SAAS;IAC9DvC,GAAG0C,SAAS,CAACJ,YAAY;IAEzB,MAAMK,WAAW3C,GAAG4C,QAAQ,CAAC;IAC7B,MAAMC,WAAW7C,GAAG4C,QAAQ,CAACN;IAE7BT,QAAQC,GAAG,CAAC,CAAC,mBAAmB,CAAC;IACjCD,QAAQC,GAAG,CAAC,CAAC,4BAA4B,EAAE,AAACa,CAAAA,SAASG,IAAI,GAAG,IAAG,EAAGC,OAAO,CAAC,GAAG,GAAG,CAAC;IACjFlB,QAAQC,GAAG,CAAC,CAAC,QAAQ,EAAEQ,WAAW,EAAE,EAAE,AAACO,CAAAA,SAASC,IAAI,GAAG,IAAG,EAAGC,OAAO,CAAC,GAAG,GAAG,CAAC;IAC5ElB,QAAQC,GAAG,CAAC,CAAC,sCAAsC,CAAC;AACrD,OAAO;IACND,QAAQmB,KAAK,CAAC,mBAAmB;WAAIjB,UAAUK,MAAM;WAAKD,UAAUC,MAAM;KAAC;IAC3Ea,QAAQC,IAAI,CAAC;AACd"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { SmartCoercionPlugin } from "@orpc/json-schema";
|
|
2
|
+
import { OpenAPIGenerator } from "@orpc/openapi";
|
|
3
|
+
import { OpenAPIHandler } from "@orpc/openapi/fetch";
|
|
4
|
+
import { RPCHandler } from "@orpc/server/fetch";
|
|
5
|
+
import { CORSPlugin } from "@orpc/server/plugins";
|
|
6
|
+
import { ZodToJsonSchemaConverter } from "@orpc/zod/zod4";
|
|
7
|
+
import { html } from "hono/html";
|
|
8
|
+
import { AuditRouter } from "./audit.js";
|
|
9
|
+
import { createMcpsRouter } from "./mcps-router.js";
|
|
10
|
+
/**
|
|
11
|
+
* Register oRPC API routes for audit and MCPS
|
|
12
|
+
*/ export function registerApiRoutes({ app, config }) {
|
|
13
|
+
// Create MCPS router with config context
|
|
14
|
+
const McpsRouter = createMcpsRouter({
|
|
15
|
+
config
|
|
16
|
+
});
|
|
17
|
+
// Combined router for all APIs
|
|
18
|
+
const combinedRouter = {
|
|
19
|
+
audit: AuditRouter,
|
|
20
|
+
mcps: McpsRouter
|
|
21
|
+
};
|
|
22
|
+
const handleByRpc = new RPCHandler(combinedRouter);
|
|
23
|
+
const handleByOpenAPI = new OpenAPIHandler(combinedRouter, {
|
|
24
|
+
plugins: [
|
|
25
|
+
new SmartCoercionPlugin({
|
|
26
|
+
schemaConverters: [
|
|
27
|
+
new ZodToJsonSchemaConverter()
|
|
28
|
+
]
|
|
29
|
+
}),
|
|
30
|
+
new CORSPlugin({
|
|
31
|
+
exposeHeaders: [
|
|
32
|
+
"Content-Disposition"
|
|
33
|
+
]
|
|
34
|
+
})
|
|
35
|
+
]
|
|
36
|
+
});
|
|
37
|
+
app.use("/api/rpc/*", async (c, next) => {
|
|
38
|
+
const { matched, response } = await handleByRpc.handle(c.req.raw, {
|
|
39
|
+
prefix: "/api/rpc",
|
|
40
|
+
context: {}
|
|
41
|
+
});
|
|
42
|
+
if (matched) {
|
|
43
|
+
return c.newResponse(response.body, response);
|
|
44
|
+
}
|
|
45
|
+
return next();
|
|
46
|
+
});
|
|
47
|
+
app.use("/api/*", async (c, next) => {
|
|
48
|
+
const { matched, response } = await handleByOpenAPI.handle(c.req.raw, {
|
|
49
|
+
prefix: "/api",
|
|
50
|
+
context: {}
|
|
51
|
+
});
|
|
52
|
+
if (matched) {
|
|
53
|
+
return c.newResponse(response.body, response);
|
|
54
|
+
}
|
|
55
|
+
return next();
|
|
56
|
+
});
|
|
57
|
+
// OpenAPI spec
|
|
58
|
+
const openAPIGenerator = new OpenAPIGenerator({
|
|
59
|
+
schemaConverters: [
|
|
60
|
+
new ZodToJsonSchemaConverter()
|
|
61
|
+
]
|
|
62
|
+
});
|
|
63
|
+
let specCache;
|
|
64
|
+
app.get("/api/spec.json", async (c) => {
|
|
65
|
+
if (!specCache) {
|
|
66
|
+
specCache = await openAPIGenerator.generate(combinedRouter, {
|
|
67
|
+
info: {
|
|
68
|
+
title: "MCPS API",
|
|
69
|
+
version: "1.0.0"
|
|
70
|
+
},
|
|
71
|
+
servers: [
|
|
72
|
+
{
|
|
73
|
+
url: "/api"
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return c.json(specCache);
|
|
79
|
+
});
|
|
80
|
+
// Swagger UI
|
|
81
|
+
app.get("/api/docs", (c) => {
|
|
82
|
+
return c.html(html `<!doctype html>
|
|
83
|
+
<html lang="en">
|
|
84
|
+
<head>
|
|
85
|
+
<title>MCPS API</title>
|
|
86
|
+
<meta charset="utf-8" />
|
|
87
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
88
|
+
</head>
|
|
89
|
+
<body>
|
|
90
|
+
<script id="api-reference" data-url="/api/spec.json"></script>
|
|
91
|
+
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
|
92
|
+
</body>
|
|
93
|
+
</html>`);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=api-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/server/api-routes.ts"],"sourcesContent":["import { SmartCoercionPlugin } from '@orpc/json-schema';\nimport { OpenAPIGenerator } from '@orpc/openapi';\nimport { OpenAPIHandler } from '@orpc/openapi/fetch';\nimport { RPCHandler } from '@orpc/server/fetch';\nimport { CORSPlugin } from '@orpc/server/plugins';\nimport { ZodToJsonSchemaConverter } from '@orpc/zod/zod4';\nimport type { Hono } from 'hono';\nimport { html } from 'hono/html';\nimport { AuditRouter } from './audit';\nimport { createMcpsRouter } from './mcps-router';\nimport type { McpsConfig } from './schema';\n\nexport interface RegisterApiRoutesOptions {\n\tapp: Hono;\n\tconfig: McpsConfig;\n}\n\n/**\n * Register oRPC API routes for audit and MCPS\n */\nexport function registerApiRoutes({ app, config }: RegisterApiRoutesOptions) {\n\t// Create MCPS router with config context\n\tconst McpsRouter = createMcpsRouter({ config });\n\n\t// Combined router for all APIs\n\tconst combinedRouter = {\n\t\taudit: AuditRouter,\n\t\tmcps: McpsRouter,\n\t};\n\n\tconst handleByRpc = new RPCHandler(combinedRouter);\n\tconst handleByOpenAPI = new OpenAPIHandler(combinedRouter, {\n\t\tplugins: [\n\t\t\tnew SmartCoercionPlugin({\n\t\t\t\tschemaConverters: [new ZodToJsonSchemaConverter()],\n\t\t\t}),\n\t\t\tnew CORSPlugin({\n\t\t\t\texposeHeaders: ['Content-Disposition'],\n\t\t\t}),\n\t\t],\n\t});\n\n\tapp.use('/api/rpc/*', async (c, next) => {\n\t\tconst { matched, response } = await handleByRpc.handle(c.req.raw, {\n\t\t\tprefix: '/api/rpc',\n\t\t\tcontext: {},\n\t\t});\n\t\tif (matched) {\n\t\t\treturn c.newResponse(response.body, response);\n\t\t}\n\t\treturn next();\n\t});\n\n\tapp.use('/api/*', async (c, next) => {\n\t\tconst { matched, response } = await handleByOpenAPI.handle(c.req.raw, {\n\t\t\tprefix: '/api',\n\t\t\tcontext: {},\n\t\t});\n\t\tif (matched) {\n\t\t\treturn c.newResponse(response.body, response);\n\t\t}\n\t\treturn next();\n\t});\n\n\t// OpenAPI spec\n\tconst openAPIGenerator = new OpenAPIGenerator({\n\t\tschemaConverters: [new ZodToJsonSchemaConverter()],\n\t});\n\tlet specCache: unknown;\n\n\tapp.get('/api/spec.json', async (c) => {\n\t\tif (!specCache) {\n\t\t\tspecCache = await openAPIGenerator.generate(combinedRouter, {\n\t\t\t\tinfo: { title: 'MCPS API', version: '1.0.0' },\n\t\t\t\tservers: [{ url: '/api' }],\n\t\t\t});\n\t\t}\n\t\treturn c.json(specCache);\n\t});\n\n\t// Swagger UI\n\tapp.get('/api/docs', (c) => {\n\t\treturn c.html(\n\t\t\thtml`<!doctype html>\n\t\t\t\t<html lang=\"en\">\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<title>MCPS API</title>\n\t\t\t\t\t\t<meta charset=\"utf-8\" />\n\t\t\t\t\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\t\t\t\t\t</head>\n\t\t\t\t\t<body>\n\t\t\t\t\t\t<script id=\"api-reference\" data-url=\"/api/spec.json\"></script>\n\t\t\t\t\t\t<script src=\"https://cdn.jsdelivr.net/npm/@scalar/api-reference\"></script>\n\t\t\t\t\t</body>\n\t\t\t\t</html>`,\n\t\t);\n\t});\n}\n"],"names":["SmartCoercionPlugin","OpenAPIGenerator","OpenAPIHandler","RPCHandler","CORSPlugin","ZodToJsonSchemaConverter","html","AuditRouter","createMcpsRouter","registerApiRoutes","app","config","McpsRouter","combinedRouter","audit","mcps","handleByRpc","handleByOpenAPI","plugins","schemaConverters","exposeHeaders","use","c","next","matched","response","handle","req","raw","prefix","context","newResponse","body","openAPIGenerator","specCache","get","generate","info","title","version","servers","url","json"],"mappings":"AAAA,SAASA,mBAAmB,QAAQ,oBAAoB;AACxD,SAASC,gBAAgB,QAAQ,gBAAgB;AACjD,SAASC,cAAc,QAAQ,sBAAsB;AACrD,SAASC,UAAU,QAAQ,qBAAqB;AAChD,SAASC,UAAU,QAAQ,uBAAuB;AAClD,SAASC,wBAAwB,QAAQ,iBAAiB;AAE1D,SAASC,IAAI,QAAQ,YAAY;AACjC,SAASC,WAAW,QAAQ,UAAU;AACtC,SAASC,gBAAgB,QAAQ,gBAAgB;AAQjD;;CAEC,GACD,OAAO,SAASC,kBAAkB,EAAEC,GAAG,EAAEC,MAAM,EAA4B;IAC1E,yCAAyC;IACzC,MAAMC,aAAaJ,iBAAiB;QAAEG;IAAO;IAE7C,+BAA+B;IAC/B,MAAME,iBAAiB;QACtBC,OAAOP;QACPQ,MAAMH;IACP;IAEA,MAAMI,cAAc,IAAIb,WAAWU;IACnC,MAAMI,kBAAkB,IAAIf,eAAeW,gBAAgB;QAC1DK,SAAS;YACR,IAAIlB,oBAAoB;gBACvBmB,kBAAkB;oBAAC,IAAId;iBAA2B;YACnD;YACA,IAAID,WAAW;gBACdgB,eAAe;oBAAC;iBAAsB;YACvC;SACA;IACF;IAEAV,IAAIW,GAAG,CAAC,cAAc,OAAOC,GAAGC;QAC/B,MAAM,EAAEC,OAAO,EAAEC,QAAQ,EAAE,GAAG,MAAMT,YAAYU,MAAM,CAACJ,EAAEK,GAAG,CAACC,GAAG,EAAE;YACjEC,QAAQ;YACRC,SAAS,CAAC;QACX;QACA,IAAIN,SAAS;YACZ,OAAOF,EAAES,WAAW,CAACN,SAASO,IAAI,EAAEP;QACrC;QACA,OAAOF;IACR;IAEAb,IAAIW,GAAG,CAAC,UAAU,OAAOC,GAAGC;QAC3B,MAAM,EAAEC,OAAO,EAAEC,QAAQ,EAAE,GAAG,MAAMR,gBAAgBS,MAAM,CAACJ,EAAEK,GAAG,CAACC,GAAG,EAAE;YACrEC,QAAQ;YACRC,SAAS,CAAC;QACX;QACA,IAAIN,SAAS;YACZ,OAAOF,EAAES,WAAW,CAACN,SAASO,IAAI,EAAEP;QACrC;QACA,OAAOF;IACR;IAEA,eAAe;IACf,MAAMU,mBAAmB,IAAIhC,iBAAiB;QAC7CkB,kBAAkB;YAAC,IAAId;SAA2B;IACnD;IACA,IAAI6B;IAEJxB,IAAIyB,GAAG,CAAC,kBAAkB,OAAOb;QAChC,IAAI,CAACY,WAAW;YACfA,YAAY,MAAMD,iBAAiBG,QAAQ,CAACvB,gBAAgB;gBAC3DwB,MAAM;oBAAEC,OAAO;oBAAYC,SAAS;gBAAQ;gBAC5CC,SAAS;oBAAC;wBAAEC,KAAK;oBAAO;iBAAE;YAC3B;QACD;QACA,OAAOnB,EAAEoB,IAAI,CAACR;IACf;IAEA,aAAa;IACbxB,IAAIyB,GAAG,CAAC,aAAa,CAACb;QACrB,OAAOA,EAAEhB,IAAI,CACZA,IAAI,CAAC;;;;;;;;;;;WAWG,CAAC;IAEX;AACD"}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { implement } from "@orpc/server";
|
|
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) {
|
|
9
|
+
const record = {};
|
|
10
|
+
headers.forEach((value, key) => {
|
|
11
|
+
record[key] = value;
|
|
12
|
+
});
|
|
13
|
+
return record;
|
|
14
|
+
}
|
|
15
|
+
// In-memory audit store using LRU cache
|
|
16
|
+
const auditStore = new LRUCache({
|
|
17
|
+
max: 10000,
|
|
18
|
+
ttl: 1000 * 60 * 60 * 24
|
|
19
|
+
});
|
|
20
|
+
// Counter for IDs
|
|
21
|
+
let eventCounter = 0;
|
|
22
|
+
// Audit configuration state
|
|
23
|
+
let auditEnabled = true; // default to enabled
|
|
24
|
+
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) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
// Lazy initialize DB on first persist
|
|
54
|
+
const orm = await ensureDbInitialized();
|
|
55
|
+
const em = orm.em.fork();
|
|
56
|
+
const logEntry = new RequestLogEntity();
|
|
57
|
+
logEntry.requestId = id;
|
|
58
|
+
logEntry.timestamp = new Date(event.timestamp);
|
|
59
|
+
logEntry.method = event.method;
|
|
60
|
+
logEntry.path = event.path;
|
|
61
|
+
logEntry.serverName = event.serverName ?? undefined;
|
|
62
|
+
logEntry.serverType = event.serverType ?? undefined;
|
|
63
|
+
logEntry.status = event.status ?? undefined;
|
|
64
|
+
logEntry.durationMs = event.durationMs ?? undefined;
|
|
65
|
+
logEntry.error = event.error ?? undefined;
|
|
66
|
+
logEntry.requestHeaders = event.requestHeaders ?? undefined;
|
|
67
|
+
// Determine request type
|
|
68
|
+
if (event.path.startsWith("/mcp/")) {
|
|
69
|
+
logEntry.requestType = "mcp";
|
|
70
|
+
}
|
|
71
|
+
else if (event.path.startsWith("/v1/")) {
|
|
72
|
+
logEntry.requestType = "chat";
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
logEntry.requestType = "api";
|
|
76
|
+
}
|
|
77
|
+
em.persist(logEntry);
|
|
78
|
+
await em.flush();
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
// Log persistence errors but don't throw - in-memory store is the primary
|
|
82
|
+
console.error("Failed to persist audit log:", e);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Add an audit event
|
|
87
|
+
*/ export function addAuditEvent(event) {
|
|
88
|
+
const id = `${Date.now()}-${++eventCounter}`;
|
|
89
|
+
const fullEvent = {
|
|
90
|
+
...event,
|
|
91
|
+
id
|
|
92
|
+
};
|
|
93
|
+
auditStore.set(id, fullEvent);
|
|
94
|
+
// Persist to database asynchronously (lazy init)
|
|
95
|
+
persistToDb(fullEvent, id).catch(() => {
|
|
96
|
+
// Already logged in persistToDb
|
|
97
|
+
});
|
|
98
|
+
return fullEvent;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Query audit events
|
|
102
|
+
*/ export function queryAuditEvents(options) {
|
|
103
|
+
const { limit = 50, offset = 0, serverName, serverType, method, from, to } = options;
|
|
104
|
+
// Get all events as array
|
|
105
|
+
let events = [];
|
|
106
|
+
for (const [, event] of auditStore.entries()) {
|
|
107
|
+
events.push(event);
|
|
108
|
+
}
|
|
109
|
+
// Sort by timestamp desc
|
|
110
|
+
events.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
111
|
+
// Apply filters
|
|
112
|
+
if (serverName) {
|
|
113
|
+
events = events.filter((e) => e.serverName === serverName);
|
|
114
|
+
}
|
|
115
|
+
if (serverType) {
|
|
116
|
+
events = events.filter((e) => e.serverType === serverType);
|
|
117
|
+
}
|
|
118
|
+
if (method) {
|
|
119
|
+
events = events.filter((e) => e.method === method);
|
|
120
|
+
}
|
|
121
|
+
if (from) {
|
|
122
|
+
const fromTime = new Date(from).getTime();
|
|
123
|
+
events = events.filter((e) => new Date(e.timestamp).getTime() >= fromTime);
|
|
124
|
+
}
|
|
125
|
+
if (to) {
|
|
126
|
+
const toTime = new Date(to).getTime();
|
|
127
|
+
events = events.filter((e) => new Date(e.timestamp).getTime() <= toTime);
|
|
128
|
+
}
|
|
129
|
+
const total = events.length;
|
|
130
|
+
// Paginate
|
|
131
|
+
events = events.slice(offset, offset + limit);
|
|
132
|
+
return {
|
|
133
|
+
events,
|
|
134
|
+
total
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get audit statistics
|
|
139
|
+
*/ export function getAuditStats(options) {
|
|
140
|
+
let events = [];
|
|
141
|
+
for (const [, event] of auditStore.entries()) {
|
|
142
|
+
events.push(event);
|
|
143
|
+
}
|
|
144
|
+
// Apply time filters
|
|
145
|
+
if (options.from) {
|
|
146
|
+
const fromTime = new Date(options.from).getTime();
|
|
147
|
+
events = events.filter((e) => new Date(e.timestamp).getTime() >= fromTime);
|
|
148
|
+
}
|
|
149
|
+
if (options.to) {
|
|
150
|
+
const toTime = new Date(options.to).getTime();
|
|
151
|
+
events = events.filter((e) => new Date(e.timestamp).getTime() <= toTime);
|
|
152
|
+
}
|
|
153
|
+
// Calculate stats
|
|
154
|
+
const totalRequests = events.length;
|
|
155
|
+
const totalErrors = events.filter((e) => e.error || e.status && e.status >= 400).length;
|
|
156
|
+
const durations = events.map((e) => e.durationMs).filter((d) => d != null);
|
|
157
|
+
const avgDurationMs = durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0;
|
|
158
|
+
// Group by server
|
|
159
|
+
const serverCounts = new Map();
|
|
160
|
+
for (const event of events) {
|
|
161
|
+
const name = event.serverName || "unknown";
|
|
162
|
+
serverCounts.set(name, (serverCounts.get(name) || 0) + 1);
|
|
163
|
+
}
|
|
164
|
+
const byServer = Array.from(serverCounts.entries()).map(([name, count]) => ({
|
|
165
|
+
name,
|
|
166
|
+
count
|
|
167
|
+
})).sort((a, b) => b.count - a.count);
|
|
168
|
+
// Group by method
|
|
169
|
+
const methodCounts = new Map();
|
|
170
|
+
for (const event of events) {
|
|
171
|
+
const method = event.method || "unknown";
|
|
172
|
+
methodCounts.set(method, (methodCounts.get(method) || 0) + 1);
|
|
173
|
+
}
|
|
174
|
+
const byMethod = Array.from(methodCounts.entries()).map(([method, count]) => ({
|
|
175
|
+
method,
|
|
176
|
+
count
|
|
177
|
+
})).sort((a, b) => b.count - a.count);
|
|
178
|
+
return {
|
|
179
|
+
totalRequests,
|
|
180
|
+
totalErrors,
|
|
181
|
+
avgDurationMs,
|
|
182
|
+
byServer,
|
|
183
|
+
byMethod
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Clear audit events before a timestamp
|
|
188
|
+
*/ export function clearAuditEvents(before) {
|
|
189
|
+
const beforeTime = new Date(before).getTime();
|
|
190
|
+
let deleted = 0;
|
|
191
|
+
for (const [id, event] of auditStore.entries()) {
|
|
192
|
+
if (new Date(event.timestamp).getTime() < beforeTime) {
|
|
193
|
+
auditStore.delete(id);
|
|
194
|
+
deleted++;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return deleted;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Audit Router implementation
|
|
201
|
+
*/ export const AuditRouter = implement(AuditContract).router({
|
|
202
|
+
list: implement(AuditContract.list).handler(async ({ input }) => {
|
|
203
|
+
return queryAuditEvents(input);
|
|
204
|
+
}),
|
|
205
|
+
get: implement(AuditContract.get).handler(async ({ input }) => {
|
|
206
|
+
return auditStore.get(input.id) ?? null;
|
|
207
|
+
}),
|
|
208
|
+
stats: implement(AuditContract.stats).handler(async ({ input }) => {
|
|
209
|
+
return getAuditStats(input);
|
|
210
|
+
}),
|
|
211
|
+
clear: implement(AuditContract.clear).handler(async ({ input }) => {
|
|
212
|
+
const deleted = clearAuditEvents(input.before);
|
|
213
|
+
return {
|
|
214
|
+
deleted
|
|
215
|
+
};
|
|
216
|
+
})
|
|
217
|
+
});
|
|
218
|
+
/**
|
|
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;
|
|
253
|
+
}
|
|
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
|
+
}
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/server/audit.ts"],"sourcesContent":["import { implement } from '@orpc/server';\nimport type { Context, Next } from 'hono';\nimport { LRUCache } from 'lru-cache';\nimport { AuditContract, type AuditEvent } from '../contracts';\nimport { RequestLogEntity } from '../entities';\nimport { ensureDbInitialized, configureDb } from './db';\nimport type { AuditConfig, DbConfig } from './schema';\n\n/**\n * Convert Headers to a plain record\n */\nfunction headersToRecord(headers: Headers): Record<string, string> {\n\tconst record: Record<string, string> = {};\n\theaders.forEach((value, key) => {\n\t\trecord[key] = value;\n\t});\n\treturn record;\n}\n\n// In-memory audit store using LRU cache\nconst auditStore = new LRUCache<string, AuditEvent>({\n\tmax: 10000, // Keep last 10k events\n\tttl: 1000 * 60 * 60 * 24, // 24 hours\n});\n\n// Counter for IDs\nlet eventCounter = 0;\n\n// Audit configuration state\nlet auditEnabled = true; // default to enabled\nlet dbConfigured = false;\n\n/**\n * Configure audit module with settings\n * Call this before using audit features\n *\n * @param auditConfig - Audit config section\n * @param fallbackDbConfig - Fallback db config from root config\n */\nexport function configureAudit(auditConfig?: AuditConfig, fallbackDbConfig?: DbConfig): void {\n\t// Determine if audit is enabled (default: true)\n\tauditEnabled = auditConfig?.enabled !== false;\n\n\tif (auditEnabled) {\n\t\t// Use audit.db config if present, otherwise fallback to root db config\n\t\tconst dbConfig = auditConfig?.db ?? fallbackDbConfig;\n\t\tconfigureDb(dbConfig);\n\t\tdbConfigured = true;\n\t}\n}\n\n/**\n * Check if audit is enabled\n */\nexport function isAuditEnabled(): boolean {\n\treturn auditEnabled;\n}\n\n/**\n * Persist audit event to database (lazy init)\n */\nasync function persistToDb(event: AuditEvent, id: string): Promise<void> {\n\tif (!auditEnabled || !dbConfigured) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\t// Lazy initialize DB on first persist\n\t\tconst orm = await ensureDbInitialized();\n\t\tconst em = orm.em.fork();\n\n\t\tconst logEntry = new RequestLogEntity();\n\t\tlogEntry.requestId = id;\n\t\tlogEntry.timestamp = new Date(event.timestamp);\n\t\tlogEntry.method = event.method;\n\t\tlogEntry.path = event.path;\n\t\tlogEntry.serverName = event.serverName ?? undefined;\n\t\tlogEntry.serverType = event.serverType ?? undefined;\n\t\tlogEntry.status = event.status ?? undefined;\n\t\tlogEntry.durationMs = event.durationMs ?? undefined;\n\t\tlogEntry.error = event.error ?? undefined;\n\t\tlogEntry.requestHeaders = event.requestHeaders ?? undefined;\n\t\t// Determine request type\n\t\tif (event.path.startsWith('/mcp/')) {\n\t\t\tlogEntry.requestType = 'mcp';\n\t\t} else if (event.path.startsWith('/v1/')) {\n\t\t\tlogEntry.requestType = 'chat';\n\t\t} else {\n\t\t\tlogEntry.requestType = 'api';\n\t\t}\n\t\tem.persist(logEntry);\n\t\tawait em.flush();\n\t} catch (e) {\n\t\t// Log persistence errors but don't throw - in-memory store is the primary\n\t\tconsole.error('Failed to persist audit log:', e);\n\t}\n}\n\n/**\n * Add an audit event\n */\nexport function addAuditEvent(event: Omit<AuditEvent, 'id'>): AuditEvent {\n\tconst id = `${Date.now()}-${++eventCounter}`;\n\tconst fullEvent: AuditEvent = { ...event, id };\n\tauditStore.set(id, fullEvent);\n\n\t// Persist to database asynchronously (lazy init)\n\tpersistToDb(fullEvent, id).catch(() => {\n\t\t// Already logged in persistToDb\n\t});\n\n\treturn fullEvent;\n}\n\n/**\n * Query audit events\n */\nexport function queryAuditEvents(options: {\n\tlimit?: number;\n\toffset?: number;\n\tserverName?: string | null;\n\tserverType?: string | null;\n\tmethod?: string | null;\n\tfrom?: string | null;\n\tto?: string | null;\n}): { events: AuditEvent[]; total: number } {\n\tconst { limit = 50, offset = 0, serverName, serverType, method, from, to } = options;\n\n\t// Get all events as array\n\tlet events: AuditEvent[] = [];\n\tfor (const [, event] of auditStore.entries()) {\n\t\tevents.push(event);\n\t}\n\n\t// Sort by timestamp desc\n\tevents.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());\n\n\t// Apply filters\n\tif (serverName) {\n\t\tevents = events.filter((e) => e.serverName === serverName);\n\t}\n\tif (serverType) {\n\t\tevents = events.filter((e) => e.serverType === serverType);\n\t}\n\tif (method) {\n\t\tevents = events.filter((e) => e.method === method);\n\t}\n\tif (from) {\n\t\tconst fromTime = new Date(from).getTime();\n\t\tevents = events.filter((e) => new Date(e.timestamp).getTime() >= fromTime);\n\t}\n\tif (to) {\n\t\tconst toTime = new Date(to).getTime();\n\t\tevents = events.filter((e) => new Date(e.timestamp).getTime() <= toTime);\n\t}\n\n\tconst total = events.length;\n\n\t// Paginate\n\tevents = events.slice(offset, offset + limit);\n\n\treturn { events, total };\n}\n\n/**\n * Get audit statistics\n */\nexport function getAuditStats(options: { from?: string | null; to?: string | null }) {\n\tlet events: AuditEvent[] = [];\n\tfor (const [, event] of auditStore.entries()) {\n\t\tevents.push(event);\n\t}\n\n\t// Apply time filters\n\tif (options.from) {\n\t\tconst fromTime = new Date(options.from).getTime();\n\t\tevents = events.filter((e) => new Date(e.timestamp).getTime() >= fromTime);\n\t}\n\tif (options.to) {\n\t\tconst toTime = new Date(options.to).getTime();\n\t\tevents = events.filter((e) => new Date(e.timestamp).getTime() <= toTime);\n\t}\n\n\t// Calculate stats\n\tconst totalRequests = events.length;\n\tconst totalErrors = events.filter((e) => e.error || (e.status && e.status >= 400)).length;\n\n\tconst durations = events.map((e) => e.durationMs).filter((d): d is number => d != null);\n\tconst avgDurationMs = durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0;\n\n\t// Group by server\n\tconst serverCounts = new Map<string, number>();\n\tfor (const event of events) {\n\t\tconst name = event.serverName || 'unknown';\n\t\tserverCounts.set(name, (serverCounts.get(name) || 0) + 1);\n\t}\n\tconst byServer = Array.from(serverCounts.entries())\n\t\t.map(([name, count]) => ({ name, count }))\n\t\t.sort((a, b) => b.count - a.count);\n\n\t// Group by method\n\tconst methodCounts = new Map<string, number>();\n\tfor (const event of events) {\n\t\tconst method = event.method || 'unknown';\n\t\tmethodCounts.set(method, (methodCounts.get(method) || 0) + 1);\n\t}\n\tconst byMethod = Array.from(methodCounts.entries())\n\t\t.map(([method, count]) => ({ method, count }))\n\t\t.sort((a, b) => b.count - a.count);\n\n\treturn { totalRequests, totalErrors, avgDurationMs, byServer, byMethod };\n}\n\n/**\n * Clear audit events before a timestamp\n */\nexport function clearAuditEvents(before: string): number {\n\tconst beforeTime = new Date(before).getTime();\n\tlet deleted = 0;\n\n\tfor (const [id, event] of auditStore.entries()) {\n\t\tif (new Date(event.timestamp).getTime() < beforeTime) {\n\t\t\tauditStore.delete(id);\n\t\t\tdeleted++;\n\t\t}\n\t}\n\n\treturn deleted;\n}\n\n/**\n * Audit Router implementation\n */\nexport const AuditRouter = implement(AuditContract).router({\n\tlist: implement(AuditContract.list).handler(async ({ input }) => {\n\t\treturn queryAuditEvents(input);\n\t}),\n\n\tget: implement(AuditContract.get).handler(async ({ input }) => {\n\t\treturn auditStore.get(input.id) ?? null;\n\t}),\n\n\tstats: implement(AuditContract.stats).handler(async ({ input }) => {\n\t\treturn getAuditStats(input);\n\t}),\n\n\tclear: implement(AuditContract.clear).handler(async ({ input }) => {\n\t\tconst deleted = clearAuditEvents(input.before);\n\t\treturn { deleted };\n\t}),\n});\n\n/**\n * Hono middleware for audit logging\n */\nexport function auditMiddleware() {\n\treturn async (c: Context, next: Next) => {\n\t\tconst startTime = Date.now();\n\t\tconst path = c.req.path;\n\n\t\t// Extract server info from path\n\t\tlet serverName: string | undefined;\n\t\tlet serverType: string | undefined;\n\n\t\tconst mcpMatch = path.match(/^\\/mcp\\/([^/]+)/);\n\t\tif (mcpMatch) {\n\t\t\tserverName = mcpMatch[1];\n\t\t\t// Infer type from well-known paths\n\t\t\tif (serverName === 'tencent-cls') serverType = 'tencent-cls';\n\t\t\telse if (serverName === 'sql') serverType = 'sql';\n\t\t\telse if (serverName === 'prometheus') serverType = 'prometheus';\n\t\t\telse if (serverName === 'relay') serverType = 'relay';\n\t\t\telse serverType = 'custom';\n\t\t}\n\n\t\t// Extract model info from chat requests\n\t\tif (path.startsWith('/v1/')) {\n\t\t\tserverType = 'chat';\n\t\t}\n\n\t\tlet error: string | undefined;\n\n\t\ttry {\n\t\t\tawait next();\n\t\t} catch (e) {\n\t\t\terror = e instanceof Error ? e.message : String(e);\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tconst durationMs = Date.now() - startTime;\n\n\t\t\t// Audit MCP requests, Chat API requests, and other API requests\n\t\t\tconst shouldAudit =\n\t\t\t\tpath.startsWith('/mcp/') || path.startsWith('/v1/') || (path.startsWith('/api/') && c.req.method !== 'GET');\n\n\t\t\tif (shouldAudit) {\n\t\t\t\taddAuditEvent({\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tmethod: c.req.method,\n\t\t\t\t\tpath,\n\t\t\t\t\tserverName,\n\t\t\t\t\tserverType,\n\t\t\t\t\tstatus: c.res.status,\n\t\t\t\t\tdurationMs,\n\t\t\t\t\terror,\n\t\t\t\t\trequestHeaders: headersToRecord(c.req.raw.headers),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t};\n}\n"],"names":["implement","LRUCache","AuditContract","RequestLogEntity","ensureDbInitialized","configureDb","headersToRecord","headers","record","forEach","value","key","auditStore","max","ttl","eventCounter","auditEnabled","dbConfigured","configureAudit","auditConfig","fallbackDbConfig","enabled","dbConfig","db","isAuditEnabled","persistToDb","event","id","orm","em","fork","logEntry","requestId","timestamp","Date","method","path","serverName","undefined","serverType","status","durationMs","error","requestHeaders","startsWith","requestType","persist","flush","e","console","addAuditEvent","now","fullEvent","set","catch","queryAuditEvents","options","limit","offset","from","to","events","entries","push","sort","a","b","getTime","filter","fromTime","toTime","total","length","slice","getAuditStats","totalRequests","totalErrors","durations","map","d","avgDurationMs","reduce","serverCounts","Map","name","get","byServer","Array","count","methodCounts","byMethod","clearAuditEvents","before","beforeTime","deleted","delete","AuditRouter","router","list","handler","input","stats","clear","auditMiddleware","c","next","startTime","req","mcpMatch","match","Error","message","String","shouldAudit","toISOString","res","raw"],"mappings":"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"}
|