skybridge 0.0.0-dev.f40327b → 0.0.0-dev.f40afe0
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 +1 -0
- package/dist/cli/build-helpers.d.ts +10 -0
- package/dist/cli/build-helpers.js +93 -0
- package/dist/cli/build-helpers.js.map +1 -0
- package/dist/cli/build-helpers.test.d.ts +1 -0
- package/dist/cli/build-helpers.test.js +89 -0
- package/dist/cli/build-helpers.test.js.map +1 -0
- package/dist/cli/build-steps.d.ts +2 -0
- package/dist/cli/build-steps.js +68 -0
- package/dist/cli/build-steps.js.map +1 -0
- package/dist/cli/build-steps.test.d.ts +1 -0
- package/dist/cli/build-steps.test.js +52 -0
- package/dist/cli/build-steps.test.js.map +1 -0
- package/dist/cli/detect-port.d.ts +2 -2
- package/dist/cli/detect-port.js +9 -20
- package/dist/cli/detect-port.js.map +1 -1
- package/dist/cli/header.d.ts +1 -1
- package/dist/cli/resolve-views-dir.d.ts +1 -0
- package/dist/cli/resolve-views-dir.js +17 -0
- package/dist/cli/resolve-views-dir.js.map +1 -0
- package/dist/cli/run-plain.d.ts +18 -0
- package/dist/cli/run-plain.js +89 -0
- package/dist/cli/run-plain.js.map +1 -0
- package/dist/cli/start-tunnel-view-build.d.ts +1 -0
- package/dist/cli/start-tunnel-view-build.js +16 -0
- package/dist/cli/start-tunnel-view-build.js.map +1 -0
- package/dist/cli/use-execute-steps.d.ts +1 -1
- package/dist/cli/use-nodemon.d.ts +14 -0
- package/dist/cli/use-nodemon.js +71 -60
- package/dist/cli/use-nodemon.js.map +1 -1
- package/dist/cli/use-typescript-check.d.ts +8 -2
- package/dist/cli/use-typescript-check.js +70 -67
- package/dist/cli/use-typescript-check.js.map +1 -1
- package/dist/commands/build.d.ts +0 -3
- package/dist/commands/build.js +2 -73
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/dev.d.ts +1 -0
- package/dist/commands/dev.js +57 -0
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/start.js +7 -1
- package/dist/commands/start.js.map +1 -1
- package/dist/server/auth/discovery.d.ts +32 -0
- package/dist/server/auth/discovery.js +56 -0
- package/dist/server/auth/discovery.js.map +1 -0
- package/dist/server/auth/discovery.test.d.ts +1 -0
- package/dist/server/auth/discovery.test.js +93 -0
- package/dist/server/auth/discovery.test.js.map +1 -0
- package/dist/server/auth/index.d.ts +18 -0
- package/dist/server/auth/index.js +2 -0
- package/dist/server/auth/index.js.map +1 -0
- package/dist/server/auth/providers/auth0.d.ts +18 -0
- package/dist/server/auth/providers/auth0.js +31 -0
- package/dist/server/auth/providers/auth0.js.map +1 -0
- package/dist/server/auth/providers/auth0.test.d.ts +1 -0
- package/dist/server/auth/providers/auth0.test.js +48 -0
- package/dist/server/auth/providers/auth0.test.js.map +1 -0
- package/dist/server/auth/providers/clerk.d.ts +14 -0
- package/dist/server/auth/providers/clerk.js +16 -0
- package/dist/server/auth/providers/clerk.js.map +1 -0
- package/dist/server/auth/providers/clerk.test.d.ts +1 -0
- package/dist/server/auth/providers/clerk.test.js +28 -0
- package/dist/server/auth/providers/clerk.test.js.map +1 -0
- package/dist/server/auth/providers/custom.d.ts +24 -0
- package/dist/server/auth/providers/custom.js +37 -0
- package/dist/server/auth/providers/custom.js.map +1 -0
- package/dist/server/auth/providers/custom.test.d.ts +1 -0
- package/dist/server/auth/providers/custom.test.js +107 -0
- package/dist/server/auth/providers/custom.test.js.map +1 -0
- package/dist/server/auth/providers/descope.d.ts +15 -0
- package/dist/server/auth/providers/descope.js +33 -0
- package/dist/server/auth/providers/descope.js.map +1 -0
- package/dist/server/auth/providers/descope.test.d.ts +1 -0
- package/dist/server/auth/providers/descope.test.js +37 -0
- package/dist/server/auth/providers/descope.test.js.map +1 -0
- package/dist/server/auth/providers/shared.d.ts +2 -0
- package/dist/server/auth/providers/shared.js +6 -0
- package/dist/server/auth/providers/shared.js.map +1 -0
- package/dist/server/auth/providers/shared.test.d.ts +1 -0
- package/dist/server/auth/providers/shared.test.js +10 -0
- package/dist/server/auth/providers/shared.test.js.map +1 -0
- package/dist/server/auth/providers/stytch.d.ts +12 -0
- package/dist/server/auth/providers/stytch.js +13 -0
- package/dist/server/auth/providers/stytch.js.map +1 -0
- package/dist/server/auth/providers/workos.d.ts +11 -0
- package/dist/server/auth/providers/workos.js +12 -0
- package/dist/server/auth/providers/workos.js.map +1 -0
- package/dist/server/auth/setup.d.ts +4 -0
- package/dist/server/auth/setup.js +51 -0
- package/dist/server/auth/setup.js.map +1 -0
- package/dist/server/auth/setup.test.d.ts +1 -0
- package/dist/server/auth/setup.test.js +185 -0
- package/dist/server/auth/setup.test.js.map +1 -0
- package/dist/server/auth/verify.d.ts +12 -0
- package/dist/server/auth/verify.js +38 -0
- package/dist/server/auth/verify.js.map +1 -0
- package/dist/server/auth/verify.test.d.ts +1 -0
- package/dist/server/auth/verify.test.js +100 -0
- package/dist/server/auth/verify.test.js.map +1 -0
- package/dist/server/build-manifest.test.d.ts +1 -0
- package/dist/server/build-manifest.test.js +27 -0
- package/dist/server/build-manifest.test.js.map +1 -0
- package/dist/server/express.js +3 -0
- package/dist/server/express.js.map +1 -1
- package/dist/server/express.test.js +61 -0
- package/dist/server/express.test.js.map +1 -1
- package/dist/server/index.d.ts +9 -2
- package/dist/server/index.js +7 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/requestOrigin.d.ts +7 -0
- package/dist/server/requestOrigin.js +25 -0
- package/dist/server/requestOrigin.js.map +1 -0
- package/dist/server/server.d.ts +56 -35
- package/dist/server/server.js +232 -136
- package/dist/server/server.js.map +1 -1
- package/dist/server/view-name.test-d.d.ts +1 -0
- package/dist/server/view-name.test-d.js +8 -0
- package/dist/server/view-name.test-d.js.map +1 -0
- package/dist/server/view-resource-resolution.test.d.ts +6 -0
- package/dist/server/view-resource-resolution.test.js +207 -0
- package/dist/server/view-resource-resolution.test.js.map +1 -0
- package/dist/test/view.test.js +69 -101
- package/dist/test/view.test.js.map +1 -1
- package/dist/web/bridges/adaptor.d.ts +51 -0
- package/dist/web/bridges/adaptor.js +330 -0
- package/dist/web/bridges/adaptor.js.map +1 -0
- package/dist/web/bridges/adaptor.test.d.ts +1 -0
- package/dist/web/bridges/adaptor.test.js +208 -0
- package/dist/web/bridges/adaptor.test.js.map +1 -0
- package/dist/web/bridges/apps-sdk/bridge.d.ts +6 -2
- package/dist/web/bridges/apps-sdk/bridge.js +15 -4
- package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
- package/dist/web/bridges/apps-sdk/index.d.ts +0 -1
- package/dist/web/bridges/apps-sdk/index.js +0 -1
- package/dist/web/bridges/apps-sdk/index.js.map +1 -1
- package/dist/web/bridges/get-adaptor.d.ts +4 -4
- package/dist/web/bridges/get-adaptor.js +6 -11
- package/dist/web/bridges/get-adaptor.js.map +1 -1
- package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
- package/dist/web/bridges/get-adaptor.test.js +32 -0
- package/dist/web/bridges/get-adaptor.test.js.map +1 -0
- package/dist/web/bridges/mcp-app/bridge.d.ts +15 -3
- package/dist/web/bridges/mcp-app/bridge.js +68 -5
- package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
- package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
- package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
- package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
- package/dist/web/bridges/mcp-app/index.d.ts +0 -1
- package/dist/web/bridges/mcp-app/index.js +0 -1
- package/dist/web/bridges/mcp-app/index.js.map +1 -1
- package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
- package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
- package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
- package/dist/web/bridges/types.d.ts +44 -1
- package/dist/web/bridges/types.js +14 -1
- package/dist/web/bridges/types.js.map +1 -1
- package/dist/web/bridges/types.test.d.ts +1 -0
- package/dist/web/bridges/types.test.js +19 -0
- package/dist/web/bridges/types.test.js.map +1 -0
- package/dist/web/components/modal-provider.d.ts +1 -1
- package/dist/web/components/modal-provider.js +4 -3
- package/dist/web/components/modal-provider.js.map +1 -1
- package/dist/web/create-store.test.js +8 -5
- package/dist/web/create-store.test.js.map +1 -1
- package/dist/web/data-llm.d.ts +1 -1
- package/dist/web/data-llm.test.js +17 -5
- package/dist/web/data-llm.test.js.map +1 -1
- package/dist/web/generate-helpers.test-d.js +4 -2
- package/dist/web/generate-helpers.test-d.js.map +1 -1
- package/dist/web/hooks/index.d.ts +1 -0
- package/dist/web/hooks/index.js +1 -0
- package/dist/web/hooks/index.js.map +1 -1
- package/dist/web/hooks/use-call-tool.test.js +37 -23
- package/dist/web/hooks/use-call-tool.test.js.map +1 -1
- package/dist/web/hooks/use-display-mode.test.js +56 -20
- package/dist/web/hooks/use-display-mode.test.js.map +1 -1
- package/dist/web/hooks/use-download.test.js +11 -3
- package/dist/web/hooks/use-download.test.js.map +1 -1
- package/dist/web/hooks/use-files.test.js +10 -2
- package/dist/web/hooks/use-files.test.js.map +1 -1
- package/dist/web/hooks/use-layout.test.js +59 -26
- package/dist/web/hooks/use-layout.test.js.map +1 -1
- package/dist/web/hooks/use-open-external.test.js +13 -3
- package/dist/web/hooks/use-open-external.test.js.map +1 -1
- package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
- package/dist/web/hooks/use-register-view-tool.js +50 -0
- package/dist/web/hooks/use-register-view-tool.js.map +1 -0
- package/dist/web/hooks/use-request-close.test.js +35 -40
- package/dist/web/hooks/use-request-close.test.js.map +1 -1
- package/dist/web/hooks/use-request-modal.test.js +10 -0
- package/dist/web/hooks/use-request-modal.test.js.map +1 -1
- package/dist/web/hooks/use-request-size.test.js +35 -53
- package/dist/web/hooks/use-request-size.test.js.map +1 -1
- package/dist/web/hooks/use-set-open-in-app-url.test.js +28 -8
- package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
- package/dist/web/hooks/use-tool-info.d.ts +25 -7
- package/dist/web/hooks/use-tool-info.js +5 -8
- package/dist/web/hooks/use-tool-info.js.map +1 -1
- package/dist/web/hooks/use-tool-info.test-d.js +11 -29
- package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
- package/dist/web/hooks/use-tool-info.test.js +42 -32
- package/dist/web/hooks/use-tool-info.test.js.map +1 -1
- package/dist/web/hooks/use-user.test.js +81 -35
- package/dist/web/hooks/use-user.test.js.map +1 -1
- package/dist/web/hooks/use-view-state.test.js +6 -2
- package/dist/web/hooks/use-view-state.test.js.map +1 -1
- package/dist/web/plugin/plugin.js +0 -1
- package/dist/web/plugin/plugin.js.map +1 -1
- package/package.json +22 -19
- package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -28
- package/dist/web/bridges/apps-sdk/adaptor.js +0 -113
- package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
- package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -52
- package/dist/web/bridges/mcp-app/adaptor.js +0 -280
- package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
package/dist/commands/build.js
CHANGED
|
@@ -1,86 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
2
|
import { Command } from "@oclif/core";
|
|
5
3
|
import { Box, render, Text } from "ink";
|
|
6
4
|
import { useEffect } from "react";
|
|
5
|
+
import { getCommandSteps } from "../cli/build-steps.js";
|
|
7
6
|
import { Header } from "../cli/header.js";
|
|
8
7
|
import { useExecuteSteps } from "../cli/use-execute-steps.js";
|
|
9
|
-
import { scanAndWriteViewsDts } from "../web/plugin/scan-views.js";
|
|
10
|
-
async function resolveViewsDir(root) {
|
|
11
|
-
const { loadConfigFromFile } = await import("vite");
|
|
12
|
-
const loaded = await loadConfigFromFile({ command: "build", mode: "production" }, undefined, root);
|
|
13
|
-
const isPluginCandidate = (value) => typeof value === "object" && value !== null;
|
|
14
|
-
const plugins = [];
|
|
15
|
-
const walk = (value) => {
|
|
16
|
-
if (Array.isArray(value)) {
|
|
17
|
-
value.forEach(walk);
|
|
18
|
-
}
|
|
19
|
-
else if (isPluginCandidate(value)) {
|
|
20
|
-
plugins.push(value);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
walk(loaded?.config.plugins ?? []);
|
|
24
|
-
return plugins.find((p) => p.name === "skybridge")?.api?.viewsDir;
|
|
25
|
-
}
|
|
26
|
-
export const commandSteps = [
|
|
27
|
-
{
|
|
28
|
-
label: "Scanning views",
|
|
29
|
-
run: async () => {
|
|
30
|
-
const root = process.cwd();
|
|
31
|
-
const viewsDir = await resolveViewsDir(root);
|
|
32
|
-
scanAndWriteViewsDts(root, viewsDir);
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
label: "Compiling server",
|
|
37
|
-
run: () => rmSync("dist", { recursive: true, force: true }),
|
|
38
|
-
command: "tsc -b --force",
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
label: "Building views",
|
|
42
|
-
command: "vite build",
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
label: "Emitting manifest module",
|
|
46
|
-
// Inline the Vite manifest as a JS module so the server can `import` it
|
|
47
|
-
// instead of `readFileSync(process.cwd() + ...)` at runtime — required for
|
|
48
|
-
// workerd, where neither cwd nor the assets directory is readable.
|
|
49
|
-
// The path mirrors `skybridge start`'s entry convention (dist/server.js)
|
|
50
|
-
// so the import in the user's entry resolves to a sibling file.
|
|
51
|
-
run: () => {
|
|
52
|
-
const root = process.cwd();
|
|
53
|
-
const manifest = readFileSync(path.join(root, "dist", "assets", ".vite", "manifest.json"), "utf-8");
|
|
54
|
-
writeFileSync(path.join(root, "dist", "vite-manifest.js"), `export default ${manifest};\n`);
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
label: "Emitting Cloudflare redirects",
|
|
59
|
-
// Cloudflare's `assets.directory` maps URL → file literally — no
|
|
60
|
-
// mount-strip like `app.use("/assets", express.static(...))`. Rewrite
|
|
61
|
-
// `/assets/assets/*` to `/assets/*` before lookup; status 200 =
|
|
62
|
-
// server-side rewrite, not HTTP redirect.
|
|
63
|
-
run: () => {
|
|
64
|
-
const root = process.cwd();
|
|
65
|
-
writeFileSync(path.join(root, "dist", "assets", "_redirects"), "/assets/assets/* /assets/:splat 200\n");
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
label: "Emitting Cloudflare headers",
|
|
70
|
-
// Cloudflare's static asset handler bypasses the worker entirely, so
|
|
71
|
-
// `app.use("/assets", cors())` never fires for asset requests. Attach
|
|
72
|
-
// CORS at the edge so cross-origin view iframes can load JS/CSS.
|
|
73
|
-
run: () => {
|
|
74
|
-
const root = process.cwd();
|
|
75
|
-
writeFileSync(path.join(root, "dist", "assets", "_headers"), "/assets/*\n Access-Control-Allow-Origin: *\n");
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
];
|
|
79
8
|
export default class Build extends Command {
|
|
80
9
|
static description = "Build the views and MCP server";
|
|
81
10
|
static examples = ["skybridge build"];
|
|
82
|
-
static flags = {};
|
|
83
11
|
async run() {
|
|
12
|
+
const commandSteps = await getCommandSteps().catch((e) => this.error(e instanceof Error ? e.message : String(e)));
|
|
84
13
|
const App = () => {
|
|
85
14
|
const { currentStep, status, error, execute } = useExecuteSteps(commandSteps);
|
|
86
15
|
useEffect(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/commands/build.tsx"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { Command } from \"@oclif/core\";\nimport { Box, render, Text } from \"ink\";\nimport { useEffect } from \"react\";\nimport { Header } from \"../cli/header.js\";\nimport { type CommandStep, useExecuteSteps } from \"../cli/use-execute-steps.js\";\nimport { scanAndWriteViewsDts } from \"../web/plugin/scan-views.js\";\n\nasync function resolveViewsDir(root: string): Promise<string | undefined> {\n const { loadConfigFromFile } = await import(\"vite\");\n const loaded = await loadConfigFromFile(\n { command: \"build\", mode: \"production\" },\n undefined,\n root,\n );\n\n const isPluginCandidate = (\n value: unknown,\n ): value is { name?: string; api?: { viewsDir?: string } } =>\n typeof value === \"object\" && value !== null;\n\n const plugins: Array<{ name?: string; api?: { viewsDir?: string } }> = [];\n const walk = (value: unknown) => {\n if (Array.isArray(value)) {\n value.forEach(walk);\n } else if (isPluginCandidate(value)) {\n plugins.push(value);\n }\n };\n walk(loaded?.config.plugins ?? []);\n return plugins.find((p) => p.name === \"skybridge\")?.api?.viewsDir;\n}\n\nexport const commandSteps: CommandStep[] = [\n {\n label: \"Scanning views\",\n run: async () => {\n const root = process.cwd();\n const viewsDir = await resolveViewsDir(root);\n scanAndWriteViewsDts(root, viewsDir);\n },\n },\n {\n label: \"Compiling server\",\n run: () => rmSync(\"dist\", { recursive: true, force: true }),\n command: \"tsc -b --force\",\n },\n {\n label: \"Building views\",\n command: \"vite build\",\n },\n {\n label: \"Emitting manifest module\",\n // Inline the Vite manifest as a JS module so the server can `import` it\n // instead of `readFileSync(process.cwd() + ...)` at runtime — required for\n // workerd, where neither cwd nor the assets directory is readable.\n // The path mirrors `skybridge start`'s entry convention (dist/server.js)\n // so the import in the user's entry resolves to a sibling file.\n run: () => {\n const root = process.cwd();\n const manifest = readFileSync(\n path.join(root, \"dist\", \"assets\", \".vite\", \"manifest.json\"),\n \"utf-8\",\n );\n writeFileSync(\n path.join(root, \"dist\", \"vite-manifest.js\"),\n `export default ${manifest};\\n`,\n );\n },\n },\n\n {\n label: \"Emitting Cloudflare redirects\",\n // Cloudflare's `assets.directory` maps URL → file literally — no\n // mount-strip like `app.use(\"/assets\", express.static(...))`. Rewrite\n // `/assets/assets/*` to `/assets/*` before lookup; status 200 =\n // server-side rewrite, not HTTP redirect.\n run: () => {\n const root = process.cwd();\n writeFileSync(\n path.join(root, \"dist\", \"assets\", \"_redirects\"),\n \"/assets/assets/* /assets/:splat 200\\n\",\n );\n },\n },\n {\n label: \"Emitting Cloudflare headers\",\n // Cloudflare's static asset handler bypasses the worker entirely, so\n // `app.use(\"/assets\", cors())` never fires for asset requests. Attach\n // CORS at the edge so cross-origin view iframes can load JS/CSS.\n run: () => {\n const root = process.cwd();\n writeFileSync(\n path.join(root, \"dist\", \"assets\", \"_headers\"),\n \"/assets/*\\n Access-Control-Allow-Origin: *\\n\",\n );\n },\n },\n];\n\nexport default class Build extends Command {\n static override description = \"Build the views and MCP server\";\n static override examples = [\"skybridge build\"];\n static override flags = {};\n\n public async run(): Promise<void> {\n const App = () => {\n const { currentStep, status, error, execute } =\n useExecuteSteps(commandSteps);\n\n useEffect(() => {\n execute();\n }, [execute]);\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Header version={this.config.version}>\n <Text color=\"green\"> → building for production…</Text>\n </Header>\n\n {commandSteps.map((step, index) => {\n const isCurrent = index === currentStep && status === \"running\";\n const isCompleted = index < currentStep || status === \"success\";\n const isError = status === \"error\" && index === currentStep;\n\n return (\n <Box key={step.label} marginBottom={0}>\n <Text color={isError ? \"red\" : isCompleted ? \"green\" : \"grey\"}>\n {isError ? \"✗\" : isCompleted ? \"✓\" : isCurrent ? \"⟳\" : \"○\"}{\" \"}\n {step.label}\n </Text>\n </Box>\n );\n })}\n\n {status === \"success\" && (\n <Box marginTop={1}>\n <Text color=\"green\" bold>\n ✓ Build completed successfully!\n </Text>\n </Box>\n )}\n\n {status === \"error\" && error && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"red\" bold>\n ✗ Build failed\n </Text>\n <Box marginTop={1} flexDirection=\"column\">\n {error.split(\"\\n\").map((line) => (\n <Text key={line} color=\"red\">\n {line}\n </Text>\n ))}\n </Box>\n </Box>\n )}\n </Box>\n );\n };\n\n render(<App />, {\n exitOnCtrlC: true,\n patchConsole: false,\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/commands/build.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Command } from \"@oclif/core\";\nimport { Box, render, Text } from \"ink\";\nimport { useEffect } from \"react\";\nimport { getCommandSteps } from \"../cli/build-steps.js\";\nimport { Header } from \"../cli/header.js\";\nimport { useExecuteSteps } from \"../cli/use-execute-steps.js\";\n\nexport default class Build extends Command {\n static override description = \"Build the views and MCP server\";\n static override examples = [\"skybridge build\"];\n\n public async run(): Promise<void> {\n const commandSteps = await getCommandSteps().catch((e: unknown) =>\n this.error(e instanceof Error ? e.message : String(e)),\n );\n\n const App = () => {\n const { currentStep, status, error, execute } =\n useExecuteSteps(commandSteps);\n\n useEffect(() => {\n execute();\n }, [execute]);\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Header version={this.config.version}>\n <Text color=\"green\"> → building for production…</Text>\n </Header>\n\n {commandSteps.map((step, index) => {\n const isCurrent = index === currentStep && status === \"running\";\n const isCompleted = index < currentStep || status === \"success\";\n const isError = status === \"error\" && index === currentStep;\n\n return (\n <Box key={step.label} marginBottom={0}>\n <Text color={isError ? \"red\" : isCompleted ? \"green\" : \"grey\"}>\n {isError ? \"✗\" : isCompleted ? \"✓\" : isCurrent ? \"⟳\" : \"○\"}{\" \"}\n {step.label}\n </Text>\n </Box>\n );\n })}\n\n {status === \"success\" && (\n <Box marginTop={1}>\n <Text color=\"green\" bold>\n ✓ Build completed successfully!\n </Text>\n </Box>\n )}\n\n {status === \"error\" && error && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"red\" bold>\n ✗ Build failed\n </Text>\n <Box marginTop={1} flexDirection=\"column\">\n {error.split(\"\\n\").map((line) => (\n <Text key={line} color=\"red\">\n {line}\n </Text>\n ))}\n </Box>\n </Box>\n )}\n </Box>\n );\n };\n\n render(<App />, {\n exitOnCtrlC: true,\n patchConsole: false,\n });\n }\n}\n"]}
|
package/dist/commands/dev.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export default class Dev extends Command {
|
|
|
7
7
|
tunnel: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
8
|
open: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
9
|
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
plain: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
11
|
};
|
|
11
12
|
run(): Promise<void>;
|
|
12
13
|
}
|
package/dist/commands/dev.js
CHANGED
|
@@ -3,12 +3,16 @@ import { Command, Flags } from "@oclif/core";
|
|
|
3
3
|
import { Box, render, Text } from "ink";
|
|
4
4
|
import { resolvePort } from "../cli/detect-port.js";
|
|
5
5
|
import { Header } from "../cli/header.js";
|
|
6
|
+
import { resolveViewsDir } from "../cli/resolve-views-dir.js";
|
|
7
|
+
import { runPlain } from "../cli/run-plain.js";
|
|
8
|
+
import { startTunnelViewBuild } from "../cli/start-tunnel-view-build.js";
|
|
6
9
|
import { startTunnelControlServer } from "../cli/tunnel-control-server.js";
|
|
7
10
|
import { useMessages } from "../cli/use-messages.js";
|
|
8
11
|
import { useNodemon } from "../cli/use-nodemon.js";
|
|
9
12
|
import { useOpenBrowser } from "../cli/use-open-browser.js";
|
|
10
13
|
import { useTunnel } from "../cli/use-tunnel.js";
|
|
11
14
|
import { useTypeScriptCheck } from "../cli/use-typescript-check.js";
|
|
15
|
+
import { scanAndWriteViewsDts } from "../web/plugin/scan-views.js";
|
|
12
16
|
export default class Dev extends Command {
|
|
13
17
|
static description = "Start development server";
|
|
14
18
|
static examples = ["skybridge"];
|
|
@@ -32,9 +36,27 @@ export default class Dev extends Command {
|
|
|
32
36
|
description: "Show tunnel logs",
|
|
33
37
|
default: false,
|
|
34
38
|
}),
|
|
39
|
+
plain: Flags.boolean({
|
|
40
|
+
description: "Disable the interactive UI and stream raw server logs to stdout, so you can pipe them through a formatter (e.g. `skybridge dev --plain | bunyan`).",
|
|
41
|
+
default: false,
|
|
42
|
+
}),
|
|
35
43
|
};
|
|
36
44
|
async run() {
|
|
37
45
|
const { flags } = await this.parse(Dev);
|
|
46
|
+
// Generate .skybridge/views.d.ts before render() spawns `tsc --noEmit
|
|
47
|
+
// --watch`. Vite's plugin config hook writes the same file when nodemon
|
|
48
|
+
// boots the server, but tsc starts in parallel — if .skybridge/ doesn't
|
|
49
|
+
// exist at tsc startup, its watcher never picks up the late-created file
|
|
50
|
+
// and the dev UI reports phantom TS errors forever.
|
|
51
|
+
const root = process.cwd();
|
|
52
|
+
try {
|
|
53
|
+
scanAndWriteViewsDts(root, await resolveViewsDir(root));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Best-effort: if the scan fails (e.g. broken vite config, duplicate
|
|
57
|
+
// view names) tsc may show phantom errors, but the dev server should
|
|
58
|
+
// still start so the developer can fix the underlying issue.
|
|
59
|
+
}
|
|
38
60
|
const { port, fallback, envWarning } = await resolvePort(flags.port);
|
|
39
61
|
if (envWarning) {
|
|
40
62
|
this.warn(envWarning);
|
|
@@ -45,6 +67,41 @@ export default class Dev extends Command {
|
|
|
45
67
|
__PORT: String(port),
|
|
46
68
|
__TUNNEL_CONTROL_PORT: String(controlPort),
|
|
47
69
|
};
|
|
70
|
+
let viewBuildStarted = false;
|
|
71
|
+
tunnelManager.subscribe((state) => {
|
|
72
|
+
if (viewBuildStarted || state.status === "idle") {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
viewBuildStarted = true;
|
|
76
|
+
startTunnelViewBuild(root);
|
|
77
|
+
});
|
|
78
|
+
if (flags.plain) {
|
|
79
|
+
const teardown = runPlain({
|
|
80
|
+
env,
|
|
81
|
+
port,
|
|
82
|
+
fallback,
|
|
83
|
+
version: this.config.version,
|
|
84
|
+
tunnel: flags.tunnel,
|
|
85
|
+
tunnelManager,
|
|
86
|
+
});
|
|
87
|
+
// Synchronous-first shutdown: kill the alpic subprocess up front so we
|
|
88
|
+
// can't leave it orphaned even if another SIGINT listener (e.g.
|
|
89
|
+
// nodemon's) exits the process before our async cleanup completes.
|
|
90
|
+
const shutdown = (code) => () => {
|
|
91
|
+
tunnelManager.stop();
|
|
92
|
+
teardown();
|
|
93
|
+
void closeTunnelControl()
|
|
94
|
+
.catch((err) => {
|
|
95
|
+
console.error("Failed to close tunnel control server", err);
|
|
96
|
+
})
|
|
97
|
+
.finally(() => {
|
|
98
|
+
process.exit(code);
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
process.once("SIGINT", shutdown(130));
|
|
102
|
+
process.once("SIGTERM", shutdown(143));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
48
105
|
const App = () => {
|
|
49
106
|
const tsErrors = useTypeScriptCheck();
|
|
50
107
|
const [messages, pushMessage] = useMessages();
|
package/dist/commands/dev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Command, Flags } from \"@oclif/core\";\nimport { Box, render, Text } from \"ink\";\nimport { resolvePort } from \"../cli/detect-port.js\";\nimport { Header } from \"../cli/header.js\";\nimport { startTunnelControlServer } from \"../cli/tunnel-control-server.js\";\nimport { useMessages } from \"../cli/use-messages.js\";\nimport { useNodemon } from \"../cli/use-nodemon.js\";\nimport { useOpenBrowser } from \"../cli/use-open-browser.js\";\nimport { useTunnel } from \"../cli/use-tunnel.js\";\nimport { useTypeScriptCheck } from \"../cli/use-typescript-check.js\";\n\nexport default class Dev extends Command {\n static override description = \"Start development server\";\n static override examples = [\"skybridge\"];\n static override flags = {\n port: Flags.integer({\n char: \"p\",\n description: \"Port to run the server on\",\n min: 1,\n }),\n tunnel: Flags.boolean({\n description: \"Open an Alpic tunnel for remote testing\",\n default: false,\n }),\n open: Flags.boolean({\n description: \"Open DevTools in the browser when the server is ready\",\n default: process.env.SKYBRIDGE_OPEN !== \"false\",\n allowNo: true,\n }),\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Show tunnel logs\",\n default: false,\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(Dev);\n\n const { port, fallback, envWarning } = await resolvePort(flags.port);\n if (envWarning) {\n this.warn(envWarning);\n }\n\n const {\n port: controlPort,\n manager: tunnelManager,\n close: closeTunnelControl,\n } = await startTunnelControlServer(() => port);\n\n const env = {\n ...process.env,\n __PORT: String(port),\n __TUNNEL_CONTROL_PORT: String(controlPort),\n };\n\n const App = () => {\n const tsErrors = useTypeScriptCheck();\n const [messages, pushMessage] = useMessages();\n useNodemon(env, pushMessage);\n useOpenBrowser(port, flags.open);\n const tunnelState = useTunnel(\n port,\n pushMessage,\n flags.verbose,\n flags.tunnel,\n );\n\n return (\n <Box flexDirection=\"column\" padding={1} marginLeft={1}>\n <Header version={this.config.version} />\n\n <Box>\n <Text>🏠{\" \"}</Text>\n {fallback ? (\n <Text color=\"yellow\">3000 in use, running on </Text>\n ) : (\n <Text>Running on </Text>\n )}\n <Text color=\"green\">{`http://localhost:${port}/mcp`}</Text>\n </Box>\n <Box marginBottom={1}>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test locally with DevTools:{\" \"}\n </Text>\n <Text color=\"green\">{`http://localhost:${port}/`}</Text>\n </Box>\n\n {tunnelState.status === \"idle\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Get a public URL and LLM Playground access with </Text>\n <Text color=\"cyan\" bold>\n --tunnel\n </Text>\n <Text>.</Text>\n </Box>\n )}\n {tunnelState.status === \"starting\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"yellow\">{tunnelState.message}</Text>\n </Box>\n )}\n {tunnelState.status === \"connected\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Exposed on </Text>\n <Text color=\"green\">{`${tunnelState.url}/mcp`}</Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test with an LLM on Playground:{\" \"}\n </Text>\n <Text color=\"green\">{`${tunnelState.url}/try`}</Text>\n </Box>\n </Box>\n )}\n {tunnelState.status === \"error\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"red\">\n Cannot open tunnel: {tunnelState.message}\n </Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"red\">{`Try manually: npx alpic tunnel --port ${port}`}</Text>\n </Box>\n </Box>\n )}\n\n <Box>\n <Text>🛟{\" \"}</Text>\n <Text>Need help? Reach us on </Text>\n <Text color=\"white\" underline>\n https://discord.alpic.ai\n </Text>\n </Box>\n\n {tsErrors.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"red\" bold>\n ⚠️ TypeScript errors found:\n </Text>\n {tsErrors.map((error) => (\n <Box\n key={`${error.file}:${error.line}:${error.col}`}\n marginLeft={2}\n flexDirection=\"column\"\n >\n <Box>\n <Text color=\"white\">{error.file}</Text>\n <Text color=\"grey\">\n ({error.line},{error.col}):{\" \"}\n </Text>\n </Box>\n <Box marginLeft={2}>\n <Text color=\"red\">{error.message}</Text>\n </Box>\n </Box>\n ))}\n </Box>\n )}\n {messages.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"white\" bold>\n Logs:\n </Text>\n {messages.map((message) => (\n <Box key={message.id} marginLeft={2}>\n {message.type === \"restart\" ? (\n <>\n <Text color=\"green\">✓{\" \"}</Text>\n <Text color=\"white\">{message.text}</Text>\n </>\n ) : message.type === \"error\" ? (\n <Text color=\"red\">{message.text}</Text>\n ) : (\n <Text>{message.text}</Text>\n )}\n </Box>\n ))}\n </Box>\n )}\n </Box>\n );\n };\n\n // Note: `exitOnCtrlC: false` because we own SIGINT below to guarantee\n // alpic gets killed before we exit. If anything ever calls `useInput` or\n // puts stdin into raw mode, also wire an explicit `\\x03` keypress to the\n // shutdown function — Ink will otherwise swallow Ctrl-C without ever\n // delivering SIGINT.\n const ink = render(<App />, { exitOnCtrlC: false, patchConsole: true });\n\n // Synchronous-first shutdown: kill the alpic subprocess up front so we\n // can't leave it orphaned even if another SIGINT listener (e.g. nodemon's)\n // exits the process before our async cleanup completes.\n const shutdown = (code: number) => () => {\n tunnelManager.stop();\n void closeTunnelControl()\n .catch((err) => {\n console.error(\"Failed to close tunnel control server\", err);\n })\n .finally(() => {\n ink.unmount();\n process.exit(code);\n });\n };\n process.once(\"SIGINT\", shutdown(130));\n process.once(\"SIGTERM\", shutdown(143));\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Command, Flags } from \"@oclif/core\";\nimport { Box, render, Text } from \"ink\";\nimport { resolvePort } from \"../cli/detect-port.js\";\nimport { Header } from \"../cli/header.js\";\nimport { resolveViewsDir } from \"../cli/resolve-views-dir.js\";\nimport { runPlain } from \"../cli/run-plain.js\";\nimport { startTunnelViewBuild } from \"../cli/start-tunnel-view-build.js\";\nimport { startTunnelControlServer } from \"../cli/tunnel-control-server.js\";\nimport { useMessages } from \"../cli/use-messages.js\";\nimport { useNodemon } from \"../cli/use-nodemon.js\";\nimport { useOpenBrowser } from \"../cli/use-open-browser.js\";\nimport { useTunnel } from \"../cli/use-tunnel.js\";\nimport { useTypeScriptCheck } from \"../cli/use-typescript-check.js\";\nimport { scanAndWriteViewsDts } from \"../web/plugin/scan-views.js\";\n\nexport default class Dev extends Command {\n static override description = \"Start development server\";\n static override examples = [\"skybridge\"];\n static override flags = {\n port: Flags.integer({\n char: \"p\",\n description: \"Port to run the server on\",\n min: 1,\n }),\n tunnel: Flags.boolean({\n description: \"Open an Alpic tunnel for remote testing\",\n default: false,\n }),\n open: Flags.boolean({\n description: \"Open DevTools in the browser when the server is ready\",\n default: process.env.SKYBRIDGE_OPEN !== \"false\",\n allowNo: true,\n }),\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Show tunnel logs\",\n default: false,\n }),\n plain: Flags.boolean({\n description:\n \"Disable the interactive UI and stream raw server logs to stdout, so you can pipe them through a formatter (e.g. `skybridge dev --plain | bunyan`).\",\n default: false,\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(Dev);\n\n // Generate .skybridge/views.d.ts before render() spawns `tsc --noEmit\n // --watch`. Vite's plugin config hook writes the same file when nodemon\n // boots the server, but tsc starts in parallel — if .skybridge/ doesn't\n // exist at tsc startup, its watcher never picks up the late-created file\n // and the dev UI reports phantom TS errors forever.\n const root = process.cwd();\n try {\n scanAndWriteViewsDts(root, await resolveViewsDir(root));\n } catch {\n // Best-effort: if the scan fails (e.g. broken vite config, duplicate\n // view names) tsc may show phantom errors, but the dev server should\n // still start so the developer can fix the underlying issue.\n }\n\n const { port, fallback, envWarning } = await resolvePort(flags.port);\n if (envWarning) {\n this.warn(envWarning);\n }\n\n const {\n port: controlPort,\n manager: tunnelManager,\n close: closeTunnelControl,\n } = await startTunnelControlServer(() => port);\n\n const env = {\n ...process.env,\n __PORT: String(port),\n __TUNNEL_CONTROL_PORT: String(controlPort),\n };\n\n let viewBuildStarted = false;\n tunnelManager.subscribe((state) => {\n if (viewBuildStarted || state.status === \"idle\") {\n return;\n }\n viewBuildStarted = true;\n startTunnelViewBuild(root);\n });\n\n if (flags.plain) {\n const teardown = runPlain({\n env,\n port,\n fallback,\n version: this.config.version,\n tunnel: flags.tunnel,\n tunnelManager,\n });\n\n // Synchronous-first shutdown: kill the alpic subprocess up front so we\n // can't leave it orphaned even if another SIGINT listener (e.g.\n // nodemon's) exits the process before our async cleanup completes.\n const shutdown = (code: number) => () => {\n tunnelManager.stop();\n teardown();\n void closeTunnelControl()\n .catch((err) => {\n console.error(\"Failed to close tunnel control server\", err);\n })\n .finally(() => {\n process.exit(code);\n });\n };\n process.once(\"SIGINT\", shutdown(130));\n process.once(\"SIGTERM\", shutdown(143));\n return;\n }\n\n const App = () => {\n const tsErrors = useTypeScriptCheck();\n const [messages, pushMessage] = useMessages();\n useNodemon(env, pushMessage);\n useOpenBrowser(port, flags.open);\n const tunnelState = useTunnel(\n port,\n pushMessage,\n flags.verbose,\n flags.tunnel,\n );\n\n return (\n <Box flexDirection=\"column\" padding={1} marginLeft={1}>\n <Header version={this.config.version} />\n\n <Box>\n <Text>🏠{\" \"}</Text>\n {fallback ? (\n <Text color=\"yellow\">3000 in use, running on </Text>\n ) : (\n <Text>Running on </Text>\n )}\n <Text color=\"green\">{`http://localhost:${port}/mcp`}</Text>\n </Box>\n <Box marginBottom={1}>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test locally with DevTools:{\" \"}\n </Text>\n <Text color=\"green\">{`http://localhost:${port}/`}</Text>\n </Box>\n\n {tunnelState.status === \"idle\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Get a public URL and LLM Playground access with </Text>\n <Text color=\"cyan\" bold>\n --tunnel\n </Text>\n <Text>.</Text>\n </Box>\n )}\n {tunnelState.status === \"starting\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"yellow\">{tunnelState.message}</Text>\n </Box>\n )}\n {tunnelState.status === \"connected\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Exposed on </Text>\n <Text color=\"green\">{`${tunnelState.url}/mcp`}</Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test with an LLM on Playground:{\" \"}\n </Text>\n <Text color=\"green\">{`${tunnelState.url}/try`}</Text>\n </Box>\n </Box>\n )}\n {tunnelState.status === \"error\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"red\">\n Cannot open tunnel: {tunnelState.message}\n </Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"red\">{`Try manually: npx alpic tunnel --port ${port}`}</Text>\n </Box>\n </Box>\n )}\n\n <Box>\n <Text>🛟{\" \"}</Text>\n <Text>Need help? Reach us on </Text>\n <Text color=\"white\" underline>\n https://discord.alpic.ai\n </Text>\n </Box>\n\n {tsErrors.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"red\" bold>\n ⚠️ TypeScript errors found:\n </Text>\n {tsErrors.map((error) => (\n <Box\n key={`${error.file}:${error.line}:${error.col}`}\n marginLeft={2}\n flexDirection=\"column\"\n >\n <Box>\n <Text color=\"white\">{error.file}</Text>\n <Text color=\"grey\">\n ({error.line},{error.col}):{\" \"}\n </Text>\n </Box>\n <Box marginLeft={2}>\n <Text color=\"red\">{error.message}</Text>\n </Box>\n </Box>\n ))}\n </Box>\n )}\n {messages.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"white\" bold>\n Logs:\n </Text>\n {messages.map((message) => (\n <Box key={message.id} marginLeft={2}>\n {message.type === \"restart\" ? (\n <>\n <Text color=\"green\">✓{\" \"}</Text>\n <Text color=\"white\">{message.text}</Text>\n </>\n ) : message.type === \"error\" ? (\n <Text color=\"red\">{message.text}</Text>\n ) : (\n <Text>{message.text}</Text>\n )}\n </Box>\n ))}\n </Box>\n )}\n </Box>\n );\n };\n\n // Note: `exitOnCtrlC: false` because we own SIGINT below to guarantee\n // alpic gets killed before we exit. If anything ever calls `useInput` or\n // puts stdin into raw mode, also wire an explicit `\\x03` keypress to the\n // shutdown function — Ink will otherwise swallow Ctrl-C without ever\n // delivering SIGINT.\n const ink = render(<App />, { exitOnCtrlC: false, patchConsole: true });\n\n // Synchronous-first shutdown: kill the alpic subprocess up front so we\n // can't leave it orphaned even if another SIGINT listener (e.g. nodemon's)\n // exits the process before our async cleanup completes.\n const shutdown = (code: number) => () => {\n tunnelManager.stop();\n void closeTunnelControl()\n .catch((err) => {\n console.error(\"Failed to close tunnel control server\", err);\n })\n .finally(() => {\n ink.unmount();\n process.exit(code);\n });\n };\n process.once(\"SIGINT\", shutdown(130));\n process.once(\"SIGTERM\", shutdown(143));\n }\n}\n"]}
|
package/dist/commands/start.js
CHANGED
|
@@ -20,7 +20,13 @@ export default class Start extends Command {
|
|
|
20
20
|
this.warn(envWarning);
|
|
21
21
|
}
|
|
22
22
|
console.clear();
|
|
23
|
-
|
|
23
|
+
// `dist/server.js` is the natural entry (the user's `await server.run()`
|
|
24
|
+
// binds the port). Prefer `dist/__entry.js` when present because it
|
|
25
|
+
// primes the Vite manifest first — without it, hashed asset URLs in
|
|
26
|
+
// views won't resolve.
|
|
27
|
+
const entryPath = resolve(process.cwd(), "dist/__entry.js");
|
|
28
|
+
const fallbackPath = resolve(process.cwd(), "dist/server.js");
|
|
29
|
+
const indexPath = existsSync(entryPath) ? entryPath : fallbackPath;
|
|
24
30
|
if (!existsSync(indexPath)) {
|
|
25
31
|
console.error("❌ Error: No build output found");
|
|
26
32
|
console.error("");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,MAAM,CAAC,OAAO,OAAO,KAAM,SAAQ,OAAO;IACxC,MAAM,CAAU,WAAW,GAAG,yBAAyB,CAAC;IACxD,MAAM,CAAU,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC/C,MAAM,CAAU,KAAK,GAAG;QACtB,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;YAClB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,2BAA2B;YACxC,GAAG,EAAE,CAAC;SACP,CAAC;KACH,CAAC;IAEK,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrE,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxB,CAAC;QAED,OAAO,CAAC,KAAK,EAAE,CAAC;QAEhB,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,gBAAgB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,MAAM,CAAC,OAAO,OAAO,KAAM,SAAQ,OAAO;IACxC,MAAM,CAAU,WAAW,GAAG,yBAAyB,CAAC;IACxD,MAAM,CAAU,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC/C,MAAM,CAAU,KAAK,GAAG;QACtB,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;YAClB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,2BAA2B;YACxC,GAAG,EAAE,CAAC;SACP,CAAC;KACH,CAAC;IAEK,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrE,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxB,CAAC;QAED,OAAO,CAAC,KAAK,EAAE,CAAC;QAEhB,yEAAyE;QACzE,oEAAoE;QACpE,oEAAoE;QACpE,uBAAuB;QACvB,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,iBAAiB,CAAC,CAAC;QAC5D,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,gBAAgB,CAAC,CAAC;QAC9D,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC;QAEnE,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;YAChD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;YAClD,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;YACnC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,GAAG,CACT,8CAA8C,IAAI,CAAC,MAAM,CAAC,OAAO,SAAS,CAC3E,CAAC;QACF,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CACT,mEAAmE,IAAI,aAAa,CACrF,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,uCAAuC,IAAI,aAAa,CAAC,CAAC;QACxE,CAAC;QAED,MAAM,UAAU,CAAC,QAAQ,SAAS,EAAE,EAAE;YACpC,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC;YACvC,GAAG,EAAE;gBACH,GAAG,OAAO,CAAC,GAAG;gBACd,QAAQ,EAAE,YAAY;gBACtB,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC;aACrB;SACF,CAAC,CAAC;IACL,CAAC","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { Command, Flags } from \"@oclif/core\";\nimport { resolvePort } from \"../cli/detect-port.js\";\nimport { runCommand } from \"../cli/run-command.js\";\n\nexport default class Start extends Command {\n static override description = \"Start production server\";\n static override examples = [\"skybridge start\"];\n static override flags = {\n port: Flags.integer({\n char: \"p\",\n description: \"Port to run the server on\",\n min: 1,\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(Start);\n const { port, fallback, envWarning } = await resolvePort(flags.port);\n if (envWarning) {\n this.warn(envWarning);\n }\n\n console.clear();\n\n // `dist/server.js` is the natural entry (the user's `await server.run()`\n // binds the port). Prefer `dist/__entry.js` when present because it\n // primes the Vite manifest first — without it, hashed asset URLs in\n // views won't resolve.\n const entryPath = resolve(process.cwd(), \"dist/__entry.js\");\n const fallbackPath = resolve(process.cwd(), \"dist/server.js\");\n const indexPath = existsSync(entryPath) ? entryPath : fallbackPath;\n\n if (!existsSync(indexPath)) {\n console.error(\"❌ Error: No build output found\");\n console.error(\"\");\n console.error(\"Please build your project first:\");\n console.error(\" skybridge build\");\n console.error(\"\");\n process.exit(1);\n }\n\n console.log(\n `\\x1b[36m\\x1b[1m⛰ Skybridge\\x1b[0m \\x1b[36mv${this.config.version}\\x1b[0m`,\n );\n if (fallback) {\n console.log(\n `\\x1b[33m3000 in use, running on\\x1b[0m \\x1b[32mhttp://localhost:${port}/mcp\\x1b[0m`,\n );\n } else {\n console.log(`Running on \\x1b[32mhttp://localhost:${port}/mcp\\x1b[0m`);\n }\n\n await runCommand(`node ${indexPath}`, {\n stdio: [\"ignore\", \"inherit\", \"inherit\"],\n env: {\n ...process.env,\n NODE_ENV: \"production\",\n __PORT: String(port),\n },\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Discovery doc validated as OAuth AS metadata + `jwks_uri`. The SDK's
|
|
4
|
+
* `OAuthMetadataSchema` omits `jwks_uri` (its client never verifies tokens), but
|
|
5
|
+
* we need it for JWKS token verification, so we extend the schema to keep it.
|
|
6
|
+
*/
|
|
7
|
+
declare const DiscoverySchema: z.ZodObject<{
|
|
8
|
+
issuer: z.ZodString;
|
|
9
|
+
authorization_endpoint: z.ZodURL;
|
|
10
|
+
token_endpoint: z.ZodURL;
|
|
11
|
+
registration_endpoint: z.ZodOptional<z.ZodURL>;
|
|
12
|
+
scopes_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
13
|
+
response_types_supported: z.ZodArray<z.ZodString>;
|
|
14
|
+
response_modes_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
15
|
+
grant_types_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
16
|
+
token_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
17
|
+
token_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
18
|
+
service_documentation: z.ZodOptional<z.ZodURL>;
|
|
19
|
+
revocation_endpoint: z.ZodOptional<z.ZodURL>;
|
|
20
|
+
revocation_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
21
|
+
revocation_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
22
|
+
introspection_endpoint: z.ZodOptional<z.ZodString>;
|
|
23
|
+
introspection_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
24
|
+
introspection_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
25
|
+
code_challenge_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
26
|
+
client_id_metadata_document_supported: z.ZodOptional<z.ZodBoolean>;
|
|
27
|
+
jwks_uri: z.ZodOptional<z.ZodString>;
|
|
28
|
+
}, z.core.$loose>;
|
|
29
|
+
export type DiscoveredMetadata = z.infer<typeof DiscoverySchema>;
|
|
30
|
+
/** Fetches and validates an authorization server's discovery document. */
|
|
31
|
+
export declare function discoverAuthorizationServer(issuer: string): Promise<DiscoveredMetadata>;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { OAuthMetadataSchema } from "@modelcontextprotocol/sdk/shared/auth.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Discovery doc validated as OAuth AS metadata + `jwks_uri`. The SDK's
|
|
5
|
+
* `OAuthMetadataSchema` omits `jwks_uri` (its client never verifies tokens), but
|
|
6
|
+
* we need it for JWKS token verification, so we extend the schema to keep it.
|
|
7
|
+
*/
|
|
8
|
+
const DiscoverySchema = OAuthMetadataSchema.extend({
|
|
9
|
+
jwks_uri: z.string().optional(),
|
|
10
|
+
});
|
|
11
|
+
const WELL_KNOWN = [
|
|
12
|
+
"/.well-known/openid-configuration",
|
|
13
|
+
"/.well-known/oauth-authorization-server",
|
|
14
|
+
];
|
|
15
|
+
const DISCOVERY_TIMEOUT_MS = 5000;
|
|
16
|
+
/** Fetches and validates an authorization server's discovery document. */
|
|
17
|
+
export async function discoverAuthorizationServer(issuer) {
|
|
18
|
+
const base = issuer.replace(/\/$/, "");
|
|
19
|
+
const errors = [];
|
|
20
|
+
// First valid doc lacking a registration_endpoint, kept as a fallback so a
|
|
21
|
+
// genuinely non-DCR IdP still resolves (and is rejected later by the caller).
|
|
22
|
+
let fallback;
|
|
23
|
+
for (const path of WELL_KNOWN) {
|
|
24
|
+
const url = `${base}${path}`;
|
|
25
|
+
// Any failure (network/timeout, non-2xx, non-JSON, invalid metadata, issuer
|
|
26
|
+
// mismatch) records a per-URL reason and falls through to the next path.
|
|
27
|
+
try {
|
|
28
|
+
const res = await fetch(url, {
|
|
29
|
+
signal: AbortSignal.timeout(DISCOVERY_TIMEOUT_MS),
|
|
30
|
+
});
|
|
31
|
+
if (!res.ok) {
|
|
32
|
+
throw new Error(`HTTP ${res.status}`);
|
|
33
|
+
}
|
|
34
|
+
const meta = DiscoverySchema.parse(await res.json());
|
|
35
|
+
// RFC 8414 §3.3: issuer must match the fetch origin (slash-insensitive).
|
|
36
|
+
if (meta.issuer.replace(/\/$/, "") !== base) {
|
|
37
|
+
throw new Error(`issuer mismatch: ${meta.issuer}`);
|
|
38
|
+
}
|
|
39
|
+
// Prefer the document that advertises DCR: some IdPs (e.g. Clerk) serve a
|
|
40
|
+
// valid openid-configuration without `registration_endpoint` yet expose
|
|
41
|
+
// it at oauth-authorization-server. Keep looking past a doc that omits it.
|
|
42
|
+
if (meta.registration_endpoint) {
|
|
43
|
+
return meta;
|
|
44
|
+
}
|
|
45
|
+
fallback ??= meta;
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
errors.push(`${url}: ${err instanceof Error ? err.message : String(err)}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (fallback) {
|
|
52
|
+
return fallback;
|
|
53
|
+
}
|
|
54
|
+
throw new Error(`OAuth discovery failed for ${issuer}: ${errors.join("; ")}`);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/server/auth/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAC/E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH,MAAM,eAAe,GAAG,mBAAmB,CAAC,MAAM,CAAC;IACjD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AAGH,MAAM,UAAU,GAAG;IACjB,mCAAmC;IACnC,yCAAyC;CAC1C,CAAC;AAEF,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAElC,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,MAAc;IAEd,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACvC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,2EAA2E;IAC3E,8EAA8E;IAC9E,IAAI,QAAwC,CAAC;IAE7C,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;QAC7B,4EAA4E;QAC5E,yEAAyE;QACzE,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC3B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,oBAAoB,CAAC;aAClD,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YACxC,CAAC;YACD,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YACrD,yEAAyE;YACzE,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC5C,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACrD,CAAC;YACD,0EAA0E;YAC1E,wEAAwE;YACxE,2EAA2E;YAC3E,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC/B,OAAO,IAAI,CAAC;YACd,CAAC;YACD,QAAQ,KAAK,IAAI,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CACT,GAAG,GAAG,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC9D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,8BAA8B,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAChF,CAAC","sourcesContent":["import { OAuthMetadataSchema } from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport { z } from \"zod\";\n\n/**\n * Discovery doc validated as OAuth AS metadata + `jwks_uri`. The SDK's\n * `OAuthMetadataSchema` omits `jwks_uri` (its client never verifies tokens), but\n * we need it for JWKS token verification, so we extend the schema to keep it.\n */\nconst DiscoverySchema = OAuthMetadataSchema.extend({\n jwks_uri: z.string().optional(),\n});\nexport type DiscoveredMetadata = z.infer<typeof DiscoverySchema>;\n\nconst WELL_KNOWN = [\n \"/.well-known/openid-configuration\",\n \"/.well-known/oauth-authorization-server\",\n];\n\nconst DISCOVERY_TIMEOUT_MS = 5000;\n\n/** Fetches and validates an authorization server's discovery document. */\nexport async function discoverAuthorizationServer(\n issuer: string,\n): Promise<DiscoveredMetadata> {\n const base = issuer.replace(/\\/$/, \"\");\n const errors: string[] = [];\n // First valid doc lacking a registration_endpoint, kept as a fallback so a\n // genuinely non-DCR IdP still resolves (and is rejected later by the caller).\n let fallback: DiscoveredMetadata | undefined;\n\n for (const path of WELL_KNOWN) {\n const url = `${base}${path}`;\n // Any failure (network/timeout, non-2xx, non-JSON, invalid metadata, issuer\n // mismatch) records a per-URL reason and falls through to the next path.\n try {\n const res = await fetch(url, {\n signal: AbortSignal.timeout(DISCOVERY_TIMEOUT_MS),\n });\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n const meta = DiscoverySchema.parse(await res.json());\n // RFC 8414 §3.3: issuer must match the fetch origin (slash-insensitive).\n if (meta.issuer.replace(/\\/$/, \"\") !== base) {\n throw new Error(`issuer mismatch: ${meta.issuer}`);\n }\n // Prefer the document that advertises DCR: some IdPs (e.g. Clerk) serve a\n // valid openid-configuration without `registration_endpoint` yet expose\n // it at oauth-authorization-server. Keep looking past a doc that omits it.\n if (meta.registration_endpoint) {\n return meta;\n }\n fallback ??= meta;\n } catch (err) {\n errors.push(\n `${url}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n if (fallback) {\n return fallback;\n }\n throw new Error(`OAuth discovery failed for ${issuer}: ${errors.join(\"; \")}`);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
import http from "node:http";
|
|
3
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
4
|
+
import { discoverAuthorizationServer } from "./discovery.js";
|
|
5
|
+
let server;
|
|
6
|
+
afterEach(() => server?.close());
|
|
7
|
+
function doc(origin, extra = {}) {
|
|
8
|
+
return {
|
|
9
|
+
issuer: origin,
|
|
10
|
+
authorization_endpoint: `${origin}/authorize`,
|
|
11
|
+
token_endpoint: `${origin}/token`,
|
|
12
|
+
registration_endpoint: `${origin}/register`,
|
|
13
|
+
response_types_supported: ["code"],
|
|
14
|
+
scopes_supported: ["openid", "email"],
|
|
15
|
+
jwks_uri: `${origin}/jwks`,
|
|
16
|
+
...extra,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
// Serves JSON bodies built from the live origin at their well-known paths;
|
|
20
|
+
// returns the origin URL.
|
|
21
|
+
async function serve(build) {
|
|
22
|
+
let origin = "";
|
|
23
|
+
const srv = http.createServer((req, res) => {
|
|
24
|
+
const body = build(origin)[req.url ?? ""];
|
|
25
|
+
if (body === undefined) {
|
|
26
|
+
res.writeHead(404).end();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
res.setHeader("content-type", "application/json");
|
|
30
|
+
res.end(JSON.stringify(body));
|
|
31
|
+
});
|
|
32
|
+
await new Promise((resolve) => srv.listen(0, resolve));
|
|
33
|
+
server = srv;
|
|
34
|
+
origin = `http://localhost:${srv.address().port}`;
|
|
35
|
+
return origin;
|
|
36
|
+
}
|
|
37
|
+
describe("discoverAuthorizationServer", () => {
|
|
38
|
+
it("fetches and validates openid-configuration", async () => {
|
|
39
|
+
const base = await serve((o) => ({
|
|
40
|
+
"/.well-known/openid-configuration": doc(o),
|
|
41
|
+
}));
|
|
42
|
+
const meta = await discoverAuthorizationServer(base);
|
|
43
|
+
expect(meta.registration_endpoint).toBe(`${base}/register`);
|
|
44
|
+
expect(meta.jwks_uri).toBe(`${base}/jwks`);
|
|
45
|
+
});
|
|
46
|
+
it("accepts a canonically slash-terminated issuer", async () => {
|
|
47
|
+
const base = await serve((o) => ({
|
|
48
|
+
"/.well-known/openid-configuration": doc(o, { issuer: `${o}/` }),
|
|
49
|
+
}));
|
|
50
|
+
const meta = await discoverAuthorizationServer(base);
|
|
51
|
+
expect(meta.registration_endpoint).toBe(`${base}/register`);
|
|
52
|
+
});
|
|
53
|
+
it("falls back to oauth-authorization-server when oidc is 404", async () => {
|
|
54
|
+
const base = await serve((o) => ({
|
|
55
|
+
"/.well-known/oauth-authorization-server": doc(o),
|
|
56
|
+
}));
|
|
57
|
+
const meta = await discoverAuthorizationServer(base);
|
|
58
|
+
expect(meta.registration_endpoint).toBe(`${base}/register`);
|
|
59
|
+
});
|
|
60
|
+
it("throws when no well-known doc is reachable", async () => {
|
|
61
|
+
const base = await serve(() => ({}));
|
|
62
|
+
await expect(discoverAuthorizationServer(base)).rejects.toThrow(/discovery failed/i);
|
|
63
|
+
});
|
|
64
|
+
it("falls through to oauth-authorization-server when oidc doc is schema-invalid", async () => {
|
|
65
|
+
const base = await serve((o) => ({
|
|
66
|
+
"/.well-known/openid-configuration": doc(o, {
|
|
67
|
+
response_types_supported: undefined,
|
|
68
|
+
}),
|
|
69
|
+
"/.well-known/oauth-authorization-server": doc(o),
|
|
70
|
+
}));
|
|
71
|
+
const meta = await discoverAuthorizationServer(base);
|
|
72
|
+
expect(meta.registration_endpoint).toBe(`${base}/register`);
|
|
73
|
+
});
|
|
74
|
+
it("prefers the doc advertising DCR when oidc omits registration_endpoint", async () => {
|
|
75
|
+
// Clerk-shaped: valid openid-configuration without a registration_endpoint,
|
|
76
|
+
// DCR exposed only at oauth-authorization-server.
|
|
77
|
+
const base = await serve((o) => ({
|
|
78
|
+
"/.well-known/openid-configuration": doc(o, {
|
|
79
|
+
registration_endpoint: undefined,
|
|
80
|
+
}),
|
|
81
|
+
"/.well-known/oauth-authorization-server": doc(o),
|
|
82
|
+
}));
|
|
83
|
+
const meta = await discoverAuthorizationServer(base);
|
|
84
|
+
expect(meta.registration_endpoint).toBe(`${base}/register`);
|
|
85
|
+
});
|
|
86
|
+
it("rejects a doc whose issuer does not match the fetch origin", async () => {
|
|
87
|
+
const base = await serve(() => ({
|
|
88
|
+
"/.well-known/openid-configuration": doc("https://evil.test"),
|
|
89
|
+
}));
|
|
90
|
+
await expect(discoverAuthorizationServer(base)).rejects.toThrow(/discovery failed/i);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=discovery.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.test.js","sourceRoot":"","sources":["../../../src/server/auth/discovery.test.ts"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment node\nimport http from \"node:http\";\nimport { afterEach, describe, expect, it } from \"vitest\";\nimport { discoverAuthorizationServer } from \"./discovery.js\";\n\nlet server: http.Server | undefined;\nafterEach(() => server?.close());\n\nfunction doc(origin: string, extra: Record<string, unknown> = {}) {\n return {\n issuer: origin,\n authorization_endpoint: `${origin}/authorize`,\n token_endpoint: `${origin}/token`,\n registration_endpoint: `${origin}/register`,\n response_types_supported: [\"code\"],\n scopes_supported: [\"openid\", \"email\"],\n jwks_uri: `${origin}/jwks`,\n ...extra,\n };\n}\n\n// Serves JSON bodies built from the live origin at their well-known paths;\n// returns the origin URL.\nasync function serve(build: (origin: string) => Record<string, unknown>) {\n let origin = \"\";\n const srv = http.createServer((req, res) => {\n const body = build(origin)[req.url ?? \"\"];\n if (body === undefined) {\n res.writeHead(404).end();\n return;\n }\n res.setHeader(\"content-type\", \"application/json\");\n res.end(JSON.stringify(body));\n });\n await new Promise<void>((resolve) => srv.listen(0, resolve));\n server = srv;\n origin = `http://localhost:${(srv.address() as { port: number }).port}`;\n return origin;\n}\n\ndescribe(\"discoverAuthorizationServer\", () => {\n it(\"fetches and validates openid-configuration\", async () => {\n const base = await serve((o) => ({\n \"/.well-known/openid-configuration\": doc(o),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n expect(meta.jwks_uri).toBe(`${base}/jwks`);\n });\n\n it(\"accepts a canonically slash-terminated issuer\", async () => {\n const base = await serve((o) => ({\n \"/.well-known/openid-configuration\": doc(o, { issuer: `${o}/` }),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n });\n\n it(\"falls back to oauth-authorization-server when oidc is 404\", async () => {\n const base = await serve((o) => ({\n \"/.well-known/oauth-authorization-server\": doc(o),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n });\n\n it(\"throws when no well-known doc is reachable\", async () => {\n const base = await serve(() => ({}));\n await expect(discoverAuthorizationServer(base)).rejects.toThrow(\n /discovery failed/i,\n );\n });\n\n it(\"falls through to oauth-authorization-server when oidc doc is schema-invalid\", async () => {\n const base = await serve((o) => ({\n \"/.well-known/openid-configuration\": doc(o, {\n response_types_supported: undefined,\n }),\n \"/.well-known/oauth-authorization-server\": doc(o),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n });\n\n it(\"prefers the doc advertising DCR when oidc omits registration_endpoint\", async () => {\n // Clerk-shaped: valid openid-configuration without a registration_endpoint,\n // DCR exposed only at oauth-authorization-server.\n const base = await serve((o) => ({\n \"/.well-known/openid-configuration\": doc(o, {\n registration_endpoint: undefined,\n }),\n \"/.well-known/oauth-authorization-server\": doc(o),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n });\n\n it(\"rejects a doc whose issuer does not match the fetch origin\", async () => {\n const base = await serve(() => ({\n \"/.well-known/openid-configuration\": doc(\"https://evil.test\"),\n }));\n await expect(discoverAuthorizationServer(base)).rejects.toThrow(\n /discovery failed/i,\n );\n });\n});\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { OAuthMetadata } from "@modelcontextprotocol/sdk/shared/auth.js";
|
|
2
|
+
import type { JwksVerifyConfig } from "./verify.js";
|
|
3
|
+
/** Resource-server OAuth config for `SkybridgeServerOptions.oauth`. */
|
|
4
|
+
export type OAuthConfig = {
|
|
5
|
+
/**
|
|
6
|
+
* Public URL of this server; sets `resourceServerUrl` and the
|
|
7
|
+
* `resource_metadata` URL. When omitted, it is inferred per request from
|
|
8
|
+
* `x-forwarded-host`/`origin`/`host` headers.
|
|
9
|
+
*/
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
/** AS metadata served at `/.well-known/oauth-authorization-server`. */
|
|
12
|
+
oauthMetadata: OAuthMetadata;
|
|
13
|
+
verify: JwksVerifyConfig;
|
|
14
|
+
/** Scopes advertised in protected-resource metadata. */
|
|
15
|
+
scopesSupported?: string[];
|
|
16
|
+
/** Server-wide required-scope floor. */
|
|
17
|
+
requiredScopes?: string[];
|
|
18
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/auth/index.ts"],"names":[],"mappings":"","sourcesContent":["import type { OAuthMetadata } from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport type { JwksVerifyConfig } from \"./verify.js\";\n\n/** Resource-server OAuth config for `SkybridgeServerOptions.oauth`. */\nexport type OAuthConfig = {\n /**\n * Public URL of this server; sets `resourceServerUrl` and the\n * `resource_metadata` URL. When omitted, it is inferred per request from\n * `x-forwarded-host`/`origin`/`host` headers.\n */\n baseUrl?: string;\n /** AS metadata served at `/.well-known/oauth-authorization-server`. */\n oauthMetadata: OAuthMetadata;\n verify: JwksVerifyConfig;\n /** Scopes advertised in protected-resource metadata. */\n scopesSupported?: string[];\n /** Server-wide required-scope floor. */\n requiredScopes?: string[];\n};\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { OAuthConfig } from "../index.js";
|
|
2
|
+
import { type CustomProviderOptions } from "./custom.js";
|
|
3
|
+
/**
|
|
4
|
+
* OAuth provider for Auth0. `domain` is the tenant domain (e.g.
|
|
5
|
+
* `acme.us.auth0.com`); `audience` is the API Identifier; `serverUrl` is this
|
|
6
|
+
* server's public URL. Requires DCR enabled on the tenant.
|
|
7
|
+
*
|
|
8
|
+
* Auth0 can't use the client's resource indicator — `audience` must be *in* the
|
|
9
|
+
* authorize request. So it runs as skybridge-as-AS (`serverUrl`, see
|
|
10
|
+
* {@link customProvider}) and bakes `?audience=<id>` into the advertised
|
|
11
|
+
* `authorization_endpoint`. The token's `aud` is the API; `verify.issuer` stays
|
|
12
|
+
* Auth0 (the token's real `iss`).
|
|
13
|
+
*/
|
|
14
|
+
export declare function auth0Provider(opts: {
|
|
15
|
+
domain: string;
|
|
16
|
+
audience: string;
|
|
17
|
+
serverUrl: string;
|
|
18
|
+
} & Omit<CustomProviderOptions, "issuer" | "audience" | "baseUrl" | "serverUrl">): Promise<OAuthConfig>;
|