@bryan-thompson/inspector-assessment 1.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/LICENSE +22 -0
- package/README.md +1042 -0
- package/cli/build/cli.js +277 -0
- package/cli/build/client/connection.js +38 -0
- package/cli/build/client/index.js +6 -0
- package/cli/build/client/prompts.js +38 -0
- package/cli/build/client/resources.js +30 -0
- package/cli/build/client/tools.js +74 -0
- package/cli/build/client/types.js +1 -0
- package/cli/build/error-handler.js +18 -0
- package/cli/build/index.js +232 -0
- package/cli/build/transport.js +65 -0
- package/cli/build/utils/awaitable-log.js +7 -0
- package/client/README.md +50 -0
- package/client/bin/client.js +62 -0
- package/client/bin/start.js +340 -0
- package/client/dist/assets/OAuthCallback-CLEJW5KO.js +55 -0
- package/client/dist/assets/OAuthDebugCallback-B154gAVm.js +64 -0
- package/client/dist/assets/index-DYiWOife.css +3138 -0
- package/client/dist/assets/index-EfKh2svk.js +53519 -0
- package/client/dist/index.html +14 -0
- package/client/dist/mcp.svg +12 -0
- package/package.json +106 -0
- package/server/build/index.js +647 -0
- package/server/build/mcpProxy.js +63 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import open from "open";
|
|
4
|
+
import { resolve, dirname } from "path";
|
|
5
|
+
import { spawnPromise, spawn } from "spawn-rx";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
import { randomBytes } from "crypto";
|
|
8
|
+
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const DEFAULT_MCP_PROXY_LISTEN_PORT = "6277";
|
|
11
|
+
|
|
12
|
+
function delay(ms) {
|
|
13
|
+
return new Promise((resolve) => setTimeout(resolve, ms, true));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getClientUrl(port, authDisabled, sessionToken, serverPort) {
|
|
17
|
+
const host = process.env.HOST || "localhost";
|
|
18
|
+
const baseUrl = `http://${host}:${port}`;
|
|
19
|
+
|
|
20
|
+
const params = new URLSearchParams();
|
|
21
|
+
if (serverPort && serverPort !== DEFAULT_MCP_PROXY_LISTEN_PORT) {
|
|
22
|
+
params.set("MCP_PROXY_PORT", serverPort);
|
|
23
|
+
}
|
|
24
|
+
if (!authDisabled) {
|
|
25
|
+
params.set("MCP_PROXY_AUTH_TOKEN", sessionToken);
|
|
26
|
+
}
|
|
27
|
+
return params.size > 0 ? `${baseUrl}/?${params.toString()}` : baseUrl;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function startDevServer(serverOptions) {
|
|
31
|
+
const {
|
|
32
|
+
SERVER_PORT,
|
|
33
|
+
CLIENT_PORT,
|
|
34
|
+
sessionToken,
|
|
35
|
+
envVars,
|
|
36
|
+
abort,
|
|
37
|
+
transport,
|
|
38
|
+
serverUrl,
|
|
39
|
+
} = serverOptions;
|
|
40
|
+
const serverCommand = "npx";
|
|
41
|
+
const serverArgs = ["tsx", "watch", "--clear-screen=false", "src/index.ts"];
|
|
42
|
+
const isWindows = process.platform === "win32";
|
|
43
|
+
|
|
44
|
+
const spawnOptions = {
|
|
45
|
+
cwd: resolve(__dirname, "../..", "server"),
|
|
46
|
+
env: {
|
|
47
|
+
...process.env,
|
|
48
|
+
SERVER_PORT,
|
|
49
|
+
CLIENT_PORT,
|
|
50
|
+
MCP_PROXY_AUTH_TOKEN: sessionToken,
|
|
51
|
+
MCP_ENV_VARS: JSON.stringify(envVars),
|
|
52
|
+
...(transport ? { MCP_TRANSPORT: transport } : {}),
|
|
53
|
+
...(serverUrl ? { MCP_SERVER_URL: serverUrl } : {}),
|
|
54
|
+
},
|
|
55
|
+
signal: abort.signal,
|
|
56
|
+
echoOutput: true,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// For Windows, we need to use stdin: 'ignore' to simulate < NUL
|
|
60
|
+
if (isWindows) {
|
|
61
|
+
spawnOptions.stdin = "ignore";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const server = spawn(serverCommand, serverArgs, spawnOptions);
|
|
65
|
+
|
|
66
|
+
// Give server time to start
|
|
67
|
+
const serverOk = await Promise.race([
|
|
68
|
+
new Promise((resolve) => {
|
|
69
|
+
server.subscribe({
|
|
70
|
+
complete: () => resolve(false),
|
|
71
|
+
error: () => resolve(false),
|
|
72
|
+
next: () => {}, // We're using echoOutput
|
|
73
|
+
});
|
|
74
|
+
}),
|
|
75
|
+
delay(3000).then(() => true),
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
return { server, serverOk };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function startProdServer(serverOptions) {
|
|
82
|
+
const {
|
|
83
|
+
SERVER_PORT,
|
|
84
|
+
CLIENT_PORT,
|
|
85
|
+
sessionToken,
|
|
86
|
+
envVars,
|
|
87
|
+
abort,
|
|
88
|
+
command,
|
|
89
|
+
mcpServerArgs,
|
|
90
|
+
transport,
|
|
91
|
+
serverUrl,
|
|
92
|
+
} = serverOptions;
|
|
93
|
+
const inspectorServerPath = resolve(
|
|
94
|
+
__dirname,
|
|
95
|
+
"../..",
|
|
96
|
+
"server",
|
|
97
|
+
"build",
|
|
98
|
+
"index.js",
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const server = spawnPromise(
|
|
102
|
+
"node",
|
|
103
|
+
[
|
|
104
|
+
inspectorServerPath,
|
|
105
|
+
...(command ? [`--command=${command}`] : []),
|
|
106
|
+
...(mcpServerArgs && mcpServerArgs.length > 0
|
|
107
|
+
? [`--args=${mcpServerArgs.join(" ")}`]
|
|
108
|
+
: []),
|
|
109
|
+
...(transport ? [`--transport=${transport}`] : []),
|
|
110
|
+
...(serverUrl ? [`--server-url=${serverUrl}`] : []),
|
|
111
|
+
],
|
|
112
|
+
{
|
|
113
|
+
env: {
|
|
114
|
+
...process.env,
|
|
115
|
+
SERVER_PORT,
|
|
116
|
+
CLIENT_PORT,
|
|
117
|
+
MCP_PROXY_AUTH_TOKEN: sessionToken,
|
|
118
|
+
MCP_ENV_VARS: JSON.stringify(envVars),
|
|
119
|
+
},
|
|
120
|
+
signal: abort.signal,
|
|
121
|
+
echoOutput: true,
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Make sure server started before starting client
|
|
126
|
+
const serverOk = await Promise.race([server, delay(2 * 1000)]);
|
|
127
|
+
|
|
128
|
+
return { server, serverOk };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function startDevClient(clientOptions) {
|
|
132
|
+
const {
|
|
133
|
+
CLIENT_PORT,
|
|
134
|
+
SERVER_PORT,
|
|
135
|
+
authDisabled,
|
|
136
|
+
sessionToken,
|
|
137
|
+
abort,
|
|
138
|
+
cancelled,
|
|
139
|
+
} = clientOptions;
|
|
140
|
+
const clientCommand = "npx";
|
|
141
|
+
const host = process.env.HOST || "localhost";
|
|
142
|
+
const clientArgs = ["vite", "--port", CLIENT_PORT, "--host", host];
|
|
143
|
+
|
|
144
|
+
const client = spawn(clientCommand, clientArgs, {
|
|
145
|
+
cwd: resolve(__dirname, ".."),
|
|
146
|
+
env: { ...process.env, CLIENT_PORT },
|
|
147
|
+
signal: abort.signal,
|
|
148
|
+
echoOutput: true,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const url = getClientUrl(
|
|
152
|
+
CLIENT_PORT,
|
|
153
|
+
authDisabled,
|
|
154
|
+
sessionToken,
|
|
155
|
+
SERVER_PORT,
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
// Give vite time to start before opening or logging the URL
|
|
159
|
+
setTimeout(() => {
|
|
160
|
+
console.log(`\n🚀 MCP Inspector is up and running at:\n ${url}\n`);
|
|
161
|
+
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") {
|
|
162
|
+
console.log("🌐 Opening browser...");
|
|
163
|
+
open(url);
|
|
164
|
+
}
|
|
165
|
+
}, 3000);
|
|
166
|
+
|
|
167
|
+
await new Promise((resolve) => {
|
|
168
|
+
client.subscribe({
|
|
169
|
+
complete: resolve,
|
|
170
|
+
error: (err) => {
|
|
171
|
+
if (!cancelled || process.env.DEBUG) {
|
|
172
|
+
console.error("Client error:", err);
|
|
173
|
+
}
|
|
174
|
+
resolve(null);
|
|
175
|
+
},
|
|
176
|
+
next: () => {}, // We're using echoOutput
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function startProdClient(clientOptions) {
|
|
182
|
+
const {
|
|
183
|
+
CLIENT_PORT,
|
|
184
|
+
SERVER_PORT,
|
|
185
|
+
authDisabled,
|
|
186
|
+
sessionToken,
|
|
187
|
+
abort,
|
|
188
|
+
cancelled,
|
|
189
|
+
} = clientOptions;
|
|
190
|
+
const inspectorClientPath = resolve(
|
|
191
|
+
__dirname,
|
|
192
|
+
"../..",
|
|
193
|
+
"client",
|
|
194
|
+
"bin",
|
|
195
|
+
"client.js",
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
const url = getClientUrl(
|
|
199
|
+
CLIENT_PORT,
|
|
200
|
+
authDisabled,
|
|
201
|
+
sessionToken,
|
|
202
|
+
SERVER_PORT,
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
await spawnPromise("node", [inspectorClientPath], {
|
|
206
|
+
env: {
|
|
207
|
+
...process.env,
|
|
208
|
+
CLIENT_PORT,
|
|
209
|
+
INSPECTOR_URL: url,
|
|
210
|
+
},
|
|
211
|
+
signal: abort.signal,
|
|
212
|
+
echoOutput: true,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async function main() {
|
|
217
|
+
// Parse command line arguments
|
|
218
|
+
const args = process.argv.slice(2);
|
|
219
|
+
const envVars = {};
|
|
220
|
+
const mcpServerArgs = [];
|
|
221
|
+
let command = null;
|
|
222
|
+
let parsingFlags = true;
|
|
223
|
+
let isDev = false;
|
|
224
|
+
let transport = null;
|
|
225
|
+
let serverUrl = null;
|
|
226
|
+
|
|
227
|
+
for (let i = 0; i < args.length; i++) {
|
|
228
|
+
const arg = args[i];
|
|
229
|
+
|
|
230
|
+
if (parsingFlags && arg === "--") {
|
|
231
|
+
parsingFlags = false;
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (parsingFlags && arg === "--dev") {
|
|
236
|
+
isDev = true;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (parsingFlags && arg === "--transport" && i + 1 < args.length) {
|
|
241
|
+
transport = args[++i];
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (parsingFlags && arg === "--server-url" && i + 1 < args.length) {
|
|
246
|
+
serverUrl = args[++i];
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (parsingFlags && arg === "-e" && i + 1 < args.length) {
|
|
251
|
+
const envVar = args[++i];
|
|
252
|
+
const equalsIndex = envVar.indexOf("=");
|
|
253
|
+
|
|
254
|
+
if (equalsIndex !== -1) {
|
|
255
|
+
const key = envVar.substring(0, equalsIndex);
|
|
256
|
+
const value = envVar.substring(equalsIndex + 1);
|
|
257
|
+
envVars[key] = value;
|
|
258
|
+
} else {
|
|
259
|
+
envVars[envVar] = "";
|
|
260
|
+
}
|
|
261
|
+
} else if (!command && !isDev) {
|
|
262
|
+
command = arg;
|
|
263
|
+
} else if (!isDev) {
|
|
264
|
+
mcpServerArgs.push(arg);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const CLIENT_PORT = process.env.CLIENT_PORT ?? "6274";
|
|
269
|
+
const SERVER_PORT = process.env.SERVER_PORT ?? DEFAULT_MCP_PROXY_LISTEN_PORT;
|
|
270
|
+
|
|
271
|
+
console.log(
|
|
272
|
+
isDev
|
|
273
|
+
? "Starting MCP inspector in development mode..."
|
|
274
|
+
: "Starting MCP inspector...",
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
// Use provided token from environment or generate a new one
|
|
278
|
+
const sessionToken =
|
|
279
|
+
process.env.MCP_PROXY_AUTH_TOKEN || randomBytes(32).toString("hex");
|
|
280
|
+
const authDisabled = !!process.env.DANGEROUSLY_OMIT_AUTH;
|
|
281
|
+
|
|
282
|
+
const abort = new AbortController();
|
|
283
|
+
|
|
284
|
+
let cancelled = false;
|
|
285
|
+
process.on("SIGINT", () => {
|
|
286
|
+
cancelled = true;
|
|
287
|
+
abort.abort();
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
let server, serverOk;
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
const serverOptions = {
|
|
294
|
+
SERVER_PORT,
|
|
295
|
+
CLIENT_PORT,
|
|
296
|
+
sessionToken,
|
|
297
|
+
envVars,
|
|
298
|
+
abort,
|
|
299
|
+
command,
|
|
300
|
+
mcpServerArgs,
|
|
301
|
+
transport,
|
|
302
|
+
serverUrl,
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
const result = isDev
|
|
306
|
+
? await startDevServer(serverOptions)
|
|
307
|
+
: await startProdServer(serverOptions);
|
|
308
|
+
|
|
309
|
+
server = result.server;
|
|
310
|
+
serverOk = result.serverOk;
|
|
311
|
+
} catch (error) {}
|
|
312
|
+
|
|
313
|
+
if (serverOk) {
|
|
314
|
+
try {
|
|
315
|
+
const clientOptions = {
|
|
316
|
+
CLIENT_PORT,
|
|
317
|
+
SERVER_PORT,
|
|
318
|
+
authDisabled,
|
|
319
|
+
sessionToken,
|
|
320
|
+
abort,
|
|
321
|
+
cancelled,
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
await (isDev
|
|
325
|
+
? startDevClient(clientOptions)
|
|
326
|
+
: startProdClient(clientOptions));
|
|
327
|
+
} catch (e) {
|
|
328
|
+
if (!cancelled || process.env.DEBUG) throw e;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return 0;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
main()
|
|
336
|
+
.then((_) => process.exit(0))
|
|
337
|
+
.catch((e) => {
|
|
338
|
+
console.error(e);
|
|
339
|
+
process.exit(1);
|
|
340
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { u as useToast, r as reactExports, j as jsxRuntimeExports, p as parseOAuthCallbackParams, g as generateOAuthErrorDescription, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-EfKh2svk.js";
|
|
2
|
+
const OAuthCallback = ({ onConnect }) => {
|
|
3
|
+
const { toast } = useToast();
|
|
4
|
+
const hasProcessedRef = reactExports.useRef(false);
|
|
5
|
+
reactExports.useEffect(() => {
|
|
6
|
+
const handleCallback = async () => {
|
|
7
|
+
if (hasProcessedRef.current) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
hasProcessedRef.current = true;
|
|
11
|
+
const notifyError = (description) => void toast({
|
|
12
|
+
title: "OAuth Authorization Error",
|
|
13
|
+
description,
|
|
14
|
+
variant: "destructive"
|
|
15
|
+
});
|
|
16
|
+
const params = parseOAuthCallbackParams(window.location.search);
|
|
17
|
+
if (!params.successful) {
|
|
18
|
+
return notifyError(generateOAuthErrorDescription(params));
|
|
19
|
+
}
|
|
20
|
+
const serverUrl = sessionStorage.getItem(SESSION_KEYS.SERVER_URL);
|
|
21
|
+
if (!serverUrl) {
|
|
22
|
+
return notifyError("Missing Server URL");
|
|
23
|
+
}
|
|
24
|
+
let result;
|
|
25
|
+
try {
|
|
26
|
+
const serverAuthProvider = new InspectorOAuthClientProvider(serverUrl);
|
|
27
|
+
result = await auth(serverAuthProvider, {
|
|
28
|
+
serverUrl,
|
|
29
|
+
authorizationCode: params.code
|
|
30
|
+
});
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error("OAuth callback error:", error);
|
|
33
|
+
return notifyError(`Unexpected error occurred: ${error}`);
|
|
34
|
+
}
|
|
35
|
+
if (result !== "AUTHORIZED") {
|
|
36
|
+
return notifyError(
|
|
37
|
+
`Expected to be authorized after providing auth code, got: ${result}`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
toast({
|
|
41
|
+
title: "Success",
|
|
42
|
+
description: "Successfully authenticated with OAuth",
|
|
43
|
+
variant: "default"
|
|
44
|
+
});
|
|
45
|
+
onConnect(serverUrl);
|
|
46
|
+
};
|
|
47
|
+
handleCallback().finally(() => {
|
|
48
|
+
window.history.replaceState({}, document.title, "/");
|
|
49
|
+
});
|
|
50
|
+
}, [toast, onConnect]);
|
|
51
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg text-gray-500", children: "Processing OAuth callback..." }) });
|
|
52
|
+
};
|
|
53
|
+
export {
|
|
54
|
+
OAuthCallback as default
|
|
55
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-EfKh2svk.js";
|
|
2
|
+
const OAuthDebugCallback = ({ onConnect }) => {
|
|
3
|
+
reactExports.useEffect(() => {
|
|
4
|
+
let isProcessed = false;
|
|
5
|
+
const handleCallback = async () => {
|
|
6
|
+
if (isProcessed) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
isProcessed = true;
|
|
10
|
+
const params = parseOAuthCallbackParams(window.location.search);
|
|
11
|
+
if (!params.successful) {
|
|
12
|
+
const errorMsg = generateOAuthErrorDescription(params);
|
|
13
|
+
onConnect({ errorMsg });
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const serverUrl = sessionStorage.getItem(SESSION_KEYS.SERVER_URL);
|
|
17
|
+
const storedState = sessionStorage.getItem(
|
|
18
|
+
SESSION_KEYS.AUTH_DEBUGGER_STATE
|
|
19
|
+
);
|
|
20
|
+
let restoredState = null;
|
|
21
|
+
if (storedState) {
|
|
22
|
+
try {
|
|
23
|
+
restoredState = JSON.parse(storedState);
|
|
24
|
+
if (restoredState && typeof restoredState.resource === "string") {
|
|
25
|
+
restoredState.resource = new URL(restoredState.resource);
|
|
26
|
+
}
|
|
27
|
+
if (restoredState && typeof restoredState.authorizationUrl === "string") {
|
|
28
|
+
restoredState.authorizationUrl = new URL(
|
|
29
|
+
restoredState.authorizationUrl
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
sessionStorage.removeItem(SESSION_KEYS.AUTH_DEBUGGER_STATE);
|
|
33
|
+
} catch (e) {
|
|
34
|
+
console.error("Failed to parse stored auth state:", e);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!serverUrl) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!params.code) {
|
|
41
|
+
onConnect({ errorMsg: "Missing authorization code" });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
onConnect({ authorizationCode: params.code, restoredState });
|
|
45
|
+
};
|
|
46
|
+
handleCallback().finally(() => {
|
|
47
|
+
if (sessionStorage.getItem(SESSION_KEYS.SERVER_URL)) {
|
|
48
|
+
window.history.replaceState({}, document.title, "/");
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return () => {
|
|
52
|
+
isProcessed = true;
|
|
53
|
+
};
|
|
54
|
+
}, [onConnect]);
|
|
55
|
+
const callbackParams = parseOAuthCallbackParams(window.location.search);
|
|
56
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-4 p-4 bg-secondary rounded-md max-w-md", children: [
|
|
57
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mb-2 text-sm", children: "Please copy this authorization code and return to the Auth Debugger:" }),
|
|
58
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "block p-2 bg-muted rounded-sm overflow-x-auto text-xs", children: callbackParams.successful && "code" in callbackParams ? callbackParams.code : `No code found: ${callbackParams.error}, ${callbackParams.error_description}` }),
|
|
59
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-4 text-xs text-muted-foreground", children: "Close this tab and paste the code in the OAuth flow to complete authentication." })
|
|
60
|
+
] }) });
|
|
61
|
+
};
|
|
62
|
+
export {
|
|
63
|
+
OAuthDebugCallback as default
|
|
64
|
+
};
|