skybridge 0.0.0-dev.fd6e4e8 → 0.0.0-dev.fd767e9

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 (309) hide show
  1. package/README.md +123 -124
  2. package/dist/cli/build-helpers.d.ts +7 -0
  3. package/dist/cli/build-helpers.js +82 -0
  4. package/dist/cli/build-helpers.js.map +1 -0
  5. package/dist/cli/build-helpers.test.js +64 -0
  6. package/dist/cli/build-helpers.test.js.map +1 -0
  7. package/dist/cli/detect-port.d.ts +2 -2
  8. package/dist/cli/detect-port.js +9 -20
  9. package/dist/cli/detect-port.js.map +1 -1
  10. package/dist/cli/header.js.map +1 -1
  11. package/dist/cli/resolve-views-dir.d.ts +1 -0
  12. package/dist/cli/resolve-views-dir.js +17 -0
  13. package/dist/cli/resolve-views-dir.js.map +1 -0
  14. package/dist/cli/run-command.js.map +1 -1
  15. package/dist/cli/telemetry.js.map +1 -1
  16. package/dist/cli/tunnel-control-server.d.ts +9 -0
  17. package/dist/cli/tunnel-control-server.js +31 -0
  18. package/dist/cli/tunnel-control-server.js.map +1 -0
  19. package/dist/cli/tunnel-control-server.test.js +39 -0
  20. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  21. package/dist/cli/tunnel-handler.d.ts +3 -0
  22. package/dist/cli/tunnel-handler.js +48 -0
  23. package/dist/cli/tunnel-handler.js.map +1 -0
  24. package/dist/cli/tunnel-handler.test.js +105 -0
  25. package/dist/cli/tunnel-handler.test.js.map +1 -0
  26. package/dist/cli/tunnel.d.ts +57 -0
  27. package/dist/cli/tunnel.js +154 -0
  28. package/dist/cli/tunnel.js.map +1 -0
  29. package/dist/cli/tunnel.test.js +190 -0
  30. package/dist/cli/tunnel.test.js.map +1 -0
  31. package/dist/cli/types.js.map +1 -1
  32. package/dist/cli/use-execute-steps.js.map +1 -1
  33. package/dist/cli/use-messages.js.map +1 -1
  34. package/dist/cli/use-nodemon.js +11 -2
  35. package/dist/cli/use-nodemon.js.map +1 -1
  36. package/dist/cli/use-open-browser.d.ts +1 -0
  37. package/dist/cli/use-open-browser.js +44 -0
  38. package/dist/cli/use-open-browser.js.map +1 -0
  39. package/dist/cli/use-open-tunnel-browser.d.ts +6 -0
  40. package/dist/cli/use-open-tunnel-browser.js +19 -0
  41. package/dist/cli/use-open-tunnel-browser.js.map +1 -0
  42. package/dist/cli/use-tunnel.d.ts +1 -1
  43. package/dist/cli/use-tunnel.js +102 -68
  44. package/dist/cli/use-tunnel.js.map +1 -1
  45. package/dist/cli/use-typescript-check.d.ts +1 -0
  46. package/dist/cli/use-typescript-check.js +42 -7
  47. package/dist/cli/use-typescript-check.js.map +1 -1
  48. package/dist/commands/build.d.ts +0 -1
  49. package/dist/commands/build.js +51 -8
  50. package/dist/commands/build.js.map +1 -1
  51. package/dist/commands/create.d.ts +9 -0
  52. package/dist/commands/create.js +30 -0
  53. package/dist/commands/create.js.map +1 -0
  54. package/dist/commands/dev.d.ts +1 -0
  55. package/dist/commands/dev.js +51 -2
  56. package/dist/commands/dev.js.map +1 -1
  57. package/dist/commands/start.js +7 -1
  58. package/dist/commands/start.js.map +1 -1
  59. package/dist/commands/telemetry/disable.js.map +1 -1
  60. package/dist/commands/telemetry/enable.js.map +1 -1
  61. package/dist/commands/telemetry/status.js.map +1 -1
  62. package/dist/server/asset-base-url-transform-plugin.d.ts +1 -0
  63. package/dist/server/asset-base-url-transform-plugin.js +17 -2
  64. package/dist/server/asset-base-url-transform-plugin.js.map +1 -1
  65. package/dist/server/asset-base-url-transform-plugin.test.js +80 -1
  66. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -1
  67. package/dist/server/auth.d.ts +20 -0
  68. package/dist/server/auth.js +28 -0
  69. package/dist/server/auth.js.map +1 -0
  70. package/dist/server/build-manifest.test.d.ts +1 -0
  71. package/dist/server/build-manifest.test.js +27 -0
  72. package/dist/server/build-manifest.test.js.map +1 -0
  73. package/dist/server/content-helpers.d.ts +40 -0
  74. package/dist/server/content-helpers.js +33 -0
  75. package/dist/server/content-helpers.js.map +1 -1
  76. package/dist/server/content-helpers.test.js +1 -1
  77. package/dist/server/content-helpers.test.js.map +1 -1
  78. package/dist/server/express.d.ts +1 -5
  79. package/dist/server/express.js +34 -10
  80. package/dist/server/express.js.map +1 -1
  81. package/dist/server/express.test.js +279 -71
  82. package/dist/server/express.test.js.map +1 -1
  83. package/dist/server/file-ref.d.ts +28 -0
  84. package/dist/server/file-ref.js +27 -0
  85. package/dist/server/file-ref.js.map +1 -0
  86. package/dist/server/index.d.ts +5 -3
  87. package/dist/server/index.js +4 -2
  88. package/dist/server/index.js.map +1 -1
  89. package/dist/server/inferUtilityTypes.d.ts +6 -6
  90. package/dist/server/inferUtilityTypes.js.map +1 -1
  91. package/dist/server/metric.js.map +1 -1
  92. package/dist/server/middleware.d.ts +16 -3
  93. package/dist/server/middleware.js.map +1 -1
  94. package/dist/server/middleware.test-d.js.map +1 -1
  95. package/dist/server/middleware.test.js.map +1 -1
  96. package/dist/server/server.d.ts +248 -41
  97. package/dist/server/server.js +327 -114
  98. package/dist/server/server.js.map +1 -1
  99. package/dist/server/templateHelper.d.ts +5 -7
  100. package/dist/server/templateHelper.js +3 -22
  101. package/dist/server/templateHelper.js.map +1 -1
  102. package/dist/server/templates.generated.d.ts +4 -0
  103. package/dist/server/templates.generated.js +47 -0
  104. package/dist/server/templates.generated.js.map +1 -0
  105. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  106. package/dist/server/tunnel-proxy-router.js +110 -0
  107. package/dist/server/tunnel-proxy-router.js.map +1 -0
  108. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  109. package/dist/server/tunnel-proxy-router.test.js +229 -0
  110. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  111. package/dist/server/viewsDevServer.d.ts +14 -0
  112. package/dist/server/{widgetsDevServer.js → viewsDevServer.js} +6 -6
  113. package/dist/server/viewsDevServer.js.map +1 -0
  114. package/dist/test/utils.d.ts +7 -7
  115. package/dist/test/utils.js +21 -21
  116. package/dist/test/utils.js.map +1 -1
  117. package/dist/test/view.test.d.ts +1 -0
  118. package/dist/test/{widget.test.js → view.test.js} +173 -59
  119. package/dist/test/view.test.js.map +1 -0
  120. package/dist/version.js +1 -3
  121. package/dist/version.js.map +1 -1
  122. package/dist/web/bridges/apps-sdk/adaptor.d.ts +8 -3
  123. package/dist/web/bridges/apps-sdk/adaptor.js +35 -5
  124. package/dist/web/bridges/apps-sdk/adaptor.js.map +1 -1
  125. package/dist/web/bridges/apps-sdk/bridge.d.ts +1 -0
  126. package/dist/web/bridges/apps-sdk/bridge.js +1 -0
  127. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  128. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  129. package/dist/web/bridges/apps-sdk/types.d.ts +8 -1
  130. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  131. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +11 -0
  132. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +11 -0
  133. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  134. package/dist/web/bridges/get-adaptor.d.ts +7 -0
  135. package/dist/web/bridges/get-adaptor.js +7 -0
  136. package/dist/web/bridges/get-adaptor.js.map +1 -1
  137. package/dist/web/bridges/index.js.map +1 -1
  138. package/dist/web/bridges/mcp-app/adaptor.d.ts +12 -7
  139. package/dist/web/bridges/mcp-app/adaptor.js +45 -30
  140. package/dist/web/bridges/mcp-app/adaptor.js.map +1 -1
  141. package/dist/web/bridges/mcp-app/bridge.d.ts +4 -2
  142. package/dist/web/bridges/mcp-app/bridge.js +23 -1
  143. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  144. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  145. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  146. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +12 -0
  147. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +12 -0
  148. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  149. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  150. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  151. package/dist/web/bridges/mcp-app/view-tools.test.js +144 -0
  152. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  153. package/dist/web/bridges/types.d.ts +105 -10
  154. package/dist/web/bridges/types.js.map +1 -1
  155. package/dist/web/bridges/use-host-context.d.ts +5 -0
  156. package/dist/web/bridges/use-host-context.js +5 -0
  157. package/dist/web/bridges/use-host-context.js.map +1 -1
  158. package/dist/web/components/modal-provider.js +1 -1
  159. package/dist/web/components/modal-provider.js.map +1 -1
  160. package/dist/web/create-store.d.ts +26 -0
  161. package/dist/web/create-store.js +35 -9
  162. package/dist/web/create-store.js.map +1 -1
  163. package/dist/web/create-store.test.js +14 -16
  164. package/dist/web/create-store.test.js.map +1 -1
  165. package/dist/web/data-llm.d.ts +34 -1
  166. package/dist/web/data-llm.js +31 -3
  167. package/dist/web/data-llm.js.map +1 -1
  168. package/dist/web/data-llm.test.js +22 -22
  169. package/dist/web/data-llm.test.js.map +1 -1
  170. package/dist/web/generate-helpers.d.ts +16 -14
  171. package/dist/web/generate-helpers.js +16 -14
  172. package/dist/web/generate-helpers.js.map +1 -1
  173. package/dist/web/generate-helpers.test-d.js +30 -28
  174. package/dist/web/generate-helpers.test-d.js.map +1 -1
  175. package/dist/web/generate-helpers.test.js.map +1 -1
  176. package/dist/web/helpers/state.d.ts +2 -2
  177. package/dist/web/helpers/state.js +11 -11
  178. package/dist/web/helpers/state.js.map +1 -1
  179. package/dist/web/helpers/state.test.js +9 -9
  180. package/dist/web/helpers/state.test.js.map +1 -1
  181. package/dist/web/hooks/index.d.ts +5 -1
  182. package/dist/web/hooks/index.js +5 -1
  183. package/dist/web/hooks/index.js.map +1 -1
  184. package/dist/web/hooks/test/utils.d.ts +6 -2
  185. package/dist/web/hooks/test/utils.js +13 -2
  186. package/dist/web/hooks/test/utils.js.map +1 -1
  187. package/dist/web/hooks/use-call-tool.d.ts +45 -0
  188. package/dist/web/hooks/use-call-tool.js +28 -0
  189. package/dist/web/hooks/use-call-tool.js.map +1 -1
  190. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  191. package/dist/web/hooks/use-call-tool.test.js +27 -6
  192. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  193. package/dist/web/hooks/use-display-mode.d.ts +20 -0
  194. package/dist/web/hooks/use-display-mode.js +20 -0
  195. package/dist/web/hooks/use-display-mode.js.map +1 -1
  196. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -1
  197. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  198. package/dist/web/hooks/use-download.d.ts +5 -0
  199. package/dist/web/hooks/use-download.js +8 -0
  200. package/dist/web/hooks/use-download.js.map +1 -0
  201. package/dist/web/hooks/use-download.test.d.ts +1 -0
  202. package/dist/web/hooks/use-download.test.js +95 -0
  203. package/dist/web/hooks/use-download.test.js.map +1 -0
  204. package/dist/web/hooks/use-files.d.ts +32 -0
  205. package/dist/web/hooks/use-files.js +32 -0
  206. package/dist/web/hooks/use-files.js.map +1 -1
  207. package/dist/web/hooks/use-files.test.js.map +1 -1
  208. package/dist/web/hooks/use-layout.d.ts +2 -0
  209. package/dist/web/hooks/use-layout.js +2 -0
  210. package/dist/web/hooks/use-layout.js.map +1 -1
  211. package/dist/web/hooks/use-layout.test.js.map +1 -1
  212. package/dist/web/hooks/use-open-external.d.ts +17 -0
  213. package/dist/web/hooks/use-open-external.js +16 -0
  214. package/dist/web/hooks/use-open-external.js.map +1 -1
  215. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  216. package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
  217. package/dist/web/hooks/use-register-view-tool.js +50 -0
  218. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  219. package/dist/web/hooks/use-request-close.d.ts +16 -0
  220. package/dist/web/hooks/use-request-close.js +21 -0
  221. package/dist/web/hooks/use-request-close.js.map +1 -0
  222. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  223. package/dist/web/hooks/use-request-close.test.js +52 -0
  224. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  225. package/dist/web/hooks/use-request-modal.d.ts +16 -1
  226. package/dist/web/hooks/use-request-modal.js +19 -4
  227. package/dist/web/hooks/use-request-modal.js.map +1 -1
  228. package/dist/web/hooks/use-request-modal.test.js +1 -1
  229. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  230. package/dist/web/hooks/use-request-size.d.ts +20 -0
  231. package/dist/web/hooks/use-request-size.js +24 -0
  232. package/dist/web/hooks/use-request-size.js.map +1 -0
  233. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  234. package/dist/web/hooks/use-request-size.test.js +65 -0
  235. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  236. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -1
  237. package/dist/web/hooks/use-send-follow-up-message.js +19 -2
  238. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  239. package/dist/web/hooks/use-set-open-in-app-url.d.ts +17 -0
  240. package/dist/web/hooks/use-set-open-in-app-url.js +17 -0
  241. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -1
  242. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  243. package/dist/web/hooks/use-tool-info.d.ts +53 -2
  244. package/dist/web/hooks/use-tool-info.js +30 -7
  245. package/dist/web/hooks/use-tool-info.js.map +1 -1
  246. package/dist/web/hooks/use-tool-info.test-d.js +11 -29
  247. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  248. package/dist/web/hooks/use-tool-info.test.js +5 -5
  249. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  250. package/dist/web/hooks/use-user.d.ts +2 -0
  251. package/dist/web/hooks/use-user.js +2 -0
  252. package/dist/web/hooks/use-user.js.map +1 -1
  253. package/dist/web/hooks/use-user.test.js.map +1 -1
  254. package/dist/web/hooks/use-view-state.d.ts +25 -0
  255. package/dist/web/hooks/use-view-state.js +32 -0
  256. package/dist/web/hooks/use-view-state.js.map +1 -0
  257. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  258. package/dist/web/hooks/{use-widget-state.test.js → use-view-state.test.js} +17 -17
  259. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  260. package/dist/web/index.d.ts +1 -3
  261. package/dist/web/index.js +1 -2
  262. package/dist/web/index.js.map +1 -1
  263. package/dist/web/mount-view.d.ts +20 -0
  264. package/dist/web/{mount-widget.js → mount-view.js} +21 -2
  265. package/dist/web/mount-view.js.map +1 -0
  266. package/dist/web/plugin/data-llm.test.js.map +1 -1
  267. package/dist/web/plugin/plugin.d.ts +29 -1
  268. package/dist/web/plugin/plugin.js +113 -55
  269. package/dist/web/plugin/plugin.js.map +1 -1
  270. package/dist/web/plugin/scan-views.d.ts +16 -0
  271. package/dist/web/plugin/scan-views.js +88 -0
  272. package/dist/web/plugin/scan-views.js.map +1 -0
  273. package/dist/web/plugin/scan-views.test.d.ts +1 -0
  274. package/dist/web/plugin/scan-views.test.js +99 -0
  275. package/dist/web/plugin/scan-views.test.js.map +1 -0
  276. package/dist/web/plugin/transform-data-llm.js.map +1 -1
  277. package/dist/web/plugin/transform-data-llm.test.js.map +1 -1
  278. package/dist/web/plugin/{validate-widget.js → validate-view.js} +1 -1
  279. package/dist/web/plugin/validate-view.js.map +1 -0
  280. package/dist/web/plugin/validate-view.test.d.ts +1 -0
  281. package/dist/web/plugin/{validate-widget.test.js → validate-view.test.js} +6 -6
  282. package/dist/web/plugin/validate-view.test.js.map +1 -0
  283. package/dist/web/proxy.js.map +1 -1
  284. package/dist/web/types.d.ts +4 -0
  285. package/dist/web/types.js.map +1 -1
  286. package/package.json +20 -8
  287. package/dist/server/templates/development.hbs +0 -12
  288. package/dist/server/templates/production.hbs +0 -6
  289. package/dist/server/widgetsDevServer.d.ts +0 -14
  290. package/dist/server/widgetsDevServer.js.map +0 -1
  291. package/dist/test/widget.test.js.map +0 -1
  292. package/dist/web/hooks/use-widget-state.d.ts +0 -4
  293. package/dist/web/hooks/use-widget-state.js +0 -32
  294. package/dist/web/hooks/use-widget-state.js.map +0 -1
  295. package/dist/web/hooks/use-widget-state.test.js.map +0 -1
  296. package/dist/web/mount-widget.d.ts +0 -1
  297. package/dist/web/mount-widget.js.map +0 -1
  298. package/dist/web/plugin/scan-widgets.d.ts +0 -8
  299. package/dist/web/plugin/scan-widgets.js +0 -68
  300. package/dist/web/plugin/scan-widgets.js.map +0 -1
  301. package/dist/web/plugin/scan-widgets.test.js +0 -96
  302. package/dist/web/plugin/scan-widgets.test.js.map +0 -1
  303. package/dist/web/plugin/validate-widget.js.map +0 -1
  304. package/dist/web/plugin/validate-widget.test.js.map +0 -1
  305. /package/dist/{test/widget.test.d.ts → cli/build-helpers.test.d.ts} +0 -0
  306. /package/dist/{web/hooks/use-widget-state.test.d.ts → cli/tunnel-control-server.test.d.ts} +0 -0
  307. /package/dist/{web/plugin/scan-widgets.test.d.ts → cli/tunnel-handler.test.d.ts} +0 -0
  308. /package/dist/{web/plugin/validate-widget.test.d.ts → cli/tunnel.test.d.ts} +0 -0
  309. /package/dist/web/plugin/{validate-widget.d.ts → validate-view.d.ts} +0 -0
@@ -1,19 +1,34 @@
1
1
  import crypto from "node:crypto";
2
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
+ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
2
4
  import { afterEach, beforeEach, describe, expect, it, vi, } from "vitest";
5
+ import { McpServer as McpServerClass } from "../server/server.js";
3
6
  import { createMockExtra, createMockMcpServer, resetTestEnv, setTestEnv, } from "./utils.js";
4
7
  const mockManifest = {
5
- "skybridge:widget:my-widget": {
6
- file: "assets/my-widget-abc123.js",
7
- name: "my-widget",
8
+ "skybridge:view:my-view": {
9
+ file: "assets/my-view-abc123.js",
10
+ name: "my-view",
8
11
  isEntry: true,
9
12
  },
10
- "skybridge:widget:folder-widget": {
11
- file: "assets/folder-widget-def456.js",
12
- name: "folder-widget",
13
+ "skybridge:view:folder-view": {
14
+ file: "assets/folder-view-def456.js",
15
+ name: "folder-view",
13
16
  isEntry: true,
14
17
  },
15
18
  "style.css": { file: "style.css" },
16
19
  };
20
+ // Mirrors `McpServer.computeViewVersionParam`. Tests recompute the expected
21
+ // hash from the mocked manifest so they don't hardcode digest output.
22
+ function expectedVersionParam(viewFile, styleFile) {
23
+ const hash = crypto
24
+ .createHash("sha256")
25
+ .update(viewFile)
26
+ .update("\0")
27
+ .update(styleFile)
28
+ .digest("hex")
29
+ .slice(0, 8);
30
+ return `?v=${hash}`;
31
+ }
17
32
  const actual = vi.hoisted(() => require("node:fs"));
18
33
  vi.mock("node:fs", () => {
19
34
  const readFileSyncImpl = (path, ...args) => {
@@ -45,11 +60,11 @@ describe("McpServer.registerTool (unified API)", () => {
45
60
  it("should generate correct HTML for development mode", async () => {
46
61
  setTestEnv({ NODE_ENV: "development" });
47
62
  server.registerTool({
48
- name: "my-widget",
63
+ name: "my-view",
49
64
  description: "Test tool",
50
65
  view: {
51
- component: "my-widget",
52
- description: "Test widget",
66
+ component: "my-view",
67
+ description: "Test view",
53
68
  },
54
69
  }, vi.fn());
55
70
  const appsSdkResourceCallback = mockRegisterResource.mock
@@ -59,12 +74,12 @@ describe("McpServer.registerTool (unified API)", () => {
59
74
  const serverUrl = `http://${host}`;
60
75
  const hmrUrl = `ws://${host}`;
61
76
  const mockExtra = createMockExtra(host);
62
- const result = await appsSdkResourceCallback(new URL("ui://widgets/apps-sdk/my-widget.html"), mockExtra);
77
+ const result = await appsSdkResourceCallback(new URL("ui://views/apps-sdk/my-view.html"), mockExtra);
63
78
  expect(mockRegisterTool).toHaveBeenCalled();
64
79
  expect(result).toEqual({
65
80
  contents: [
66
81
  {
67
- uri: "ui://widgets/apps-sdk/my-widget.html",
82
+ uri: "ui://views/apps-sdk/my-view.html",
68
83
  mimeType: "text/html+skybridge",
69
84
  text: expect.stringContaining('<div id="root"></div>'),
70
85
  _meta: {
@@ -73,23 +88,23 @@ describe("McpServer.registerTool (unified API)", () => {
73
88
  connect_domains: [serverUrl, hmrUrl],
74
89
  },
75
90
  "openai/widgetDomain": serverUrl,
76
- "openai/widgetDescription": "Test widget",
91
+ "openai/widgetDescription": "Test view",
77
92
  },
78
93
  },
79
94
  ],
80
95
  });
81
96
  expect(result.contents[0]?.text).toContain(`${serverUrl}/assets/@react-refresh`);
82
97
  expect(result.contents[0]?.text).toContain(`${serverUrl}/@vite/client`);
83
- expect(result.contents[0]?.text).toContain(`${serverUrl}/_skybridge/widget/my-widget`);
98
+ expect(result.contents[0]?.text).toContain(`${serverUrl}/_skybridge/view/my-view`);
84
99
  });
85
100
  it("should generate correct HTML for production mode", async () => {
86
101
  setTestEnv({ NODE_ENV: "production" });
87
102
  server.registerTool({
88
- name: "my-widget",
103
+ name: "my-view",
89
104
  description: "Test tool",
90
105
  view: {
91
- component: "my-widget",
92
- description: "Test widget",
106
+ component: "my-view",
107
+ description: "Test view",
93
108
  },
94
109
  }, vi.fn());
95
110
  const appsSdkResourceCallback = mockRegisterResource.mock
@@ -98,11 +113,12 @@ describe("McpServer.registerTool (unified API)", () => {
98
113
  const host = "myapp.com";
99
114
  const serverUrl = `https://${host}`;
100
115
  const mockExtra = createMockExtra(host);
101
- const result = await appsSdkResourceCallback(new URL("ui://widgets/apps-sdk/my-widget.html"), mockExtra);
116
+ const versionedUri = `ui://views/apps-sdk/my-view.html${expectedVersionParam("assets/my-view-abc123.js", "style.css")}`;
117
+ const result = await appsSdkResourceCallback(new URL(versionedUri), mockExtra);
102
118
  expect(result).toEqual({
103
119
  contents: [
104
120
  {
105
- uri: "ui://widgets/apps-sdk/my-widget.html",
121
+ uri: versionedUri,
106
122
  mimeType: "text/html+skybridge",
107
123
  text: expect.stringContaining('<div id="root"></div>'),
108
124
  _meta: {
@@ -111,22 +127,22 @@ describe("McpServer.registerTool (unified API)", () => {
111
127
  connect_domains: [serverUrl],
112
128
  },
113
129
  "openai/widgetDomain": serverUrl,
114
- "openai/widgetDescription": "Test widget",
130
+ "openai/widgetDescription": "Test view",
115
131
  },
116
132
  },
117
133
  ],
118
134
  });
119
135
  expect(result.contents[0]?.text).not.toContain(`${serverUrl}/assets/@react-refresh`);
120
136
  expect(result.contents[0]?.text).not.toContain(`${serverUrl}@vite/client`);
121
- expect(result.contents[0]?.text).toContain(`${serverUrl}/assets/assets/my-widget-abc123.js`);
137
+ expect(result.contents[0]?.text).toContain(`${serverUrl}/assets/assets/my-view-abc123.js`);
122
138
  expect(result.contents[0]?.text).toContain(`${serverUrl}/assets/style.css`);
123
139
  });
124
- it("should prefer x-alpic-forwarded-url when hashing Claude widget domains", async () => {
140
+ it("should prefer x-alpic-forwarded-url when hashing Claude view domains", async () => {
125
141
  setTestEnv({ NODE_ENV: "production" });
126
142
  server.registerTool({
127
- name: "my-widget",
143
+ name: "my-view",
128
144
  description: "Test tool",
129
- view: { component: "my-widget", description: "Test widget" },
145
+ view: { component: "my-view", description: "Test view" },
130
146
  }, vi.fn());
131
147
  const extAppsResourceCallback = mockRegisterResource.mock
132
148
  .calls[1]?.[3];
@@ -137,7 +153,7 @@ describe("McpServer.registerTool (unified API)", () => {
137
153
  .update(forwardedUrl)
138
154
  .digest("hex")
139
155
  .slice(0, 32)}.claudemcpcontent.com`;
140
- const result = await extAppsResourceCallback(new URL("ui://widgets/ext-apps/my-widget.html"), createMockExtra("localhost:3000", {
156
+ 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
157
  headers: {
142
158
  "user-agent": "Claude-User",
143
159
  "x-alpic-forwarded-url": forwardedUrl,
@@ -151,18 +167,18 @@ describe("McpServer.registerTool (unified API)", () => {
151
167
  connectDomains: ["http://localhost:3000"],
152
168
  baseUriDomains: ["http://localhost:3000"],
153
169
  },
154
- description: "Test widget",
170
+ description: "Test view",
155
171
  domain: expectedDomain,
156
172
  },
157
173
  });
158
174
  });
159
175
  it("should register resources with correct hostType for both apps-sdk and ext-apps", async () => {
160
176
  server.registerTool({
161
- name: "my-widget",
177
+ name: "my-view",
162
178
  description: "Test tool",
163
179
  view: {
164
- component: "my-widget",
165
- description: "Test widget",
180
+ component: "my-view",
181
+ description: "Test view",
166
182
  prefersBorder: true,
167
183
  },
168
184
  }, vi.fn());
@@ -172,11 +188,11 @@ describe("McpServer.registerTool (unified API)", () => {
172
188
  const host = "localhost:3000";
173
189
  const serverUrl = `http://${host}`;
174
190
  const hmrUrl = `ws://${host}`;
175
- const appsSdkResult = await appsSdkCallback(new URL("ui://widgets/apps-sdk/my-widget.html"), createMockExtra(host));
191
+ const appsSdkResult = await appsSdkCallback(new URL("ui://views/apps-sdk/my-view.html"), createMockExtra(host));
176
192
  expect(appsSdkResult).toEqual({
177
193
  contents: [
178
194
  {
179
- uri: "ui://widgets/apps-sdk/my-widget.html",
195
+ uri: "ui://views/apps-sdk/my-view.html",
180
196
  mimeType: "text/html+skybridge",
181
197
  text: expect.stringContaining('<div id="root"></div>'),
182
198
  _meta: {
@@ -185,7 +201,7 @@ describe("McpServer.registerTool (unified API)", () => {
185
201
  connect_domains: [serverUrl, hmrUrl],
186
202
  },
187
203
  "openai/widgetDomain": serverUrl,
188
- "openai/widgetDescription": "Test widget",
204
+ "openai/widgetDescription": "Test view",
189
205
  "openai/widgetPrefersBorder": true,
190
206
  },
191
207
  },
@@ -195,11 +211,11 @@ describe("McpServer.registerTool (unified API)", () => {
195
211
  const extAppsResourceCallback = mockRegisterResource.mock
196
212
  .calls[1]?.[3];
197
213
  expect(extAppsResourceCallback).toBeDefined();
198
- const extAppsResult = await extAppsResourceCallback(new URL("ui://widgets/ext-apps/my-widget.html"), createMockExtra(host));
214
+ const extAppsResult = await extAppsResourceCallback(new URL("ui://views/ext-apps/my-view.html"), createMockExtra(host));
199
215
  expect(extAppsResult).toEqual({
200
216
  contents: [
201
217
  {
202
- uri: "ui://widgets/ext-apps/my-widget.html",
218
+ uri: "ui://views/ext-apps/my-view.html",
203
219
  mimeType: "text/html;profile=mcp-app",
204
220
  text: expect.stringContaining('<div id="root"></div>'),
205
221
  _meta: {
@@ -210,7 +226,7 @@ describe("McpServer.registerTool (unified API)", () => {
210
226
  baseUriDomains: [serverUrl],
211
227
  },
212
228
  domain: serverUrl,
213
- description: "Test widget",
229
+ description: "Test view",
214
230
  prefersBorder: true,
215
231
  },
216
232
  },
@@ -221,25 +237,25 @@ describe("McpServer.registerTool (unified API)", () => {
221
237
  });
222
238
  it("should register tool with ui.resourceUri metadata", async () => {
223
239
  server.registerTool({
224
- name: "my-widget",
240
+ name: "my-view",
225
241
  description: "Test tool",
226
- view: { component: "my-widget", description: "Test widget" },
242
+ view: { component: "my-view", description: "Test view" },
227
243
  }, vi.fn());
228
244
  expect(mockRegisterTool).toHaveBeenCalledTimes(1);
229
245
  const toolCallArgs = mockRegisterTool.mock.calls[0];
230
246
  const toolConfig = toolCallArgs?.[1];
231
247
  expect(toolConfig._meta).toHaveProperty("ui");
232
248
  expect(toolConfig._meta?.ui).toEqual({
233
- resourceUri: "ui://widgets/ext-apps/my-widget.html",
249
+ resourceUri: "ui://views/ext-apps/my-view.html",
234
250
  });
235
251
  });
236
252
  it("should register tool with openai/outputTemplate when apps-sdk only", async () => {
237
253
  server.registerTool({
238
- name: "my-widget",
254
+ name: "my-view",
239
255
  description: "Test tool",
240
256
  view: {
241
- component: "my-widget",
242
- description: "Test widget",
257
+ component: "my-view",
258
+ description: "Test view",
243
259
  hosts: ["apps-sdk"],
244
260
  },
245
261
  }, vi.fn());
@@ -247,15 +263,71 @@ describe("McpServer.registerTool (unified API)", () => {
247
263
  const toolCallArgs = mockRegisterTool.mock.calls[0];
248
264
  const toolConfig = toolCallArgs?.[1];
249
265
  expect(toolConfig._meta).not.toHaveProperty("ui");
250
- expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://widgets/apps-sdk/my-widget.html");
266
+ expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://views/apps-sdk/my-view.html");
267
+ });
268
+ it("should not version view URIs in development", () => {
269
+ server.registerTool({
270
+ name: "my-view",
271
+ description: "Test tool",
272
+ view: { component: "my-view", description: "Test view" },
273
+ }, vi.fn());
274
+ const toolConfig = mockRegisterTool.mock.calls[0]?.[1];
275
+ expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://views/apps-sdk/my-view.html");
276
+ expect(toolConfig._meta?.ui?.resourceUri).toBe("ui://views/ext-apps/my-view.html");
277
+ // The URI registered with the resource handler must match the URI in
278
+ // 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");
281
+ });
282
+ it("should append a stable content hash to view URIs in production", () => {
283
+ setTestEnv({ NODE_ENV: "production" });
284
+ server.registerTool({
285
+ name: "my-view",
286
+ description: "Test tool",
287
+ view: { component: "my-view", description: "Test view" },
288
+ }, vi.fn());
289
+ const expected = expectedVersionParam("assets/my-view-abc123.js", "style.css");
290
+ const toolConfig = mockRegisterTool.mock.calls[0]?.[1];
291
+ expect(toolConfig._meta?.["openai/outputTemplate"]).toBe(`ui://views/apps-sdk/my-view.html${expected}`);
292
+ 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}`);
295
+ });
296
+ it("should produce different version params for views with different bundles", () => {
297
+ setTestEnv({ NODE_ENV: "production" });
298
+ server.registerTool({
299
+ name: "my-view",
300
+ description: "First tool",
301
+ view: { component: "my-view" },
302
+ }, vi.fn());
303
+ server.registerTool({
304
+ name: "folder-view",
305
+ description: "Second tool",
306
+ view: { component: "folder-view" },
307
+ }, vi.fn());
308
+ const myviewTemplate = (mockRegisterTool.mock.calls[0]?.[1])._meta?.["openai/outputTemplate"];
309
+ const folderviewTemplate = (mockRegisterTool.mock.calls[1]?.[1])._meta?.["openai/outputTemplate"];
310
+ expect(myviewTemplate).not.toEqual(folderviewTemplate);
311
+ expect(myviewTemplate).toMatch(/\?v=[0-9a-f]{8}$/);
312
+ expect(folderviewTemplate).toMatch(/\?v=[0-9a-f]{8}$/);
313
+ });
314
+ it("should fall back to bare URI in production when manifest is missing", () => {
315
+ setTestEnv({ NODE_ENV: "production" });
316
+ server.registerTool({
317
+ name: "unknown-view",
318
+ description: "Test tool",
319
+ view: { component: "unknown-view" },
320
+ }, vi.fn());
321
+ const toolConfig = mockRegisterTool.mock.calls[0]?.[1];
322
+ expect(toolConfig._meta?.["openai/outputTemplate"]).toBe("ui://views/apps-sdk/unknown-view.html");
251
323
  });
252
324
  it("should register tool with ui.resourceUri only when mcp-app only", async () => {
253
325
  server.registerTool({
254
- name: "my-widget",
326
+ name: "my-view",
255
327
  description: "Test tool",
256
328
  view: {
257
- component: "my-widget",
258
- description: "Test widget",
329
+ component: "my-view",
330
+ description: "Test view",
259
331
  hosts: ["mcp-app"],
260
332
  },
261
333
  }, vi.fn());
@@ -264,7 +336,7 @@ describe("McpServer.registerTool (unified API)", () => {
264
336
  const toolConfig = toolCallArgs?.[1];
265
337
  expect(toolConfig._meta).toHaveProperty("ui");
266
338
  expect(toolConfig._meta?.ui).toEqual({
267
- resourceUri: "ui://widgets/ext-apps/my-widget.html",
339
+ resourceUri: "ui://views/ext-apps/my-view.html",
268
340
  });
269
341
  expect(toolConfig._meta?.["openai/outputTemplate"]).toBeUndefined();
270
342
  });
@@ -274,9 +346,9 @@ describe("McpServer.registerTool (unified API)", () => {
274
346
  structuredContent: { data: "test" },
275
347
  });
276
348
  server.registerTool({
277
- name: "my-widget",
349
+ name: "my-view",
278
350
  description: "Test tool",
279
- view: { component: "my-widget", description: "Test widget" },
351
+ view: { component: "my-view", description: "Test view" },
280
352
  }, mockToolCallback);
281
353
  const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2];
282
354
  expect(wrappedCallback).toBeDefined();
@@ -293,9 +365,9 @@ describe("McpServer.registerTool (unified API)", () => {
293
365
  _meta: { requestId: "req-123", cached: true },
294
366
  });
295
367
  server.registerTool({
296
- name: "my-widget",
368
+ name: "my-view",
297
369
  description: "Test tool",
298
- view: { component: "my-widget", description: "Test widget" },
370
+ view: { component: "my-view", description: "Test view" },
299
371
  }, mockToolCallback);
300
372
  const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2];
301
373
  const result = await wrappedCallback({}, {});
@@ -309,16 +381,16 @@ describe("McpServer.registerTool (unified API)", () => {
309
381
  structuredContent: {},
310
382
  });
311
383
  server.registerTool({
312
- name: "my-widget",
384
+ name: "my-view",
313
385
  description: "Test tool",
314
- view: { component: "my-widget", description: "Test widget" },
386
+ view: { component: "my-view", description: "Test view" },
315
387
  }, mockToolCallback);
316
388
  const wrappedCallback = mockRegisterTool.mock.calls[0]?.[2];
317
389
  const result1 = await wrappedCallback({}, {});
318
390
  const result2 = await wrappedCallback({}, {});
319
391
  expect(result1._meta?.viewUUID).not.toBe(result2._meta?.viewUUID);
320
392
  });
321
- it("should enforce one-tool-per-widget constraint", () => {
393
+ it("should enforce one-tool-per-view constraint", () => {
322
394
  server.registerTool({
323
395
  name: "shake",
324
396
  description: "First tool",
@@ -330,7 +402,7 @@ describe("McpServer.registerTool (unified API)", () => {
330
402
  description: "Second tool",
331
403
  view: { component: "magic-8-ball" },
332
404
  }, vi.fn());
333
- }).toThrow('skybridge: widget "magic-8-ball" is already used by tool "shake"');
405
+ }).toThrow('skybridge: view "magic-8-ball" is already used by tool "shake"');
334
406
  });
335
407
  it("should normalize string content to ContentBlock array", async () => {
336
408
  const mockToolCallback = vi.fn().mockResolvedValue({
@@ -381,7 +453,7 @@ describe("McpServer.registerTool (unified API)", () => {
381
453
  it("should register tool without view (no resource registration)", () => {
382
454
  server.registerTool({
383
455
  name: "plain-tool",
384
- description: "No widget",
456
+ description: "No view",
385
457
  }, vi.fn());
386
458
  expect(mockRegisterResource).not.toHaveBeenCalled();
387
459
  expect(mockRegisterTool).toHaveBeenCalledTimes(1);
@@ -392,7 +464,7 @@ describe("McpServer.registerTool (unified API)", () => {
392
464
  description: "Test tool",
393
465
  view: {
394
466
  component: "csp-tool",
395
- description: "Test widget",
467
+ description: "Test view",
396
468
  csp: {
397
469
  connectDomains: ["https://api.example.com"],
398
470
  resourceDomains: ["https://cdn.example.com"],
@@ -404,7 +476,7 @@ describe("McpServer.registerTool (unified API)", () => {
404
476
  const host = "localhost:3000";
405
477
  const serverUrl = `http://${host}`;
406
478
  const hmrUrl = `ws://${host}`;
407
- const result = await appsSdkCallback(new URL("ui://widgets/apps-sdk/csp-tool.html"), createMockExtra(host));
479
+ const result = await appsSdkCallback(new URL("ui://views/apps-sdk/csp-tool.html"), createMockExtra(host));
408
480
  const meta = result.contents[0]?._meta;
409
481
  expect(meta["openai/widgetCSP"]).toEqual({
410
482
  resource_domains: [serverUrl, "https://cdn.example.com"],
@@ -417,7 +489,7 @@ describe("McpServer.registerTool (unified API)", () => {
417
489
  description: "Test tool",
418
490
  view: {
419
491
  component: "override-tool",
420
- description: "Test widget",
492
+ description: "Test view",
421
493
  csp: { connectDomains: ["https://api.x.com"] },
422
494
  _meta: {
423
495
  "openai/widgetCSP": {
@@ -428,7 +500,7 @@ describe("McpServer.registerTool (unified API)", () => {
428
500
  }, vi.fn());
429
501
  const appsSdkCallback = mockRegisterResource.mock
430
502
  .calls[0]?.[3];
431
- const result = await appsSdkCallback(new URL("ui://widgets/apps-sdk/override-tool.html"), createMockExtra("localhost:3000"));
503
+ const result = await appsSdkCallback(new URL("ui://views/apps-sdk/override-tool.html"), createMockExtra("localhost:3000"));
432
504
  const meta = result.contents[0]?._meta;
433
505
  expect(meta["openai/widgetCSP"]).toEqual({
434
506
  connect_domains: ["https://api.y.com"],
@@ -451,4 +523,46 @@ describe("McpServer.registerTool (unified API)", () => {
451
523
  expect(toolConfig._meta?.["acme.com/category"]).toBe("utility");
452
524
  });
453
525
  });
454
- //# sourceMappingURL=widget.test.js.map
526
+ describe("resources/list view _meta injection", () => {
527
+ afterEach(() => resetTestEnv());
528
+ it("attaches CSP, domain, and connectDomains _meta to view resources at list time", async () => {
529
+ setTestEnv({ NODE_ENV: "production" });
530
+ const server = new McpServerClass({ name: "test", version: "1.0.0" }, { capabilities: {} });
531
+ server.registerTool({
532
+ name: "start",
533
+ description: "Start",
534
+ view: {
535
+ component: "my-view",
536
+ description: "Onboarding deck",
537
+ domain: "skybridge.tech",
538
+ csp: {
539
+ resourceDomains: ["https://fonts.googleapis.com"],
540
+ redirectDomains: ["https://docs.skybridge.tech"],
541
+ },
542
+ },
543
+ }, vi.fn().mockResolvedValue({
544
+ content: [{ type: "text", text: "ok" }],
545
+ structuredContent: {},
546
+ }));
547
+ const client = new Client({ name: "test-client", version: "1.0.0" });
548
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
549
+ await server.connect(serverTransport);
550
+ await client.connect(clientTransport);
551
+ const { resources } = await client.listResources();
552
+ await client.close();
553
+ await server.close();
554
+ const appsSdk = resources.find((r) => r.uri.includes("apps-sdk"));
555
+ const extApps = resources.find((r) => r.uri.includes("ext-apps"));
556
+ expect(appsSdk?._meta).toBeDefined();
557
+ 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
+ const extUi = (extApps?._meta).ui;
563
+ expect(extUi?.csp?.connectDomains?.length).toBeGreaterThan(0);
564
+ expect(extUi?.csp?.resourceDomains).toContain("https://fonts.googleapis.com");
565
+ expect(extUi?.domain).toBe("skybridge.tech");
566
+ });
567
+ });
568
+ //# sourceMappingURL=view.test.js.map
@@ -0,0 +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"]}
package/dist/version.js CHANGED
@@ -1,5 +1,3 @@
1
- import { createRequire } from "node:module";
2
- const require = createRequire(import.meta.url);
3
- const pkg = require("../package.json");
1
+ import pkg from "../package.json" with { type: "json" };
4
2
  export const VERSION = pkg.version;
5
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAE9D,MAAM,CAAC,MAAM,OAAO,GAAW,GAAG,CAAC,OAAO,CAAC"}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAExD,MAAM,CAAC,MAAM,OAAO,GAAW,GAAG,CAAC,OAAO,CAAC","sourcesContent":["import pkg from \"../package.json\" with { type: \"json\" };\n\nexport const VERSION: string = pkg.version;\n"]}