staff-mcp 1.2.0 → 2.0.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 +29 -0
- package/README.md +178 -49
- package/README_zh.md +176 -47
- package/dist/src/data/HttpDataSession.d.ts +22 -0
- package/dist/src/data/HttpDataSession.js +925 -0
- package/dist/src/data/HttpDataSession.js.map +1 -0
- package/dist/src/data/node.d.ts +4 -0
- package/dist/src/data/node.js +93 -0
- package/dist/src/data/node.js.map +1 -0
- package/dist/src/data/types.d.ts +54 -0
- package/dist/src/data/types.js +2 -0
- package/dist/src/data/types.js.map +1 -0
- package/dist/src/data-stdio-docker.d.ts +10 -0
- package/dist/src/data-stdio-docker.js +140 -0
- package/dist/src/data-stdio-docker.js.map +1 -0
- package/dist/src/docker-proxy.d.ts +6 -1
- package/dist/src/docker-proxy.js +324 -147
- package/dist/src/docker-proxy.js.map +1 -1
- package/dist/src/extensions/apps.d.ts +12 -0
- package/dist/src/extensions/apps.js +85 -0
- package/dist/src/extensions/apps.js.map +1 -0
- package/dist/src/extensions/config.d.ts +27 -0
- package/dist/src/extensions/config.js +91 -0
- package/dist/src/extensions/config.js.map +1 -0
- package/dist/src/extensions/protocol.d.ts +35 -0
- package/dist/src/extensions/protocol.js +47 -0
- package/dist/src/extensions/protocol.js.map +1 -0
- package/dist/src/extensions/runtime.d.ts +16 -0
- package/dist/src/extensions/runtime.js +266 -0
- package/dist/src/extensions/runtime.js.map +1 -0
- package/dist/src/file-manager/extension.d.ts +21 -0
- package/dist/src/file-manager/extension.js +514 -0
- package/dist/src/file-manager/extension.js.map +1 -0
- package/dist/src/file-manager/file-core.d.ts +128 -0
- package/dist/src/file-manager/file-core.js +750 -0
- package/dist/src/file-manager/file-core.js.map +1 -0
- package/dist/src/file-manager/transfers.d.ts +423 -0
- package/dist/src/file-manager/transfers.js +540 -0
- package/dist/src/file-manager/transfers.js.map +1 -0
- package/dist/src/file-manager/ui/index.html +81 -0
- package/dist/src/index.js +289 -128
- package/dist/src/index.js.map +1 -1
- package/dist/src/lsp/manager.d.ts +2 -0
- package/dist/src/lsp/manager.js +22 -10
- package/dist/src/lsp/manager.js.map +1 -1
- package/dist/src/reverse/SseTransport.d.ts +34 -0
- package/dist/src/reverse/SseTransport.js +215 -0
- package/dist/src/reverse/SseTransport.js.map +1 -0
- package/dist/src/reverse/http.d.ts +7 -0
- package/dist/src/reverse/http.js +85 -0
- package/dist/src/reverse/http.js.map +1 -0
- package/dist/src/server.d.ts +4 -2
- package/dist/src/server.js +80 -18
- package/dist/src/server.js.map +1 -1
- package/dist/src/terminal/extension.d.ts +4 -0
- package/dist/src/terminal/extension.js +108 -0
- package/dist/src/terminal/extension.js.map +1 -0
- package/dist/src/terminal/pty.d.ts +14 -0
- package/dist/src/terminal/pty.js +121 -0
- package/dist/src/terminal/pty.js.map +1 -0
- package/dist/src/terminal/session.d.ts +136 -0
- package/dist/src/terminal/session.js +422 -0
- package/dist/src/terminal/session.js.map +1 -0
- package/dist/src/terminal/ui/index.html +183 -0
- package/dist/src/tools/file-tools.d.ts +2 -1
- package/dist/src/tools/file-tools.js +19 -7
- package/dist/src/tools/file-tools.js.map +1 -1
- package/dist/src/tools/mcp-client-tools.js +244 -104
- package/dist/src/tools/mcp-client-tools.js.map +1 -1
- package/dist/src/tools/shell-tools.js +1 -1
- package/dist/src/tools/shell-tools.js.map +1 -1
- package/dist/src/tools/skills.js +26 -1
- package/dist/src/tools/skills.js.map +1 -1
- package/dist/src/tools/system-tools.d.ts +9 -3
- package/dist/src/tools/system-tools.js +31 -48
- package/dist/src/tools/system-tools.js.map +1 -1
- package/dist/src/transports/http.d.ts +16 -2
- package/dist/src/transports/http.js +261 -59
- package/dist/src/transports/http.js.map +1 -1
- package/dist/src/transports/reverse.d.ts +23 -19
- package/dist/src/transports/reverse.js +130 -74
- package/dist/src/transports/reverse.js.map +1 -1
- package/dist/src/transports/stdio.d.ts +6 -2
- package/dist/src/transports/stdio.js +131 -19
- package/dist/src/transports/stdio.js.map +1 -1
- package/dist/src/utils/proxy.d.ts +3 -3
- package/dist/src/utils/proxy.js +84 -62
- package/dist/src/utils/proxy.js.map +1 -1
- package/dist/src/utils/server-activity.d.ts +6 -0
- package/dist/src/utils/server-activity.js +46 -0
- package/dist/src/utils/server-activity.js.map +1 -0
- package/dist/src/utils/server-lifecycle.d.ts +5 -0
- package/dist/src/utils/server-lifecycle.js +51 -0
- package/dist/src/utils/server-lifecycle.js.map +1 -0
- package/docs/file-manager.md +179 -0
- package/docs/terminal.md +66 -0
- package/package.json +40 -19
- package/dist/src/transports/fte-lifecycle.d.ts +0 -13
- package/dist/src/transports/fte-lifecycle.js +0 -76
- package/dist/src/transports/fte-lifecycle.js.map +0 -1
- package/dist/tests/docker-proxy.test.d.ts +0 -1
- package/dist/tests/docker-proxy.test.js +0 -395
- package/dist/tests/docker-proxy.test.js.map +0 -1
- package/dist/tests/file-write-queue.test.d.ts +0 -1
- package/dist/tests/file-write-queue.test.js +0 -105
- package/dist/tests/file-write-queue.test.js.map +0 -1
- package/dist/tests/fte-lifecycle.test.d.ts +0 -1
- package/dist/tests/fte-lifecycle.test.js +0 -118
- package/dist/tests/fte-lifecycle.test.js.map +0 -1
- package/dist/tests/lsp-client.test.d.ts +0 -1
- package/dist/tests/lsp-client.test.js +0 -52
- package/dist/tests/lsp-client.test.js.map +0 -1
- package/dist/tests/package-info.test.d.ts +0 -1
- package/dist/tests/package-info.test.js +0 -54
- package/dist/tests/package-info.test.js.map +0 -1
- package/dist/tests/proxy-no-proxy.test.d.ts +0 -1
- package/dist/tests/proxy-no-proxy.test.js +0 -156
- package/dist/tests/proxy-no-proxy.test.js.map +0 -1
- package/dist/tests/proxy.test.d.ts +0 -1
- package/dist/tests/proxy.test.js +0 -89
- package/dist/tests/proxy.test.js.map +0 -1
- package/dist/tests/reverse-reconnect.test.d.ts +0 -1
- package/dist/tests/reverse-reconnect.test.js +0 -89
- package/dist/tests/reverse-reconnect.test.js.map +0 -1
- package/dist/tests/security.test.d.ts +0 -1
- package/dist/tests/security.test.js +0 -21
- package/dist/tests/security.test.js.map +0 -1
- package/dist/tests/shell-tools.test.d.ts +0 -1
- package/dist/tests/shell-tools.test.js +0 -113
- package/dist/tests/shell-tools.test.js.map +0 -1
- package/dist/tests/test_files/test.d.ts +0 -1
- package/dist/tests/test_files/test.js +0 -4
- package/dist/tests/test_files/test.js.map +0 -1
|
@@ -1,80 +1,282 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
import { HttpDataSession } from '../data/HttpDataSession.js';
|
|
2
|
+
import { handleNodeRequest } from '../data/node.js';
|
|
3
|
+
import { configureExtensionData } from '../extensions/runtime.js';
|
|
4
|
+
import { hasServerActivity } from '../utils/server-activity.js';
|
|
5
|
+
import express from 'express';
|
|
6
|
+
import cors from 'cors';
|
|
7
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
8
|
+
import { isInitializeRequest, isJSONRPCRequest, } from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
+
import { randomUUID, timingSafeEqual } from 'node:crypto';
|
|
10
|
+
export function getHttpAuthToken(token) {
|
|
11
|
+
if (token === undefined)
|
|
12
|
+
return undefined;
|
|
13
|
+
if (!token || /\s/.test(token)) {
|
|
14
|
+
throw new Error('--http-token must be non-empty and contain no whitespace when provided.');
|
|
15
|
+
}
|
|
16
|
+
return token;
|
|
17
|
+
}
|
|
18
|
+
export const HTTP_MAX_SESSIONS = 64;
|
|
19
|
+
export const HTTP_SESSION_IDLE_MS = 30 * 60 * 1000;
|
|
20
|
+
export function resolveHttpSessionPolicy(policy = {}) {
|
|
21
|
+
const maxSessions = policy.maxSessions ?? HTTP_MAX_SESSIONS;
|
|
22
|
+
const idleTimeoutMs = policy.idleTimeoutMs ?? HTTP_SESSION_IDLE_MS;
|
|
23
|
+
if (!Number.isSafeInteger(maxSessions) || maxSessions <= 0)
|
|
24
|
+
throw new Error('HTTP max sessions must be a positive safe integer.');
|
|
25
|
+
if (!Number.isInteger(idleTimeoutMs) ||
|
|
26
|
+
idleTimeoutMs <= 0 ||
|
|
27
|
+
idleTimeoutMs > 2_147_483_647)
|
|
28
|
+
throw new Error('HTTP session idle timeout must be 1..2147483647 ms.');
|
|
29
|
+
return { maxSessions, idleTimeoutMs };
|
|
30
|
+
}
|
|
31
|
+
export async function startHttpServer(serverFactory, port, host = '0.0.0.0', token, policy = {}) {
|
|
32
|
+
const { maxSessions, idleTimeoutMs } = resolveHttpSessionPolicy(policy);
|
|
33
|
+
const authToken = getHttpAuthToken(token);
|
|
6
34
|
const app = express();
|
|
7
|
-
|
|
35
|
+
let stopping = false;
|
|
36
|
+
const sessions = new Map();
|
|
37
|
+
const dataSessions = new Map();
|
|
38
|
+
const closeSession = (id, session) => {
|
|
39
|
+
session.closing ??= Promise.resolve()
|
|
40
|
+
.then(() => session.server.close())
|
|
41
|
+
.then(() => {
|
|
42
|
+
if (sessions.get(id) === session)
|
|
43
|
+
sessions.delete(id);
|
|
44
|
+
});
|
|
45
|
+
return session.closing;
|
|
46
|
+
};
|
|
47
|
+
const observeClose = (id, session) => {
|
|
48
|
+
void closeSession(id, session).catch(() => console.error('[staff-mcp] HTTP session cleanup failed.'));
|
|
49
|
+
};
|
|
50
|
+
const sweepIdle = () => {
|
|
51
|
+
const now = performance.now();
|
|
52
|
+
for (const [id, session] of sessions) {
|
|
53
|
+
if (session.closing)
|
|
54
|
+
continue;
|
|
55
|
+
if (session.initializing || hasServerActivity(session.server)) {
|
|
56
|
+
session.idleSince = undefined;
|
|
57
|
+
}
|
|
58
|
+
else if (session.idleSince === undefined) {
|
|
59
|
+
session.idleSince = now;
|
|
60
|
+
}
|
|
61
|
+
else if (now - session.idleSince >= idleTimeoutMs) {
|
|
62
|
+
// Fence synchronously; cleanup keeps its slot until it succeeds.
|
|
63
|
+
observeClose(id, session);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const reject = (res, status, message) => {
|
|
68
|
+
if (!res.headersSent && !res.destroyed) {
|
|
69
|
+
res.status(status).json({
|
|
70
|
+
jsonrpc: '2.0',
|
|
71
|
+
id: null,
|
|
72
|
+
error: {
|
|
73
|
+
code: status === 404
|
|
74
|
+
? -32001
|
|
75
|
+
: status === 429
|
|
76
|
+
? -32000
|
|
77
|
+
: -32600,
|
|
78
|
+
message,
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
// CORS preflight is public and never reaches MCP session handling.
|
|
8
84
|
app.use(cors());
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
85
|
+
app.use((_req, res, next) => {
|
|
86
|
+
if (stopping)
|
|
87
|
+
return reject(res, 503, 'Server is stopping');
|
|
88
|
+
next();
|
|
89
|
+
});
|
|
90
|
+
// Session-owned public data endpoints must bypass the MCP JSON parser.
|
|
91
|
+
app.use((req, res, next) => {
|
|
92
|
+
const match = /^\/mcp\/data\/([A-Za-z0-9_-]{16,256})(?:\/|$)/.exec(req.url);
|
|
93
|
+
if (!match)
|
|
94
|
+
return next();
|
|
95
|
+
const session = dataSessions.get(match[1]);
|
|
96
|
+
if (!session) {
|
|
97
|
+
res.status(404).end();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
void handleNodeRequest(session, req, res).then((handled) => {
|
|
101
|
+
if (!handled && !res.headersSent)
|
|
102
|
+
res.status(404).end();
|
|
103
|
+
}, () => {
|
|
104
|
+
console.error('[staff-mcp] HTTP data request failed.');
|
|
105
|
+
if (!res.headersSent)
|
|
106
|
+
res.status(500).end();
|
|
107
|
+
else
|
|
108
|
+
res.destroy();
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
// When configured, authenticate before parsing bodies or accessing sessions.
|
|
112
|
+
if (authToken !== undefined) {
|
|
113
|
+
const expectedToken = Buffer.from(authToken);
|
|
114
|
+
app.use(['/mcp', '/sse', '/messages'], (req, res, next) => {
|
|
115
|
+
const match = /^Bearer +(\S+)$/i.exec(req.headers.authorization ?? '');
|
|
116
|
+
const providedToken = Buffer.from(match?.[1] ?? '');
|
|
117
|
+
if (providedToken.length !== expectedToken.length ||
|
|
118
|
+
!timingSafeEqual(providedToken, expectedToken)) {
|
|
119
|
+
res.setHeader('WWW-Authenticate', 'Bearer realm="staff-mcp"');
|
|
120
|
+
res.status(401).json({ error: 'Unauthorized' });
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
next();
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// Preserve ordinary tool payloads; binary data bypasses this parser.
|
|
12
127
|
app.use(express.json({ limit: '50mb' }));
|
|
13
|
-
// === Session Pool ===
|
|
14
|
-
const sessions = new Map();
|
|
15
128
|
const mcpHandler = async (req, res) => {
|
|
16
|
-
const sessionId = req.headers[
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
129
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
130
|
+
if (sessionId !== undefined) {
|
|
131
|
+
if (typeof sessionId !== 'string' || !sessionId) {
|
|
132
|
+
return reject(res, 400, 'Invalid MCP session ID');
|
|
133
|
+
}
|
|
134
|
+
const session = sessions.get(sessionId);
|
|
135
|
+
if (!session || session.closing) {
|
|
136
|
+
return reject(res, 404, 'Session not found');
|
|
137
|
+
}
|
|
20
138
|
try {
|
|
21
|
-
await
|
|
139
|
+
await session.transport.handleRequest(req, res, req.body);
|
|
22
140
|
}
|
|
23
|
-
catch
|
|
24
|
-
console.error(
|
|
25
|
-
|
|
26
|
-
res.status(500).json({
|
|
27
|
-
error: "Internal Server Error",
|
|
28
|
-
message: error instanceof Error ? error.message : String(error)
|
|
29
|
-
});
|
|
30
|
-
}
|
|
141
|
+
catch {
|
|
142
|
+
console.error('[staff-mcp] HTTP control request failed.');
|
|
143
|
+
reject(res, 500, 'Internal Server Error');
|
|
31
144
|
}
|
|
32
145
|
return;
|
|
33
146
|
}
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (sessionId) {
|
|
40
|
-
delete req.headers["mcp-session-id"];
|
|
41
|
-
delete req.headers["last-event-id"];
|
|
147
|
+
// A stale ID, GET, DELETE or malformed request cannot allocate resources.
|
|
148
|
+
if (req.method !== 'POST' ||
|
|
149
|
+
!isJSONRPCRequest(req.body) ||
|
|
150
|
+
!isInitializeRequest(req.body)) {
|
|
151
|
+
return reject(res, 400, 'A new session requires initialization');
|
|
42
152
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
153
|
+
// JSON body parsing can finish after shutdown has started.
|
|
154
|
+
if (stopping)
|
|
155
|
+
return reject(res, 503, 'Server is stopping');
|
|
156
|
+
sweepIdle();
|
|
157
|
+
if (sessions.size >= maxSessions)
|
|
158
|
+
return reject(res, 429, 'HTTP session capacity reached');
|
|
159
|
+
const id = randomUUID();
|
|
160
|
+
let session;
|
|
161
|
+
const disconnected = () => {
|
|
162
|
+
if (!res.writableFinished && session)
|
|
163
|
+
observeClose(id, session);
|
|
51
164
|
};
|
|
52
|
-
await server.connect(t);
|
|
53
|
-
sessions.set(newSessionId, t);
|
|
54
165
|
try {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
166
|
+
const server = serverFactory();
|
|
167
|
+
const transport = new StreamableHTTPServerTransport({
|
|
168
|
+
sessionIdGenerator: () => id,
|
|
169
|
+
enableJsonResponse: true,
|
|
170
|
+
});
|
|
171
|
+
session = { server, transport, initializing: true };
|
|
172
|
+
const owned = session;
|
|
173
|
+
// The SDK calls this only after parsing/validating the control message.
|
|
174
|
+
// Neither an idle GET SSE stream nor invalid HTTP/data traffic renews it.
|
|
175
|
+
transport.onmessage = () => {
|
|
176
|
+
owned.idleSince = undefined;
|
|
177
|
+
};
|
|
178
|
+
// Include starting sessions in shutdown ownership before the first await.
|
|
179
|
+
sessions.set(id, session);
|
|
180
|
+
transport.onclose = () => observeClose(id, owned);
|
|
181
|
+
res.once('close', disconnected);
|
|
182
|
+
configureExtensionData(server, (binding, accept, signal, origin, supportsPurpose) => {
|
|
183
|
+
signal.throwIfAborted();
|
|
184
|
+
if (stopping || owned.closing)
|
|
185
|
+
throw new Error('HTTP session is closing.');
|
|
186
|
+
if (dataSessions.has(binding))
|
|
187
|
+
throw new Error('Data binding already exists.');
|
|
188
|
+
const authority = req.get('host');
|
|
189
|
+
if (!authority)
|
|
190
|
+
throw new Error('MCP HTTP Host header is required.');
|
|
191
|
+
const endpoint = new URL(`/mcp/data/${binding}`, origin ?? `${req.protocol}://${authority}`).href;
|
|
192
|
+
const data = new HttpDataSession({
|
|
193
|
+
role: 'remote',
|
|
194
|
+
binding,
|
|
195
|
+
endpoint,
|
|
196
|
+
accept,
|
|
197
|
+
supportsPurpose,
|
|
198
|
+
fetch: async () => {
|
|
199
|
+
throw new Error('Outbound data is unavailable in HTTP listener mode');
|
|
200
|
+
},
|
|
201
|
+
validateEndpoint: () => {
|
|
202
|
+
throw new Error('Outbound data endpoint is unavailable in HTTP listener mode');
|
|
203
|
+
},
|
|
63
204
|
});
|
|
205
|
+
dataSessions.set(binding, data);
|
|
206
|
+
return {
|
|
207
|
+
session: data,
|
|
208
|
+
endpoint,
|
|
209
|
+
close: () => {
|
|
210
|
+
if (dataSessions.get(binding) === data)
|
|
211
|
+
dataSessions.delete(binding);
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
});
|
|
215
|
+
await server.connect(transport);
|
|
216
|
+
if (stopping || session.closing) {
|
|
217
|
+
await closeSession(id, session);
|
|
218
|
+
return reject(res, 503, 'Server is stopping');
|
|
219
|
+
}
|
|
220
|
+
await transport.handleRequest(req, res, req.body);
|
|
221
|
+
if (!transport.sessionId ||
|
|
222
|
+
res.statusCode >= 400 ||
|
|
223
|
+
(res.destroyed && !res.writableFinished)) {
|
|
224
|
+
await closeSession(id, session);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
if (session) {
|
|
229
|
+
await closeSession(id, session).catch(() => console.error('[staff-mcp] HTTP session cleanup failed.'));
|
|
64
230
|
}
|
|
231
|
+
console.error('[staff-mcp] HTTP initialization failed.');
|
|
232
|
+
reject(res, 500, 'Internal Server Error');
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
if (session) {
|
|
236
|
+
session.initializing = false;
|
|
237
|
+
session.idleSince = undefined;
|
|
238
|
+
}
|
|
239
|
+
res.removeListener('close', disconnected);
|
|
65
240
|
}
|
|
66
241
|
};
|
|
67
|
-
|
|
68
|
-
app.
|
|
69
|
-
|
|
70
|
-
app.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
console.error(`[MCP HTTP] JSON Response enabled: true`);
|
|
242
|
+
app.all('/mcp', mcpHandler);
|
|
243
|
+
app.get('/sse', mcpHandler);
|
|
244
|
+
app.post('/messages', mcpHandler);
|
|
245
|
+
const listener = app.listen(port, host);
|
|
246
|
+
await new Promise((resolve, reject) => {
|
|
247
|
+
listener.once('error', reject);
|
|
248
|
+
listener.once('listening', () => {
|
|
249
|
+
listener.removeListener('error', reject);
|
|
76
250
|
resolve();
|
|
77
251
|
});
|
|
78
252
|
});
|
|
253
|
+
const address = listener.address();
|
|
254
|
+
console.error(`[MCP HTTP] Server listening on http://${host}:${address.port}/mcp`);
|
|
255
|
+
// One bounded sweep per listener; no per-session timers or resource lease changes.
|
|
256
|
+
const idleTimer = setInterval(sweepIdle, Math.min(idleTimeoutMs, 60_000));
|
|
257
|
+
idleTimer.unref();
|
|
258
|
+
let stopped;
|
|
259
|
+
return {
|
|
260
|
+
port: address.port,
|
|
261
|
+
stop: () => {
|
|
262
|
+
if (stopped)
|
|
263
|
+
return stopped;
|
|
264
|
+
stopping = true;
|
|
265
|
+
clearInterval(idleTimer);
|
|
266
|
+
// Stop accepting first, but keep the listener alive until owned cleanup settles.
|
|
267
|
+
const listenerClosed = new Promise((resolve, reject) => {
|
|
268
|
+
listener.close((error) => (error ? reject(error) : resolve()));
|
|
269
|
+
});
|
|
270
|
+
stopped = (async () => {
|
|
271
|
+
const results = await Promise.allSettled([...sessions].map(([id, session]) => closeSession(id, session)));
|
|
272
|
+
listener.closeAllConnections();
|
|
273
|
+
await listenerClosed;
|
|
274
|
+
const failed = results.filter((result) => result.status === 'rejected');
|
|
275
|
+
if (failed.length)
|
|
276
|
+
throw new AggregateError(failed.map((result) => result.reason), 'HTTP session cleanup failed');
|
|
277
|
+
})();
|
|
278
|
+
return stopped;
|
|
279
|
+
},
|
|
280
|
+
};
|
|
79
281
|
}
|
|
80
282
|
//# sourceMappingURL=http.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/transports/http.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/transports/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EACH,mBAAmB,EACnB,gBAAgB,GACnB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG1D,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC3C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACX,yEAAyE,CAC5E,CAAC;IACN,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AACpC,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAOnD,MAAM,UAAU,wBAAwB,CAAC,SAA4B,EAAE;IACnE,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,iBAAiB,CAAC;IAC5D,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,IAAI,oBAAoB,CAAC;IACnE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,IAAI,WAAW,IAAI,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IAC1E,IACI,CAAC,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC;QAChC,aAAa,IAAI,CAAC;QAClB,aAAa,GAAG,aAAa;QAE7B,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IAC3E,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC;AAC1C,CAAC;AAWD,MAAM,CAAC,KAAK,UAAU,eAAe,CACjC,aAA8B,EAC9B,IAAY,EACZ,OAAe,SAAS,EACxB,KAAc,EACd,SAA4B,EAAE;IAE9B,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;IAChD,MAAM,YAAY,GAAG,IAAI,GAAG,EAA2B,CAAC;IAExD,MAAM,YAAY,GAAG,CAAC,EAAU,EAAE,OAAoB,EAAE,EAAE;QACtD,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE;aAChC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;aAClC,IAAI,CAAC,GAAG,EAAE;YACP,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,OAAO;gBAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QACP,OAAO,OAAO,CAAC,OAAO,CAAC;IAC3B,CAAC,CAAC;IACF,MAAM,YAAY,GAAG,CAAC,EAAU,EAAE,OAAoB,EAAE,EAAE;QACtD,KAAK,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CACtC,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAC5D,CAAC;IACN,CAAC,CAAC;IACF,MAAM,SAAS,GAAG,GAAG,EAAE;QACnB,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC9B,KAAK,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,QAAQ,EAAE,CAAC;YACnC,IAAI,OAAO,CAAC,OAAO;gBAAE,SAAS;YAC9B,IAAI,OAAO,CAAC,YAAY,IAAI,iBAAiB,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5D,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;YAClC,CAAC;iBAAM,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;gBACzC,OAAO,CAAC,SAAS,GAAG,GAAG,CAAC;YAC5B,CAAC;iBAAM,IAAI,GAAG,GAAG,OAAO,CAAC,SAAS,IAAI,aAAa,EAAE,CAAC;gBAClD,iEAAiE;gBACjE,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAC9B,CAAC;QACL,CAAC;IACL,CAAC,CAAC;IACF,MAAM,MAAM,GAAG,CAAC,GAAqB,EAAE,MAAc,EAAE,OAAe,EAAE,EAAE;QACtE,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACrC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;gBACpB,OAAO,EAAE,KAAK;gBACd,EAAE,EAAE,IAAI;gBACR,KAAK,EAAE;oBACH,IAAI,EACA,MAAM,KAAK,GAAG;wBACV,CAAC,CAAC,CAAC,KAAK;wBACR,CAAC,CAAC,MAAM,KAAK,GAAG;4BACd,CAAC,CAAC,CAAC,KAAK;4BACR,CAAC,CAAC,CAAC,KAAK;oBAClB,OAAO;iBACV;aACJ,CAAC,CAAC;QACP,CAAC;IACL,CAAC,CAAC;IAEF,mEAAmE;IACnE,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAChB,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACxB,IAAI,QAAQ;YAAE,OAAO,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,oBAAoB,CAAC,CAAC;QAC5D,IAAI,EAAE,CAAC;IACX,CAAC,CAAC,CAAC;IAEH,uEAAuE;IACvE,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACvB,MAAM,KAAK,GAAG,+CAA+C,CAAC,IAAI,CAC9D,GAAG,CAAC,GAAG,CACV,CAAC;QACF,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;YACX,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YACtB,OAAO;QACX,CAAC;QACD,KAAK,iBAAiB,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,IAAI,CAC1C,CAAC,OAAO,EAAE,EAAE;YACR,IAAI,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW;gBAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC5D,CAAC,EACD,GAAG,EAAE;YACD,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;YACvD,IAAI,CAAC,GAAG,CAAC,WAAW;gBAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;;gBACvC,GAAG,CAAC,OAAO,EAAE,CAAC;QACvB,CAAC,CACJ,CAAC;IACN,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC7C,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;YACtD,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CACjC,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAClC,CAAC;YACF,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACpD,IACI,aAAa,CAAC,MAAM,KAAK,aAAa,CAAC,MAAM;gBAC7C,CAAC,eAAe,CAAC,aAAa,EAAE,aAAa,CAAC,EAChD,CAAC;gBACC,GAAG,CAAC,SAAS,CAAC,kBAAkB,EAAE,0BAA0B,CAAC,CAAC;gBAC9D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;gBAChD,OAAO;YACX,CAAC;YACD,IAAI,EAAE,CAAC;QACX,CAAC,CAAC,CAAC;IACP,CAAC;IAED,qEAAqE;IACrE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAEzC,MAAM,UAAU,GAAG,KAAK,EAAE,GAAoB,EAAE,GAAqB,EAAE,EAAE;QACrE,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAChD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC1B,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC9C,OAAO,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,wBAAwB,CAAC,CAAC;YACtD,CAAC;YACD,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBAC9B,OAAO,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,mBAAmB,CAAC,CAAC;YACjD,CAAC;YACD,IAAI,CAAC;gBACD,MAAM,OAAO,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;YAC9D,CAAC;YAAC,MAAM,CAAC;gBACL,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;gBAC1D,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,uBAAuB,CAAC,CAAC;YAC9C,CAAC;YACD,OAAO;QACX,CAAC;QAED,0EAA0E;QAC1E,IACI,GAAG,CAAC,MAAM,KAAK,MAAM;YACrB,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;YAC3B,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,EAChC,CAAC;YACC,OAAO,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,uCAAuC,CAAC,CAAC;QACrE,CAAC;QACD,2DAA2D;QAC3D,IAAI,QAAQ;YAAE,OAAO,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,oBAAoB,CAAC,CAAC;QAC5D,SAAS,EAAE,CAAC;QACZ,IAAI,QAAQ,CAAC,IAAI,IAAI,WAAW;YAC5B,OAAO,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,+BAA+B,CAAC,CAAC;QAE7D,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;QACxB,IAAI,OAAgC,CAAC;QACrC,MAAM,YAAY,GAAG,GAAG,EAAE;YACtB,IAAI,CAAC,GAAG,CAAC,gBAAgB,IAAI,OAAO;gBAAE,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACpE,CAAC,CAAC;QACF,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,IAAI,6BAA6B,CAAC;gBAChD,kBAAkB,EAAE,GAAG,EAAE,CAAC,EAAE;gBAC5B,kBAAkB,EAAE,IAAI;aAC3B,CAAC,CAAC;YACH,OAAO,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;YACpD,MAAM,KAAK,GAAG,OAAO,CAAC;YACtB,wEAAwE;YACxE,0EAA0E;YAC1E,SAAS,CAAC,SAAS,GAAG,GAAG,EAAE;gBACvB,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;YAChC,CAAC,CAAC;YACF,0EAA0E;YAC1E,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAC1B,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAClD,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YAEhC,sBAAsB,CAClB,MAAM,EACN,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE;gBACjD,MAAM,CAAC,cAAc,EAAE,CAAC;gBACxB,IAAI,QAAQ,IAAI,KAAK,CAAC,OAAO;oBACzB,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;gBAChD,IAAI,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC;oBACzB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;gBACpD,MAAM,SAAS,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAClC,IAAI,CAAC,SAAS;oBACV,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;gBACzD,MAAM,QAAQ,GAAG,IAAI,GAAG,CACpB,aAAa,OAAO,EAAE,EACtB,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,MAAM,SAAS,EAAE,CAC7C,CAAC,IAAI,CAAC;gBACP,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC;oBAC7B,IAAI,EAAE,QAAQ;oBACd,OAAO;oBACP,QAAQ;oBACR,MAAM;oBACN,eAAe;oBACf,KAAK,EAAE,KAAK,IAAI,EAAE;wBACd,MAAM,IAAI,KAAK,CACX,oDAAoD,CACvD,CAAC;oBACN,CAAC;oBACD,gBAAgB,EAAE,GAAG,EAAE;wBACnB,MAAM,IAAI,KAAK,CACX,6DAA6D,CAChE,CAAC;oBACN,CAAC;iBACJ,CAAC,CAAC;gBACH,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gBAChC,OAAO;oBACH,OAAO,EAAE,IAAI;oBACb,QAAQ;oBACR,KAAK,EAAE,GAAG,EAAE;wBACR,IAAI,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI;4BAClC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;oBACrC,CAAC;iBACJ,CAAC;YACN,CAAC,CACJ,CAAC;YACF,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAChC,IAAI,QAAQ,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBAC9B,MAAM,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;gBAChC,OAAO,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,oBAAoB,CAAC,CAAC;YAClD,CAAC;YACD,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;YAClD,IACI,CAAC,SAAS,CAAC,SAAS;gBACpB,GAAG,CAAC,UAAU,IAAI,GAAG;gBACrB,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAC1C,CAAC;gBACC,MAAM,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YACpC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACL,IAAI,OAAO,EAAE,CAAC;gBACV,MAAM,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CACvC,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAC5D,CAAC;YACN,CAAC;YACD,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;YACzD,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,uBAAuB,CAAC,CAAC;QAC9C,CAAC;gBAAS,CAAC;YACP,IAAI,OAAO,EAAE,CAAC;gBACV,OAAO,CAAC,YAAY,GAAG,KAAK,CAAC;gBAC7B,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;YAClC,CAAC;YACD,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QAC9C,CAAC;IACL,CAAC,CAAC;IAEF,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC5B,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC5B,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IAElC,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACxC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC/B,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;YAC5B,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACzC,OAAO,EAAE,CAAC;QACd,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAiB,CAAC;IAClD,OAAO,CAAC,KAAK,CACT,yCAAyC,IAAI,IAAI,OAAO,CAAC,IAAI,MAAM,CACtE,CAAC;IACF,mFAAmF;IACnF,MAAM,SAAS,GAAG,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1E,SAAS,CAAC,KAAK,EAAE,CAAC;IAClB,IAAI,OAAkC,CAAC;IACvC,OAAO;QACH,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,GAAG,EAAE;YACP,IAAI,OAAO;gBAAE,OAAO,OAAO,CAAC;YAC5B,QAAQ,GAAG,IAAI,CAAC;YAChB,aAAa,CAAC,SAAS,CAAC,CAAC;YACzB,iFAAiF;YACjF,MAAM,cAAc,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACzD,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACnE,CAAC,CAAC,CAAC;YACH,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;gBAClB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CACpC,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,CAChC,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAC5B,CACJ,CAAC;gBACF,QAAQ,CAAC,mBAAmB,EAAE,CAAC;gBAC/B,MAAM,cAAc,CAAC;gBACrB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CACzB,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,UAAU,CAC3C,CAAC;gBACF,IAAI,MAAM,CAAC,MAAM;oBACb,MAAM,IAAI,cAAc,CACpB,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EACrC,6BAA6B,CAChC,CAAC;YACV,CAAC,CAAC,EAAE,CAAC;YACL,OAAO,OAAO,CAAC;QACnB,CAAC;KACJ,CAAC;AACN,CAAC"}
|
|
@@ -1,23 +1,27 @@
|
|
|
1
|
-
import { McpServer } from
|
|
2
|
-
|
|
3
|
-
import { ReverseMCPClient } from "mcp-reverse/client";
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
export { reverseProxyUrl, validateReverseUrl } from '../reverse/http.js';
|
|
4
3
|
export interface ReverseServerOptions {
|
|
5
|
-
|
|
4
|
+
proxy?: string;
|
|
6
5
|
connectTimeout?: number;
|
|
7
|
-
/** Deadline for MCP initialization after the SSE transport opens. */
|
|
8
6
|
initializationTimeout?: number;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
reconnect?:
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
heartbeat?: {
|
|
8
|
+
readTimeout?: number;
|
|
9
|
+
};
|
|
10
|
+
reconnect?: {
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
initialDelay?: number;
|
|
13
|
+
maxDelay?: number;
|
|
14
|
+
stableConnectionMs?: number;
|
|
15
|
+
};
|
|
16
|
+
logger?: {
|
|
17
|
+
info(message: string): void;
|
|
18
|
+
warn(message: string): void;
|
|
19
|
+
error(message: string): void;
|
|
20
|
+
};
|
|
15
21
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*/
|
|
23
|
-
export declare function startReverseServer(server: McpServer, url: string, token: string, name: string, options?: ReverseServerOptions): Promise<ReverseMCPClient>;
|
|
22
|
+
export interface ReverseController {
|
|
23
|
+
stop(): Promise<void>;
|
|
24
|
+
readonly closed: Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/** New HTTP pool, SDK transport and data resources per attempt; never replay requests or input. */
|
|
27
|
+
export declare function startReverseServer(serverFactory: () => McpServer, value: string, token: string, name: string, options?: ReverseServerOptions): Promise<ReverseController>;
|
|
@@ -1,78 +1,134 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
debug: debugEnabled
|
|
21
|
-
? (message, ...args) => console.error(`[staff-mcp][reverse][debug] ${message}`, ...args)
|
|
22
|
-
: () => { },
|
|
23
|
-
info: (message, ...args) => console.error(`[staff-mcp][reverse][info] ${message}`, ...args),
|
|
24
|
-
warn: (message, ...args) => console.error(`[staff-mcp][reverse][warn] ${message}`, ...args),
|
|
25
|
-
error: (message, ...args) => console.error(`[staff-mcp][reverse][error] ${message}`, ...args),
|
|
1
|
+
import { performance } from 'node:perf_hooks';
|
|
2
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
3
|
+
import { configureExtensionData } from '../extensions/runtime.js';
|
|
4
|
+
import { HttpDataSession } from '../data/HttpDataSession.js';
|
|
5
|
+
import { ReverseSseTransport } from '../reverse/SseTransport.js';
|
|
6
|
+
import { createReverseHttp, reverseProxyUrl, validateReverseUrl, } from '../reverse/http.js';
|
|
7
|
+
export { reverseProxyUrl, validateReverseUrl } from '../reverse/http.js';
|
|
8
|
+
/** New HTTP pool, SDK transport and data resources per attempt; never replay requests or input. */
|
|
9
|
+
export async function startReverseServer(serverFactory, value, token, name, options = {}) {
|
|
10
|
+
const url = validateReverseUrl(value);
|
|
11
|
+
const proxy = reverseProxyUrl(url, options.proxy);
|
|
12
|
+
if (!token || /\s/.test(token) || token.length > 4096)
|
|
13
|
+
throw new Error('Invalid reverse token.');
|
|
14
|
+
if (!name || name.length > 512 || /[\u0000-\u001f\u007f]/.test(name))
|
|
15
|
+
throw new Error('Invalid reverse server name.');
|
|
16
|
+
const log = options.logger ?? {
|
|
17
|
+
info: (message) => console.error(`[staff-mcp][reverse] ${message}`),
|
|
18
|
+
warn: (message) => console.error(`[staff-mcp][reverse] ${message}`),
|
|
19
|
+
error: (message) => console.error(`[staff-mcp][reverse] ${message}`),
|
|
26
20
|
};
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
21
|
+
if (url.protocol === 'http:')
|
|
22
|
+
log.warn('Explicit HTTP reverse control uses plaintext; use HTTPS on untrusted networks.');
|
|
23
|
+
const abort = new AbortController();
|
|
24
|
+
let active;
|
|
25
|
+
let backoff = options.reconnect?.initialDelay ?? 1000;
|
|
26
|
+
const run = async () => {
|
|
27
|
+
while (!abort.signal.aborted) {
|
|
28
|
+
let server;
|
|
29
|
+
let initializedAt;
|
|
30
|
+
let previousInitialized;
|
|
31
|
+
let initializationTimer;
|
|
32
|
+
const attempt = new AbortController();
|
|
33
|
+
const stopped = () => {
|
|
34
|
+
attempt.abort();
|
|
35
|
+
void active?.close();
|
|
36
|
+
};
|
|
37
|
+
abort.signal.addEventListener('abort', stopped, { once: true });
|
|
38
|
+
const http = createReverseHttp(url, proxy, attempt.signal);
|
|
39
|
+
const transport = new ReverseSseTransport(url, { Authorization: `Bearer ${token}`, 'X-MCP-Server-Name': name }, http.fetch, options.connectTimeout, options.heartbeat?.readTimeout);
|
|
40
|
+
active = transport;
|
|
41
|
+
try {
|
|
42
|
+
server = serverFactory();
|
|
43
|
+
configureExtensionData(server, (binding, accept, signal, origin, supportsPurpose) => {
|
|
44
|
+
if (origin !== undefined)
|
|
45
|
+
throw new Error('Reverse data does not accept an advertised origin');
|
|
46
|
+
const sessionId = transport.sessionId;
|
|
47
|
+
if (!sessionId ||
|
|
48
|
+
attempt.signal.aborted ||
|
|
49
|
+
signal.aborted)
|
|
50
|
+
throw new Error('Reverse data control session unavailable');
|
|
51
|
+
const expected = new URL(url.href);
|
|
52
|
+
expected.pathname =
|
|
53
|
+
url.pathname.replace(/\/$/, '') +
|
|
54
|
+
'/data/' +
|
|
55
|
+
sessionId;
|
|
56
|
+
return {
|
|
57
|
+
session: new HttpDataSession({
|
|
58
|
+
role: 'remote',
|
|
59
|
+
binding,
|
|
60
|
+
accept,
|
|
61
|
+
supportsPurpose,
|
|
62
|
+
fetch: http.fetch,
|
|
63
|
+
validateEndpoint: (endpoint) => {
|
|
64
|
+
if (endpoint.origin !== expected.origin ||
|
|
65
|
+
endpoint.pathname !==
|
|
66
|
+
expected.pathname ||
|
|
67
|
+
endpoint.username ||
|
|
68
|
+
endpoint.password ||
|
|
69
|
+
endpoint.search ||
|
|
70
|
+
endpoint.hash)
|
|
71
|
+
throw new Error('Reverse data endpoint rejected');
|
|
72
|
+
},
|
|
73
|
+
}),
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
previousInitialized = server.server.oninitialized;
|
|
77
|
+
server.server.oninitialized = () => {
|
|
78
|
+
previousInitialized?.();
|
|
79
|
+
initializedAt = performance.now();
|
|
80
|
+
clearTimeout(initializationTimer);
|
|
81
|
+
log.info('MCP initialized on a new SSE session.');
|
|
82
|
+
};
|
|
83
|
+
await server.connect(transport);
|
|
84
|
+
// start() completes once the SSE endpoint is admitted; only then start the initialization deadline.
|
|
85
|
+
if (initializedAt === undefined) {
|
|
86
|
+
initializationTimer = setTimeout(() => {
|
|
87
|
+
void transport.close();
|
|
88
|
+
}, options.initializationTimeout ?? 15000);
|
|
89
|
+
initializationTimer.unref();
|
|
90
|
+
}
|
|
91
|
+
await transport.closed;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
if (!abort.signal.aborted)
|
|
95
|
+
log.warn('Connection attempt ended before readiness or control connection closed.');
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
clearTimeout(initializationTimer);
|
|
99
|
+
await transport.close().catch(() => { });
|
|
100
|
+
attempt.abort();
|
|
101
|
+
await http.close().catch(() => { });
|
|
102
|
+
abort.signal.removeEventListener('abort', stopped);
|
|
103
|
+
await server?.close();
|
|
104
|
+
if (server)
|
|
105
|
+
server.server.oninitialized = previousInitialized;
|
|
106
|
+
active = undefined;
|
|
107
|
+
}
|
|
108
|
+
if (abort.signal.aborted || options.reconnect?.enabled === false)
|
|
109
|
+
break;
|
|
110
|
+
if (initializedAt !== undefined &&
|
|
111
|
+
performance.now() - initializedAt >=
|
|
112
|
+
(options.reconnect?.stableConnectionMs ?? 30000))
|
|
113
|
+
backoff = options.reconnect?.initialDelay ?? 1000;
|
|
114
|
+
log.info('Disconnected; retrying with a new session and no replay.');
|
|
115
|
+
try {
|
|
116
|
+
await delay(backoff, undefined, { signal: abort.signal });
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
backoff = Math.min(options.reconnect?.maxDelay ?? 30000, backoff * 2);
|
|
67
122
|
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
123
|
+
};
|
|
124
|
+
const closed = run();
|
|
125
|
+
return {
|
|
126
|
+
closed,
|
|
127
|
+
stop: async () => {
|
|
128
|
+
abort.abort();
|
|
129
|
+
await active?.close().catch(() => { });
|
|
130
|
+
await closed;
|
|
131
|
+
},
|
|
132
|
+
};
|
|
77
133
|
}
|
|
78
134
|
//# sourceMappingURL=reverse.js.map
|