skybridge 0.0.0-dev.bc9b932 → 0.0.0-dev.bcab395
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 +17 -8
- package/dist/cli/detect-port.d.ts +18 -0
- package/dist/cli/detect-port.js +61 -0
- package/dist/cli/detect-port.js.map +1 -0
- package/dist/cli/header.js +1 -1
- package/dist/cli/header.js.map +1 -1
- package/dist/cli/tunnel-control-server.d.ts +9 -0
- package/dist/cli/tunnel-control-server.js +31 -0
- package/dist/cli/tunnel-control-server.js.map +1 -0
- package/dist/cli/tunnel-control-server.test.js +39 -0
- package/dist/cli/tunnel-control-server.test.js.map +1 -0
- package/dist/cli/tunnel-handler.d.ts +3 -0
- package/dist/cli/tunnel-handler.js +48 -0
- package/dist/cli/tunnel-handler.js.map +1 -0
- package/dist/cli/tunnel-handler.test.d.ts +1 -0
- package/dist/cli/tunnel-handler.test.js +105 -0
- package/dist/cli/tunnel-handler.test.js.map +1 -0
- package/dist/cli/tunnel.d.ts +57 -0
- package/dist/cli/tunnel.js +154 -0
- package/dist/cli/tunnel.js.map +1 -0
- package/dist/cli/tunnel.test.d.ts +1 -0
- package/dist/cli/tunnel.test.js +190 -0
- package/dist/cli/tunnel.test.js.map +1 -0
- package/dist/cli/types.d.ts +5 -0
- package/dist/cli/types.js +2 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/use-messages.d.ts +3 -0
- package/dist/cli/use-messages.js +11 -0
- package/dist/cli/use-messages.js.map +1 -0
- package/dist/cli/use-nodemon.d.ts +2 -6
- package/dist/cli/use-nodemon.js +20 -17
- package/dist/cli/use-nodemon.js.map +1 -1
- package/dist/cli/use-tunnel.d.ts +14 -0
- package/dist/cli/use-tunnel.js +131 -0
- package/dist/cli/use-tunnel.js.map +1 -0
- package/dist/commands/build.js +28 -7
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/dev.d.ts +3 -1
- package/dist/commands/dev.js +50 -8
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/start.d.ts +3 -1
- package/dist/commands/start.js +30 -9
- package/dist/commands/start.js.map +1 -1
- package/dist/server/asset-base-url-transform-plugin.d.ts +5 -6
- package/dist/server/asset-base-url-transform-plugin.js +8 -9
- package/dist/server/asset-base-url-transform-plugin.js.map +1 -1
- package/dist/server/asset-base-url-transform-plugin.test.js +12 -13
- package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -1
- package/dist/server/content-helpers.d.ts +27 -0
- package/dist/server/content-helpers.js +46 -0
- package/dist/server/content-helpers.js.map +1 -0
- package/dist/server/content-helpers.test.d.ts +1 -0
- package/dist/server/content-helpers.test.js +70 -0
- package/dist/server/content-helpers.test.js.map +1 -0
- package/dist/server/express.d.ts +15 -0
- package/dist/server/express.js +95 -0
- package/dist/server/express.js.map +1 -0
- package/dist/server/express.test.d.ts +1 -0
- package/dist/server/express.test.js +348 -0
- package/dist/server/express.test.js.map +1 -0
- package/dist/server/index.d.ts +5 -3
- package/dist/server/index.js +3 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/metric.d.ts +14 -0
- package/dist/server/metric.js +62 -0
- package/dist/server/metric.js.map +1 -0
- package/dist/server/middleware.d.ts +124 -0
- package/dist/server/middleware.js +93 -0
- package/dist/server/middleware.js.map +1 -0
- package/dist/server/middleware.test-d.d.ts +1 -0
- package/dist/server/middleware.test-d.js +75 -0
- package/dist/server/middleware.test-d.js.map +1 -0
- package/dist/server/middleware.test.d.ts +1 -0
- package/dist/server/middleware.test.js +493 -0
- package/dist/server/middleware.test.js.map +1 -0
- package/dist/server/server.d.ts +137 -63
- package/dist/server/server.js +348 -77
- package/dist/server/server.js.map +1 -1
- package/dist/server/templateHelper.d.ts +5 -6
- package/dist/server/templateHelper.js.map +1 -1
- package/dist/server/templates/development.hbs +2 -57
- package/dist/server/templates/production.hbs +1 -1
- package/dist/server/tunnel-proxy-router.d.ts +7 -0
- package/dist/server/tunnel-proxy-router.js +110 -0
- package/dist/server/tunnel-proxy-router.js.map +1 -0
- package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
- package/dist/server/tunnel-proxy-router.test.js +229 -0
- package/dist/server/tunnel-proxy-router.test.js.map +1 -0
- package/dist/server/viewsDevServer.d.ts +14 -0
- package/dist/server/viewsDevServer.js +45 -0
- package/dist/server/viewsDevServer.js.map +1 -0
- package/dist/test/utils.d.ts +13 -21
- package/dist/test/utils.js +42 -37
- package/dist/test/utils.js.map +1 -1
- package/dist/test/view.test.d.ts +1 -0
- package/dist/test/view.test.js +523 -0
- package/dist/test/view.test.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/dist/web/bridges/apps-sdk/adaptor.d.ts +7 -5
- package/dist/web/bridges/apps-sdk/adaptor.js +39 -16
- package/dist/web/bridges/apps-sdk/adaptor.js.map +1 -1
- package/dist/web/bridges/apps-sdk/bridge.d.ts +1 -1
- package/dist/web/bridges/apps-sdk/index.d.ts +1 -1
- package/dist/web/bridges/apps-sdk/index.js.map +1 -1
- package/dist/web/bridges/apps-sdk/types.d.ts +24 -13
- package/dist/web/bridges/apps-sdk/types.js.map +1 -1
- package/dist/web/bridges/mcp-app/adaptor.d.ts +16 -4
- package/dist/web/bridges/mcp-app/adaptor.js +121 -38
- package/dist/web/bridges/mcp-app/adaptor.js.map +1 -1
- package/dist/web/bridges/mcp-app/bridge.d.ts +13 -30
- package/dist/web/bridges/mcp-app/bridge.js +43 -196
- package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
- package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +5 -3
- package/dist/web/bridges/mcp-app/use-mcp-app-context.js +2 -2
- package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
- package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -41
- package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
- package/dist/web/bridges/types.d.ts +17 -6
- package/dist/web/components/modal-provider.js +2 -4
- package/dist/web/components/modal-provider.js.map +1 -1
- package/dist/web/create-store.js +15 -1
- package/dist/web/create-store.js.map +1 -1
- package/dist/web/create-store.test.js +9 -4
- package/dist/web/create-store.test.js.map +1 -1
- package/dist/web/data-llm.test.js +11 -8
- package/dist/web/data-llm.test.js.map +1 -1
- package/dist/web/generate-helpers.d.ts +20 -18
- package/dist/web/generate-helpers.js +20 -18
- package/dist/web/generate-helpers.js.map +1 -1
- package/dist/web/generate-helpers.test-d.js +20 -20
- package/dist/web/generate-helpers.test-d.js.map +1 -1
- package/dist/web/hooks/index.d.ts +1 -1
- package/dist/web/hooks/index.js.map +1 -1
- package/dist/web/hooks/test/utils.js +4 -0
- package/dist/web/hooks/test/utils.js.map +1 -1
- package/dist/web/hooks/use-display-mode.d.ts +3 -3
- package/dist/web/hooks/use-display-mode.js.map +1 -1
- package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
- package/dist/web/hooks/use-display-mode.test-d.js +8 -0
- package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
- package/dist/web/hooks/use-files.d.ts +2 -1
- package/dist/web/hooks/use-files.js +1 -0
- package/dist/web/hooks/use-files.js.map +1 -1
- package/dist/web/hooks/use-files.test.js +27 -3
- package/dist/web/hooks/use-files.test.js.map +1 -1
- package/dist/web/hooks/use-layout.test.js +3 -3
- package/dist/web/hooks/use-layout.test.js.map +1 -1
- package/dist/web/hooks/use-open-external.d.ts +3 -1
- package/dist/web/hooks/use-open-external.js +1 -1
- package/dist/web/hooks/use-open-external.js.map +1 -1
- package/dist/web/hooks/use-open-external.test.js +26 -11
- package/dist/web/hooks/use-open-external.test.js.map +1 -1
- package/dist/web/hooks/use-request-modal.test.js +5 -1
- package/dist/web/hooks/use-request-modal.test.js.map +1 -1
- package/dist/web/hooks/use-set-open-in-app-url.test.js +5 -11
- package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
- package/dist/web/hooks/use-tool-info.test.js +1 -1
- package/dist/web/hooks/use-tool-info.test.js.map +1 -1
- package/dist/web/hooks/use-user.js +18 -2
- package/dist/web/hooks/use-user.js.map +1 -1
- package/dist/web/hooks/use-user.test.js +29 -1
- package/dist/web/hooks/use-user.test.js.map +1 -1
- package/dist/web/hooks/use-widget-state.test.js +123 -7
- package/dist/web/hooks/use-widget-state.test.js.map +1 -1
- package/dist/web/index.d.ts +1 -0
- package/dist/web/index.js.map +1 -1
- package/dist/web/plugin/plugin.d.ts +4 -1
- package/dist/web/plugin/plugin.js +113 -18
- package/dist/web/plugin/plugin.js.map +1 -1
- package/dist/web/plugin/scan-views.d.ts +8 -0
- package/dist/web/plugin/scan-views.js +70 -0
- package/dist/web/plugin/scan-views.js.map +1 -0
- package/dist/web/plugin/scan-views.test.d.ts +1 -0
- package/dist/web/plugin/scan-views.test.js +67 -0
- package/dist/web/plugin/scan-views.test.js.map +1 -0
- package/dist/web/plugin/transform-data-llm.js +1 -1
- package/dist/web/plugin/transform-data-llm.js.map +1 -1
- package/dist/web/plugin/validate-view.d.ts +1 -0
- package/dist/web/plugin/validate-view.js +9 -0
- package/dist/web/plugin/validate-view.js.map +1 -0
- package/dist/web/plugin/validate-view.test.d.ts +1 -0
- package/dist/web/plugin/validate-view.test.js +24 -0
- package/dist/web/plugin/validate-view.test.js.map +1 -0
- package/package.json +33 -25
- package/tsconfig.base.json +33 -0
- package/dist/server/widgetsDevServer.d.ts +0 -12
- package/dist/server/widgetsDevServer.js +0 -57
- package/dist/server/widgetsDevServer.js.map +0 -1
- package/dist/test/widget.test.js +0 -255
- package/dist/test/widget.test.js.map +0 -1
- /package/dist/{test/widget.test.d.ts → cli/tunnel-control-server.test.d.ts} +0 -0
package/dist/commands/dev.js
CHANGED
|
@@ -1,31 +1,73 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Command, Flags } from "@oclif/core";
|
|
3
3
|
import { Box, render, Text } from "ink";
|
|
4
|
+
import { resolvePort } from "../cli/detect-port.js";
|
|
4
5
|
import { Header } from "../cli/header.js";
|
|
6
|
+
import { startTunnelControlServer } from "../cli/tunnel-control-server.js";
|
|
7
|
+
import { useMessages } from "../cli/use-messages.js";
|
|
5
8
|
import { useNodemon } from "../cli/use-nodemon.js";
|
|
9
|
+
import { useTunnel } from "../cli/use-tunnel.js";
|
|
6
10
|
import { useTypeScriptCheck } from "../cli/use-typescript-check.js";
|
|
7
11
|
export default class Dev extends Command {
|
|
8
12
|
static description = "Start development server";
|
|
9
13
|
static examples = ["skybridge"];
|
|
10
14
|
static flags = {
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
port: Flags.integer({
|
|
16
|
+
char: "p",
|
|
17
|
+
description: "Port to run the server on",
|
|
18
|
+
min: 1,
|
|
19
|
+
}),
|
|
20
|
+
tunnel: Flags.boolean({
|
|
21
|
+
description: "Open an Alpic tunnel for remote testing",
|
|
22
|
+
default: false,
|
|
23
|
+
}),
|
|
24
|
+
verbose: Flags.boolean({
|
|
25
|
+
char: "v",
|
|
26
|
+
description: "Show tunnel logs",
|
|
27
|
+
default: false,
|
|
13
28
|
}),
|
|
14
29
|
};
|
|
15
30
|
async run() {
|
|
16
31
|
const { flags } = await this.parse(Dev);
|
|
32
|
+
const { port, fallback, envWarning } = await resolvePort(flags.port);
|
|
33
|
+
if (envWarning) {
|
|
34
|
+
this.warn(envWarning);
|
|
35
|
+
}
|
|
36
|
+
const { port: controlPort, manager: tunnelManager, close: closeTunnelControl, } = await startTunnelControlServer(() => port);
|
|
17
37
|
const env = {
|
|
18
38
|
...process.env,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
: {}),
|
|
39
|
+
__PORT: String(port),
|
|
40
|
+
__TUNNEL_CONTROL_PORT: String(controlPort),
|
|
22
41
|
};
|
|
23
42
|
const App = () => {
|
|
24
43
|
const tsErrors = useTypeScriptCheck();
|
|
25
|
-
const messages =
|
|
26
|
-
|
|
44
|
+
const [messages, pushMessage] = useMessages();
|
|
45
|
+
useNodemon(env, pushMessage);
|
|
46
|
+
const tunnelState = useTunnel(port, pushMessage, flags.verbose, flags.tunnel);
|
|
47
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, marginLeft: 1, children: [_jsx(Header, { version: this.config.version }), _jsxs(Box, { children: [_jsxs(Text, { children: ["\uD83C\uDFE0", " "] }), fallback ? (_jsx(Text, { color: "yellow", children: "3000 in use, running on " })) : (_jsx(Text, { children: "Running on " })), _jsx(Text, { color: "green", children: `http://localhost:${port}/mcp` })] }), _jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: "#20a832", children: ["\u2192", " "] }), _jsxs(Text, { color: "white", bold: true, children: ["Test locally with DevTools:", " "] }), _jsx(Text, { color: "green", children: `http://localhost:${port}/` })] }), tunnelState.status === "idle" && (_jsxs(Box, { children: [_jsxs(Text, { children: ["\uD83C\uDF0D", " "] }), _jsx(Text, { children: "Get a public URL and LLM Playground access with " }), _jsx(Text, { color: "cyan", bold: true, children: "--tunnel" }), _jsx(Text, { children: "." })] })), tunnelState.status === "starting" && (_jsxs(Box, { children: [_jsxs(Text, { children: ["\uD83C\uDF0D", " "] }), _jsx(Text, { color: "yellow", children: tunnelState.message })] })), tunnelState.status === "connected" && (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { children: ["\uD83C\uDF0D", " "] }), _jsx(Text, { children: "Exposed on " }), _jsx(Text, { color: "green", children: `${tunnelState.url}/mcp` })] }), _jsxs(Box, { children: [_jsxs(Text, { color: "#20a832", children: ["\u2192", " "] }), _jsxs(Text, { color: "white", bold: true, children: ["Test with an LLM on Playground:", " "] }), _jsx(Text, { color: "green", children: `${tunnelState.url}/try` })] })] })), tunnelState.status === "error" && (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { children: ["\uD83C\uDF0D", " "] }), _jsxs(Text, { color: "red", children: ["Cannot open tunnel: ", tunnelState.message] })] }), _jsxs(Box, { children: [_jsxs(Text, { color: "#20a832", children: ["\u2192", " "] }), _jsx(Text, { color: "red", children: `Try manually: npx alpic tunnel --port ${port}` })] })] })), _jsxs(Box, { children: [_jsxs(Text, { children: ["\uD83D\uDEDF", " "] }), _jsx(Text, { children: "Need help? Reach us on " }), _jsx(Text, { color: "white", underline: true, children: "https://discord.alpic.ai" })] }), tsErrors.length > 0 && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "red", bold: true, children: "\u26A0\uFE0F TypeScript errors found:" }), tsErrors.map((error) => (_jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: "white", children: error.file }), _jsxs(Text, { color: "grey", children: ["(", error.line, ",", error.col, "):", " "] })] }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "red", children: error.message }) })] }, `${error.file}:${error.line}:${error.col}`)))] })), messages.length > 0 && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "white", bold: true, children: "Logs:" }), messages.map((message) => (_jsx(Box, { marginLeft: 2, children: message.type === "restart" ? (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "green", children: ["\u2713", " "] }), _jsx(Text, { color: "white", children: message.text })] })) : message.type === "error" ? (_jsx(Text, { color: "red", children: message.text })) : (_jsx(Text, { children: message.text })) }, message.id)))] }))] }));
|
|
48
|
+
};
|
|
49
|
+
// Note: `exitOnCtrlC: false` because we own SIGINT below to guarantee
|
|
50
|
+
// alpic gets killed before we exit. If anything ever calls `useInput` or
|
|
51
|
+
// puts stdin into raw mode, also wire an explicit `\x03` keypress to the
|
|
52
|
+
// shutdown function — Ink will otherwise swallow Ctrl-C without ever
|
|
53
|
+
// delivering SIGINT.
|
|
54
|
+
const ink = render(_jsx(App, {}), { exitOnCtrlC: false, patchConsole: true });
|
|
55
|
+
// Synchronous-first shutdown: kill the alpic subprocess up front so we
|
|
56
|
+
// can't leave it orphaned even if another SIGINT listener (e.g. nodemon's)
|
|
57
|
+
// exits the process before our async cleanup completes.
|
|
58
|
+
const shutdown = (code) => () => {
|
|
59
|
+
tunnelManager.stop();
|
|
60
|
+
void closeTunnelControl()
|
|
61
|
+
.catch((err) => {
|
|
62
|
+
console.error("Failed to close tunnel control server", err);
|
|
63
|
+
})
|
|
64
|
+
.finally(() => {
|
|
65
|
+
ink.unmount();
|
|
66
|
+
process.exit(code);
|
|
67
|
+
});
|
|
27
68
|
};
|
|
28
|
-
|
|
69
|
+
process.once("SIGINT", shutdown(130));
|
|
70
|
+
process.once("SIGTERM", shutdown(143));
|
|
29
71
|
}
|
|
30
72
|
}
|
|
31
73
|
//# sourceMappingURL=dev.js.map
|
package/dist/commands/dev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAEpE,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,OAAO;IACtC,MAAM,CAAU,WAAW,GAAG,0BAA0B,CAAC;IACzD,MAAM,CAAU,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,CAAU,KAAK,GAAG;QACtB,
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.tsx"],"names":[],"mappings":"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"}
|
package/dist/commands/start.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { Command } from "@oclif/core";
|
|
|
2
2
|
export default class Start extends Command {
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
|
-
static flags: {
|
|
5
|
+
static flags: {
|
|
6
|
+
port: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
};
|
|
6
8
|
run(): Promise<void>;
|
|
7
9
|
}
|
package/dist/commands/start.js
CHANGED
|
@@ -1,27 +1,48 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
-
import { Command } from "@oclif/core";
|
|
3
|
+
import { Command, Flags } from "@oclif/core";
|
|
4
|
+
import { resolvePort } from "../cli/detect-port.js";
|
|
4
5
|
import { runCommand } from "../cli/run-command.js";
|
|
5
6
|
export default class Start extends Command {
|
|
6
7
|
static description = "Start production server";
|
|
7
8
|
static examples = ["skybridge start"];
|
|
8
|
-
static flags = {
|
|
9
|
+
static flags = {
|
|
10
|
+
port: Flags.integer({
|
|
11
|
+
char: "p",
|
|
12
|
+
description: "Port to run the server on",
|
|
13
|
+
min: 1,
|
|
14
|
+
}),
|
|
15
|
+
};
|
|
9
16
|
async run() {
|
|
17
|
+
const { flags } = await this.parse(Start);
|
|
18
|
+
const { port, fallback, envWarning } = await resolvePort(flags.port);
|
|
19
|
+
if (envWarning) {
|
|
20
|
+
this.warn(envWarning);
|
|
21
|
+
}
|
|
10
22
|
console.clear();
|
|
11
|
-
const
|
|
12
|
-
if (!existsSync(
|
|
13
|
-
console.error("❌ Error:
|
|
23
|
+
const indexPath = resolve(process.cwd(), "dist/server.js");
|
|
24
|
+
if (!existsSync(indexPath)) {
|
|
25
|
+
console.error("❌ Error: No build output found");
|
|
14
26
|
console.error("");
|
|
15
27
|
console.error("Please build your project first:");
|
|
16
28
|
console.error(" skybridge build");
|
|
17
29
|
console.error("");
|
|
18
30
|
process.exit(1);
|
|
19
31
|
}
|
|
20
|
-
console.log(`\x1b[36m\x1b[1m⛰
|
|
21
|
-
|
|
22
|
-
|
|
32
|
+
console.log(`\x1b[36m\x1b[1m⛰ Skybridge\x1b[0m \x1b[36mv${this.config.version}\x1b[0m`);
|
|
33
|
+
if (fallback) {
|
|
34
|
+
console.log(`\x1b[33m3000 in use, running on\x1b[0m \x1b[32mhttp://localhost:${port}/mcp\x1b[0m`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.log(`Running on \x1b[32mhttp://localhost:${port}/mcp\x1b[0m`);
|
|
38
|
+
}
|
|
39
|
+
await runCommand(`node ${indexPath}`, {
|
|
23
40
|
stdio: ["ignore", "inherit", "inherit"],
|
|
24
|
-
env: {
|
|
41
|
+
env: {
|
|
42
|
+
...process.env,
|
|
43
|
+
NODE_ENV: "production",
|
|
44
|
+
__PORT: String(port),
|
|
45
|
+
},
|
|
25
46
|
});
|
|
26
47
|
}
|
|
27
48
|
}
|
|
@@ -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,MAAM,aAAa,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,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,gBAAgB,CAAC,CAAC;QAE3D,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"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
2
|
/**
|
|
3
|
-
* Transforms asset import paths to
|
|
3
|
+
* Transforms asset import paths to resolve at runtime via `window.skybridge.serverUrl`,
|
|
4
|
+
* so they work both locally and behind tunnels.
|
|
4
5
|
*/
|
|
5
|
-
export declare function assetBaseUrlTransform(code: string
|
|
6
|
+
export declare function assetBaseUrlTransform(code: string): string;
|
|
6
7
|
/**
|
|
7
|
-
* Vite plugin that transforms asset import paths to
|
|
8
|
+
* Vite plugin that transforms asset import paths to resolve at runtime via `window.skybridge.serverUrl`.
|
|
8
9
|
*/
|
|
9
|
-
export declare function assetBaseUrlTransformPlugin(
|
|
10
|
-
devServerOrigin: string;
|
|
11
|
-
}): Plugin;
|
|
10
|
+
export declare function assetBaseUrlTransformPlugin(): Plugin;
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Transforms asset import paths to
|
|
2
|
+
* Transforms asset import paths to resolve at runtime via `window.skybridge.serverUrl`,
|
|
3
|
+
* so they work both locally and behind tunnels.
|
|
3
4
|
*/
|
|
4
|
-
export function assetBaseUrlTransform(code
|
|
5
|
+
export function assetBaseUrlTransform(code) {
|
|
5
6
|
const assetStringPattern = /(?<!https?:\/\/)(["'`])(\/[^"'`]+\.(svg|png|jpeg|jpg|gif|webp|mp3|mp4|woff|woff2|ttf|eot))\1/g;
|
|
6
|
-
code = code.replace(assetStringPattern, (_match,
|
|
7
|
-
return
|
|
7
|
+
code = code.replace(assetStringPattern, (_match, _quote, assetPath) => {
|
|
8
|
+
return `(window.skybridge?.serverUrl ?? "") + "${assetPath}"`;
|
|
8
9
|
});
|
|
9
10
|
return code;
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
12
|
-
* Vite plugin that transforms asset import paths to
|
|
13
|
+
* Vite plugin that transforms asset import paths to resolve at runtime via `window.skybridge.serverUrl`.
|
|
13
14
|
*/
|
|
14
|
-
export function assetBaseUrlTransformPlugin(
|
|
15
|
-
const { devServerOrigin } = options;
|
|
15
|
+
export function assetBaseUrlTransformPlugin() {
|
|
16
16
|
return {
|
|
17
17
|
name: "asset-base-url-transform",
|
|
18
|
-
enforce: "pre",
|
|
19
18
|
transform(code) {
|
|
20
19
|
if (!code) {
|
|
21
20
|
return null;
|
|
22
21
|
}
|
|
23
|
-
const transformedCode = assetBaseUrlTransform(code
|
|
22
|
+
const transformedCode = assetBaseUrlTransform(code);
|
|
24
23
|
if (transformedCode === code) {
|
|
25
24
|
return null;
|
|
26
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset-base-url-transform-plugin.js","sourceRoot":"","sources":["../../src/server/asset-base-url-transform-plugin.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"asset-base-url-transform-plugin.js","sourceRoot":"","sources":["../../src/server/asset-base-url-transform-plugin.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,MAAM,kBAAkB,GACtB,+FAA+F,CAAC;IAElG,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE;QACpE,OAAO,0CAA0C,SAAS,GAAG,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO;QACL,IAAI,EAAE,0BAA0B;QAChC,SAAS,CAAC,IAAI;YACZ,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,eAAe,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAEpD,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;gBAC7B,OAAO,IAAI,CAAC;YACd,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,eAAe;gBACrB,GAAG,EAAE,IAAI;aACV,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { assetBaseUrlTransform } from "./asset-base-url-transform-plugin.js";
|
|
3
3
|
describe("assetBaseUrlTransform", () => {
|
|
4
|
-
|
|
5
|
-
it("should transform asset paths in single, double, and backtick quotes", () => {
|
|
4
|
+
it("should transform asset paths to use window.skybridge.serverUrl", () => {
|
|
6
5
|
const cases = [
|
|
7
6
|
{
|
|
8
7
|
desc: "single-quoted",
|
|
9
8
|
code: `const image = '/assets/logo.png';`,
|
|
10
|
-
expected: `const image =
|
|
9
|
+
expected: `const image = (window.skybridge?.serverUrl ?? "") + "/assets/logo.png";`,
|
|
11
10
|
},
|
|
12
11
|
{
|
|
13
12
|
desc: "double-quoted",
|
|
14
13
|
code: `const image = "/assets/logo.png";`,
|
|
15
|
-
expected: `const image = "
|
|
14
|
+
expected: `const image = (window.skybridge?.serverUrl ?? "") + "/assets/logo.png";`,
|
|
16
15
|
},
|
|
17
16
|
{
|
|
18
17
|
desc: "backtick-quoted",
|
|
19
18
|
code: "const image = `/assets/logo.png`;",
|
|
20
|
-
expected: `const image =
|
|
19
|
+
expected: `const image = (window.skybridge?.serverUrl ?? "") + "/assets/logo.png";`,
|
|
21
20
|
},
|
|
22
21
|
];
|
|
23
22
|
for (const { code, expected } of cases) {
|
|
24
|
-
const result = assetBaseUrlTransform(code
|
|
23
|
+
const result = assetBaseUrlTransform(code);
|
|
25
24
|
expect(result).toBe(expected);
|
|
26
25
|
}
|
|
27
26
|
});
|
|
@@ -31,10 +30,10 @@ describe("assetBaseUrlTransform", () => {
|
|
|
31
30
|
const icon = '/assets/icon.svg';
|
|
32
31
|
const font = '/assets/font.woff2';
|
|
33
32
|
`;
|
|
34
|
-
const result = assetBaseUrlTransform(code
|
|
35
|
-
expect(result).toContain(
|
|
36
|
-
expect(result).toContain(
|
|
37
|
-
expect(result).toContain(
|
|
33
|
+
const result = assetBaseUrlTransform(code);
|
|
34
|
+
expect(result).toContain(`(window.skybridge?.serverUrl ?? "") + "/assets/logo.png"`);
|
|
35
|
+
expect(result).toContain(`(window.skybridge?.serverUrl ?? "") + "/assets/icon.svg"`);
|
|
36
|
+
expect(result).toContain(`(window.skybridge?.serverUrl ?? "") + "/assets/font.woff2"`);
|
|
38
37
|
});
|
|
39
38
|
it("should not transform already absolute URLs", () => {
|
|
40
39
|
const code = `
|
|
@@ -42,14 +41,14 @@ describe("assetBaseUrlTransform", () => {
|
|
|
42
41
|
const http = 'http://example.com/image.png';
|
|
43
42
|
const https = 'https://example.com/image.png';
|
|
44
43
|
`;
|
|
45
|
-
const result = assetBaseUrlTransform(code
|
|
46
|
-
expect(result).toContain(
|
|
44
|
+
const result = assetBaseUrlTransform(code);
|
|
45
|
+
expect(result).toContain(`(window.skybridge?.serverUrl ?? "") + "/assets/logo.png"`);
|
|
47
46
|
expect(result).toContain("http://example.com/image.png");
|
|
48
47
|
expect(result).toContain("https://example.com/image.png");
|
|
49
48
|
});
|
|
50
49
|
it("should not transform code without asset paths", () => {
|
|
51
50
|
const code = `const text = "Hello World";`;
|
|
52
|
-
const result = assetBaseUrlTransform(code
|
|
51
|
+
const result = assetBaseUrlTransform(code);
|
|
53
52
|
expect(result).toBe(code);
|
|
54
53
|
});
|
|
55
54
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset-base-url-transform-plugin.test.js","sourceRoot":"","sources":["../../src/server/asset-base-url-transform-plugin.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAE7E,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,
|
|
1
|
+
{"version":3,"file":"asset-base-url-transform-plugin.test.js","sourceRoot":"","sources":["../../src/server/asset-base-url-transform-plugin.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAE7E,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,KAAK,GAAG;YACZ;gBACE,IAAI,EAAE,eAAe;gBACrB,IAAI,EAAE,mCAAmC;gBACzC,QAAQ,EAAE,yEAAyE;aACpF;YACD;gBACE,IAAI,EAAE,eAAe;gBACrB,IAAI,EAAE,mCAAmC;gBACzC,QAAQ,EAAE,yEAAyE;aACpF;YACD;gBACE,IAAI,EAAE,iBAAiB;gBACvB,IAAI,EAAE,mCAAmC;gBACzC,QAAQ,EAAE,yEAAyE;aACpF;SACF,CAAC;QAEF,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,KAAK,EAAE,CAAC;YACvC,MAAM,MAAM,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,IAAI,GAAG;;;;KAIZ,CAAC;QACF,MAAM,MAAM,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAE3C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,0DAA0D,CAC3D,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,0DAA0D,CAC3D,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,4DAA4D,CAC7D,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,IAAI,GAAG;;;;KAIZ,CAAC;QACF,MAAM,MAAM,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAE3C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,0DAA0D,CAC3D,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,+BAA+B,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,IAAI,GAAG,6BAA6B,CAAC;QAC3C,MAAM,MAAM,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAE3C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AudioContent, EmbeddedResource, ImageContent, ResourceLink, TextContent } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
type ContentAnnotations = {
|
|
3
|
+
audience?: ("user" | "assistant")[];
|
|
4
|
+
priority?: number;
|
|
5
|
+
lastModified?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function text(value: string, annotations?: ContentAnnotations): TextContent;
|
|
8
|
+
export declare function image(data: string | Uint8Array, mimeType: string, annotations?: ContentAnnotations): ImageContent;
|
|
9
|
+
export declare function audio(data: string | Uint8Array, mimeType: string, annotations?: ContentAnnotations): AudioContent;
|
|
10
|
+
export declare function embeddedResource(resource: {
|
|
11
|
+
uri: string;
|
|
12
|
+
mimeType?: string;
|
|
13
|
+
text: string;
|
|
14
|
+
} | {
|
|
15
|
+
uri: string;
|
|
16
|
+
mimeType?: string;
|
|
17
|
+
blob: string;
|
|
18
|
+
}, annotations?: ContentAnnotations): EmbeddedResource;
|
|
19
|
+
export declare function resourceLink(link: {
|
|
20
|
+
uri: string;
|
|
21
|
+
name: string;
|
|
22
|
+
title?: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
mimeType?: string;
|
|
25
|
+
size?: number;
|
|
26
|
+
}, annotations?: ContentAnnotations): ResourceLink;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a base64-encoded string.
|
|
3
|
+
* - `Uint8Array` input is encoded via `Buffer.toString("base64")`.
|
|
4
|
+
* - `string` input is assumed to be **already base64-encoded** and is returned
|
|
5
|
+
* as-is. Passing raw/unencoded string bytes will produce invalid MCP content.
|
|
6
|
+
*/
|
|
7
|
+
function toBase64(data) {
|
|
8
|
+
if (typeof data === "string") {
|
|
9
|
+
return data;
|
|
10
|
+
}
|
|
11
|
+
return Buffer.from(data).toString("base64");
|
|
12
|
+
}
|
|
13
|
+
export function text(value, annotations) {
|
|
14
|
+
return { type: "text", text: value, ...(annotations && { annotations }) };
|
|
15
|
+
}
|
|
16
|
+
export function image(data, mimeType, annotations) {
|
|
17
|
+
return {
|
|
18
|
+
type: "image",
|
|
19
|
+
data: toBase64(data),
|
|
20
|
+
mimeType,
|
|
21
|
+
...(annotations && { annotations }),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function audio(data, mimeType, annotations) {
|
|
25
|
+
return {
|
|
26
|
+
type: "audio",
|
|
27
|
+
data: toBase64(data),
|
|
28
|
+
mimeType,
|
|
29
|
+
...(annotations && { annotations }),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function embeddedResource(resource, annotations) {
|
|
33
|
+
return {
|
|
34
|
+
type: "resource",
|
|
35
|
+
resource,
|
|
36
|
+
...(annotations && { annotations }),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function resourceLink(link, annotations) {
|
|
40
|
+
return {
|
|
41
|
+
type: "resource_link",
|
|
42
|
+
...link,
|
|
43
|
+
...(annotations && { annotations }),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=content-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-helpers.js","sourceRoot":"","sources":["../../src/server/content-helpers.ts"],"names":[],"mappings":"AAcA;;;;;GAKG;AACH,SAAS,QAAQ,CAAC,IAAyB;IACzC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,IAAI,CAClB,KAAa,EACb,WAAgC;IAEhC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,KAAK,CACnB,IAAyB,EACzB,QAAgB,EAChB,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;QACpB,QAAQ;QACR,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,KAAK,CACnB,IAAyB,EACzB,QAAgB,EAChB,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;QACpB,QAAQ;QACR,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,QAEoD,EACpD,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,QAAQ;QACR,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,IAOC,EACD,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,GAAG,IAAI;QACP,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { audio, embeddedResource, image, resourceLink, text, } from "./content-helpers.js";
|
|
3
|
+
describe("text", () => {
|
|
4
|
+
it("returns a TextContent without annotations when none given", () => {
|
|
5
|
+
expect(text("hello")).toEqual({ type: "text", text: "hello" });
|
|
6
|
+
});
|
|
7
|
+
it("includes annotations when provided", () => {
|
|
8
|
+
expect(text("hi", { priority: 1 })).toEqual({
|
|
9
|
+
type: "text",
|
|
10
|
+
text: "hi",
|
|
11
|
+
annotations: { priority: 1 },
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
describe("image", () => {
|
|
16
|
+
it("base64-encodes Uint8Array data", () => {
|
|
17
|
+
const bytes = new Uint8Array([104, 105]);
|
|
18
|
+
expect(image(bytes, "image/png")).toEqual({
|
|
19
|
+
type: "image",
|
|
20
|
+
data: "aGk=",
|
|
21
|
+
mimeType: "image/png",
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
it("passes string data through unchanged (caller is responsible for base64)", () => {
|
|
25
|
+
expect(image("YWxyZWFkeS1iNjQ=", "image/png")).toEqual({
|
|
26
|
+
type: "image",
|
|
27
|
+
data: "YWxyZWFkeS1iNjQ=",
|
|
28
|
+
mimeType: "image/png",
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
describe("audio", () => {
|
|
33
|
+
it("base64-encodes Uint8Array data", () => {
|
|
34
|
+
const bytes = new Uint8Array([104, 105]);
|
|
35
|
+
expect(audio(bytes, "audio/mpeg")).toMatchObject({
|
|
36
|
+
type: "audio",
|
|
37
|
+
data: "aGk=",
|
|
38
|
+
mimeType: "audio/mpeg",
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe("embeddedResource", () => {
|
|
43
|
+
it("wraps a text resource with a type tag", () => {
|
|
44
|
+
expect(embeddedResource({
|
|
45
|
+
uri: "file:///a.txt",
|
|
46
|
+
mimeType: "text/plain",
|
|
47
|
+
text: "x",
|
|
48
|
+
})).toEqual({
|
|
49
|
+
type: "resource",
|
|
50
|
+
resource: { uri: "file:///a.txt", mimeType: "text/plain", text: "x" },
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
it("wraps a blob resource with a type tag", () => {
|
|
54
|
+
expect(embeddedResource({ uri: "file:///a.bin", blob: "YmFy" })).toEqual({
|
|
55
|
+
type: "resource",
|
|
56
|
+
resource: { uri: "file:///a.bin", blob: "YmFy" },
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe("resourceLink", () => {
|
|
61
|
+
it("spreads link fields alongside the type tag", () => {
|
|
62
|
+
expect(resourceLink({ uri: "file:///a", name: "a", title: "A" })).toEqual({
|
|
63
|
+
type: "resource_link",
|
|
64
|
+
uri: "file:///a",
|
|
65
|
+
name: "a",
|
|
66
|
+
title: "A",
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
//# sourceMappingURL=content-helpers.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-helpers.test.js","sourceRoot":"","sources":["../../src/server/content-helpers.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,KAAK,EACL,gBAAgB,EAChB,KAAK,EACL,YAAY,EACZ,IAAI,GACL,MAAM,sBAAsB,CAAC;AAE9B,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;IACpB,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAC1C,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,IAAI;YACV,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE;SAC7B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACrB,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;YACxC,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,MAAM;YACZ,QAAQ,EAAE,WAAW;SACtB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACjF,MAAM,CAAC,KAAK,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;YACrD,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,kBAAkB;YACxB,QAAQ,EAAE,WAAW;SACtB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACrB,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC;YAC/C,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,MAAM;YACZ,QAAQ,EAAE,YAAY;SACvB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CACJ,gBAAgB,CAAC;YACf,GAAG,EAAE,eAAe;YACpB,QAAQ,EAAE,YAAY;YACtB,IAAI,EAAE,GAAG;SACV,CAAC,CACH,CAAC,OAAO,CAAC;YACR,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE,EAAE,GAAG,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,EAAE;SACtE,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACvE,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE,EAAE,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE;SACjD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACxE,IAAI,EAAE,eAAe;YACrB,GAAG,EAAE,WAAW;YAChB,IAAI,EAAE,GAAG;YACT,KAAK,EAAE,GAAG;SACX,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type http from "node:http";
|
|
2
|
+
import express from "express";
|
|
3
|
+
import type { McpServer } from "./server.js";
|
|
4
|
+
export declare function createApp({ mcpServer, httpServer, customMiddleware, errorMiddleware, }: {
|
|
5
|
+
mcpServer: McpServer;
|
|
6
|
+
httpServer: http.Server;
|
|
7
|
+
customMiddleware?: {
|
|
8
|
+
path?: string;
|
|
9
|
+
handlers: express.RequestHandler[];
|
|
10
|
+
}[];
|
|
11
|
+
errorMiddleware?: {
|
|
12
|
+
path?: string;
|
|
13
|
+
handlers: express.ErrorRequestHandler[];
|
|
14
|
+
}[];
|
|
15
|
+
}): Promise<express.Express>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
3
|
+
import cors from "cors";
|
|
4
|
+
import express from "express";
|
|
5
|
+
function parseControlPort(raw) {
|
|
6
|
+
if (raw === undefined) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const n = Number.parseInt(raw, 10);
|
|
10
|
+
if (!Number.isFinite(n) || n <= 0 || n >= 65536) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return n;
|
|
14
|
+
}
|
|
15
|
+
function applyMiddlewares(app, middlewares) {
|
|
16
|
+
for (const middleware of middlewares) {
|
|
17
|
+
if (middleware.path) {
|
|
18
|
+
app.use(middleware.path, ...middleware.handlers);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
app.use(...middleware.handlers);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function defaultErrorHandler(err, _req, res, _next) {
|
|
26
|
+
console.error("Error handling MCP request:", err);
|
|
27
|
+
if (!res.headersSent) {
|
|
28
|
+
res.status(500).json({
|
|
29
|
+
jsonrpc: "2.0",
|
|
30
|
+
error: { code: -32603, message: "Internal server error" },
|
|
31
|
+
id: null,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export async function createApp({ mcpServer, httpServer, customMiddleware = [], errorMiddleware = [], }) {
|
|
36
|
+
const app = express();
|
|
37
|
+
app.use(express.json());
|
|
38
|
+
const env = process.env.NODE_ENV || "development";
|
|
39
|
+
applyMiddlewares(app, customMiddleware);
|
|
40
|
+
if (env !== "production") {
|
|
41
|
+
const { devtoolsStaticServer } = await import("@skybridge/devtools");
|
|
42
|
+
app.use(await devtoolsStaticServer());
|
|
43
|
+
const { viewsDevServer } = await import("./viewsDevServer.js");
|
|
44
|
+
app.use(await viewsDevServer(httpServer));
|
|
45
|
+
const controlPort = parseControlPort(process.env.__TUNNEL_CONTROL_PORT);
|
|
46
|
+
if (controlPort !== null) {
|
|
47
|
+
const { createTunnelProxyRouter } = await import("./tunnel-proxy-router.js");
|
|
48
|
+
app.use(createTunnelProxyRouter(controlPort));
|
|
49
|
+
}
|
|
50
|
+
else if (process.env.__TUNNEL_CONTROL_PORT !== undefined) {
|
|
51
|
+
console.warn(`Ignoring invalid __TUNNEL_CONTROL_PORT=${process.env.__TUNNEL_CONTROL_PORT}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (env === "production") {
|
|
55
|
+
const assetsPath = path.join(process.cwd(), "dist", "assets");
|
|
56
|
+
app.use("/assets", cors());
|
|
57
|
+
app.use("/assets", express.static(assetsPath));
|
|
58
|
+
}
|
|
59
|
+
app.use("/mcp", mcpMiddleware(mcpServer));
|
|
60
|
+
applyMiddlewares(app, errorMiddleware);
|
|
61
|
+
app.use("/mcp", defaultErrorHandler);
|
|
62
|
+
return app;
|
|
63
|
+
}
|
|
64
|
+
const mcpMiddleware = (server) => {
|
|
65
|
+
return async (req, res, next) => {
|
|
66
|
+
if (req.method !== "POST") {
|
|
67
|
+
res.writeHead(405).end(JSON.stringify({
|
|
68
|
+
jsonrpc: "2.0",
|
|
69
|
+
error: {
|
|
70
|
+
code: -32000,
|
|
71
|
+
message: "Method not allowed.",
|
|
72
|
+
},
|
|
73
|
+
id: null,
|
|
74
|
+
}));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const transport = new StreamableHTTPServerTransport({
|
|
79
|
+
sessionIdGenerator: undefined,
|
|
80
|
+
});
|
|
81
|
+
res.on("close", () => {
|
|
82
|
+
transport.close();
|
|
83
|
+
});
|
|
84
|
+
await server.connectStatelessTransport(transport);
|
|
85
|
+
// Express strips the mount path from req.url (e.g. "/mcp" becomes "/").
|
|
86
|
+
// Restore it so the SDK builds the correct requestInfo.url.
|
|
87
|
+
req.url = req.originalUrl;
|
|
88
|
+
await transport.handleRequest(req, res, req.body);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
next(error);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=express.js.map
|