@dotsetlabs/tollgate 0.1.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.
- package/LICENSE +21 -0
- package/README.md +885 -0
- package/dist/analyzers/filesystem.d.ts +26 -0
- package/dist/analyzers/filesystem.d.ts.map +1 -0
- package/dist/analyzers/filesystem.js +284 -0
- package/dist/analyzers/filesystem.js.map +1 -0
- package/dist/analyzers/http.d.ts +90 -0
- package/dist/analyzers/http.d.ts.map +1 -0
- package/dist/analyzers/http.js +433 -0
- package/dist/analyzers/http.js.map +1 -0
- package/dist/analyzers/index.d.ts +101 -0
- package/dist/analyzers/index.d.ts.map +1 -0
- package/dist/analyzers/index.js +342 -0
- package/dist/analyzers/index.js.map +1 -0
- package/dist/analyzers/loader.d.ts +114 -0
- package/dist/analyzers/loader.d.ts.map +1 -0
- package/dist/analyzers/loader.js +184 -0
- package/dist/analyzers/loader.js.map +1 -0
- package/dist/analyzers/prompt-injection.d.ts +95 -0
- package/dist/analyzers/prompt-injection.d.ts.map +1 -0
- package/dist/analyzers/prompt-injection.js +725 -0
- package/dist/analyzers/prompt-injection.js.map +1 -0
- package/dist/analyzers/sdk.d.ts +230 -0
- package/dist/analyzers/sdk.d.ts.map +1 -0
- package/dist/analyzers/sdk.js +283 -0
- package/dist/analyzers/sdk.js.map +1 -0
- package/dist/analyzers/shell.d.ts +20 -0
- package/dist/analyzers/shell.d.ts.map +1 -0
- package/dist/analyzers/shell.js +297 -0
- package/dist/analyzers/shell.js.map +1 -0
- package/dist/analyzers/sql.d.ts +37 -0
- package/dist/analyzers/sql.d.ts.map +1 -0
- package/dist/analyzers/sql.js +455 -0
- package/dist/analyzers/sql.js.map +1 -0
- package/dist/analyzers/types.d.ts +117 -0
- package/dist/analyzers/types.d.ts.map +1 -0
- package/dist/analyzers/types.js +46 -0
- package/dist/analyzers/types.js.map +1 -0
- package/dist/approval/interactive.d.ts +72 -0
- package/dist/approval/interactive.d.ts.map +1 -0
- package/dist/approval/interactive.js +550 -0
- package/dist/approval/interactive.js.map +1 -0
- package/dist/approval/terminal.d.ts +59 -0
- package/dist/approval/terminal.d.ts.map +1 -0
- package/dist/approval/terminal.js +238 -0
- package/dist/approval/terminal.js.map +1 -0
- package/dist/approval/types.d.ts +66 -0
- package/dist/approval/types.d.ts.map +1 -0
- package/dist/approval/types.js +2 -0
- package/dist/approval/types.js.map +1 -0
- package/dist/audit/exporter.d.ts +138 -0
- package/dist/audit/exporter.d.ts.map +1 -0
- package/dist/audit/exporter.js +366 -0
- package/dist/audit/exporter.js.map +1 -0
- package/dist/audit/logger.d.ts +156 -0
- package/dist/audit/logger.d.ts.map +1 -0
- package/dist/audit/logger.js +406 -0
- package/dist/audit/logger.js.map +1 -0
- package/dist/audit/redaction.d.ts +110 -0
- package/dist/audit/redaction.d.ts.map +1 -0
- package/dist/audit/redaction.js +307 -0
- package/dist/audit/redaction.js.map +1 -0
- package/dist/audit/schema.d.ts +76 -0
- package/dist/audit/schema.d.ts.map +1 -0
- package/dist/audit/schema.js +122 -0
- package/dist/audit/schema.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +34 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +431 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/export.d.ts +18 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +63 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/init.d.ts +12 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +102 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/logs.d.ts +11 -0
- package/dist/cli/commands/logs.d.ts.map +1 -0
- package/dist/cli/commands/logs.js +60 -0
- package/dist/cli/commands/logs.js.map +1 -0
- package/dist/cli/commands/scan.d.ts +29 -0
- package/dist/cli/commands/scan.d.ts.map +1 -0
- package/dist/cli/commands/scan.js +251 -0
- package/dist/cli/commands/scan.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +26 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +424 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/start.d.ts +20 -0
- package/dist/cli/commands/start.d.ts.map +1 -0
- package/dist/cli/commands/start.js +82 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/stats.d.ts +10 -0
- package/dist/cli/commands/stats.d.ts.map +1 -0
- package/dist/cli/commands/stats.js +42 -0
- package/dist/cli/commands/stats.js.map +1 -0
- package/dist/cli/commands/templates.d.ts +26 -0
- package/dist/cli/commands/templates.d.ts.map +1 -0
- package/dist/cli/commands/templates.js +221 -0
- package/dist/cli/commands/templates.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +12 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +107 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/commands/wrap.d.ts +19 -0
- package/dist/cli/commands/wrap.d.ts.map +1 -0
- package/dist/cli/commands/wrap.js +59 -0
- package/dist/cli/commands/wrap.js.map +1 -0
- package/dist/cli/index.d.ts +17 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +202 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/ui.d.ts +139 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/ui.js +271 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/constants.d.ts +33 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +54 -0
- package/dist/constants.js.map +1 -0
- package/dist/errors.d.ts +28 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +37 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +82 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator/index.d.ts +11 -0
- package/dist/orchestrator/index.d.ts.map +1 -0
- package/dist/orchestrator/index.js +10 -0
- package/dist/orchestrator/index.js.map +1 -0
- package/dist/orchestrator/manager.d.ts +127 -0
- package/dist/orchestrator/manager.d.ts.map +1 -0
- package/dist/orchestrator/manager.js +498 -0
- package/dist/orchestrator/manager.js.map +1 -0
- package/dist/orchestrator/types.d.ts +141 -0
- package/dist/orchestrator/types.d.ts.map +1 -0
- package/dist/orchestrator/types.js +9 -0
- package/dist/orchestrator/types.js.map +1 -0
- package/dist/policy/engine.d.ts +55 -0
- package/dist/policy/engine.d.ts.map +1 -0
- package/dist/policy/engine.js +288 -0
- package/dist/policy/engine.js.map +1 -0
- package/dist/policy/natural-language.d.ts +141 -0
- package/dist/policy/natural-language.d.ts.map +1 -0
- package/dist/policy/natural-language.js +552 -0
- package/dist/policy/natural-language.js.map +1 -0
- package/dist/policy/parser.d.ts +141 -0
- package/dist/policy/parser.d.ts.map +1 -0
- package/dist/policy/parser.js +314 -0
- package/dist/policy/parser.js.map +1 -0
- package/dist/policy/types.d.ts +428 -0
- package/dist/policy/types.d.ts.map +1 -0
- package/dist/policy/types.js +32 -0
- package/dist/policy/types.js.map +1 -0
- package/dist/policy/validator.d.ts +72 -0
- package/dist/policy/validator.d.ts.map +1 -0
- package/dist/policy/validator.js +453 -0
- package/dist/policy/validator.js.map +1 -0
- package/dist/proxy/bridge.d.ts +84 -0
- package/dist/proxy/bridge.d.ts.map +1 -0
- package/dist/proxy/bridge.js +217 -0
- package/dist/proxy/bridge.js.map +1 -0
- package/dist/proxy/client.d.ts +130 -0
- package/dist/proxy/client.d.ts.map +1 -0
- package/dist/proxy/client.js +290 -0
- package/dist/proxy/client.js.map +1 -0
- package/dist/proxy/server.d.ts +111 -0
- package/dist/proxy/server.d.ts.map +1 -0
- package/dist/proxy/server.js +444 -0
- package/dist/proxy/server.js.map +1 -0
- package/dist/scanner.d.ts +91 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +373 -0
- package/dist/scanner.js.map +1 -0
- package/dist/session/index.d.ts +32 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +31 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/manager.d.ts +166 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +454 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/session/sqlite-store.d.ts +54 -0
- package/dist/session/sqlite-store.d.ts.map +1 -0
- package/dist/session/sqlite-store.js +209 -0
- package/dist/session/sqlite-store.js.map +1 -0
- package/dist/session/types.d.ts +179 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +38 -0
- package/dist/session/types.js.map +1 -0
- package/dist/templates.d.ts +64 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +451 -0
- package/dist/templates.js.map +1 -0
- package/dist/utils/config.d.ts +57 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +104 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/errors.d.ts +18 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +35 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.d.ts +144 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +300 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/wizard.d.ts +68 -0
- package/dist/wizard.d.ts.map +1 -0
- package/dist/wizard.js +395 -0
- package/dist/wizard.js.map +1 -0
- package/package.json +99 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tollgate Bridge
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates the proxy components: policy engine, session manager,
|
|
5
|
+
* audit logger, approval handler, and upstream client.
|
|
6
|
+
*
|
|
7
|
+
* Resilience features:
|
|
8
|
+
* - Graceful shutdown with configurable timeout
|
|
9
|
+
* - Force exit after graceful shutdown timeout
|
|
10
|
+
* - Health status monitoring
|
|
11
|
+
*/
|
|
12
|
+
import { homedir } from 'node:os';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { PolicyEngine } from '../policy/engine.js';
|
|
15
|
+
import { AuditLogger } from '../audit/logger.js';
|
|
16
|
+
import { TerminalApprovalHandler } from '../approval/terminal.js';
|
|
17
|
+
import { InteractiveApprovalHandler } from '../approval/interactive.js';
|
|
18
|
+
import { TollgateServer } from './server.js';
|
|
19
|
+
import { UpstreamClient } from './client.js';
|
|
20
|
+
import { SessionManager } from '../session/manager.js';
|
|
21
|
+
import { SqliteSessionStore } from '../session/sqlite-store.js';
|
|
22
|
+
import { ConfigError } from '../utils/errors.js';
|
|
23
|
+
import { getServerConfig, validateConfig } from '../policy/parser.js';
|
|
24
|
+
import { proxyLogger as logger } from '../utils/logger.js';
|
|
25
|
+
import { DEFAULT_RESILIENCE } from '../constants.js';
|
|
26
|
+
export class TollgateBridge {
|
|
27
|
+
server = null;
|
|
28
|
+
options;
|
|
29
|
+
resilience;
|
|
30
|
+
isShuttingDown = false;
|
|
31
|
+
forceExitTimeout = null;
|
|
32
|
+
constructor(options) {
|
|
33
|
+
this.options = options;
|
|
34
|
+
// Merge resilience configuration with defaults
|
|
35
|
+
const configResilience = options.config.resilience ?? {};
|
|
36
|
+
this.resilience = {
|
|
37
|
+
failureMode: options.failureMode ?? configResilience.failureMode ?? DEFAULT_RESILIENCE.failureMode,
|
|
38
|
+
upstreamTimeoutMs: configResilience.upstreamTimeoutMs ?? DEFAULT_RESILIENCE.upstreamTimeoutMs,
|
|
39
|
+
healthCheck: {
|
|
40
|
+
enabled: configResilience.healthCheck?.enabled ?? DEFAULT_RESILIENCE.healthCheck.enabled,
|
|
41
|
+
intervalMs: configResilience.healthCheck?.intervalMs ?? DEFAULT_RESILIENCE.healthCheck.intervalMs,
|
|
42
|
+
timeoutMs: configResilience.healthCheck?.timeoutMs ?? DEFAULT_RESILIENCE.healthCheck.timeoutMs,
|
|
43
|
+
failureThreshold: configResilience.healthCheck?.failureThreshold ?? DEFAULT_RESILIENCE.healthCheck.failureThreshold,
|
|
44
|
+
},
|
|
45
|
+
shutdown: {
|
|
46
|
+
timeoutMs: configResilience.shutdown?.timeoutMs ?? DEFAULT_RESILIENCE.shutdown.timeoutMs,
|
|
47
|
+
drainTimeoutMs: configResilience.shutdown?.drainTimeoutMs ?? DEFAULT_RESILIENCE.shutdown.drainTimeoutMs,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async start() {
|
|
52
|
+
const { config, serverName } = this.options;
|
|
53
|
+
// Validate configuration
|
|
54
|
+
validateConfig(config);
|
|
55
|
+
// Get server configuration
|
|
56
|
+
const serverConfig = getServerConfig(config, serverName);
|
|
57
|
+
if (!serverConfig) {
|
|
58
|
+
throw new ConfigError(`Server "${serverName}" not found in configuration`, {
|
|
59
|
+
availableServers: Object.keys(config.servers ?? {}),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
// Initialize components
|
|
63
|
+
const policyEngine = new PolicyEngine(config);
|
|
64
|
+
const auditLogger = new AuditLogger(this.options.auditPath);
|
|
65
|
+
const approvalHandler = this.createApprovalHandler(config);
|
|
66
|
+
// Create upstream client with resilience configuration
|
|
67
|
+
const upstreamClient = new UpstreamClient({
|
|
68
|
+
config: serverConfig,
|
|
69
|
+
callTimeoutMs: this.resilience.upstreamTimeoutMs,
|
|
70
|
+
healthCheck: this.resilience.healthCheck,
|
|
71
|
+
onHealthChange: this.handleHealthChange.bind(this),
|
|
72
|
+
});
|
|
73
|
+
// Create session manager unless disabled
|
|
74
|
+
const sessionManager = this.options.disableSessions
|
|
75
|
+
? undefined
|
|
76
|
+
: new SessionManager(this.createSessionStore(config));
|
|
77
|
+
// Create and start the server
|
|
78
|
+
this.server = new TollgateServer({
|
|
79
|
+
serverName,
|
|
80
|
+
policyEngine,
|
|
81
|
+
auditLogger,
|
|
82
|
+
approvalHandler,
|
|
83
|
+
upstreamClient,
|
|
84
|
+
sessionManager,
|
|
85
|
+
dryRun: this.options.dryRun,
|
|
86
|
+
failureMode: this.resilience.failureMode,
|
|
87
|
+
});
|
|
88
|
+
// Handle shutdown signals
|
|
89
|
+
const shutdown = async (signal) => {
|
|
90
|
+
if (this.isShuttingDown) {
|
|
91
|
+
logger.warn('Force exit requested');
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
this.isShuttingDown = true;
|
|
95
|
+
logger.info('Shutting down gracefully', { signal });
|
|
96
|
+
// Set up force exit timeout
|
|
97
|
+
this.forceExitTimeout = setTimeout(() => {
|
|
98
|
+
logger.error('Graceful shutdown timeout - forcing exit');
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}, this.resilience.shutdown.timeoutMs);
|
|
101
|
+
// Unref so it doesn't prevent exit if we finish early
|
|
102
|
+
this.forceExitTimeout.unref();
|
|
103
|
+
try {
|
|
104
|
+
await this.stop();
|
|
105
|
+
if (this.forceExitTimeout) {
|
|
106
|
+
clearTimeout(this.forceExitTimeout);
|
|
107
|
+
}
|
|
108
|
+
logger.info('Shutdown complete');
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
logger.error('Error during shutdown', {
|
|
113
|
+
error: error instanceof Error ? error.message : String(error),
|
|
114
|
+
});
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
119
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
120
|
+
await this.server.start();
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Stop the bridge and all components.
|
|
124
|
+
* Waits for in-flight requests to complete before closing.
|
|
125
|
+
*/
|
|
126
|
+
async stop() {
|
|
127
|
+
if (this.server) {
|
|
128
|
+
await this.server.close(this.resilience.shutdown.drainTimeoutMs);
|
|
129
|
+
this.server = null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Handle upstream health status changes.
|
|
134
|
+
*/
|
|
135
|
+
handleHealthChange(status, previousStatus) {
|
|
136
|
+
if (status === 'unhealthy') {
|
|
137
|
+
logger.warn('Upstream server became unhealthy', {
|
|
138
|
+
previousStatus,
|
|
139
|
+
failureMode: this.resilience.failureMode,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
else if (status === 'healthy' && previousStatus === 'unhealthy') {
|
|
143
|
+
logger.info('Upstream server recovered and is now healthy');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Creates the appropriate approval handler based on configuration.
|
|
148
|
+
*/
|
|
149
|
+
createApprovalHandler(config) {
|
|
150
|
+
const method = config.approval?.method ?? 'terminal';
|
|
151
|
+
const timeoutMs = this.options.approvalTimeout ?? config.approval?.timeout ?? 60000;
|
|
152
|
+
switch (method) {
|
|
153
|
+
case 'interactive':
|
|
154
|
+
return new InteractiveApprovalHandler({
|
|
155
|
+
port: config.approval?.port,
|
|
156
|
+
timeoutMs,
|
|
157
|
+
});
|
|
158
|
+
case 'webhook':
|
|
159
|
+
// Webhook not yet implemented - fall back to terminal with warning
|
|
160
|
+
logger.warn('Webhook approval method not yet implemented, using terminal');
|
|
161
|
+
return new TerminalApprovalHandler(timeoutMs);
|
|
162
|
+
case 'terminal':
|
|
163
|
+
default:
|
|
164
|
+
return new TerminalApprovalHandler(timeoutMs);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Creates the appropriate session store based on configuration.
|
|
169
|
+
*/
|
|
170
|
+
createSessionStore(config) {
|
|
171
|
+
const persist = config.session?.persist ?? false;
|
|
172
|
+
if (!persist) {
|
|
173
|
+
// Use in-memory store (default)
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
// Use SQLite persistent store
|
|
177
|
+
const defaultPath = join(homedir(), '.tollgate', 'sessions.db');
|
|
178
|
+
const dbPath = config.session?.path ?? defaultPath;
|
|
179
|
+
logger.info('Using persistent session store', { path: dbPath });
|
|
180
|
+
return new SqliteSessionStore(dbPath);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
export async function startWrapMode(options) {
|
|
184
|
+
// Create an inline config for wrap mode
|
|
185
|
+
const config = {
|
|
186
|
+
version: '1',
|
|
187
|
+
defaults: {
|
|
188
|
+
action: options.defaultAction ?? 'prompt',
|
|
189
|
+
},
|
|
190
|
+
servers: {
|
|
191
|
+
wrapped: {
|
|
192
|
+
command: options.command,
|
|
193
|
+
args: options.args,
|
|
194
|
+
env: options.env,
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
approval: {
|
|
198
|
+
method: options.approvalMethod ?? 'terminal',
|
|
199
|
+
port: options.approvalPort,
|
|
200
|
+
timeout: options.approvalTimeout,
|
|
201
|
+
},
|
|
202
|
+
session: {
|
|
203
|
+
persist: options.persistSessions ?? false,
|
|
204
|
+
path: options.sessionPath,
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
const bridge = new TollgateBridge({
|
|
208
|
+
config,
|
|
209
|
+
serverName: 'wrapped',
|
|
210
|
+
auditPath: options.auditPath,
|
|
211
|
+
approvalTimeout: options.approvalTimeout,
|
|
212
|
+
dryRun: options.dryRun,
|
|
213
|
+
failureMode: options.failureMode,
|
|
214
|
+
});
|
|
215
|
+
await bridge.start();
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/proxy/bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upstream MCP Client
|
|
3
|
+
*
|
|
4
|
+
* Manages connection to the upstream MCP server with:
|
|
5
|
+
* - Health checking and status monitoring
|
|
6
|
+
* - Timeout support for tool calls
|
|
7
|
+
* - Connection state tracking
|
|
8
|
+
*/
|
|
9
|
+
import type { CallToolResult, ListToolsResult } from '@modelcontextprotocol/sdk/types.js';
|
|
10
|
+
import type { ServerConfig, HealthCheckConfig } from '../policy/types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Health status of the upstream server.
|
|
13
|
+
*/
|
|
14
|
+
export type HealthStatus = 'healthy' | 'unhealthy' | 'unknown';
|
|
15
|
+
/**
|
|
16
|
+
* Result of a health check operation.
|
|
17
|
+
*/
|
|
18
|
+
export interface HealthCheckResult {
|
|
19
|
+
status: HealthStatus;
|
|
20
|
+
lastCheck: Date;
|
|
21
|
+
consecutiveFailures: number;
|
|
22
|
+
error?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Options for the upstream client.
|
|
26
|
+
*/
|
|
27
|
+
export interface UpstreamClientOptions {
|
|
28
|
+
/** Server configuration */
|
|
29
|
+
config: ServerConfig;
|
|
30
|
+
/** Timeout for tool calls in ms (default: 30000) */
|
|
31
|
+
callTimeoutMs?: number;
|
|
32
|
+
/** Health check configuration */
|
|
33
|
+
healthCheck?: HealthCheckConfig;
|
|
34
|
+
/** Callback when health status changes */
|
|
35
|
+
onHealthChange?: (status: HealthStatus, previousStatus: HealthStatus) => void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Upstream MCP client with health monitoring and resilience features.
|
|
39
|
+
*/
|
|
40
|
+
export declare class UpstreamClient {
|
|
41
|
+
private client;
|
|
42
|
+
private transport;
|
|
43
|
+
private config;
|
|
44
|
+
private initialized;
|
|
45
|
+
private callTimeoutMs;
|
|
46
|
+
private healthCheckConfig;
|
|
47
|
+
private healthCheckInterval;
|
|
48
|
+
private healthStatus;
|
|
49
|
+
private lastHealthCheck;
|
|
50
|
+
private consecutiveFailures;
|
|
51
|
+
private lastHealthError?;
|
|
52
|
+
private onHealthChange?;
|
|
53
|
+
private isClosing;
|
|
54
|
+
/** Mutex to prevent concurrent initialization */
|
|
55
|
+
private initializePromise;
|
|
56
|
+
constructor(options: UpstreamClientOptions | ServerConfig);
|
|
57
|
+
/**
|
|
58
|
+
* Initialize the upstream connection.
|
|
59
|
+
* Spawns the upstream MCP server process and establishes connection.
|
|
60
|
+
* Thread-safe: concurrent calls will wait for the first initialization to complete.
|
|
61
|
+
*/
|
|
62
|
+
initialize(): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Internal initialization logic.
|
|
65
|
+
*/
|
|
66
|
+
private doInitialize;
|
|
67
|
+
/**
|
|
68
|
+
* List available tools from the upstream server.
|
|
69
|
+
*/
|
|
70
|
+
listTools(): Promise<ListToolsResult>;
|
|
71
|
+
/**
|
|
72
|
+
* Call a tool on the upstream server with timeout support.
|
|
73
|
+
*
|
|
74
|
+
* @param name - Tool name
|
|
75
|
+
* @param args - Tool arguments
|
|
76
|
+
* @returns Tool call result
|
|
77
|
+
* @throws UpstreamError if timeout or upstream error occurs
|
|
78
|
+
*/
|
|
79
|
+
callTool(name: string, args?: Record<string, unknown>): Promise<CallToolResult>;
|
|
80
|
+
/**
|
|
81
|
+
* Perform a health check on the upstream server.
|
|
82
|
+
* Tests connectivity by calling listTools().
|
|
83
|
+
*
|
|
84
|
+
* @returns Health check result
|
|
85
|
+
*/
|
|
86
|
+
healthCheck(): Promise<HealthCheckResult>;
|
|
87
|
+
/**
|
|
88
|
+
* Get the current health status.
|
|
89
|
+
*/
|
|
90
|
+
getHealthStatus(): HealthCheckResult;
|
|
91
|
+
/**
|
|
92
|
+
* Check if the upstream server is healthy.
|
|
93
|
+
*/
|
|
94
|
+
isHealthy(): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Check if the client is initialized and connected.
|
|
97
|
+
*/
|
|
98
|
+
isConnected(): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Close the upstream connection and stop health checks.
|
|
101
|
+
*/
|
|
102
|
+
close(): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Start periodic health checks.
|
|
105
|
+
*/
|
|
106
|
+
private startHealthChecks;
|
|
107
|
+
/**
|
|
108
|
+
* Stop periodic health checks.
|
|
109
|
+
*/
|
|
110
|
+
private stopHealthChecks;
|
|
111
|
+
/**
|
|
112
|
+
* Update health status and notify listeners.
|
|
113
|
+
*/
|
|
114
|
+
private updateHealthStatus;
|
|
115
|
+
/**
|
|
116
|
+
* Ensure the client is initialized before operations.
|
|
117
|
+
*/
|
|
118
|
+
private ensureInitialized;
|
|
119
|
+
/**
|
|
120
|
+
* Wrap a promise with a timeout.
|
|
121
|
+
*
|
|
122
|
+
* @param promise - Promise to wrap
|
|
123
|
+
* @param timeoutMs - Timeout in milliseconds
|
|
124
|
+
* @param operation - Description for error message
|
|
125
|
+
* @returns Promise result
|
|
126
|
+
* @throws UpstreamError on timeout
|
|
127
|
+
*/
|
|
128
|
+
private withTimeout;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/proxy/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAE1F,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAI1E;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,IAAI,CAAC;IAChB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,2BAA2B;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,oDAAoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,0CAA0C;IAC1C,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,KAAK,IAAI,CAAC;CAC/E;AAeD;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAS;IAG9B,OAAO,CAAC,iBAAiB,CAA8B;IACvD,OAAO,CAAC,mBAAmB,CAA+B;IAC1D,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,cAAc,CAAC,CAA+D;IAGtF,OAAO,CAAC,SAAS,CAAS;IAC1B,iDAAiD;IACjD,OAAO,CAAC,iBAAiB,CAA8B;gBAE3C,OAAO,EAAE,qBAAqB,GAAG,YAAY;IA6BzD;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAWjC;;OAEG;YACW,YAAY;IA0B1B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC;IAK3C;;;;;;;OAOG;IACG,QAAQ,CACZ,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,cAAc,CAAC;IAU1B;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAgD/C;;OAEG;IACH,eAAe,IAAI,iBAAiB;IASpC;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAoBzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAS1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASzB;;;;;;;;OAQG;YACW,WAAW;CAsB1B"}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upstream MCP Client
|
|
3
|
+
*
|
|
4
|
+
* Manages connection to the upstream MCP server with:
|
|
5
|
+
* - Health checking and status monitoring
|
|
6
|
+
* - Timeout support for tool calls
|
|
7
|
+
* - Connection state tracking
|
|
8
|
+
*/
|
|
9
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
10
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
11
|
+
import { UpstreamError } from '../utils/errors.js';
|
|
12
|
+
import { resolveServerEnv } from '../policy/parser.js';
|
|
13
|
+
import { upstreamLogger as logger } from '../utils/logger.js';
|
|
14
|
+
/**
|
|
15
|
+
* Default configuration values.
|
|
16
|
+
*/
|
|
17
|
+
const DEFAULTS = {
|
|
18
|
+
callTimeoutMs: 30000,
|
|
19
|
+
healthCheck: {
|
|
20
|
+
enabled: true,
|
|
21
|
+
intervalMs: 30000,
|
|
22
|
+
timeoutMs: 5000,
|
|
23
|
+
failureThreshold: 3,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Upstream MCP client with health monitoring and resilience features.
|
|
28
|
+
*/
|
|
29
|
+
export class UpstreamClient {
|
|
30
|
+
client;
|
|
31
|
+
transport = null;
|
|
32
|
+
config;
|
|
33
|
+
initialized = false;
|
|
34
|
+
callTimeoutMs;
|
|
35
|
+
// Health monitoring state
|
|
36
|
+
healthCheckConfig;
|
|
37
|
+
healthCheckInterval = null;
|
|
38
|
+
healthStatus = 'unknown';
|
|
39
|
+
lastHealthCheck = null;
|
|
40
|
+
consecutiveFailures = 0;
|
|
41
|
+
lastHealthError;
|
|
42
|
+
onHealthChange;
|
|
43
|
+
// Connection state tracking
|
|
44
|
+
isClosing = false;
|
|
45
|
+
/** Mutex to prevent concurrent initialization */
|
|
46
|
+
initializePromise = null;
|
|
47
|
+
constructor(options) {
|
|
48
|
+
// Support legacy constructor signature
|
|
49
|
+
if ('command' in options) {
|
|
50
|
+
this.config = options;
|
|
51
|
+
this.callTimeoutMs = DEFAULTS.callTimeoutMs;
|
|
52
|
+
this.healthCheckConfig = { ...DEFAULTS.healthCheck };
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
this.config = options.config;
|
|
56
|
+
this.callTimeoutMs = options.callTimeoutMs ?? DEFAULTS.callTimeoutMs;
|
|
57
|
+
this.healthCheckConfig = {
|
|
58
|
+
enabled: options.healthCheck?.enabled ?? DEFAULTS.healthCheck.enabled,
|
|
59
|
+
intervalMs: options.healthCheck?.intervalMs ?? DEFAULTS.healthCheck.intervalMs,
|
|
60
|
+
timeoutMs: options.healthCheck?.timeoutMs ?? DEFAULTS.healthCheck.timeoutMs,
|
|
61
|
+
failureThreshold: options.healthCheck?.failureThreshold ?? DEFAULTS.healthCheck.failureThreshold,
|
|
62
|
+
};
|
|
63
|
+
this.onHealthChange = options.onHealthChange;
|
|
64
|
+
}
|
|
65
|
+
this.client = new Client({
|
|
66
|
+
name: 'tollgate-client',
|
|
67
|
+
version: '0.1.0',
|
|
68
|
+
}, {
|
|
69
|
+
capabilities: {},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Initialize the upstream connection.
|
|
74
|
+
* Spawns the upstream MCP server process and establishes connection.
|
|
75
|
+
* Thread-safe: concurrent calls will wait for the first initialization to complete.
|
|
76
|
+
*/
|
|
77
|
+
async initialize() {
|
|
78
|
+
// Already initialized
|
|
79
|
+
if (this.initialized)
|
|
80
|
+
return;
|
|
81
|
+
// Use mutex pattern to prevent concurrent initialization
|
|
82
|
+
if (!this.initializePromise) {
|
|
83
|
+
this.initializePromise = this.doInitialize();
|
|
84
|
+
}
|
|
85
|
+
return this.initializePromise;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Internal initialization logic.
|
|
89
|
+
*/
|
|
90
|
+
async doInitialize() {
|
|
91
|
+
if (this.initialized)
|
|
92
|
+
return;
|
|
93
|
+
const resolvedEnv = resolveServerEnv(this.config.env);
|
|
94
|
+
// StdioClientTransport spawns the process internally
|
|
95
|
+
this.transport = new StdioClientTransport({
|
|
96
|
+
command: this.config.command,
|
|
97
|
+
args: this.config.args,
|
|
98
|
+
env: resolvedEnv,
|
|
99
|
+
cwd: this.config.cwd,
|
|
100
|
+
});
|
|
101
|
+
// Connect the client
|
|
102
|
+
await this.client.connect(this.transport);
|
|
103
|
+
this.initialized = true;
|
|
104
|
+
// Start health checking if enabled
|
|
105
|
+
if (this.healthCheckConfig.enabled) {
|
|
106
|
+
this.startHealthChecks();
|
|
107
|
+
}
|
|
108
|
+
// Mark as healthy after successful initialization
|
|
109
|
+
this.updateHealthStatus('healthy');
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* List available tools from the upstream server.
|
|
113
|
+
*/
|
|
114
|
+
async listTools() {
|
|
115
|
+
this.ensureInitialized();
|
|
116
|
+
return await this.client.listTools();
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Call a tool on the upstream server with timeout support.
|
|
120
|
+
*
|
|
121
|
+
* @param name - Tool name
|
|
122
|
+
* @param args - Tool arguments
|
|
123
|
+
* @returns Tool call result
|
|
124
|
+
* @throws UpstreamError if timeout or upstream error occurs
|
|
125
|
+
*/
|
|
126
|
+
async callTool(name, args) {
|
|
127
|
+
this.ensureInitialized();
|
|
128
|
+
return await this.withTimeout(this.client.callTool({ name, arguments: args }), this.callTimeoutMs, `Tool call '${name}'`);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Perform a health check on the upstream server.
|
|
132
|
+
* Tests connectivity by calling listTools().
|
|
133
|
+
*
|
|
134
|
+
* @returns Health check result
|
|
135
|
+
*/
|
|
136
|
+
async healthCheck() {
|
|
137
|
+
if (!this.initialized) {
|
|
138
|
+
return {
|
|
139
|
+
status: 'unknown',
|
|
140
|
+
lastCheck: new Date(),
|
|
141
|
+
consecutiveFailures: 0,
|
|
142
|
+
error: 'Client not initialized',
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
// Use listTools as a ping - it's lightweight and always available
|
|
147
|
+
await this.withTimeout(this.client.listTools(), this.healthCheckConfig.timeoutMs, 'Health check');
|
|
148
|
+
// Success - reset failure count
|
|
149
|
+
this.consecutiveFailures = 0;
|
|
150
|
+
this.lastHealthError = undefined;
|
|
151
|
+
this.updateHealthStatus('healthy');
|
|
152
|
+
return {
|
|
153
|
+
status: 'healthy',
|
|
154
|
+
lastCheck: new Date(),
|
|
155
|
+
consecutiveFailures: 0,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
this.consecutiveFailures++;
|
|
160
|
+
this.lastHealthError = error instanceof Error ? error.message : String(error);
|
|
161
|
+
const isUnhealthy = this.consecutiveFailures >= this.healthCheckConfig.failureThreshold;
|
|
162
|
+
if (isUnhealthy) {
|
|
163
|
+
this.updateHealthStatus('unhealthy');
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
status: isUnhealthy ? 'unhealthy' : this.healthStatus,
|
|
167
|
+
lastCheck: new Date(),
|
|
168
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
169
|
+
error: this.lastHealthError,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
this.lastHealthCheck = new Date();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Get the current health status.
|
|
178
|
+
*/
|
|
179
|
+
getHealthStatus() {
|
|
180
|
+
return {
|
|
181
|
+
status: this.healthStatus,
|
|
182
|
+
lastCheck: this.lastHealthCheck ?? new Date(),
|
|
183
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
184
|
+
error: this.lastHealthError,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Check if the upstream server is healthy.
|
|
189
|
+
*/
|
|
190
|
+
isHealthy() {
|
|
191
|
+
return this.healthStatus === 'healthy';
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Check if the client is initialized and connected.
|
|
195
|
+
*/
|
|
196
|
+
isConnected() {
|
|
197
|
+
return this.initialized && !this.isClosing;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Close the upstream connection and stop health checks.
|
|
201
|
+
*/
|
|
202
|
+
async close() {
|
|
203
|
+
this.isClosing = true;
|
|
204
|
+
this.stopHealthChecks();
|
|
205
|
+
if (this.transport) {
|
|
206
|
+
await this.transport.close();
|
|
207
|
+
this.transport = null;
|
|
208
|
+
}
|
|
209
|
+
this.initialized = false;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Start periodic health checks.
|
|
213
|
+
*/
|
|
214
|
+
startHealthChecks() {
|
|
215
|
+
if (this.healthCheckInterval)
|
|
216
|
+
return;
|
|
217
|
+
this.healthCheckInterval = setInterval(async () => {
|
|
218
|
+
if (this.initialized && !this.isClosing) {
|
|
219
|
+
try {
|
|
220
|
+
await this.healthCheck();
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
// Log health check errors but don't crash
|
|
224
|
+
logger.error('Health check error', {
|
|
225
|
+
error: error instanceof Error ? error.message : String(error),
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}, this.healthCheckConfig.intervalMs);
|
|
230
|
+
// Don't prevent process exit
|
|
231
|
+
this.healthCheckInterval.unref();
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Stop periodic health checks.
|
|
235
|
+
*/
|
|
236
|
+
stopHealthChecks() {
|
|
237
|
+
if (this.healthCheckInterval) {
|
|
238
|
+
clearInterval(this.healthCheckInterval);
|
|
239
|
+
this.healthCheckInterval = null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Update health status and notify listeners.
|
|
244
|
+
*/
|
|
245
|
+
updateHealthStatus(newStatus) {
|
|
246
|
+
const previousStatus = this.healthStatus;
|
|
247
|
+
this.healthStatus = newStatus;
|
|
248
|
+
if (previousStatus !== newStatus && this.onHealthChange) {
|
|
249
|
+
this.onHealthChange(newStatus, previousStatus);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Ensure the client is initialized before operations.
|
|
254
|
+
*/
|
|
255
|
+
ensureInitialized() {
|
|
256
|
+
if (!this.initialized) {
|
|
257
|
+
throw new UpstreamError('Client not initialized');
|
|
258
|
+
}
|
|
259
|
+
if (this.isClosing) {
|
|
260
|
+
throw new UpstreamError('Client is closing');
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Wrap a promise with a timeout.
|
|
265
|
+
*
|
|
266
|
+
* @param promise - Promise to wrap
|
|
267
|
+
* @param timeoutMs - Timeout in milliseconds
|
|
268
|
+
* @param operation - Description for error message
|
|
269
|
+
* @returns Promise result
|
|
270
|
+
* @throws UpstreamError on timeout
|
|
271
|
+
*/
|
|
272
|
+
async withTimeout(promise, timeoutMs, operation) {
|
|
273
|
+
let timeoutId;
|
|
274
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
275
|
+
timeoutId = setTimeout(() => {
|
|
276
|
+
reject(new UpstreamError(`${operation} timed out after ${timeoutMs}ms`));
|
|
277
|
+
}, timeoutMs);
|
|
278
|
+
});
|
|
279
|
+
try {
|
|
280
|
+
const result = await Promise.race([promise, timeoutPromise]);
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
283
|
+
finally {
|
|
284
|
+
if (timeoutId) {
|
|
285
|
+
clearTimeout(timeoutId);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/proxy/client.ts"],"names":[],"mappings":"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"}
|