skybridge 0.0.0-dev.db51ef5 → 0.0.0-dev.db532c6

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 (513) hide show
  1. package/README.md +155 -0
  2. package/dist/cli/build-helpers.d.ts +11 -0
  3. package/dist/cli/build-helpers.js +107 -0
  4. package/dist/cli/build-helpers.js.map +1 -0
  5. package/dist/cli/build-helpers.test.js +132 -0
  6. package/dist/cli/build-helpers.test.js.map +1 -0
  7. package/dist/cli/build-steps.d.ts +2 -0
  8. package/dist/cli/build-steps.js +73 -0
  9. package/dist/cli/build-steps.js.map +1 -0
  10. package/dist/cli/build-steps.test.js +52 -0
  11. package/dist/cli/build-steps.test.js.map +1 -0
  12. package/dist/cli/detect-port.d.ts +18 -0
  13. package/dist/cli/detect-port.js +49 -0
  14. package/dist/cli/detect-port.js.map +1 -0
  15. package/dist/cli/header.d.ts +1 -1
  16. package/dist/cli/header.js +1 -1
  17. package/dist/cli/header.js.map +1 -1
  18. package/dist/cli/resolve-skybridge-config.d.ts +5 -0
  19. package/dist/cli/resolve-skybridge-config.js +18 -0
  20. package/dist/cli/resolve-skybridge-config.js.map +1 -0
  21. package/dist/cli/run-command.js.map +1 -1
  22. package/dist/cli/run-plain.d.ts +18 -0
  23. package/dist/cli/run-plain.js +90 -0
  24. package/dist/cli/run-plain.js.map +1 -0
  25. package/dist/cli/telemetry.js +2 -0
  26. package/dist/cli/telemetry.js.map +1 -1
  27. package/dist/cli/tunnel-control-server.d.ts +9 -0
  28. package/dist/cli/tunnel-control-server.js +31 -0
  29. package/dist/cli/tunnel-control-server.js.map +1 -0
  30. package/dist/cli/tunnel-control-server.test.js +39 -0
  31. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  32. package/dist/cli/tunnel-handler.d.ts +3 -0
  33. package/dist/cli/tunnel-handler.js +48 -0
  34. package/dist/cli/tunnel-handler.js.map +1 -0
  35. package/dist/cli/tunnel-handler.test.js +105 -0
  36. package/dist/cli/tunnel-handler.test.js.map +1 -0
  37. package/dist/cli/tunnel.d.ts +57 -0
  38. package/dist/cli/tunnel.js +154 -0
  39. package/dist/cli/tunnel.js.map +1 -0
  40. package/dist/cli/tunnel.test.js +190 -0
  41. package/dist/cli/tunnel.test.js.map +1 -0
  42. package/dist/cli/types.d.ts +5 -0
  43. package/dist/cli/types.js +2 -0
  44. package/dist/cli/types.js.map +1 -0
  45. package/dist/cli/use-execute-steps.d.ts +3 -2
  46. package/dist/cli/use-execute-steps.js +6 -1
  47. package/dist/cli/use-execute-steps.js.map +1 -1
  48. package/dist/cli/use-messages.d.ts +3 -0
  49. package/dist/cli/use-messages.js +11 -0
  50. package/dist/cli/use-messages.js.map +1 -0
  51. package/dist/cli/use-nodemon.d.ts +26 -0
  52. package/dist/cli/use-nodemon.js +106 -0
  53. package/dist/cli/use-nodemon.js.map +1 -0
  54. package/dist/cli/use-open-browser.d.ts +1 -0
  55. package/dist/cli/use-open-browser.js +44 -0
  56. package/dist/cli/use-open-browser.js.map +1 -0
  57. package/dist/cli/use-tunnel.d.ts +14 -0
  58. package/dist/cli/use-tunnel.js +131 -0
  59. package/dist/cli/use-tunnel.js.map +1 -0
  60. package/dist/cli/use-typescript-check.d.ts +15 -0
  61. package/dist/cli/use-typescript-check.js +97 -0
  62. package/dist/cli/use-typescript-check.js.map +1 -0
  63. package/dist/commands/build.d.ts +0 -3
  64. package/dist/commands/build.js +3 -16
  65. package/dist/commands/build.js.map +1 -1
  66. package/dist/commands/create.d.ts +9 -0
  67. package/dist/commands/create.js +30 -0
  68. package/dist/commands/create.js.map +1 -0
  69. package/dist/commands/dev.d.ts +5 -1
  70. package/dist/commands/dev.js +109 -13
  71. package/dist/commands/dev.js.map +1 -1
  72. package/dist/commands/start.d.ts +3 -1
  73. package/dist/commands/start.js +37 -15
  74. package/dist/commands/start.js.map +1 -1
  75. package/dist/commands/telemetry/disable.js.map +1 -1
  76. package/dist/commands/telemetry/enable.js.map +1 -1
  77. package/dist/commands/telemetry/status.js.map +1 -1
  78. package/dist/context-warnings.d.ts +5 -0
  79. package/dist/context-warnings.js +31 -0
  80. package/dist/context-warnings.js.map +1 -0
  81. package/dist/context-warnings.test.d.ts +1 -0
  82. package/dist/context-warnings.test.js +28 -0
  83. package/dist/context-warnings.test.js.map +1 -0
  84. package/dist/server/app.d.ts +194 -0
  85. package/dist/server/app.js +266 -0
  86. package/dist/server/app.js.map +1 -0
  87. package/dist/server/app.test.d.ts +1 -0
  88. package/dist/server/app.test.js +97 -0
  89. package/dist/server/app.test.js.map +1 -0
  90. package/dist/server/asset-base-url-transform-plugin.d.ts +11 -0
  91. package/dist/server/asset-base-url-transform-plugin.js +48 -0
  92. package/dist/server/asset-base-url-transform-plugin.js.map +1 -0
  93. package/dist/server/asset-base-url-transform-plugin.test.d.ts +1 -0
  94. package/dist/server/asset-base-url-transform-plugin.test.js +134 -0
  95. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -0
  96. package/dist/server/auth/discovery.d.ts +33 -0
  97. package/dist/server/auth/discovery.js +56 -0
  98. package/dist/server/auth/discovery.js.map +1 -0
  99. package/dist/server/auth/discovery.test.d.ts +1 -0
  100. package/dist/server/auth/discovery.test.js +93 -0
  101. package/dist/server/auth/discovery.test.js.map +1 -0
  102. package/dist/server/auth/index.d.ts +48 -0
  103. package/dist/server/auth/index.js +2 -0
  104. package/dist/server/auth/index.js.map +1 -0
  105. package/dist/server/auth/providers/auth0.d.ts +40 -0
  106. package/dist/server/auth/providers/auth0.js +36 -0
  107. package/dist/server/auth/providers/auth0.js.map +1 -0
  108. package/dist/server/auth/providers/auth0.test.d.ts +1 -0
  109. package/dist/server/auth/providers/auth0.test.js +50 -0
  110. package/dist/server/auth/providers/auth0.test.js.map +1 -0
  111. package/dist/server/auth/providers/authplane.d.ts +49 -0
  112. package/dist/server/auth/providers/authplane.js +57 -0
  113. package/dist/server/auth/providers/authplane.js.map +1 -0
  114. package/dist/server/auth/providers/authplane.test.d.ts +1 -0
  115. package/dist/server/auth/providers/authplane.test.js +143 -0
  116. package/dist/server/auth/providers/authplane.test.js.map +1 -0
  117. package/dist/server/auth/providers/clerk.d.ts +51 -0
  118. package/dist/server/auth/providers/clerk.js +19 -0
  119. package/dist/server/auth/providers/clerk.js.map +1 -0
  120. package/dist/server/auth/providers/clerk.test.d.ts +1 -0
  121. package/dist/server/auth/providers/clerk.test.js +30 -0
  122. package/dist/server/auth/providers/clerk.test.js.map +1 -0
  123. package/dist/server/auth/providers/custom.d.ts +42 -0
  124. package/dist/server/auth/providers/custom.js +59 -0
  125. package/dist/server/auth/providers/custom.js.map +1 -0
  126. package/dist/server/auth/providers/custom.test.d.ts +1 -0
  127. package/dist/server/auth/providers/custom.test.js +161 -0
  128. package/dist/server/auth/providers/custom.test.js.map +1 -0
  129. package/dist/server/auth/providers/descope.d.ts +44 -0
  130. package/dist/server/auth/providers/descope.js +44 -0
  131. package/dist/server/auth/providers/descope.js.map +1 -0
  132. package/dist/server/auth/providers/descope.test.d.ts +1 -0
  133. package/dist/server/auth/providers/descope.test.js +62 -0
  134. package/dist/server/auth/providers/descope.test.js.map +1 -0
  135. package/dist/server/auth/providers/shared.d.ts +2 -0
  136. package/dist/server/auth/providers/shared.js +6 -0
  137. package/dist/server/auth/providers/shared.js.map +1 -0
  138. package/dist/server/auth/providers/shared.test.d.ts +1 -0
  139. package/dist/server/auth/providers/shared.test.js +10 -0
  140. package/dist/server/auth/providers/shared.test.js.map +1 -0
  141. package/dist/server/auth/providers/stytch.d.ts +25 -0
  142. package/dist/server/auth/providers/stytch.js +16 -0
  143. package/dist/server/auth/providers/stytch.js.map +1 -0
  144. package/dist/server/auth/providers/verify-spy.d.ts +12 -0
  145. package/dist/server/auth/providers/verify-spy.js +21 -0
  146. package/dist/server/auth/providers/verify-spy.js.map +1 -0
  147. package/dist/server/auth/providers/workos.d.ts +34 -0
  148. package/dist/server/auth/providers/workos.js +16 -0
  149. package/dist/server/auth/providers/workos.js.map +1 -0
  150. package/dist/server/auth/security-schemes.d.ts +23 -0
  151. package/dist/server/auth/security-schemes.js +64 -0
  152. package/dist/server/auth/security-schemes.js.map +1 -0
  153. package/dist/server/auth/security-schemes.test.d.ts +1 -0
  154. package/dist/server/auth/security-schemes.test.js +99 -0
  155. package/dist/server/auth/security-schemes.test.js.map +1 -0
  156. package/dist/server/auth/setup.d.ts +6 -0
  157. package/dist/server/auth/setup.js +91 -0
  158. package/dist/server/auth/setup.js.map +1 -0
  159. package/dist/server/auth/setup.test.d.ts +1 -0
  160. package/dist/server/auth/setup.test.js +514 -0
  161. package/dist/server/auth/setup.test.js.map +1 -0
  162. package/dist/server/auth/verify.d.ts +48 -0
  163. package/dist/server/auth/verify.js +62 -0
  164. package/dist/server/auth/verify.js.map +1 -0
  165. package/dist/server/auth/verify.test.d.ts +1 -0
  166. package/dist/server/auth/verify.test.js +165 -0
  167. package/dist/server/auth/verify.test.js.map +1 -0
  168. package/dist/server/auth-extra.test-d.d.ts +1 -0
  169. package/dist/server/auth-extra.test-d.js +130 -0
  170. package/dist/server/auth-extra.test-d.js.map +1 -0
  171. package/dist/server/auth.d.ts +57 -0
  172. package/dist/server/auth.js +27 -0
  173. package/dist/server/auth.js.map +1 -0
  174. package/dist/server/build-manifest.test.d.ts +1 -0
  175. package/dist/server/build-manifest.test.js +28 -0
  176. package/dist/server/build-manifest.test.js.map +1 -0
  177. package/dist/server/content-helpers.d.ts +67 -0
  178. package/dist/server/content-helpers.js +79 -0
  179. package/dist/server/content-helpers.js.map +1 -0
  180. package/dist/server/content-helpers.test.d.ts +1 -0
  181. package/dist/server/content-helpers.test.js +70 -0
  182. package/dist/server/content-helpers.test.js.map +1 -0
  183. package/dist/server/express.d.ts +31 -0
  184. package/dist/server/express.js +107 -0
  185. package/dist/server/express.js.map +1 -0
  186. package/dist/server/express.test.d.ts +1 -0
  187. package/dist/server/express.test.js +608 -0
  188. package/dist/server/express.test.js.map +1 -0
  189. package/dist/server/file-ref.d.ts +28 -0
  190. package/dist/server/file-ref.js +27 -0
  191. package/dist/server/file-ref.js.map +1 -0
  192. package/dist/server/host.d.ts +2 -0
  193. package/dist/server/host.js +11 -0
  194. package/dist/server/host.js.map +1 -0
  195. package/dist/server/host.test.d.ts +1 -0
  196. package/dist/server/host.test.js +13 -0
  197. package/dist/server/host.test.js.map +1 -0
  198. package/dist/server/index.d.ts +21 -3
  199. package/dist/server/index.js +17 -2
  200. package/dist/server/index.js.map +1 -1
  201. package/dist/server/inferUtilityTypes.d.ts +6 -6
  202. package/dist/server/inferUtilityTypes.js.map +1 -1
  203. package/dist/server/mcp-errors.test.d.ts +1 -0
  204. package/dist/server/mcp-errors.test.js +41 -0
  205. package/dist/server/mcp-errors.test.js.map +1 -0
  206. package/dist/server/metric.d.ts +14 -0
  207. package/dist/server/metric.js +62 -0
  208. package/dist/server/metric.js.map +1 -0
  209. package/dist/server/middleware.d.ts +162 -0
  210. package/dist/server/middleware.js +126 -0
  211. package/dist/server/middleware.js.map +1 -0
  212. package/dist/server/middleware.test-d.d.ts +1 -0
  213. package/dist/server/middleware.test-d.js +75 -0
  214. package/dist/server/middleware.test-d.js.map +1 -0
  215. package/dist/server/middleware.test.d.ts +1 -0
  216. package/dist/server/middleware.test.js +601 -0
  217. package/dist/server/middleware.test.js.map +1 -0
  218. package/dist/server/openai-ui.d.ts +11 -0
  219. package/dist/server/openai-ui.js +82 -0
  220. package/dist/server/openai-ui.js.map +1 -0
  221. package/dist/server/register-tool.test.d.ts +1 -0
  222. package/dist/server/register-tool.test.js +74 -0
  223. package/dist/server/register-tool.test.js.map +1 -0
  224. package/dist/server/requestOrigin.d.ts +7 -0
  225. package/dist/server/requestOrigin.js +25 -0
  226. package/dist/server/requestOrigin.js.map +1 -0
  227. package/dist/server/server.d.ts +459 -64
  228. package/dist/server/server.js +533 -109
  229. package/dist/server/server.js.map +1 -1
  230. package/dist/server/skills-integration.test.d.ts +1 -0
  231. package/dist/server/skills-integration.test.js +86 -0
  232. package/dist/server/skills-integration.test.js.map +1 -0
  233. package/dist/server/skills.d.ts +27 -0
  234. package/dist/server/skills.js +188 -0
  235. package/dist/server/skills.js.map +1 -0
  236. package/dist/server/skills.test.d.ts +1 -0
  237. package/dist/server/skills.test.js +243 -0
  238. package/dist/server/skills.test.js.map +1 -0
  239. package/dist/server/templateHelper.d.ts +2 -7
  240. package/dist/server/templateHelper.js +3 -22
  241. package/dist/server/templateHelper.js.map +1 -1
  242. package/dist/server/templates.generated.d.ts +4 -0
  243. package/dist/server/templates.generated.js +43 -0
  244. package/dist/server/templates.generated.js.map +1 -0
  245. package/dist/server/tool-extra.test.d.ts +1 -0
  246. package/dist/server/tool-extra.test.js +88 -0
  247. package/dist/server/tool-extra.test.js.map +1 -0
  248. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  249. package/dist/server/tunnel-proxy-router.js +110 -0
  250. package/dist/server/tunnel-proxy-router.js.map +1 -0
  251. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  252. package/dist/server/tunnel-proxy-router.test.js +229 -0
  253. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  254. package/dist/server/view-name.test-d.d.ts +1 -0
  255. package/dist/server/view-name.test-d.js +8 -0
  256. package/dist/server/view-name.test-d.js.map +1 -0
  257. package/dist/server/view-resource-resolution.test.d.ts +6 -0
  258. package/dist/server/view-resource-resolution.test.js +176 -0
  259. package/dist/server/view-resource-resolution.test.js.map +1 -0
  260. package/dist/server/viewsDevServer.d.ts +14 -0
  261. package/dist/server/viewsDevServer.js +48 -0
  262. package/dist/server/viewsDevServer.js.map +1 -0
  263. package/dist/test/utils.d.ts +21 -31
  264. package/dist/test/utils.js +222 -198
  265. package/dist/test/utils.js.map +1 -1
  266. package/dist/test/view.test.d.ts +1 -0
  267. package/dist/test/view.test.js +540 -0
  268. package/dist/test/view.test.js.map +1 -0
  269. package/dist/version.d.ts +1 -0
  270. package/dist/version.js +3 -0
  271. package/dist/version.js.map +1 -0
  272. package/dist/views/index.d.ts +10 -0
  273. package/dist/views/index.js +3 -0
  274. package/dist/views/index.js.map +1 -0
  275. package/dist/views/scan-views.d.ts +16 -0
  276. package/dist/views/scan-views.js +88 -0
  277. package/dist/views/scan-views.js.map +1 -0
  278. package/dist/views/scan-views.test.d.ts +1 -0
  279. package/dist/views/scan-views.test.js +99 -0
  280. package/dist/views/scan-views.test.js.map +1 -0
  281. package/dist/views/validate-view.d.ts +1 -0
  282. package/dist/views/validate-view.js +9 -0
  283. package/dist/views/validate-view.js.map +1 -0
  284. package/dist/views/validate-view.test.d.ts +1 -0
  285. package/dist/views/validate-view.test.js +24 -0
  286. package/dist/views/validate-view.test.js.map +1 -0
  287. package/dist/web/bridges/adaptor.d.ts +51 -0
  288. package/dist/web/bridges/adaptor.js +327 -0
  289. package/dist/web/bridges/adaptor.js.map +1 -0
  290. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  291. package/dist/web/bridges/adaptor.test.js +225 -0
  292. package/dist/web/bridges/adaptor.test.js.map +1 -0
  293. package/dist/web/bridges/apps-sdk/bridge.d.ts +7 -2
  294. package/dist/web/bridges/apps-sdk/bridge.js +15 -3
  295. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  296. package/dist/web/bridges/apps-sdk/index.d.ts +1 -2
  297. package/dist/web/bridges/apps-sdk/index.js +0 -1
  298. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  299. package/dist/web/bridges/apps-sdk/types.d.ts +32 -14
  300. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  301. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +11 -0
  302. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +11 -0
  303. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  304. package/dist/web/bridges/get-adaptor.d.ts +7 -0
  305. package/dist/web/bridges/get-adaptor.js +9 -7
  306. package/dist/web/bridges/get-adaptor.js.map +1 -1
  307. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  308. package/dist/web/bridges/get-adaptor.test.js +32 -0
  309. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  310. package/dist/web/bridges/index.js.map +1 -1
  311. package/dist/web/bridges/mcp-app/bridge.d.ts +27 -31
  312. package/dist/web/bridges/mcp-app/bridge.js +118 -198
  313. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  314. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  315. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  316. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  317. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  318. package/dist/web/bridges/mcp-app/index.js +0 -1
  319. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  320. package/dist/web/bridges/mcp-app/types.d.ts +21 -2
  321. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  322. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +17 -3
  323. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +14 -2
  324. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  325. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +2 -42
  326. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  327. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  328. package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
  329. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  330. package/dist/web/bridges/types.d.ts +135 -14
  331. package/dist/web/bridges/types.js +14 -1
  332. package/dist/web/bridges/types.js.map +1 -1
  333. package/dist/web/bridges/types.test.d.ts +1 -0
  334. package/dist/web/bridges/types.test.js +19 -0
  335. package/dist/web/bridges/types.test.js.map +1 -0
  336. package/dist/web/bridges/use-host-context.d.ts +5 -0
  337. package/dist/web/bridges/use-host-context.js +5 -0
  338. package/dist/web/bridges/use-host-context.js.map +1 -1
  339. package/dist/web/components/modal-provider.d.ts +1 -1
  340. package/dist/web/components/modal-provider.js +5 -6
  341. package/dist/web/components/modal-provider.js.map +1 -1
  342. package/dist/web/create-store.d.ts +26 -0
  343. package/dist/web/create-store.js +43 -3
  344. package/dist/web/create-store.js.map +1 -1
  345. package/dist/web/create-store.test.js +33 -27
  346. package/dist/web/create-store.test.js.map +1 -1
  347. package/dist/web/data-llm.d.ts +35 -2
  348. package/dist/web/data-llm.js +31 -3
  349. package/dist/web/data-llm.js.map +1 -1
  350. package/dist/web/data-llm.test.js +53 -37
  351. package/dist/web/data-llm.test.js.map +1 -1
  352. package/dist/web/generate-helpers.d.ts +39 -31
  353. package/dist/web/generate-helpers.js +36 -28
  354. package/dist/web/generate-helpers.js.map +1 -1
  355. package/dist/web/generate-helpers.test-d.js +33 -31
  356. package/dist/web/generate-helpers.test-d.js.map +1 -1
  357. package/dist/web/generate-helpers.test.js +2 -2
  358. package/dist/web/generate-helpers.test.js.map +1 -1
  359. package/dist/web/helpers/state.d.ts +2 -2
  360. package/dist/web/helpers/state.js +11 -11
  361. package/dist/web/helpers/state.js.map +1 -1
  362. package/dist/web/helpers/state.test.js +9 -9
  363. package/dist/web/helpers/state.test.js.map +1 -1
  364. package/dist/web/hooks/index.d.ts +9 -3
  365. package/dist/web/hooks/index.js +8 -2
  366. package/dist/web/hooks/index.js.map +1 -1
  367. package/dist/web/hooks/test/utils.d.ts +7 -2
  368. package/dist/web/hooks/test/utils.js +18 -3
  369. package/dist/web/hooks/test/utils.js.map +1 -1
  370. package/dist/web/hooks/use-call-tool.d.ts +45 -0
  371. package/dist/web/hooks/use-call-tool.js +40 -8
  372. package/dist/web/hooks/use-call-tool.js.map +1 -1
  373. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  374. package/dist/web/hooks/use-call-tool.test.js +71 -29
  375. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  376. package/dist/web/hooks/use-deep-link.d.ts +22 -0
  377. package/dist/web/hooks/use-deep-link.js +34 -0
  378. package/dist/web/hooks/use-deep-link.js.map +1 -0
  379. package/dist/web/hooks/use-display-mode.d.ts +23 -3
  380. package/dist/web/hooks/use-display-mode.js +20 -0
  381. package/dist/web/hooks/use-display-mode.js.map +1 -1
  382. package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
  383. package/dist/web/hooks/use-display-mode.test-d.js +8 -0
  384. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
  385. package/dist/web/hooks/use-display-mode.test.js +57 -21
  386. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  387. package/dist/web/hooks/use-download.d.ts +3 -0
  388. package/dist/web/hooks/use-download.js +7 -0
  389. package/dist/web/hooks/use-download.js.map +1 -0
  390. package/dist/web/hooks/use-download.test.d.ts +1 -0
  391. package/dist/web/hooks/use-download.test.js +103 -0
  392. package/dist/web/hooks/use-download.test.js.map +1 -0
  393. package/dist/web/hooks/use-files.d.ts +34 -1
  394. package/dist/web/hooks/use-files.js +33 -0
  395. package/dist/web/hooks/use-files.js.map +1 -1
  396. package/dist/web/hooks/use-files.test.js +36 -4
  397. package/dist/web/hooks/use-files.test.js.map +1 -1
  398. package/dist/web/hooks/use-host.d.ts +44 -0
  399. package/dist/web/hooks/use-host.js +45 -0
  400. package/dist/web/hooks/use-host.js.map +1 -0
  401. package/dist/web/hooks/use-host.test.d.ts +1 -0
  402. package/dist/web/hooks/use-host.test.js +59 -0
  403. package/dist/web/hooks/use-host.test.js.map +1 -0
  404. package/dist/web/hooks/use-open-external.d.ts +20 -1
  405. package/dist/web/hooks/use-open-external.js +17 -1
  406. package/dist/web/hooks/use-open-external.js.map +1 -1
  407. package/dist/web/hooks/use-open-external.test.js +40 -15
  408. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  409. package/dist/web/hooks/use-register-view-tool.d.ts +37 -0
  410. package/dist/web/hooks/use-register-view-tool.js +50 -0
  411. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  412. package/dist/web/hooks/use-request-close.d.ts +16 -0
  413. package/dist/web/hooks/use-request-close.js +21 -0
  414. package/dist/web/hooks/use-request-close.js.map +1 -0
  415. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  416. package/dist/web/hooks/use-request-close.test.js +47 -0
  417. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  418. package/dist/web/hooks/use-request-modal.d.ts +16 -1
  419. package/dist/web/hooks/use-request-modal.js +19 -4
  420. package/dist/web/hooks/use-request-modal.js.map +1 -1
  421. package/dist/web/hooks/use-request-modal.test.js +16 -2
  422. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  423. package/dist/web/hooks/use-request-size.d.ts +20 -0
  424. package/dist/web/hooks/use-request-size.js +24 -0
  425. package/dist/web/hooks/use-request-size.js.map +1 -0
  426. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  427. package/dist/web/hooks/use-request-size.test.js +47 -0
  428. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  429. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -1
  430. package/dist/web/hooks/use-send-follow-up-message.js +19 -2
  431. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  432. package/dist/web/hooks/use-set-open-in-app-url.d.ts +17 -0
  433. package/dist/web/hooks/use-set-open-in-app-url.js +17 -0
  434. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -1
  435. package/dist/web/hooks/use-set-open-in-app-url.test.js +29 -21
  436. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  437. package/dist/web/hooks/use-tool-info.d.ts +46 -14
  438. package/dist/web/hooks/use-tool-info.js +29 -7
  439. package/dist/web/hooks/use-tool-info.js.map +1 -1
  440. package/dist/web/hooks/use-tool-info.test-d.js +11 -34
  441. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  442. package/dist/web/hooks/use-tool-info.test.js +43 -38
  443. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  444. package/dist/web/hooks/use-user.d.ts +5 -2
  445. package/dist/web/hooks/use-user.js +23 -4
  446. package/dist/web/hooks/use-user.js.map +1 -1
  447. package/dist/web/hooks/use-user.test.js +105 -29
  448. package/dist/web/hooks/use-user.test.js.map +1 -1
  449. package/dist/web/hooks/use-view-state.d.ts +25 -0
  450. package/dist/web/hooks/use-view-state.js +42 -0
  451. package/dist/web/hooks/use-view-state.js.map +1 -0
  452. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  453. package/dist/web/hooks/use-view-state.test.js +212 -0
  454. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  455. package/dist/web/hooks/use-viewport.d.ts +20 -0
  456. package/dist/web/hooks/use-viewport.js +21 -0
  457. package/dist/web/hooks/use-viewport.js.map +1 -0
  458. package/dist/web/hooks/use-viewport.test.d.ts +1 -0
  459. package/dist/web/hooks/use-viewport.test.js +109 -0
  460. package/dist/web/hooks/use-viewport.test.js.map +1 -0
  461. package/dist/web/index.d.ts +1 -2
  462. package/dist/web/index.js +1 -2
  463. package/dist/web/index.js.map +1 -1
  464. package/dist/web/mount-view.d.ts +21 -0
  465. package/dist/web/mount-view.js +43 -0
  466. package/dist/web/mount-view.js.map +1 -0
  467. package/dist/web/proxy.js +0 -1
  468. package/dist/web/proxy.js.map +1 -1
  469. package/dist/web/types.d.ts +4 -0
  470. package/dist/web/types.js.map +1 -1
  471. package/package.json +56 -31
  472. package/tsconfig.base.json +33 -0
  473. package/dist/server/templates/development.hbs +0 -66
  474. package/dist/server/templates/production.hbs +0 -7
  475. package/dist/server/widgetsDevServer.d.ts +0 -12
  476. package/dist/server/widgetsDevServer.js +0 -47
  477. package/dist/server/widgetsDevServer.js.map +0 -1
  478. package/dist/test/widget.test.js +0 -255
  479. package/dist/test/widget.test.js.map +0 -1
  480. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -22
  481. package/dist/web/bridges/apps-sdk/adaptor.js +0 -64
  482. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  483. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -36
  484. package/dist/web/bridges/mcp-app/adaptor.js +0 -185
  485. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
  486. package/dist/web/hooks/use-layout.d.ts +0 -22
  487. package/dist/web/hooks/use-layout.js +0 -23
  488. package/dist/web/hooks/use-layout.js.map +0 -1
  489. package/dist/web/hooks/use-layout.test.js +0 -96
  490. package/dist/web/hooks/use-layout.test.js.map +0 -1
  491. package/dist/web/hooks/use-widget-state.d.ts +0 -4
  492. package/dist/web/hooks/use-widget-state.js +0 -32
  493. package/dist/web/hooks/use-widget-state.js.map +0 -1
  494. package/dist/web/hooks/use-widget-state.test.js +0 -61
  495. package/dist/web/hooks/use-widget-state.test.js.map +0 -1
  496. package/dist/web/mount-widget.d.ts +0 -1
  497. package/dist/web/mount-widget.js +0 -27
  498. package/dist/web/mount-widget.js.map +0 -1
  499. package/dist/web/plugin/data-llm.test.js +0 -81
  500. package/dist/web/plugin/data-llm.test.js.map +0 -1
  501. package/dist/web/plugin/plugin.d.ts +0 -2
  502. package/dist/web/plugin/plugin.js +0 -39
  503. package/dist/web/plugin/plugin.js.map +0 -1
  504. package/dist/web/plugin/transform-data-llm.d.ts +0 -12
  505. package/dist/web/plugin/transform-data-llm.js +0 -96
  506. package/dist/web/plugin/transform-data-llm.js.map +0 -1
  507. package/dist/web/plugin/transform-data-llm.test.js +0 -81
  508. package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
  509. /package/dist/{test/widget.test.d.ts → cli/build-helpers.test.d.ts} +0 -0
  510. /package/dist/{web/hooks/use-layout.test.d.ts → cli/build-steps.test.d.ts} +0 -0
  511. /package/dist/{web/hooks/use-widget-state.test.d.ts → cli/tunnel-control-server.test.d.ts} +0 -0
  512. /package/dist/{web/plugin/data-llm.test.d.ts → cli/tunnel-handler.test.d.ts} +0 -0
  513. /package/dist/{web/plugin/transform-data-llm.test.d.ts → cli/tunnel.test.d.ts} +0 -0
@@ -1,24 +1,56 @@
1
1
  import { renderHook } from "@testing-library/react";
2
2
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
+ import { HostAdaptor } from "../bridges/adaptor.js";
4
+ import { AppsSdkBridge } from "../bridges/apps-sdk/bridge.js";
5
+ import { McpAppBridge } from "../bridges/mcp-app/bridge.js";
3
6
  import { useFiles } from "./use-files.js";
4
7
  describe("useFiles", () => {
5
8
  const OpenaiMock = {
6
- uploadFile: vi.fn(),
9
+ uploadFile: vi.fn().mockResolvedValue({
10
+ fileId: `sediment://file_abc123`,
11
+ }),
7
12
  getFileDownloadUrl: vi.fn(),
13
+ widgetState: null,
14
+ setWidgetState: vi.fn(),
8
15
  };
9
16
  beforeEach(() => {
10
- vi.stubGlobal("skybridge", { hostType: "apps-sdk" });
17
+ HostAdaptor.resetInstance();
18
+ McpAppBridge.resetInstance();
19
+ AppsSdkBridge.resetInstance();
20
+ vi.stubGlobal("skybridge", {});
11
21
  vi.stubGlobal("openai", OpenaiMock);
22
+ vi.stubGlobal("parent", { postMessage: vi.fn() });
12
23
  });
13
24
  afterEach(() => {
14
25
  vi.unstubAllGlobals();
15
- vi.resetAllMocks();
26
+ vi.clearAllMocks();
27
+ HostAdaptor.resetInstance();
28
+ McpAppBridge.resetInstance();
29
+ AppsSdkBridge.resetInstance();
16
30
  });
17
31
  const dummyFile = new File([], "test.txt");
18
32
  it("should upload a file to ChatGPT", () => {
19
33
  const { result } = renderHook(() => useFiles());
20
34
  result.current.upload(dummyFile);
21
- expect(OpenaiMock.uploadFile).toHaveBeenCalledWith(dummyFile);
35
+ expect(OpenaiMock.uploadFile).toHaveBeenCalledWith(dummyFile, undefined);
36
+ });
37
+ it("should upload a file with library option", () => {
38
+ const { result } = renderHook(() => useFiles());
39
+ result.current.upload(dummyFile, { library: true });
40
+ expect(OpenaiMock.uploadFile).toHaveBeenCalledWith(dummyFile, {
41
+ library: true,
42
+ });
43
+ });
44
+ it("should select files from ChatGPT", async () => {
45
+ const selectedFiles = [
46
+ { fileId: "file_1", fileName: "doc.pdf", mimeType: "application/pdf" },
47
+ ];
48
+ OpenaiMock.selectFiles = vi.fn().mockResolvedValue(selectedFiles);
49
+ const { result } = renderHook(() => useFiles());
50
+ const files = await result.current.selectFiles();
51
+ expect(OpenaiMock.selectFiles).toHaveBeenCalled();
52
+ expect(files).toEqual(selectedFiles);
53
+ delete OpenaiMock.selectFiles;
22
54
  });
23
55
  it("should download a file from ChatGPT", () => {
24
56
  const fileId = "123";
@@ -1 +1 @@
1
- {"version":3,"file":"use-files.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-files.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,MAAM,UAAU,GAAG;QACjB,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE;QACnB,kBAAkB,EAAE,EAAE,CAAC,EAAE,EAAE;KAC5B,CAAC;IAEF,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACrD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IAE3C,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;QAEhD,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACjC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,MAAM,GAAG,KAAK,CAAC;QACrB,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;QAEhD,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAC1C,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"use-files.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-files.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { renderHook } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { HostAdaptor } from \"../bridges/adaptor.js\";\nimport { AppsSdkBridge } from \"../bridges/apps-sdk/bridge.js\";\nimport { McpAppBridge } from \"../bridges/mcp-app/bridge.js\";\nimport { useFiles } from \"./use-files.js\";\n\ndescribe(\"useFiles\", () => {\n const OpenaiMock: Record<string, unknown> = {\n uploadFile: vi.fn().mockResolvedValue({\n fileId: `sediment://file_abc123`,\n }),\n getFileDownloadUrl: vi.fn(),\n widgetState: null,\n setWidgetState: vi.fn(),\n };\n\n beforeEach(() => {\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"openai\", OpenaiMock);\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.clearAllMocks();\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n });\n\n const dummyFile = new File([], \"test.txt\");\n\n it(\"should upload a file to ChatGPT\", () => {\n const { result } = renderHook(() => useFiles());\n\n result.current.upload(dummyFile);\n expect(OpenaiMock.uploadFile).toHaveBeenCalledWith(dummyFile, undefined);\n });\n\n it(\"should upload a file with library option\", () => {\n const { result } = renderHook(() => useFiles());\n\n result.current.upload(dummyFile, { library: true });\n expect(OpenaiMock.uploadFile).toHaveBeenCalledWith(dummyFile, {\n library: true,\n });\n });\n\n it(\"should select files from ChatGPT\", async () => {\n const selectedFiles = [\n { fileId: \"file_1\", fileName: \"doc.pdf\", mimeType: \"application/pdf\" },\n ];\n OpenaiMock.selectFiles = vi.fn().mockResolvedValue(selectedFiles);\n\n const { result } = renderHook(() => useFiles());\n\n const files = await result.current.selectFiles();\n expect(OpenaiMock.selectFiles).toHaveBeenCalled();\n expect(files).toEqual(selectedFiles);\n\n delete OpenaiMock.selectFiles;\n });\n\n it(\"should download a file from ChatGPT\", () => {\n const fileId = \"123\";\n const { result } = renderHook(() => useFiles());\n\n result.current.getDownloadUrl({ fileId });\n expect(OpenaiMock.getFileDownloadUrl).toHaveBeenCalledWith({ fileId });\n });\n});\n"]}
@@ -0,0 +1,44 @@
1
+ import type { McpUiHostCapabilities } from "@modelcontextprotocol/ext-apps";
2
+ /**
3
+ * Known host applications, as normalized slugs. Unrecognized hosts surface
4
+ * their raw `hostInfo.name` string instead.
5
+ */
6
+ export type Host = "chatgpt" | "claude" | "cursor" | "goose" | "mistral-vibe" | "alpic";
7
+ /**
8
+ * OpenAI MCP extensions the host advertises. Each flag is `true` only when the
9
+ * host sends a truthy `hostCapabilities.experimental["openai/<name>"]`, so every flag is
10
+ * `false` before the handshake and on hosts other than ChatGPT.
11
+ */
12
+ export type OpenAIHostCapabilities = {
13
+ /** Read, subscribe to and write the file opened through a file entrypoint. */
14
+ resource: boolean;
15
+ /** Titles, thumbnails and background content in `ui/update-model-context`. */
16
+ modelContext: boolean;
17
+ /** `ui/message` targets and titled items. */
18
+ message: boolean;
19
+ /** Open a local file with `openai/files/open`. */
20
+ files: boolean;
21
+ };
22
+ export type HostInfo = {
23
+ name: Host | (string & {}) | undefined;
24
+ version: string | undefined;
25
+ /** The host's MCP Apps capabilities, `undefined` until the handshake. */
26
+ capabilities: McpUiHostCapabilities | undefined;
27
+ /** OpenAI MCP extensions the host supports. */
28
+ openai: OpenAIHostCapabilities;
29
+ };
30
+ /**
31
+ * Identity and capabilities of the host application rendering the view, from
32
+ * the MCP Apps `ui/initialize` handshake. `name` is normalized to a
33
+ * {@link Host} slug when recognized, otherwise the raw string; `name`,
34
+ * `version` and `capabilities` are `undefined` until the handshake resolves
35
+ * (the view renders first and re-renders once it lands).
36
+ *
37
+ * @example
38
+ * ```tsx
39
+ * const { name, openai } = useHost();
40
+ * if (name === "claude") return <ClaudeLayout />;
41
+ * if (openai.files) return <OpenFileButton />;
42
+ * ```
43
+ */
44
+ export declare function useHost(): HostInfo;
@@ -0,0 +1,45 @@
1
+ import { useMemo } from "react";
2
+ import { useMcpAppContext } from "../bridges/index.js";
3
+ const HOST_BY_REPORTED_NAME = {
4
+ chatgpt: "chatgpt",
5
+ Claude: "claude",
6
+ Cursor: "cursor",
7
+ "MCP-UI Host": "goose",
8
+ "Le Chat": "mistral-vibe",
9
+ "alpic-playground": "alpic",
10
+ };
11
+ /**
12
+ * Identity and capabilities of the host application rendering the view, from
13
+ * the MCP Apps `ui/initialize` handshake. `name` is normalized to a
14
+ * {@link Host} slug when recognized, otherwise the raw string; `name`,
15
+ * `version` and `capabilities` are `undefined` until the handshake resolves
16
+ * (the view renders first and re-renders once it lands).
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * const { name, openai } = useHost();
21
+ * if (name === "claude") return <ClaudeLayout />;
22
+ * if (openai.files) return <OpenFileButton />;
23
+ * ```
24
+ */
25
+ export function useHost() {
26
+ const hostInfo = useMcpAppContext("hostInfo");
27
+ const capabilities = useMcpAppContext("hostCapabilities") ?? undefined;
28
+ const name = hostInfo?.name;
29
+ const openai = useMemo(() => {
30
+ const supports = (extension) => Boolean(capabilities?.experimental?.[`openai/${extension}`]);
31
+ return {
32
+ resource: supports("resource"),
33
+ modelContext: supports("modelContext"),
34
+ message: supports("message"),
35
+ files: supports("files"),
36
+ };
37
+ }, [capabilities]);
38
+ return {
39
+ name: name !== undefined ? (HOST_BY_REPORTED_NAME[name] ?? name) : undefined,
40
+ version: hostInfo?.version,
41
+ capabilities,
42
+ openai,
43
+ };
44
+ }
45
+ //# sourceMappingURL=use-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-host.js","sourceRoot":"","sources":["../../../src/web/hooks/use-host.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAcvD,MAAM,qBAAqB,GAAyB;IAClD,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,aAAa,EAAE,OAAO;IACtB,SAAS,EAAE,cAAc;IACzB,kBAAkB,EAAE,OAAO;CAC5B,CAAC;AA2BF;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,OAAO;IACrB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,gBAAgB,CAAC,kBAAkB,CAAC,IAAI,SAAS,CAAC;IACvE,MAAM,IAAI,GAAG,QAAQ,EAAE,IAAI,CAAC;IAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE;QAC1B,MAAM,QAAQ,GAAG,CAAC,SAAiB,EAAE,EAAE,CACrC,OAAO,CAAC,YAAY,EAAE,YAAY,EAAE,CAAC,UAAU,SAAS,EAAE,CAAC,CAAC,CAAC;QAC/D,OAAO;YACL,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC;YAC9B,YAAY,EAAE,QAAQ,CAAC,cAAc,CAAC;YACtC,OAAO,EAAE,QAAQ,CAAC,SAAS,CAAC;YAC5B,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC;SACzB,CAAC;IACJ,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;IAEnB,OAAO;QACL,IAAI,EACF,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;QACxE,OAAO,EAAE,QAAQ,EAAE,OAAO;QAC1B,YAAY;QACZ,MAAM;KACP,CAAC;AACJ,CAAC","sourcesContent":["import type { McpUiHostCapabilities } from \"@modelcontextprotocol/ext-apps\";\nimport { useMemo } from \"react\";\nimport { useMcpAppContext } from \"../bridges/index.js\";\n\n/**\n * Known host applications, as normalized slugs. Unrecognized hosts surface\n * their raw `hostInfo.name` string instead.\n */\nexport type Host =\n | \"chatgpt\"\n | \"claude\"\n | \"cursor\"\n | \"goose\"\n | \"mistral-vibe\"\n | \"alpic\";\n\nconst HOST_BY_REPORTED_NAME: Record<string, Host> = {\n chatgpt: \"chatgpt\",\n Claude: \"claude\",\n Cursor: \"cursor\",\n \"MCP-UI Host\": \"goose\",\n \"Le Chat\": \"mistral-vibe\",\n \"alpic-playground\": \"alpic\",\n};\n\n/**\n * OpenAI MCP extensions the host advertises. Each flag is `true` only when the\n * host sends a truthy `hostCapabilities.experimental[\"openai/<name>\"]`, so every flag is\n * `false` before the handshake and on hosts other than ChatGPT.\n */\nexport type OpenAIHostCapabilities = {\n /** Read, subscribe to and write the file opened through a file entrypoint. */\n resource: boolean;\n /** Titles, thumbnails and background content in `ui/update-model-context`. */\n modelContext: boolean;\n /** `ui/message` targets and titled items. */\n message: boolean;\n /** Open a local file with `openai/files/open`. */\n files: boolean;\n};\n\nexport type HostInfo = {\n name: Host | (string & {}) | undefined;\n version: string | undefined;\n /** The host's MCP Apps capabilities, `undefined` until the handshake. */\n capabilities: McpUiHostCapabilities | undefined;\n /** OpenAI MCP extensions the host supports. */\n openai: OpenAIHostCapabilities;\n};\n\n/**\n * Identity and capabilities of the host application rendering the view, from\n * the MCP Apps `ui/initialize` handshake. `name` is normalized to a\n * {@link Host} slug when recognized, otherwise the raw string; `name`,\n * `version` and `capabilities` are `undefined` until the handshake resolves\n * (the view renders first and re-renders once it lands).\n *\n * @example\n * ```tsx\n * const { name, openai } = useHost();\n * if (name === \"claude\") return <ClaudeLayout />;\n * if (openai.files) return <OpenFileButton />;\n * ```\n */\nexport function useHost(): HostInfo {\n const hostInfo = useMcpAppContext(\"hostInfo\");\n const capabilities = useMcpAppContext(\"hostCapabilities\") ?? undefined;\n const name = hostInfo?.name;\n const openai = useMemo(() => {\n const supports = (extension: string) =>\n Boolean(capabilities?.experimental?.[`openai/${extension}`]);\n return {\n resource: supports(\"resource\"),\n modelContext: supports(\"modelContext\"),\n message: supports(\"message\"),\n files: supports(\"files\"),\n };\n }, [capabilities]);\n\n return {\n name:\n name !== undefined ? (HOST_BY_REPORTED_NAME[name] ?? name) : undefined,\n version: hostInfo?.version,\n capabilities,\n openai,\n };\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,59 @@
1
+ import { renderHook, waitFor } from "@testing-library/react";
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
+ import { HostAdaptor } from "../bridges/adaptor.js";
4
+ import { McpAppBridge } from "../bridges/mcp-app/bridge.js";
5
+ import { getMcpAppHostPostMessageMock, MockResizeObserver, } from "./test/utils.js";
6
+ import { useHost } from "./use-host.js";
7
+ const stubHost = (hostInfo) => {
8
+ vi.stubGlobal("parent", {
9
+ postMessage: getMcpAppHostPostMessageMock({}, { hostInfo }),
10
+ });
11
+ };
12
+ describe("useHost", () => {
13
+ beforeEach(() => {
14
+ HostAdaptor.resetInstance();
15
+ McpAppBridge.resetInstance();
16
+ vi.stubGlobal("openai", undefined);
17
+ vi.stubGlobal("skybridge", {});
18
+ vi.stubGlobal("ResizeObserver", MockResizeObserver);
19
+ });
20
+ afterEach(() => {
21
+ vi.unstubAllGlobals();
22
+ vi.resetAllMocks();
23
+ McpAppBridge.resetInstance();
24
+ HostAdaptor.resetInstance();
25
+ });
26
+ it("is undefined before the handshake resolves, then populated after", async () => {
27
+ stubHost({ name: "Claude", version: "1.2.3" });
28
+ const { result } = renderHook(() => useHost());
29
+ expect(result.current.name).toBeUndefined();
30
+ expect(result.current.version).toBeUndefined();
31
+ await waitFor(() => {
32
+ expect(result.current.name).toBe("claude");
33
+ expect(result.current.version).toBe("1.2.3");
34
+ });
35
+ });
36
+ it.each([
37
+ ["chatgpt", "chatgpt"],
38
+ ["Claude", "claude"],
39
+ ["Cursor", "cursor"],
40
+ ["MCP-UI Host", "goose"],
41
+ ["Le Chat", "mistral-vibe"],
42
+ ["alpic-playground", "alpic"],
43
+ ])("normalizes reported name %j to slug %j", async (reported, slug) => {
44
+ stubHost({ name: reported, version: "1.0.0" });
45
+ const { result } = renderHook(() => useHost());
46
+ await waitFor(() => {
47
+ expect(result.current.name).toBe(slug);
48
+ });
49
+ });
50
+ it("preserves an unrecognized reported name as-is", async () => {
51
+ stubHost({ name: "Some Future Host", version: "9.9.9" });
52
+ const { result } = renderHook(() => useHost());
53
+ await waitFor(() => {
54
+ expect(result.current.name).toBe("Some Future Host");
55
+ expect(result.current.version).toBe("9.9.9");
56
+ });
57
+ });
58
+ });
59
+ //# sourceMappingURL=use-host.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-host.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-host.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { renderHook, waitFor } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { HostAdaptor } from \"../bridges/adaptor.js\";\nimport { McpAppBridge } from \"../bridges/mcp-app/bridge.js\";\nimport {\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"./test/utils.js\";\nimport { type Host, useHost } from \"./use-host.js\";\n\nconst stubHost = (hostInfo?: { name: string; version: string }) => {\n vi.stubGlobal(\"parent\", {\n postMessage: getMcpAppHostPostMessageMock({}, { hostInfo }),\n });\n};\n\ndescribe(\"useHost\", () => {\n beforeEach(() => {\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n vi.stubGlobal(\"openai\", undefined);\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n McpAppBridge.resetInstance();\n HostAdaptor.resetInstance();\n });\n\n it(\"is undefined before the handshake resolves, then populated after\", async () => {\n stubHost({ name: \"Claude\", version: \"1.2.3\" });\n const { result } = renderHook(() => useHost());\n\n expect(result.current.name).toBeUndefined();\n expect(result.current.version).toBeUndefined();\n\n await waitFor(() => {\n expect(result.current.name).toBe(\"claude\");\n expect(result.current.version).toBe(\"1.2.3\");\n });\n });\n\n it.each<[string, Host]>([\n [\"chatgpt\", \"chatgpt\"],\n [\"Claude\", \"claude\"],\n [\"Cursor\", \"cursor\"],\n [\"MCP-UI Host\", \"goose\"],\n [\"Le Chat\", \"mistral-vibe\"],\n [\"alpic-playground\", \"alpic\"],\n ])(\"normalizes reported name %j to slug %j\", async (reported, slug) => {\n stubHost({ name: reported, version: \"1.0.0\" });\n const { result } = renderHook(() => useHost());\n\n await waitFor(() => {\n expect(result.current.name).toBe(slug);\n });\n });\n\n it(\"preserves an unrecognized reported name as-is\", async () => {\n stubHost({ name: \"Some Future Host\", version: \"9.9.9\" });\n const { result } = renderHook(() => useHost());\n\n await waitFor(() => {\n expect(result.current.name).toBe(\"Some Future Host\");\n expect(result.current.version).toBe(\"9.9.9\");\n });\n });\n});\n"]}
@@ -1 +1,20 @@
1
- export declare function useOpenExternal(): (href: string) => void;
1
+ import type { OpenExternalOptions } from "../bridges/types.js";
2
+ /** Function that opens a URL outside the view's iframe, returned by {@link useOpenExternal}. */
3
+ export type OpenExternalFn = (href: string, options?: OpenExternalOptions) => void;
4
+ /**
5
+ * Open an external URL through the host (e.g. in the user's browser).
6
+ *
7
+ * Use this instead of `window.open` or anchor `target="_blank"`, which are
8
+ * unreliable inside a sandboxed iframe. Hosts may transform the URL (e.g.
9
+ * ChatGPT appends a `?redirectUrl=…` parameter for allowlisted targets — pass
10
+ * `redirectUrl: false` to suppress it).
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * const openExternal = useOpenExternal();
15
+ * <button onClick={() => openExternal("https://example.com")}>Open docs</button>
16
+ * ```
17
+ *
18
+ * @see https://docs.skybridge.tech/api-reference/use-open-external
19
+ */
20
+ export declare function useOpenExternal(): OpenExternalFn;
@@ -1,8 +1,24 @@
1
1
  import { useCallback } from "react";
2
2
  import { getAdaptor } from "../bridges/index.js";
3
+ /**
4
+ * Open an external URL through the host (e.g. in the user's browser).
5
+ *
6
+ * Use this instead of `window.open` or anchor `target="_blank"`, which are
7
+ * unreliable inside a sandboxed iframe. Hosts may transform the URL (e.g.
8
+ * ChatGPT appends a `?redirectUrl=…` parameter for allowlisted targets — pass
9
+ * `redirectUrl: false` to suppress it).
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * const openExternal = useOpenExternal();
14
+ * <button onClick={() => openExternal("https://example.com")}>Open docs</button>
15
+ * ```
16
+ *
17
+ * @see https://docs.skybridge.tech/api-reference/use-open-external
18
+ */
3
19
  export function useOpenExternal() {
4
20
  const adaptor = getAdaptor();
5
- const openExternal = useCallback((href) => adaptor.openExternal(href), [adaptor]);
21
+ const openExternal = useCallback((href, options) => adaptor.openExternal(href, options), [adaptor]);
6
22
  return openExternal;
7
23
  }
8
24
  //# sourceMappingURL=use-open-external.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-open-external.js","sourceRoot":"","sources":["../../../src/web/hooks/use-open-external.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,EAC5C,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,OAAO,YAAY,CAAC;AACtB,CAAC"}
1
+ {"version":3,"file":"use-open-external.js","sourceRoot":"","sources":["../../../src/web/hooks/use-open-external.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AASjD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,IAAY,EAAE,OAA6B,EAAE,EAAE,CAC9C,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,EACrC,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["import { useCallback } from \"react\";\nimport { getAdaptor } from \"../bridges/index.js\";\nimport type { OpenExternalOptions } from \"../bridges/types.js\";\n\n/** Function that opens a URL outside the view's iframe, returned by {@link useOpenExternal}. */\nexport type OpenExternalFn = (\n href: string,\n options?: OpenExternalOptions,\n) => void;\n\n/**\n * Open an external URL through the host (e.g. in the user's browser).\n *\n * Use this instead of `window.open` or anchor `target=\"_blank\"`, which are\n * unreliable inside a sandboxed iframe. Hosts may transform the URL (e.g.\n * ChatGPT appends a `?redirectUrl=…` parameter for allowlisted targets — pass\n * `redirectUrl: false` to suppress it).\n *\n * @example\n * ```tsx\n * const openExternal = useOpenExternal();\n * <button onClick={() => openExternal(\"https://example.com\")}>Open docs</button>\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/use-open-external\n */\nexport function useOpenExternal(): OpenExternalFn {\n const adaptor = getAdaptor();\n const openExternal = useCallback(\n (href: string, options?: OpenExternalOptions) =>\n adaptor.openExternal(href, options),\n [adaptor],\n );\n\n return openExternal;\n}\n"]}
@@ -1,49 +1,74 @@
1
- import { renderHook } from "@testing-library/react";
1
+ import { renderHook, waitFor } from "@testing-library/react";
2
2
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
+ import { HostAdaptor } from "../bridges/adaptor.js";
3
4
  import { McpAppBridge } from "../bridges/mcp-app/bridge.js";
5
+ import { getMcpAppHostPostMessageMock, MockResizeObserver, } from "./test/utils.js";
4
6
  import { useOpenExternal } from "./use-open-external.js";
5
7
  describe("useOpenExternal", () => {
6
8
  describe("apps-sdk host", () => {
7
9
  let openExternalMock;
10
+ let postMessageMock;
8
11
  beforeEach(() => {
9
12
  openExternalMock = vi.fn();
10
13
  vi.stubGlobal("openai", {
11
14
  openExternal: openExternalMock,
12
15
  });
13
- vi.stubGlobal("skybridge", { hostType: "apps-sdk" });
16
+ vi.stubGlobal("skybridge", {});
17
+ vi.stubGlobal("ResizeObserver", MockResizeObserver);
18
+ postMessageMock = getMcpAppHostPostMessageMock();
19
+ vi.stubGlobal("parent", { postMessage: postMessageMock });
14
20
  });
15
21
  afterEach(() => {
22
+ HostAdaptor.resetInstance();
23
+ McpAppBridge.resetInstance();
16
24
  vi.unstubAllGlobals();
17
25
  vi.resetAllMocks();
18
26
  });
19
- it("should return a function that calls window.openai.openExternal with the href", () => {
27
+ it("should call window.openai.openExternal even without a redirectUrl option", () => {
20
28
  const { result } = renderHook(() => useOpenExternal());
21
29
  const href = "https://example.com";
22
30
  result.current(href);
23
31
  expect(openExternalMock).toHaveBeenCalledTimes(1);
24
32
  expect(openExternalMock).toHaveBeenCalledWith({ href });
33
+ expect(postMessageMock).not.toHaveBeenCalledWith(expect.objectContaining({ method: "ui/open-link" }), "*");
34
+ });
35
+ it("should call window.openai.openExternal when redirectUrl is false", () => {
36
+ const { result } = renderHook(() => useOpenExternal());
37
+ const href = "https://example.com";
38
+ result.current(href, { redirectUrl: false });
39
+ expect(openExternalMock).toHaveBeenCalledTimes(1);
40
+ expect(openExternalMock).toHaveBeenCalledWith({
41
+ href,
42
+ redirectUrl: false,
43
+ });
25
44
  });
26
45
  });
27
46
  describe("mcp-app host", () => {
28
- const mockPostMessage = vi.fn();
47
+ let postMessageMock;
29
48
  beforeEach(() => {
30
- vi.stubGlobal("parent", { postMessage: mockPostMessage });
31
- vi.stubGlobal("skybridge", { hostType: "mcp-app" });
49
+ vi.stubGlobal("openai", undefined);
50
+ vi.stubGlobal("skybridge", {});
51
+ vi.stubGlobal("ResizeObserver", MockResizeObserver);
52
+ postMessageMock = getMcpAppHostPostMessageMock();
53
+ vi.stubGlobal("parent", { postMessage: postMessageMock });
32
54
  });
33
- afterEach(() => {
55
+ afterEach(async () => {
56
+ HostAdaptor.resetInstance();
57
+ McpAppBridge.resetInstance();
34
58
  vi.unstubAllGlobals();
35
59
  vi.resetAllMocks();
36
- McpAppBridge.resetInstance();
37
60
  });
38
- it("should return a function that sends ui/open-link request to the MCP host", () => {
61
+ it("should return a function that sends ui/open-link request to the MCP host", async () => {
39
62
  const { result } = renderHook(() => useOpenExternal());
40
63
  const href = "https://example.com";
41
- result.current(href);
42
- expect(mockPostMessage).toHaveBeenCalledWith(expect.objectContaining({
43
- jsonrpc: "2.0",
44
- method: "ui/open-link",
45
- params: { url: href },
46
- }), "*");
64
+ result.current(href, { redirectUrl: false });
65
+ await waitFor(() => {
66
+ expect(postMessageMock).toHaveBeenCalledWith(expect.objectContaining({
67
+ jsonrpc: "2.0",
68
+ method: "ui/open-link",
69
+ params: { url: href },
70
+ }), "*");
71
+ });
47
72
  });
48
73
  });
49
74
  });
@@ -1 +1 @@
1
- {"version":3,"file":"use-open-external.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-open-external.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,IAAI,gBAA0C,CAAC;QAE/C,UAAU,CAAC,GAAG,EAAE;YACd,gBAAgB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE;gBACtB,YAAY,EAAE,gBAAgB;aAC/B,CAAC,CAAC;YACH,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,SAAS,CAAC,GAAG,EAAE;YACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;YACtB,EAAE,CAAC,aAAa,EAAE,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8EAA8E,EAAE,GAAG,EAAE;YACtF,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,MAAM,IAAI,GAAG,qBAAqB,CAAC;YACnC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAErB,MAAM,CAAC,gBAAgB,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;YAClD,MAAM,CAAC,gBAAgB,CAAC,CAAC,oBAAoB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,MAAM,eAAe,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAEhC,UAAU,CAAC,GAAG,EAAE;YACd,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC,CAAC;YAC1D,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;QAEH,SAAS,CAAC,GAAG,EAAE;YACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;YACtB,EAAE,CAAC,aAAa,EAAE,CAAC;YACnB,YAAY,CAAC,aAAa,EAAE,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;YAClF,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,MAAM,IAAI,GAAG,qBAAqB,CAAC;YACnC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAErB,MAAM,CAAC,eAAe,CAAC,CAAC,oBAAoB,CAC1C,MAAM,CAAC,gBAAgB,CAAC;gBACtB,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,cAAc;gBACtB,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE;aACtB,CAAC,EACF,GAAG,CACJ,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"use-open-external.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-open-external.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { renderHook, waitFor } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { HostAdaptor } from \"../bridges/adaptor.js\";\nimport { McpAppBridge } from \"../bridges/mcp-app/bridge.js\";\nimport {\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"./test/utils.js\";\nimport { useOpenExternal } from \"./use-open-external.js\";\n\ndescribe(\"useOpenExternal\", () => {\n describe(\"apps-sdk host\", () => {\n let openExternalMock: ReturnType<typeof vi.fn>;\n let postMessageMock: ReturnType<typeof getMcpAppHostPostMessageMock>;\n\n beforeEach(() => {\n openExternalMock = vi.fn();\n vi.stubGlobal(\"openai\", {\n openExternal: openExternalMock,\n });\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n postMessageMock = getMcpAppHostPostMessageMock();\n vi.stubGlobal(\"parent\", { postMessage: postMessageMock });\n });\n\n afterEach(() => {\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n });\n\n it(\"should call window.openai.openExternal even without a redirectUrl option\", () => {\n const { result } = renderHook(() => useOpenExternal());\n\n const href = \"https://example.com\";\n result.current(href);\n\n expect(openExternalMock).toHaveBeenCalledTimes(1);\n expect(openExternalMock).toHaveBeenCalledWith({ href });\n expect(postMessageMock).not.toHaveBeenCalledWith(\n expect.objectContaining({ method: \"ui/open-link\" }),\n \"*\",\n );\n });\n\n it(\"should call window.openai.openExternal when redirectUrl is false\", () => {\n const { result } = renderHook(() => useOpenExternal());\n\n const href = \"https://example.com\";\n result.current(href, { redirectUrl: false });\n\n expect(openExternalMock).toHaveBeenCalledTimes(1);\n expect(openExternalMock).toHaveBeenCalledWith({\n href,\n redirectUrl: false,\n });\n });\n });\n\n describe(\"mcp-app host\", () => {\n let postMessageMock: ReturnType<typeof getMcpAppHostPostMessageMock>;\n\n beforeEach(() => {\n vi.stubGlobal(\"openai\", undefined);\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n postMessageMock = getMcpAppHostPostMessageMock();\n vi.stubGlobal(\"parent\", { postMessage: postMessageMock });\n });\n\n afterEach(async () => {\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n });\n\n it(\"should return a function that sends ui/open-link request to the MCP host\", async () => {\n const { result } = renderHook(() => useOpenExternal());\n\n const href = \"https://example.com\";\n result.current(href, { redirectUrl: false });\n\n await waitFor(() => {\n expect(postMessageMock).toHaveBeenCalledWith(\n expect.objectContaining({\n jsonrpc: \"2.0\",\n method: \"ui/open-link\",\n params: { url: href },\n }),\n \"*\",\n );\n });\n });\n });\n});\n"]}
@@ -0,0 +1,37 @@
1
+ import type { ViewToolConfig, ViewToolHandler, ViewToolInputShape } from "../bridges/types.js";
2
+ /**
3
+ * Register a tool the view exposes to the host and model — the MCP Apps
4
+ * "app-provided tools" feature. A view tool runs *inside the view*: the host
5
+ * discovers it via `tools/list` and invokes it via `tools/call`, and the
6
+ * handler executes against the view's live state. It is the inverse of
7
+ * {@link useCallTool} (which calls a server tool). Registered on mount, removed
8
+ * on unmount; re-registered when `config.name` changes.
9
+ *
10
+ * MCP Apps only — on the Apps SDK (`window.openai`) runtime it is a no-op.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * import * as z from "zod";
15
+ * import { useRegisterViewTool } from "skybridge/web";
16
+ *
17
+ * useRegisterViewTool(
18
+ * {
19
+ * name: "chess_make_move",
20
+ * description: "Play a move in algebraic notation, e.g. 'e4' or 'Nf3'.",
21
+ * inputSchema: { san: z.string() },
22
+ * annotations: { readOnlyHint: false },
23
+ * },
24
+ * ({ san }) => {
25
+ * const move = game.move(san);
26
+ * return {
27
+ * content: [{ type: "text", text: move ? `Played ${move.san}` : "Illegal move" }],
28
+ * structuredContent: { fen: game.fen() },
29
+ * isError: !move,
30
+ * };
31
+ * },
32
+ * );
33
+ * ```
34
+ *
35
+ * @see https://docs.skybridge.tech/api-reference/use-register-view-tool
36
+ */
37
+ export declare const useRegisterViewTool: <TInput extends ViewToolInputShape = ViewToolInputShape>(config: ViewToolConfig<TInput>, handler: ViewToolHandler<TInput>) => void;
@@ -0,0 +1,50 @@
1
+ import { useEffect, useRef } from "react";
2
+ import { getAdaptor } from "../bridges/index.js";
3
+ /**
4
+ * Register a tool the view exposes to the host and model — the MCP Apps
5
+ * "app-provided tools" feature. A view tool runs *inside the view*: the host
6
+ * discovers it via `tools/list` and invokes it via `tools/call`, and the
7
+ * handler executes against the view's live state. It is the inverse of
8
+ * {@link useCallTool} (which calls a server tool). Registered on mount, removed
9
+ * on unmount; re-registered when `config.name` changes.
10
+ *
11
+ * MCP Apps only — on the Apps SDK (`window.openai`) runtime it is a no-op.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * import * as z from "zod";
16
+ * import { useRegisterViewTool } from "skybridge/web";
17
+ *
18
+ * useRegisterViewTool(
19
+ * {
20
+ * name: "chess_make_move",
21
+ * description: "Play a move in algebraic notation, e.g. 'e4' or 'Nf3'.",
22
+ * inputSchema: { san: z.string() },
23
+ * annotations: { readOnlyHint: false },
24
+ * },
25
+ * ({ san }) => {
26
+ * const move = game.move(san);
27
+ * return {
28
+ * content: [{ type: "text", text: move ? `Played ${move.san}` : "Illegal move" }],
29
+ * structuredContent: { fen: game.fen() },
30
+ * isError: !move,
31
+ * };
32
+ * },
33
+ * );
34
+ * ```
35
+ *
36
+ * @see https://docs.skybridge.tech/api-reference/use-register-view-tool
37
+ */
38
+ export const useRegisterViewTool = (config, handler) => {
39
+ const { name } = config;
40
+ const configRef = useRef(config);
41
+ configRef.current = config;
42
+ const handlerRef = useRef(handler);
43
+ handlerRef.current = handler;
44
+ useEffect(() => {
45
+ const adaptor = getAdaptor();
46
+ const wrappedHandler = (args) => handlerRef.current(args);
47
+ return adaptor.registerViewTool({ ...configRef.current, name }, wrappedHandler);
48
+ }, [name]);
49
+ };
50
+ //# sourceMappingURL=use-register-view-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-register-view-tool.js","sourceRoot":"","sources":["../../../src/web/hooks/use-register-view-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAQjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAGjC,MAA8B,EAC9B,OAAgC,EAChC,EAAE;IACF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC;IACxB,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC;IAC3B,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC;IAE7B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAC7B,MAAM,cAAc,GAAuB,CAAC,IAAI,EAAE,EAAE,CAClD,UAAU,CAAC,OAAO,CAAC,IAA8C,CAAC,CAAC;QAErE,OAAO,OAAO,CAAC,gBAAgB,CAC7B,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,EAC9B,cAAc,CACf,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AACb,CAAC,CAAC","sourcesContent":["import { useEffect, useRef } from \"react\";\nimport { getAdaptor } from \"../bridges/index.js\";\nimport type {\n AnyViewToolHandler,\n ViewToolConfig,\n ViewToolHandler,\n ViewToolInputShape,\n} from \"../bridges/types.js\";\n\n/**\n * Register a tool the view exposes to the host and model — the MCP Apps\n * \"app-provided tools\" feature. A view tool runs *inside the view*: the host\n * discovers it via `tools/list` and invokes it via `tools/call`, and the\n * handler executes against the view's live state. It is the inverse of\n * {@link useCallTool} (which calls a server tool). Registered on mount, removed\n * on unmount; re-registered when `config.name` changes.\n *\n * MCP Apps only — on the Apps SDK (`window.openai`) runtime it is a no-op.\n *\n * @example\n * ```tsx\n * import * as z from \"zod\";\n * import { useRegisterViewTool } from \"skybridge/web\";\n *\n * useRegisterViewTool(\n * {\n * name: \"chess_make_move\",\n * description: \"Play a move in algebraic notation, e.g. 'e4' or 'Nf3'.\",\n * inputSchema: { san: z.string() },\n * annotations: { readOnlyHint: false },\n * },\n * ({ san }) => {\n * const move = game.move(san);\n * return {\n * content: [{ type: \"text\", text: move ? `Played ${move.san}` : \"Illegal move\" }],\n * structuredContent: { fen: game.fen() },\n * isError: !move,\n * };\n * },\n * );\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/use-register-view-tool\n */\nexport const useRegisterViewTool = <\n TInput extends ViewToolInputShape = ViewToolInputShape,\n>(\n config: ViewToolConfig<TInput>,\n handler: ViewToolHandler<TInput>,\n) => {\n const { name } = config;\n const configRef = useRef(config);\n configRef.current = config;\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n useEffect(() => {\n const adaptor = getAdaptor();\n const wrappedHandler: AnyViewToolHandler = (args) =>\n handlerRef.current(args as Parameters<ViewToolHandler<TInput>>[0]);\n\n return adaptor.registerViewTool(\n { ...configRef.current, name },\n wrappedHandler,\n );\n }, [name]);\n};\n"]}
@@ -0,0 +1,16 @@
1
+ /** Function that asks the host to close the current view, returned by {@link useRequestClose}. */
2
+ export type RequestCloseFn = () => Promise<void>;
3
+ /**
4
+ * Ask the host to close (dismiss) the current view. The host decides whether
5
+ * to honor the request. Useful from modal views or after a terminal action
6
+ * like "Done".
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * const close = useRequestClose();
11
+ * <button onClick={() => close()}>Done</button>
12
+ * ```
13
+ *
14
+ * @see https://docs.skybridge.tech/api-reference/use-request-close
15
+ */
16
+ export declare function useRequestClose(): RequestCloseFn;
@@ -0,0 +1,21 @@
1
+ import { useCallback } from "react";
2
+ import { getAdaptor } from "../bridges/index.js";
3
+ /**
4
+ * Ask the host to close (dismiss) the current view. The host decides whether
5
+ * to honor the request. Useful from modal views or after a terminal action
6
+ * like "Done".
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * const close = useRequestClose();
11
+ * <button onClick={() => close()}>Done</button>
12
+ * ```
13
+ *
14
+ * @see https://docs.skybridge.tech/api-reference/use-request-close
15
+ */
16
+ export function useRequestClose() {
17
+ const adaptor = getAdaptor();
18
+ const requestClose = useCallback(() => adaptor.requestClose(), [adaptor]);
19
+ return requestClose;
20
+ }
21
+ //# sourceMappingURL=use-request-close.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-request-close.js","sourceRoot":"","sources":["../../../src/web/hooks/use-request-close.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAKjD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAE1E,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["import { useCallback } from \"react\";\nimport { getAdaptor } from \"../bridges/index.js\";\n\n/** Function that asks the host to close the current view, returned by {@link useRequestClose}. */\nexport type RequestCloseFn = () => Promise<void>;\n\n/**\n * Ask the host to close (dismiss) the current view. The host decides whether\n * to honor the request. Useful from modal views or after a terminal action\n * like \"Done\".\n *\n * @example\n * ```tsx\n * const close = useRequestClose();\n * <button onClick={() => close()}>Done</button>\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/use-request-close\n */\nexport function useRequestClose(): RequestCloseFn {\n const adaptor = getAdaptor();\n const requestClose = useCallback(() => adaptor.requestClose(), [adaptor]);\n\n return requestClose;\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,47 @@
1
+ import { act, renderHook } from "@testing-library/react";
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
+ import { HostAdaptor } from "../bridges/adaptor.js";
4
+ import { getAdaptor } from "../bridges/get-adaptor.js";
5
+ import { McpAppBridge } from "../bridges/mcp-app/bridge.js";
6
+ import { useRequestClose } from "./use-request-close.js";
7
+ describe("useRequestClose", () => {
8
+ beforeEach(() => {
9
+ HostAdaptor.resetInstance();
10
+ McpAppBridge.resetInstance();
11
+ vi.stubGlobal("skybridge", {});
12
+ vi.stubGlobal("openai", undefined);
13
+ vi.stubGlobal("parent", { postMessage: vi.fn() });
14
+ });
15
+ afterEach(() => {
16
+ vi.unstubAllGlobals();
17
+ vi.resetAllMocks();
18
+ HostAdaptor.resetInstance();
19
+ McpAppBridge.resetInstance();
20
+ });
21
+ it("calls app.requestTeardown via the MCP path", async () => {
22
+ const requestTeardown = vi.fn().mockResolvedValue(undefined);
23
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
24
+ const adaptor = getAdaptor();
25
+ adaptor.mcp.getApp = vi.fn().mockResolvedValue({ requestTeardown });
26
+ const { result } = renderHook(() => useRequestClose());
27
+ await act(async () => {
28
+ await result.current();
29
+ });
30
+ expect(requestTeardown).toHaveBeenCalledTimes(1);
31
+ });
32
+ it("calls app.requestTeardown even when window.openai is present", async () => {
33
+ vi.stubGlobal("openai", { requestClose: vi.fn() });
34
+ HostAdaptor.resetInstance();
35
+ McpAppBridge.resetInstance();
36
+ const requestTeardown = vi.fn().mockResolvedValue(undefined);
37
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
38
+ const adaptor = getAdaptor();
39
+ adaptor.mcp.getApp = vi.fn().mockResolvedValue({ requestTeardown });
40
+ const { result } = renderHook(() => useRequestClose());
41
+ await act(async () => {
42
+ await result.current();
43
+ });
44
+ expect(requestTeardown).toHaveBeenCalledTimes(1);
45
+ });
46
+ });
47
+ //# sourceMappingURL=use-request-close.test.js.map