skybridge 0.0.0-dev.89e1390 → 0.0.0-dev.89e35fa

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.
Files changed (123) hide show
  1. package/dist/cli/use-open-tunnel-browser.d.ts +6 -0
  2. package/dist/cli/use-open-tunnel-browser.js +19 -0
  3. package/dist/cli/use-open-tunnel-browser.js.map +1 -0
  4. package/dist/commands/dev.js +3 -1
  5. package/dist/commands/dev.js.map +1 -1
  6. package/dist/server/express.test.js +0 -31
  7. package/dist/server/express.test.js.map +1 -1
  8. package/dist/server/index.d.ts +1 -2
  9. package/dist/server/index.js.map +1 -1
  10. package/dist/server/server.d.ts +14 -29
  11. package/dist/server/server.js +80 -163
  12. package/dist/server/server.js.map +1 -1
  13. package/dist/test/view.test.js +57 -99
  14. package/dist/test/view.test.js.map +1 -1
  15. package/dist/web/bridges/adaptor.d.ts +50 -0
  16. package/dist/web/bridges/adaptor.js +314 -0
  17. package/dist/web/bridges/adaptor.js.map +1 -0
  18. package/dist/web/bridges/adaptor.test.js +205 -0
  19. package/dist/web/bridges/adaptor.test.js.map +1 -0
  20. package/dist/web/bridges/apps-sdk/bridge.d.ts +1 -1
  21. package/dist/web/bridges/apps-sdk/bridge.js +3 -4
  22. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  23. package/dist/web/bridges/apps-sdk/index.d.ts +0 -1
  24. package/dist/web/bridges/apps-sdk/index.js +0 -1
  25. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  26. package/dist/web/bridges/get-adaptor.d.ts +6 -4
  27. package/dist/web/bridges/get-adaptor.js +16 -9
  28. package/dist/web/bridges/get-adaptor.js.map +1 -1
  29. package/dist/web/bridges/get-adaptor.test.js +32 -0
  30. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  31. package/dist/web/bridges/host-context-stores.d.ts +27 -0
  32. package/dist/web/bridges/host-context-stores.js +73 -0
  33. package/dist/web/bridges/host-context-stores.js.map +1 -0
  34. package/dist/web/bridges/mcp-app/bridge.d.ts +3 -4
  35. package/dist/web/bridges/mcp-app/bridge.js +2 -26
  36. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  37. package/dist/web/bridges/mcp-app/bridge.test.js +21 -0
  38. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  39. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  40. package/dist/web/bridges/mcp-app/index.js +0 -1
  41. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  42. package/dist/web/bridges/types.d.ts +16 -34
  43. package/dist/web/bridges/types.js +14 -1
  44. package/dist/web/bridges/types.js.map +1 -1
  45. package/dist/web/bridges/types.test.d.ts +1 -0
  46. package/dist/web/bridges/types.test.js +19 -0
  47. package/dist/web/bridges/types.test.js.map +1 -0
  48. package/dist/web/components/modal-provider.js +4 -3
  49. package/dist/web/components/modal-provider.js.map +1 -1
  50. package/dist/web/create-store.test.js +7 -5
  51. package/dist/web/create-store.test.js.map +1 -1
  52. package/dist/web/data-llm.test.js +8 -5
  53. package/dist/web/data-llm.test.js.map +1 -1
  54. package/dist/web/generate-helpers.test-d.js +2 -4
  55. package/dist/web/generate-helpers.test-d.js.map +1 -1
  56. package/dist/web/hooks/index.d.ts +0 -1
  57. package/dist/web/hooks/index.js +0 -1
  58. package/dist/web/hooks/index.js.map +1 -1
  59. package/dist/web/hooks/use-call-tool.test.js +36 -23
  60. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  61. package/dist/web/hooks/use-display-mode.test.js +55 -20
  62. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  63. package/dist/web/hooks/use-download.test.js +11 -3
  64. package/dist/web/hooks/use-download.test.js.map +1 -1
  65. package/dist/web/hooks/use-files.test.js +10 -2
  66. package/dist/web/hooks/use-files.test.js.map +1 -1
  67. package/dist/web/hooks/use-layout.test.js +59 -26
  68. package/dist/web/hooks/use-layout.test.js.map +1 -1
  69. package/dist/web/hooks/use-open-external.test.js +19 -5
  70. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  71. package/dist/web/hooks/use-request-close.test.js +34 -40
  72. package/dist/web/hooks/use-request-close.test.js.map +1 -1
  73. package/dist/web/hooks/use-request-modal.test.js +10 -0
  74. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  75. package/dist/web/hooks/use-request-size.test.js +35 -53
  76. package/dist/web/hooks/use-request-size.test.js.map +1 -1
  77. package/dist/web/hooks/use-set-open-in-app-url.test.js +28 -8
  78. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  79. package/dist/web/hooks/use-tool-info.d.ts +7 -25
  80. package/dist/web/hooks/use-tool-info.js +8 -5
  81. package/dist/web/hooks/use-tool-info.js.map +1 -1
  82. package/dist/web/hooks/use-tool-info.test-d.js +29 -11
  83. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  84. package/dist/web/hooks/use-tool-info.test.js +42 -32
  85. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  86. package/dist/web/hooks/use-user.test.js +81 -35
  87. package/dist/web/hooks/use-user.test.js.map +1 -1
  88. package/dist/web/hooks/use-view-state.test.js +6 -2
  89. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  90. package/package.json +3 -4
  91. package/dist/server/auth/index.d.ts +0 -20
  92. package/dist/server/auth/index.js +0 -2
  93. package/dist/server/auth/index.js.map +0 -1
  94. package/dist/server/auth/setup.d.ts +0 -4
  95. package/dist/server/auth/setup.js +0 -52
  96. package/dist/server/auth/setup.js.map +0 -1
  97. package/dist/server/auth/setup.test.js +0 -210
  98. package/dist/server/auth/setup.test.js.map +0 -1
  99. package/dist/server/auth/verify.d.ts +0 -11
  100. package/dist/server/auth/verify.js +0 -37
  101. package/dist/server/auth/verify.js.map +0 -1
  102. package/dist/server/auth/verify.test.js +0 -87
  103. package/dist/server/auth/verify.test.js.map +0 -1
  104. package/dist/server/requestOrigin.d.ts +0 -6
  105. package/dist/server/requestOrigin.js +0 -30
  106. package/dist/server/requestOrigin.js.map +0 -1
  107. package/dist/server/view-resource-resolution.test.d.ts +0 -6
  108. package/dist/server/view-resource-resolution.test.js +0 -88
  109. package/dist/server/view-resource-resolution.test.js.map +0 -1
  110. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -29
  111. package/dist/web/bridges/apps-sdk/adaptor.js +0 -117
  112. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  113. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -53
  114. package/dist/web/bridges/mcp-app/adaptor.js +0 -283
  115. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
  116. package/dist/web/bridges/mcp-app/view-tools.test.js +0 -144
  117. package/dist/web/bridges/mcp-app/view-tools.test.js.map +0 -1
  118. package/dist/web/hooks/use-register-view-tool.d.ts +0 -38
  119. package/dist/web/hooks/use-register-view-tool.js +0 -50
  120. package/dist/web/hooks/use-register-view-tool.js.map +0 -1
  121. /package/dist/{server/auth/setup.test.d.ts → web/bridges/adaptor.test.d.ts} +0 -0
  122. /package/dist/{server/auth/verify.test.d.ts → web/bridges/get-adaptor.test.d.ts} +0 -0
  123. /package/dist/web/bridges/mcp-app/{view-tools.test.d.ts → bridge.test.d.ts} +0 -0
@@ -74,21 +74,24 @@ describe("McpServer.registerTool (unified API)", () => {
74
74
  const serverUrl = `http://${host}`;
75
75
  const hmrUrl = `ws://${host}`;
76
76
  const mockExtra = createMockExtra(host);
77
- const result = await appsSdkResourceCallback(new URL("ui://views/apps-sdk/my-view.html"), mockExtra);
77
+ const result = await appsSdkResourceCallback(new URL("ui://views/ext-apps/my-view.html"), mockExtra);
78
78
  expect(mockRegisterTool).toHaveBeenCalled();
79
79
  expect(result).toEqual({
80
80
  contents: [
81
81
  {
82
- uri: "ui://views/apps-sdk/my-view.html",
83
- mimeType: "text/html+skybridge",
82
+ uri: "ui://views/ext-apps/my-view.html",
83
+ mimeType: "text/html;profile=mcp-app",
84
84
  text: expect.stringContaining('<div id="root"></div>'),
85
85
  _meta: {
86
- "openai/widgetCSP": {
87
- resource_domains: [serverUrl],
88
- connect_domains: [serverUrl, hmrUrl],
86
+ ui: {
87
+ csp: {
88
+ resourceDomains: [serverUrl],
89
+ connectDomains: [serverUrl, hmrUrl],
90
+ baseUriDomains: [serverUrl],
91
+ },
92
+ domain: serverUrl,
93
+ description: "Test view",
89
94
  },
90
- "openai/widgetDomain": serverUrl,
91
- "openai/widgetDescription": "Test view",
92
95
  },
93
96
  },
94
97
  ],
@@ -113,21 +116,24 @@ describe("McpServer.registerTool (unified API)", () => {
113
116
  const host = "myapp.com";
114
117
  const serverUrl = `https://${host}`;
115
118
  const mockExtra = createMockExtra(host);
116
- const versionedUri = `ui://views/apps-sdk/my-view.html${expectedVersionParam("assets/my-view-abc123.js", "style.css")}`;
119
+ const versionedUri = `ui://views/ext-apps/my-view.html${expectedVersionParam("assets/my-view-abc123.js", "style.css")}`;
117
120
  const result = await appsSdkResourceCallback(new URL(versionedUri), mockExtra);
118
121
  expect(result).toEqual({
119
122
  contents: [
120
123
  {
121
124
  uri: versionedUri,
122
- mimeType: "text/html+skybridge",
125
+ mimeType: "text/html;profile=mcp-app",
123
126
  text: expect.stringContaining('<div id="root"></div>'),
124
127
  _meta: {
125
- "openai/widgetCSP": {
126
- resource_domains: [serverUrl],
127
- connect_domains: [serverUrl],
128
+ ui: {
129
+ csp: {
130
+ resourceDomains: [serverUrl],
131
+ connectDomains: [serverUrl],
132
+ baseUriDomains: [serverUrl],
133
+ },
134
+ domain: serverUrl,
135
+ description: "Test view",
128
136
  },
129
- "openai/widgetDomain": serverUrl,
130
- "openai/widgetDescription": "Test view",
131
137
  },
132
138
  },
133
139
  ],
@@ -145,7 +151,7 @@ describe("McpServer.registerTool (unified API)", () => {
145
151
  view: { component: "my-view", description: "Test view" },
146
152
  }, vi.fn());
147
153
  const extAppsResourceCallback = mockRegisterResource.mock
148
- .calls[1]?.[3];
154
+ .calls[0]?.[3];
149
155
  expect(extAppsResourceCallback).toBeDefined();
150
156
  const forwardedUrl = "https://everything-3a2c1264.staging.alpic.live/mcp?foo=bar";
151
157
  const expectedDomain = `${crypto
@@ -172,7 +178,7 @@ describe("McpServer.registerTool (unified API)", () => {
172
178
  },
173
179
  });
174
180
  });
175
- it("should register resources with correct hostType for both apps-sdk and ext-apps", async () => {
181
+ it("should register a single ext-apps resource", async () => {
176
182
  server.registerTool({
177
183
  name: "my-view",
178
184
  description: "Test tool",
@@ -182,37 +188,14 @@ describe("McpServer.registerTool (unified API)", () => {
182
188
  prefersBorder: true,
183
189
  },
184
190
  }, vi.fn());
185
- expect(mockRegisterResource).toHaveBeenCalledTimes(2);
186
- const appsSdkCallback = mockRegisterResource.mock
191
+ expect(mockRegisterResource).toHaveBeenCalledTimes(1);
192
+ const resourceCallback = mockRegisterResource.mock
187
193
  .calls[0]?.[3];
188
194
  const host = "localhost:3000";
189
195
  const serverUrl = `http://${host}`;
190
196
  const hmrUrl = `ws://${host}`;
191
- const appsSdkResult = await appsSdkCallback(new URL("ui://views/apps-sdk/my-view.html"), createMockExtra(host));
192
- expect(appsSdkResult).toEqual({
193
- contents: [
194
- {
195
- uri: "ui://views/apps-sdk/my-view.html",
196
- mimeType: "text/html+skybridge",
197
- text: expect.stringContaining('<div id="root"></div>'),
198
- _meta: {
199
- "openai/widgetCSP": {
200
- resource_domains: [serverUrl],
201
- connect_domains: [serverUrl, hmrUrl],
202
- },
203
- "openai/widgetDomain": serverUrl,
204
- "openai/widgetDescription": "Test view",
205
- "openai/widgetPrefersBorder": true,
206
- },
207
- },
208
- ],
209
- });
210
- expect(appsSdkResult.contents[0]?.text).toContain('window.skybridge = { hostType: "apps-sdk", serverUrl: "http://localhost:3000" };');
211
- const extAppsResourceCallback = mockRegisterResource.mock
212
- .calls[1]?.[3];
213
- expect(extAppsResourceCallback).toBeDefined();
214
- const extAppsResult = await extAppsResourceCallback(new URL("ui://views/ext-apps/my-view.html"), createMockExtra(host));
215
- expect(extAppsResult).toEqual({
197
+ const result = await resourceCallback(new URL("ui://views/ext-apps/my-view.html"), createMockExtra(host));
198
+ expect(result).toEqual({
216
199
  contents: [
217
200
  {
218
201
  uri: "ui://views/ext-apps/my-view.html",
@@ -233,23 +216,21 @@ describe("McpServer.registerTool (unified API)", () => {
233
216
  },
234
217
  ],
235
218
  });
236
- expect(extAppsResult.contents[0]?.text).toContain('window.skybridge = { hostType: "mcp-app", serverUrl: "http://localhost:3000" };');
219
+ expect(result.contents[0]?.text).toContain('window.skybridge = { hostType: "mcp-app", serverUrl: "http://localhost:3000" };');
237
220
  });
238
- it("should register tool with ui.resourceUri metadata", async () => {
221
+ it("should advertise the single resource via ui.resourceUri and openai/outputTemplate alias", async () => {
239
222
  server.registerTool({
240
223
  name: "my-view",
241
224
  description: "Test tool",
242
225
  view: { component: "my-view", description: "Test view" },
243
226
  }, vi.fn());
244
- expect(mockRegisterTool).toHaveBeenCalledTimes(1);
245
- const toolCallArgs = mockRegisterTool.mock.calls[0];
246
- const toolConfig = toolCallArgs?.[1];
247
- expect(toolConfig._meta).toHaveProperty("ui");
248
- expect(toolConfig._meta?.ui).toEqual({
249
- resourceUri: "ui://views/ext-apps/my-view.html",
250
- });
227
+ const toolConfig = mockRegisterTool.mock.calls[0]?.[1];
228
+ const uri = "ui://views/ext-apps/my-view.html";
229
+ expect(toolConfig._meta?.ui?.resourceUri).toBe(uri);
230
+ expect(toolConfig._meta?.["ui/resourceUri"]).toBe(uri);
231
+ expect(toolConfig._meta?.["openai/outputTemplate"]).toBe(uri);
251
232
  });
252
- it("should register tool with openai/outputTemplate when apps-sdk only", async () => {
233
+ it("treats the deprecated hosts option as a no-op (always the single resource)", async () => {
253
234
  server.registerTool({
254
235
  name: "my-view",
255
236
  description: "Test tool",
@@ -259,11 +240,10 @@ describe("McpServer.registerTool (unified API)", () => {
259
240
  hosts: ["apps-sdk"],
260
241
  },
261
242
  }, vi.fn());
262
- expect(mockRegisterTool).toHaveBeenCalledTimes(1);
263
- const toolCallArgs = mockRegisterTool.mock.calls[0];
264
- const toolConfig = toolCallArgs?.[1];
265
- expect(toolConfig._meta).not.toHaveProperty("ui");
266
- expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://views/apps-sdk/my-view.html");
243
+ expect(mockRegisterResource).toHaveBeenCalledTimes(1);
244
+ const toolConfig = mockRegisterTool.mock.calls[0]?.[1];
245
+ expect(toolConfig._meta?.ui?.resourceUri).toBe("ui://views/ext-apps/my-view.html");
246
+ expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://views/ext-apps/my-view.html");
267
247
  });
268
248
  it("should not version view URIs in development", () => {
269
249
  server.registerTool({
@@ -272,12 +252,11 @@ describe("McpServer.registerTool (unified API)", () => {
272
252
  view: { component: "my-view", description: "Test view" },
273
253
  }, vi.fn());
274
254
  const toolConfig = mockRegisterTool.mock.calls[0]?.[1];
275
- expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://views/apps-sdk/my-view.html");
255
+ expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://views/ext-apps/my-view.html");
276
256
  expect(toolConfig._meta?.ui?.resourceUri).toBe("ui://views/ext-apps/my-view.html");
277
257
  // The URI registered with the resource handler must match the URI in
278
258
  // outputTemplate exactly so the SDK can resolve `resources/read` requests.
279
- expect(mockRegisterResource.mock.calls[0]?.[1]).toBe("ui://views/apps-sdk/my-view.html");
280
- expect(mockRegisterResource.mock.calls[1]?.[1]).toBe("ui://views/ext-apps/my-view.html");
259
+ expect(mockRegisterResource.mock.calls[0]?.[1]).toBe("ui://views/ext-apps/my-view.html");
281
260
  });
282
261
  it("should append a stable content hash to view URIs in production", () => {
283
262
  setTestEnv({ NODE_ENV: "production" });
@@ -288,10 +267,9 @@ describe("McpServer.registerTool (unified API)", () => {
288
267
  }, vi.fn());
289
268
  const expected = expectedVersionParam("assets/my-view-abc123.js", "style.css");
290
269
  const toolConfig = mockRegisterTool.mock.calls[0]?.[1];
291
- expect(toolConfig._meta?.["openai/outputTemplate"]).toBe(`ui://views/apps-sdk/my-view.html${expected}`);
270
+ expect(toolConfig._meta?.["openai/outputTemplate"]).toBe(`ui://views/ext-apps/my-view.html${expected}`);
292
271
  expect(toolConfig._meta?.ui?.resourceUri).toBe(`ui://views/ext-apps/my-view.html${expected}`);
293
- expect(mockRegisterResource.mock.calls[0]?.[1]).toBe(`ui://views/apps-sdk/my-view.html${expected}`);
294
- expect(mockRegisterResource.mock.calls[1]?.[1]).toBe(`ui://views/ext-apps/my-view.html${expected}`);
272
+ expect(mockRegisterResource.mock.calls[0]?.[1]).toBe(`ui://views/ext-apps/my-view.html${expected}`);
295
273
  });
296
274
  it("should produce different version params for views with different bundles", () => {
297
275
  setTestEnv({ NODE_ENV: "production" });
@@ -319,26 +297,7 @@ describe("McpServer.registerTool (unified API)", () => {
319
297
  view: { component: "unknown-view" },
320
298
  }, vi.fn());
321
299
  const toolConfig = mockRegisterTool.mock.calls[0]?.[1];
322
- expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://views/apps-sdk/unknown-view.html");
323
- });
324
- it("should register tool with ui.resourceUri only when mcp-app only", async () => {
325
- server.registerTool({
326
- name: "my-view",
327
- description: "Test tool",
328
- view: {
329
- component: "my-view",
330
- description: "Test view",
331
- hosts: ["mcp-app"],
332
- },
333
- }, vi.fn());
334
- expect(mockRegisterTool).toHaveBeenCalledTimes(1);
335
- const toolCallArgs = mockRegisterTool.mock.calls[0];
336
- const toolConfig = toolCallArgs?.[1];
337
- expect(toolConfig._meta).toHaveProperty("ui");
338
- expect(toolConfig._meta?.ui).toEqual({
339
- resourceUri: "ui://views/ext-apps/my-view.html",
340
- });
341
- expect(toolConfig._meta?.["openai/outputTemplate"]).toBeUndefined();
300
+ expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://views/ext-apps/unknown-view.html");
342
301
  });
343
302
  it("should inject viewUUID into _meta of tool callback results", async () => {
344
303
  const mockToolCallback = vi.fn().mockResolvedValue({
@@ -476,11 +435,12 @@ describe("McpServer.registerTool (unified API)", () => {
476
435
  const host = "localhost:3000";
477
436
  const serverUrl = `http://${host}`;
478
437
  const hmrUrl = `ws://${host}`;
479
- const result = await appsSdkCallback(new URL("ui://views/apps-sdk/csp-tool.html"), createMockExtra(host));
438
+ const result = await appsSdkCallback(new URL("ui://views/ext-apps/csp-tool.html"), createMockExtra(host));
480
439
  const meta = result.contents[0]?._meta;
481
- expect(meta["openai/widgetCSP"]).toEqual({
482
- resource_domains: [serverUrl, "https://cdn.example.com"],
483
- connect_domains: [serverUrl, hmrUrl, "https://api.example.com"],
440
+ expect(meta.ui?.csp).toEqual({
441
+ resourceDomains: [serverUrl, "https://cdn.example.com"],
442
+ connectDomains: [serverUrl, hmrUrl, "https://api.example.com"],
443
+ baseUriDomains: [serverUrl],
484
444
  });
485
445
  });
486
446
  it("should let view._meta override framework-computed keys", async () => {
@@ -492,18 +452,20 @@ describe("McpServer.registerTool (unified API)", () => {
492
452
  description: "Test view",
493
453
  csp: { connectDomains: ["https://api.x.com"] },
494
454
  _meta: {
495
- "openai/widgetCSP": {
496
- connect_domains: ["https://api.y.com"],
455
+ ui: {
456
+ csp: {
457
+ connectDomains: ["https://api.y.com"],
458
+ },
497
459
  },
498
460
  },
499
461
  },
500
462
  }, vi.fn());
501
463
  const appsSdkCallback = mockRegisterResource.mock
502
464
  .calls[0]?.[3];
503
- const result = await appsSdkCallback(new URL("ui://views/apps-sdk/override-tool.html"), createMockExtra("localhost:3000"));
465
+ const result = await appsSdkCallback(new URL("ui://views/ext-apps/override-tool.html"), createMockExtra("localhost:3000"));
504
466
  const meta = result.contents[0]?._meta;
505
- expect(meta["openai/widgetCSP"]).toEqual({
506
- connect_domains: ["https://api.y.com"],
467
+ expect(meta.ui?.csp).toEqual({
468
+ connectDomains: ["https://api.y.com"],
507
469
  });
508
470
  });
509
471
  it("should pass user _meta keys through to tool config", () => {
@@ -553,12 +515,8 @@ describe("resources/list view _meta injection", () => {
553
515
  await server.close();
554
516
  const appsSdk = resources.find((r) => r.uri.includes("apps-sdk"));
555
517
  const extApps = resources.find((r) => r.uri.includes("ext-apps"));
556
- expect(appsSdk?._meta).toBeDefined();
518
+ expect(appsSdk).toBeUndefined();
557
519
  expect(extApps?._meta).toBeDefined();
558
- const appsSdkCsp = appsSdk?._meta?.["openai/widgetCSP"];
559
- expect(appsSdkCsp.connect_domains?.length).toBeGreaterThan(0);
560
- expect(appsSdkCsp.resource_domains).toContain("https://fonts.googleapis.com");
561
- expect(appsSdk?._meta?.["openai/widgetDomain"]).toBe("skybridge.tech");
562
520
  const extUi = (extApps?._meta).ui;
563
521
  expect(extUi?.csp?.connectDomains?.length).toBeGreaterThan(0);
564
522
  expect(extUi?.csp?.resourceDomains).toContain("https://fonts.googleapis.com");
@@ -1 +1 @@
1
- {"version":3,"file":"view.test.js","sourceRoot":"","sources":["../../src/test/view.test.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"node:crypto\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { InMemoryTransport } from \"@modelcontextprotocol/sdk/inMemory.js\";\nimport type { RequestHandlerExtra } from \"@modelcontextprotocol/sdk/shared/protocol.js\";\nimport type {\n ServerNotification,\n ServerRequest,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport {\n afterEach,\n beforeEach,\n describe,\n expect,\n it,\n type MockInstance,\n vi,\n} from \"vitest\";\nimport type { McpServer, ViewName } from \"../server/server.js\";\nimport { McpServer as McpServerClass } from \"../server/server.js\";\nimport {\n createMockExtra,\n createMockMcpServer,\n resetTestEnv,\n setTestEnv,\n} from \"./utils.js\";\n\nconst mockManifest = {\n \"skybridge:view:my-view\": {\n file: \"assets/my-view-abc123.js\",\n name: \"my-view\",\n isEntry: true,\n },\n \"skybridge:view:folder-view\": {\n file: \"assets/folder-view-def456.js\",\n name: \"folder-view\",\n isEntry: true,\n },\n \"style.css\": { file: \"style.css\" },\n};\n\n// Mirrors `McpServer.computeViewVersionParam`. Tests recompute the expected\n// hash from the mocked manifest so they don't hardcode digest output.\nfunction expectedVersionParam(viewFile: string, styleFile: string): string {\n const hash = crypto\n .createHash(\"sha256\")\n .update(viewFile)\n .update(\"\\0\")\n .update(styleFile)\n .digest(\"hex\")\n .slice(0, 8);\n return `?v=${hash}`;\n}\n\nconst actual = vi.hoisted(() => require(\"node:fs\"));\n\nvi.mock(\"node:fs\", () => {\n const readFileSyncImpl = (\n path: Parameters<typeof actual.readFileSync>[0],\n ...args: unknown[]\n ): ReturnType<typeof actual.readFileSync> => {\n if (typeof path === \"string\" && path.includes(\"manifest.json\")) {\n return JSON.stringify(mockManifest) as ReturnType<\n typeof actual.readFileSync\n >;\n }\n return actual.readFileSync(path, ...args);\n };\n const readFileSync = vi.fn(readFileSyncImpl) as typeof actual.readFileSync;\n\n return {\n readFileSync,\n default: {\n readFileSync,\n },\n };\n});\n\ndescribe(\"McpServer.registerTool (unified API)\", () => {\n let server: McpServer;\n let mockRegisterResource: MockInstance<McpServer[\"registerResource\"]>;\n let mockRegisterTool: MockInstance;\n\n beforeEach(() => {\n ({ server, mockRegisterResource, mockRegisterTool } =\n createMockMcpServer());\n });\n\n afterEach(() => {\n vi.clearAllMocks();\n resetTestEnv();\n });\n\n it(\"should generate correct HTML for development mode\", async () => {\n setTestEnv({ NODE_ENV: \"development\" });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: {\n component: \"my-view\" as ViewName,\n description: \"Test view\",\n },\n },\n vi.fn(),\n );\n\n const appsSdkResourceCallback = mockRegisterResource.mock\n .calls[0]?.[3] as unknown as (\n uri: URL,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => Promise<{\n contents: Array<{ uri: URL | string; mimeType: string; text?: string }>;\n }>;\n expect(appsSdkResourceCallback).toBeDefined();\n\n const host = \"localhost:3000\";\n const serverUrl = `http://${host}`;\n const hmrUrl = `ws://${host}`;\n const mockExtra = createMockExtra(host) as unknown as RequestHandlerExtra<\n ServerRequest,\n ServerNotification\n >;\n const result = await appsSdkResourceCallback(\n new URL(\"ui://views/apps-sdk/my-view.html\"),\n mockExtra,\n );\n\n expect(mockRegisterTool).toHaveBeenCalled();\n expect(result).toEqual({\n contents: [\n {\n uri: \"ui://views/apps-sdk/my-view.html\",\n mimeType: \"text/html+skybridge\",\n text: expect.stringContaining('<div id=\"root\"></div>'),\n _meta: {\n \"openai/widgetCSP\": {\n resource_domains: [serverUrl],\n connect_domains: [serverUrl, hmrUrl],\n },\n \"openai/widgetDomain\": serverUrl,\n \"openai/widgetDescription\": \"Test view\",\n },\n },\n ],\n });\n\n expect(result.contents[0]?.text).toContain(\n `${serverUrl}/assets/@react-refresh`,\n );\n expect(result.contents[0]?.text).toContain(`${serverUrl}/@vite/client`);\n expect(result.contents[0]?.text).toContain(\n `${serverUrl}/_skybridge/view/my-view`,\n );\n });\n\n it(\"should generate correct HTML for production mode\", async () => {\n setTestEnv({ NODE_ENV: \"production\" });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: {\n component: \"my-view\" as ViewName,\n description: \"Test view\",\n },\n },\n vi.fn(),\n );\n\n const appsSdkResourceCallback = mockRegisterResource.mock\n .calls[0]?.[3] as unknown as (\n uri: URL,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => Promise<{\n contents: Array<{ uri: URL | string; mimeType: string; text?: string }>;\n }>;\n expect(appsSdkResourceCallback).toBeDefined();\n\n const host = \"myapp.com\";\n const serverUrl = `https://${host}`;\n const mockExtra = createMockExtra(host) as unknown as RequestHandlerExtra<\n ServerRequest,\n ServerNotification\n >;\n const versionedUri = `ui://views/apps-sdk/my-view.html${expectedVersionParam(\"assets/my-view-abc123.js\", \"style.css\")}`;\n const result = await appsSdkResourceCallback(\n new URL(versionedUri),\n mockExtra,\n );\n\n expect(result).toEqual({\n contents: [\n {\n uri: versionedUri,\n mimeType: \"text/html+skybridge\",\n text: expect.stringContaining('<div id=\"root\"></div>'),\n _meta: {\n \"openai/widgetCSP\": {\n resource_domains: [serverUrl],\n connect_domains: [serverUrl],\n },\n \"openai/widgetDomain\": serverUrl,\n \"openai/widgetDescription\": \"Test view\",\n },\n },\n ],\n });\n\n expect(result.contents[0]?.text).not.toContain(\n `${serverUrl}/assets/@react-refresh`,\n );\n expect(result.contents[0]?.text).not.toContain(`${serverUrl}@vite/client`);\n expect(result.contents[0]?.text).toContain(\n `${serverUrl}/assets/assets/my-view-abc123.js`,\n );\n expect(result.contents[0]?.text).toContain(`${serverUrl}/assets/style.css`);\n });\n\n it(\"should prefer x-alpic-forwarded-url when hashing Claude view domains\", async () => {\n setTestEnv({ NODE_ENV: \"production\" });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n vi.fn(),\n );\n\n const extAppsResourceCallback = mockRegisterResource.mock\n .calls[1]?.[3] as unknown as (\n uri: URL,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => Promise<{\n contents: Array<{\n uri: URL | string;\n mimeType: string;\n text?: string;\n _meta?: Record<string, unknown>;\n }>;\n }>;\n expect(extAppsResourceCallback).toBeDefined();\n\n const forwardedUrl =\n \"https://everything-3a2c1264.staging.alpic.live/mcp?foo=bar\";\n const expectedDomain = `${crypto\n .createHash(\"sha256\")\n .update(forwardedUrl)\n .digest(\"hex\")\n .slice(0, 32)}.claudemcpcontent.com`;\n\n const result = await extAppsResourceCallback(\n new URL(\n `ui://views/ext-apps/my-view.html${expectedVersionParam(\"assets/my-view-abc123.js\", \"style.css\")}`,\n ),\n createMockExtra(\"localhost:3000\", {\n headers: {\n \"user-agent\": \"Claude-User\",\n \"x-alpic-forwarded-url\": forwardedUrl,\n },\n url: \"http://localhost:3000/mcp\",\n }) as unknown as RequestHandlerExtra<ServerRequest, ServerNotification>,\n );\n\n expect(result.contents[0]?._meta).toEqual({\n ui: {\n csp: {\n resourceDomains: [\"http://localhost:3000\"],\n connectDomains: [\"http://localhost:3000\"],\n baseUriDomains: [\"http://localhost:3000\"],\n },\n description: \"Test view\",\n domain: expectedDomain,\n },\n });\n });\n\n it(\"should register resources with correct hostType for both apps-sdk and ext-apps\", async () => {\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: {\n component: \"my-view\" as ViewName,\n description: \"Test view\",\n prefersBorder: true,\n },\n },\n vi.fn(),\n );\n\n expect(mockRegisterResource).toHaveBeenCalledTimes(2);\n\n const appsSdkCallback = mockRegisterResource.mock\n .calls[0]?.[3] as unknown as (\n uri: URL,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => Promise<{\n contents: Array<{ uri: URL | string; mimeType: string; text?: string }>;\n }>;\n const host = \"localhost:3000\";\n const serverUrl = `http://${host}`;\n const hmrUrl = `ws://${host}`;\n\n const appsSdkResult = await appsSdkCallback(\n new URL(\"ui://views/apps-sdk/my-view.html\"),\n createMockExtra(host) as unknown as RequestHandlerExtra<\n ServerRequest,\n ServerNotification\n >,\n );\n\n expect(appsSdkResult).toEqual({\n contents: [\n {\n uri: \"ui://views/apps-sdk/my-view.html\",\n mimeType: \"text/html+skybridge\",\n text: expect.stringContaining('<div id=\"root\"></div>'),\n _meta: {\n \"openai/widgetCSP\": {\n resource_domains: [serverUrl],\n connect_domains: [serverUrl, hmrUrl],\n },\n \"openai/widgetDomain\": serverUrl,\n \"openai/widgetDescription\": \"Test view\",\n \"openai/widgetPrefersBorder\": true,\n },\n },\n ],\n });\n expect(appsSdkResult.contents[0]?.text).toContain(\n 'window.skybridge = { hostType: \"apps-sdk\", serverUrl: \"http://localhost:3000\" };',\n );\n\n const extAppsResourceCallback = mockRegisterResource.mock\n .calls[1]?.[3] as unknown as (\n uri: URL,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => Promise<{\n contents: Array<{\n uri: URL | string;\n mimeType: string;\n text?: string;\n _meta?: Record<string, unknown>;\n }>;\n }>;\n expect(extAppsResourceCallback).toBeDefined();\n\n const extAppsResult = await extAppsResourceCallback(\n new URL(\"ui://views/ext-apps/my-view.html\"),\n createMockExtra(host) as unknown as RequestHandlerExtra<\n ServerRequest,\n ServerNotification\n >,\n );\n\n expect(extAppsResult).toEqual({\n contents: [\n {\n uri: \"ui://views/ext-apps/my-view.html\",\n mimeType: \"text/html;profile=mcp-app\",\n text: expect.stringContaining('<div id=\"root\"></div>'),\n _meta: {\n ui: {\n csp: {\n resourceDomains: [serverUrl],\n connectDomains: [serverUrl, hmrUrl],\n baseUriDomains: [serverUrl],\n },\n domain: serverUrl,\n description: \"Test view\",\n prefersBorder: true,\n },\n },\n },\n ],\n });\n expect(extAppsResult.contents[0]?.text).toContain(\n 'window.skybridge = { hostType: \"mcp-app\", serverUrl: \"http://localhost:3000\" };',\n );\n });\n\n it(\"should register tool with ui.resourceUri metadata\", async () => {\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n vi.fn(),\n );\n\n expect(mockRegisterTool).toHaveBeenCalledTimes(1);\n\n const toolCallArgs = mockRegisterTool.mock.calls[0];\n const toolConfig = toolCallArgs?.[1] as { _meta?: Record<string, unknown> };\n\n expect(toolConfig._meta).toHaveProperty(\"ui\");\n expect(toolConfig._meta?.ui).toEqual({\n resourceUri: \"ui://views/ext-apps/my-view.html\",\n });\n });\n\n it(\"should register tool with openai/outputTemplate when apps-sdk only\", async () => {\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: {\n component: \"my-view\" as ViewName,\n description: \"Test view\",\n hosts: [\"apps-sdk\"],\n },\n },\n vi.fn(),\n );\n\n expect(mockRegisterTool).toHaveBeenCalledTimes(1);\n\n const toolCallArgs = mockRegisterTool.mock.calls[0];\n const toolConfig = toolCallArgs?.[1] as { _meta?: Record<string, unknown> };\n\n expect(toolConfig._meta).not.toHaveProperty(\"ui\");\n expect(toolConfig._meta?.[\"openai/outputTemplate\"]).toBe(\n \"ui://views/apps-sdk/my-view.html\",\n );\n });\n\n it(\"should not version view URIs in development\", () => {\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n vi.fn(),\n );\n\n const toolConfig = mockRegisterTool.mock.calls[0]?.[1] as {\n _meta?: Record<string, unknown> & { ui?: { resourceUri?: string } };\n };\n\n expect(toolConfig._meta?.[\"openai/outputTemplate\"]).toBe(\n \"ui://views/apps-sdk/my-view.html\",\n );\n expect(toolConfig._meta?.ui?.resourceUri).toBe(\n \"ui://views/ext-apps/my-view.html\",\n );\n // The URI registered with the resource handler must match the URI in\n // outputTemplate exactly so the SDK can resolve `resources/read` requests.\n expect(mockRegisterResource.mock.calls[0]?.[1]).toBe(\n \"ui://views/apps-sdk/my-view.html\",\n );\n expect(mockRegisterResource.mock.calls[1]?.[1]).toBe(\n \"ui://views/ext-apps/my-view.html\",\n );\n });\n\n it(\"should append a stable content hash to view URIs in production\", () => {\n setTestEnv({ NODE_ENV: \"production\" });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n vi.fn(),\n );\n\n const expected = expectedVersionParam(\n \"assets/my-view-abc123.js\",\n \"style.css\",\n );\n const toolConfig = mockRegisterTool.mock.calls[0]?.[1] as {\n _meta?: Record<string, unknown> & { ui?: { resourceUri?: string } };\n };\n\n expect(toolConfig._meta?.[\"openai/outputTemplate\"]).toBe(\n `ui://views/apps-sdk/my-view.html${expected}`,\n );\n expect(toolConfig._meta?.ui?.resourceUri).toBe(\n `ui://views/ext-apps/my-view.html${expected}`,\n );\n expect(mockRegisterResource.mock.calls[0]?.[1]).toBe(\n `ui://views/apps-sdk/my-view.html${expected}`,\n );\n expect(mockRegisterResource.mock.calls[1]?.[1]).toBe(\n `ui://views/ext-apps/my-view.html${expected}`,\n );\n });\n\n it(\"should produce different version params for views with different bundles\", () => {\n setTestEnv({ NODE_ENV: \"production\" });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"First tool\",\n view: { component: \"my-view\" as ViewName },\n },\n vi.fn(),\n );\n server.registerTool(\n {\n name: \"folder-view\",\n description: \"Second tool\",\n view: { component: \"folder-view\" as ViewName },\n },\n vi.fn(),\n );\n\n const myviewTemplate = (\n mockRegisterTool.mock.calls[0]?.[1] as { _meta?: Record<string, unknown> }\n )._meta?.[\"openai/outputTemplate\"];\n const folderviewTemplate = (\n mockRegisterTool.mock.calls[1]?.[1] as { _meta?: Record<string, unknown> }\n )._meta?.[\"openai/outputTemplate\"];\n\n expect(myviewTemplate).not.toEqual(folderviewTemplate);\n expect(myviewTemplate).toMatch(/\\?v=[0-9a-f]{8}$/);\n expect(folderviewTemplate).toMatch(/\\?v=[0-9a-f]{8}$/);\n });\n\n it(\"should fall back to bare URI in production when manifest is missing\", () => {\n setTestEnv({ NODE_ENV: \"production\" });\n\n server.registerTool(\n {\n name: \"unknown-view\",\n description: \"Test tool\",\n view: { component: \"unknown-view\" as ViewName },\n },\n vi.fn(),\n );\n\n const toolConfig = mockRegisterTool.mock.calls[0]?.[1] as {\n _meta?: Record<string, unknown>;\n };\n expect(toolConfig._meta?.[\"openai/outputTemplate\"]).toBe(\n \"ui://views/apps-sdk/unknown-view.html\",\n );\n });\n\n it(\"should register tool with ui.resourceUri only when mcp-app only\", async () => {\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: {\n component: \"my-view\" as ViewName,\n description: \"Test view\",\n hosts: [\"mcp-app\"],\n },\n },\n vi.fn(),\n );\n\n expect(mockRegisterTool).toHaveBeenCalledTimes(1);\n\n const toolCallArgs = mockRegisterTool.mock.calls[0];\n const toolConfig = toolCallArgs?.[1] as { _meta?: Record<string, unknown> };\n\n expect(toolConfig._meta).toHaveProperty(\"ui\");\n expect(toolConfig._meta?.ui).toEqual({\n resourceUri: \"ui://views/ext-apps/my-view.html\",\n });\n expect(toolConfig._meta?.[\"openai/outputTemplate\"]).toBeUndefined();\n });\n\n it(\"should inject viewUUID into _meta of tool callback results\", async () => {\n const mockToolCallback = vi.fn().mockResolvedValue({\n content: [{ type: \"text\", text: \"result\" }],\n structuredContent: { data: \"test\" },\n });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n mockToolCallback,\n );\n\n const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2] as (\n ...args: unknown[]\n ) => Promise<{ _meta?: Record<string, unknown> }>;\n expect(wrappedCallback).toBeDefined();\n\n const result = await wrappedCallback({}, {});\n\n expect(result._meta).toBeDefined();\n expect(result._meta?.viewUUID).toBeDefined();\n expect(typeof result._meta?.viewUUID).toBe(\"string\");\n expect(result._meta?.viewUUID).toMatch(\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,\n );\n });\n\n it(\"should preserve existing _meta when injecting viewUUID\", async () => {\n const mockToolCallback = vi.fn().mockResolvedValue({\n content: [{ type: \"text\", text: \"result\" }],\n structuredContent: { data: \"test\" },\n _meta: { requestId: \"req-123\", cached: true },\n });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n mockToolCallback,\n );\n\n const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2] as (\n ...args: unknown[]\n ) => Promise<{ _meta?: Record<string, unknown> }>;\n const result = await wrappedCallback({}, {});\n\n expect(result._meta?.requestId).toBe(\"req-123\");\n expect(result._meta?.cached).toBe(true);\n expect(result._meta?.viewUUID).toBeDefined();\n });\n\n it(\"should generate unique viewUUIDs across calls\", async () => {\n const mockToolCallback = vi.fn().mockResolvedValue({\n content: [{ type: \"text\", text: \"result\" }],\n structuredContent: {},\n });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n mockToolCallback,\n );\n\n const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2] as (\n ...args: unknown[]\n ) => Promise<{ _meta?: Record<string, unknown> }>;\n const result1 = await wrappedCallback({}, {});\n const result2 = await wrappedCallback({}, {});\n\n expect(result1._meta?.viewUUID).not.toBe(result2._meta?.viewUUID);\n });\n\n it(\"should enforce one-tool-per-view constraint\", () => {\n server.registerTool(\n {\n name: \"shake\",\n description: \"First tool\",\n view: { component: \"magic-8-ball\" as ViewName },\n },\n vi.fn(),\n );\n\n expect(() => {\n server.registerTool(\n {\n name: \"shake-v2\",\n description: \"Second tool\",\n view: { component: \"magic-8-ball\" as ViewName },\n },\n vi.fn(),\n );\n }).toThrow(\n 'skybridge: view \"magic-8-ball\" is already used by tool \"shake\"',\n );\n });\n\n it(\"should normalize string content to ContentBlock array\", async () => {\n const mockToolCallback = vi.fn().mockResolvedValue({\n content: \"Hello world\",\n structuredContent: {},\n });\n\n server.registerTool(\n {\n name: \"string-content\",\n description: \"Test tool\",\n view: { component: \"string-content\" as ViewName },\n },\n mockToolCallback,\n );\n\n const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2] as (\n ...args: unknown[]\n ) => Promise<{ content: unknown[] }>;\n const result = await wrappedCallback({}, {});\n\n expect(result.content).toEqual([{ type: \"text\", text: \"Hello world\" }]);\n });\n\n it(\"should normalize single ContentBlock to array\", async () => {\n const mockToolCallback = vi.fn().mockResolvedValue({\n content: { type: \"text\", text: \"Single block\" },\n structuredContent: {},\n });\n\n server.registerTool(\n {\n name: \"single-block\",\n description: \"Test tool\",\n view: { component: \"single-block\" as ViewName },\n },\n mockToolCallback,\n );\n\n const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2] as (\n ...args: unknown[]\n ) => Promise<{ content: unknown[] }>;\n const result = await wrappedCallback({}, {});\n\n expect(result.content).toEqual([{ type: \"text\", text: \"Single block\" }]);\n });\n\n it(\"should pass through ContentBlock array unchanged\", async () => {\n const blocks = [\n { type: \"text\", text: \"A\" },\n { type: \"text\", text: \"B\" },\n ];\n const mockToolCallback = vi.fn().mockResolvedValue({\n content: blocks,\n structuredContent: {},\n });\n\n server.registerTool(\n {\n name: \"array-content\",\n description: \"Test tool\",\n view: { component: \"array-content\" as ViewName },\n },\n mockToolCallback,\n );\n\n const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2] as (\n ...args: unknown[]\n ) => Promise<{ content: unknown[] }>;\n const result = await wrappedCallback({}, {});\n\n expect(result.content).toEqual(blocks);\n });\n\n it(\"should register tool without view (no resource registration)\", () => {\n server.registerTool(\n {\n name: \"plain-tool\",\n description: \"No view\",\n },\n vi.fn(),\n );\n\n expect(mockRegisterResource).not.toHaveBeenCalled();\n expect(mockRegisterTool).toHaveBeenCalledTimes(1);\n });\n\n it(\"should apply view.csp fields to resource _meta\", async () => {\n server.registerTool(\n {\n name: \"csp-tool\",\n description: \"Test tool\",\n view: {\n component: \"csp-tool\" as ViewName,\n description: \"Test view\",\n csp: {\n connectDomains: [\"https://api.example.com\"],\n resourceDomains: [\"https://cdn.example.com\"],\n },\n },\n },\n vi.fn(),\n );\n\n const appsSdkCallback = mockRegisterResource.mock\n .calls[0]?.[3] as unknown as (\n uri: URL,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => Promise<{\n contents: Array<{\n uri: URL | string;\n mimeType: string;\n _meta?: Record<string, unknown>;\n }>;\n }>;\n\n const host = \"localhost:3000\";\n const serverUrl = `http://${host}`;\n const hmrUrl = `ws://${host}`;\n const result = await appsSdkCallback(\n new URL(\"ui://views/apps-sdk/csp-tool.html\"),\n createMockExtra(host) as unknown as RequestHandlerExtra<\n ServerRequest,\n ServerNotification\n >,\n );\n\n const meta = result.contents[0]?._meta as Record<string, unknown>;\n expect(meta[\"openai/widgetCSP\"]).toEqual({\n resource_domains: [serverUrl, \"https://cdn.example.com\"],\n connect_domains: [serverUrl, hmrUrl, \"https://api.example.com\"],\n });\n });\n\n it(\"should let view._meta override framework-computed keys\", async () => {\n server.registerTool(\n {\n name: \"override-tool\",\n description: \"Test tool\",\n view: {\n component: \"override-tool\" as ViewName,\n description: \"Test view\",\n csp: { connectDomains: [\"https://api.x.com\"] },\n _meta: {\n \"openai/widgetCSP\": {\n connect_domains: [\"https://api.y.com\"],\n },\n },\n },\n },\n vi.fn(),\n );\n\n const appsSdkCallback = mockRegisterResource.mock\n .calls[0]?.[3] as unknown as (\n uri: URL,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => Promise<{\n contents: Array<{\n uri: URL | string;\n mimeType: string;\n _meta?: Record<string, unknown>;\n }>;\n }>;\n\n const result = await appsSdkCallback(\n new URL(\"ui://views/apps-sdk/override-tool.html\"),\n createMockExtra(\"localhost:3000\") as unknown as RequestHandlerExtra<\n ServerRequest,\n ServerNotification\n >,\n );\n\n const meta = result.contents[0]?._meta as Record<string, unknown>;\n expect(meta[\"openai/widgetCSP\"]).toEqual({\n connect_domains: [\"https://api.y.com\"],\n });\n });\n\n it(\"should pass user _meta keys through to tool config\", () => {\n server.registerTool(\n {\n name: \"meta-tool\",\n description: \"Test tool\",\n _meta: {\n \"openai/widgetAccessible\": true,\n \"openai/toolInvocation/invoking\": \"Loading...\",\n \"acme.com/category\": \"utility\",\n },\n },\n vi.fn(),\n );\n\n const toolCallArgs = mockRegisterTool.mock.calls[0];\n const toolConfig = toolCallArgs?.[1] as { _meta?: Record<string, unknown> };\n\n expect(toolConfig._meta?.[\"openai/widgetAccessible\"]).toBe(true);\n expect(toolConfig._meta?.[\"openai/toolInvocation/invoking\"]).toBe(\n \"Loading...\",\n );\n expect(toolConfig._meta?.[\"acme.com/category\"]).toBe(\"utility\");\n });\n});\n\ndescribe(\"resources/list view _meta injection\", () => {\n afterEach(() => resetTestEnv());\n\n it(\"attaches CSP, domain, and connectDomains _meta to view resources at list time\", async () => {\n setTestEnv({ NODE_ENV: \"production\" });\n\n const server = new McpServerClass(\n { name: \"test\", version: \"1.0.0\" },\n { capabilities: {} },\n );\n server.registerTool(\n {\n name: \"start\",\n description: \"Start\",\n view: {\n component: \"my-view\" as ViewName,\n description: \"Onboarding deck\",\n domain: \"skybridge.tech\",\n csp: {\n resourceDomains: [\"https://fonts.googleapis.com\"],\n redirectDomains: [\"https://docs.skybridge.tech\"],\n },\n },\n },\n vi.fn().mockResolvedValue({\n content: [{ type: \"text\", text: \"ok\" }],\n structuredContent: {},\n }),\n );\n\n const client = new Client({ name: \"test-client\", version: \"1.0.0\" });\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n await server.connect(serverTransport);\n await client.connect(clientTransport);\n\n const { resources } = await client.listResources();\n await client.close();\n await server.close();\n\n const appsSdk = resources.find((r) => r.uri.includes(\"apps-sdk\"));\n const extApps = resources.find((r) => r.uri.includes(\"ext-apps\"));\n expect(appsSdk?._meta).toBeDefined();\n expect(extApps?._meta).toBeDefined();\n\n const appsSdkCsp = (appsSdk?._meta as Record<string, unknown>)?.[\n \"openai/widgetCSP\"\n ] as { resource_domains?: string[]; connect_domains?: string[] };\n expect(appsSdkCsp.connect_domains?.length).toBeGreaterThan(0);\n expect(appsSdkCsp.resource_domains).toContain(\n \"https://fonts.googleapis.com\",\n );\n expect(\n (appsSdk?._meta as Record<string, unknown>)?.[\"openai/widgetDomain\"],\n ).toBe(\"skybridge.tech\");\n\n const extUi = (\n extApps?._meta as {\n ui?: {\n csp?: { connectDomains?: string[]; resourceDomains?: string[] };\n domain?: string;\n };\n }\n ).ui;\n expect(extUi?.csp?.connectDomains?.length).toBeGreaterThan(0);\n expect(extUi?.csp?.resourceDomains).toContain(\n \"https://fonts.googleapis.com\",\n );\n expect(extUi?.domain).toBe(\"skybridge.tech\");\n });\n});\n"]}
1
+ {"version":3,"file":"view.test.js","sourceRoot":"","sources":["../../src/test/view.test.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"node:crypto\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { InMemoryTransport } from \"@modelcontextprotocol/sdk/inMemory.js\";\nimport type { RequestHandlerExtra } from \"@modelcontextprotocol/sdk/shared/protocol.js\";\nimport type {\n ServerNotification,\n ServerRequest,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport {\n afterEach,\n beforeEach,\n describe,\n expect,\n it,\n type MockInstance,\n vi,\n} from \"vitest\";\nimport type { McpServer, ViewName } from \"../server/server.js\";\nimport { McpServer as McpServerClass } from \"../server/server.js\";\nimport {\n createMockExtra,\n createMockMcpServer,\n resetTestEnv,\n setTestEnv,\n} from \"./utils.js\";\n\nconst mockManifest = {\n \"skybridge:view:my-view\": {\n file: \"assets/my-view-abc123.js\",\n name: \"my-view\",\n isEntry: true,\n },\n \"skybridge:view:folder-view\": {\n file: \"assets/folder-view-def456.js\",\n name: \"folder-view\",\n isEntry: true,\n },\n \"style.css\": { file: \"style.css\" },\n};\n\n// Mirrors `McpServer.computeViewVersionParam`. Tests recompute the expected\n// hash from the mocked manifest so they don't hardcode digest output.\nfunction expectedVersionParam(viewFile: string, styleFile: string): string {\n const hash = crypto\n .createHash(\"sha256\")\n .update(viewFile)\n .update(\"\\0\")\n .update(styleFile)\n .digest(\"hex\")\n .slice(0, 8);\n return `?v=${hash}`;\n}\n\nconst actual = vi.hoisted(() => require(\"node:fs\"));\n\nvi.mock(\"node:fs\", () => {\n const readFileSyncImpl = (\n path: Parameters<typeof actual.readFileSync>[0],\n ...args: unknown[]\n ): ReturnType<typeof actual.readFileSync> => {\n if (typeof path === \"string\" && path.includes(\"manifest.json\")) {\n return JSON.stringify(mockManifest) as ReturnType<\n typeof actual.readFileSync\n >;\n }\n return actual.readFileSync(path, ...args);\n };\n const readFileSync = vi.fn(readFileSyncImpl) as typeof actual.readFileSync;\n\n return {\n readFileSync,\n default: {\n readFileSync,\n },\n };\n});\n\ndescribe(\"McpServer.registerTool (unified API)\", () => {\n let server: McpServer;\n let mockRegisterResource: MockInstance<McpServer[\"registerResource\"]>;\n let mockRegisterTool: MockInstance;\n\n beforeEach(() => {\n ({ server, mockRegisterResource, mockRegisterTool } =\n createMockMcpServer());\n });\n\n afterEach(() => {\n vi.clearAllMocks();\n resetTestEnv();\n });\n\n it(\"should generate correct HTML for development mode\", async () => {\n setTestEnv({ NODE_ENV: \"development\" });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: {\n component: \"my-view\" as ViewName,\n description: \"Test view\",\n },\n },\n vi.fn(),\n );\n\n const appsSdkResourceCallback = mockRegisterResource.mock\n .calls[0]?.[3] as unknown as (\n uri: URL,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => Promise<{\n contents: Array<{ uri: URL | string; mimeType: string; text?: string }>;\n }>;\n expect(appsSdkResourceCallback).toBeDefined();\n\n const host = \"localhost:3000\";\n const serverUrl = `http://${host}`;\n const hmrUrl = `ws://${host}`;\n const mockExtra = createMockExtra(host) as unknown as RequestHandlerExtra<\n ServerRequest,\n ServerNotification\n >;\n const result = await appsSdkResourceCallback(\n new URL(\"ui://views/ext-apps/my-view.html\"),\n mockExtra,\n );\n\n expect(mockRegisterTool).toHaveBeenCalled();\n expect(result).toEqual({\n contents: [\n {\n uri: \"ui://views/ext-apps/my-view.html\",\n mimeType: \"text/html;profile=mcp-app\",\n text: expect.stringContaining('<div id=\"root\"></div>'),\n _meta: {\n ui: {\n csp: {\n resourceDomains: [serverUrl],\n connectDomains: [serverUrl, hmrUrl],\n baseUriDomains: [serverUrl],\n },\n domain: serverUrl,\n description: \"Test view\",\n },\n },\n },\n ],\n });\n\n expect(result.contents[0]?.text).toContain(\n `${serverUrl}/assets/@react-refresh`,\n );\n expect(result.contents[0]?.text).toContain(`${serverUrl}/@vite/client`);\n expect(result.contents[0]?.text).toContain(\n `${serverUrl}/_skybridge/view/my-view`,\n );\n });\n\n it(\"should generate correct HTML for production mode\", async () => {\n setTestEnv({ NODE_ENV: \"production\" });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: {\n component: \"my-view\" as ViewName,\n description: \"Test view\",\n },\n },\n vi.fn(),\n );\n\n const appsSdkResourceCallback = mockRegisterResource.mock\n .calls[0]?.[3] as unknown as (\n uri: URL,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => Promise<{\n contents: Array<{ uri: URL | string; mimeType: string; text?: string }>;\n }>;\n expect(appsSdkResourceCallback).toBeDefined();\n\n const host = \"myapp.com\";\n const serverUrl = `https://${host}`;\n const mockExtra = createMockExtra(host) as unknown as RequestHandlerExtra<\n ServerRequest,\n ServerNotification\n >;\n const versionedUri = `ui://views/ext-apps/my-view.html${expectedVersionParam(\"assets/my-view-abc123.js\", \"style.css\")}`;\n const result = await appsSdkResourceCallback(\n new URL(versionedUri),\n mockExtra,\n );\n\n expect(result).toEqual({\n contents: [\n {\n uri: versionedUri,\n mimeType: \"text/html;profile=mcp-app\",\n text: expect.stringContaining('<div id=\"root\"></div>'),\n _meta: {\n ui: {\n csp: {\n resourceDomains: [serverUrl],\n connectDomains: [serverUrl],\n baseUriDomains: [serverUrl],\n },\n domain: serverUrl,\n description: \"Test view\",\n },\n },\n },\n ],\n });\n\n expect(result.contents[0]?.text).not.toContain(\n `${serverUrl}/assets/@react-refresh`,\n );\n expect(result.contents[0]?.text).not.toContain(`${serverUrl}@vite/client`);\n expect(result.contents[0]?.text).toContain(\n `${serverUrl}/assets/assets/my-view-abc123.js`,\n );\n expect(result.contents[0]?.text).toContain(`${serverUrl}/assets/style.css`);\n });\n\n it(\"should prefer x-alpic-forwarded-url when hashing Claude view domains\", async () => {\n setTestEnv({ NODE_ENV: \"production\" });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n vi.fn(),\n );\n\n const extAppsResourceCallback = mockRegisterResource.mock\n .calls[0]?.[3] as unknown as (\n uri: URL,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => Promise<{\n contents: Array<{\n uri: URL | string;\n mimeType: string;\n text?: string;\n _meta?: Record<string, unknown>;\n }>;\n }>;\n expect(extAppsResourceCallback).toBeDefined();\n\n const forwardedUrl =\n \"https://everything-3a2c1264.staging.alpic.live/mcp?foo=bar\";\n const expectedDomain = `${crypto\n .createHash(\"sha256\")\n .update(forwardedUrl)\n .digest(\"hex\")\n .slice(0, 32)}.claudemcpcontent.com`;\n\n const result = await extAppsResourceCallback(\n new URL(\n `ui://views/ext-apps/my-view.html${expectedVersionParam(\"assets/my-view-abc123.js\", \"style.css\")}`,\n ),\n createMockExtra(\"localhost:3000\", {\n headers: {\n \"user-agent\": \"Claude-User\",\n \"x-alpic-forwarded-url\": forwardedUrl,\n },\n url: \"http://localhost:3000/mcp\",\n }) as unknown as RequestHandlerExtra<ServerRequest, ServerNotification>,\n );\n\n expect(result.contents[0]?._meta).toEqual({\n ui: {\n csp: {\n resourceDomains: [\"http://localhost:3000\"],\n connectDomains: [\"http://localhost:3000\"],\n baseUriDomains: [\"http://localhost:3000\"],\n },\n description: \"Test view\",\n domain: expectedDomain,\n },\n });\n });\n\n it(\"should register a single ext-apps resource\", async () => {\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: {\n component: \"my-view\" as ViewName,\n description: \"Test view\",\n prefersBorder: true,\n },\n },\n vi.fn(),\n );\n\n expect(mockRegisterResource).toHaveBeenCalledTimes(1);\n\n const resourceCallback = mockRegisterResource.mock\n .calls[0]?.[3] as unknown as (\n uri: URL,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => Promise<{\n contents: Array<{\n uri: URL | string;\n mimeType: string;\n text?: string;\n _meta?: Record<string, unknown>;\n }>;\n }>;\n const host = \"localhost:3000\";\n const serverUrl = `http://${host}`;\n const hmrUrl = `ws://${host}`;\n\n const result = await resourceCallback(\n new URL(\"ui://views/ext-apps/my-view.html\"),\n createMockExtra(host) as unknown as RequestHandlerExtra<\n ServerRequest,\n ServerNotification\n >,\n );\n\n expect(result).toEqual({\n contents: [\n {\n uri: \"ui://views/ext-apps/my-view.html\",\n mimeType: \"text/html;profile=mcp-app\",\n text: expect.stringContaining('<div id=\"root\"></div>'),\n _meta: {\n ui: {\n csp: {\n resourceDomains: [serverUrl],\n connectDomains: [serverUrl, hmrUrl],\n baseUriDomains: [serverUrl],\n },\n domain: serverUrl,\n description: \"Test view\",\n prefersBorder: true,\n },\n },\n },\n ],\n });\n expect(result.contents[0]?.text).toContain(\n 'window.skybridge = { hostType: \"mcp-app\", serverUrl: \"http://localhost:3000\" };',\n );\n });\n\n it(\"should advertise the single resource via ui.resourceUri and openai/outputTemplate alias\", async () => {\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n vi.fn(),\n );\n\n const toolConfig = mockRegisterTool.mock.calls[0]?.[1] as {\n _meta?: Record<string, unknown> & { ui?: { resourceUri?: string } };\n };\n const uri = \"ui://views/ext-apps/my-view.html\";\n\n expect(toolConfig._meta?.ui?.resourceUri).toBe(uri);\n expect(toolConfig._meta?.[\"ui/resourceUri\"]).toBe(uri);\n expect(toolConfig._meta?.[\"openai/outputTemplate\"]).toBe(uri);\n });\n\n it(\"treats the deprecated hosts option as a no-op (always the single resource)\", async () => {\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: {\n component: \"my-view\" as ViewName,\n description: \"Test view\",\n hosts: [\"apps-sdk\"],\n },\n },\n vi.fn(),\n );\n\n expect(mockRegisterResource).toHaveBeenCalledTimes(1);\n const toolConfig = mockRegisterTool.mock.calls[0]?.[1] as {\n _meta?: Record<string, unknown> & { ui?: { resourceUri?: string } };\n };\n expect(toolConfig._meta?.ui?.resourceUri).toBe(\n \"ui://views/ext-apps/my-view.html\",\n );\n expect(toolConfig._meta?.[\"openai/outputTemplate\"]).toBe(\n \"ui://views/ext-apps/my-view.html\",\n );\n });\n\n it(\"should not version view URIs in development\", () => {\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n vi.fn(),\n );\n\n const toolConfig = mockRegisterTool.mock.calls[0]?.[1] as {\n _meta?: Record<string, unknown> & { ui?: { resourceUri?: string } };\n };\n\n expect(toolConfig._meta?.[\"openai/outputTemplate\"]).toBe(\n \"ui://views/ext-apps/my-view.html\",\n );\n expect(toolConfig._meta?.ui?.resourceUri).toBe(\n \"ui://views/ext-apps/my-view.html\",\n );\n // The URI registered with the resource handler must match the URI in\n // outputTemplate exactly so the SDK can resolve `resources/read` requests.\n expect(mockRegisterResource.mock.calls[0]?.[1]).toBe(\n \"ui://views/ext-apps/my-view.html\",\n );\n });\n\n it(\"should append a stable content hash to view URIs in production\", () => {\n setTestEnv({ NODE_ENV: \"production\" });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n vi.fn(),\n );\n\n const expected = expectedVersionParam(\n \"assets/my-view-abc123.js\",\n \"style.css\",\n );\n const toolConfig = mockRegisterTool.mock.calls[0]?.[1] as {\n _meta?: Record<string, unknown> & { ui?: { resourceUri?: string } };\n };\n\n expect(toolConfig._meta?.[\"openai/outputTemplate\"]).toBe(\n `ui://views/ext-apps/my-view.html${expected}`,\n );\n expect(toolConfig._meta?.ui?.resourceUri).toBe(\n `ui://views/ext-apps/my-view.html${expected}`,\n );\n expect(mockRegisterResource.mock.calls[0]?.[1]).toBe(\n `ui://views/ext-apps/my-view.html${expected}`,\n );\n });\n\n it(\"should produce different version params for views with different bundles\", () => {\n setTestEnv({ NODE_ENV: \"production\" });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"First tool\",\n view: { component: \"my-view\" as ViewName },\n },\n vi.fn(),\n );\n server.registerTool(\n {\n name: \"folder-view\",\n description: \"Second tool\",\n view: { component: \"folder-view\" as ViewName },\n },\n vi.fn(),\n );\n\n const myviewTemplate = (\n mockRegisterTool.mock.calls[0]?.[1] as { _meta?: Record<string, unknown> }\n )._meta?.[\"openai/outputTemplate\"];\n const folderviewTemplate = (\n mockRegisterTool.mock.calls[1]?.[1] as { _meta?: Record<string, unknown> }\n )._meta?.[\"openai/outputTemplate\"];\n\n expect(myviewTemplate).not.toEqual(folderviewTemplate);\n expect(myviewTemplate).toMatch(/\\?v=[0-9a-f]{8}$/);\n expect(folderviewTemplate).toMatch(/\\?v=[0-9a-f]{8}$/);\n });\n\n it(\"should fall back to bare URI in production when manifest is missing\", () => {\n setTestEnv({ NODE_ENV: \"production\" });\n\n server.registerTool(\n {\n name: \"unknown-view\",\n description: \"Test tool\",\n view: { component: \"unknown-view\" as ViewName },\n },\n vi.fn(),\n );\n\n const toolConfig = mockRegisterTool.mock.calls[0]?.[1] as {\n _meta?: Record<string, unknown>;\n };\n expect(toolConfig._meta?.[\"openai/outputTemplate\"]).toBe(\n \"ui://views/ext-apps/unknown-view.html\",\n );\n });\n\n it(\"should inject viewUUID into _meta of tool callback results\", async () => {\n const mockToolCallback = vi.fn().mockResolvedValue({\n content: [{ type: \"text\", text: \"result\" }],\n structuredContent: { data: \"test\" },\n });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n mockToolCallback,\n );\n\n const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2] as (\n ...args: unknown[]\n ) => Promise<{ _meta?: Record<string, unknown> }>;\n expect(wrappedCallback).toBeDefined();\n\n const result = await wrappedCallback({}, {});\n\n expect(result._meta).toBeDefined();\n expect(result._meta?.viewUUID).toBeDefined();\n expect(typeof result._meta?.viewUUID).toBe(\"string\");\n expect(result._meta?.viewUUID).toMatch(\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,\n );\n });\n\n it(\"should preserve existing _meta when injecting viewUUID\", async () => {\n const mockToolCallback = vi.fn().mockResolvedValue({\n content: [{ type: \"text\", text: \"result\" }],\n structuredContent: { data: \"test\" },\n _meta: { requestId: \"req-123\", cached: true },\n });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n mockToolCallback,\n );\n\n const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2] as (\n ...args: unknown[]\n ) => Promise<{ _meta?: Record<string, unknown> }>;\n const result = await wrappedCallback({}, {});\n\n expect(result._meta?.requestId).toBe(\"req-123\");\n expect(result._meta?.cached).toBe(true);\n expect(result._meta?.viewUUID).toBeDefined();\n });\n\n it(\"should generate unique viewUUIDs across calls\", async () => {\n const mockToolCallback = vi.fn().mockResolvedValue({\n content: [{ type: \"text\", text: \"result\" }],\n structuredContent: {},\n });\n\n server.registerTool(\n {\n name: \"my-view\",\n description: \"Test tool\",\n view: { component: \"my-view\" as ViewName, description: \"Test view\" },\n },\n mockToolCallback,\n );\n\n const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2] as (\n ...args: unknown[]\n ) => Promise<{ _meta?: Record<string, unknown> }>;\n const result1 = await wrappedCallback({}, {});\n const result2 = await wrappedCallback({}, {});\n\n expect(result1._meta?.viewUUID).not.toBe(result2._meta?.viewUUID);\n });\n\n it(\"should enforce one-tool-per-view constraint\", () => {\n server.registerTool(\n {\n name: \"shake\",\n description: \"First tool\",\n view: { component: \"magic-8-ball\" as ViewName },\n },\n vi.fn(),\n );\n\n expect(() => {\n server.registerTool(\n {\n name: \"shake-v2\",\n description: \"Second tool\",\n view: { component: \"magic-8-ball\" as ViewName },\n },\n vi.fn(),\n );\n }).toThrow(\n 'skybridge: view \"magic-8-ball\" is already used by tool \"shake\"',\n );\n });\n\n it(\"should normalize string content to ContentBlock array\", async () => {\n const mockToolCallback = vi.fn().mockResolvedValue({\n content: \"Hello world\",\n structuredContent: {},\n });\n\n server.registerTool(\n {\n name: \"string-content\",\n description: \"Test tool\",\n view: { component: \"string-content\" as ViewName },\n },\n mockToolCallback,\n );\n\n const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2] as (\n ...args: unknown[]\n ) => Promise<{ content: unknown[] }>;\n const result = await wrappedCallback({}, {});\n\n expect(result.content).toEqual([{ type: \"text\", text: \"Hello world\" }]);\n });\n\n it(\"should normalize single ContentBlock to array\", async () => {\n const mockToolCallback = vi.fn().mockResolvedValue({\n content: { type: \"text\", text: \"Single block\" },\n structuredContent: {},\n });\n\n server.registerTool(\n {\n name: \"single-block\",\n description: \"Test tool\",\n view: { component: \"single-block\" as ViewName },\n },\n mockToolCallback,\n );\n\n const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2] as (\n ...args: unknown[]\n ) => Promise<{ content: unknown[] }>;\n const result = await wrappedCallback({}, {});\n\n expect(result.content).toEqual([{ type: \"text\", text: \"Single block\" }]);\n });\n\n it(\"should pass through ContentBlock array unchanged\", async () => {\n const blocks = [\n { type: \"text\", text: \"A\" },\n { type: \"text\", text: \"B\" },\n ];\n const mockToolCallback = vi.fn().mockResolvedValue({\n content: blocks,\n structuredContent: {},\n });\n\n server.registerTool(\n {\n name: \"array-content\",\n description: \"Test tool\",\n view: { component: \"array-content\" as ViewName },\n },\n mockToolCallback,\n );\n\n const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2] as (\n ...args: unknown[]\n ) => Promise<{ content: unknown[] }>;\n const result = await wrappedCallback({}, {});\n\n expect(result.content).toEqual(blocks);\n });\n\n it(\"should register tool without view (no resource registration)\", () => {\n server.registerTool(\n {\n name: \"plain-tool\",\n description: \"No view\",\n },\n vi.fn(),\n );\n\n expect(mockRegisterResource).not.toHaveBeenCalled();\n expect(mockRegisterTool).toHaveBeenCalledTimes(1);\n });\n\n it(\"should apply view.csp fields to resource _meta\", async () => {\n server.registerTool(\n {\n name: \"csp-tool\",\n description: \"Test tool\",\n view: {\n component: \"csp-tool\" as ViewName,\n description: \"Test view\",\n csp: {\n connectDomains: [\"https://api.example.com\"],\n resourceDomains: [\"https://cdn.example.com\"],\n },\n },\n },\n vi.fn(),\n );\n\n const appsSdkCallback = mockRegisterResource.mock\n .calls[0]?.[3] as unknown as (\n uri: URL,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => Promise<{\n contents: Array<{\n uri: URL | string;\n mimeType: string;\n _meta?: Record<string, unknown>;\n }>;\n }>;\n\n const host = \"localhost:3000\";\n const serverUrl = `http://${host}`;\n const hmrUrl = `ws://${host}`;\n const result = await appsSdkCallback(\n new URL(\"ui://views/ext-apps/csp-tool.html\"),\n createMockExtra(host) as unknown as RequestHandlerExtra<\n ServerRequest,\n ServerNotification\n >,\n );\n\n const meta = result.contents[0]?._meta as {\n ui?: { csp?: Record<string, unknown> };\n };\n expect(meta.ui?.csp).toEqual({\n resourceDomains: [serverUrl, \"https://cdn.example.com\"],\n connectDomains: [serverUrl, hmrUrl, \"https://api.example.com\"],\n baseUriDomains: [serverUrl],\n });\n });\n\n it(\"should let view._meta override framework-computed keys\", async () => {\n server.registerTool(\n {\n name: \"override-tool\",\n description: \"Test tool\",\n view: {\n component: \"override-tool\" as ViewName,\n description: \"Test view\",\n csp: { connectDomains: [\"https://api.x.com\"] },\n _meta: {\n ui: {\n csp: {\n connectDomains: [\"https://api.y.com\"],\n },\n },\n },\n },\n },\n vi.fn(),\n );\n\n const appsSdkCallback = mockRegisterResource.mock\n .calls[0]?.[3] as unknown as (\n uri: URL,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => Promise<{\n contents: Array<{\n uri: URL | string;\n mimeType: string;\n _meta?: Record<string, unknown>;\n }>;\n }>;\n\n const result = await appsSdkCallback(\n new URL(\"ui://views/ext-apps/override-tool.html\"),\n createMockExtra(\"localhost:3000\") as unknown as RequestHandlerExtra<\n ServerRequest,\n ServerNotification\n >,\n );\n\n const meta = result.contents[0]?._meta as {\n ui?: { csp?: Record<string, unknown> };\n };\n expect(meta.ui?.csp).toEqual({\n connectDomains: [\"https://api.y.com\"],\n });\n });\n\n it(\"should pass user _meta keys through to tool config\", () => {\n server.registerTool(\n {\n name: \"meta-tool\",\n description: \"Test tool\",\n _meta: {\n \"openai/widgetAccessible\": true,\n \"openai/toolInvocation/invoking\": \"Loading...\",\n \"acme.com/category\": \"utility\",\n },\n },\n vi.fn(),\n );\n\n const toolCallArgs = mockRegisterTool.mock.calls[0];\n const toolConfig = toolCallArgs?.[1] as { _meta?: Record<string, unknown> };\n\n expect(toolConfig._meta?.[\"openai/widgetAccessible\"]).toBe(true);\n expect(toolConfig._meta?.[\"openai/toolInvocation/invoking\"]).toBe(\n \"Loading...\",\n );\n expect(toolConfig._meta?.[\"acme.com/category\"]).toBe(\"utility\");\n });\n});\n\ndescribe(\"resources/list view _meta injection\", () => {\n afterEach(() => resetTestEnv());\n\n it(\"attaches CSP, domain, and connectDomains _meta to view resources at list time\", async () => {\n setTestEnv({ NODE_ENV: \"production\" });\n\n const server = new McpServerClass(\n { name: \"test\", version: \"1.0.0\" },\n { capabilities: {} },\n );\n server.registerTool(\n {\n name: \"start\",\n description: \"Start\",\n view: {\n component: \"my-view\" as ViewName,\n description: \"Onboarding deck\",\n domain: \"skybridge.tech\",\n csp: {\n resourceDomains: [\"https://fonts.googleapis.com\"],\n redirectDomains: [\"https://docs.skybridge.tech\"],\n },\n },\n },\n vi.fn().mockResolvedValue({\n content: [{ type: \"text\", text: \"ok\" }],\n structuredContent: {},\n }),\n );\n\n const client = new Client({ name: \"test-client\", version: \"1.0.0\" });\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n await server.connect(serverTransport);\n await client.connect(clientTransport);\n\n const { resources } = await client.listResources();\n await client.close();\n await server.close();\n\n const appsSdk = resources.find((r) => r.uri.includes(\"apps-sdk\"));\n const extApps = resources.find((r) => r.uri.includes(\"ext-apps\"));\n expect(appsSdk).toBeUndefined();\n expect(extApps?._meta).toBeDefined();\n\n const extUi = (\n extApps?._meta as {\n ui?: {\n csp?: { connectDomains?: string[]; resourceDomains?: string[] };\n domain?: string;\n };\n }\n ).ui;\n expect(extUi?.csp?.connectDomains?.length).toBeGreaterThan(0);\n expect(extUi?.csp?.resourceDomains).toContain(\n \"https://fonts.googleapis.com\",\n );\n expect(extUi?.domain).toBe(\"skybridge.tech\");\n });\n});\n"]}
@@ -0,0 +1,50 @@
1
+ import type { Adaptor, CallToolResponse, DownloadParams, DownloadResult, FileMetadata, HostContext, HostContextStore, OpenExternalOptions, RequestDisplayMode, RequestModalOptions, RequestSizeOptions, SendFollowUpMessageOptions, SetViewStateAction, UploadFileOptions } from "./types.js";
2
+ /**
3
+ * @internal
4
+ * Single composite implementation of {@link Adaptor}. Composes the MCP App
5
+ * bridge (always present) with an optional `window.openai` overlay. Per-method
6
+ * routing rules are encoded inline.
7
+ */
8
+ export declare class HostAdaptor implements Adaptor {
9
+ private readonly mcp;
10
+ private readonly openai;
11
+ private readonly appsSdkBridge;
12
+ private readonly mcpStores;
13
+ private readonly appsSdkStores;
14
+ private _viewState;
15
+ private readonly viewStateListeners;
16
+ private _viewUUID;
17
+ private _polyfillDisplay;
18
+ private readonly polyfillDisplayListeners;
19
+ private readonly polyfillDisplayStore;
20
+ private readonly polyfillViewStateStore;
21
+ private unsubscribeViewUUID;
22
+ constructor();
23
+ hasAppsSdkOverlay(): boolean;
24
+ /** @internal Release any subscriptions held on the underlying bridges. */
25
+ cleanup(): void;
26
+ getHostContextStore: <K extends keyof HostContext>(key: K) => HostContextStore<K>;
27
+ callTool: <ToolArgs extends Record<string, unknown> | null = null, ToolResponse extends CallToolResponse = CallToolResponse>(name: string, args: ToolArgs) => Promise<ToolResponse>;
28
+ requestDisplayMode: (mode: RequestDisplayMode) => Promise<{
29
+ [x: string]: unknown;
30
+ mode: "inline" | "fullscreen" | "pip";
31
+ }>;
32
+ requestClose: () => Promise<void>;
33
+ requestSize: (size: RequestSizeOptions) => Promise<void>;
34
+ sendFollowUpMessage: (prompt: string, options?: SendFollowUpMessageOptions) => Promise<void>;
35
+ openExternal: (href: string, options?: OpenExternalOptions) => void;
36
+ download: (params: DownloadParams) => Promise<DownloadResult>;
37
+ setViewState: (stateOrUpdater: SetViewStateAction) => Promise<void>;
38
+ uploadFile: (file: File, options?: UploadFileOptions) => Promise<FileMetadata>;
39
+ getFileDownloadUrl: (file: FileMetadata) => Promise<{
40
+ downloadUrl: string;
41
+ }>;
42
+ selectFiles: () => Promise<FileMetadata[]>;
43
+ openModal: (options: RequestModalOptions) => void;
44
+ setOpenInAppUrl: (href: string) => Promise<void>;
45
+ closeModal: () => void;
46
+ private trackFileIds;
47
+ private subscribeToViewUUID;
48
+ private restoreFromLocalStorage;
49
+ protected persistToLocalStorage(state: Record<string, unknown> | null): void;
50
+ }