skybridge 0.0.0-dev.f03017e → 0.0.0-dev.f06114a
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 +8 -8
- 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/use-open-browser.d.ts +1 -0
- package/dist/cli/use-open-browser.js +44 -0
- package/dist/cli/use-open-browser.js.map +1 -0
- package/dist/cli/use-tunnel.d.ts +1 -1
- package/dist/cli/use-tunnel.js +102 -68
- package/dist/cli/use-tunnel.js.map +1 -1
- package/dist/cli/use-typescript-check.d.ts +1 -0
- package/dist/cli/use-typescript-check.js +41 -6
- package/dist/cli/use-typescript-check.js.map +1 -1
- package/dist/commands/build.js +37 -2
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/dev.d.ts +1 -0
- package/dist/commands/dev.js +33 -2
- package/dist/commands/dev.js.map +1 -1
- package/dist/server/asset-base-url-transform-plugin.js +1 -1
- package/dist/server/asset-base-url-transform-plugin.js.map +1 -1
- package/dist/server/asset-base-url-transform-plugin.test.js +29 -0
- package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -1
- package/dist/server/express.d.ts +1 -5
- package/dist/server/express.js +31 -7
- package/dist/server/express.js.map +1 -1
- package/dist/server/express.test.js +210 -69
- package/dist/server/express.test.js.map +1 -1
- package/dist/server/inferUtilityTypes.d.ts +6 -6
- package/dist/server/server.d.ts +29 -5
- package/dist/server/server.js +88 -20
- package/dist/server/server.js.map +1 -1
- package/dist/server/templateHelper.d.ts +0 -2
- package/dist/server/templateHelper.js +3 -22
- package/dist/server/templateHelper.js.map +1 -1
- package/dist/server/templates.generated.d.ts +4 -0
- package/dist/server/templates.generated.js +47 -0
- package/dist/server/templates.generated.js.map +1 -0
- 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/test/utils.js.map +1 -1
- package/dist/test/view.test.js +111 -42
- package/dist/test/view.test.js.map +1 -1
- package/dist/version.js +1 -3
- package/dist/version.js.map +1 -1
- package/dist/web/bridges/apps-sdk/adaptor.d.ts +2 -2
- package/dist/web/bridges/apps-sdk/adaptor.js +8 -2
- package/dist/web/bridges/apps-sdk/adaptor.js.map +1 -1
- package/dist/web/bridges/mcp-app/adaptor.d.ts +6 -6
- package/dist/web/bridges/mcp-app/adaptor.js +24 -24
- package/dist/web/bridges/mcp-app/adaptor.js.map +1 -1
- package/dist/web/bridges/types.d.ts +5 -5
- package/dist/web/components/modal-provider.js +1 -1
- package/dist/web/components/modal-provider.js.map +1 -1
- package/dist/web/create-store.js +9 -9
- package/dist/web/create-store.js.map +1 -1
- package/dist/web/create-store.test.js +14 -16
- package/dist/web/create-store.test.js.map +1 -1
- package/dist/web/data-llm.d.ts +1 -1
- package/dist/web/data-llm.js +3 -3
- package/dist/web/data-llm.js.map +1 -1
- package/dist/web/data-llm.test.js +22 -22
- package/dist/web/data-llm.test.js.map +1 -1
- package/dist/web/generate-helpers.test-d.js +7 -7
- package/dist/web/generate-helpers.test-d.js.map +1 -1
- package/dist/web/helpers/state.d.ts +2 -2
- package/dist/web/helpers/state.js +11 -11
- package/dist/web/helpers/state.js.map +1 -1
- package/dist/web/helpers/state.test.js +9 -9
- package/dist/web/helpers/state.test.js.map +1 -1
- package/dist/web/hooks/index.d.ts +1 -1
- package/dist/web/hooks/index.js +1 -1
- package/dist/web/hooks/index.js.map +1 -1
- package/dist/web/hooks/use-request-modal.d.ts +1 -1
- package/dist/web/hooks/use-request-modal.js +4 -4
- package/dist/web/hooks/use-request-modal.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-view-state.d.ts +4 -0
- package/dist/web/hooks/use-view-state.js +32 -0
- package/dist/web/hooks/use-view-state.js.map +1 -0
- package/dist/web/hooks/use-view-state.test.d.ts +1 -0
- package/dist/web/hooks/{use-widget-state.test.js → use-view-state.test.js} +17 -17
- package/dist/web/hooks/use-view-state.test.js.map +1 -0
- package/dist/web/index.d.ts +1 -3
- package/dist/web/index.js +1 -2
- package/dist/web/index.js.map +1 -1
- package/dist/web/mount-view.d.ts +1 -0
- package/dist/web/{mount-widget.js → mount-view.js} +2 -2
- package/dist/web/mount-view.js.map +1 -0
- package/dist/web/plugin/plugin.js +32 -17
- 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 +26 -8
- package/dist/web/plugin/scan-views.js.map +1 -1
- package/dist/web/plugin/scan-views.test.js +33 -1
- package/dist/web/plugin/scan-views.test.js.map +1 -1
- package/package.json +20 -14
- package/dist/server/templates/development.hbs +0 -12
- package/dist/server/templates/production.hbs +0 -6
- package/dist/web/hooks/use-widget-state.d.ts +0 -4
- package/dist/web/hooks/use-widget-state.js +0 -32
- package/dist/web/hooks/use-widget-state.js.map +0 -1
- package/dist/web/hooks/use-widget-state.test.js.map +0 -1
- package/dist/web/mount-widget.d.ts +0 -1
- package/dist/web/mount-widget.js.map +0 -1
- /package/dist/{web/hooks/use-widget-state.test.d.ts → cli/tunnel-control-server.test.d.ts} +0 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import http from "node:http";
|
|
3
|
+
import { Readable } from "node:stream";
|
|
4
|
+
import express from "express";
|
|
5
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
import { startTunnelControlServer } from "../cli/tunnel-control-server.js";
|
|
7
|
+
import { createTunnelProxyRouter } from "./tunnel-proxy-router.js";
|
|
8
|
+
function makeFakeChild() {
|
|
9
|
+
const child = new EventEmitter();
|
|
10
|
+
child.stdout = new Readable({ read() { } });
|
|
11
|
+
child.stderr = new Readable({ read() { } });
|
|
12
|
+
child.kill = vi.fn(() => true);
|
|
13
|
+
return child;
|
|
14
|
+
}
|
|
15
|
+
async function listen(handler) {
|
|
16
|
+
const server = http.createServer(handler);
|
|
17
|
+
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
18
|
+
const port = server.address().port;
|
|
19
|
+
return { port, server };
|
|
20
|
+
}
|
|
21
|
+
const cleanups = [];
|
|
22
|
+
afterEach(async () => {
|
|
23
|
+
while (cleanups.length > 0) {
|
|
24
|
+
const cleanup = cleanups.pop();
|
|
25
|
+
if (cleanup) {
|
|
26
|
+
await cleanup();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
async function startProxy(controlPort) {
|
|
31
|
+
const app = express();
|
|
32
|
+
app.use(createTunnelProxyRouter(controlPort));
|
|
33
|
+
const { port, server } = await listen(app);
|
|
34
|
+
cleanups.push(() => new Promise((resolve) => {
|
|
35
|
+
server.closeAllConnections?.();
|
|
36
|
+
server.close(() => resolve());
|
|
37
|
+
}));
|
|
38
|
+
return { port, server };
|
|
39
|
+
}
|
|
40
|
+
async function startControl() {
|
|
41
|
+
const child = makeFakeChild();
|
|
42
|
+
const control = await startTunnelControlServer(() => 3000, {
|
|
43
|
+
spawn: () => child,
|
|
44
|
+
});
|
|
45
|
+
cleanups.push(() => control.close());
|
|
46
|
+
return { control, child };
|
|
47
|
+
}
|
|
48
|
+
describe("createTunnelProxyRouter", () => {
|
|
49
|
+
describe("POST /__skybridge/tunnel", () => {
|
|
50
|
+
it("forwards to upstream and returns the upstream JSON", async () => {
|
|
51
|
+
const { control } = await startControl();
|
|
52
|
+
const { port } = await startProxy(control.port);
|
|
53
|
+
const res = await fetch(`http://127.0.0.1:${port}/__skybridge/tunnel`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
});
|
|
56
|
+
expect(res.status).toBe(200);
|
|
57
|
+
expect(res.headers.get("content-type")).toMatch(/application\/json/);
|
|
58
|
+
expect(await res.json()).toEqual({
|
|
59
|
+
status: "starting",
|
|
60
|
+
message: "Starting tunnel…",
|
|
61
|
+
});
|
|
62
|
+
expect(control.manager.getState().status).toBe("starting");
|
|
63
|
+
});
|
|
64
|
+
it("returns 502 when upstream is unavailable", async () => {
|
|
65
|
+
// Pick a port nothing is listening on by starting+stopping a server.
|
|
66
|
+
const probe = http.createServer();
|
|
67
|
+
await new Promise((resolve) => probe.listen(0, "127.0.0.1", resolve));
|
|
68
|
+
const deadPort = probe.address().port;
|
|
69
|
+
await new Promise((resolve) => probe.close(() => resolve()));
|
|
70
|
+
const { port } = await startProxy(deadPort);
|
|
71
|
+
const res = await fetch(`http://127.0.0.1:${port}/__skybridge/tunnel`, {
|
|
72
|
+
method: "POST",
|
|
73
|
+
});
|
|
74
|
+
expect(res.status).toBe(502);
|
|
75
|
+
const body = (await res.json());
|
|
76
|
+
expect(body.status).toBe("error");
|
|
77
|
+
expect(typeof body.message).toBe("string");
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe("DELETE /__skybridge/tunnel", () => {
|
|
81
|
+
it("forwards to upstream and returns the upstream JSON", async () => {
|
|
82
|
+
const { control, child } = await startControl();
|
|
83
|
+
const { port } = await startProxy(control.port);
|
|
84
|
+
// First start the tunnel so DELETE has something to stop.
|
|
85
|
+
await fetch(`http://127.0.0.1:${port}/__skybridge/tunnel`, {
|
|
86
|
+
method: "POST",
|
|
87
|
+
});
|
|
88
|
+
const res = await fetch(`http://127.0.0.1:${port}/__skybridge/tunnel`, {
|
|
89
|
+
method: "DELETE",
|
|
90
|
+
});
|
|
91
|
+
expect(res.status).toBe(200);
|
|
92
|
+
expect(await res.json()).toEqual({ status: "idle" });
|
|
93
|
+
expect(child.kill).toHaveBeenCalled();
|
|
94
|
+
});
|
|
95
|
+
it("returns 502 when upstream is unavailable", async () => {
|
|
96
|
+
const probe = http.createServer();
|
|
97
|
+
await new Promise((resolve) => probe.listen(0, "127.0.0.1", resolve));
|
|
98
|
+
const deadPort = probe.address().port;
|
|
99
|
+
await new Promise((resolve) => probe.close(() => resolve()));
|
|
100
|
+
const { port } = await startProxy(deadPort);
|
|
101
|
+
const res = await fetch(`http://127.0.0.1:${port}/__skybridge/tunnel`, {
|
|
102
|
+
method: "DELETE",
|
|
103
|
+
});
|
|
104
|
+
expect(res.status).toBe(502);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe("GET /__skybridge/tunnel/events", () => {
|
|
108
|
+
it("pipes the upstream SSE stream through to the client", async () => {
|
|
109
|
+
const { control, child } = await startControl();
|
|
110
|
+
const { port } = await startProxy(control.port);
|
|
111
|
+
// Get the manager into a known state so the initial SSE frame is
|
|
112
|
+
// deterministic.
|
|
113
|
+
await fetch(`http://127.0.0.1:${port}/__skybridge/tunnel`, {
|
|
114
|
+
method: "POST",
|
|
115
|
+
});
|
|
116
|
+
child.stdout.emit("data", Buffer.from("Forwarding: https://abc.tunnel.example -> http://localhost:3000\n"));
|
|
117
|
+
const res = await fetch(`http://127.0.0.1:${port}/__skybridge/tunnel/events`);
|
|
118
|
+
expect(res.status).toBe(200);
|
|
119
|
+
expect(res.headers.get("content-type")).toMatch(/text\/event-stream/);
|
|
120
|
+
expect(res.headers.get("cache-control")).toMatch(/no-cache/);
|
|
121
|
+
const body = res.body;
|
|
122
|
+
if (!body) {
|
|
123
|
+
throw new Error("expected response body");
|
|
124
|
+
}
|
|
125
|
+
const reader = body.getReader();
|
|
126
|
+
const { value } = await reader.read();
|
|
127
|
+
const chunk = new TextDecoder().decode(value);
|
|
128
|
+
expect(chunk).toContain("event: state");
|
|
129
|
+
expect(chunk).toContain('"status":"connected"');
|
|
130
|
+
expect(chunk).toContain('"url":"https://abc.tunnel.example"');
|
|
131
|
+
await reader.cancel();
|
|
132
|
+
});
|
|
133
|
+
it("forwards subsequent state changes through the SSE stream", async () => {
|
|
134
|
+
const { control, child } = await startControl();
|
|
135
|
+
const { port } = await startProxy(control.port);
|
|
136
|
+
await fetch(`http://127.0.0.1:${port}/__skybridge/tunnel`, {
|
|
137
|
+
method: "POST",
|
|
138
|
+
});
|
|
139
|
+
const res = await fetch(`http://127.0.0.1:${port}/__skybridge/tunnel/events`);
|
|
140
|
+
const body = res.body;
|
|
141
|
+
if (!body) {
|
|
142
|
+
throw new Error("expected response body");
|
|
143
|
+
}
|
|
144
|
+
const reader = body.getReader();
|
|
145
|
+
const decoder = new TextDecoder();
|
|
146
|
+
// Drain the initial "starting" frame.
|
|
147
|
+
const first = await reader.read();
|
|
148
|
+
expect(decoder.decode(first.value)).toContain('"status":"starting"');
|
|
149
|
+
// Now drive a state change on the manager and read the next frame.
|
|
150
|
+
child.stdout.emit("data", Buffer.from("Forwarding: https://abc.tunnel.example -> http://localhost:3000\n"));
|
|
151
|
+
let combined = "";
|
|
152
|
+
// Reads may chunk arbitrarily, so accumulate until we see the connected
|
|
153
|
+
// event or hit a sane cap.
|
|
154
|
+
for (let i = 0; i < 5; i++) {
|
|
155
|
+
const { value, done } = await reader.read();
|
|
156
|
+
if (done) {
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
combined += decoder.decode(value);
|
|
160
|
+
if (combined.includes('"status":"connected"')) {
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
expect(combined).toContain('"status":"connected"');
|
|
165
|
+
expect(combined).toContain('"url":"https://abc.tunnel.example"');
|
|
166
|
+
await reader.cancel();
|
|
167
|
+
});
|
|
168
|
+
it("returns 502 when upstream is unavailable", async () => {
|
|
169
|
+
const probe = http.createServer();
|
|
170
|
+
await new Promise((resolve) => probe.listen(0, "127.0.0.1", resolve));
|
|
171
|
+
const deadPort = probe.address().port;
|
|
172
|
+
await new Promise((resolve) => probe.close(() => resolve()));
|
|
173
|
+
const { port } = await startProxy(deadPort);
|
|
174
|
+
const res = await fetch(`http://127.0.0.1:${port}/__skybridge/tunnel/events`);
|
|
175
|
+
expect(res.status).toBe(502);
|
|
176
|
+
const body = (await res.json());
|
|
177
|
+
expect(body.status).toBe("error");
|
|
178
|
+
});
|
|
179
|
+
it("aborts the upstream connection when the proxy server is closed mid-stream", async () => {
|
|
180
|
+
const { control } = await startControl();
|
|
181
|
+
const { port, server } = await startProxy(control.port);
|
|
182
|
+
await fetch(`http://127.0.0.1:${port}/__skybridge/tunnel`, {
|
|
183
|
+
method: "POST",
|
|
184
|
+
});
|
|
185
|
+
// Snapshot the manager's listener counts before the SSE subscription so
|
|
186
|
+
// we can verify the proxy disconnected from upstream after shutdown.
|
|
187
|
+
const baseStateListeners = control.manager.listenerCount("state");
|
|
188
|
+
const baseActivityListeners = control.manager.listenerCount("activity");
|
|
189
|
+
const res = await fetch(`http://127.0.0.1:${port}/__skybridge/tunnel/events`);
|
|
190
|
+
const body = res.body;
|
|
191
|
+
if (!body) {
|
|
192
|
+
throw new Error("expected response body");
|
|
193
|
+
}
|
|
194
|
+
const reader = body.getReader();
|
|
195
|
+
// Drain the first frame to confirm the stream is live and the upstream
|
|
196
|
+
// SSE handler has subscribed to the manager.
|
|
197
|
+
await reader.read();
|
|
198
|
+
expect(control.manager.listenerCount("state")).toBe(baseStateListeners + 1);
|
|
199
|
+
// Close the proxy server, destroying in-flight responses. The proxy's
|
|
200
|
+
// req.on("close", ...) should fire and abort the upstream fetch.
|
|
201
|
+
server.closeAllConnections?.();
|
|
202
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
203
|
+
// The client-side stream is dead — drain or fail, either is acceptable.
|
|
204
|
+
try {
|
|
205
|
+
while (true) {
|
|
206
|
+
const { done } = await reader.read();
|
|
207
|
+
if (done) {
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// expected: socket terminated when proxy server was destroyed
|
|
214
|
+
}
|
|
215
|
+
// Wait briefly for the upstream's req.on("close") to fire, then assert
|
|
216
|
+
// the manager listeners were detached. This is the load-bearing
|
|
217
|
+
// verification: it proves the proxy's AbortController propagated and
|
|
218
|
+
// upstream cleaned up its SSE subscription.
|
|
219
|
+
const start = Date.now();
|
|
220
|
+
while (control.manager.listenerCount("state") > baseStateListeners &&
|
|
221
|
+
Date.now() - start < 1000) {
|
|
222
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
223
|
+
}
|
|
224
|
+
expect(control.manager.listenerCount("state")).toBe(baseStateListeners);
|
|
225
|
+
expect(control.manager.listenerCount("activity")).toBe(baseActivityListeners);
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
//# sourceMappingURL=tunnel-proxy-router.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tunnel-proxy-router.test.js","sourceRoot":"","sources":["../../src/server/tunnel-proxy-router.test.ts"],"names":[],"mappings":"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"}
|
package/dist/test/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/test/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACrF,OAAO,EAAqB,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/test/utils.ts"],"names":[],"mappings":"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"}
|
package/dist/test/view.test.js
CHANGED
|
@@ -2,18 +2,30 @@ import crypto from "node:crypto";
|
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi, } from "vitest";
|
|
3
3
|
import { createMockExtra, createMockMcpServer, resetTestEnv, setTestEnv, } from "./utils.js";
|
|
4
4
|
const mockManifest = {
|
|
5
|
-
"skybridge:view:my-
|
|
6
|
-
file: "assets/my-
|
|
7
|
-
name: "my-
|
|
5
|
+
"skybridge:view:my-view": {
|
|
6
|
+
file: "assets/my-view-abc123.js",
|
|
7
|
+
name: "my-view",
|
|
8
8
|
isEntry: true,
|
|
9
9
|
},
|
|
10
|
-
"skybridge:view:folder-
|
|
11
|
-
file: "assets/folder-
|
|
12
|
-
name: "folder-
|
|
10
|
+
"skybridge:view:folder-view": {
|
|
11
|
+
file: "assets/folder-view-def456.js",
|
|
12
|
+
name: "folder-view",
|
|
13
13
|
isEntry: true,
|
|
14
14
|
},
|
|
15
15
|
"style.css": { file: "style.css" },
|
|
16
16
|
};
|
|
17
|
+
// Mirrors `McpServer.computeViewVersionParam`. Tests recompute the expected
|
|
18
|
+
// hash from the mocked manifest so they don't hardcode digest output.
|
|
19
|
+
function expectedVersionParam(viewFile, styleFile) {
|
|
20
|
+
const hash = crypto
|
|
21
|
+
.createHash("sha256")
|
|
22
|
+
.update(viewFile)
|
|
23
|
+
.update("\0")
|
|
24
|
+
.update(styleFile)
|
|
25
|
+
.digest("hex")
|
|
26
|
+
.slice(0, 8);
|
|
27
|
+
return `?v=${hash}`;
|
|
28
|
+
}
|
|
17
29
|
const actual = vi.hoisted(() => require("node:fs"));
|
|
18
30
|
vi.mock("node:fs", () => {
|
|
19
31
|
const readFileSyncImpl = (path, ...args) => {
|
|
@@ -45,10 +57,10 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
45
57
|
it("should generate correct HTML for development mode", async () => {
|
|
46
58
|
setTestEnv({ NODE_ENV: "development" });
|
|
47
59
|
server.registerTool({
|
|
48
|
-
name: "my-
|
|
60
|
+
name: "my-view",
|
|
49
61
|
description: "Test tool",
|
|
50
62
|
view: {
|
|
51
|
-
component: "my-
|
|
63
|
+
component: "my-view",
|
|
52
64
|
description: "Test view",
|
|
53
65
|
},
|
|
54
66
|
}, vi.fn());
|
|
@@ -59,12 +71,12 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
59
71
|
const serverUrl = `http://${host}`;
|
|
60
72
|
const hmrUrl = `ws://${host}`;
|
|
61
73
|
const mockExtra = createMockExtra(host);
|
|
62
|
-
const result = await appsSdkResourceCallback(new URL("ui://
|
|
74
|
+
const result = await appsSdkResourceCallback(new URL("ui://views/apps-sdk/my-view.html"), mockExtra);
|
|
63
75
|
expect(mockRegisterTool).toHaveBeenCalled();
|
|
64
76
|
expect(result).toEqual({
|
|
65
77
|
contents: [
|
|
66
78
|
{
|
|
67
|
-
uri: "ui://
|
|
79
|
+
uri: "ui://views/apps-sdk/my-view.html",
|
|
68
80
|
mimeType: "text/html+skybridge",
|
|
69
81
|
text: expect.stringContaining('<div id="root"></div>'),
|
|
70
82
|
_meta: {
|
|
@@ -80,15 +92,15 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
80
92
|
});
|
|
81
93
|
expect(result.contents[0]?.text).toContain(`${serverUrl}/assets/@react-refresh`);
|
|
82
94
|
expect(result.contents[0]?.text).toContain(`${serverUrl}/@vite/client`);
|
|
83
|
-
expect(result.contents[0]?.text).toContain(`${serverUrl}/_skybridge/view/my-
|
|
95
|
+
expect(result.contents[0]?.text).toContain(`${serverUrl}/_skybridge/view/my-view`);
|
|
84
96
|
});
|
|
85
97
|
it("should generate correct HTML for production mode", async () => {
|
|
86
98
|
setTestEnv({ NODE_ENV: "production" });
|
|
87
99
|
server.registerTool({
|
|
88
|
-
name: "my-
|
|
100
|
+
name: "my-view",
|
|
89
101
|
description: "Test tool",
|
|
90
102
|
view: {
|
|
91
|
-
component: "my-
|
|
103
|
+
component: "my-view",
|
|
92
104
|
description: "Test view",
|
|
93
105
|
},
|
|
94
106
|
}, vi.fn());
|
|
@@ -98,11 +110,12 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
98
110
|
const host = "myapp.com";
|
|
99
111
|
const serverUrl = `https://${host}`;
|
|
100
112
|
const mockExtra = createMockExtra(host);
|
|
101
|
-
const
|
|
113
|
+
const versionedUri = `ui://views/apps-sdk/my-view.html${expectedVersionParam("assets/my-view-abc123.js", "style.css")}`;
|
|
114
|
+
const result = await appsSdkResourceCallback(new URL(versionedUri), mockExtra);
|
|
102
115
|
expect(result).toEqual({
|
|
103
116
|
contents: [
|
|
104
117
|
{
|
|
105
|
-
uri:
|
|
118
|
+
uri: versionedUri,
|
|
106
119
|
mimeType: "text/html+skybridge",
|
|
107
120
|
text: expect.stringContaining('<div id="root"></div>'),
|
|
108
121
|
_meta: {
|
|
@@ -118,15 +131,15 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
118
131
|
});
|
|
119
132
|
expect(result.contents[0]?.text).not.toContain(`${serverUrl}/assets/@react-refresh`);
|
|
120
133
|
expect(result.contents[0]?.text).not.toContain(`${serverUrl}@vite/client`);
|
|
121
|
-
expect(result.contents[0]?.text).toContain(`${serverUrl}/assets/assets/my-
|
|
134
|
+
expect(result.contents[0]?.text).toContain(`${serverUrl}/assets/assets/my-view-abc123.js`);
|
|
122
135
|
expect(result.contents[0]?.text).toContain(`${serverUrl}/assets/style.css`);
|
|
123
136
|
});
|
|
124
137
|
it("should prefer x-alpic-forwarded-url when hashing Claude view domains", async () => {
|
|
125
138
|
setTestEnv({ NODE_ENV: "production" });
|
|
126
139
|
server.registerTool({
|
|
127
|
-
name: "my-
|
|
140
|
+
name: "my-view",
|
|
128
141
|
description: "Test tool",
|
|
129
|
-
view: { component: "my-
|
|
142
|
+
view: { component: "my-view", description: "Test view" },
|
|
130
143
|
}, vi.fn());
|
|
131
144
|
const extAppsResourceCallback = mockRegisterResource.mock
|
|
132
145
|
.calls[1]?.[3];
|
|
@@ -137,7 +150,7 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
137
150
|
.update(forwardedUrl)
|
|
138
151
|
.digest("hex")
|
|
139
152
|
.slice(0, 32)}.claudemcpcontent.com`;
|
|
140
|
-
const result = await extAppsResourceCallback(new URL(
|
|
153
|
+
const result = await extAppsResourceCallback(new URL(`ui://views/ext-apps/my-view.html${expectedVersionParam("assets/my-view-abc123.js", "style.css")}`), createMockExtra("localhost:3000", {
|
|
141
154
|
headers: {
|
|
142
155
|
"user-agent": "Claude-User",
|
|
143
156
|
"x-alpic-forwarded-url": forwardedUrl,
|
|
@@ -158,10 +171,10 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
158
171
|
});
|
|
159
172
|
it("should register resources with correct hostType for both apps-sdk and ext-apps", async () => {
|
|
160
173
|
server.registerTool({
|
|
161
|
-
name: "my-
|
|
174
|
+
name: "my-view",
|
|
162
175
|
description: "Test tool",
|
|
163
176
|
view: {
|
|
164
|
-
component: "my-
|
|
177
|
+
component: "my-view",
|
|
165
178
|
description: "Test view",
|
|
166
179
|
prefersBorder: true,
|
|
167
180
|
},
|
|
@@ -172,11 +185,11 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
172
185
|
const host = "localhost:3000";
|
|
173
186
|
const serverUrl = `http://${host}`;
|
|
174
187
|
const hmrUrl = `ws://${host}`;
|
|
175
|
-
const appsSdkResult = await appsSdkCallback(new URL("ui://
|
|
188
|
+
const appsSdkResult = await appsSdkCallback(new URL("ui://views/apps-sdk/my-view.html"), createMockExtra(host));
|
|
176
189
|
expect(appsSdkResult).toEqual({
|
|
177
190
|
contents: [
|
|
178
191
|
{
|
|
179
|
-
uri: "ui://
|
|
192
|
+
uri: "ui://views/apps-sdk/my-view.html",
|
|
180
193
|
mimeType: "text/html+skybridge",
|
|
181
194
|
text: expect.stringContaining('<div id="root"></div>'),
|
|
182
195
|
_meta: {
|
|
@@ -195,11 +208,11 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
195
208
|
const extAppsResourceCallback = mockRegisterResource.mock
|
|
196
209
|
.calls[1]?.[3];
|
|
197
210
|
expect(extAppsResourceCallback).toBeDefined();
|
|
198
|
-
const extAppsResult = await extAppsResourceCallback(new URL("ui://
|
|
211
|
+
const extAppsResult = await extAppsResourceCallback(new URL("ui://views/ext-apps/my-view.html"), createMockExtra(host));
|
|
199
212
|
expect(extAppsResult).toEqual({
|
|
200
213
|
contents: [
|
|
201
214
|
{
|
|
202
|
-
uri: "ui://
|
|
215
|
+
uri: "ui://views/ext-apps/my-view.html",
|
|
203
216
|
mimeType: "text/html;profile=mcp-app",
|
|
204
217
|
text: expect.stringContaining('<div id="root"></div>'),
|
|
205
218
|
_meta: {
|
|
@@ -221,24 +234,24 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
221
234
|
});
|
|
222
235
|
it("should register tool with ui.resourceUri metadata", async () => {
|
|
223
236
|
server.registerTool({
|
|
224
|
-
name: "my-
|
|
237
|
+
name: "my-view",
|
|
225
238
|
description: "Test tool",
|
|
226
|
-
view: { component: "my-
|
|
239
|
+
view: { component: "my-view", description: "Test view" },
|
|
227
240
|
}, vi.fn());
|
|
228
241
|
expect(mockRegisterTool).toHaveBeenCalledTimes(1);
|
|
229
242
|
const toolCallArgs = mockRegisterTool.mock.calls[0];
|
|
230
243
|
const toolConfig = toolCallArgs?.[1];
|
|
231
244
|
expect(toolConfig._meta).toHaveProperty("ui");
|
|
232
245
|
expect(toolConfig._meta?.ui).toEqual({
|
|
233
|
-
resourceUri: "ui://
|
|
246
|
+
resourceUri: "ui://views/ext-apps/my-view.html",
|
|
234
247
|
});
|
|
235
248
|
});
|
|
236
249
|
it("should register tool with openai/outputTemplate when apps-sdk only", async () => {
|
|
237
250
|
server.registerTool({
|
|
238
|
-
name: "my-
|
|
251
|
+
name: "my-view",
|
|
239
252
|
description: "Test tool",
|
|
240
253
|
view: {
|
|
241
|
-
component: "my-
|
|
254
|
+
component: "my-view",
|
|
242
255
|
description: "Test view",
|
|
243
256
|
hosts: ["apps-sdk"],
|
|
244
257
|
},
|
|
@@ -247,14 +260,70 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
247
260
|
const toolCallArgs = mockRegisterTool.mock.calls[0];
|
|
248
261
|
const toolConfig = toolCallArgs?.[1];
|
|
249
262
|
expect(toolConfig._meta).not.toHaveProperty("ui");
|
|
250
|
-
expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://
|
|
263
|
+
expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://views/apps-sdk/my-view.html");
|
|
264
|
+
});
|
|
265
|
+
it("should not version view URIs in development", () => {
|
|
266
|
+
server.registerTool({
|
|
267
|
+
name: "my-view",
|
|
268
|
+
description: "Test tool",
|
|
269
|
+
view: { component: "my-view", description: "Test view" },
|
|
270
|
+
}, vi.fn());
|
|
271
|
+
const toolConfig = mockRegisterTool.mock.calls[0]?.[1];
|
|
272
|
+
expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://views/apps-sdk/my-view.html");
|
|
273
|
+
expect(toolConfig._meta?.ui?.resourceUri).toBe("ui://views/ext-apps/my-view.html");
|
|
274
|
+
// The URI registered with the resource handler must match the URI in
|
|
275
|
+
// outputTemplate exactly so the SDK can resolve `resources/read` requests.
|
|
276
|
+
expect(mockRegisterResource.mock.calls[0]?.[1]).toBe("ui://views/apps-sdk/my-view.html");
|
|
277
|
+
expect(mockRegisterResource.mock.calls[1]?.[1]).toBe("ui://views/ext-apps/my-view.html");
|
|
278
|
+
});
|
|
279
|
+
it("should append a stable content hash to view URIs in production", () => {
|
|
280
|
+
setTestEnv({ NODE_ENV: "production" });
|
|
281
|
+
server.registerTool({
|
|
282
|
+
name: "my-view",
|
|
283
|
+
description: "Test tool",
|
|
284
|
+
view: { component: "my-view", description: "Test view" },
|
|
285
|
+
}, vi.fn());
|
|
286
|
+
const expected = expectedVersionParam("assets/my-view-abc123.js", "style.css");
|
|
287
|
+
const toolConfig = mockRegisterTool.mock.calls[0]?.[1];
|
|
288
|
+
expect(toolConfig._meta?.["openai/outputTemplate"]).toBe(`ui://views/apps-sdk/my-view.html${expected}`);
|
|
289
|
+
expect(toolConfig._meta?.ui?.resourceUri).toBe(`ui://views/ext-apps/my-view.html${expected}`);
|
|
290
|
+
expect(mockRegisterResource.mock.calls[0]?.[1]).toBe(`ui://views/apps-sdk/my-view.html${expected}`);
|
|
291
|
+
expect(mockRegisterResource.mock.calls[1]?.[1]).toBe(`ui://views/ext-apps/my-view.html${expected}`);
|
|
292
|
+
});
|
|
293
|
+
it("should produce different version params for views with different bundles", () => {
|
|
294
|
+
setTestEnv({ NODE_ENV: "production" });
|
|
295
|
+
server.registerTool({
|
|
296
|
+
name: "my-view",
|
|
297
|
+
description: "First tool",
|
|
298
|
+
view: { component: "my-view" },
|
|
299
|
+
}, vi.fn());
|
|
300
|
+
server.registerTool({
|
|
301
|
+
name: "folder-view",
|
|
302
|
+
description: "Second tool",
|
|
303
|
+
view: { component: "folder-view" },
|
|
304
|
+
}, vi.fn());
|
|
305
|
+
const myviewTemplate = (mockRegisterTool.mock.calls[0]?.[1])._meta?.["openai/outputTemplate"];
|
|
306
|
+
const folderviewTemplate = (mockRegisterTool.mock.calls[1]?.[1])._meta?.["openai/outputTemplate"];
|
|
307
|
+
expect(myviewTemplate).not.toEqual(folderviewTemplate);
|
|
308
|
+
expect(myviewTemplate).toMatch(/\?v=[0-9a-f]{8}$/);
|
|
309
|
+
expect(folderviewTemplate).toMatch(/\?v=[0-9a-f]{8}$/);
|
|
310
|
+
});
|
|
311
|
+
it("should fall back to bare URI in production when manifest is missing", () => {
|
|
312
|
+
setTestEnv({ NODE_ENV: "production" });
|
|
313
|
+
server.registerTool({
|
|
314
|
+
name: "unknown-view",
|
|
315
|
+
description: "Test tool",
|
|
316
|
+
view: { component: "unknown-view" },
|
|
317
|
+
}, vi.fn());
|
|
318
|
+
const toolConfig = mockRegisterTool.mock.calls[0]?.[1];
|
|
319
|
+
expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://views/apps-sdk/unknown-view.html");
|
|
251
320
|
});
|
|
252
321
|
it("should register tool with ui.resourceUri only when mcp-app only", async () => {
|
|
253
322
|
server.registerTool({
|
|
254
|
-
name: "my-
|
|
323
|
+
name: "my-view",
|
|
255
324
|
description: "Test tool",
|
|
256
325
|
view: {
|
|
257
|
-
component: "my-
|
|
326
|
+
component: "my-view",
|
|
258
327
|
description: "Test view",
|
|
259
328
|
hosts: ["mcp-app"],
|
|
260
329
|
},
|
|
@@ -264,7 +333,7 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
264
333
|
const toolConfig = toolCallArgs?.[1];
|
|
265
334
|
expect(toolConfig._meta).toHaveProperty("ui");
|
|
266
335
|
expect(toolConfig._meta?.ui).toEqual({
|
|
267
|
-
resourceUri: "ui://
|
|
336
|
+
resourceUri: "ui://views/ext-apps/my-view.html",
|
|
268
337
|
});
|
|
269
338
|
expect(toolConfig._meta?.["openai/outputTemplate"]).toBeUndefined();
|
|
270
339
|
});
|
|
@@ -274,9 +343,9 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
274
343
|
structuredContent: { data: "test" },
|
|
275
344
|
});
|
|
276
345
|
server.registerTool({
|
|
277
|
-
name: "my-
|
|
346
|
+
name: "my-view",
|
|
278
347
|
description: "Test tool",
|
|
279
|
-
view: { component: "my-
|
|
348
|
+
view: { component: "my-view", description: "Test view" },
|
|
280
349
|
}, mockToolCallback);
|
|
281
350
|
const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2];
|
|
282
351
|
expect(wrappedCallback).toBeDefined();
|
|
@@ -293,9 +362,9 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
293
362
|
_meta: { requestId: "req-123", cached: true },
|
|
294
363
|
});
|
|
295
364
|
server.registerTool({
|
|
296
|
-
name: "my-
|
|
365
|
+
name: "my-view",
|
|
297
366
|
description: "Test tool",
|
|
298
|
-
view: { component: "my-
|
|
367
|
+
view: { component: "my-view", description: "Test view" },
|
|
299
368
|
}, mockToolCallback);
|
|
300
369
|
const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2];
|
|
301
370
|
const result = await wrappedCallback({}, {});
|
|
@@ -309,9 +378,9 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
309
378
|
structuredContent: {},
|
|
310
379
|
});
|
|
311
380
|
server.registerTool({
|
|
312
|
-
name: "my-
|
|
381
|
+
name: "my-view",
|
|
313
382
|
description: "Test tool",
|
|
314
|
-
view: { component: "my-
|
|
383
|
+
view: { component: "my-view", description: "Test view" },
|
|
315
384
|
}, mockToolCallback);
|
|
316
385
|
const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2];
|
|
317
386
|
const result1 = await wrappedCallback({}, {});
|
|
@@ -404,7 +473,7 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
404
473
|
const host = "localhost:3000";
|
|
405
474
|
const serverUrl = `http://${host}`;
|
|
406
475
|
const hmrUrl = `ws://${host}`;
|
|
407
|
-
const result = await appsSdkCallback(new URL("ui://
|
|
476
|
+
const result = await appsSdkCallback(new URL("ui://views/apps-sdk/csp-tool.html"), createMockExtra(host));
|
|
408
477
|
const meta = result.contents[0]?._meta;
|
|
409
478
|
expect(meta["openai/widgetCSP"]).toEqual({
|
|
410
479
|
resource_domains: [serverUrl, "https://cdn.example.com"],
|
|
@@ -428,7 +497,7 @@ describe("McpServer.registerTool (unified API)", () => {
|
|
|
428
497
|
}, vi.fn());
|
|
429
498
|
const appsSdkCallback = mockRegisterResource.mock
|
|
430
499
|
.calls[0]?.[3];
|
|
431
|
-
const result = await appsSdkCallback(new URL("ui://
|
|
500
|
+
const result = await appsSdkCallback(new URL("ui://views/apps-sdk/override-tool.html"), createMockExtra("localhost:3000"));
|
|
432
501
|
const meta = result.contents[0]?._meta;
|
|
433
502
|
expect(meta["openai/widgetCSP"]).toEqual({
|
|
434
503
|
connect_domains: ["https://api.y.com"],
|