@mcp-guardian/server 0.3.0 → 0.5.0

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 (101) hide show
  1. package/README.md +362 -136
  2. package/dist/auth/auth-types.d.ts +40 -0
  3. package/dist/auth/auth-types.d.ts.map +1 -0
  4. package/dist/auth/auth-types.js +5 -0
  5. package/dist/auth/auth-types.js.map +1 -0
  6. package/dist/auth/dashboard-auth.d.ts +97 -0
  7. package/dist/auth/dashboard-auth.d.ts.map +1 -0
  8. package/dist/auth/dashboard-auth.js +319 -0
  9. package/dist/auth/dashboard-auth.js.map +1 -0
  10. package/dist/auth/dpop.d.ts +38 -0
  11. package/dist/auth/dpop.d.ts.map +1 -0
  12. package/dist/auth/dpop.js +72 -0
  13. package/dist/auth/dpop.js.map +1 -0
  14. package/dist/auth/oauth.d.ts +25 -0
  15. package/dist/auth/oauth.d.ts.map +1 -0
  16. package/dist/auth/oauth.js +96 -0
  17. package/dist/auth/oauth.js.map +1 -0
  18. package/dist/auth/redis-session-cache.d.ts +21 -0
  19. package/dist/auth/redis-session-cache.d.ts.map +1 -0
  20. package/dist/auth/redis-session-cache.js +74 -0
  21. package/dist/auth/redis-session-cache.js.map +1 -0
  22. package/dist/auth/session-cache.d.ts +47 -0
  23. package/dist/auth/session-cache.d.ts.map +1 -0
  24. package/dist/auth/session-cache.js +91 -0
  25. package/dist/auth/session-cache.js.map +1 -0
  26. package/dist/cli.js +48 -3
  27. package/dist/cli.js.map +1 -1
  28. package/dist/database/database-interface.d.ts +17 -0
  29. package/dist/database/database-interface.d.ts.map +1 -0
  30. package/dist/database/database-interface.js +2 -0
  31. package/dist/database/database-interface.js.map +1 -0
  32. package/dist/database/postgres-db.d.ts +18 -0
  33. package/dist/database/postgres-db.d.ts.map +1 -0
  34. package/dist/database/postgres-db.js +118 -0
  35. package/dist/database/postgres-db.js.map +1 -0
  36. package/dist/index.js +1 -1
  37. package/dist/policy/policy-engine.d.ts +19 -0
  38. package/dist/policy/policy-engine.d.ts.map +1 -0
  39. package/dist/policy/policy-engine.js +87 -0
  40. package/dist/policy/policy-engine.js.map +1 -0
  41. package/dist/policy/policy-types.d.ts +42 -0
  42. package/dist/policy/policy-types.d.ts.map +1 -0
  43. package/dist/policy/policy-types.js +5 -0
  44. package/dist/policy/policy-types.js.map +1 -0
  45. package/dist/policy/policy-watcher.d.ts +24 -0
  46. package/dist/policy/policy-watcher.d.ts.map +1 -0
  47. package/dist/policy/policy-watcher.js +68 -0
  48. package/dist/policy/policy-watcher.js.map +1 -0
  49. package/dist/policy/shell-tokenizer.d.ts +92 -0
  50. package/dist/policy/shell-tokenizer.d.ts.map +1 -0
  51. package/dist/policy/shell-tokenizer.js +300 -0
  52. package/dist/policy/shell-tokenizer.js.map +1 -0
  53. package/dist/proxy/http-proxy-server.d.ts +26 -0
  54. package/dist/proxy/http-proxy-server.d.ts.map +1 -0
  55. package/dist/proxy/http-proxy-server.js +172 -0
  56. package/dist/proxy/http-proxy-server.js.map +1 -0
  57. package/dist/proxy/proxy-manager.d.ts +5 -1
  58. package/dist/proxy/proxy-manager.d.ts.map +1 -1
  59. package/dist/proxy/proxy-manager.js +12 -3
  60. package/dist/proxy/proxy-manager.js.map +1 -1
  61. package/dist/proxy/proxy-server.d.ts +20 -5
  62. package/dist/proxy/proxy-server.d.ts.map +1 -1
  63. package/dist/proxy/proxy-server.js +126 -9
  64. package/dist/proxy/proxy-server.js.map +1 -1
  65. package/dist/utils/circuit-breaker.d.ts +29 -0
  66. package/dist/utils/circuit-breaker.d.ts.map +1 -0
  67. package/dist/utils/circuit-breaker.js +81 -0
  68. package/dist/utils/circuit-breaker.js.map +1 -0
  69. package/dist/utils/dashboard-server.d.ts +19 -0
  70. package/dist/utils/dashboard-server.d.ts.map +1 -0
  71. package/dist/utils/dashboard-server.js +258 -0
  72. package/dist/utils/dashboard-server.js.map +1 -0
  73. package/dist/utils/metrics.d.ts +17 -0
  74. package/dist/utils/metrics.d.ts.map +1 -0
  75. package/dist/utils/metrics.js +79 -0
  76. package/dist/utils/metrics.js.map +1 -0
  77. package/dist/utils/mtls-config.d.ts +27 -0
  78. package/dist/utils/mtls-config.d.ts.map +1 -0
  79. package/dist/utils/mtls-config.js +82 -0
  80. package/dist/utils/mtls-config.js.map +1 -0
  81. package/dist/utils/payload-normalizer.d.ts +62 -0
  82. package/dist/utils/payload-normalizer.d.ts.map +1 -0
  83. package/dist/utils/payload-normalizer.js +240 -0
  84. package/dist/utils/payload-normalizer.js.map +1 -0
  85. package/dist/utils/policy-auditor.d.ts +24 -0
  86. package/dist/utils/policy-auditor.d.ts.map +1 -0
  87. package/dist/utils/policy-auditor.js +58 -0
  88. package/dist/utils/policy-auditor.js.map +1 -0
  89. package/dist/utils/redis-rate-limiter.d.ts +22 -0
  90. package/dist/utils/redis-rate-limiter.d.ts.map +1 -0
  91. package/dist/utils/redis-rate-limiter.js +61 -0
  92. package/dist/utils/redis-rate-limiter.js.map +1 -0
  93. package/dist/utils/structured-logger.d.ts +47 -0
  94. package/dist/utils/structured-logger.d.ts.map +1 -0
  95. package/dist/utils/structured-logger.js +48 -0
  96. package/dist/utils/structured-logger.js.map +1 -0
  97. package/dist/utils/tracing.d.ts +7 -0
  98. package/dist/utils/tracing.d.ts.map +1 -0
  99. package/dist/utils/tracing.js +34 -0
  100. package/dist/utils/tracing.js.map +1 -0
  101. package/package.json +14 -8
@@ -1 +1 @@
1
- {"version":3,"file":"proxy-server.d.ts","sourceRoot":"","sources":["../../src/proxy/proxy-server.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAG5D;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,EAAE,CAAkB;IAC5B,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,UAAU,CAAS;gBAGzB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,EAAE,EAAE,eAAe,EACnB,UAAU,CAAC,EAAE,MAAM;IAarB,IAAI,KAAK,IAAI,MAAM,CAAC,cAAc,GAAG,IAAI,CAExC;IAED,OAAO,CAAC,WAAW;IAqCnB,OAAO,CAAC,WAAW;IAMnB;;;OAGG;IACH,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAepC,IAAI,IAAI,IAAI;CAOb"}
1
+ {"version":3,"file":"proxy-server.d.ts","sourceRoot":"","sources":["../../src/proxy/proxy-server.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG1D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlD;;;;;;;GAOG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,EAAE,CAAkB;IAC5B,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,gBAAgB,CAAsC;IAC9D,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,aAAa,CAAwB;gBAG3C,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,EAAE,EAAE,eAAe,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,YAAY,EAC3B,aAAa,CAAC,EAAE,cAAc;IAsBhC,IAAI,KAAK,IAAI,MAAM,CAAC,cAAc,GAAG,IAAI,CAExC;IAED,OAAO,CAAC,WAAW;IAiCnB,OAAO,CAAC,WAAW;IAMnB;;OAEG;IACH,OAAO,CAAC,SAAS;IASjB;;;;;OAKG;IACG,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmHnD,IAAI,IAAI,IAAI;CAOb"}
@@ -2,9 +2,15 @@ import { spawn } from 'child_process';
2
2
  import { createInterface } from 'readline';
3
3
  import { TokenCounter } from '../utils/token-counter.js';
4
4
  import { Logger } from '../utils/logger.js';
5
+ import { StructuredLogger } from '../utils/structured-logger.js';
6
+ import { OAuthValidator } from '../auth/oauth.js';
5
7
  /**
6
- * MCP Proxy Interceptor — sits between the AI client and an MCP server,
7
- * capturing every JSON-RPC call's token usage for real cost auditing.
8
+ * MCP Proxy Interceptor — sits between the AI client and an MCP server.
9
+ *
10
+ * v0.4: Integrated PolicyEngine for active blocking of malicious tool calls.
11
+ * v0.5: OAuth 2.1 JWT validation — validates bearer tokens before policy evaluation.
12
+ * If authValidator is provided, every tools/call requires a valid JWT.
13
+ * Unauthenticated calls are blocked with a JSON-RPC auth error.
8
14
  */
9
15
  export class McpProxyServer {
10
16
  child;
@@ -14,9 +20,14 @@ export class McpProxyServer {
14
20
  requestStartTime = 0;
15
21
  requestToolName = null;
16
22
  requestTokens = 0;
23
+ requestArguments;
17
24
  serverName;
18
- constructor(command, args, env, db, serverName) {
25
+ policyEngine;
26
+ authValidator;
27
+ constructor(command, args, env, db, serverName, policyEngine, authValidator) {
19
28
  this.serverName = serverName || command.split('/').pop() || command;
29
+ this.policyEngine = policyEngine || null;
30
+ this.authValidator = authValidator || null;
20
31
  this.child = spawn(command, args, {
21
32
  env: { ...process.env, ...env },
22
33
  stdio: ['pipe', 'pipe', 'pipe'],
@@ -25,6 +36,12 @@ export class McpProxyServer {
25
36
  this.db = db;
26
37
  this.setupStdout();
27
38
  this.setupStderr();
39
+ StructuredLogger.info({
40
+ event: 'proxy_started',
41
+ serverName: this.serverName,
42
+ blockingMode: this.policyEngine ? this.policyEngine.getMode() : 'audit',
43
+ authEnabled: this.authValidator ? this.authValidator.getConfig().required : false,
44
+ });
28
45
  }
29
46
  get stdin() {
30
47
  return this.child.stdin;
@@ -35,7 +52,6 @@ export class McpProxyServer {
35
52
  try {
36
53
  const msg = JSON.parse(line);
37
54
  if (msg.id && msg.id === this.currentRequestId) {
38
- // Response to our tracked tools/call request
39
55
  const responseTokens = this.tokenCounter.count(line);
40
56
  const record = {
41
57
  serverName: this.serverName,
@@ -46,16 +62,13 @@ export class McpProxyServer {
46
62
  durationMs: Date.now() - this.requestStartTime,
47
63
  timestamp: new Date().toISOString(),
48
64
  };
49
- // Await the DB write so tests can read immediately
50
65
  this.db.addCallRecord(record).then(() => this.db.flush()).catch((err) => Logger.debug(`Proxy: failed to store call record: ${err?.message}`));
51
66
  this.currentRequestId = null;
52
67
  this.requestToolName = null;
53
68
  }
54
- // Forward response to client
55
69
  process.stdout.write(line + '\n');
56
70
  }
57
71
  catch {
58
- // Non-JSON line — forward as-is
59
72
  process.stdout.write(line + '\n');
60
73
  }
61
74
  });
@@ -68,11 +81,24 @@ export class McpProxyServer {
68
81
  process.stderr.write(data);
69
82
  });
70
83
  }
84
+ /**
85
+ * Send a JSON-RPC 2.0 error response to the client.
86
+ */
87
+ sendError(id, code, message, data) {
88
+ const errorResponse = JSON.stringify({
89
+ jsonrpc: '2.0',
90
+ id,
91
+ error: { code, message, data },
92
+ });
93
+ process.stdout.write(errorResponse + '\n');
94
+ }
71
95
  /**
72
96
  * Called when the AI client writes a request to be proxied.
73
- * Tracks tools/call requests for token counting.
97
+ * 1. Validate OAuth 2.1 JWT (if configured)
98
+ * 2. Evaluate against policy engine
99
+ * 3. Forward or block
74
100
  */
75
- handleClientInput(raw) {
101
+ async handleClientInput(raw) {
76
102
  try {
77
103
  const msg = JSON.parse(raw);
78
104
  if (msg.method === 'tools/call' && msg.id) {
@@ -80,6 +106,97 @@ export class McpProxyServer {
80
106
  this.currentRequestId = msg.id;
81
107
  this.requestToolName = msg.params?.name || 'unknown';
82
108
  this.requestTokens = this.tokenCounter.count(raw);
109
+ this.requestArguments = msg.params?.arguments;
110
+ const toolName = this.requestToolName || 'unknown';
111
+ // ── v0.5: OAuth 2.1 JWT validation ──────────────────
112
+ if (this.authValidator) {
113
+ const authHeader = msg.params?._meta?.auth?.Authorization
114
+ || msg.Authorization
115
+ || msg.params?.Authorization
116
+ || undefined;
117
+ const token = OAuthValidator.extractToken(authHeader);
118
+ if (!token) {
119
+ if (this.authValidator.getConfig().required) {
120
+ StructuredLogger.info({
121
+ event: 'auth_required',
122
+ serverName: this.serverName,
123
+ toolName,
124
+ requestId: msg.id,
125
+ });
126
+ this.sendError(msg.id, -32002, 'Authentication required. Provide a valid Bearer token in the Authorization header.');
127
+ this.currentRequestId = null;
128
+ this.requestToolName = null;
129
+ this.requestArguments = undefined;
130
+ return;
131
+ }
132
+ }
133
+ else {
134
+ const result = await this.authValidator.validate(token);
135
+ if (!result.valid) {
136
+ StructuredLogger.logError({
137
+ event: 'oidc_auth_error',
138
+ serverName: this.serverName,
139
+ error: `JWT validation failed: ${result.error}`,
140
+ requestId: msg.id,
141
+ });
142
+ if (this.authValidator.getConfig().required) {
143
+ this.sendError(msg.id, -32003, `Authentication failed: ${result.error}`);
144
+ this.currentRequestId = null;
145
+ this.requestToolName = null;
146
+ this.requestArguments = undefined;
147
+ return;
148
+ }
149
+ }
150
+ else {
151
+ StructuredLogger.info({
152
+ event: 'auth_success',
153
+ serverName: this.serverName,
154
+ toolName,
155
+ requestId: msg.id,
156
+ agent: result.identity?.sub,
157
+ clientId: result.identity?.clientId,
158
+ });
159
+ }
160
+ }
161
+ }
162
+ // ── v0.4: Active policy enforcement ──────────────────
163
+ if (this.policyEngine) {
164
+ const context = {
165
+ serverName: this.serverName,
166
+ toolName,
167
+ arguments: this.requestArguments,
168
+ requestId: msg.id,
169
+ requestTokens: this.requestTokens,
170
+ timestamp: new Date().toISOString(),
171
+ };
172
+ const decision = this.policyEngine.evaluate(context);
173
+ StructuredLogger.logPolicyDecision({
174
+ event: 'policy_decision',
175
+ requestId: msg.id,
176
+ serverName: this.serverName,
177
+ toolName,
178
+ decision,
179
+ context,
180
+ });
181
+ if (decision.action === 'block') {
182
+ StructuredLogger.logBlocked({
183
+ event: 'tool_blocked',
184
+ requestId: msg.id,
185
+ serverName: this.serverName,
186
+ toolName,
187
+ reason: decision.reason,
188
+ rule: decision.rule,
189
+ });
190
+ this.sendError(msg.id, -32001, `Blocked by MCP Guardian policy: ${decision.reason}`, {
191
+ rule: decision.rule,
192
+ policy: this.policyEngine.getMode(),
193
+ });
194
+ this.currentRequestId = null;
195
+ this.requestToolName = null;
196
+ this.requestArguments = undefined;
197
+ return;
198
+ }
199
+ }
83
200
  }
84
201
  }
85
202
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"proxy-server.js","sourceRoot":"","sources":["../../src/proxy/proxy-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"proxy-server.js","sourceRoot":"","sources":["../../src/proxy/proxy-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';
2
+ export declare class CircuitBreaker {
3
+ private state;
4
+ private failureCount;
5
+ private successCount;
6
+ private lastFailureTime;
7
+ private readonly resetTimeout;
8
+ private readonly failureThreshold;
9
+ private readonly successThreshold;
10
+ private readonly name;
11
+ constructor(name: string, options?: {
12
+ failureThreshold?: number;
13
+ successThreshold?: number;
14
+ resetTimeoutMs?: number;
15
+ });
16
+ /** Check if the circuit allows a request through */
17
+ allowRequest(): boolean;
18
+ /** Record a successful request */
19
+ recordSuccess(): void;
20
+ /** Record a failed request */
21
+ recordFailure(): void;
22
+ getState(): CircuitState;
23
+ getStats(): {
24
+ state: CircuitState;
25
+ failureCount: number;
26
+ successCount: number;
27
+ };
28
+ }
29
+ //# sourceMappingURL=circuit-breaker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.d.ts","sourceRoot":"","sources":["../../src/utils/circuit-breaker.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAE3D,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAG5B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAO;IAQjG,oDAAoD;IACpD,YAAY,IAAI,OAAO;IAcvB,kCAAkC;IAClC,aAAa,IAAI,IAAI;IAcrB,8BAA8B;IAC9B,aAAa,IAAI,IAAI;IAerB,QAAQ,IAAI,YAAY;IAIxB,QAAQ,IAAI;QAAE,KAAK,EAAE,YAAY,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE;CAOhF"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Circuit Breaker for MCP Proxy Server.
3
+ * Implements the classic 3-state circuit breaker pattern:
4
+ * CLOSED → OPEN → HALF_OPEN → CLOSED (or OPEN again).
5
+ *
6
+ * Used to protect upstream MCP servers from cascading failures.
7
+ */
8
+ import { Logger } from './logger.js';
9
+ export class CircuitBreaker {
10
+ state = 'CLOSED';
11
+ failureCount = 0;
12
+ successCount = 0;
13
+ lastFailureTime = 0;
14
+ resetTimeout;
15
+ failureThreshold;
16
+ successThreshold;
17
+ name;
18
+ constructor(name, options = {}) {
19
+ this.name = name;
20
+ this.failureThreshold = options.failureThreshold || 5;
21
+ this.successThreshold = options.successThreshold || 2;
22
+ this.resetTimeout = options.resetTimeoutMs || 30000;
23
+ }
24
+ /** Check if the circuit allows a request through */
25
+ allowRequest() {
26
+ if (this.state === 'CLOSED')
27
+ return true;
28
+ if (this.state === 'OPEN') {
29
+ if (Date.now() - this.lastFailureTime >= this.resetTimeout) {
30
+ this.state = 'HALF_OPEN';
31
+ Logger.debug(`[circuit-breaker:${this.name}] Transitioned to HALF_OPEN`);
32
+ return true;
33
+ }
34
+ return false;
35
+ }
36
+ // HALF_OPEN: allow probes
37
+ return true;
38
+ }
39
+ /** Record a successful request */
40
+ recordSuccess() {
41
+ if (this.state === 'HALF_OPEN') {
42
+ this.successCount++;
43
+ if (this.successCount >= this.successThreshold) {
44
+ this.state = 'CLOSED';
45
+ this.failureCount = 0;
46
+ this.successCount = 0;
47
+ Logger.info(`[circuit-breaker:${this.name}] Circuit CLOSED — service healthy`);
48
+ }
49
+ }
50
+ else if (this.state === 'CLOSED') {
51
+ this.failureCount = 0;
52
+ }
53
+ }
54
+ /** Record a failed request */
55
+ recordFailure() {
56
+ this.lastFailureTime = Date.now();
57
+ if (this.state === 'HALF_OPEN') {
58
+ this.state = 'OPEN';
59
+ this.successCount = 0;
60
+ Logger.warn(`[circuit-breaker:${this.name}] Circuit OPEN — half-open probe failed`);
61
+ }
62
+ else if (this.state === 'CLOSED') {
63
+ this.failureCount++;
64
+ if (this.failureCount >= this.failureThreshold) {
65
+ this.state = 'OPEN';
66
+ Logger.warn(`[circuit-breaker:${this.name}] Circuit OPEN — ${this.failureCount} consecutive failures`);
67
+ }
68
+ }
69
+ }
70
+ getState() {
71
+ return this.state;
72
+ }
73
+ getStats() {
74
+ return {
75
+ state: this.state,
76
+ failureCount: this.failureCount,
77
+ successCount: this.successCount,
78
+ };
79
+ }
80
+ }
81
+ //# sourceMappingURL=circuit-breaker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../../src/utils/circuit-breaker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { createServer } from 'http';
2
+ import { PolicyWatcher } from '../policy/policy-watcher.js';
3
+ import { DashboardAuth } from '../auth/dashboard-auth.js';
4
+ /**
5
+ * Lightweight dashboard server that serves:
6
+ * - / — the dashboard HTML (requires auth if enabled)
7
+ * - /login — login page (when JWT auth is enabled)
8
+ * - /api/login — POST login endpoint
9
+ * - /api/policy — current policy (JSON, requires auth)
10
+ * - /api/policy/reload — trigger policy reload (requires auth)
11
+ * - /metrics — Prometheus metrics (can be auth-gated or public via DASHBOARD_METRICS_PUBLIC=true)
12
+ *
13
+ * v1.2: Integrated DashboardAuth for JWT/API key authentication, CSRF protection.
14
+ */
15
+ export declare function startDashboardServer(port?: number, policyWatcher?: PolicyWatcher, dashboardAuth?: DashboardAuth): Promise<{
16
+ auth: DashboardAuth;
17
+ server: ReturnType<typeof createServer>;
18
+ }>;
19
+ //# sourceMappingURL=dashboard-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-server.d.ts","sourceRoot":"","sources":["../../src/utils/dashboard-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAmC,MAAM,MAAM,CAAC;AAKrE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAM1D;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,GAAE,MAAa,EACnB,aAAa,CAAC,EAAE,aAAa,EAC7B,aAAa,CAAC,EAAE,aAAa,GAC5B,OAAO,CAAC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAA;CAAE,CAAC,CA2P3E"}
@@ -0,0 +1,258 @@
1
+ import { createServer } from 'http';
2
+ import { readFileSync } from 'fs';
3
+ import { resolve, dirname } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { Logger } from './logger.js';
6
+ import { DashboardAuth } from '../auth/dashboard-auth.js';
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+ /**
10
+ * Lightweight dashboard server that serves:
11
+ * - / — the dashboard HTML (requires auth if enabled)
12
+ * - /login — login page (when JWT auth is enabled)
13
+ * - /api/login — POST login endpoint
14
+ * - /api/policy — current policy (JSON, requires auth)
15
+ * - /api/policy/reload — trigger policy reload (requires auth)
16
+ * - /metrics — Prometheus metrics (can be auth-gated or public via DASHBOARD_METRICS_PUBLIC=true)
17
+ *
18
+ * v1.2: Integrated DashboardAuth for JWT/API key authentication, CSRF protection.
19
+ */
20
+ export async function startDashboardServer(port = 4000, policyWatcher, dashboardAuth) {
21
+ if (process.env['DASHBOARD_ENABLED'] !== 'true') {
22
+ Logger.debug('[dashboard] Dashboard server not enabled (set DASHBOARD_ENABLED=true)');
23
+ return { auth: dashboardAuth || new DashboardAuth({ enabled: false }), server: createServer((_req, res) => {
24
+ res.writeHead(200);
25
+ res.end();
26
+ }) };
27
+ }
28
+ const auth = dashboardAuth || new DashboardAuth();
29
+ const authEnabled = auth.isEnabled();
30
+ if (authEnabled) {
31
+ Logger.info('[dashboard] Dashboard authentication enabled');
32
+ }
33
+ else {
34
+ Logger.info('[dashboard] Dashboard running without authentication (set DASHBOARD_AUTH_ENABLED=true)');
35
+ }
36
+ const dashboardHtml = readFileSync(resolve(__dirname, '..', '..', 'deploy', 'dashboard.html'), 'utf-8');
37
+ /** Read JSON body from request */
38
+ async function readBody(req) {
39
+ return new Promise((resolve, reject) => {
40
+ let data = '';
41
+ req.on('data', (chunk) => { data += chunk.toString(); });
42
+ req.on('end', () => {
43
+ try {
44
+ resolve(data ? JSON.parse(data) : {});
45
+ }
46
+ catch {
47
+ resolve({});
48
+ }
49
+ });
50
+ req.on('error', reject);
51
+ });
52
+ }
53
+ /** Parse form-encoded body from request */
54
+ async function readFormBody(req) {
55
+ return new Promise((resolve) => {
56
+ let data = '';
57
+ req.on('data', (chunk) => { data += chunk.toString(); });
58
+ req.on('end', () => {
59
+ const result = {};
60
+ if (data) {
61
+ try {
62
+ const params = new URLSearchParams(data);
63
+ for (const [key, value] of params) {
64
+ result[key] = value;
65
+ }
66
+ }
67
+ catch {
68
+ // Ignore parse errors
69
+ }
70
+ }
71
+ resolve(result);
72
+ });
73
+ });
74
+ }
75
+ /** Get client IP for rate limiting */
76
+ function getClientIp(req) {
77
+ const forwarded = req.headers['x-forwarded-for'];
78
+ if (forwarded) {
79
+ const first = Array.isArray(forwarded) ? forwarded[0] : forwarded.split(',')[0];
80
+ return (first || '').trim();
81
+ }
82
+ return req.socket?.remoteAddress || 'unknown';
83
+ }
84
+ /** Write JSON response */
85
+ function writeJson(res, status, data) {
86
+ res.writeHead(status, { 'Content-Type': 'application/json' });
87
+ res.end(JSON.stringify(data));
88
+ }
89
+ const server = createServer(async (req, res) => {
90
+ const url = req.url || '/';
91
+ const method = req.method || 'GET';
92
+ // ── CORS preflight ─────────────────────────────────────
93
+ if (method === 'OPTIONS') {
94
+ res.writeHead(204, {
95
+ 'Access-Control-Allow-Origin': '*',
96
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
97
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-API-Key',
98
+ });
99
+ res.end();
100
+ return;
101
+ }
102
+ // ── CORS headers on all responses ─────────────────────
103
+ const setCors = () => {
104
+ res.setHeader('Access-Control-Allow-Origin', '*');
105
+ };
106
+ try {
107
+ // ── Login page (only when JWT auth is enabled, no API key set) ──
108
+ if (url === '/login' && method === 'GET') {
109
+ setCors();
110
+ if (auth.isEnabled() && auth.hasJwtSessionAuth()) {
111
+ res.writeHead(200, { 'Content-Type': 'text/html' });
112
+ res.end(auth.getLoginPageHtml());
113
+ }
114
+ else {
115
+ res.writeHead(302, { 'Location': '/' });
116
+ res.end();
117
+ }
118
+ return;
119
+ }
120
+ // ── Login API endpoint ──────────────────────────────
121
+ if (url === '/api/login' && method === 'POST') {
122
+ setCors();
123
+ const ip = getClientIp(req);
124
+ const contentType = req.headers['content-type'] || '';
125
+ let body;
126
+ if (contentType.includes('application/x-www-form-urlencoded')) {
127
+ body = await readFormBody(req);
128
+ }
129
+ else {
130
+ body = await readBody(req);
131
+ }
132
+ const result = auth.login({
133
+ url,
134
+ headers: req.headers,
135
+ body: {
136
+ username: body.username,
137
+ password: body.password,
138
+ api_key: body.api_key,
139
+ },
140
+ ip,
141
+ });
142
+ if (result.success && req.headers['content-type']?.includes('form')) {
143
+ // Form submission — redirect to dashboard with token
144
+ res.writeHead(302, {
145
+ 'Location': `/?api_key=${encodeURIComponent(result.token)}`,
146
+ 'Set-Cookie': `mcp_guardian_session=${result.token}; Path=/; HttpOnly; SameSite=Strict; Max-Age=3600`,
147
+ });
148
+ res.end();
149
+ return;
150
+ }
151
+ if (result.success) {
152
+ writeJson(res, 200, { success: true, token: result.token });
153
+ }
154
+ else {
155
+ writeJson(res, 401, { success: false, error: result.error });
156
+ }
157
+ return;
158
+ }
159
+ // ── Auth check for all other routes ─────────────────
160
+ const authResult = auth.authenticate({ url, headers: req.headers, method });
161
+ if (!authResult.authenticated) {
162
+ setCors();
163
+ if (req.headers['accept']?.includes('text/html')) {
164
+ // Browser request — redirect to login
165
+ res.writeHead(302, { 'Location': '/login' });
166
+ res.end();
167
+ }
168
+ else {
169
+ writeJson(res, 401, { error: 'Authentication required', reason: authResult.reason });
170
+ }
171
+ return;
172
+ }
173
+ // ── Dashboard HTML ──────────────────────────────────
174
+ if (url === '/' || url === '/dashboard.html') {
175
+ setCors();
176
+ res.writeHead(200, { 'Content-Type': 'text/html' });
177
+ res.end(dashboardHtml);
178
+ return;
179
+ }
180
+ // ── Policy API ──────────────────────────────────────
181
+ if (url === '/api/policy' && method === 'GET') {
182
+ setCors();
183
+ if (!policyWatcher || !policyWatcher.get()) {
184
+ writeJson(res, 404, { error: 'No active policy. Start proxy with --policy flag.' });
185
+ return;
186
+ }
187
+ writeJson(res, 200, { mode: policyWatcher.get().getMode(), rules: 'Policy engine active (YAML view available on filesystem)' });
188
+ return;
189
+ }
190
+ if (url === '/api/policy/reload' && method === 'POST') {
191
+ setCors();
192
+ if (!policyWatcher) {
193
+ writeJson(res, 404, { error: 'Policy watcher not configured' });
194
+ return;
195
+ }
196
+ writeJson(res, 200, { status: 'ok', message: 'Policy watcher is active. File changes are auto-detected.' });
197
+ return;
198
+ }
199
+ // ── Prometheus /metrics proxy ──────────────────────
200
+ if (url === '/metrics') {
201
+ setCors();
202
+ const metricsPublic = process.env['DASHBOARD_METRICS_PUBLIC'] === 'true';
203
+ // Re-check auth for metrics unless public
204
+ if (metricsPublic || authResult.authenticated) {
205
+ try {
206
+ const metricsPort = process.env['METRICS_PORT'] || '9090';
207
+ const metricsRes = await fetch(`http://localhost:${metricsPort}/metrics`);
208
+ if (!metricsRes.ok)
209
+ throw new Error(`Metrics server returned ${metricsRes.status}`);
210
+ const text = await metricsRes.text();
211
+ res.writeHead(200, {
212
+ 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8',
213
+ 'Access-Control-Allow-Origin': '*',
214
+ });
215
+ res.end(text);
216
+ }
217
+ catch {
218
+ writeJson(res, 200, { error: 'Metrics not available. Ensure METRICS_ENABLED=true and proxy is running.' });
219
+ }
220
+ }
221
+ else {
222
+ writeJson(res, 401, { error: 'Authentication required for metrics' });
223
+ }
224
+ return;
225
+ }
226
+ // ── Auth status check ───────────────────────────────
227
+ if (url === '/api/auth/status' && method === 'GET') {
228
+ setCors();
229
+ writeJson(res, 200, { authenticated: true, identity: authResult.identity, authEnabled });
230
+ return;
231
+ }
232
+ // ── Logout ──────────────────────────────────────────
233
+ if (url === '/api/logout' && method === 'POST') {
234
+ setCors();
235
+ const authHeader = req.headers['authorization'];
236
+ if (authHeader) {
237
+ const match = authHeader.match(/^Bearer\s+(.+)$/i);
238
+ if (match)
239
+ auth.logout(match[1]);
240
+ }
241
+ writeJson(res, 200, { status: 'ok', message: 'Logged out' });
242
+ return;
243
+ }
244
+ // ── 404 ──────────────────────────────────────────────
245
+ setCors();
246
+ writeJson(res, 404, { error: 'Not found' });
247
+ }
248
+ catch (err) {
249
+ setCors();
250
+ writeJson(res, 500, { error: err?.message || 'Internal error' });
251
+ }
252
+ });
253
+ server.listen(port, () => {
254
+ Logger.info(`[dashboard] Dashboard available at http://localhost:${port}${authEnabled ? ' (auth enabled)' : ''}`);
255
+ });
256
+ return { auth, server };
257
+ }
258
+ //# sourceMappingURL=dashboard-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-server.js","sourceRoot":"","sources":["../../src/utils/dashboard-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAmC,MAAM,MAAM,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAG1D,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAe,IAAI,EACnB,aAA6B,EAC7B,aAA6B;IAE7B,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,KAAK,MAAM,EAAE,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,uEAAuE,CAAC,CAAC;QACtF,OAAO,EAAE,IAAI,EAAE,aAAa,IAAI,IAAI,aAAa,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;gBACxG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC,CAAC,EAAE,CAAC;IACP,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,IAAI,IAAI,aAAa,EAAE,CAAC;IAClD,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IAErC,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAC9D,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,CAAC,wFAAwF,CAAC,CAAC;IACxG,CAAC;IAED,MAAM,aAAa,GAAG,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,gBAAgB,CAAC,EAAE,OAAO,CAAC,CAAC;IAExG,kCAAkC;IAClC,KAAK,UAAU,QAAQ,CAAC,GAAoB;QAC1C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,GAAG,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACjE,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACjB,IAAI,CAAC;oBACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACxC,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,CAAC,EAAE,CAAC,CAAC;gBACd,CAAC;YACH,CAAC,CAAC,CAAC;YACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,2CAA2C;IAC3C,KAAK,UAAU,YAAY,CAAC,GAAoB;QAC9C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,GAAG,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACjE,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACjB,MAAM,MAAM,GAA2B,EAAE,CAAC;gBAC1C,IAAI,IAAI,EAAE,CAAC;oBACT,IAAI,CAAC;wBACH,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;wBACzC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;4BAClC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;wBACtB,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,sBAAsB;oBACxB,CAAC;gBACH,CAAC;gBACD,OAAO,CAAC,MAAM,CAAC,CAAC;YAClB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,sCAAsC;IACtC,SAAS,WAAW,CAAC,GAAoB;QACvC,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACjD,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAChF,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9B,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,EAAE,aAAa,IAAI,SAAS,CAAC;IAChD,CAAC;IAED,0BAA0B;IAC1B,SAAS,SAAS,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;QACnE,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC9D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC7C,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC;QAC3B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC;QAEnC,0DAA0D;QAC1D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;gBACjB,6BAA6B,EAAE,GAAG;gBAClC,8BAA8B,EAAE,oBAAoB;gBACpD,8BAA8B,EAAE,wCAAwC;aACzE,CAAC,CAAC;YACH,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QAED,yDAAyD;QACzD,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;QACpD,CAAC,CAAC;QAEF,IAAI,CAAC;YACH,mEAAmE;YACnE,IAAI,GAAG,KAAK,QAAQ,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACzC,OAAO,EAAE,CAAC;gBACV,IAAI,IAAI,CAAC,SAAS,EAAE,IAAI,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;oBACjD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;oBACpD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;gBACnC,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;oBACxC,GAAG,CAAC,GAAG,EAAE,CAAC;gBACZ,CAAC;gBACD,OAAO;YACT,CAAC;YAED,uDAAuD;YACvD,IAAI,GAAG,KAAK,YAAY,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC9C,OAAO,EAAE,CAAC;gBACV,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;gBAC5B,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;gBAEtD,IAAI,IAA4B,CAAC;gBACjC,IAAI,WAAW,CAAC,QAAQ,CAAC,mCAAmC,CAAC,EAAE,CAAC;oBAC9D,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;gBACjC,CAAC;qBAAM,CAAC;oBACN,IAAI,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAsC,CAAC;gBAClE,CAAC;gBAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC;oBACxB,GAAG;oBACH,OAAO,EAAE,GAAG,CAAC,OAAwD;oBACrE,IAAI,EAAE;wBACJ,QAAQ,EAAE,IAAI,CAAC,QAAQ;wBACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;wBACvB,OAAO,EAAE,IAAI,CAAC,OAAO;qBACtB;oBACD,EAAE;iBACH,CAAC,CAAC;gBAEH,IAAI,MAAM,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;oBACpE,qDAAqD;oBACrD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;wBACjB,UAAU,EAAE,aAAa,kBAAkB,CAAC,MAAM,CAAC,KAAM,CAAC,EAAE;wBAC5D,YAAY,EAAE,wBAAwB,MAAM,CAAC,KAAK,mDAAmD;qBACtG,CAAC,CAAC;oBACH,GAAG,CAAC,GAAG,EAAE,CAAC;oBACV,OAAO;gBACT,CAAC;gBAED,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;oBACnB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;gBAC9D,CAAC;qBAAM,CAAC;oBACN,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;gBAC/D,CAAC;gBACD,OAAO;YACT,CAAC;YAED,uDAAuD;YACvD,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC5E,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC;gBAC9B,OAAO,EAAE,CAAC;gBACV,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;oBACjD,sCAAsC;oBACtC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;oBAC7C,GAAG,CAAC,GAAG,EAAE,CAAC;gBACZ,CAAC;qBAAM,CAAC;oBACN,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,yBAAyB,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;gBACvF,CAAC;gBACD,OAAO;YACT,CAAC;YAED,uDAAuD;YACvD,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,iBAAiB,EAAE,CAAC;gBAC7C,OAAO,EAAE,CAAC;gBACV,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;gBACpD,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBACvB,OAAO;YACT,CAAC;YAED,uDAAuD;YACvD,IAAI,GAAG,KAAK,aAAa,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBAC9C,OAAO,EAAE,CAAC;gBACV,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC;oBAC3C,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,mDAAmD,EAAE,CAAC,CAAC;oBACpF,OAAO;gBACT,CAAC;gBACD,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,GAAG,EAAG,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,0DAA0D,EAAE,CAAC,CAAC;gBACjI,OAAO;YACT,CAAC;YAED,IAAI,GAAG,KAAK,oBAAoB,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACtD,OAAO,EAAE,CAAC;gBACV,IAAI,CAAC,aAAa,EAAE,CAAC;oBACnB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC,CAAC;oBAChE,OAAO;gBACT,CAAC;gBACD,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,2DAA2D,EAAE,CAAC,CAAC;gBAC5G,OAAO;YACT,CAAC;YAED,sDAAsD;YACtD,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;gBACvB,OAAO,EAAE,CAAC;gBACV,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,KAAK,MAAM,CAAC;gBACzE,0CAA0C;gBAC1C,IAAI,aAAa,IAAI,UAAU,CAAC,aAAa,EAAE,CAAC;oBAC9C,IAAI,CAAC;wBACH,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,MAAM,CAAC;wBAC1D,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,oBAAoB,WAAW,UAAU,CAAC,CAAC;wBAC1E,IAAI,CAAC,UAAU,CAAC,EAAE;4BAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;wBACpF,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC;wBACrC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;4BACjB,cAAc,EAAE,0CAA0C;4BAC1D,6BAA6B,EAAE,GAAG;yBACnC,CAAC,CAAC;wBACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBAChB,CAAC;oBAAC,MAAM,CAAC;wBACP,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,0EAA0E,EAAE,CAAC,CAAC;oBAC7G,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,qCAAqC,EAAE,CAAC,CAAC;gBACxE,CAAC;gBACD,OAAO;YACT,CAAC;YAED,uDAAuD;YACvD,IAAI,GAAG,KAAK,kBAAkB,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACnD,OAAO,EAAE,CAAC;gBACV,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;gBACzF,OAAO;YACT,CAAC;YAED,uDAAuD;YACvD,IAAI,GAAG,KAAK,aAAa,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC/C,OAAO,EAAE,CAAC;gBACV,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;gBAChD,IAAI,UAAU,EAAE,CAAC;oBACf,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;oBACnD,IAAI,KAAK;wBAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBACnC,CAAC;gBACD,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;gBAC7D,OAAO;YACT,CAAC;YAED,wDAAwD;YACxD,OAAO,EAAE,CAAC;YACV,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC;YACV,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,IAAI,gBAAgB,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;QACvB,MAAM,CAAC,IAAI,CAAC,uDAAuD,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACpH,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1B,CAAC"}