@dxheroes/local-mcp-backend 0.3.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.
Files changed (106) hide show
  1. package/.swcrc +22 -0
  2. package/.turbo/turbo-build.log +9 -0
  3. package/AGENTS.md +360 -0
  4. package/CHANGELOG.md +60 -0
  5. package/Dockerfile +71 -0
  6. package/LICENSE +94 -0
  7. package/dist/app.module.js +72 -0
  8. package/dist/app.module.js.map +1 -0
  9. package/dist/common/decorators/request-id.decorator.js +12 -0
  10. package/dist/common/decorators/request-id.decorator.js.map +1 -0
  11. package/dist/common/filters/all-exceptions.filter.js +61 -0
  12. package/dist/common/filters/all-exceptions.filter.js.map +1 -0
  13. package/dist/common/interceptors/logging.interceptor.js +46 -0
  14. package/dist/common/interceptors/logging.interceptor.js.map +1 -0
  15. package/dist/common/pipes/validation.pipe.js +43 -0
  16. package/dist/common/pipes/validation.pipe.js.map +1 -0
  17. package/dist/config/app.config.js +14 -0
  18. package/dist/config/app.config.js.map +1 -0
  19. package/dist/config/database.config.js +30 -0
  20. package/dist/config/database.config.js.map +1 -0
  21. package/dist/main.js +68 -0
  22. package/dist/main.js.map +1 -0
  23. package/dist/modules/database/database.module.js +27 -0
  24. package/dist/modules/database/database.module.js.map +1 -0
  25. package/dist/modules/database/prisma.service.js +122 -0
  26. package/dist/modules/database/prisma.service.js.map +1 -0
  27. package/dist/modules/debug/debug.controller.js +87 -0
  28. package/dist/modules/debug/debug.controller.js.map +1 -0
  29. package/dist/modules/debug/debug.module.js +30 -0
  30. package/dist/modules/debug/debug.module.js.map +1 -0
  31. package/dist/modules/debug/debug.service.js +126 -0
  32. package/dist/modules/debug/debug.service.js.map +1 -0
  33. package/dist/modules/health/health.controller.js +69 -0
  34. package/dist/modules/health/health.controller.js.map +1 -0
  35. package/dist/modules/health/health.module.js +23 -0
  36. package/dist/modules/health/health.module.js.map +1 -0
  37. package/dist/modules/mcp/dto/create-mcp-server.dto.js +74 -0
  38. package/dist/modules/mcp/dto/create-mcp-server.dto.js.map +1 -0
  39. package/dist/modules/mcp/dto/update-mcp-server.dto.js +74 -0
  40. package/dist/modules/mcp/dto/update-mcp-server.dto.js.map +1 -0
  41. package/dist/modules/mcp/mcp-discovery.service.js +176 -0
  42. package/dist/modules/mcp/mcp-discovery.service.js.map +1 -0
  43. package/dist/modules/mcp/mcp-registry.js +67 -0
  44. package/dist/modules/mcp/mcp-registry.js.map +1 -0
  45. package/dist/modules/mcp/mcp-seed.service.js +122 -0
  46. package/dist/modules/mcp/mcp-seed.service.js.map +1 -0
  47. package/dist/modules/mcp/mcp.controller.js +152 -0
  48. package/dist/modules/mcp/mcp.controller.js.map +1 -0
  49. package/dist/modules/mcp/mcp.module.js +70 -0
  50. package/dist/modules/mcp/mcp.module.js.map +1 -0
  51. package/dist/modules/mcp/mcp.service.js +401 -0
  52. package/dist/modules/mcp/mcp.service.js.map +1 -0
  53. package/dist/modules/oauth/oauth.controller.js +116 -0
  54. package/dist/modules/oauth/oauth.controller.js.map +1 -0
  55. package/dist/modules/oauth/oauth.module.js +31 -0
  56. package/dist/modules/oauth/oauth.module.js.map +1 -0
  57. package/dist/modules/oauth/oauth.service.js +183 -0
  58. package/dist/modules/oauth/oauth.service.js.map +1 -0
  59. package/dist/modules/profiles/profiles.controller.js +241 -0
  60. package/dist/modules/profiles/profiles.controller.js.map +1 -0
  61. package/dist/modules/profiles/profiles.module.js +34 -0
  62. package/dist/modules/profiles/profiles.module.js.map +1 -0
  63. package/dist/modules/profiles/profiles.service.js +390 -0
  64. package/dist/modules/profiles/profiles.service.js.map +1 -0
  65. package/dist/modules/proxy/proxy.controller.js +98 -0
  66. package/dist/modules/proxy/proxy.controller.js.map +1 -0
  67. package/dist/modules/proxy/proxy.module.js +36 -0
  68. package/dist/modules/proxy/proxy.module.js.map +1 -0
  69. package/dist/modules/proxy/proxy.service.js +439 -0
  70. package/dist/modules/proxy/proxy.service.js.map +1 -0
  71. package/docker-entrypoint.sh +10 -0
  72. package/nest-cli.json +10 -0
  73. package/package.json +51 -0
  74. package/src/app.module.ts +59 -0
  75. package/src/common/decorators/request-id.decorator.ts +16 -0
  76. package/src/common/filters/all-exceptions.filter.ts +77 -0
  77. package/src/common/interceptors/logging.interceptor.ts +45 -0
  78. package/src/common/pipes/validation.pipe.ts +31 -0
  79. package/src/config/app.config.ts +15 -0
  80. package/src/config/database.config.ts +34 -0
  81. package/src/main.ts +66 -0
  82. package/src/modules/database/database.module.ts +15 -0
  83. package/src/modules/database/prisma.service.ts +110 -0
  84. package/src/modules/debug/debug.controller.ts +53 -0
  85. package/src/modules/debug/debug.module.ts +16 -0
  86. package/src/modules/debug/debug.service.ts +143 -0
  87. package/src/modules/health/health.controller.ts +48 -0
  88. package/src/modules/health/health.module.ts +13 -0
  89. package/src/modules/mcp/dto/create-mcp-server.dto.ts +53 -0
  90. package/src/modules/mcp/dto/update-mcp-server.dto.ts +53 -0
  91. package/src/modules/mcp/mcp-discovery.service.ts +205 -0
  92. package/src/modules/mcp/mcp-registry.ts +73 -0
  93. package/src/modules/mcp/mcp-seed.service.ts +125 -0
  94. package/src/modules/mcp/mcp.controller.ts +98 -0
  95. package/src/modules/mcp/mcp.module.ts +48 -0
  96. package/src/modules/mcp/mcp.service.ts +427 -0
  97. package/src/modules/oauth/oauth.controller.ts +89 -0
  98. package/src/modules/oauth/oauth.module.ts +17 -0
  99. package/src/modules/oauth/oauth.service.ts +212 -0
  100. package/src/modules/profiles/profiles.controller.ts +177 -0
  101. package/src/modules/profiles/profiles.module.ts +18 -0
  102. package/src/modules/profiles/profiles.service.ts +421 -0
  103. package/src/modules/proxy/proxy.controller.ts +61 -0
  104. package/src/modules/proxy/proxy.module.ts +19 -0
  105. package/src/modules/proxy/proxy.service.ts +595 -0
  106. package/tsconfig.json +28 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/app.module.ts"],"sourcesContent":["/**\n * Root Application Module\n *\n * Configures all NestJS modules for the Local MCP Gateway.\n * No authentication module - immediate access to all features.\n */\n\nimport { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { ThrottlerModule } from '@nestjs/throttler';\nimport appConfig from './config/app.config.js';\nimport databaseConfig from './config/database.config.js';\nimport { DatabaseModule } from './modules/database/database.module.js';\nimport { DebugModule } from './modules/debug/debug.module.js';\nimport { HealthModule } from './modules/health/health.module.js';\nimport { McpModule } from './modules/mcp/mcp.module.js';\nimport { OAuthModule } from './modules/oauth/oauth.module.js';\nimport { ProfilesModule } from './modules/profiles/profiles.module.js';\nimport { ProxyModule } from './modules/proxy/proxy.module.js';\n\n@Module({\n imports: [\n // Configuration\n ConfigModule.forRoot({\n isGlobal: true,\n load: [appConfig, databaseConfig],\n envFilePath: ['../../.env', '.env.local', '.env'],\n }),\n\n // Rate limiting\n ThrottlerModule.forRoot([\n {\n name: 'short',\n ttl: 1000,\n limit: 10,\n },\n {\n name: 'medium',\n ttl: 10000,\n limit: 50,\n },\n {\n name: 'long',\n ttl: 60000,\n limit: 200,\n },\n ]),\n\n // Core modules (no authentication - immediate access)\n DatabaseModule,\n McpModule,\n ProfilesModule,\n OAuthModule, // For OAuth MCP servers, not user authentication\n ProxyModule,\n HealthModule,\n DebugModule,\n ],\n})\nexport class AppModule {}\n"],"names":["Module","ConfigModule","ThrottlerModule","appConfig","databaseConfig","DatabaseModule","DebugModule","HealthModule","McpModule","OAuthModule","ProfilesModule","ProxyModule","AppModule","imports","forRoot","isGlobal","load","envFilePath","name","ttl","limit"],"mappings":";;;;;;AAAA;;;;;CAKC,GAED,SAASA,MAAM,QAAQ,iBAAiB;AACxC,SAASC,YAAY,QAAQ,iBAAiB;AAC9C,SAASC,eAAe,QAAQ,oBAAoB;AACpD,OAAOC,eAAe,yBAAyB;AAC/C,OAAOC,oBAAoB,8BAA8B;AACzD,SAASC,cAAc,QAAQ,wCAAwC;AACvE,SAASC,WAAW,QAAQ,kCAAkC;AAC9D,SAASC,YAAY,QAAQ,oCAAoC;AACjE,SAASC,SAAS,QAAQ,8BAA8B;AACxD,SAASC,WAAW,QAAQ,kCAAkC;AAC9D,SAASC,cAAc,QAAQ,wCAAwC;AACvE,SAASC,WAAW,QAAQ,kCAAkC;AAwC9D,OAAO,MAAMC;AAAW;;;QArCtBC,SAAS;YACP,gBAAgB;YAChBZ,aAAaa,OAAO,CAAC;gBACnBC,UAAU;gBACVC,MAAM;oBAACb;oBAAWC;iBAAe;gBACjCa,aAAa;oBAAC;oBAAc;oBAAc;iBAAO;YACnD;YAEA,gBAAgB;YAChBf,gBAAgBY,OAAO,CAAC;gBACtB;oBACEI,MAAM;oBACNC,KAAK;oBACLC,OAAO;gBACT;gBACA;oBACEF,MAAM;oBACNC,KAAK;oBACLC,OAAO;gBACT;gBACA;oBACEF,MAAM;oBACNC,KAAK;oBACLC,OAAO;gBACT;aACD;YAED,sDAAsD;YACtDf;YACAG;YACAE;YACAD;YACAE;YACAJ;YACAD;SACD"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Request ID Decorator
3
+ *
4
+ * Extracts request ID from the request headers.
5
+ */ import { createParamDecorator } from "@nestjs/common";
6
+ export const RequestId = createParamDecorator((_data, ctx)=>{
7
+ const request = ctx.switchToHttp().getRequest();
8
+ const requestId = request.headers['x-request-id'];
9
+ return typeof requestId === 'string' ? requestId : undefined;
10
+ });
11
+
12
+ //# sourceMappingURL=request-id.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/common/decorators/request-id.decorator.ts"],"sourcesContent":["/**\n * Request ID Decorator\n *\n * Extracts request ID from the request headers.\n */\n\nimport { createParamDecorator, ExecutionContext } from '@nestjs/common';\nimport { Request } from 'express';\n\nexport const RequestId = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext): string | undefined => {\n const request = ctx.switchToHttp().getRequest<Request>();\n const requestId = request.headers['x-request-id'];\n return typeof requestId === 'string' ? requestId : undefined;\n }\n);\n"],"names":["createParamDecorator","RequestId","_data","ctx","request","switchToHttp","getRequest","requestId","headers","undefined"],"mappings":"AAAA;;;;CAIC,GAED,SAASA,oBAAoB,QAA0B,iBAAiB;AAGxE,OAAO,MAAMC,YAAYD,qBACvB,CAACE,OAAgBC;IACf,MAAMC,UAAUD,IAAIE,YAAY,GAAGC,UAAU;IAC7C,MAAMC,YAAYH,QAAQI,OAAO,CAAC,eAAe;IACjD,OAAO,OAAOD,cAAc,WAAWA,YAAYE;AACrD,GACA"}
@@ -0,0 +1,61 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ /**
8
+ * Global Exception Filter
9
+ *
10
+ * Catches all exceptions and formats them consistently.
11
+ */ import { Catch, HttpException, HttpStatus, Logger } from "@nestjs/common";
12
+ export class AllExceptionsFilter {
13
+ catch(exception, host) {
14
+ const ctx = host.switchToHttp();
15
+ const response = ctx.getResponse();
16
+ const request = ctx.getRequest();
17
+ let status = HttpStatus.INTERNAL_SERVER_ERROR;
18
+ let message = 'Internal server error';
19
+ let error = 'Internal Server Error';
20
+ if (exception instanceof HttpException) {
21
+ status = exception.getStatus();
22
+ const exceptionResponse = exception.getResponse();
23
+ if (typeof exceptionResponse === 'string') {
24
+ message = exceptionResponse;
25
+ } else if (typeof exceptionResponse === 'object') {
26
+ const responseObj = exceptionResponse;
27
+ message = responseObj.message || message;
28
+ error = responseObj.error || exception.name;
29
+ }
30
+ } else if (exception instanceof Error) {
31
+ message = exception.message;
32
+ error = exception.name;
33
+ }
34
+ // Log error
35
+ this.logger.error(`${request.method} ${request.url} - ${status} - ${message}`, {
36
+ exception: exception instanceof Error ? exception.stack : String(exception),
37
+ requestId: request.headers['x-request-id']
38
+ });
39
+ const errorResponse = {
40
+ statusCode: status,
41
+ message,
42
+ error,
43
+ timestamp: new Date().toISOString(),
44
+ path: request.url
45
+ };
46
+ // Add request ID if present
47
+ const requestId = request.headers['x-request-id'];
48
+ if (typeof requestId === 'string') {
49
+ errorResponse.requestId = requestId;
50
+ }
51
+ response.status(status).json(errorResponse);
52
+ }
53
+ constructor(){
54
+ this.logger = new Logger(AllExceptionsFilter.name);
55
+ }
56
+ }
57
+ AllExceptionsFilter = _ts_decorate([
58
+ Catch()
59
+ ], AllExceptionsFilter);
60
+
61
+ //# sourceMappingURL=all-exceptions.filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/common/filters/all-exceptions.filter.ts"],"sourcesContent":["/**\n * Global Exception Filter\n *\n * Catches all exceptions and formats them consistently.\n */\n\nimport {\n ArgumentsHost,\n Catch,\n ExceptionFilter,\n HttpException,\n HttpStatus,\n Logger,\n} from '@nestjs/common';\nimport { Request, Response } from 'express';\n\ninterface ErrorResponse {\n statusCode: number;\n message: string;\n error: string;\n timestamp: string;\n path: string;\n requestId?: string;\n}\n\n@Catch()\nexport class AllExceptionsFilter implements ExceptionFilter {\n private readonly logger = new Logger(AllExceptionsFilter.name);\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n const response = ctx.getResponse<Response>();\n const request = ctx.getRequest<Request>();\n\n let status = HttpStatus.INTERNAL_SERVER_ERROR;\n let message = 'Internal server error';\n let error = 'Internal Server Error';\n\n if (exception instanceof HttpException) {\n status = exception.getStatus();\n const exceptionResponse = exception.getResponse();\n\n if (typeof exceptionResponse === 'string') {\n message = exceptionResponse;\n } else if (typeof exceptionResponse === 'object') {\n const responseObj = exceptionResponse as Record<string, unknown>;\n message = (responseObj.message as string) || message;\n error = (responseObj.error as string) || exception.name;\n }\n } else if (exception instanceof Error) {\n message = exception.message;\n error = exception.name;\n }\n\n // Log error\n this.logger.error(`${request.method} ${request.url} - ${status} - ${message}`, {\n exception: exception instanceof Error ? exception.stack : String(exception),\n requestId: request.headers['x-request-id'],\n });\n\n const errorResponse: ErrorResponse = {\n statusCode: status,\n message,\n error,\n timestamp: new Date().toISOString(),\n path: request.url,\n };\n\n // Add request ID if present\n const requestId = request.headers['x-request-id'];\n if (typeof requestId === 'string') {\n errorResponse.requestId = requestId;\n }\n\n response.status(status).json(errorResponse);\n }\n}\n"],"names":["Catch","HttpException","HttpStatus","Logger","AllExceptionsFilter","catch","exception","host","ctx","switchToHttp","response","getResponse","request","getRequest","status","INTERNAL_SERVER_ERROR","message","error","getStatus","exceptionResponse","responseObj","name","Error","logger","method","url","stack","String","requestId","headers","errorResponse","statusCode","timestamp","Date","toISOString","path","json"],"mappings":";;;;;;AAAA;;;;CAIC,GAED,SAEEA,KAAK,EAELC,aAAa,EACbC,UAAU,EACVC,MAAM,QACD,iBAAiB;AAaxB,OAAO,MAAMC;IAGXC,MAAMC,SAAkB,EAAEC,IAAmB,EAAQ;QACnD,MAAMC,MAAMD,KAAKE,YAAY;QAC7B,MAAMC,WAAWF,IAAIG,WAAW;QAChC,MAAMC,UAAUJ,IAAIK,UAAU;QAE9B,IAAIC,SAASZ,WAAWa,qBAAqB;QAC7C,IAAIC,UAAU;QACd,IAAIC,QAAQ;QAEZ,IAAIX,qBAAqBL,eAAe;YACtCa,SAASR,UAAUY,SAAS;YAC5B,MAAMC,oBAAoBb,UAAUK,WAAW;YAE/C,IAAI,OAAOQ,sBAAsB,UAAU;gBACzCH,UAAUG;YACZ,OAAO,IAAI,OAAOA,sBAAsB,UAAU;gBAChD,MAAMC,cAAcD;gBACpBH,UAAU,AAACI,YAAYJ,OAAO,IAAeA;gBAC7CC,QAAQ,AAACG,YAAYH,KAAK,IAAeX,UAAUe,IAAI;YACzD;QACF,OAAO,IAAIf,qBAAqBgB,OAAO;YACrCN,UAAUV,UAAUU,OAAO;YAC3BC,QAAQX,UAAUe,IAAI;QACxB;QAEA,YAAY;QACZ,IAAI,CAACE,MAAM,CAACN,KAAK,CAAC,GAAGL,QAAQY,MAAM,CAAC,CAAC,EAAEZ,QAAQa,GAAG,CAAC,GAAG,EAAEX,OAAO,GAAG,EAAEE,SAAS,EAAE;YAC7EV,WAAWA,qBAAqBgB,QAAQhB,UAAUoB,KAAK,GAAGC,OAAOrB;YACjEsB,WAAWhB,QAAQiB,OAAO,CAAC,eAAe;QAC5C;QAEA,MAAMC,gBAA+B;YACnCC,YAAYjB;YACZE;YACAC;YACAe,WAAW,IAAIC,OAAOC,WAAW;YACjCC,MAAMvB,QAAQa,GAAG;QACnB;QAEA,4BAA4B;QAC5B,MAAMG,YAAYhB,QAAQiB,OAAO,CAAC,eAAe;QACjD,IAAI,OAAOD,cAAc,UAAU;YACjCE,cAAcF,SAAS,GAAGA;QAC5B;QAEAlB,SAASI,MAAM,CAACA,QAAQsB,IAAI,CAACN;IAC/B;;aAhDiBP,SAAS,IAAIpB,OAAOC,oBAAoBiB,IAAI;;AAiD/D"}
@@ -0,0 +1,46 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ /**
8
+ * Logging Interceptor
9
+ *
10
+ * Logs incoming requests and outgoing responses with timing.
11
+ */ import { randomUUID } from "node:crypto";
12
+ import { Injectable, Logger } from "@nestjs/common";
13
+ import { tap } from "rxjs/operators";
14
+ export class LoggingInterceptor {
15
+ intercept(context, next) {
16
+ const ctx = context.switchToHttp();
17
+ const request = ctx.getRequest();
18
+ const response = ctx.getResponse();
19
+ // Add request ID if not present
20
+ if (!request.headers['x-request-id']) {
21
+ request.headers['x-request-id'] = randomUUID();
22
+ }
23
+ const requestId = request.headers['x-request-id'];
24
+ response.setHeader('x-request-id', requestId);
25
+ const { method, url } = request;
26
+ const startTime = Date.now();
27
+ return next.handle().pipe(tap({
28
+ next: ()=>{
29
+ const duration = Date.now() - startTime;
30
+ this.logger.log(`${method} ${url} ${response.statusCode} - ${duration}ms`);
31
+ },
32
+ error: ()=>{
33
+ const duration = Date.now() - startTime;
34
+ this.logger.warn(`${method} ${url} ERROR - ${duration}ms`);
35
+ }
36
+ }));
37
+ }
38
+ constructor(){
39
+ this.logger = new Logger('HTTP');
40
+ }
41
+ }
42
+ LoggingInterceptor = _ts_decorate([
43
+ Injectable()
44
+ ], LoggingInterceptor);
45
+
46
+ //# sourceMappingURL=logging.interceptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/common/interceptors/logging.interceptor.ts"],"sourcesContent":["/**\n * Logging Interceptor\n *\n * Logs incoming requests and outgoing responses with timing.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { CallHandler, ExecutionContext, Injectable, Logger, NestInterceptor } from '@nestjs/common';\nimport { Request, Response } from 'express';\nimport { Observable } from 'rxjs';\nimport { tap } from 'rxjs/operators';\n\n@Injectable()\nexport class LoggingInterceptor implements NestInterceptor {\n private readonly logger = new Logger('HTTP');\n\n intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {\n const ctx = context.switchToHttp();\n const request = ctx.getRequest<Request>();\n const response = ctx.getResponse<Response>();\n\n // Add request ID if not present\n if (!request.headers['x-request-id']) {\n request.headers['x-request-id'] = randomUUID();\n }\n const requestId = request.headers['x-request-id'];\n response.setHeader('x-request-id', requestId);\n\n const { method, url } = request;\n const startTime = Date.now();\n\n return next.handle().pipe(\n tap({\n next: () => {\n const duration = Date.now() - startTime;\n this.logger.log(`${method} ${url} ${response.statusCode} - ${duration}ms`);\n },\n error: () => {\n const duration = Date.now() - startTime;\n this.logger.warn(`${method} ${url} ERROR - ${duration}ms`);\n },\n })\n );\n }\n}\n"],"names":["randomUUID","Injectable","Logger","tap","LoggingInterceptor","intercept","context","next","ctx","switchToHttp","request","getRequest","response","getResponse","headers","requestId","setHeader","method","url","startTime","Date","now","handle","pipe","duration","logger","log","statusCode","error","warn"],"mappings":";;;;;;AAAA;;;;CAIC,GAED,SAASA,UAAU,QAAQ,cAAc;AACzC,SAAwCC,UAAU,EAAEC,MAAM,QAAyB,iBAAiB;AAGpG,SAASC,GAAG,QAAQ,iBAAiB;AAGrC,OAAO,MAAMC;IAGXC,UAAUC,OAAyB,EAAEC,IAAiB,EAAuB;QAC3E,MAAMC,MAAMF,QAAQG,YAAY;QAChC,MAAMC,UAAUF,IAAIG,UAAU;QAC9B,MAAMC,WAAWJ,IAAIK,WAAW;QAEhC,gCAAgC;QAChC,IAAI,CAACH,QAAQI,OAAO,CAAC,eAAe,EAAE;YACpCJ,QAAQI,OAAO,CAAC,eAAe,GAAGd;QACpC;QACA,MAAMe,YAAYL,QAAQI,OAAO,CAAC,eAAe;QACjDF,SAASI,SAAS,CAAC,gBAAgBD;QAEnC,MAAM,EAAEE,MAAM,EAAEC,GAAG,EAAE,GAAGR;QACxB,MAAMS,YAAYC,KAAKC,GAAG;QAE1B,OAAOd,KAAKe,MAAM,GAAGC,IAAI,CACvBpB,IAAI;YACFI,MAAM;gBACJ,MAAMiB,WAAWJ,KAAKC,GAAG,KAAKF;gBAC9B,IAAI,CAACM,MAAM,CAACC,GAAG,CAAC,GAAGT,OAAO,CAAC,EAAEC,IAAI,CAAC,EAAEN,SAASe,UAAU,CAAC,GAAG,EAAEH,SAAS,EAAE,CAAC;YAC3E;YACAI,OAAO;gBACL,MAAMJ,WAAWJ,KAAKC,GAAG,KAAKF;gBAC9B,IAAI,CAACM,MAAM,CAACI,IAAI,CAAC,GAAGZ,OAAO,CAAC,EAAEC,IAAI,SAAS,EAAEM,SAAS,EAAE,CAAC;YAC3D;QACF;IAEJ;;aA7BiBC,SAAS,IAAIvB,OAAO;;AA8BvC"}
@@ -0,0 +1,43 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ function _ts_metadata(k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ }
10
+ /**
11
+ * Zod Validation Pipe
12
+ *
13
+ * Custom validation pipe that uses Zod schemas.
14
+ */ import { BadRequestException, Injectable } from "@nestjs/common";
15
+ import { z } from "zod";
16
+ export class ZodValidationPipe {
17
+ constructor(schema){
18
+ this.schema = schema;
19
+ }
20
+ transform(value) {
21
+ const result = this.schema.safeParse(value);
22
+ if (!result.success) {
23
+ const errors = result.error.issues.map((issue)=>({
24
+ path: issue.path.join('.'),
25
+ message: issue.message
26
+ }));
27
+ throw new BadRequestException({
28
+ message: 'Validation failed',
29
+ errors
30
+ });
31
+ }
32
+ return result.data;
33
+ }
34
+ }
35
+ ZodValidationPipe = _ts_decorate([
36
+ Injectable(),
37
+ _ts_metadata("design:type", Function),
38
+ _ts_metadata("design:paramtypes", [
39
+ typeof z === "undefined" || typeof z.ZodSchema === "undefined" ? Object : z.ZodSchema
40
+ ])
41
+ ], ZodValidationPipe);
42
+
43
+ //# sourceMappingURL=validation.pipe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/common/pipes/validation.pipe.ts"],"sourcesContent":["/**\n * Zod Validation Pipe\n *\n * Custom validation pipe that uses Zod schemas.\n */\n\nimport { BadRequestException, Injectable, PipeTransform } from '@nestjs/common';\nimport { z } from 'zod';\n\n@Injectable()\nexport class ZodValidationPipe implements PipeTransform {\n constructor(private schema: z.ZodSchema) {}\n\n transform(value: unknown) {\n const result = this.schema.safeParse(value);\n\n if (!result.success) {\n const errors = result.error.issues.map((issue) => ({\n path: issue.path.join('.'),\n message: issue.message,\n }));\n\n throw new BadRequestException({\n message: 'Validation failed',\n errors,\n });\n }\n\n return result.data;\n }\n}\n"],"names":["BadRequestException","Injectable","z","ZodValidationPipe","schema","transform","value","result","safeParse","success","errors","error","issues","map","issue","path","join","message","data"],"mappings":";;;;;;;;;AAAA;;;;CAIC,GAED,SAASA,mBAAmB,EAAEC,UAAU,QAAuB,iBAAiB;AAChF,SAASC,CAAC,QAAQ,MAAM;AAGxB,OAAO,MAAMC;IACX,YAAY,AAAQC,MAAmB,CAAE;aAArBA,SAAAA;IAAsB;IAE1CC,UAAUC,KAAc,EAAE;QACxB,MAAMC,SAAS,IAAI,CAACH,MAAM,CAACI,SAAS,CAACF;QAErC,IAAI,CAACC,OAAOE,OAAO,EAAE;YACnB,MAAMC,SAASH,OAAOI,KAAK,CAACC,MAAM,CAACC,GAAG,CAAC,CAACC,QAAW,CAAA;oBACjDC,MAAMD,MAAMC,IAAI,CAACC,IAAI,CAAC;oBACtBC,SAASH,MAAMG,OAAO;gBACxB,CAAA;YAEA,MAAM,IAAIjB,oBAAoB;gBAC5BiB,SAAS;gBACTP;YACF;QACF;QAEA,OAAOH,OAAOW,IAAI;IACpB;AACF;;;;;6CAnBgC,uCAAA"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Application configuration
3
+ */ import { registerAs } from "@nestjs/config";
4
+ export default registerAs('app', ()=>({
5
+ nodeEnv: process.env.NODE_ENV || 'development',
6
+ port: Number.parseInt(process.env.PORT || '3001', 10),
7
+ corsOrigins: process.env.CORS_ORIGINS?.split(',') || [
8
+ 'http://localhost:5173',
9
+ 'http://localhost:3000'
10
+ ],
11
+ logLevel: process.env.LOG_LEVEL || 'info'
12
+ }));
13
+
14
+ //# sourceMappingURL=app.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/config/app.config.ts"],"sourcesContent":["/**\n * Application configuration\n */\n\nimport { registerAs } from '@nestjs/config';\n\nexport default registerAs('app', () => ({\n nodeEnv: process.env.NODE_ENV || 'development',\n port: Number.parseInt(process.env.PORT || '3001', 10),\n corsOrigins: process.env.CORS_ORIGINS?.split(',') || [\n 'http://localhost:5173',\n 'http://localhost:3000',\n ],\n logLevel: process.env.LOG_LEVEL || 'info',\n}));\n"],"names":["registerAs","nodeEnv","process","env","NODE_ENV","port","Number","parseInt","PORT","corsOrigins","CORS_ORIGINS","split","logLevel","LOG_LEVEL"],"mappings":"AAAA;;CAEC,GAED,SAASA,UAAU,QAAQ,iBAAiB;AAE5C,eAAeA,WAAW,OAAO,IAAO,CAAA;QACtCC,SAASC,QAAQC,GAAG,CAACC,QAAQ,IAAI;QACjCC,MAAMC,OAAOC,QAAQ,CAACL,QAAQC,GAAG,CAACK,IAAI,IAAI,QAAQ;QAClDC,aAAaP,QAAQC,GAAG,CAACO,YAAY,EAAEC,MAAM,QAAQ;YACnD;YACA;SACD;QACDC,UAAUV,QAAQC,GAAG,CAACU,SAAS,IAAI;IACrC,CAAA,GAAI"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Database configuration
3
+ */ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { registerAs } from "@nestjs/config";
6
+ export default registerAs('database', ()=>{
7
+ // Parse DATABASE_URL for path
8
+ const databaseUrl = process.env.DATABASE_URL;
9
+ // Default path if not set
10
+ const defaultPath = join(homedir(), '.local-mcp-gateway-data', 'local-mcp-gateway.db');
11
+ // Extract path from file: URL
12
+ let path = defaultPath;
13
+ if (databaseUrl?.startsWith('file:')) {
14
+ const filePath = databaseUrl.replace('file:', '');
15
+ if (!filePath.startsWith(':memory:')) {
16
+ // Handle relative paths (./dev.db)
17
+ if (filePath.startsWith('./')) {
18
+ path = join(process.cwd(), filePath.slice(2));
19
+ } else {
20
+ path = filePath;
21
+ }
22
+ }
23
+ }
24
+ return {
25
+ url: databaseUrl || `file:${defaultPath}`,
26
+ path
27
+ };
28
+ });
29
+
30
+ //# sourceMappingURL=database.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/config/database.config.ts"],"sourcesContent":["/**\n * Database configuration\n */\n\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { registerAs } from '@nestjs/config';\n\nexport default registerAs('database', () => {\n // Parse DATABASE_URL for path\n const databaseUrl = process.env.DATABASE_URL;\n\n // Default path if not set\n const defaultPath = join(homedir(), '.local-mcp-gateway-data', 'local-mcp-gateway.db');\n\n // Extract path from file: URL\n let path = defaultPath;\n if (databaseUrl?.startsWith('file:')) {\n const filePath = databaseUrl.replace('file:', '');\n if (!filePath.startsWith(':memory:')) {\n // Handle relative paths (./dev.db)\n if (filePath.startsWith('./')) {\n path = join(process.cwd(), filePath.slice(2));\n } else {\n path = filePath;\n }\n }\n }\n\n return {\n url: databaseUrl || `file:${defaultPath}`,\n path,\n };\n});\n"],"names":["homedir","join","registerAs","databaseUrl","process","env","DATABASE_URL","defaultPath","path","startsWith","filePath","replace","cwd","slice","url"],"mappings":"AAAA;;CAEC,GAED,SAASA,OAAO,QAAQ,UAAU;AAClC,SAASC,IAAI,QAAQ,YAAY;AACjC,SAASC,UAAU,QAAQ,iBAAiB;AAE5C,eAAeA,WAAW,YAAY;IACpC,8BAA8B;IAC9B,MAAMC,cAAcC,QAAQC,GAAG,CAACC,YAAY;IAE5C,0BAA0B;IAC1B,MAAMC,cAAcN,KAAKD,WAAW,2BAA2B;IAE/D,8BAA8B;IAC9B,IAAIQ,OAAOD;IACX,IAAIJ,aAAaM,WAAW,UAAU;QACpC,MAAMC,WAAWP,YAAYQ,OAAO,CAAC,SAAS;QAC9C,IAAI,CAACD,SAASD,UAAU,CAAC,aAAa;YACpC,mCAAmC;YACnC,IAAIC,SAASD,UAAU,CAAC,OAAO;gBAC7BD,OAAOP,KAAKG,QAAQQ,GAAG,IAAIF,SAASG,KAAK,CAAC;YAC5C,OAAO;gBACLL,OAAOE;YACT;QACF;IACF;IAEA,OAAO;QACLI,KAAKX,eAAe,CAAC,KAAK,EAAEI,aAAa;QACzCC;IACF;AACF,GAAG"}
package/dist/main.js ADDED
@@ -0,0 +1,68 @@
1
+ /**
2
+ * NestJS Application Bootstrap
3
+ *
4
+ * Entry point for the Local MCP Gateway backend.
5
+ * No authentication required - immediate access to all features.
6
+ */ import { Logger, ValidationPipe } from "@nestjs/common";
7
+ import { ConfigService } from "@nestjs/config";
8
+ import { NestFactory } from "@nestjs/core";
9
+ import compression from "compression";
10
+ import helmet from "helmet";
11
+ import { AppModule } from "./app.module.js";
12
+ import { AllExceptionsFilter } from "./common/filters/all-exceptions.filter.js";
13
+ import { LoggingInterceptor } from "./common/interceptors/logging.interceptor.js";
14
+ async function bootstrap() {
15
+ const logger = new Logger('Bootstrap');
16
+ const app = await NestFactory.create(AppModule, {
17
+ logger: [
18
+ 'error',
19
+ 'warn',
20
+ 'log',
21
+ 'debug',
22
+ 'verbose'
23
+ ]
24
+ });
25
+ const configService = app.get(ConfigService);
26
+ // Security
27
+ app.use(helmet());
28
+ app.use(compression());
29
+ // CORS
30
+ const corsOrigins = configService.get('CORS_ORIGINS')?.split(',') || [
31
+ 'http://localhost:5173',
32
+ 'http://localhost:3000'
33
+ ];
34
+ app.enableCors({
35
+ origin: corsOrigins,
36
+ credentials: true,
37
+ methods: [
38
+ 'GET',
39
+ 'POST',
40
+ 'PUT',
41
+ 'DELETE',
42
+ 'PATCH',
43
+ 'OPTIONS'
44
+ ]
45
+ });
46
+ // Global prefix
47
+ app.setGlobalPrefix('api');
48
+ // Global pipes
49
+ app.useGlobalPipes(new ValidationPipe({
50
+ whitelist: true,
51
+ forbidNonWhitelisted: true,
52
+ transform: true,
53
+ transformOptions: {
54
+ enableImplicitConversion: true
55
+ }
56
+ }));
57
+ // Global filters
58
+ app.useGlobalFilters(new AllExceptionsFilter());
59
+ // Global interceptors
60
+ app.useGlobalInterceptors(new LoggingInterceptor());
61
+ const port = configService.get('PORT') || 3001;
62
+ await app.listen(port);
63
+ logger.log(`Application is running on: http://localhost:${port}`);
64
+ logger.log(`API available at: http://localhost:${port}/api`);
65
+ }
66
+ bootstrap();
67
+
68
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/main.ts"],"sourcesContent":["/**\n * NestJS Application Bootstrap\n *\n * Entry point for the Local MCP Gateway backend.\n * No authentication required - immediate access to all features.\n */\n\nimport { Logger, ValidationPipe } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { NestFactory } from '@nestjs/core';\nimport compression from 'compression';\nimport helmet from 'helmet';\nimport { AppModule } from './app.module.js';\nimport { AllExceptionsFilter } from './common/filters/all-exceptions.filter.js';\nimport { LoggingInterceptor } from './common/interceptors/logging.interceptor.js';\n\nasync function bootstrap() {\n const logger = new Logger('Bootstrap');\n const app = await NestFactory.create(AppModule, {\n logger: ['error', 'warn', 'log', 'debug', 'verbose'],\n });\n\n const configService = app.get(ConfigService);\n\n // Security\n app.use(helmet());\n app.use(compression());\n\n // CORS\n const corsOrigins = configService.get<string>('CORS_ORIGINS')?.split(',') || [\n 'http://localhost:5173',\n 'http://localhost:3000',\n ];\n app.enableCors({\n origin: corsOrigins,\n credentials: true,\n methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],\n });\n\n // Global prefix\n app.setGlobalPrefix('api');\n\n // Global pipes\n app.useGlobalPipes(\n new ValidationPipe({\n whitelist: true,\n forbidNonWhitelisted: true,\n transform: true,\n transformOptions: { enableImplicitConversion: true },\n })\n );\n\n // Global filters\n app.useGlobalFilters(new AllExceptionsFilter());\n\n // Global interceptors\n app.useGlobalInterceptors(new LoggingInterceptor());\n\n const port = configService.get<number>('PORT') || 3001;\n await app.listen(port);\n\n logger.log(`Application is running on: http://localhost:${port}`);\n logger.log(`API available at: http://localhost:${port}/api`);\n}\n\nbootstrap();\n"],"names":["Logger","ValidationPipe","ConfigService","NestFactory","compression","helmet","AppModule","AllExceptionsFilter","LoggingInterceptor","bootstrap","logger","app","create","configService","get","use","corsOrigins","split","enableCors","origin","credentials","methods","setGlobalPrefix","useGlobalPipes","whitelist","forbidNonWhitelisted","transform","transformOptions","enableImplicitConversion","useGlobalFilters","useGlobalInterceptors","port","listen","log"],"mappings":"AAAA;;;;;CAKC,GAED,SAASA,MAAM,EAAEC,cAAc,QAAQ,iBAAiB;AACxD,SAASC,aAAa,QAAQ,iBAAiB;AAC/C,SAASC,WAAW,QAAQ,eAAe;AAC3C,OAAOC,iBAAiB,cAAc;AACtC,OAAOC,YAAY,SAAS;AAC5B,SAASC,SAAS,QAAQ,kBAAkB;AAC5C,SAASC,mBAAmB,QAAQ,4CAA4C;AAChF,SAASC,kBAAkB,QAAQ,+CAA+C;AAElF,eAAeC;IACb,MAAMC,SAAS,IAAIV,OAAO;IAC1B,MAAMW,MAAM,MAAMR,YAAYS,MAAM,CAACN,WAAW;QAC9CI,QAAQ;YAAC;YAAS;YAAQ;YAAO;YAAS;SAAU;IACtD;IAEA,MAAMG,gBAAgBF,IAAIG,GAAG,CAACZ;IAE9B,WAAW;IACXS,IAAII,GAAG,CAACV;IACRM,IAAII,GAAG,CAACX;IAER,OAAO;IACP,MAAMY,cAAcH,cAAcC,GAAG,CAAS,iBAAiBG,MAAM,QAAQ;QAC3E;QACA;KACD;IACDN,IAAIO,UAAU,CAAC;QACbC,QAAQH;QACRI,aAAa;QACbC,SAAS;YAAC;YAAO;YAAQ;YAAO;YAAU;YAAS;SAAU;IAC/D;IAEA,gBAAgB;IAChBV,IAAIW,eAAe,CAAC;IAEpB,eAAe;IACfX,IAAIY,cAAc,CAChB,IAAItB,eAAe;QACjBuB,WAAW;QACXC,sBAAsB;QACtBC,WAAW;QACXC,kBAAkB;YAAEC,0BAA0B;QAAK;IACrD;IAGF,iBAAiB;IACjBjB,IAAIkB,gBAAgB,CAAC,IAAItB;IAEzB,sBAAsB;IACtBI,IAAImB,qBAAqB,CAAC,IAAItB;IAE9B,MAAMuB,OAAOlB,cAAcC,GAAG,CAAS,WAAW;IAClD,MAAMH,IAAIqB,MAAM,CAACD;IAEjBrB,OAAOuB,GAAG,CAAC,CAAC,4CAA4C,EAAEF,MAAM;IAChErB,OAAOuB,GAAG,CAAC,CAAC,mCAAmC,EAAEF,KAAK,IAAI,CAAC;AAC7D;AAEAtB"}
@@ -0,0 +1,27 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ /**
8
+ * Database Module
9
+ *
10
+ * Global module providing Prisma client for database operations.
11
+ */ import { Global, Module } from "@nestjs/common";
12
+ import { PrismaService } from "./prisma.service.js";
13
+ export class DatabaseModule {
14
+ }
15
+ DatabaseModule = _ts_decorate([
16
+ Global(),
17
+ Module({
18
+ providers: [
19
+ PrismaService
20
+ ],
21
+ exports: [
22
+ PrismaService
23
+ ]
24
+ })
25
+ ], DatabaseModule);
26
+
27
+ //# sourceMappingURL=database.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/modules/database/database.module.ts"],"sourcesContent":["/**\n * Database Module\n *\n * Global module providing Prisma client for database operations.\n */\n\nimport { Global, Module } from '@nestjs/common';\nimport { PrismaService } from './prisma.service.js';\n\n@Global()\n@Module({\n providers: [PrismaService],\n exports: [PrismaService],\n})\nexport class DatabaseModule {}\n"],"names":["Global","Module","PrismaService","DatabaseModule","providers","exports"],"mappings":";;;;;;AAAA;;;;CAIC,GAED,SAASA,MAAM,EAAEC,MAAM,QAAQ,iBAAiB;AAChD,SAASC,aAAa,QAAQ,sBAAsB;AAOpD,OAAO,MAAMC;AAAgB;;;;QAH3BC,WAAW;YAACF;SAAc;QAC1BG,SAAS;YAACH;SAAc"}
@@ -0,0 +1,122 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ function _ts_metadata(k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ }
10
+ /**
11
+ * Prisma Service
12
+ *
13
+ * NestJS service wrapping Prisma Client with lifecycle management.
14
+ */ import { createPrismaAdapter } from "@dxheroes/local-mcp-database";
15
+ import { PrismaClient } from "@dxheroes/local-mcp-database/generated/prisma";
16
+ import { Injectable, Logger } from "@nestjs/common";
17
+ export class PrismaService extends PrismaClient {
18
+ constructor(){
19
+ super({
20
+ adapter: createPrismaAdapter(),
21
+ log: process.env.NODE_ENV === 'development' ? [
22
+ {
23
+ emit: 'event',
24
+ level: 'query'
25
+ },
26
+ {
27
+ emit: 'stdout',
28
+ level: 'info'
29
+ },
30
+ {
31
+ emit: 'stdout',
32
+ level: 'warn'
33
+ },
34
+ {
35
+ emit: 'stdout',
36
+ level: 'error'
37
+ }
38
+ ] : [
39
+ {
40
+ emit: 'stdout',
41
+ level: 'error'
42
+ }
43
+ ]
44
+ }), this.logger = new Logger(PrismaService.name);
45
+ }
46
+ async onModuleInit() {
47
+ this.logger.log('Connecting to database...');
48
+ await this.$connect();
49
+ this.logger.log('Database connected');
50
+ // Seed default data on first run
51
+ await this.seedDefaultData();
52
+ }
53
+ /**
54
+ * Seed default data if database is empty (first run only)
55
+ * Only seeds if no profiles exist - respects user data
56
+ */ async seedDefaultData() {
57
+ // Check if any profiles exist - if so, user has data, don't seed
58
+ const profileCount = await this.profile.count();
59
+ if (profileCount > 0) {
60
+ this.logger.debug('Database has existing data, skipping seed');
61
+ return;
62
+ }
63
+ this.logger.log('First run detected, seeding default data...');
64
+ // Create default profile
65
+ const defaultProfile = await this.profile.create({
66
+ data: {
67
+ name: 'default',
68
+ description: 'Default MCP profile for general use'
69
+ }
70
+ });
71
+ this.logger.log(`Created default profile: ${defaultProfile.id}`);
72
+ // Create Context7 MCP server
73
+ const context7 = await this.mcpServer.create({
74
+ data: {
75
+ name: 'Context7',
76
+ type: 'remote_http',
77
+ config: JSON.stringify({
78
+ url: 'https://mcp.context7.com/mcp'
79
+ })
80
+ }
81
+ });
82
+ this.logger.log(`Created Context7 MCP server: ${context7.id}`);
83
+ // Link Context7 to default profile
84
+ await this.profileMcpServer.create({
85
+ data: {
86
+ profileId: defaultProfile.id,
87
+ mcpServerId: context7.id,
88
+ order: 0
89
+ }
90
+ });
91
+ this.logger.log('Linked Context7 to default profile');
92
+ this.logger.log('Default data seeding complete');
93
+ }
94
+ async onModuleDestroy() {
95
+ this.logger.log('Disconnecting from database...');
96
+ await this.$disconnect();
97
+ this.logger.log('Database disconnected');
98
+ }
99
+ /**
100
+ * Clean database (for testing only)
101
+ */ async cleanDatabase() {
102
+ if (process.env.NODE_ENV !== 'test') {
103
+ throw new Error('cleanDatabase can only be called in test environment');
104
+ }
105
+ const tablenames = await this.$queryRaw`
106
+ SELECT name FROM sqlite_master
107
+ WHERE type='table'
108
+ AND name NOT LIKE '_prisma%'
109
+ AND name NOT LIKE 'sqlite%'
110
+ `;
111
+ for (const { name } of tablenames){
112
+ await this.$executeRawUnsafe(`DELETE FROM "${name}"`);
113
+ }
114
+ }
115
+ }
116
+ PrismaService = _ts_decorate([
117
+ Injectable(),
118
+ _ts_metadata("design:type", Function),
119
+ _ts_metadata("design:paramtypes", [])
120
+ ], PrismaService);
121
+
122
+ //# sourceMappingURL=prisma.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/modules/database/prisma.service.ts"],"sourcesContent":["/**\n * Prisma Service\n *\n * NestJS service wrapping Prisma Client with lifecycle management.\n */\n\nimport { createPrismaAdapter } from '@dxheroes/local-mcp-database';\nimport { PrismaClient } from '@dxheroes/local-mcp-database/generated/prisma';\nimport { Injectable, Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/common';\n\n@Injectable()\nexport class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger(PrismaService.name);\n\n constructor() {\n super({\n adapter: createPrismaAdapter(),\n log:\n process.env.NODE_ENV === 'development'\n ? [\n { emit: 'event', level: 'query' },\n { emit: 'stdout', level: 'info' },\n { emit: 'stdout', level: 'warn' },\n { emit: 'stdout', level: 'error' },\n ]\n : [{ emit: 'stdout', level: 'error' }],\n });\n }\n\n async onModuleInit() {\n this.logger.log('Connecting to database...');\n await this.$connect();\n this.logger.log('Database connected');\n\n // Seed default data on first run\n await this.seedDefaultData();\n }\n\n /**\n * Seed default data if database is empty (first run only)\n * Only seeds if no profiles exist - respects user data\n */\n private async seedDefaultData() {\n // Check if any profiles exist - if so, user has data, don't seed\n const profileCount = await this.profile.count();\n if (profileCount > 0) {\n this.logger.debug('Database has existing data, skipping seed');\n return;\n }\n\n this.logger.log('First run detected, seeding default data...');\n\n // Create default profile\n const defaultProfile = await this.profile.create({\n data: {\n name: 'default',\n description: 'Default MCP profile for general use',\n },\n });\n this.logger.log(`Created default profile: ${defaultProfile.id}`);\n\n // Create Context7 MCP server\n const context7 = await this.mcpServer.create({\n data: {\n name: 'Context7',\n type: 'remote_http',\n config: JSON.stringify({ url: 'https://mcp.context7.com/mcp' }),\n },\n });\n this.logger.log(`Created Context7 MCP server: ${context7.id}`);\n\n // Link Context7 to default profile\n await this.profileMcpServer.create({\n data: {\n profileId: defaultProfile.id,\n mcpServerId: context7.id,\n order: 0,\n },\n });\n this.logger.log('Linked Context7 to default profile');\n\n this.logger.log('Default data seeding complete');\n }\n\n async onModuleDestroy() {\n this.logger.log('Disconnecting from database...');\n await this.$disconnect();\n this.logger.log('Database disconnected');\n }\n\n /**\n * Clean database (for testing only)\n */\n async cleanDatabase() {\n if (process.env.NODE_ENV !== 'test') {\n throw new Error('cleanDatabase can only be called in test environment');\n }\n\n const tablenames = await this.$queryRaw<Array<{ name: string }>>`\n SELECT name FROM sqlite_master\n WHERE type='table'\n AND name NOT LIKE '_prisma%'\n AND name NOT LIKE 'sqlite%'\n `;\n\n for (const { name } of tablenames) {\n await this.$executeRawUnsafe(`DELETE FROM \"${name}\"`);\n }\n }\n}\n"],"names":["createPrismaAdapter","PrismaClient","Injectable","Logger","PrismaService","adapter","log","process","env","NODE_ENV","emit","level","logger","name","onModuleInit","$connect","seedDefaultData","profileCount","profile","count","debug","defaultProfile","create","data","description","id","context7","mcpServer","type","config","JSON","stringify","url","profileMcpServer","profileId","mcpServerId","order","onModuleDestroy","$disconnect","cleanDatabase","Error","tablenames","$queryRaw","$executeRawUnsafe"],"mappings":";;;;;;;;;AAAA;;;;CAIC,GAED,SAASA,mBAAmB,QAAQ,+BAA+B;AACnE,SAASC,YAAY,QAAQ,gDAAgD;AAC7E,SAASC,UAAU,EAAEC,MAAM,QAAuC,iBAAiB;AAGnF,OAAO,MAAMC,sBAAsBH;IAGjC,aAAc;QACZ,KAAK,CAAC;YACJI,SAASL;YACTM,KACEC,QAAQC,GAAG,CAACC,QAAQ,KAAK,gBACrB;gBACE;oBAAEC,MAAM;oBAASC,OAAO;gBAAQ;gBAChC;oBAAED,MAAM;oBAAUC,OAAO;gBAAO;gBAChC;oBAAED,MAAM;oBAAUC,OAAO;gBAAO;gBAChC;oBAAED,MAAM;oBAAUC,OAAO;gBAAQ;aAClC,GACD;gBAAC;oBAAED,MAAM;oBAAUC,OAAO;gBAAQ;aAAE;QAC5C,SAdeC,SAAS,IAAIT,OAAOC,cAAcS,IAAI;IAevD;IAEA,MAAMC,eAAe;QACnB,IAAI,CAACF,MAAM,CAACN,GAAG,CAAC;QAChB,MAAM,IAAI,CAACS,QAAQ;QACnB,IAAI,CAACH,MAAM,CAACN,GAAG,CAAC;QAEhB,iCAAiC;QACjC,MAAM,IAAI,CAACU,eAAe;IAC5B;IAEA;;;GAGC,GACD,MAAcA,kBAAkB;QAC9B,iEAAiE;QACjE,MAAMC,eAAe,MAAM,IAAI,CAACC,OAAO,CAACC,KAAK;QAC7C,IAAIF,eAAe,GAAG;YACpB,IAAI,CAACL,MAAM,CAACQ,KAAK,CAAC;YAClB;QACF;QAEA,IAAI,CAACR,MAAM,CAACN,GAAG,CAAC;QAEhB,yBAAyB;QACzB,MAAMe,iBAAiB,MAAM,IAAI,CAACH,OAAO,CAACI,MAAM,CAAC;YAC/CC,MAAM;gBACJV,MAAM;gBACNW,aAAa;YACf;QACF;QACA,IAAI,CAACZ,MAAM,CAACN,GAAG,CAAC,CAAC,yBAAyB,EAAEe,eAAeI,EAAE,EAAE;QAE/D,6BAA6B;QAC7B,MAAMC,WAAW,MAAM,IAAI,CAACC,SAAS,CAACL,MAAM,CAAC;YAC3CC,MAAM;gBACJV,MAAM;gBACNe,MAAM;gBACNC,QAAQC,KAAKC,SAAS,CAAC;oBAAEC,KAAK;gBAA+B;YAC/D;QACF;QACA,IAAI,CAACpB,MAAM,CAACN,GAAG,CAAC,CAAC,6BAA6B,EAAEoB,SAASD,EAAE,EAAE;QAE7D,mCAAmC;QACnC,MAAM,IAAI,CAACQ,gBAAgB,CAACX,MAAM,CAAC;YACjCC,MAAM;gBACJW,WAAWb,eAAeI,EAAE;gBAC5BU,aAAaT,SAASD,EAAE;gBACxBW,OAAO;YACT;QACF;QACA,IAAI,CAACxB,MAAM,CAACN,GAAG,CAAC;QAEhB,IAAI,CAACM,MAAM,CAACN,GAAG,CAAC;IAClB;IAEA,MAAM+B,kBAAkB;QACtB,IAAI,CAACzB,MAAM,CAACN,GAAG,CAAC;QAChB,MAAM,IAAI,CAACgC,WAAW;QACtB,IAAI,CAAC1B,MAAM,CAACN,GAAG,CAAC;IAClB;IAEA;;GAEC,GACD,MAAMiC,gBAAgB;QACpB,IAAIhC,QAAQC,GAAG,CAACC,QAAQ,KAAK,QAAQ;YACnC,MAAM,IAAI+B,MAAM;QAClB;QAEA,MAAMC,aAAa,MAAM,IAAI,CAACC,SAAS,AAAyB,CAAC;;;;;IAKjE,CAAC;QAED,KAAK,MAAM,EAAE7B,IAAI,EAAE,IAAI4B,WAAY;YACjC,MAAM,IAAI,CAACE,iBAAiB,CAAC,CAAC,aAAa,EAAE9B,KAAK,CAAC,CAAC;QACtD;IACF;AACF"}
@@ -0,0 +1,87 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ function _ts_metadata(k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ }
10
+ function _ts_param(paramIndex, decorator) {
11
+ return function(target, key) {
12
+ decorator(target, key, paramIndex);
13
+ };
14
+ }
15
+ /**
16
+ * Debug Controller
17
+ *
18
+ * REST API endpoints for debug log management.
19
+ */ import { Controller, Delete, Get, HttpCode, HttpStatus, Query } from "@nestjs/common";
20
+ import { DebugService } from "./debug.service.js";
21
+ export class DebugController {
22
+ constructor(debugService){
23
+ this.debugService = debugService;
24
+ }
25
+ /**
26
+ * Get debug logs with optional filters
27
+ */ async getLogs(profileId, mcpServerId, status, since, until, limit, offset) {
28
+ const filter = {
29
+ profileId,
30
+ mcpServerId,
31
+ status,
32
+ since: since ? new Date(since) : undefined,
33
+ until: until ? new Date(until) : undefined
34
+ };
35
+ return this.debugService.getLogs(filter, limit ? Number.parseInt(limit, 10) : 100, offset ? Number.parseInt(offset, 10) : 0);
36
+ }
37
+ /**
38
+ * Clear debug logs
39
+ */ async clearLogs(profileId, mcpServerId) {
40
+ await this.debugService.clearLogs({
41
+ profileId,
42
+ mcpServerId
43
+ });
44
+ }
45
+ }
46
+ _ts_decorate([
47
+ Get('logs'),
48
+ _ts_param(0, Query('profileId')),
49
+ _ts_param(1, Query('mcpServerId')),
50
+ _ts_param(2, Query('status')),
51
+ _ts_param(3, Query('since')),
52
+ _ts_param(4, Query('until')),
53
+ _ts_param(5, Query('limit')),
54
+ _ts_param(6, Query('offset')),
55
+ _ts_metadata("design:type", Function),
56
+ _ts_metadata("design:paramtypes", [
57
+ String,
58
+ String,
59
+ String,
60
+ String,
61
+ String,
62
+ String,
63
+ String
64
+ ]),
65
+ _ts_metadata("design:returntype", Promise)
66
+ ], DebugController.prototype, "getLogs", null);
67
+ _ts_decorate([
68
+ Delete('logs'),
69
+ HttpCode(HttpStatus.NO_CONTENT),
70
+ _ts_param(0, Query('profileId')),
71
+ _ts_param(1, Query('mcpServerId')),
72
+ _ts_metadata("design:type", Function),
73
+ _ts_metadata("design:paramtypes", [
74
+ String,
75
+ String
76
+ ]),
77
+ _ts_metadata("design:returntype", Promise)
78
+ ], DebugController.prototype, "clearLogs", null);
79
+ DebugController = _ts_decorate([
80
+ Controller('debug'),
81
+ _ts_metadata("design:type", Function),
82
+ _ts_metadata("design:paramtypes", [
83
+ typeof DebugService === "undefined" ? Object : DebugService
84
+ ])
85
+ ], DebugController);
86
+
87
+ //# sourceMappingURL=debug.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/modules/debug/debug.controller.ts"],"sourcesContent":["/**\n * Debug Controller\n *\n * REST API endpoints for debug log management.\n */\n\nimport { Controller, Delete, Get, HttpCode, HttpStatus, Query } from '@nestjs/common';\nimport { DebugService } from './debug.service.js';\n\n@Controller('debug')\nexport class DebugController {\n constructor(private readonly debugService: DebugService) {}\n\n /**\n * Get debug logs with optional filters\n */\n @Get('logs')\n async getLogs(\n @Query('profileId') profileId?: string,\n @Query('mcpServerId') mcpServerId?: string,\n @Query('status') status?: 'pending' | 'success' | 'error',\n @Query('since') since?: string,\n @Query('until') until?: string,\n @Query('limit') limit?: string,\n @Query('offset') offset?: string\n ) {\n const filter = {\n profileId,\n mcpServerId,\n status,\n since: since ? new Date(since) : undefined,\n until: until ? new Date(until) : undefined,\n };\n\n return this.debugService.getLogs(\n filter,\n limit ? Number.parseInt(limit, 10) : 100,\n offset ? Number.parseInt(offset, 10) : 0\n );\n }\n\n /**\n * Clear debug logs\n */\n @Delete('logs')\n @HttpCode(HttpStatus.NO_CONTENT)\n async clearLogs(\n @Query('profileId') profileId?: string,\n @Query('mcpServerId') mcpServerId?: string\n ) {\n await this.debugService.clearLogs({ profileId, mcpServerId });\n }\n}\n"],"names":["Controller","Delete","Get","HttpCode","HttpStatus","Query","DebugService","DebugController","debugService","getLogs","profileId","mcpServerId","status","since","until","limit","offset","filter","Date","undefined","Number","parseInt","clearLogs","NO_CONTENT"],"mappings":";;;;;;;;;;;;;;AAAA;;;;CAIC,GAED,SAASA,UAAU,EAAEC,MAAM,EAAEC,GAAG,EAAEC,QAAQ,EAAEC,UAAU,EAAEC,KAAK,QAAQ,iBAAiB;AACtF,SAASC,YAAY,QAAQ,qBAAqB;AAGlD,OAAO,MAAMC;IACX,YAAY,AAAiBC,YAA0B,CAAE;aAA5BA,eAAAA;IAA6B;IAE1D;;GAEC,GACD,MACMC,QACJ,AAAoBC,SAAkB,EACtC,AAAsBC,WAAoB,EAC1C,AAAiBC,MAAwC,EACzD,AAAgBC,KAAc,EAC9B,AAAgBC,KAAc,EAC9B,AAAgBC,KAAc,EAC9B,AAAiBC,MAAe,EAChC;QACA,MAAMC,SAAS;YACbP;YACAC;YACAC;YACAC,OAAOA,QAAQ,IAAIK,KAAKL,SAASM;YACjCL,OAAOA,QAAQ,IAAII,KAAKJ,SAASK;QACnC;QAEA,OAAO,IAAI,CAACX,YAAY,CAACC,OAAO,CAC9BQ,QACAF,QAAQK,OAAOC,QAAQ,CAACN,OAAO,MAAM,KACrCC,SAASI,OAAOC,QAAQ,CAACL,QAAQ,MAAM;IAE3C;IAEA;;GAEC,GACD,MAEMM,UACJ,AAAoBZ,SAAkB,EACtC,AAAsBC,WAAoB,EAC1C;QACA,MAAM,IAAI,CAACH,YAAY,CAACc,SAAS,CAAC;YAAEZ;YAAWC;QAAY;IAC7D;AACF;;;;;;;;;;;;;;;;;;;;;;;;wBAPuBY"}
@@ -0,0 +1,30 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ /**
8
+ * Debug Module
9
+ *
10
+ * Debug logging endpoints for MCP traffic inspection.
11
+ */ import { Module } from "@nestjs/common";
12
+ import { DebugController } from "./debug.controller.js";
13
+ import { DebugService } from "./debug.service.js";
14
+ export class DebugModule {
15
+ }
16
+ DebugModule = _ts_decorate([
17
+ Module({
18
+ controllers: [
19
+ DebugController
20
+ ],
21
+ providers: [
22
+ DebugService
23
+ ],
24
+ exports: [
25
+ DebugService
26
+ ]
27
+ })
28
+ ], DebugModule);
29
+
30
+ //# sourceMappingURL=debug.module.js.map