skybridge 0.0.0-dev.81fd90a → 0.0.0-dev.8226541
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 +14 -14
- package/dist/cli/build-helpers.d.ts +1 -1
- package/dist/cli/build-helpers.js +4 -4
- package/dist/cli/build-helpers.js.map +1 -1
- package/dist/cli/build-helpers.test.js +2 -2
- package/dist/cli/build-helpers.test.js.map +1 -1
- package/dist/cli/build-steps.js +1 -1
- package/dist/cli/build-steps.js.map +1 -1
- package/dist/cli/build-steps.test.js +3 -3
- package/dist/cli/build-steps.test.js.map +1 -1
- package/dist/cli/detect-port.js +0 -1
- package/dist/cli/detect-port.js.map +1 -1
- package/dist/cli/run-plain.js +2 -1
- package/dist/cli/run-plain.js.map +1 -1
- package/dist/cli/telemetry.js +2 -0
- package/dist/cli/telemetry.js.map +1 -1
- package/dist/cli/use-nodemon.d.ts +11 -1
- package/dist/cli/use-nodemon.js +30 -8
- package/dist/cli/use-nodemon.js.map +1 -1
- package/dist/cli/use-typescript-check.js +1 -1
- package/dist/cli/use-typescript-check.js.map +1 -1
- package/dist/commands/dev.js +4 -4
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/start.js +2 -2
- package/dist/commands/start.js.map +1 -1
- package/dist/server/app.d.ts +194 -0
- package/dist/server/app.js +266 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/app.test.js +97 -0
- package/dist/server/app.test.js.map +1 -0
- package/dist/server/auth/discovery.d.ts +1 -1
- package/dist/server/auth/discovery.js +1 -1
- package/dist/server/auth/discovery.js.map +1 -1
- package/dist/server/auth/index.d.ts +19 -1
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/auth/providers/auth0.d.ts +2 -2
- package/dist/server/auth/providers/auth0.js +13 -8
- package/dist/server/auth/providers/auth0.js.map +1 -1
- package/dist/server/auth/providers/auth0.test.js +1 -1
- package/dist/server/auth/providers/auth0.test.js.map +1 -1
- package/dist/server/auth/providers/authplane.d.ts +2 -2
- package/dist/server/auth/providers/authplane.js.map +1 -1
- package/dist/server/auth/providers/authplane.test.js +10 -7
- package/dist/server/auth/providers/authplane.test.js.map +1 -1
- package/dist/server/auth/providers/clerk.d.ts +2 -2
- package/dist/server/auth/providers/clerk.js.map +1 -1
- package/dist/server/auth/providers/clerk.test.js +1 -1
- package/dist/server/auth/providers/clerk.test.js.map +1 -1
- package/dist/server/auth/providers/custom.d.ts +7 -5
- package/dist/server/auth/providers/custom.js +5 -2
- package/dist/server/auth/providers/custom.js.map +1 -1
- package/dist/server/auth/providers/custom.test.js +13 -10
- package/dist/server/auth/providers/custom.test.js.map +1 -1
- package/dist/server/auth/providers/descope.d.ts +2 -2
- package/dist/server/auth/providers/descope.js.map +1 -1
- package/dist/server/auth/providers/descope.test.js +3 -3
- package/dist/server/auth/providers/descope.test.js.map +1 -1
- package/dist/server/auth/providers/stytch.d.ts +2 -2
- package/dist/server/auth/providers/stytch.js.map +1 -1
- package/dist/server/auth/providers/workos.d.ts +5 -4
- package/dist/server/auth/providers/workos.js +2 -1
- package/dist/server/auth/providers/workos.js.map +1 -1
- package/dist/server/auth/setup.d.ts +1 -1
- package/dist/server/auth/setup.js.map +1 -1
- package/dist/server/auth/setup.test.js +74 -58
- package/dist/server/auth/setup.test.js.map +1 -1
- package/dist/server/auth/verify.d.ts +5 -3
- package/dist/server/auth/verify.js.map +1 -1
- package/dist/server/auth/verify.test.js +16 -0
- package/dist/server/auth/verify.test.js.map +1 -1
- package/dist/server/auth-extra.test-d.js +93 -34
- package/dist/server/auth-extra.test-d.js.map +1 -1
- package/dist/server/auth.d.ts +4 -4
- package/dist/server/auth.js +2 -2
- package/dist/server/auth.js.map +1 -1
- package/dist/server/build-manifest.test.js +7 -6
- package/dist/server/build-manifest.test.js.map +1 -1
- package/dist/server/events.d.ts +113 -0
- package/dist/server/events.js +318 -0
- package/dist/server/events.js.map +1 -0
- package/dist/server/events.test.js +172 -0
- package/dist/server/events.test.js.map +1 -0
- package/dist/server/express.d.ts +23 -3
- package/dist/server/express.js +40 -10
- package/dist/server/express.js.map +1 -1
- package/dist/server/express.test.js +193 -110
- package/dist/server/express.test.js.map +1 -1
- package/dist/server/file-ref.d.ts +1 -1
- package/dist/server/file-ref.js +1 -1
- package/dist/server/file-ref.js.map +1 -1
- package/dist/server/form-input.d.ts +120 -0
- package/dist/server/form-input.js +89 -0
- package/dist/server/form-input.js.map +1 -0
- package/dist/server/index.d.ts +8 -4
- package/dist/server/index.js +5 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp-errors.test.js +9 -5
- package/dist/server/mcp-errors.test.js.map +1 -1
- package/dist/server/middleware.test.js +221 -148
- package/dist/server/middleware.test.js.map +1 -1
- package/dist/server/register-tool.test.js +212 -7
- package/dist/server/register-tool.test.js.map +1 -1
- package/dist/server/server.d.ts +323 -150
- package/dist/server/server.js +349 -324
- package/dist/server/server.js.map +1 -1
- package/dist/server/skills-integration.test.js +16 -9
- package/dist/server/skills-integration.test.js.map +1 -1
- package/dist/server/skills.js +1 -1
- package/dist/server/skills.js.map +1 -1
- package/dist/server/templateHelper.d.ts +0 -3
- package/dist/server/templateHelper.js.map +1 -1
- package/dist/server/templates.generated.js +4 -8
- package/dist/server/templates.generated.js.map +1 -1
- package/dist/server/tool-extra.test.js +115 -20
- package/dist/server/tool-extra.test.js.map +1 -1
- package/dist/server/view-resource-resolution.test.js +17 -10
- package/dist/server/view-resource-resolution.test.js.map +1 -1
- package/dist/test/utils.d.ts +7 -6
- package/dist/test/utils.js +212 -197
- package/dist/test/utils.js.map +1 -1
- package/dist/test/view.test.js +24 -20
- package/dist/test/view.test.js.map +1 -1
- package/dist/views/index.d.ts +10 -0
- package/dist/views/index.js +3 -0
- package/dist/views/index.js.map +1 -0
- package/dist/{web/plugin → views}/scan-views.js +1 -1
- package/dist/views/scan-views.js.map +1 -0
- package/dist/views/scan-views.test.js.map +1 -0
- package/dist/views/validate-view.d.ts +1 -0
- package/dist/{web/plugin → views}/validate-view.js +2 -2
- package/dist/views/validate-view.js.map +1 -0
- package/dist/views/validate-view.test.js.map +1 -0
- package/dist/web/bridges/adaptor.d.ts +14 -3
- package/dist/web/bridges/adaptor.js +157 -13
- package/dist/web/bridges/adaptor.js.map +1 -1
- package/dist/web/bridges/adaptor.test.js +46 -7
- package/dist/web/bridges/adaptor.test.js.map +1 -1
- package/dist/web/bridges/apps-sdk/bridge.js +1 -1
- package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
- package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +3 -3
- package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +3 -3
- package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
- package/dist/web/bridges/get-adaptor.test.js +2 -2
- package/dist/web/bridges/get-adaptor.test.js.map +1 -1
- package/dist/web/bridges/mcp-app/bridge.d.ts +1 -1
- package/dist/web/bridges/mcp-app/bridge.js +10 -3
- package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
- package/dist/web/bridges/mcp-app/bridge.test.js +2 -2
- package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -1
- package/dist/web/bridges/mcp-app/types.d.ts +18 -3
- package/dist/web/bridges/mcp-app/types.js.map +1 -1
- package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +2 -2
- package/dist/web/bridges/mcp-app/use-mcp-app-context.js +1 -1
- 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 -1
- package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
- package/dist/web/bridges/mcp-app/view-tools.test.js +1 -1
- package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -1
- package/dist/web/bridges/types.d.ts +63 -13
- package/dist/web/bridges/types.js +1 -1
- package/dist/web/bridges/types.js.map +1 -1
- package/dist/web/create-store.test.js +2 -2
- package/dist/web/create-store.test.js.map +1 -1
- package/dist/web/data-llm.js +3 -2
- package/dist/web/data-llm.js.map +1 -1
- package/dist/web/data-llm.test.js +8 -2
- package/dist/web/data-llm.test.js.map +1 -1
- package/dist/web/generate-helpers.d.ts +23 -19
- package/dist/web/generate-helpers.js +21 -17
- package/dist/web/generate-helpers.js.map +1 -1
- package/dist/web/generate-helpers.test-d.js +3 -3
- package/dist/web/generate-helpers.test-d.js.map +1 -1
- package/dist/web/generate-helpers.test.js +2 -2
- package/dist/web/generate-helpers.test.js.map +1 -1
- package/dist/web/hooks/index.d.ts +5 -1
- package/dist/web/hooks/index.js +5 -1
- package/dist/web/hooks/index.js.map +1 -1
- package/dist/web/hooks/openai-extensions.test.js +107 -0
- package/dist/web/hooks/openai-extensions.test.js.map +1 -0
- package/dist/web/hooks/use-call-tool.d.ts +2 -2
- package/dist/web/hooks/use-call-tool.js +15 -10
- package/dist/web/hooks/use-call-tool.js.map +1 -1
- package/dist/web/hooks/use-call-tool.test.js +15 -4
- package/dist/web/hooks/use-call-tool.test.js.map +1 -1
- package/dist/web/hooks/use-deep-link.d.ts +22 -0
- package/dist/web/hooks/use-deep-link.js +34 -0
- package/dist/web/hooks/use-deep-link.js.map +1 -0
- package/dist/web/hooks/use-display-mode.test.js +1 -1
- package/dist/web/hooks/use-display-mode.test.js.map +1 -1
- package/dist/web/hooks/use-download.test.js +3 -3
- package/dist/web/hooks/use-download.test.js.map +1 -1
- package/dist/web/hooks/use-file-resource.d.ts +37 -0
- package/dist/web/hooks/use-file-resource.js +98 -0
- package/dist/web/hooks/use-file-resource.js.map +1 -0
- package/dist/web/hooks/use-file-resource.test.js +65 -0
- package/dist/web/hooks/use-file-resource.test.js.map +1 -0
- package/dist/web/hooks/use-files.test.js +1 -1
- package/dist/web/hooks/use-files.test.js.map +1 -1
- package/dist/web/hooks/use-host.d.ts +27 -5
- package/dist/web/hooks/use-host.js +20 -5
- package/dist/web/hooks/use-host.js.map +1 -1
- package/dist/web/hooks/use-host.test.js +1 -1
- package/dist/web/hooks/use-host.test.js.map +1 -1
- package/dist/web/hooks/use-model-context.d.ts +44 -0
- package/dist/web/hooks/use-model-context.js +63 -0
- package/dist/web/hooks/use-model-context.js.map +1 -0
- package/dist/web/hooks/use-open-external.test.js +2 -2
- package/dist/web/hooks/use-open-external.test.js.map +1 -1
- package/dist/web/hooks/use-open-file.d.ts +20 -0
- package/dist/web/hooks/use-open-file.js +25 -0
- package/dist/web/hooks/use-open-file.js.map +1 -0
- package/dist/web/hooks/use-register-view-tool.d.ts +1 -1
- package/dist/web/hooks/use-register-view-tool.js +1 -1
- package/dist/web/hooks/use-register-view-tool.js.map +1 -1
- package/dist/web/hooks/use-request-close.test.js +1 -1
- package/dist/web/hooks/use-request-close.test.js.map +1 -1
- package/dist/web/hooks/use-request-modal.test.js +1 -1
- package/dist/web/hooks/use-request-modal.test.js.map +1 -1
- package/dist/web/hooks/use-request-size.test.js +1 -1
- package/dist/web/hooks/use-request-size.test.js.map +1 -1
- package/dist/web/hooks/use-send-follow-up-message.d.ts +8 -2
- package/dist/web/hooks/use-send-follow-up-message.js +6 -0
- package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
- package/dist/web/hooks/use-set-open-in-app-url.test.js +2 -8
- package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
- package/dist/web/hooks/use-tool-info.test.js +2 -2
- package/dist/web/hooks/use-tool-info.test.js.map +1 -1
- package/dist/web/hooks/use-user.test.js +2 -2
- package/dist/web/hooks/use-user.test.js.map +1 -1
- package/dist/web/hooks/use-view-state.test.js +2 -2
- package/dist/web/hooks/use-view-state.test.js.map +1 -1
- package/dist/web/hooks/use-viewport.test.js +2 -2
- package/dist/web/hooks/use-viewport.test.js.map +1 -1
- package/dist/web/index.d.ts +0 -1
- package/dist/web/index.js.map +1 -1
- package/dist/web/mount-view.js +2 -6
- package/dist/web/mount-view.js.map +1 -1
- package/package.json +15 -15
- package/dist/standard-schema.d.ts +0 -3
- package/dist/standard-schema.js +0 -2
- package/dist/standard-schema.js.map +0 -1
- package/dist/web/plugin/data-llm.test.js +0 -81
- package/dist/web/plugin/data-llm.test.js.map +0 -1
- package/dist/web/plugin/plugin-build.test.js +0 -54
- package/dist/web/plugin/plugin-build.test.js.map +0 -1
- package/dist/web/plugin/plugin.d.ts +0 -39
- package/dist/web/plugin/plugin.js +0 -200
- package/dist/web/plugin/plugin.js.map +0 -1
- package/dist/web/plugin/plugin.test.js +0 -61
- package/dist/web/plugin/plugin.test.js.map +0 -1
- package/dist/web/plugin/scan-views.js.map +0 -1
- package/dist/web/plugin/scan-views.test.js.map +0 -1
- package/dist/web/plugin/transform-data-llm.d.ts +0 -12
- package/dist/web/plugin/transform-data-llm.js +0 -96
- package/dist/web/plugin/transform-data-llm.js.map +0 -1
- package/dist/web/plugin/transform-data-llm.test.js +0 -81
- package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
- package/dist/web/plugin/validate-view.d.ts +0 -1
- package/dist/web/plugin/validate-view.js.map +0 -1
- package/dist/web/plugin/validate-view.test.js.map +0 -1
- /package/dist/{web/plugin/data-llm.test.d.ts → server/app.test.d.ts} +0 -0
- /package/dist/{web/plugin/plugin-build.test.d.ts → server/events.test.d.ts} +0 -0
- /package/dist/{web/plugin → views}/scan-views.d.ts +0 -0
- /package/dist/{web/plugin → views}/scan-views.test.d.ts +0 -0
- /package/dist/{web/plugin → views}/scan-views.test.js +0 -0
- /package/dist/{web/plugin → views}/validate-view.test.d.ts +0 -0
- /package/dist/{web/plugin → views}/validate-view.test.js +0 -0
- /package/dist/web/{plugin/plugin.test.d.ts → hooks/openai-extensions.test.d.ts} +0 -0
- /package/dist/web/{plugin/transform-data-llm.test.d.ts → hooks/use-file-resource.test.d.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import http from "node:http";
|
|
2
2
|
import { Client, StreamableHTTPClientTransport, } from "@modelcontextprotocol/client";
|
|
3
3
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
4
|
-
import {
|
|
4
|
+
import { Skybridge } from "./app.js";
|
|
5
5
|
vi.mock("@skybridge/devtools", () => ({
|
|
6
6
|
devtoolsStaticServer: () => ((_req, _res, next) => next()),
|
|
7
7
|
}));
|
|
@@ -26,36 +26,49 @@ async function postMcp(port) {
|
|
|
26
26
|
async function postApi(port) {
|
|
27
27
|
return fetch(`http://localhost:${port}/api/test`, { method: "POST" });
|
|
28
28
|
}
|
|
29
|
-
describe("
|
|
29
|
+
describe("Skybridge.express", () => {
|
|
30
30
|
it("exposes a ready Express app immediately after construction", () => {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
const app = new Skybridge({
|
|
32
|
+
name: "t",
|
|
33
|
+
version: "0.0.0",
|
|
34
|
+
handler: (server) => server,
|
|
35
|
+
});
|
|
36
|
+
expect(app.express).toBeDefined();
|
|
37
|
+
expect(typeof app.express.use).toBe("function");
|
|
38
|
+
expect(typeof app.express.get).toBe("function");
|
|
35
39
|
});
|
|
36
|
-
it("
|
|
40
|
+
it("app.express.get registers a route reachable alongside /mcp", async () => {
|
|
37
41
|
const { createApp } = await import("./express.js");
|
|
38
|
-
const
|
|
39
|
-
|
|
42
|
+
const app = new Skybridge({
|
|
43
|
+
name: "t",
|
|
44
|
+
version: "0.0.0",
|
|
45
|
+
handler: (server) => server,
|
|
46
|
+
});
|
|
47
|
+
app.express.get("/health", (_req, res) => {
|
|
40
48
|
res.json({ status: "ok" });
|
|
41
49
|
});
|
|
42
50
|
const httpServer = http.createServer();
|
|
43
|
-
await createApp({
|
|
44
|
-
const { port, server: listening } = await listen(
|
|
51
|
+
await createApp({ app, httpServer });
|
|
52
|
+
const { port, server: listening } = await listen(app.express);
|
|
45
53
|
openServer = listening;
|
|
46
54
|
const health = await fetch(`http://localhost:${port}/health`);
|
|
47
55
|
expect(health.status).toBe(200);
|
|
56
|
+
expect(health.headers.get("x-powered-by")).toBe("skybridge");
|
|
48
57
|
expect(await health.json()).toEqual({ status: "ok" });
|
|
49
58
|
// /mcp still works (POST returns 200/4xx, not 404)
|
|
50
59
|
const mcp = await postMcp(port);
|
|
51
60
|
expect(mcp.status).not.toBe(404);
|
|
52
61
|
});
|
|
53
|
-
it("
|
|
62
|
+
it("app.use and app.express.use produce the same registration order", async () => {
|
|
54
63
|
const { createApp } = await import("./express.js");
|
|
55
64
|
const callsA = [];
|
|
56
65
|
const callsB = [];
|
|
57
|
-
const
|
|
58
|
-
|
|
66
|
+
const buildApp = () => new Skybridge({
|
|
67
|
+
name: "t",
|
|
68
|
+
version: "0.0.0",
|
|
69
|
+
handler: (server) => server,
|
|
70
|
+
});
|
|
71
|
+
const sA = buildApp();
|
|
59
72
|
sA.use((_req, _res, next) => {
|
|
60
73
|
callsA.push("first");
|
|
61
74
|
next();
|
|
@@ -64,7 +77,7 @@ describe("McpServer.express", () => {
|
|
|
64
77
|
callsA.push("second");
|
|
65
78
|
next();
|
|
66
79
|
});
|
|
67
|
-
const sB =
|
|
80
|
+
const sB = buildApp();
|
|
68
81
|
sB.express.use((_req, _res, next) => {
|
|
69
82
|
callsB.push("first");
|
|
70
83
|
next();
|
|
@@ -76,7 +89,7 @@ describe("McpServer.express", () => {
|
|
|
76
89
|
for (const s of [sA, sB]) {
|
|
77
90
|
s.express.get("/probe", (_req, res) => res.json({ ok: true }));
|
|
78
91
|
const httpServer = http.createServer();
|
|
79
|
-
await createApp({
|
|
92
|
+
await createApp({ app: s, httpServer });
|
|
80
93
|
const { port, server: listening } = await listen(s.express);
|
|
81
94
|
openServer = listening;
|
|
82
95
|
await fetch(`http://localhost:${port}/probe`);
|
|
@@ -87,28 +100,32 @@ describe("McpServer.express", () => {
|
|
|
87
100
|
});
|
|
88
101
|
it("useOnError still wraps thrown /mcp errors after the route is mounted", async () => {
|
|
89
102
|
const { createApp } = await import("./express.js");
|
|
90
|
-
const
|
|
103
|
+
const app = new Skybridge({
|
|
104
|
+
name: "t",
|
|
105
|
+
version: "0.0.0",
|
|
106
|
+
handler: (server) => server,
|
|
107
|
+
});
|
|
91
108
|
// Register the error handler BEFORE createApp — useOnError should still
|
|
92
109
|
// apply it after /mcp, so /mcp errors hit it.
|
|
93
110
|
const seen = [];
|
|
94
|
-
|
|
111
|
+
app.useOnError((_err, _req, res, _next) => {
|
|
95
112
|
seen.push("useOnError");
|
|
96
113
|
res.status(503).json({ from: "useOnError" });
|
|
97
114
|
});
|
|
98
115
|
// Force the /mcp handler to throw so the error pipeline runs.
|
|
99
|
-
|
|
116
|
+
app.use("/mcp", () => {
|
|
100
117
|
throw new Error("boom");
|
|
101
118
|
});
|
|
102
119
|
const httpServer = http.createServer();
|
|
103
120
|
await createApp({
|
|
104
|
-
|
|
121
|
+
app,
|
|
105
122
|
httpServer,
|
|
106
|
-
// Mirror what run() does: forward the
|
|
123
|
+
// Mirror what run() does: forward the app's useOnError handlers
|
|
107
124
|
// to createApp so they get applied after /mcp.
|
|
108
125
|
// biome-ignore lint/complexity/useLiteralKeys: test mirrors run() internals to verify useOnError ordering
|
|
109
|
-
errorMiddleware:
|
|
126
|
+
errorMiddleware: app["errorMiddleware"],
|
|
110
127
|
});
|
|
111
|
-
const { port, server: listening } = await listen(
|
|
128
|
+
const { port, server: listening } = await listen(app.express);
|
|
112
129
|
openServer = listening;
|
|
113
130
|
const res = await postMcp(port);
|
|
114
131
|
expect(seen).toEqual(["useOnError"]);
|
|
@@ -116,7 +133,7 @@ describe("McpServer.express", () => {
|
|
|
116
133
|
expect(await res.json()).toEqual({ from: "useOnError" });
|
|
117
134
|
});
|
|
118
135
|
});
|
|
119
|
-
describe("
|
|
136
|
+
describe("Skybridge JSON body parser options", () => {
|
|
120
137
|
const largeBody = JSON.stringify({ data: "x".repeat(200 * 1024) });
|
|
121
138
|
async function postEcho(port, body) {
|
|
122
139
|
return fetch(`http://localhost:${port}/echo`, {
|
|
@@ -126,22 +143,31 @@ describe("McpServer JSON body parser options", () => {
|
|
|
126
143
|
});
|
|
127
144
|
}
|
|
128
145
|
it("forwards json options to express.json", async () => {
|
|
129
|
-
const
|
|
130
|
-
|
|
146
|
+
const app = new Skybridge({
|
|
147
|
+
name: "t",
|
|
148
|
+
version: "0.0.0",
|
|
149
|
+
json: { limit: "10mb" },
|
|
150
|
+
handler: (server) => server,
|
|
151
|
+
});
|
|
152
|
+
app.express.post("/echo", (req, res) => {
|
|
131
153
|
res.json({ received: req.body.data.length });
|
|
132
154
|
});
|
|
133
|
-
const { port, server: listening } = await listen(
|
|
155
|
+
const { port, server: listening } = await listen(app.express);
|
|
134
156
|
openServer = listening;
|
|
135
157
|
const res = await postEcho(port, largeBody);
|
|
136
158
|
expect(res.status).toBe(200);
|
|
137
159
|
expect(await res.json()).toEqual({ received: 200 * 1024 });
|
|
138
160
|
});
|
|
139
161
|
it("keeps the default 100kb limit when no options are passed", async () => {
|
|
140
|
-
const
|
|
141
|
-
|
|
162
|
+
const app = new Skybridge({
|
|
163
|
+
name: "t",
|
|
164
|
+
version: "0.0.0",
|
|
165
|
+
handler: (server) => server,
|
|
166
|
+
});
|
|
167
|
+
app.express.post("/echo", (_req, res) => {
|
|
142
168
|
res.json({ ok: true });
|
|
143
169
|
});
|
|
144
|
-
const { port, server: listening } = await listen(
|
|
170
|
+
const { port, server: listening } = await listen(app.express);
|
|
145
171
|
openServer = listening;
|
|
146
172
|
const res = await postEcho(port, largeBody);
|
|
147
173
|
expect(res.status).toBe(413);
|
|
@@ -155,11 +181,15 @@ describe("createApp", () => {
|
|
|
155
181
|
calls.push("custom");
|
|
156
182
|
next();
|
|
157
183
|
};
|
|
158
|
-
const
|
|
159
|
-
|
|
184
|
+
const app = new Skybridge({
|
|
185
|
+
name: "t",
|
|
186
|
+
version: "0.0.0",
|
|
187
|
+
handler: (server) => server,
|
|
188
|
+
});
|
|
189
|
+
app.use(mw);
|
|
160
190
|
const httpServer = http.createServer();
|
|
161
|
-
const
|
|
162
|
-
const { port, server: httpListening } = await listen(
|
|
191
|
+
const expressApp = await createApp({ app, httpServer });
|
|
192
|
+
const { port, server: httpListening } = await listen(expressApp);
|
|
163
193
|
openServer = httpListening;
|
|
164
194
|
await postMcp(port);
|
|
165
195
|
expect(calls).toEqual(["custom"]);
|
|
@@ -171,11 +201,15 @@ describe("createApp", () => {
|
|
|
171
201
|
calls.push("auth");
|
|
172
202
|
next();
|
|
173
203
|
};
|
|
174
|
-
const
|
|
175
|
-
|
|
204
|
+
const app = new Skybridge({
|
|
205
|
+
name: "t",
|
|
206
|
+
version: "0.0.0",
|
|
207
|
+
handler: (server) => server,
|
|
208
|
+
});
|
|
209
|
+
app.use("/mcp", mw);
|
|
176
210
|
const httpServer = http.createServer();
|
|
177
|
-
const
|
|
178
|
-
const { port, server: httpListening } = await listen(
|
|
211
|
+
const expressApp = await createApp({ app, httpServer });
|
|
212
|
+
const { port, server: httpListening } = await listen(expressApp);
|
|
179
213
|
openServer = httpListening;
|
|
180
214
|
await postMcp(port);
|
|
181
215
|
expect(calls).toEqual(["auth"]);
|
|
@@ -187,11 +221,15 @@ describe("createApp", () => {
|
|
|
187
221
|
calls.push("reject");
|
|
188
222
|
res.status(401).json({ error: "Unauthorized" });
|
|
189
223
|
};
|
|
190
|
-
const
|
|
191
|
-
|
|
224
|
+
const app = new Skybridge({
|
|
225
|
+
name: "t",
|
|
226
|
+
version: "0.0.0",
|
|
227
|
+
handler: (server) => server,
|
|
228
|
+
});
|
|
229
|
+
app.use("/mcp", reject);
|
|
192
230
|
const httpServer = http.createServer();
|
|
193
|
-
const
|
|
194
|
-
const { port, server: httpListening } = await listen(
|
|
231
|
+
const expressApp = await createApp({ app, httpServer });
|
|
232
|
+
const { port, server: httpListening } = await listen(expressApp);
|
|
195
233
|
openServer = httpListening;
|
|
196
234
|
const res = await postMcp(port);
|
|
197
235
|
expect(calls).toEqual(["reject"]);
|
|
@@ -209,12 +247,16 @@ describe("createApp", () => {
|
|
|
209
247
|
calls.push("B");
|
|
210
248
|
next();
|
|
211
249
|
};
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
250
|
+
const app = new Skybridge({
|
|
251
|
+
name: "t",
|
|
252
|
+
version: "0.0.0",
|
|
253
|
+
handler: (server) => server,
|
|
254
|
+
});
|
|
255
|
+
app.use(mwA);
|
|
256
|
+
app.use(mwB);
|
|
215
257
|
const httpServer = http.createServer();
|
|
216
|
-
const
|
|
217
|
-
const { port, server: httpListening } = await listen(
|
|
258
|
+
const expressApp = await createApp({ app, httpServer });
|
|
259
|
+
const { port, server: httpListening } = await listen(expressApp);
|
|
218
260
|
openServer = httpListening;
|
|
219
261
|
await postMcp(port);
|
|
220
262
|
expect(calls).toEqual(["A", "B"]);
|
|
@@ -226,11 +268,15 @@ describe("createApp", () => {
|
|
|
226
268
|
calls.push("api");
|
|
227
269
|
next();
|
|
228
270
|
};
|
|
229
|
-
const
|
|
230
|
-
|
|
271
|
+
const app = new Skybridge({
|
|
272
|
+
name: "t",
|
|
273
|
+
version: "0.0.0",
|
|
274
|
+
handler: (server) => server,
|
|
275
|
+
});
|
|
276
|
+
app.use("/api", apiMw);
|
|
231
277
|
const httpServer = http.createServer();
|
|
232
|
-
const
|
|
233
|
-
const { port, server: httpListening } = await listen(
|
|
278
|
+
const expressApp = await createApp({ app, httpServer });
|
|
279
|
+
const { port, server: httpListening } = await listen(expressApp);
|
|
234
280
|
openServer = httpListening;
|
|
235
281
|
// Hit /mcp — the /api middleware should NOT fire
|
|
236
282
|
await postMcp(port);
|
|
@@ -243,11 +289,15 @@ describe("createApp", () => {
|
|
|
243
289
|
router.get("/health", (_req, res) => {
|
|
244
290
|
res.json({ status: "ok" });
|
|
245
291
|
});
|
|
246
|
-
const
|
|
247
|
-
|
|
292
|
+
const app = new Skybridge({
|
|
293
|
+
name: "t",
|
|
294
|
+
version: "0.0.0",
|
|
295
|
+
handler: (server) => server,
|
|
296
|
+
});
|
|
297
|
+
app.use(router);
|
|
248
298
|
const httpServer = http.createServer();
|
|
249
|
-
const
|
|
250
|
-
const { port, server: httpListening } = await listen(
|
|
299
|
+
const expressApp = await createApp({ app, httpServer });
|
|
300
|
+
const { port, server: httpListening } = await listen(expressApp);
|
|
251
301
|
openServer = httpListening;
|
|
252
302
|
const res = await fetch(`http://localhost:${port}/health`);
|
|
253
303
|
expect(res.status).toBe(200);
|
|
@@ -260,11 +310,15 @@ describe("createApp", () => {
|
|
|
260
310
|
router.get("/data", (_req, res) => {
|
|
261
311
|
res.json({ value: 42 });
|
|
262
312
|
});
|
|
263
|
-
const
|
|
264
|
-
|
|
313
|
+
const app = new Skybridge({
|
|
314
|
+
name: "t",
|
|
315
|
+
version: "0.0.0",
|
|
316
|
+
handler: (server) => server,
|
|
317
|
+
});
|
|
318
|
+
app.use("/api", router);
|
|
265
319
|
const httpServer = http.createServer();
|
|
266
|
-
const
|
|
267
|
-
const { port, server: httpListening } = await listen(
|
|
320
|
+
const expressApp = await createApp({ app, httpServer });
|
|
321
|
+
const { port, server: httpListening } = await listen(expressApp);
|
|
268
322
|
openServer = httpListening;
|
|
269
323
|
const res = await fetch(`http://localhost:${port}/api/data`);
|
|
270
324
|
expect(res.status).toBe(200);
|
|
@@ -275,11 +329,15 @@ describe("createApp", () => {
|
|
|
275
329
|
const throwing = () => {
|
|
276
330
|
throw new Error("boom");
|
|
277
331
|
};
|
|
278
|
-
const
|
|
279
|
-
|
|
332
|
+
const app = new Skybridge({
|
|
333
|
+
name: "t",
|
|
334
|
+
version: "0.0.0",
|
|
335
|
+
handler: (server) => server,
|
|
336
|
+
});
|
|
337
|
+
app.use("/explode", throwing);
|
|
280
338
|
const httpServer = http.createServer();
|
|
281
|
-
const
|
|
282
|
-
const { port, server: httpListening } = await listen(
|
|
339
|
+
const expressApp = await createApp({ app, httpServer });
|
|
340
|
+
const { port, server: httpListening } = await listen(expressApp);
|
|
283
341
|
openServer = httpListening;
|
|
284
342
|
const res = await fetch(`http://localhost:${port}/explode`);
|
|
285
343
|
expect(res.status).toBe(500);
|
|
@@ -290,15 +348,19 @@ describe("createApp", () => {
|
|
|
290
348
|
it("returns 500 JSON-RPC error when the MCP handler throws and no error middleware is registered", async () => {
|
|
291
349
|
const { createApp } = await import("./express.js");
|
|
292
350
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
293
|
-
const
|
|
351
|
+
const app = new Skybridge({
|
|
352
|
+
name: "t",
|
|
353
|
+
version: "0.0.0",
|
|
354
|
+
handler: (server) => server,
|
|
355
|
+
});
|
|
294
356
|
// Force the express-level error path: make a /mcp middleware throw so the
|
|
295
357
|
// error pipeline runs and lands in the default /mcp error handler.
|
|
296
|
-
|
|
358
|
+
app.use("/mcp", () => {
|
|
297
359
|
throw new Error("boom");
|
|
298
360
|
});
|
|
299
361
|
const httpServer = http.createServer();
|
|
300
|
-
const
|
|
301
|
-
const { port, server: httpListening } = await listen(
|
|
362
|
+
const expressApp = await createApp({ app, httpServer });
|
|
363
|
+
const { port, server: httpListening } = await listen(expressApp);
|
|
302
364
|
openServer = httpListening;
|
|
303
365
|
const res = await postMcp(port);
|
|
304
366
|
expect(res.status).toBe(500);
|
|
@@ -317,17 +379,21 @@ describe("createApp", () => {
|
|
|
317
379
|
calls.push("error-handler");
|
|
318
380
|
res.status(503).json({ custom: true });
|
|
319
381
|
};
|
|
320
|
-
const
|
|
321
|
-
|
|
382
|
+
const app = new Skybridge({
|
|
383
|
+
name: "t",
|
|
384
|
+
version: "0.0.0",
|
|
385
|
+
handler: (server) => server,
|
|
386
|
+
});
|
|
387
|
+
app.use("/mcp", () => {
|
|
322
388
|
throw new Error("boom");
|
|
323
389
|
});
|
|
324
390
|
const httpServer = http.createServer();
|
|
325
|
-
const
|
|
326
|
-
|
|
391
|
+
const expressApp = await createApp({
|
|
392
|
+
app,
|
|
327
393
|
httpServer,
|
|
328
394
|
errorMiddleware: [{ handlers: [errorHandler] }],
|
|
329
395
|
});
|
|
330
|
-
const { port, server: httpListening } = await listen(
|
|
396
|
+
const { port, server: httpListening } = await listen(expressApp);
|
|
331
397
|
openServer = httpListening;
|
|
332
398
|
const res = await postMcp(port);
|
|
333
399
|
expect(calls).toEqual(["error-handler"]);
|
|
@@ -344,18 +410,22 @@ describe("createApp", () => {
|
|
|
344
410
|
const throwingApiRoute = (_req, _res, next) => {
|
|
345
411
|
next(new Error("api error"));
|
|
346
412
|
};
|
|
347
|
-
const
|
|
348
|
-
|
|
413
|
+
const app = new Skybridge({
|
|
414
|
+
name: "t",
|
|
415
|
+
version: "0.0.0",
|
|
416
|
+
handler: (server) => server,
|
|
417
|
+
});
|
|
418
|
+
app.use("/mcp", () => {
|
|
349
419
|
throw new Error("boom");
|
|
350
420
|
});
|
|
351
|
-
|
|
421
|
+
app.use("/api/test", throwingApiRoute);
|
|
352
422
|
const httpServer = http.createServer();
|
|
353
|
-
const
|
|
354
|
-
|
|
423
|
+
const expressApp = await createApp({
|
|
424
|
+
app,
|
|
355
425
|
httpServer,
|
|
356
426
|
errorMiddleware: [{ path: "/mcp", handlers: [mcpErrorHandler] }],
|
|
357
427
|
});
|
|
358
|
-
const { port, server: httpListening } = await listen(
|
|
428
|
+
const { port, server: httpListening } = await listen(expressApp);
|
|
359
429
|
openServer = httpListening;
|
|
360
430
|
const mcpRes = await postMcp(port);
|
|
361
431
|
expect(calls).toEqual(["mcp-error-handler"]);
|
|
@@ -369,20 +439,20 @@ describe("createApp", () => {
|
|
|
369
439
|
});
|
|
370
440
|
it("handles concurrent /mcp requests without 'Already connected to a transport'", async () => {
|
|
371
441
|
const { createApp } = await import("./express.js");
|
|
372
|
-
const mcpServer = new McpServer({
|
|
373
|
-
name: "concurrent-test",
|
|
374
|
-
version: "0.0.0",
|
|
375
|
-
});
|
|
376
442
|
// Slow tool: keeps the underlying transport bound long enough to overlap
|
|
377
443
|
// with concurrent requests, exposing the shared-McpServer race.
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
444
|
+
const app = new Skybridge({
|
|
445
|
+
name: "concurrent-test",
|
|
446
|
+
version: "0.0.0",
|
|
447
|
+
handler: (server) => server.registerTool({ name: "slow", description: "slow" }, async () => {
|
|
448
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
449
|
+
return { content: [{ type: "text", text: "done" }] };
|
|
450
|
+
}),
|
|
381
451
|
});
|
|
382
452
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
383
453
|
const httpServer = http.createServer();
|
|
384
|
-
const
|
|
385
|
-
const { port, server } = await listen(
|
|
454
|
+
const expressApp = await createApp({ app, httpServer });
|
|
455
|
+
const { port, server } = await listen(expressApp);
|
|
386
456
|
openServer = server;
|
|
387
457
|
const callBody = (id) => JSON.stringify({
|
|
388
458
|
jsonrpc: "2.0",
|
|
@@ -405,19 +475,23 @@ describe("createApp", () => {
|
|
|
405
475
|
});
|
|
406
476
|
});
|
|
407
477
|
describe("createApp Vercel mode", () => {
|
|
408
|
-
it("
|
|
478
|
+
it("app.run() returns the Express app without binding a port when VERCEL=1", async () => {
|
|
409
479
|
const prevVercel = process.env.VERCEL;
|
|
410
480
|
const prevEnv = process.env.NODE_ENV;
|
|
411
481
|
process.env.VERCEL = "1";
|
|
412
482
|
process.env.NODE_ENV = "production";
|
|
413
483
|
try {
|
|
414
484
|
vi.resetModules();
|
|
415
|
-
const {
|
|
416
|
-
const
|
|
417
|
-
|
|
485
|
+
const { Skybridge: Reloaded } = await import("./app.js");
|
|
486
|
+
const app = new Reloaded({
|
|
487
|
+
name: "t",
|
|
488
|
+
version: "0.0.0",
|
|
489
|
+
handler: (server) => server,
|
|
490
|
+
});
|
|
491
|
+
const result = await app.run();
|
|
418
492
|
expect(typeof result).toBe("function");
|
|
419
|
-
expect(result).toBe(
|
|
420
|
-
const { port, server: listening } = await listen(
|
|
493
|
+
expect(result).toBe(app.express);
|
|
494
|
+
const { port, server: listening } = await listen(app.express);
|
|
421
495
|
openServer = listening;
|
|
422
496
|
const res = await postMcp(port);
|
|
423
497
|
expect(res.status).not.toBe(404);
|
|
@@ -452,10 +526,14 @@ describe("createApp tunnel routes", () => {
|
|
|
452
526
|
process.env.__TUNNEL_CONTROL_PORT = String(controlPort);
|
|
453
527
|
try {
|
|
454
528
|
const { createApp } = await import("./express.js");
|
|
455
|
-
const
|
|
529
|
+
const app = new Skybridge({
|
|
530
|
+
name: "t",
|
|
531
|
+
version: "0.0.0",
|
|
532
|
+
handler: (server) => server,
|
|
533
|
+
});
|
|
456
534
|
const httpServer = http.createServer();
|
|
457
|
-
const
|
|
458
|
-
const { port, server } = await listen(
|
|
535
|
+
const expressApp = await createApp({ app, httpServer });
|
|
536
|
+
const { port, server } = await listen(expressApp);
|
|
459
537
|
openServer = server;
|
|
460
538
|
const res = await fetch(`http://localhost:${port}/__skybridge/tunnel`, {
|
|
461
539
|
method: "POST",
|
|
@@ -479,11 +557,15 @@ describe("createApp tunnel routes", () => {
|
|
|
479
557
|
try {
|
|
480
558
|
vi.resetModules();
|
|
481
559
|
const { createApp } = await import("./express.js");
|
|
482
|
-
const {
|
|
483
|
-
const
|
|
560
|
+
const { Skybridge: ReloadedSkybridge } = await import("./app.js");
|
|
561
|
+
const app = new ReloadedSkybridge({
|
|
562
|
+
name: "t",
|
|
563
|
+
version: "0.0.0",
|
|
564
|
+
handler: (server) => server,
|
|
565
|
+
});
|
|
484
566
|
const httpServer = http.createServer();
|
|
485
|
-
const
|
|
486
|
-
const { port, server } = await listen(
|
|
567
|
+
const expressApp = await createApp({ app, httpServer });
|
|
568
|
+
const { port, server } = await listen(expressApp);
|
|
487
569
|
openServer = server;
|
|
488
570
|
const res = await fetch(`http://localhost:${port}/__skybridge/tunnel`, {
|
|
489
571
|
method: "POST",
|
|
@@ -499,19 +581,20 @@ describe("createApp tunnel routes", () => {
|
|
|
499
581
|
describe("createApp mount path", () => {
|
|
500
582
|
it("serves /mcp with the mount path intact on the request URL", async () => {
|
|
501
583
|
const { createApp } = await import("./express.js");
|
|
502
|
-
const
|
|
584
|
+
const app = new Skybridge({
|
|
503
585
|
name: "t",
|
|
504
586
|
version: "0.0.0",
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
587
|
+
handler: (server) => server.registerTool({
|
|
588
|
+
name: "echo-url",
|
|
589
|
+
description: "Echoes the request URL.",
|
|
590
|
+
inputSchema: {},
|
|
591
|
+
}, (_args, extra) => ({
|
|
592
|
+
content: [{ type: "text", text: extra.http?.req?.url ?? "" }],
|
|
593
|
+
})),
|
|
594
|
+
});
|
|
512
595
|
const httpServer = http.createServer();
|
|
513
|
-
const
|
|
514
|
-
const { port, server } = await listen(
|
|
596
|
+
const expressApp = await createApp({ app, httpServer });
|
|
597
|
+
const { port, server } = await listen(expressApp);
|
|
515
598
|
openServer = server;
|
|
516
599
|
const client = new Client({ name: "test-client", version: "0.0.0" });
|
|
517
600
|
await client.connect(new StreamableHTTPClientTransport(new URL(`http://localhost:${port}/mcp`)));
|