@wener/mcps 1.0.2 → 1.0.4

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 (59) hide show
  1. package/README.md +144 -0
  2. package/dist/index.mjs +213076 -1
  3. package/dist/mcps-cli.mjs +102547 -59344
  4. package/lib/chat/handler.js +2 -2
  5. package/lib/chat/handler.js.map +1 -1
  6. package/lib/cli-start.js +36 -0
  7. package/lib/cli-start.js.map +1 -0
  8. package/lib/cli.js +19 -0
  9. package/lib/cli.js.map +1 -0
  10. package/lib/dev.server.js +7 -1
  11. package/lib/dev.server.js.map +1 -1
  12. package/lib/index.js +21 -3
  13. package/lib/index.js.map +1 -1
  14. package/lib/mcps-cli.js +6 -35
  15. package/lib/mcps-cli.js.map +1 -1
  16. package/lib/providers/feishu/def.js +35 -0
  17. package/lib/providers/feishu/def.js.map +1 -0
  18. package/lib/providers/findMcpServerDef.js +1 -0
  19. package/lib/providers/findMcpServerDef.js.map +1 -1
  20. package/lib/scripts/bundle.js +7 -1
  21. package/lib/scripts/bundle.js.map +1 -1
  22. package/lib/server/api-routes.js +7 -8
  23. package/lib/server/api-routes.js.map +1 -1
  24. package/lib/server/audit-db.js +64 -0
  25. package/lib/server/audit-db.js.map +1 -0
  26. package/lib/server/{audit.js → audit-plugin.js} +72 -126
  27. package/lib/server/audit-plugin.js.map +1 -0
  28. package/lib/server/events.js +13 -0
  29. package/lib/server/events.js.map +1 -0
  30. package/lib/server/mcp-routes.js +31 -60
  31. package/lib/server/mcp-routes.js.map +1 -1
  32. package/lib/server/mcps-router.js +19 -24
  33. package/lib/server/mcps-router.js.map +1 -1
  34. package/lib/server/schema.js +22 -2
  35. package/lib/server/schema.js.map +1 -1
  36. package/lib/server/server.js +142 -87
  37. package/lib/server/server.js.map +1 -1
  38. package/package.json +33 -6
  39. package/src/chat/handler.ts +2 -2
  40. package/src/cli-start.ts +43 -0
  41. package/src/cli.ts +45 -0
  42. package/src/dev.server.ts +8 -1
  43. package/src/index.ts +47 -1
  44. package/src/mcps-cli.ts +6 -48
  45. package/src/providers/feishu/def.ts +37 -0
  46. package/src/providers/findMcpServerDef.ts +1 -0
  47. package/src/scripts/bundle.ts +12 -1
  48. package/src/server/api-routes.ts +11 -8
  49. package/src/server/audit-db.ts +65 -0
  50. package/src/server/{audit.ts → audit-plugin.ts} +69 -142
  51. package/src/server/events.ts +29 -0
  52. package/src/server/mcp-routes.ts +30 -58
  53. package/src/server/mcps-router.ts +21 -29
  54. package/src/server/schema.ts +23 -2
  55. package/src/server/server.ts +149 -81
  56. package/lib/server/audit.js.map +0 -1
  57. package/lib/server/db.js +0 -97
  58. package/lib/server/db.js.map +0 -1
  59. package/src/server/db.ts +0 -115
@@ -4,6 +4,7 @@ import "./prometheus/def.js";
4
4
  import "./tencent-cls/def.js";
5
5
  import "./sql/def.js";
6
6
  import "./relay/def.js";
7
+ import "./feishu/def.js";
7
8
  /**
8
9
  * Find MCP server definitions matching a predicate
9
10
  */ export function findMcpServerDef(predicate) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/findMcpServerDef.ts"],"sourcesContent":["import { getAllMcpServerHandlerDefs, type McpServerHandlerDef } from './McpServerHandlerDef';\n// Import all server definitions to ensure they are registered\nimport './prometheus/def';\nimport './tencent-cls/def';\nimport './sql/def';\nimport './relay/def';\n\n/**\n * Find MCP server definitions matching a predicate\n */\nexport function findMcpServerDef(predicate?: (def: McpServerHandlerDef) => boolean): McpServerHandlerDef[] {\n\tconst all = getAllMcpServerHandlerDefs();\n\tif (!predicate) {\n\t\treturn all;\n\t}\n\treturn all.filter(predicate);\n}\n\n/**\n * Resolve a single MCP server definition by name\n */\nexport function resolveMcpServerDef(name: string): McpServerHandlerDef | undefined {\n\treturn findMcpServerDef((v) => v.name === name)[0];\n}\n\n/**\n * Get total count of registered MCP server types\n */\nexport function getMcpServerDefCount(): number {\n\treturn getAllMcpServerHandlerDefs().length;\n}\n"],"names":["getAllMcpServerHandlerDefs","findMcpServerDef","predicate","all","filter","resolveMcpServerDef","name","v","getMcpServerDefCount","length"],"mappings":"AAAA,SAASA,0BAA0B,QAAkC,wBAAwB;AAC7F,8DAA8D;AAC9D,OAAO,mBAAmB;AAC1B,OAAO,oBAAoB;AAC3B,OAAO,YAAY;AACnB,OAAO,cAAc;AAErB;;CAEC,GACD,OAAO,SAASC,iBAAiBC,SAAiD;IACjF,MAAMC,MAAMH;IACZ,IAAI,CAACE,WAAW;QACf,OAAOC;IACR;IACA,OAAOA,IAAIC,MAAM,CAACF;AACnB;AAEA;;CAEC,GACD,OAAO,SAASG,oBAAoBC,IAAY;IAC/C,OAAOL,iBAAiB,CAACM,IAAMA,EAAED,IAAI,KAAKA,KAAK,CAAC,EAAE;AACnD;AAEA;;CAEC,GACD,OAAO,SAASE;IACf,OAAOR,6BAA6BS,MAAM;AAC3C"}
1
+ {"version":3,"sources":["../../src/providers/findMcpServerDef.ts"],"sourcesContent":["import { getAllMcpServerHandlerDefs, type McpServerHandlerDef } from './McpServerHandlerDef';\n// Import all server definitions to ensure they are registered\nimport './prometheus/def';\nimport './tencent-cls/def';\nimport './sql/def';\nimport './relay/def';\nimport './feishu/def';\n\n/**\n * Find MCP server definitions matching a predicate\n */\nexport function findMcpServerDef(predicate?: (def: McpServerHandlerDef) => boolean): McpServerHandlerDef[] {\n\tconst all = getAllMcpServerHandlerDefs();\n\tif (!predicate) {\n\t\treturn all;\n\t}\n\treturn all.filter(predicate);\n}\n\n/**\n * Resolve a single MCP server definition by name\n */\nexport function resolveMcpServerDef(name: string): McpServerHandlerDef | undefined {\n\treturn findMcpServerDef((v) => v.name === name)[0];\n}\n\n/**\n * Get total count of registered MCP server types\n */\nexport function getMcpServerDefCount(): number {\n\treturn getAllMcpServerHandlerDefs().length;\n}\n"],"names":["getAllMcpServerHandlerDefs","findMcpServerDef","predicate","all","filter","resolveMcpServerDef","name","v","getMcpServerDefCount","length"],"mappings":"AAAA,SAASA,0BAA0B,QAAkC,wBAAwB;AAC7F,8DAA8D;AAC9D,OAAO,mBAAmB;AAC1B,OAAO,oBAAoB;AAC3B,OAAO,YAAY;AACnB,OAAO,cAAc;AACrB,OAAO,eAAe;AAEtB;;CAEC,GACD,OAAO,SAASC,iBAAiBC,SAAiD;IACjF,MAAMC,MAAMH;IACZ,IAAI,CAACE,WAAW;QACf,OAAOC;IACR;IACA,OAAOA,IAAIC,MAAM,CAACF;AACnB;AAEA;;CAEC,GACD,OAAO,SAASG,oBAAoBC,IAAY;IAC/C,OAAOL,iBAAiB,CAACM,IAAMA,EAAED,IAAI,KAAKA,KAAK,CAAC,EAAE;AACnD;AAEA;;CAEC,GACD,OAAO,SAASE;IACf,OAAOR,6BAA6BS,MAAM;AAC3C"}
@@ -40,9 +40,15 @@ const commonOptions = {
40
40
  // External native modules
41
41
  external: [
42
42
  'better-sqlite3',
43
+ 'bun:sqlite',
44
+ 'kysely-bun-sqlite',
43
45
  'oracledb',
44
46
  'mariadb/callback',
45
- 'mysql'
47
+ 'mysql',
48
+ '@nestjs/websockets',
49
+ '@nestjs/microservices',
50
+ '@nestjs/platform-express',
51
+ '@larksuiteoapi/node-sdk'
46
52
  ]
47
53
  };
48
54
  // Ensure dist directory exists
@@ -1 +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"}
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: [\n\t\t'better-sqlite3',\n\t\t'bun:sqlite',\n\t\t'kysely-bun-sqlite',\n\t\t'oracledb',\n\t\t'mariadb/callback',\n\t\t'mysql',\n\t\t'@nestjs/websockets',\n\t\t'@nestjs/microservices',\n\t\t'@nestjs/platform-express',\n\t\t'@larksuiteoapi/node-sdk',\n\t],\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;QACT;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;KACA;AACF;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"}
@@ -5,19 +5,18 @@ import { RPCHandler } from "@orpc/server/fetch";
5
5
  import { CORSPlugin } from "@orpc/server/plugins";
6
6
  import { ZodToJsonSchemaConverter } from "@orpc/zod/zod4";
7
7
  import { html } from "hono/html";
8
- import { AuditRouter } from "./audit.js";
9
8
  import { createMcpsRouter } from "./mcps-router.js";
10
9
  /**
11
- * Register oRPC API routes for audit and MCPS
12
- */ export function registerApiRoutes({ app, config }) {
13
- // Create MCPS router with config context
10
+ * Register oRPC API routes for MCPS.
11
+ * Audit router is not included by default - use setupAudit() plugin to add it.
12
+ */ export function registerApiRoutes({ app, config, apiRouters, statsProvider }) {
14
13
  const McpsRouter = createMcpsRouter({
15
- config
14
+ config,
15
+ statsProvider
16
16
  });
17
- // Combined router for all APIs
18
17
  const combinedRouter = {
19
- audit: AuditRouter,
20
- mcps: McpsRouter
18
+ mcps: McpsRouter,
19
+ ...apiRouters
21
20
  };
22
21
  const handleByRpc = new RPCHandler(combinedRouter);
23
22
  const handleByOpenAPI = new OpenAPIHandler(combinedRouter, {
@@ -1 +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"}
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 { createMcpsRouter } from './mcps-router';\nimport type { McpsConfig } from './schema';\nimport type { StatsProvider } from './server';\n\nexport interface RegisterApiRoutesOptions {\n\tapp: Hono;\n\tconfig: McpsConfig;\n\t/** Additional oRPC routers registered by plugins (e.g. audit) */\n\tapiRouters?: Record<string, any>;\n\t/** Optional stats provider from audit plugin */\n\tstatsProvider?: StatsProvider;\n}\n\n/**\n * Register oRPC API routes for MCPS.\n * Audit router is not included by default - use setupAudit() plugin to add it.\n */\nexport function registerApiRoutes({ app, config, apiRouters, statsProvider }: RegisterApiRoutesOptions) {\n\tconst McpsRouter = createMcpsRouter({ config, statsProvider });\n\n\tconst combinedRouter: Record<string, any> = {\n\t\tmcps: McpsRouter,\n\t\t...apiRouters,\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","createMcpsRouter","registerApiRoutes","app","config","apiRouters","statsProvider","McpsRouter","combinedRouter","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,gBAAgB,QAAQ,gBAAgB;AAajD;;;CAGC,GACD,OAAO,SAASC,kBAAkB,EAAEC,GAAG,EAAEC,MAAM,EAAEC,UAAU,EAAEC,aAAa,EAA4B;IACrG,MAAMC,aAAaN,iBAAiB;QAAEG;QAAQE;IAAc;IAE5D,MAAME,iBAAsC;QAC3CC,MAAMF;QACN,GAAGF,UAAU;IACd;IAEA,MAAMK,cAAc,IAAIb,WAAWW;IACnC,MAAMG,kBAAkB,IAAIf,eAAeY,gBAAgB;QAC1DI,SAAS;YACR,IAAIlB,oBAAoB;gBACvBmB,kBAAkB;oBAAC,IAAId;iBAA2B;YACnD;YACA,IAAID,WAAW;gBACdgB,eAAe;oBAAC;iBAAsB;YACvC;SACA;IACF;IAEAX,IAAIY,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;IAEAd,IAAIY,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;IAEJzB,IAAI0B,GAAG,CAAC,kBAAkB,OAAOb;QAChC,IAAI,CAACY,WAAW;YACfA,YAAY,MAAMD,iBAAiBG,QAAQ,CAACtB,gBAAgB;gBAC3DuB,MAAM;oBAAEC,OAAO;oBAAYC,SAAS;gBAAQ;gBAC5CC,SAAS;oBAAC;wBAAEC,KAAK;oBAAO;iBAAE;YAC3B;QACD;QACA,OAAOnB,EAAEoB,IAAI,CAACR;IACf;IAEA,aAAa;IACbzB,IAAI0B,GAAG,CAAC,aAAa,CAACb;QACrB,OAAOA,EAAEhB,IAAI,CACZA,IAAI,CAAC;;;;;;;;;;;WAWG,CAAC;IAEX;AACD"}
@@ -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=audit-db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/server/audit-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 { ChatRequestEntity } from '../entities/ChatRequestEntity';\nimport { McpRequestEntity } from '../entities/McpRequestEntity';\nimport { RequestLogEntity } from '../entities/RequestLogEntity';\nimport { ResponseEntity } from '../entities/ResponseEntity';\nimport type { DbConfig } from './schema';\n\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;AAC9D,SAASC,iBAAiB,QAAQ,gCAAgC;AAClE,SAASC,gBAAgB,QAAQ,+BAA+B;AAChE,SAASC,gBAAgB,QAAQ,+BAA+B;AAChE,SAASC,cAAc,QAAQ,6BAA6B;AAG5D,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"}
@@ -1,57 +1,28 @@
1
1
  import { implement } from "@orpc/server";
2
2
  import { LRUCache } from "lru-cache";
3
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) {
4
+ import { McpsEventType } from "./events.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("./audit-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=audit-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/server/audit-plugin.ts"],"sourcesContent":["import { implement } from '@orpc/server';\nimport { LRUCache } from 'lru-cache';\nimport { AuditContract, type AuditEvent } from '../contracts';\nimport { McpsEventType, type McpsEmitter } from './events';\nimport type { AuditConfig, DbConfig } from './schema';\nimport type { McpsServerContext } from './server';\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('./audit-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","AuditContract","McpsEventType","headersToRecord","headers","record","forEach","value","key","auditStore","max","ttl","eventCounter","dbConfigured","storedAuditConfig","storedDbConfig","persistToDb","event","id","ensureDbInitialized","RequestLogEntity","orm","em","fork","logEntry","requestId","timestamp","Date","method","path","serverName","undefined","serverType","status","durationMs","error","requestHeaders","startsWith","requestType","persist","flush","e","console","addAuditEvent","now","fullEvent","set","catch","queryAuditEvents","options","limit","offset","from","to","events","entries","push","sort","a","b","getTime","filter","fromTime","toTime","total","length","slice","getAuditStats","totalRequests","totalErrors","durations","map","d","avgDurationMs","reduce","serverCounts","Map","name","get","byServer","Array","count","methodCounts","m","byMethod","clearAuditEvents","before","beforeTime","deleted","delete","AuditRouter","router","list","handler","input","stats","clear","setupAudit","ctx","auditConfig","config","audit","dbConfig","db","enabled","auditDbConfig","emitter","on","Request","shouldAudit","apiRouters","statsProvider","getStats","queryEvents","opts","result"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import Emittery from 'emittery';
2
+ export const McpsEventType = {
3
+ Request: 'Mcps:Request'
4
+ };
5
+ export function createMcpsEmitter() {
6
+ return new Emittery({
7
+ debug: {
8
+ name: 'McpsEmitter'
9
+ }
10
+ });
11
+ }
12
+
13
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/server/events.ts"],"sourcesContent":["import Emittery from 'emittery';\n\nexport const McpsEventType = {\n\tRequest: 'Mcps:Request',\n} as const;\n\nexport type McpsRequestEvent = {\n\ttimestamp: string;\n\tmethod: string;\n\tpath: string;\n\tserverName?: string;\n\tserverType?: string;\n\tstatus?: number;\n\tdurationMs?: number;\n\terror?: string;\n\trequestHeaders?: Record<string, string>;\n};\n\nexport type McpsEventData = {\n\t[McpsEventType.Request]: McpsRequestEvent;\n};\n\nexport type McpsEmitter = Emittery<McpsEventData>;\n\nexport function createMcpsEmitter(): McpsEmitter {\n\treturn new Emittery<McpsEventData>({\n\t\tdebug: { name: 'McpsEmitter' },\n\t});\n}\n"],"names":["Emittery","McpsEventType","Request","createMcpsEmitter","debug","name"],"mappings":"AAAA,OAAOA,cAAc,WAAW;AAEhC,OAAO,MAAMC,gBAAgB;IAC5BC,SAAS;AACV,EAAW;AAoBX,OAAO,SAASC;IACf,OAAO,IAAIH,SAAwB;QAClCI,OAAO;YAAEC,MAAM;QAAc;IAC9B;AACD"}