@modelcontextprotocol/inspector 2.2.0 → 2.3.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/README.md +105 -11
- package/clients/cli/build/index.js +1397 -442
- package/clients/tui/build/index.js +1282 -76
- package/clients/tui/build/{undici-HXPKCIY3.js → undici-KNXAVD2F.js} +1225 -370
- package/clients/web/build/index.js +152 -52
- package/clients/web/build/{undici-HXPKCIY3.js → undici-KNXAVD2F.js} +1225 -370
- package/clients/web/dist/assets/{index-BrCIxo3Q.js → index-CwhDusR3.js} +46 -51
- package/clients/web/dist/assets/{prism-light-CWdjx3zH.js → prism-light-DBxbqjnM.js} +1 -1
- package/clients/web/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -180,6 +180,38 @@ function envPairsToRecord(pairs) {
|
|
|
180
180
|
}
|
|
181
181
|
return out;
|
|
182
182
|
}
|
|
183
|
+
function cleanAuthorizationParams(params) {
|
|
184
|
+
if (params === void 0) return void 0;
|
|
185
|
+
if (typeof params !== "object" || params === null || Array.isArray(params)) {
|
|
186
|
+
console.warn(
|
|
187
|
+
"Ignoring `oauth.authorizationParams`: expected an object of string values, got",
|
|
188
|
+
Array.isArray(params) ? "array" : typeof params
|
|
189
|
+
);
|
|
190
|
+
return void 0;
|
|
191
|
+
}
|
|
192
|
+
const out = {};
|
|
193
|
+
for (const [key, value] of Object.entries(params)) {
|
|
194
|
+
if (typeof value !== "string") {
|
|
195
|
+
console.warn(
|
|
196
|
+
`Dropping \`oauth.authorizationParams.${key}\`: expected a string value, got ${typeof value}.`
|
|
197
|
+
);
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (key.trim() === "") continue;
|
|
201
|
+
out[key] = value;
|
|
202
|
+
}
|
|
203
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
204
|
+
}
|
|
205
|
+
function cleanEndpointOverride(value, field) {
|
|
206
|
+
if (value === void 0) return void 0;
|
|
207
|
+
if (typeof value !== "string") {
|
|
208
|
+
console.warn(
|
|
209
|
+
`Ignoring \`oauth.${field}\`: expected a string, got ${typeof value}.`
|
|
210
|
+
);
|
|
211
|
+
return void 0;
|
|
212
|
+
}
|
|
213
|
+
return value.trim() || void 0;
|
|
214
|
+
}
|
|
183
215
|
function storedFieldsToInspectorSettings(stored) {
|
|
184
216
|
const hasAny = stored.headers !== void 0 || stored.metadata !== void 0 || stored.connectionTimeout !== void 0 || stored.requestTimeout !== void 0 || stored.taskTtl !== void 0 || stored.autoRefreshOnListChanged !== void 0 || stored.paginatedLists !== void 0 || stored.advertisedExtensions !== void 0 || stored.maxFetchRequests !== void 0 || stored.oauth !== void 0 || stored.roots !== void 0 || stored.protocolEra !== void 0 || stored.modernLogLevel !== void 0 || stored.env !== void 0 || stored.cwd !== void 0;
|
|
185
217
|
if (!hasAny) return void 0;
|
|
@@ -217,6 +249,19 @@ function storedFieldsToInspectorSettings(stored) {
|
|
|
217
249
|
if (stored.oauth?.clientSecret)
|
|
218
250
|
settings.oauthClientSecret = stored.oauth.clientSecret;
|
|
219
251
|
if (stored.oauth?.scopes) settings.oauthScopes = stored.oauth.scopes;
|
|
252
|
+
const authorizationParams = cleanAuthorizationParams(
|
|
253
|
+
stored.oauth?.authorizationParams
|
|
254
|
+
);
|
|
255
|
+
if (authorizationParams) {
|
|
256
|
+
settings.oauthAuthorizationParams = envRecordToPairs(authorizationParams);
|
|
257
|
+
}
|
|
258
|
+
const authorizationUrl = cleanEndpointOverride(
|
|
259
|
+
stored.oauth?.authorizationUrl,
|
|
260
|
+
"authorizationUrl"
|
|
261
|
+
);
|
|
262
|
+
if (authorizationUrl) settings.oauthAuthorizationUrl = authorizationUrl;
|
|
263
|
+
const tokenUrl = cleanEndpointOverride(stored.oauth?.tokenUrl, "tokenUrl");
|
|
264
|
+
if (tokenUrl) settings.oauthTokenUrl = tokenUrl;
|
|
220
265
|
if (stored.oauth?.onInsufficientScope) {
|
|
221
266
|
settings.oauthOnInsufficientScope = stored.oauth.onInsufficientScope;
|
|
222
267
|
}
|
|
@@ -272,6 +317,18 @@ function inspectorSettingsToStoredFields(settings) {
|
|
|
272
317
|
if (settings.oauthClientSecret)
|
|
273
318
|
oauthFields.clientSecret = settings.oauthClientSecret;
|
|
274
319
|
if (settings.oauthScopes) oauthFields.scopes = settings.oauthScopes;
|
|
320
|
+
if (settings.oauthAuthorizationParams) {
|
|
321
|
+
const authParams = envPairsToRecord(settings.oauthAuthorizationParams);
|
|
322
|
+
if (Object.keys(authParams).length > 0) {
|
|
323
|
+
oauthFields.authorizationParams = authParams;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (settings.oauthAuthorizationUrl?.trim()) {
|
|
327
|
+
oauthFields.authorizationUrl = settings.oauthAuthorizationUrl.trim();
|
|
328
|
+
}
|
|
329
|
+
if (settings.oauthTokenUrl?.trim()) {
|
|
330
|
+
oauthFields.tokenUrl = settings.oauthTokenUrl.trim();
|
|
331
|
+
}
|
|
275
332
|
if (settings.oauthOnInsufficientScope) {
|
|
276
333
|
oauthFields.onInsufficientScope = settings.oauthOnInsufficientScope;
|
|
277
334
|
}
|
|
@@ -318,14 +375,7 @@ function extractSecretsFromStored(stored) {
|
|
|
318
375
|
const stripped = { ...stored };
|
|
319
376
|
if (stored.oauth?.clientSecret) {
|
|
320
377
|
secrets[SECRET_FIELD_OAUTH_CLIENT_SECRET] = stored.oauth.clientSecret;
|
|
321
|
-
const restOauth =
|
|
322
|
-
if (stored.oauth.clientId !== void 0)
|
|
323
|
-
restOauth.clientId = stored.oauth.clientId;
|
|
324
|
-
if (stored.oauth.scopes !== void 0)
|
|
325
|
-
restOauth.scopes = stored.oauth.scopes;
|
|
326
|
-
if (stored.oauth.enterpriseManaged === true) {
|
|
327
|
-
restOauth.enterpriseManaged = true;
|
|
328
|
-
}
|
|
378
|
+
const { clientSecret: _clientSecret, ...restOauth } = stored.oauth;
|
|
329
379
|
if (Object.keys(restOauth).length > 0) {
|
|
330
380
|
stripped.oauth = restOauth;
|
|
331
381
|
} else {
|
|
@@ -608,6 +658,7 @@ function resolveServerConfigs(options, mode) {
|
|
|
608
658
|
}
|
|
609
659
|
|
|
610
660
|
// server/web-server-config.ts
|
|
661
|
+
import open from "open";
|
|
611
662
|
import pino from "pino";
|
|
612
663
|
|
|
613
664
|
// ../../core/mcp/remote/constants.ts
|
|
@@ -710,6 +761,25 @@ function isAllInterfacesHost(host) {
|
|
|
710
761
|
return ALL_INTERFACES_LITERALS.has(normalized) || isAllZeroIpv4(normalized);
|
|
711
762
|
}
|
|
712
763
|
|
|
764
|
+
// server/resolve-bind-host.ts
|
|
765
|
+
var BIND_ALL_INTERFACES_ENV = "DANGEROUSLY_BIND_ALL_INTERFACES";
|
|
766
|
+
function isEnabled(value) {
|
|
767
|
+
const v = value?.trim().toLowerCase();
|
|
768
|
+
return v === "true" || v === "1";
|
|
769
|
+
}
|
|
770
|
+
var DEFAULT_BIND_HOST = "127.0.0.1";
|
|
771
|
+
function resolveBindHostname(env = process.env) {
|
|
772
|
+
const host = (env.HOST ?? DEFAULT_BIND_HOST).trim();
|
|
773
|
+
if (isAllInterfacesHost(host) && !isEnabled(env[BIND_ALL_INTERFACES_ENV])) {
|
|
774
|
+
const resolved = canonicalUrlHost(host);
|
|
775
|
+
const shown = stripBrackets(resolved) === stripBrackets(host.toLowerCase()) ? `HOST="${host}"` : `HOST="${host}" (resolves to ${resolved})`;
|
|
776
|
+
throw new Error(
|
|
777
|
+
`Refusing to bind ${shown}: this exposes the MCP Inspector to your entire network, and its backend can spawn local processes and connect to MCP servers on your behalf \u2014 the exposure DNS-rebinding attacks target. Bind a loopback host (localhost / 127.0.0.1) instead. To override \u2014 only inside an isolated container or trusted network \u2014 set ${BIND_ALL_INTERFACES_ENV}=true.`
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
return stripBrackets(host);
|
|
781
|
+
}
|
|
782
|
+
|
|
713
783
|
// server/sandbox-controller.ts
|
|
714
784
|
var __dirname = dirname4(fileURLToPath2(import.meta.url));
|
|
715
785
|
var LOOPBACK_FRAME_ANCESTORS = ["http://127.0.0.1:*", "http://localhost:*"];
|
|
@@ -725,6 +795,7 @@ function parseListenPort(raw) {
|
|
|
725
795
|
const n = parseInt(v, 10);
|
|
726
796
|
return n <= 65535 ? n : void 0;
|
|
727
797
|
}
|
|
798
|
+
var DEFAULT_SANDBOX_PORT = 6275;
|
|
728
799
|
function resolveSandboxPort() {
|
|
729
800
|
const fromSandbox = parseListenPort(process.env.MCP_SANDBOX_PORT);
|
|
730
801
|
if (fromSandbox === void 0 && process.env.MCP_SANDBOX_PORT?.trim()) {
|
|
@@ -732,10 +803,10 @@ function resolveSandboxPort() {
|
|
|
732
803
|
`Ignoring invalid MCP_SANDBOX_PORT="${process.env.MCP_SANDBOX_PORT}" (need an integer 0\u201365535); falling back.`
|
|
733
804
|
);
|
|
734
805
|
}
|
|
735
|
-
return fromSandbox ?? parseListenPort(process.env.SERVER_PORT) ??
|
|
806
|
+
return fromSandbox ?? parseListenPort(process.env.SERVER_PORT) ?? DEFAULT_SANDBOX_PORT;
|
|
736
807
|
}
|
|
737
808
|
function createSandboxController(options) {
|
|
738
|
-
const { port, host =
|
|
809
|
+
const { port, host = DEFAULT_BIND_HOST, allowedOrigins } = options;
|
|
739
810
|
let server = null;
|
|
740
811
|
let sandboxUrl = null;
|
|
741
812
|
const SANDBOX_PROXY_CSP = sandboxFrameAncestors(allowedOrigins);
|
|
@@ -773,8 +844,17 @@ function createSandboxController(options) {
|
|
|
773
844
|
});
|
|
774
845
|
res.end(sandboxHtml);
|
|
775
846
|
});
|
|
847
|
+
let retriedDynamic = false;
|
|
776
848
|
server.on("error", (err) => {
|
|
777
849
|
if (err.code === "EADDRINUSE") {
|
|
850
|
+
if (!retriedDynamic && port !== 0) {
|
|
851
|
+
retriedDynamic = true;
|
|
852
|
+
console.warn(
|
|
853
|
+
`Sandbox: port ${port} in use; falling back to an OS-assigned port. The MCP Apps tab will work locally, but the sandbox is no longer on a predictable port \u2014 set MCP_SANDBOX_PORT to a free one if you need to forward it (container / SSH tunnel / reverse proxy).`
|
|
854
|
+
);
|
|
855
|
+
server.listen(0, host);
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
778
858
|
console.error(
|
|
779
859
|
`Sandbox: port ${port || "dynamic"} in use. MCP Apps tab may not work.`
|
|
780
860
|
);
|
|
@@ -816,24 +896,6 @@ function createSandboxController(options) {
|
|
|
816
896
|
};
|
|
817
897
|
}
|
|
818
898
|
|
|
819
|
-
// server/resolve-bind-host.ts
|
|
820
|
-
var BIND_ALL_INTERFACES_ENV = "DANGEROUSLY_BIND_ALL_INTERFACES";
|
|
821
|
-
function isEnabled(value) {
|
|
822
|
-
const v = value?.trim().toLowerCase();
|
|
823
|
-
return v === "true" || v === "1";
|
|
824
|
-
}
|
|
825
|
-
function resolveBindHostname(env = process.env) {
|
|
826
|
-
const host = (env.HOST ?? "localhost").trim();
|
|
827
|
-
if (isAllInterfacesHost(host) && !isEnabled(env[BIND_ALL_INTERFACES_ENV])) {
|
|
828
|
-
const resolved = canonicalUrlHost(host);
|
|
829
|
-
const shown = stripBrackets(resolved) === stripBrackets(host.toLowerCase()) ? `HOST="${host}"` : `HOST="${host}" (resolves to ${resolved})`;
|
|
830
|
-
throw new Error(
|
|
831
|
-
`Refusing to bind ${shown}: this exposes the MCP Inspector to your entire network, and its backend can spawn local processes and connect to MCP servers on your behalf \u2014 the exposure DNS-rebinding attacks target. Bind a loopback host (localhost / 127.0.0.1) instead. To override \u2014 only inside an isolated container or trusted network \u2014 set ${BIND_ALL_INTERFACES_ENV}=true.`
|
|
832
|
-
);
|
|
833
|
-
}
|
|
834
|
-
return stripBrackets(host);
|
|
835
|
-
}
|
|
836
|
-
|
|
837
899
|
// server/web-server-config.ts
|
|
838
900
|
var inspectorVersion = readInspectorVersionSafe(import.meta.url);
|
|
839
901
|
function defaultEnvironmentFromProcess(extra) {
|
|
@@ -928,6 +990,11 @@ MCP Inspector Web is up and running at:
|
|
|
928
990
|
}
|
|
929
991
|
return url;
|
|
930
992
|
}
|
|
993
|
+
function openBrowser(url) {
|
|
994
|
+
open(url).catch((err) => {
|
|
995
|
+
console.warn("Could not open a browser automatically:", err);
|
|
996
|
+
});
|
|
997
|
+
}
|
|
931
998
|
var LOOPBACK_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
932
999
|
function httpOrigin(host, port) {
|
|
933
1000
|
return port === 80 ? `http://${host}` : `http://${host}:${port}`;
|
|
@@ -1023,9 +1090,6 @@ import { fileURLToPath as fileURLToPath4 } from "url";
|
|
|
1023
1090
|
import { createServer as createServer2 } from "vite";
|
|
1024
1091
|
import react from "@vitejs/plugin-react";
|
|
1025
1092
|
|
|
1026
|
-
// server/vite-hono-plugin.ts
|
|
1027
|
-
import open from "open";
|
|
1028
|
-
|
|
1029
1093
|
// ../../core/mcp/remote/node/server.ts
|
|
1030
1094
|
import { randomBytes, timingSafeEqual } from "crypto";
|
|
1031
1095
|
import { existsSync as existsSync2, readFileSync as readFileSync4 } from "fs";
|
|
@@ -1395,7 +1459,7 @@ function withProxyDispatcher(baseFetch) {
|
|
|
1395
1459
|
if (readProxyEnv() === void 0) return baseFetch;
|
|
1396
1460
|
let dispatcherPromise;
|
|
1397
1461
|
const getDispatcher = () => {
|
|
1398
|
-
dispatcherPromise ??= import("./undici-
|
|
1462
|
+
dispatcherPromise ??= import("./undici-KNXAVD2F.js").then(
|
|
1399
1463
|
({ EnvHttpProxyAgent }) => new EnvHttpProxyAgent(),
|
|
1400
1464
|
(cause) => {
|
|
1401
1465
|
throw new Error(
|
|
@@ -2319,6 +2383,24 @@ async function deleteClientConfigStore(filePath, secretStore) {
|
|
|
2319
2383
|
// ../../core/mcp/remote/node/server.ts
|
|
2320
2384
|
import { ZodError as ZodError2 } from "zod";
|
|
2321
2385
|
var SSE_PRIMING_COMMENT = ":\n\n";
|
|
2386
|
+
function closeAbortedStream(stream) {
|
|
2387
|
+
stream.close().catch(() => {
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
async function primeAndHoldSseStream(stream, cleanup) {
|
|
2391
|
+
let done = false;
|
|
2392
|
+
const aborted = new Promise((resolve6) => {
|
|
2393
|
+
stream.onAbort(() => {
|
|
2394
|
+
if (done) return;
|
|
2395
|
+
done = true;
|
|
2396
|
+
cleanup();
|
|
2397
|
+
closeAbortedStream(stream);
|
|
2398
|
+
resolve6();
|
|
2399
|
+
});
|
|
2400
|
+
});
|
|
2401
|
+
await stream.write(SSE_PRIMING_COMMENT);
|
|
2402
|
+
await aborted;
|
|
2403
|
+
}
|
|
2322
2404
|
function createOriginMiddleware(allowedOrigins) {
|
|
2323
2405
|
return async (c, next) => {
|
|
2324
2406
|
if (!allowedOrigins || allowedOrigins.length === 0) {
|
|
@@ -2730,19 +2812,12 @@ function createRemoteApp(options) {
|
|
|
2730
2812
|
sessions.delete(sessionId);
|
|
2731
2813
|
return;
|
|
2732
2814
|
}
|
|
2733
|
-
await stream
|
|
2734
|
-
stream.onAbort(() => {
|
|
2815
|
+
await primeAndHoldSseStream(stream, () => {
|
|
2735
2816
|
const shouldCleanup = session.clearEventConsumer();
|
|
2736
|
-
stream.close();
|
|
2737
2817
|
if (shouldCleanup || session.isTransportDead()) {
|
|
2738
2818
|
sessions.delete(sessionId);
|
|
2739
2819
|
}
|
|
2740
2820
|
});
|
|
2741
|
-
await new Promise((resolve6) => {
|
|
2742
|
-
stream.onAbort(() => {
|
|
2743
|
-
resolve6();
|
|
2744
|
-
});
|
|
2745
|
-
});
|
|
2746
2821
|
});
|
|
2747
2822
|
});
|
|
2748
2823
|
app.post("/api/mcp/disconnect", async (c) => {
|
|
@@ -2930,9 +3005,21 @@ function createRemoteApp(options) {
|
|
|
2930
3005
|
const isOauthObject = (v) => {
|
|
2931
3006
|
if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
|
|
2932
3007
|
const o = v;
|
|
2933
|
-
for (const k of [
|
|
3008
|
+
for (const k of [
|
|
3009
|
+
"clientId",
|
|
3010
|
+
"clientSecret",
|
|
3011
|
+
"scopes",
|
|
3012
|
+
// #1906 — shape only; the values are validated as absolute http(s) URLs
|
|
3013
|
+
// where they're applied (core/auth/endpointOverrides.ts), so a typo drops
|
|
3014
|
+
// one field with a warning instead of dropping the whole `oauth` block.
|
|
3015
|
+
"authorizationUrl",
|
|
3016
|
+
"tokenUrl"
|
|
3017
|
+
]) {
|
|
2934
3018
|
if (o[k] !== void 0 && typeof o[k] !== "string") return false;
|
|
2935
3019
|
}
|
|
3020
|
+
if (o.authorizationParams !== void 0 && !isStringRecord(o.authorizationParams)) {
|
|
3021
|
+
return false;
|
|
3022
|
+
}
|
|
2936
3023
|
if (o.enterpriseManaged !== void 0 && typeof o.enterpriseManaged !== "boolean") {
|
|
2937
3024
|
return false;
|
|
2938
3025
|
}
|
|
@@ -3007,7 +3094,7 @@ function createRemoteApp(options) {
|
|
|
3007
3094
|
if ("oauth" in valObj && !isOauthObject(valObj.oauth)) {
|
|
3008
3095
|
logWarn(
|
|
3009
3096
|
{ route: "/api/servers", id, droppedKey: "oauth" },
|
|
3010
|
-
"Dropping malformed `oauth` field \u2014 expected `{ clientId?, clientSecret?, scopes?, enterpriseManaged? }`."
|
|
3097
|
+
"Dropping malformed `oauth` field \u2014 expected `{ clientId?, clientSecret?, scopes?, authorizationParams?, authorizationUrl?, tokenUrl?, enterpriseManaged?, onInsufficientScope? }`."
|
|
3011
3098
|
);
|
|
3012
3099
|
delete valObj.oauth;
|
|
3013
3100
|
}
|
|
@@ -3164,12 +3251,22 @@ function createRemoteApp(options) {
|
|
|
3164
3251
|
for (const optional of [
|
|
3165
3252
|
"oauthClientId",
|
|
3166
3253
|
"oauthClientSecret",
|
|
3167
|
-
"oauthScopes"
|
|
3254
|
+
"oauthScopes",
|
|
3255
|
+
// #1906 — string-shaped on the wire; URL validity is checked where the
|
|
3256
|
+
// override is applied, not here.
|
|
3257
|
+
"oauthAuthorizationUrl",
|
|
3258
|
+
"oauthTokenUrl"
|
|
3168
3259
|
]) {
|
|
3169
3260
|
if (obj[optional] !== void 0 && typeof obj[optional] !== "string") {
|
|
3170
3261
|
return { ok: false, error: `settings.${optional} must be a string` };
|
|
3171
3262
|
}
|
|
3172
3263
|
}
|
|
3264
|
+
if (obj.oauthAuthorizationParams !== void 0 && !isKvArray2(obj.oauthAuthorizationParams)) {
|
|
3265
|
+
return {
|
|
3266
|
+
ok: false,
|
|
3267
|
+
error: "settings.oauthAuthorizationParams must be an array of { key, value }"
|
|
3268
|
+
};
|
|
3269
|
+
}
|
|
3173
3270
|
if (obj.enterpriseManaged !== void 0 && typeof obj.enterpriseManaged !== "boolean") {
|
|
3174
3271
|
return {
|
|
3175
3272
|
ok: false,
|
|
@@ -3243,6 +3340,15 @@ function createRemoteApp(options) {
|
|
|
3243
3340
|
if (typeof obj.oauthScopes === "string" && obj.oauthScopes !== "") {
|
|
3244
3341
|
value.oauthScopes = obj.oauthScopes;
|
|
3245
3342
|
}
|
|
3343
|
+
if (isKvArray2(obj.oauthAuthorizationParams)) {
|
|
3344
|
+
value.oauthAuthorizationParams = obj.oauthAuthorizationParams;
|
|
3345
|
+
}
|
|
3346
|
+
if (typeof obj.oauthAuthorizationUrl === "string" && obj.oauthAuthorizationUrl !== "") {
|
|
3347
|
+
value.oauthAuthorizationUrl = obj.oauthAuthorizationUrl;
|
|
3348
|
+
}
|
|
3349
|
+
if (typeof obj.oauthTokenUrl === "string" && obj.oauthTokenUrl !== "") {
|
|
3350
|
+
value.oauthTokenUrl = obj.oauthTokenUrl;
|
|
3351
|
+
}
|
|
3246
3352
|
if (obj.enterpriseManaged === true) {
|
|
3247
3353
|
value.enterpriseManaged = true;
|
|
3248
3354
|
}
|
|
@@ -3701,14 +3807,9 @@ function createRemoteApp(options) {
|
|
|
3701
3807
|
serverEventSubscribers.add(send);
|
|
3702
3808
|
ensureWatcher();
|
|
3703
3809
|
}
|
|
3704
|
-
await stream
|
|
3705
|
-
stream.onAbort(() => {
|
|
3810
|
+
await primeAndHoldSseStream(stream, () => {
|
|
3706
3811
|
serverEventSubscribers.delete(send);
|
|
3707
3812
|
void maybeStopWatcher();
|
|
3708
|
-
stream.close();
|
|
3709
|
-
});
|
|
3710
|
-
await new Promise((resolve6) => {
|
|
3711
|
-
stream.onAbort(() => resolve6());
|
|
3712
3813
|
});
|
|
3713
3814
|
});
|
|
3714
3815
|
});
|
|
@@ -3807,7 +3908,7 @@ function honoMiddlewarePlugin(config) {
|
|
|
3807
3908
|
sandboxUrl ?? void 0
|
|
3808
3909
|
);
|
|
3809
3910
|
if (config.autoOpen) {
|
|
3810
|
-
|
|
3911
|
+
openBrowser(url);
|
|
3811
3912
|
}
|
|
3812
3913
|
};
|
|
3813
3914
|
server.httpServer.once("listening", () => {
|
|
@@ -4129,7 +4230,6 @@ import { readFileSync as readFileSync5 } from "fs";
|
|
|
4129
4230
|
import { join as join7, dirname as dirname6 } from "path";
|
|
4130
4231
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
4131
4232
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
4132
|
-
import open2 from "open";
|
|
4133
4233
|
import { serve } from "@hono/node-server";
|
|
4134
4234
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
4135
4235
|
import { Hono as Hono2 } from "hono";
|
|
@@ -4201,7 +4301,7 @@ async function startHonoServer(config) {
|
|
|
4201
4301
|
sandboxUrl ?? void 0
|
|
4202
4302
|
);
|
|
4203
4303
|
if (config.autoOpen) {
|
|
4204
|
-
|
|
4304
|
+
openBrowser(url);
|
|
4205
4305
|
}
|
|
4206
4306
|
}
|
|
4207
4307
|
);
|