@winstonsayno/mcp-gateway 0.0.0-stage → 0.4.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/CHANGELOG.md +130 -0
- package/LICENSE +21 -0
- package/README.md +432 -2
- package/dashboard/README.md +27 -0
- package/dashboard/index.html +415 -0
- package/dist/auth/middleware.d.ts +24 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +108 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/ratelimit.d.ts +19 -0
- package/dist/auth/ratelimit.d.ts.map +1 -0
- package/dist/auth/ratelimit.js +81 -0
- package/dist/auth/ratelimit.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +129 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/loader.d.ts +13 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +276 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/watcher.d.ts +29 -0
- package/dist/config/watcher.d.ts.map +1 -0
- package/dist/config/watcher.js +96 -0
- package/dist/config/watcher.js.map +1 -0
- package/dist/gateway/api.d.ts +47 -0
- package/dist/gateway/api.d.ts.map +1 -0
- package/dist/gateway/api.js +324 -0
- package/dist/gateway/api.js.map +1 -0
- package/dist/gateway/index.d.ts +49 -0
- package/dist/gateway/index.d.ts.map +1 -0
- package/dist/gateway/index.js +261 -0
- package/dist/gateway/index.js.map +1 -0
- package/dist/gateway/supervisor.d.ts +58 -0
- package/dist/gateway/supervisor.d.ts.map +1 -0
- package/dist/gateway/supervisor.js +205 -0
- package/dist/gateway/supervisor.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/cors.d.ts +19 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +65 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +40 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +98 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/request-id.d.ts +23 -0
- package/dist/middleware/request-id.d.ts.map +1 -0
- package/dist/middleware/request-id.js +30 -0
- package/dist/middleware/request-id.js.map +1 -0
- package/dist/middleware/timeout.d.ts +12 -0
- package/dist/middleware/timeout.d.ts.map +1 -0
- package/dist/middleware/timeout.js +39 -0
- package/dist/middleware/timeout.js.map +1 -0
- package/dist/monitor/index.d.ts +49 -0
- package/dist/monitor/index.d.ts.map +1 -0
- package/dist/monitor/index.js +204 -0
- package/dist/monitor/index.js.map +1 -0
- package/dist/proxy/index.d.ts +86 -0
- package/dist/proxy/index.d.ts.map +1 -0
- package/dist/proxy/index.js +389 -0
- package/dist/proxy/index.js.map +1 -0
- package/dist/registry/index.d.ts +48 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +171 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/transport/channel.d.ts +61 -0
- package/dist/transport/channel.d.ts.map +1 -0
- package/dist/transport/channel.js +38 -0
- package/dist/transport/channel.js.map +1 -0
- package/dist/transport/sse-parser.d.ts +30 -0
- package/dist/transport/sse-parser.d.ts.map +1 -0
- package/dist/transport/sse-parser.js +107 -0
- package/dist/transport/sse-parser.js.map +1 -0
- package/dist/transport/sse.d.ts +39 -0
- package/dist/transport/sse.d.ts.map +1 -0
- package/dist/transport/sse.js +142 -0
- package/dist/transport/sse.js.map +1 -0
- package/dist/transport/stdio.d.ts +35 -0
- package/dist/transport/stdio.d.ts.map +1 -0
- package/dist/transport/stdio.js +149 -0
- package/dist/transport/stdio.js.map +1 -0
- package/dist/transport/streamable-http.d.ts +45 -0
- package/dist/transport/streamable-http.d.ts.map +1 -0
- package/dist/transport/streamable-http.js +183 -0
- package/dist/transport/streamable-http.js.map +1 -0
- package/dist/transport/websocket.d.ts +38 -0
- package/dist/transport/websocket.d.ts.map +1 -0
- package/dist/transport/websocket.js +172 -0
- package/dist/transport/websocket.js.map +1 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +60 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/mutex.d.ts +25 -0
- package/dist/utils/mutex.d.ts.map +1 -0
- package/dist/utils/mutex.js +62 -0
- package/dist/utils/mutex.js.map +1 -0
- package/dist/utils/semaphore.d.ts +16 -0
- package/dist/utils/semaphore.d.ts.map +1 -0
- package/dist/utils/semaphore.js +42 -0
- package/dist/utils/semaphore.js.map +1 -0
- package/dist/utils/tool-filter.d.ts +24 -0
- package/dist/utils/tool-filter.d.ts.map +1 -0
- package/dist/utils/tool-filter.js +48 -0
- package/dist/utils/tool-filter.js.map +1 -0
- package/dist/utils/types.d.ts +223 -0
- package/dist/utils/types.d.ts.map +1 -0
- package/dist/utils/types.js +5 -0
- package/dist/utils/types.js.map +1 -0
- package/dist/utils/version.d.ts +6 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +18 -0
- package/dist/utils/version.js.map +1 -0
- package/package.json +79 -4
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway bootstrap — wires together all subsystems
|
|
3
|
+
*/
|
|
4
|
+
import express from 'express';
|
|
5
|
+
import { createServer } from 'http';
|
|
6
|
+
import { existsSync } from 'fs';
|
|
7
|
+
import { dirname, resolve } from 'path';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
import { ServerRegistry } from '../registry/index.js';
|
|
10
|
+
import { McpProxy } from '../proxy/index.js';
|
|
11
|
+
import { MetricsCollector } from '../monitor/index.js';
|
|
12
|
+
import { createApiRouter } from './api.js';
|
|
13
|
+
import { ServerSupervisor } from './supervisor.js';
|
|
14
|
+
import { corsMiddleware } from '../middleware/cors.js';
|
|
15
|
+
import { requestIdMiddleware } from '../middleware/request-id.js';
|
|
16
|
+
import { errorHandler, notFoundHandler } from '../middleware/error-handler.js';
|
|
17
|
+
import { logger } from '../utils/logger.js';
|
|
18
|
+
import { Mutex } from '../utils/mutex.js';
|
|
19
|
+
import { VERSION } from '../utils/version.js';
|
|
20
|
+
function findDashboard() {
|
|
21
|
+
// src/gateway → ../../dashboard (tsx) and dist/gateway → ../../dashboard (built)
|
|
22
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
const file = resolve(here, '../../dashboard/index.html');
|
|
24
|
+
return existsSync(file) ? file : undefined;
|
|
25
|
+
}
|
|
26
|
+
export class Gateway {
|
|
27
|
+
config;
|
|
28
|
+
app = express();
|
|
29
|
+
server = createServer(this.app);
|
|
30
|
+
registry;
|
|
31
|
+
proxy;
|
|
32
|
+
metrics;
|
|
33
|
+
supervisor;
|
|
34
|
+
router;
|
|
35
|
+
cors;
|
|
36
|
+
reloadLock = new Mutex();
|
|
37
|
+
started = false;
|
|
38
|
+
stopping;
|
|
39
|
+
constructor(config) {
|
|
40
|
+
this.config = config;
|
|
41
|
+
this.registry = new ServerRegistry(config.healthCheckIntervalMs ?? 30_000);
|
|
42
|
+
this.proxy = new McpProxy();
|
|
43
|
+
this.metrics = new MetricsCollector(config.monitor);
|
|
44
|
+
this.supervisor = new ServerSupervisor(this.proxy, this.registry, { reconnect: config.reconnect });
|
|
45
|
+
this.cors = corsMiddleware({ origins: config.corsOrigins ?? ['*'] });
|
|
46
|
+
}
|
|
47
|
+
async start() {
|
|
48
|
+
if (this.started)
|
|
49
|
+
throw new Error('Gateway already started');
|
|
50
|
+
this.started = true;
|
|
51
|
+
logger.setLevel(this.config.logLevel ?? 'info');
|
|
52
|
+
// Builds auth/rate-limit; throws on insecure misconfiguration (fail closed)
|
|
53
|
+
this.router = createApiRouter(this.config, this.registry, this.proxy, this.metrics, {
|
|
54
|
+
supervisor: this.supervisor,
|
|
55
|
+
isShuttingDown: () => this.stopping !== undefined,
|
|
56
|
+
});
|
|
57
|
+
this.app.disable('x-powered-by');
|
|
58
|
+
this.app.use(requestIdMiddleware);
|
|
59
|
+
// Previously an inline handler joined multiple origins into one
|
|
60
|
+
// Access-Control-Allow-Origin value, which browsers reject.
|
|
61
|
+
// Indirection so CORS origins can be hot reloaded.
|
|
62
|
+
this.app.use((req, res, next) => this.cors(req, res, next));
|
|
63
|
+
this.app.use(express.json({ limit: '10mb' }));
|
|
64
|
+
this.app.use('/api/v1', this.router);
|
|
65
|
+
const dashboard = this.config.dashboard?.enabled === false ? undefined : findDashboard();
|
|
66
|
+
if (dashboard) {
|
|
67
|
+
this.app.get('/dashboard', (_req, res) => res.sendFile(dashboard));
|
|
68
|
+
}
|
|
69
|
+
this.app.get('/', (_req, res) => {
|
|
70
|
+
res.json({
|
|
71
|
+
name: 'mcp-gateway',
|
|
72
|
+
version: VERSION,
|
|
73
|
+
docs: '/api/v1/health',
|
|
74
|
+
dashboard: dashboard
|
|
75
|
+
? '/dashboard'
|
|
76
|
+
: this.config.dashboard?.enabled === false
|
|
77
|
+
? 'disabled'
|
|
78
|
+
: 'not available (dashboard/index.html missing)',
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
this.app.use(notFoundHandler);
|
|
82
|
+
this.app.use(errorHandler);
|
|
83
|
+
this.metrics.start();
|
|
84
|
+
await this.connectServers(this.config.servers);
|
|
85
|
+
this.registry.startHealthChecks((serverId) => this.checkHealth(serverId));
|
|
86
|
+
// Reject on listen errors (EADDRINUSE, EACCES) instead of hanging forever
|
|
87
|
+
// and crashing with an unhandled 'error' event.
|
|
88
|
+
await new Promise((resolveListen, rejectListen) => {
|
|
89
|
+
const onError = (err) => {
|
|
90
|
+
this.server.off('listening', onListening);
|
|
91
|
+
rejectListen(err);
|
|
92
|
+
};
|
|
93
|
+
const onListening = () => {
|
|
94
|
+
this.server.off('error', onError);
|
|
95
|
+
const { port } = this.address() ?? { port: this.config.port };
|
|
96
|
+
logger.info(`mcp-gateway v${VERSION} listening on http://${this.config.host}:${port}`);
|
|
97
|
+
logger.info(`API: http://${this.config.host}:${port}/api/v1`);
|
|
98
|
+
resolveListen();
|
|
99
|
+
};
|
|
100
|
+
this.server.once('error', onError);
|
|
101
|
+
this.server.once('listening', onListening);
|
|
102
|
+
this.server.listen(this.config.port, this.config.host);
|
|
103
|
+
}).catch(async (err) => {
|
|
104
|
+
await this.shutdownInternals();
|
|
105
|
+
throw err;
|
|
106
|
+
});
|
|
107
|
+
this.server.on('error', (err) => logger.error(`HTTP server error: ${err.message}`));
|
|
108
|
+
}
|
|
109
|
+
/** Bound address (useful when listening on port 0). */
|
|
110
|
+
address() {
|
|
111
|
+
const a = this.server.address();
|
|
112
|
+
return a && typeof a === 'object' ? a : undefined;
|
|
113
|
+
}
|
|
114
|
+
/** Idempotent: concurrent/double calls (e.g. SIGINT twice) share one shutdown. */
|
|
115
|
+
stop() {
|
|
116
|
+
this.stopping ??= this._stop();
|
|
117
|
+
return this.stopping;
|
|
118
|
+
}
|
|
119
|
+
async _stop() {
|
|
120
|
+
logger.info('Shutting down mcp-gateway...');
|
|
121
|
+
const closed = this.server.listening
|
|
122
|
+
? new Promise((res, rej) => this.server.close((err) => (err ? rej(err) : res())))
|
|
123
|
+
: Promise.resolve();
|
|
124
|
+
// Idle keep-alive sockets would otherwise hold close() open indefinitely.
|
|
125
|
+
this.server.closeIdleConnections?.();
|
|
126
|
+
await this.shutdownInternals();
|
|
127
|
+
const force = setTimeout(() => this.server.closeAllConnections?.(), 5_000);
|
|
128
|
+
force.unref();
|
|
129
|
+
try {
|
|
130
|
+
await closed;
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
clearTimeout(force);
|
|
134
|
+
}
|
|
135
|
+
logger.info('Gateway stopped.');
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* One health check: an MCP `ping` for connected servers (records latency,
|
|
139
|
+
* marks `degraded` when it fails); disconnected servers are `reconnecting`
|
|
140
|
+
* while the supervisor is on it, otherwise `offline`.
|
|
141
|
+
*/
|
|
142
|
+
async checkHealth(serverId) {
|
|
143
|
+
if (this.proxy.isConnected(serverId)) {
|
|
144
|
+
const timeout = Math.min(this.registry.getServer(serverId)?.timeout ?? 5_000, 5_000);
|
|
145
|
+
try {
|
|
146
|
+
const latency = await this.proxy.ping(serverId, timeout);
|
|
147
|
+
if (this.proxy.isConnected(serverId))
|
|
148
|
+
this.registry.updateHealth(serverId, 'online', latency);
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
if (!this.proxy.isConnected(serverId))
|
|
152
|
+
return; // the disconnect handler owns the status now
|
|
153
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
154
|
+
this.registry.updateHealth(serverId, 'degraded', undefined, `health ping failed: ${msg}`);
|
|
155
|
+
}
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (this.supervisor.isRecovering(serverId))
|
|
159
|
+
return;
|
|
160
|
+
const prev = this.registry.getHealth(serverId);
|
|
161
|
+
this.registry.updateHealth(serverId, 'offline', undefined, prev?.errorMessage);
|
|
162
|
+
}
|
|
163
|
+
async shutdownInternals() {
|
|
164
|
+
this.supervisor.stop();
|
|
165
|
+
this.registry.stopHealthChecks();
|
|
166
|
+
this.metrics.stop();
|
|
167
|
+
this.router?.close();
|
|
168
|
+
await this.proxy.disconnectAll();
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Apply a new configuration without restarting:
|
|
172
|
+
* - servers that were removed or disabled are disconnected, new or changed
|
|
173
|
+
* ones (re)connected;
|
|
174
|
+
* - auth (strategy, keys, secret, protect flags), rate limits, CORS origins,
|
|
175
|
+
* monitor.requestLog / monitor.prometheus, reconnect policy and logLevel
|
|
176
|
+
* take effect immediately.
|
|
177
|
+
* port, host, monitor.retentionHours, healthCheckIntervalMs and dashboard
|
|
178
|
+
* still require a restart.
|
|
179
|
+
*/
|
|
180
|
+
async reload(next) {
|
|
181
|
+
await this.reloadLock.runExclusive(async () => {
|
|
182
|
+
if (this.stopping)
|
|
183
|
+
return;
|
|
184
|
+
const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
185
|
+
const key = (s) => JSON.stringify(s);
|
|
186
|
+
const current = new Map(this.config.servers.filter((s) => s.enabled !== false).map((s) => [s.id, s]));
|
|
187
|
+
const wanted = new Map(next.servers.filter((s) => s.enabled !== false).map((s) => [s.id, s]));
|
|
188
|
+
const toRemove = [...current.keys()].filter((id) => !wanted.has(id));
|
|
189
|
+
const reconnectChanged = !same(this.config.reconnect, next.reconnect);
|
|
190
|
+
const toConnect = [...wanted.values()].filter((s) => {
|
|
191
|
+
const prev = current.get(s.id);
|
|
192
|
+
return !prev || key(prev) !== key(s);
|
|
193
|
+
});
|
|
194
|
+
const applied = [];
|
|
195
|
+
for (const field of ['port', 'host', 'healthCheckIntervalMs', 'dashboard']) {
|
|
196
|
+
if (!same(this.config[field], next[field])) {
|
|
197
|
+
logger.warn(`Config "${field}" changed — restart required for it to take effect`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (this.config.monitor?.retentionHours !== next.monitor?.retentionHours) {
|
|
201
|
+
logger.warn('Config "monitor.retentionHours" changed — restart required for it to take effect');
|
|
202
|
+
}
|
|
203
|
+
// Router-level settings (auth may be rejected and kept; the router logs that).
|
|
204
|
+
this.router?.update(next);
|
|
205
|
+
if (!same(this.config.auth, next.auth))
|
|
206
|
+
applied.push('auth');
|
|
207
|
+
if (!same(this.config.rateLimit, next.rateLimit))
|
|
208
|
+
applied.push('rateLimit');
|
|
209
|
+
if (!same(this.config.monitor, next.monitor))
|
|
210
|
+
applied.push('monitor');
|
|
211
|
+
if (!same(this.config.corsOrigins, next.corsOrigins)) {
|
|
212
|
+
this.cors = corsMiddleware({ origins: next.corsOrigins ?? ['*'] });
|
|
213
|
+
applied.push('corsOrigins');
|
|
214
|
+
}
|
|
215
|
+
if (reconnectChanged) {
|
|
216
|
+
this.supervisor.setReconnectDefaults(next.reconnect);
|
|
217
|
+
applied.push('reconnect');
|
|
218
|
+
}
|
|
219
|
+
if (next.logLevel && next.logLevel !== this.config.logLevel) {
|
|
220
|
+
logger.setLevel(next.logLevel);
|
|
221
|
+
applied.push('logLevel');
|
|
222
|
+
}
|
|
223
|
+
await Promise.all(toRemove.map(async (id) => {
|
|
224
|
+
this.supervisor.forget(id);
|
|
225
|
+
await this.proxy.disconnect(id);
|
|
226
|
+
this.registry.unregister(id);
|
|
227
|
+
}));
|
|
228
|
+
this.config = {
|
|
229
|
+
...this.config,
|
|
230
|
+
servers: next.servers,
|
|
231
|
+
logLevel: next.logLevel ?? this.config.logLevel,
|
|
232
|
+
auth: next.auth,
|
|
233
|
+
rateLimit: next.rateLimit,
|
|
234
|
+
monitor: next.monitor ? { ...next.monitor, retentionHours: this.config.monitor?.retentionHours } : next.monitor,
|
|
235
|
+
corsOrigins: next.corsOrigins,
|
|
236
|
+
reconnect: next.reconnect,
|
|
237
|
+
};
|
|
238
|
+
await this.connectServers(toConnect);
|
|
239
|
+
logger.info(`Hot reload applied: ${toConnect.length} (re)connected, ${toRemove.length} removed` +
|
|
240
|
+
(applied.length ? `; updated ${applied.join(', ')}` : ''));
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
async connectServers(servers) {
|
|
244
|
+
const enabled = servers.filter((s) => s.enabled !== false);
|
|
245
|
+
if (enabled.length === 0)
|
|
246
|
+
return;
|
|
247
|
+
logger.info(`Connecting to ${enabled.length} MCP server(s)...`);
|
|
248
|
+
const outcomes = await Promise.all(enabled.map((serverConfig) => {
|
|
249
|
+
this.registry.register(serverConfig);
|
|
250
|
+
// Failed servers are retried in the background with backoff.
|
|
251
|
+
return this.supervisor.connect(serverConfig);
|
|
252
|
+
}));
|
|
253
|
+
const succeeded = outcomes.filter(Boolean).length;
|
|
254
|
+
logger.info(`Connected: ${succeeded}/${enabled.length} servers (${enabled.length - succeeded} failed)`);
|
|
255
|
+
}
|
|
256
|
+
/** Server registry (read-only use when embedding). */
|
|
257
|
+
getRegistry() {
|
|
258
|
+
return this.registry;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gateway/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server supervisor — keeps every enabled MCP server connected.
|
|
3
|
+
*
|
|
4
|
+
* - Connects servers and publishes their tools and health to the registry.
|
|
5
|
+
* - When a server fails to connect, crashes or disconnects (`proxy` emits
|
|
6
|
+
* `disconnected`), it schedules a reconnect with exponential backoff and
|
|
7
|
+
* jitter, re-running the full MCP handshake on a fresh channel.
|
|
8
|
+
* - Reconnect state (attempt, next attempt time, last error, reconnect count)
|
|
9
|
+
* is mirrored into the registry so `/servers`, `/health`, the dashboard and
|
|
10
|
+
* Prometheus can show it.
|
|
11
|
+
*
|
|
12
|
+
* Each server carries a generation number; a hot reload or removal bumps it so
|
|
13
|
+
* an in-flight attempt that finishes late can never resurrect stale state.
|
|
14
|
+
*
|
|
15
|
+
* @module gateway/supervisor
|
|
16
|
+
*/
|
|
17
|
+
import type { McpServerConfig, ReconnectConfig, ReconnectState } from '../utils/types.js';
|
|
18
|
+
import type { McpProxy } from '../proxy/index.js';
|
|
19
|
+
import type { ServerRegistry } from '../registry/index.js';
|
|
20
|
+
export declare const DEFAULT_RECONNECT: ReconnectConfig;
|
|
21
|
+
export declare function resolveReconnect(gateway?: Partial<ReconnectConfig>, server?: Partial<ReconnectConfig>): ReconnectConfig;
|
|
22
|
+
/**
|
|
23
|
+
* Delay before reconnect attempt `attempt` (1-based):
|
|
24
|
+
* `min(maxDelay, initialDelay * multiplier^(attempt-1))`, then ±jitter.
|
|
25
|
+
*/
|
|
26
|
+
export declare function computeBackoff(attempt: number, cfg: ReconnectConfig, random?: () => number): number;
|
|
27
|
+
export interface SupervisorOptions {
|
|
28
|
+
/** Gateway-wide reconnect defaults (merged with each server's `reconnect`). */
|
|
29
|
+
reconnect?: Partial<ReconnectConfig>;
|
|
30
|
+
random?: () => number;
|
|
31
|
+
}
|
|
32
|
+
export declare class ServerSupervisor {
|
|
33
|
+
private readonly proxy;
|
|
34
|
+
private readonly registry;
|
|
35
|
+
private readonly entries;
|
|
36
|
+
private reconnectDefaults?;
|
|
37
|
+
private readonly random;
|
|
38
|
+
private stopped;
|
|
39
|
+
private readonly onDisconnected;
|
|
40
|
+
private readonly onToolsChanged;
|
|
41
|
+
constructor(proxy: McpProxy, registry: ServerRegistry, options?: SupervisorOptions);
|
|
42
|
+
/** Update gateway-wide reconnect defaults (hot reload). Applies to future attempts. */
|
|
43
|
+
setReconnectDefaults(reconnect?: Partial<ReconnectConfig>): void;
|
|
44
|
+
/** Connect (or reconnect with a new config) now. Resolves true on success. */
|
|
45
|
+
connect(config: McpServerConfig): Promise<boolean>;
|
|
46
|
+
/** Stop managing a server (cancel pending reconnects). Does not disconnect it. */
|
|
47
|
+
forget(serverId: string): void;
|
|
48
|
+
/** Is a reconnect scheduled or in progress for this server? */
|
|
49
|
+
isRecovering(serverId: string): boolean;
|
|
50
|
+
getState(serverId: string): ReconnectState | undefined;
|
|
51
|
+
stop(): void;
|
|
52
|
+
private current;
|
|
53
|
+
private attempt;
|
|
54
|
+
private handleDisconnect;
|
|
55
|
+
private scheduleRetry;
|
|
56
|
+
private publish;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=supervisor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../../src/gateway/supervisor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAY,MAAM,mBAAmB,CAAC;AACpG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,eAAO,MAAM,iBAAiB,EAAE,eAO/B,CAAC;AAEF,wBAAgB,gBAAgB,CAC9B,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,EAClC,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAChC,eAAe,CAMjB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,GAAE,MAAM,MAAoB,GAAG,MAAM,CAMhH;AAUD,MAAM,WAAW,iBAAiB;IAChC,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;CACvB;AAED,qBAAa,gBAAgB;IAazB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAb3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,iBAAiB,CAAC,CAA2B;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA0E;IACzG,OAAO,CAAC,QAAQ,CAAC,cAAc,CAI7B;gBAGiB,KAAK,EAAE,QAAQ,EACf,QAAQ,EAAE,cAAc,EACzC,OAAO,GAAE,iBAAsB;IAQjC,uFAAuF;IACvF,oBAAoB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAKhE,8EAA8E;IACxE,OAAO,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAexD,kFAAkF;IAClF,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAO9B,+DAA+D;IAC/D,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAKvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAKtD,IAAI,IAAI,IAAI;IAUZ,OAAO,CAAC,OAAO;YAID,OAAO;IAgCrB,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,OAAO;CAUhB"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server supervisor — keeps every enabled MCP server connected.
|
|
3
|
+
*
|
|
4
|
+
* - Connects servers and publishes their tools and health to the registry.
|
|
5
|
+
* - When a server fails to connect, crashes or disconnects (`proxy` emits
|
|
6
|
+
* `disconnected`), it schedules a reconnect with exponential backoff and
|
|
7
|
+
* jitter, re-running the full MCP handshake on a fresh channel.
|
|
8
|
+
* - Reconnect state (attempt, next attempt time, last error, reconnect count)
|
|
9
|
+
* is mirrored into the registry so `/servers`, `/health`, the dashboard and
|
|
10
|
+
* Prometheus can show it.
|
|
11
|
+
*
|
|
12
|
+
* Each server carries a generation number; a hot reload or removal bumps it so
|
|
13
|
+
* an in-flight attempt that finishes late can never resurrect stale state.
|
|
14
|
+
*
|
|
15
|
+
* @module gateway/supervisor
|
|
16
|
+
*/
|
|
17
|
+
import { logger } from '../utils/logger.js';
|
|
18
|
+
export const DEFAULT_RECONNECT = {
|
|
19
|
+
enabled: true,
|
|
20
|
+
initialDelayMs: 1_000,
|
|
21
|
+
maxDelayMs: 60_000,
|
|
22
|
+
multiplier: 2,
|
|
23
|
+
jitter: 0.2,
|
|
24
|
+
maxAttempts: 0,
|
|
25
|
+
};
|
|
26
|
+
export function resolveReconnect(gateway, server) {
|
|
27
|
+
const strip = (o) => Object.fromEntries(Object.entries(o ?? {}).filter(([, v]) => v !== undefined));
|
|
28
|
+
const merged = { ...DEFAULT_RECONNECT, ...strip(gateway), ...strip(server) };
|
|
29
|
+
merged.maxDelayMs = Math.max(merged.maxDelayMs, merged.initialDelayMs);
|
|
30
|
+
return merged;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Delay before reconnect attempt `attempt` (1-based):
|
|
34
|
+
* `min(maxDelay, initialDelay * multiplier^(attempt-1))`, then ±jitter.
|
|
35
|
+
*/
|
|
36
|
+
export function computeBackoff(attempt, cfg, random = Math.random) {
|
|
37
|
+
const exp = cfg.initialDelayMs * Math.pow(cfg.multiplier, Math.max(0, attempt - 1));
|
|
38
|
+
const base = Math.min(cfg.maxDelayMs, exp);
|
|
39
|
+
const spread = base * cfg.jitter;
|
|
40
|
+
const jittered = base - spread + random() * 2 * spread;
|
|
41
|
+
return Math.max(0, Math.round(Math.min(cfg.maxDelayMs, jittered)));
|
|
42
|
+
}
|
|
43
|
+
export class ServerSupervisor {
|
|
44
|
+
proxy;
|
|
45
|
+
registry;
|
|
46
|
+
entries = new Map();
|
|
47
|
+
reconnectDefaults;
|
|
48
|
+
random;
|
|
49
|
+
stopped = false;
|
|
50
|
+
onDisconnected = (serverId, err) => this.handleDisconnect(serverId, err);
|
|
51
|
+
onToolsChanged = (serverId, tools) => {
|
|
52
|
+
if (!this.entries.has(serverId))
|
|
53
|
+
return;
|
|
54
|
+
this.registry.setTools(serverId, tools);
|
|
55
|
+
logger.info(`Server "${serverId}" updated its tool list (${tools.length} tools)`);
|
|
56
|
+
};
|
|
57
|
+
constructor(proxy, registry, options = {}) {
|
|
58
|
+
this.proxy = proxy;
|
|
59
|
+
this.registry = registry;
|
|
60
|
+
this.reconnectDefaults = options.reconnect;
|
|
61
|
+
this.random = options.random ?? Math.random;
|
|
62
|
+
proxy.on('disconnected', this.onDisconnected);
|
|
63
|
+
proxy.on('tools-changed', this.onToolsChanged);
|
|
64
|
+
}
|
|
65
|
+
/** Update gateway-wide reconnect defaults (hot reload). Applies to future attempts. */
|
|
66
|
+
setReconnectDefaults(reconnect) {
|
|
67
|
+
this.reconnectDefaults = reconnect;
|
|
68
|
+
for (const e of this.entries.values())
|
|
69
|
+
e.policy = resolveReconnect(reconnect, e.config.reconnect);
|
|
70
|
+
}
|
|
71
|
+
/** Connect (or reconnect with a new config) now. Resolves true on success. */
|
|
72
|
+
async connect(config) {
|
|
73
|
+
if (this.stopped)
|
|
74
|
+
return false;
|
|
75
|
+
const prev = this.entries.get(config.id);
|
|
76
|
+
if (prev?.timer)
|
|
77
|
+
clearTimeout(prev.timer);
|
|
78
|
+
const entry = {
|
|
79
|
+
config,
|
|
80
|
+
policy: resolveReconnect(this.reconnectDefaults, config.reconnect),
|
|
81
|
+
gen: (prev?.gen ?? 0) + 1,
|
|
82
|
+
state: { state: 'connecting', attempt: 0, reconnects: prev?.state.reconnects ?? 0 },
|
|
83
|
+
};
|
|
84
|
+
this.entries.set(config.id, entry);
|
|
85
|
+
this.publish(entry);
|
|
86
|
+
return this.attempt(entry, entry.gen, false);
|
|
87
|
+
}
|
|
88
|
+
/** Stop managing a server (cancel pending reconnects). Does not disconnect it. */
|
|
89
|
+
forget(serverId) {
|
|
90
|
+
const e = this.entries.get(serverId);
|
|
91
|
+
if (!e)
|
|
92
|
+
return;
|
|
93
|
+
if (e.timer)
|
|
94
|
+
clearTimeout(e.timer);
|
|
95
|
+
this.entries.delete(serverId);
|
|
96
|
+
}
|
|
97
|
+
/** Is a reconnect scheduled or in progress for this server? */
|
|
98
|
+
isRecovering(serverId) {
|
|
99
|
+
const s = this.entries.get(serverId)?.state.state;
|
|
100
|
+
return s === 'scheduled' || s === 'connecting';
|
|
101
|
+
}
|
|
102
|
+
getState(serverId) {
|
|
103
|
+
const e = this.entries.get(serverId);
|
|
104
|
+
return e ? { ...e.state } : undefined;
|
|
105
|
+
}
|
|
106
|
+
stop() {
|
|
107
|
+
this.stopped = true;
|
|
108
|
+
for (const e of this.entries.values())
|
|
109
|
+
if (e.timer)
|
|
110
|
+
clearTimeout(e.timer);
|
|
111
|
+
this.entries.clear();
|
|
112
|
+
this.proxy.off('disconnected', this.onDisconnected);
|
|
113
|
+
this.proxy.off('tools-changed', this.onToolsChanged);
|
|
114
|
+
}
|
|
115
|
+
// ─── Internal ───────────────────────────────────────────────────────────────
|
|
116
|
+
current(entry, gen) {
|
|
117
|
+
return !this.stopped && this.entries.get(entry.config.id) === entry && entry.gen === gen;
|
|
118
|
+
}
|
|
119
|
+
async attempt(entry, gen, isReconnect) {
|
|
120
|
+
const { config } = entry;
|
|
121
|
+
entry.state.state = 'connecting';
|
|
122
|
+
entry.state.nextAttemptAt = undefined;
|
|
123
|
+
this.publish(entry);
|
|
124
|
+
try {
|
|
125
|
+
const tools = await this.proxy.connect(config);
|
|
126
|
+
if (!this.current(entry, gen))
|
|
127
|
+
return false; // superseded by reload/removal
|
|
128
|
+
entry.state = {
|
|
129
|
+
state: 'idle',
|
|
130
|
+
attempt: 0,
|
|
131
|
+
reconnects: entry.state.reconnects + (isReconnect ? 1 : 0),
|
|
132
|
+
lastDisconnectAt: entry.state.lastDisconnectAt,
|
|
133
|
+
};
|
|
134
|
+
this.registry.setTools(config.id, tools);
|
|
135
|
+
this.registry.updateHealth(config.id, 'online', undefined, undefined, {
|
|
136
|
+
connectedSince: new Date(),
|
|
137
|
+
reconnect: { ...entry.state },
|
|
138
|
+
});
|
|
139
|
+
logger.info(`✓ ${config.name} — ${tools.length} tools available${isReconnect ? ' (reconnected)' : ''}`);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
if (!this.current(entry, gen))
|
|
144
|
+
return false;
|
|
145
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
146
|
+
entry.state.lastError = msg;
|
|
147
|
+
if (!isReconnect)
|
|
148
|
+
this.registry.setTools(config.id, []);
|
|
149
|
+
logger.warn(`✗ ${config.name} — failed to connect: ${msg}`);
|
|
150
|
+
this.scheduleRetry(entry, gen);
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
handleDisconnect(serverId, err) {
|
|
155
|
+
const entry = this.entries.get(serverId);
|
|
156
|
+
if (!entry || this.stopped)
|
|
157
|
+
return;
|
|
158
|
+
entry.state.lastError = err.message;
|
|
159
|
+
entry.state.lastDisconnectAt = new Date();
|
|
160
|
+
entry.state.attempt = 0;
|
|
161
|
+
// Tools stay listed (marked unavailable via health) so clients see what will come back.
|
|
162
|
+
logger.warn(`Server "${serverId}" disconnected: ${err.message}`);
|
|
163
|
+
this.scheduleRetry(entry, entry.gen);
|
|
164
|
+
}
|
|
165
|
+
scheduleRetry(entry, gen) {
|
|
166
|
+
const { policy } = entry;
|
|
167
|
+
if (!policy.enabled) {
|
|
168
|
+
entry.state.state = 'disabled';
|
|
169
|
+
this.publish(entry, 'offline');
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (policy.maxAttempts > 0 && entry.state.attempt >= policy.maxAttempts) {
|
|
173
|
+
entry.state.state = 'gave-up';
|
|
174
|
+
logger.error(`Server "${entry.config.id}": giving up after ${entry.state.attempt} reconnect attempts`);
|
|
175
|
+
this.publish(entry, 'offline');
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
entry.state.attempt++;
|
|
179
|
+
const delay = computeBackoff(entry.state.attempt, policy, this.random);
|
|
180
|
+
entry.state.state = 'scheduled';
|
|
181
|
+
entry.state.nextAttemptAt = new Date(Date.now() + delay);
|
|
182
|
+
logger.info(`Reconnecting "${entry.config.id}" in ${delay}ms (attempt ${entry.state.attempt})`);
|
|
183
|
+
this.publish(entry, 'reconnecting');
|
|
184
|
+
if (entry.timer)
|
|
185
|
+
clearTimeout(entry.timer);
|
|
186
|
+
entry.timer = setTimeout(() => {
|
|
187
|
+
entry.timer = undefined;
|
|
188
|
+
if (this.current(entry, gen))
|
|
189
|
+
void this.attempt(entry, gen, true);
|
|
190
|
+
}, delay);
|
|
191
|
+
entry.timer.unref();
|
|
192
|
+
}
|
|
193
|
+
publish(entry, status) {
|
|
194
|
+
const id = entry.config.id;
|
|
195
|
+
if (!this.registry.getServer(id))
|
|
196
|
+
return;
|
|
197
|
+
const prev = this.registry.getHealth(id);
|
|
198
|
+
const next = status ?? prev?.status ?? 'unknown';
|
|
199
|
+
this.registry.updateHealth(id, next, undefined, entry.state.lastError, {
|
|
200
|
+
reconnect: { ...entry.state },
|
|
201
|
+
connectedSince: status ? undefined : prev?.connectedSince,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=supervisor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../../src/gateway/supervisor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcp-gateway public API
|
|
3
|
+
* Use this when embedding the gateway as a library
|
|
4
|
+
*/
|
|
5
|
+
export { Gateway } from './gateway/index.js';
|
|
6
|
+
export { computeReadiness } from './gateway/api.js';
|
|
7
|
+
export type { Readiness } from './gateway/api.js';
|
|
8
|
+
export { ServerRegistry } from './registry/index.js';
|
|
9
|
+
export { McpProxy, defaultChannelFactory, MCP_PROTOCOL_VERSION } from './proxy/index.js';
|
|
10
|
+
export type { ProxyOptions, SessionInfo } from './proxy/index.js';
|
|
11
|
+
export { ServerSupervisor, computeBackoff, DEFAULT_RECONNECT } from './gateway/supervisor.js';
|
|
12
|
+
export type { UpstreamChannel, ChannelFactory, ChannelOptions, JsonRpcMessage } from './transport/channel.js';
|
|
13
|
+
export { MetricsCollector } from './monitor/index.js';
|
|
14
|
+
export { loadConfig, generateDefaultConfig } from './config/loader.js';
|
|
15
|
+
export { logger } from './utils/logger.js';
|
|
16
|
+
export { isToolAllowed, filterTools } from './utils/tool-filter.js';
|
|
17
|
+
export type { GatewayConfig, McpServerConfig, ServerHealth, ServerStatus, ServerTransport, ToolInfo, RequestMetric, AggregatedMetrics, AuthConfig, RateLimitConfig, MonitorConfig, ReconnectConfig, ReconnectState, ToolFilterConfig, } from './utils/types.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACzF,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC9F,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC9G,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACpE,YAAY,EACV,aAAa,EACb,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,EACd,gBAAgB,GACjB,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcp-gateway public API
|
|
3
|
+
* Use this when embedding the gateway as a library
|
|
4
|
+
*/
|
|
5
|
+
export { Gateway } from './gateway/index.js';
|
|
6
|
+
export { computeReadiness } from './gateway/api.js';
|
|
7
|
+
export { ServerRegistry } from './registry/index.js';
|
|
8
|
+
export { McpProxy, defaultChannelFactory, MCP_PROTOCOL_VERSION } from './proxy/index.js';
|
|
9
|
+
export { ServerSupervisor, computeBackoff, DEFAULT_RECONNECT } from './gateway/supervisor.js';
|
|
10
|
+
export { MetricsCollector } from './monitor/index.js';
|
|
11
|
+
export { loadConfig, generateDefaultConfig } from './config/loader.js';
|
|
12
|
+
export { logger } from './utils/logger.js';
|
|
13
|
+
export { isToolAllowed, filterTools } from './utils/tool-filter.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAEzF,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE9F,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CORS Middleware
|
|
3
|
+
*
|
|
4
|
+
* Configurable Cross-Origin Resource Sharing headers.
|
|
5
|
+
* Supports wildcard, specific origins list, and regex patterns.
|
|
6
|
+
*
|
|
7
|
+
* @module middleware/cors
|
|
8
|
+
*/
|
|
9
|
+
import { Request, Response, NextFunction } from 'express';
|
|
10
|
+
export interface CORSOptions {
|
|
11
|
+
origins: string[];
|
|
12
|
+
methods?: string[];
|
|
13
|
+
allowedHeaders?: string[];
|
|
14
|
+
exposedHeaders?: string[];
|
|
15
|
+
credentials?: boolean;
|
|
16
|
+
maxAge?: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function corsMiddleware(options: CORSOptions): (req: Request, res: Response, next: NextFunction) => void;
|
|
19
|
+
//# sourceMappingURL=cors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE1D,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAUD,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,IA0BzC,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CA+B/D"}
|