skybridge 0.0.0-dev.f561bc3 → 0.0.0-dev.f57f202

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 (656) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +155 -0
  3. package/bin/run.js +5 -0
  4. package/dist/cli/build-helpers.d.ts +11 -0
  5. package/dist/cli/build-helpers.js +107 -0
  6. package/dist/cli/build-helpers.js.map +1 -0
  7. package/dist/cli/build-helpers.test.js +132 -0
  8. package/dist/cli/build-helpers.test.js.map +1 -0
  9. package/dist/cli/build-steps.d.ts +2 -0
  10. package/dist/cli/build-steps.js +73 -0
  11. package/dist/cli/build-steps.js.map +1 -0
  12. package/dist/cli/build-steps.test.js +52 -0
  13. package/dist/cli/build-steps.test.js.map +1 -0
  14. package/dist/cli/detect-port.d.ts +18 -0
  15. package/dist/cli/detect-port.js +49 -0
  16. package/dist/cli/detect-port.js.map +1 -0
  17. package/dist/cli/header.d.ts +4 -0
  18. package/dist/cli/header.js +6 -0
  19. package/dist/cli/header.js.map +1 -0
  20. package/dist/cli/resolve-skybridge-config.d.ts +5 -0
  21. package/dist/cli/resolve-skybridge-config.js +18 -0
  22. package/dist/cli/resolve-skybridge-config.js.map +1 -0
  23. package/dist/cli/run-command.d.ts +2 -0
  24. package/dist/cli/run-command.js +43 -0
  25. package/dist/cli/run-command.js.map +1 -0
  26. package/dist/cli/run-plain.d.ts +18 -0
  27. package/dist/cli/run-plain.js +90 -0
  28. package/dist/cli/run-plain.js.map +1 -0
  29. package/dist/cli/telemetry.d.ts +7 -0
  30. package/dist/cli/telemetry.js +125 -0
  31. package/dist/cli/telemetry.js.map +1 -0
  32. package/dist/cli/tunnel-control-server.d.ts +9 -0
  33. package/dist/cli/tunnel-control-server.js +31 -0
  34. package/dist/cli/tunnel-control-server.js.map +1 -0
  35. package/dist/cli/tunnel-control-server.test.js +39 -0
  36. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  37. package/dist/cli/tunnel-handler.d.ts +3 -0
  38. package/dist/cli/tunnel-handler.js +48 -0
  39. package/dist/cli/tunnel-handler.js.map +1 -0
  40. package/dist/cli/tunnel-handler.test.js +105 -0
  41. package/dist/cli/tunnel-handler.test.js.map +1 -0
  42. package/dist/cli/tunnel.d.ts +57 -0
  43. package/dist/cli/tunnel.js +154 -0
  44. package/dist/cli/tunnel.js.map +1 -0
  45. package/dist/cli/tunnel.test.js +190 -0
  46. package/dist/cli/tunnel.test.js.map +1 -0
  47. package/dist/cli/types.d.ts +5 -0
  48. package/dist/cli/types.js.map +1 -0
  49. package/dist/cli/use-execute-steps.d.ts +11 -0
  50. package/dist/cli/use-execute-steps.js +36 -0
  51. package/dist/cli/use-execute-steps.js.map +1 -0
  52. package/dist/cli/use-messages.d.ts +3 -0
  53. package/dist/cli/use-messages.js +11 -0
  54. package/dist/cli/use-messages.js.map +1 -0
  55. package/dist/cli/use-nodemon.d.ts +26 -0
  56. package/dist/cli/use-nodemon.js +106 -0
  57. package/dist/cli/use-nodemon.js.map +1 -0
  58. package/dist/cli/use-open-browser.d.ts +1 -0
  59. package/dist/cli/use-open-browser.js +44 -0
  60. package/dist/cli/use-open-browser.js.map +1 -0
  61. package/dist/cli/use-tunnel.d.ts +14 -0
  62. package/dist/cli/use-tunnel.js +131 -0
  63. package/dist/cli/use-tunnel.js.map +1 -0
  64. package/dist/cli/use-typescript-check.d.ts +15 -0
  65. package/dist/cli/use-typescript-check.js +97 -0
  66. package/dist/cli/use-typescript-check.js.map +1 -0
  67. package/dist/commands/build.d.ts +6 -0
  68. package/dist/commands/build.js +31 -0
  69. package/dist/commands/build.js.map +1 -0
  70. package/dist/commands/create.d.ts +9 -0
  71. package/dist/commands/create.js +30 -0
  72. package/dist/commands/create.js.map +1 -0
  73. package/dist/commands/dev.d.ts +13 -0
  74. package/dist/commands/dev.js +128 -0
  75. package/dist/commands/dev.js.map +1 -0
  76. package/dist/commands/start.d.ts +9 -0
  77. package/dist/commands/start.js +55 -0
  78. package/dist/commands/start.js.map +1 -0
  79. package/dist/commands/telemetry/disable.d.ts +5 -0
  80. package/dist/commands/telemetry/disable.js +14 -0
  81. package/dist/commands/telemetry/disable.js.map +1 -0
  82. package/dist/commands/telemetry/enable.d.ts +5 -0
  83. package/dist/commands/telemetry/enable.js +14 -0
  84. package/dist/commands/telemetry/enable.js.map +1 -0
  85. package/dist/commands/telemetry/status.d.ts +5 -0
  86. package/dist/commands/telemetry/status.js +14 -0
  87. package/dist/commands/telemetry/status.js.map +1 -0
  88. package/dist/context-warnings.d.ts +5 -0
  89. package/dist/context-warnings.js +31 -0
  90. package/dist/context-warnings.js.map +1 -0
  91. package/dist/context-warnings.test.js +28 -0
  92. package/dist/context-warnings.test.js.map +1 -0
  93. package/dist/server/app.d.ts +194 -0
  94. package/dist/server/app.js +266 -0
  95. package/dist/server/app.js.map +1 -0
  96. package/dist/server/app.test.js +97 -0
  97. package/dist/server/app.test.js.map +1 -0
  98. package/dist/server/asset-base-url-transform-plugin.d.ts +11 -0
  99. package/dist/server/asset-base-url-transform-plugin.js +48 -0
  100. package/dist/server/asset-base-url-transform-plugin.js.map +1 -0
  101. package/dist/server/asset-base-url-transform-plugin.test.js +134 -0
  102. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -0
  103. package/dist/server/auth/discovery.d.ts +33 -0
  104. package/dist/server/auth/discovery.js +56 -0
  105. package/dist/server/auth/discovery.js.map +1 -0
  106. package/dist/server/auth/discovery.test.js +93 -0
  107. package/dist/server/auth/discovery.test.js.map +1 -0
  108. package/dist/server/auth/index.d.ts +48 -0
  109. package/dist/server/auth/index.js +2 -0
  110. package/dist/server/auth/index.js.map +1 -0
  111. package/dist/server/auth/providers/auth0.d.ts +40 -0
  112. package/dist/server/auth/providers/auth0.js +36 -0
  113. package/dist/server/auth/providers/auth0.js.map +1 -0
  114. package/dist/server/auth/providers/auth0.test.js +50 -0
  115. package/dist/server/auth/providers/auth0.test.js.map +1 -0
  116. package/dist/server/auth/providers/authplane.d.ts +49 -0
  117. package/dist/server/auth/providers/authplane.js +57 -0
  118. package/dist/server/auth/providers/authplane.js.map +1 -0
  119. package/dist/server/auth/providers/authplane.test.js +143 -0
  120. package/dist/server/auth/providers/authplane.test.js.map +1 -0
  121. package/dist/server/auth/providers/clerk.d.ts +51 -0
  122. package/dist/server/auth/providers/clerk.js +19 -0
  123. package/dist/server/auth/providers/clerk.js.map +1 -0
  124. package/dist/server/auth/providers/clerk.test.js +30 -0
  125. package/dist/server/auth/providers/clerk.test.js.map +1 -0
  126. package/dist/server/auth/providers/custom.d.ts +42 -0
  127. package/dist/server/auth/providers/custom.js +59 -0
  128. package/dist/server/auth/providers/custom.js.map +1 -0
  129. package/dist/server/auth/providers/custom.test.js +161 -0
  130. package/dist/server/auth/providers/custom.test.js.map +1 -0
  131. package/dist/server/auth/providers/descope.d.ts +44 -0
  132. package/dist/server/auth/providers/descope.js +44 -0
  133. package/dist/server/auth/providers/descope.js.map +1 -0
  134. package/dist/server/auth/providers/descope.test.js +62 -0
  135. package/dist/server/auth/providers/descope.test.js.map +1 -0
  136. package/dist/server/auth/providers/shared.d.ts +2 -0
  137. package/dist/server/auth/providers/shared.js +6 -0
  138. package/dist/server/auth/providers/shared.js.map +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.js +99 -0
  154. package/dist/server/auth/security-schemes.test.js.map +1 -0
  155. package/dist/server/auth/setup.d.ts +6 -0
  156. package/dist/server/auth/setup.js +91 -0
  157. package/dist/server/auth/setup.js.map +1 -0
  158. package/dist/server/auth/setup.test.js +514 -0
  159. package/dist/server/auth/setup.test.js.map +1 -0
  160. package/dist/server/auth/verify.d.ts +48 -0
  161. package/dist/server/auth/verify.js +62 -0
  162. package/dist/server/auth/verify.js.map +1 -0
  163. package/dist/server/auth/verify.test.js +165 -0
  164. package/dist/server/auth/verify.test.js.map +1 -0
  165. package/dist/server/auth-extra.test-d.js +130 -0
  166. package/dist/server/auth-extra.test-d.js.map +1 -0
  167. package/dist/server/auth.d.ts +57 -0
  168. package/dist/server/auth.js +27 -0
  169. package/dist/server/auth.js.map +1 -0
  170. package/dist/server/build-manifest.test.js +28 -0
  171. package/dist/server/build-manifest.test.js.map +1 -0
  172. package/dist/server/content-helpers.d.ts +67 -0
  173. package/dist/server/content-helpers.js +79 -0
  174. package/dist/server/content-helpers.js.map +1 -0
  175. package/dist/server/content-helpers.test.d.ts +1 -0
  176. package/dist/server/content-helpers.test.js +70 -0
  177. package/dist/server/content-helpers.test.js.map +1 -0
  178. package/dist/server/express.d.ts +31 -0
  179. package/dist/server/express.js +107 -0
  180. package/dist/server/express.js.map +1 -0
  181. package/dist/server/express.test.d.ts +1 -0
  182. package/dist/server/express.test.js +608 -0
  183. package/dist/server/express.test.js.map +1 -0
  184. package/dist/server/file-ref.d.ts +28 -0
  185. package/dist/server/file-ref.js +27 -0
  186. package/dist/server/file-ref.js.map +1 -0
  187. package/dist/server/host.d.ts +2 -0
  188. package/dist/server/host.js +11 -0
  189. package/dist/server/host.js.map +1 -0
  190. package/dist/server/host.test.d.ts +1 -0
  191. package/dist/server/host.test.js +13 -0
  192. package/dist/server/host.test.js.map +1 -0
  193. package/dist/server/index.d.ts +22 -0
  194. package/dist/server/index.js +18 -0
  195. package/dist/server/index.js.map +1 -0
  196. package/dist/{src/server → server}/inferUtilityTypes.d.ts +6 -6
  197. package/dist/server/inferUtilityTypes.js.map +1 -0
  198. package/dist/server/mcp-errors.test.d.ts +1 -0
  199. package/dist/server/mcp-errors.test.js +41 -0
  200. package/dist/server/mcp-errors.test.js.map +1 -0
  201. package/dist/server/metric.d.ts +14 -0
  202. package/dist/server/metric.js +62 -0
  203. package/dist/server/metric.js.map +1 -0
  204. package/dist/server/middleware.d.ts +162 -0
  205. package/dist/server/middleware.js +126 -0
  206. package/dist/server/middleware.js.map +1 -0
  207. package/dist/server/middleware.test-d.d.ts +1 -0
  208. package/dist/server/middleware.test-d.js +75 -0
  209. package/dist/server/middleware.test-d.js.map +1 -0
  210. package/dist/server/middleware.test.d.ts +1 -0
  211. package/dist/server/middleware.test.js +601 -0
  212. package/dist/server/middleware.test.js.map +1 -0
  213. package/dist/server/register-tool.test.d.ts +1 -0
  214. package/dist/server/register-tool.test.js +77 -0
  215. package/dist/server/register-tool.test.js.map +1 -0
  216. package/dist/server/requestOrigin.d.ts +7 -0
  217. package/dist/server/requestOrigin.js +25 -0
  218. package/dist/server/requestOrigin.js.map +1 -0
  219. package/dist/server/server.d.ts +496 -0
  220. package/dist/server/server.js +591 -0
  221. package/dist/server/server.js.map +1 -0
  222. package/dist/server/skills-integration.test.d.ts +1 -0
  223. package/dist/server/skills-integration.test.js +86 -0
  224. package/dist/server/skills-integration.test.js.map +1 -0
  225. package/dist/server/skills.d.ts +27 -0
  226. package/dist/server/skills.js +188 -0
  227. package/dist/server/skills.js.map +1 -0
  228. package/dist/server/skills.test.d.ts +1 -0
  229. package/dist/server/skills.test.js +243 -0
  230. package/dist/server/skills.test.js.map +1 -0
  231. package/dist/{src/server → server}/templateHelper.d.ts +2 -7
  232. package/dist/server/templateHelper.js +11 -0
  233. package/dist/server/templateHelper.js.map +1 -0
  234. package/dist/server/templates.generated.d.ts +4 -0
  235. package/dist/server/templates.generated.js +43 -0
  236. package/dist/server/templates.generated.js.map +1 -0
  237. package/dist/server/tool-extra.test.d.ts +1 -0
  238. package/dist/server/tool-extra.test.js +88 -0
  239. package/dist/server/tool-extra.test.js.map +1 -0
  240. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  241. package/dist/server/tunnel-proxy-router.js +110 -0
  242. package/dist/server/tunnel-proxy-router.js.map +1 -0
  243. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  244. package/dist/server/tunnel-proxy-router.test.js +229 -0
  245. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  246. package/dist/server/view-name.test-d.d.ts +1 -0
  247. package/dist/server/view-name.test-d.js +8 -0
  248. package/dist/server/view-name.test-d.js.map +1 -0
  249. package/dist/server/view-resource-resolution.test.d.ts +6 -0
  250. package/dist/server/view-resource-resolution.test.js +176 -0
  251. package/dist/server/view-resource-resolution.test.js.map +1 -0
  252. package/dist/server/viewsDevServer.d.ts +14 -0
  253. package/dist/server/viewsDevServer.js +48 -0
  254. package/dist/server/viewsDevServer.js.map +1 -0
  255. package/dist/{src/test → test}/utils.d.ts +21 -31
  256. package/dist/test/utils.js +266 -0
  257. package/dist/test/utils.js.map +1 -0
  258. package/dist/test/view.test.d.ts +1 -0
  259. package/dist/test/view.test.js +540 -0
  260. package/dist/test/view.test.js.map +1 -0
  261. package/dist/version.d.ts +1 -0
  262. package/dist/version.js +3 -0
  263. package/dist/version.js.map +1 -0
  264. package/dist/views/index.d.ts +10 -0
  265. package/dist/views/index.js +3 -0
  266. package/dist/views/index.js.map +1 -0
  267. package/dist/views/scan-views.d.ts +16 -0
  268. package/dist/views/scan-views.js +88 -0
  269. package/dist/views/scan-views.js.map +1 -0
  270. package/dist/views/scan-views.test.d.ts +1 -0
  271. package/dist/views/scan-views.test.js +99 -0
  272. package/dist/views/scan-views.test.js.map +1 -0
  273. package/dist/views/validate-view.d.ts +1 -0
  274. package/dist/views/validate-view.js +9 -0
  275. package/dist/views/validate-view.js.map +1 -0
  276. package/dist/views/validate-view.test.d.ts +1 -0
  277. package/dist/views/validate-view.test.js +24 -0
  278. package/dist/views/validate-view.test.js.map +1 -0
  279. package/dist/web/bridges/adaptor.d.ts +55 -0
  280. package/dist/web/bridges/adaptor.js +377 -0
  281. package/dist/web/bridges/adaptor.js.map +1 -0
  282. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  283. package/dist/web/bridges/adaptor.test.js +231 -0
  284. package/dist/web/bridges/adaptor.test.js.map +1 -0
  285. package/dist/web/bridges/apps-sdk/bridge.d.ts +15 -0
  286. package/dist/web/bridges/apps-sdk/bridge.js +58 -0
  287. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -0
  288. package/dist/web/bridges/apps-sdk/index.d.ts +4 -0
  289. package/dist/web/bridges/apps-sdk/index.js +4 -0
  290. package/dist/web/bridges/apps-sdk/index.js.map +1 -0
  291. package/dist/web/bridges/apps-sdk/types.d.ts +133 -0
  292. package/dist/{src/web → web/bridges/apps-sdk}/types.js +0 -1
  293. package/dist/web/bridges/apps-sdk/types.js.map +1 -0
  294. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +13 -0
  295. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +18 -0
  296. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -0
  297. package/dist/web/bridges/get-adaptor.d.ts +9 -0
  298. package/dist/web/bridges/get-adaptor.js +10 -0
  299. package/dist/web/bridges/get-adaptor.js.map +1 -0
  300. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  301. package/dist/web/bridges/get-adaptor.test.js +32 -0
  302. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  303. package/dist/web/bridges/index.d.ts +5 -0
  304. package/dist/web/bridges/index.js +6 -0
  305. package/dist/web/bridges/index.js.map +1 -0
  306. package/dist/web/bridges/mcp-app/bridge.d.ts +39 -0
  307. package/dist/web/bridges/mcp-app/bridge.js +175 -0
  308. package/dist/web/bridges/mcp-app/bridge.js.map +1 -0
  309. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  310. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  311. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  312. package/dist/web/bridges/mcp-app/index.d.ts +3 -0
  313. package/dist/web/bridges/mcp-app/index.js +3 -0
  314. package/dist/web/bridges/mcp-app/index.js.map +1 -0
  315. package/dist/web/bridges/mcp-app/types.d.ts +33 -0
  316. package/dist/web/bridges/mcp-app/types.js.map +1 -0
  317. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +19 -0
  318. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +19 -0
  319. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -0
  320. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.d.ts +1 -0
  321. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +26 -0
  322. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -0
  323. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  324. package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
  325. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  326. package/dist/web/bridges/types.d.ts +233 -0
  327. package/dist/web/bridges/types.js +15 -0
  328. package/dist/web/bridges/types.js.map +1 -0
  329. package/dist/web/bridges/types.test.d.ts +1 -0
  330. package/dist/web/bridges/types.test.js +19 -0
  331. package/dist/web/bridges/types.test.js.map +1 -0
  332. package/dist/web/bridges/use-host-context.d.ts +7 -0
  333. package/dist/web/bridges/use-host-context.js +13 -0
  334. package/dist/web/bridges/use-host-context.js.map +1 -0
  335. package/dist/web/components/modal-provider.d.ts +4 -0
  336. package/dist/web/components/modal-provider.js +46 -0
  337. package/dist/web/components/modal-provider.js.map +1 -0
  338. package/dist/web/create-store.d.ts +29 -0
  339. package/dist/web/create-store.js +64 -0
  340. package/dist/web/create-store.js.map +1 -0
  341. package/dist/web/create-store.test.d.ts +1 -0
  342. package/dist/web/create-store.test.js +132 -0
  343. package/dist/web/create-store.test.js.map +1 -0
  344. package/dist/web/data-llm.d.ts +47 -0
  345. package/dist/{src/web → web}/data-llm.js +42 -9
  346. package/dist/web/data-llm.js.map +1 -0
  347. package/dist/web/data-llm.test.d.ts +1 -0
  348. package/dist/web/data-llm.test.js +161 -0
  349. package/dist/web/data-llm.test.js.map +1 -0
  350. package/dist/{src/web → web}/generate-helpers.d.ts +41 -32
  351. package/dist/{src/web → web}/generate-helpers.js +38 -30
  352. package/dist/web/generate-helpers.js.map +1 -0
  353. package/dist/web/generate-helpers.test-d.d.ts +1 -0
  354. package/dist/{src/web → web}/generate-helpers.test-d.js +35 -30
  355. package/dist/web/generate-helpers.test-d.js.map +1 -0
  356. package/dist/web/generate-helpers.test.d.ts +1 -0
  357. package/dist/{src/web → web}/generate-helpers.test.js +2 -2
  358. package/dist/web/generate-helpers.test.js.map +1 -0
  359. package/dist/{src/web → web}/helpers/state.d.ts +2 -2
  360. package/dist/web/helpers/state.js +45 -0
  361. package/dist/web/helpers/state.js.map +1 -0
  362. package/dist/web/helpers/state.test.d.ts +1 -0
  363. package/dist/{src/web → web}/helpers/state.test.js +9 -9
  364. package/dist/web/helpers/state.test.js.map +1 -0
  365. package/dist/web/hooks/index.d.ts +18 -0
  366. package/dist/web/hooks/index.js +19 -0
  367. package/dist/web/hooks/index.js.map +1 -0
  368. package/dist/web/hooks/openai-extensions.test.d.ts +1 -0
  369. package/dist/web/hooks/openai-extensions.test.js +114 -0
  370. package/dist/web/hooks/openai-extensions.test.js.map +1 -0
  371. package/dist/web/hooks/test/utils.d.ts +21 -0
  372. package/dist/web/hooks/test/utils.js +75 -0
  373. package/dist/web/hooks/test/utils.js.map +1 -0
  374. package/dist/{src/web → web}/hooks/use-call-tool.d.ts +48 -2
  375. package/dist/web/hooks/use-call-tool.js +101 -0
  376. package/dist/web/hooks/use-call-tool.js.map +1 -0
  377. package/dist/web/hooks/use-call-tool.test-d.d.ts +1 -0
  378. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -0
  379. package/dist/web/hooks/use-call-tool.test.d.ts +1 -0
  380. package/dist/{src/web → web}/hooks/use-call-tool.test.js +91 -24
  381. package/dist/web/hooks/use-call-tool.test.js.map +1 -0
  382. package/dist/web/hooks/use-deep-link.d.ts +22 -0
  383. package/dist/web/hooks/use-deep-link.js +60 -0
  384. package/dist/web/hooks/use-deep-link.js.map +1 -0
  385. package/dist/web/hooks/use-display-mode.d.ts +24 -0
  386. package/dist/web/hooks/use-display-mode.js +29 -0
  387. package/dist/web/hooks/use-display-mode.js.map +1 -0
  388. package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
  389. package/dist/web/hooks/use-display-mode.test-d.js +8 -0
  390. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
  391. package/dist/web/hooks/use-display-mode.test.d.ts +1 -0
  392. package/dist/web/hooks/use-display-mode.test.js +77 -0
  393. package/dist/web/hooks/use-display-mode.test.js.map +1 -0
  394. package/dist/web/hooks/use-download.d.ts +3 -0
  395. package/dist/web/hooks/use-download.js +7 -0
  396. package/dist/web/hooks/use-download.js.map +1 -0
  397. package/dist/web/hooks/use-download.test.d.ts +1 -0
  398. package/dist/web/hooks/use-download.test.js +103 -0
  399. package/dist/web/hooks/use-download.test.js.map +1 -0
  400. package/dist/web/hooks/use-files.d.ts +39 -0
  401. package/dist/web/hooks/use-files.js +42 -0
  402. package/dist/web/hooks/use-files.js.map +1 -0
  403. package/dist/web/hooks/use-files.test.d.ts +1 -0
  404. package/dist/web/hooks/use-files.test.js +62 -0
  405. package/dist/web/hooks/use-files.test.js.map +1 -0
  406. package/dist/web/hooks/use-host.d.ts +44 -0
  407. package/dist/web/hooks/use-host.js +45 -0
  408. package/dist/web/hooks/use-host.js.map +1 -0
  409. package/dist/web/hooks/use-host.test.d.ts +1 -0
  410. package/dist/web/hooks/use-host.test.js +59 -0
  411. package/dist/web/hooks/use-host.test.js.map +1 -0
  412. package/dist/web/hooks/use-model-context.d.ts +44 -0
  413. package/dist/web/hooks/use-model-context.js +65 -0
  414. package/dist/web/hooks/use-model-context.js.map +1 -0
  415. package/dist/web/hooks/use-open-external.d.ts +20 -0
  416. package/dist/web/hooks/use-open-external.js +24 -0
  417. package/dist/web/hooks/use-open-external.js.map +1 -0
  418. package/dist/web/hooks/use-open-external.test.d.ts +1 -0
  419. package/dist/web/hooks/use-open-external.test.js +75 -0
  420. package/dist/web/hooks/use-open-external.test.js.map +1 -0
  421. package/dist/web/hooks/use-register-view-tool.d.ts +37 -0
  422. package/dist/web/hooks/use-register-view-tool.js +50 -0
  423. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  424. package/dist/web/hooks/use-request-close.d.ts +16 -0
  425. package/dist/web/hooks/use-request-close.js +21 -0
  426. package/dist/web/hooks/use-request-close.js.map +1 -0
  427. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  428. package/dist/web/hooks/use-request-close.test.js +47 -0
  429. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  430. package/dist/web/hooks/use-request-modal.d.ts +24 -0
  431. package/dist/web/hooks/use-request-modal.js +31 -0
  432. package/dist/web/hooks/use-request-modal.js.map +1 -0
  433. package/dist/web/hooks/use-request-modal.test.d.ts +1 -0
  434. package/dist/{src/web → web}/hooks/use-request-modal.test.js +16 -2
  435. package/dist/web/hooks/use-request-modal.test.js.map +1 -0
  436. package/dist/web/hooks/use-request-size.d.ts +20 -0
  437. package/dist/web/hooks/use-request-size.js +24 -0
  438. package/dist/web/hooks/use-request-size.js.map +1 -0
  439. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  440. package/dist/web/hooks/use-request-size.test.js +47 -0
  441. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  442. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -0
  443. package/dist/web/hooks/use-send-follow-up-message.js +25 -0
  444. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -0
  445. package/dist/web/hooks/use-set-open-in-app-url.d.ts +18 -0
  446. package/dist/web/hooks/use-set-open-in-app-url.js +25 -0
  447. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -0
  448. package/dist/web/hooks/use-set-open-in-app-url.test.d.ts +1 -0
  449. package/dist/web/hooks/use-set-open-in-app-url.test.js +57 -0
  450. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -0
  451. package/dist/web/hooks/use-tool-info.d.ts +68 -0
  452. package/dist/web/hooks/use-tool-info.js +48 -0
  453. package/dist/web/hooks/use-tool-info.js.map +1 -0
  454. package/dist/web/hooks/use-tool-info.test-d.d.ts +1 -0
  455. package/dist/{src/web → web}/hooks/use-tool-info.test-d.js +19 -6
  456. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -0
  457. package/dist/web/hooks/use-tool-info.test.d.ts +1 -0
  458. package/dist/web/hooks/use-tool-info.test.js +135 -0
  459. package/dist/web/hooks/use-tool-info.test.js.map +1 -0
  460. package/dist/{src/web → web}/hooks/use-user.d.ts +5 -2
  461. package/dist/web/hooks/use-user.js +38 -0
  462. package/dist/web/hooks/use-user.js.map +1 -0
  463. package/dist/web/hooks/use-user.test.d.ts +1 -0
  464. package/dist/web/hooks/use-user.test.js +170 -0
  465. package/dist/web/hooks/use-user.test.js.map +1 -0
  466. package/dist/web/hooks/use-view-state.d.ts +25 -0
  467. package/dist/web/hooks/use-view-state.js +42 -0
  468. package/dist/web/hooks/use-view-state.js.map +1 -0
  469. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  470. package/dist/web/hooks/use-view-state.test.js +212 -0
  471. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  472. package/dist/web/hooks/use-viewport.d.ts +20 -0
  473. package/dist/web/hooks/use-viewport.js +21 -0
  474. package/dist/web/hooks/use-viewport.js.map +1 -0
  475. package/dist/web/hooks/use-viewport.test.d.ts +1 -0
  476. package/dist/web/hooks/use-viewport.test.js +109 -0
  477. package/dist/web/hooks/use-viewport.test.js.map +1 -0
  478. package/dist/{src/web → web}/index.d.ts +1 -2
  479. package/dist/{src/web → web}/index.js +1 -2
  480. package/dist/web/index.js.map +1 -0
  481. package/dist/web/mount-view.d.ts +21 -0
  482. package/dist/web/mount-view.js +43 -0
  483. package/dist/web/mount-view.js.map +1 -0
  484. package/dist/{src/web → web}/proxy.js +0 -1
  485. package/dist/web/proxy.js.map +1 -0
  486. package/dist/web/types.d.ts +20 -0
  487. package/dist/web/types.js +2 -0
  488. package/dist/web/types.js.map +1 -0
  489. package/package.json +86 -41
  490. package/tsconfig.base.json +33 -0
  491. package/dist/src/server/devtoolsStaticServer.d.ts +0 -15
  492. package/dist/src/server/devtoolsStaticServer.js +0 -38
  493. package/dist/src/server/devtoolsStaticServer.js.map +0 -1
  494. package/dist/src/server/index.d.ts +0 -5
  495. package/dist/src/server/index.js +0 -4
  496. package/dist/src/server/index.js.map +0 -1
  497. package/dist/src/server/inferUtilityTypes.js.map +0 -1
  498. package/dist/src/server/server.d.ts +0 -74
  499. package/dist/src/server/server.js +0 -82
  500. package/dist/src/server/server.js.map +0 -1
  501. package/dist/src/server/templateHelper.js +0 -30
  502. package/dist/src/server/templateHelper.js.map +0 -1
  503. package/dist/src/server/templates/development.hbs +0 -13
  504. package/dist/src/server/templates/production.hbs +0 -7
  505. package/dist/src/server/widgetsDevServer.d.ts +0 -12
  506. package/dist/src/server/widgetsDevServer.js +0 -39
  507. package/dist/src/server/widgetsDevServer.js.map +0 -1
  508. package/dist/src/test/utils.js +0 -242
  509. package/dist/src/test/utils.js.map +0 -1
  510. package/dist/src/test/widget.test.js +0 -146
  511. package/dist/src/test/widget.test.js.map +0 -1
  512. package/dist/src/web/bridges/apps-sdk-adapter.d.ts +0 -3
  513. package/dist/src/web/bridges/apps-sdk-adapter.js +0 -7
  514. package/dist/src/web/bridges/apps-sdk-adapter.js.map +0 -1
  515. package/dist/src/web/bridges/apps-sdk-bridge.d.ts +0 -8
  516. package/dist/src/web/bridges/apps-sdk-bridge.js +0 -41
  517. package/dist/src/web/bridges/apps-sdk-bridge.js.map +0 -1
  518. package/dist/src/web/bridges/get-bridge-methods.d.ts +0 -2
  519. package/dist/src/web/bridges/get-bridge-methods.js +0 -8
  520. package/dist/src/web/bridges/get-bridge-methods.js.map +0 -1
  521. package/dist/src/web/bridges/hooks/types.d.ts +0 -6
  522. package/dist/src/web/bridges/hooks/types.js.map +0 -1
  523. package/dist/src/web/bridges/hooks/use-apps-sdk-bridge.d.ts +0 -2
  524. package/dist/src/web/bridges/hooks/use-apps-sdk-bridge.js +0 -7
  525. package/dist/src/web/bridges/hooks/use-apps-sdk-bridge.js.map +0 -1
  526. package/dist/src/web/bridges/hooks/use-bridge.d.ts +0 -2
  527. package/dist/src/web/bridges/hooks/use-bridge.js +0 -19
  528. package/dist/src/web/bridges/hooks/use-bridge.js.map +0 -1
  529. package/dist/src/web/bridges/hooks/use-mcp-app-bridge.d.ts +0 -4
  530. package/dist/src/web/bridges/hooks/use-mcp-app-bridge.js +0 -7
  531. package/dist/src/web/bridges/hooks/use-mcp-app-bridge.js.map +0 -1
  532. package/dist/src/web/bridges/hooks/use-mcp-app-bridge.test.js +0 -58
  533. package/dist/src/web/bridges/hooks/use-mcp-app-bridge.test.js.map +0 -1
  534. package/dist/src/web/bridges/index.d.ts +0 -4
  535. package/dist/src/web/bridges/index.js +0 -5
  536. package/dist/src/web/bridges/index.js.map +0 -1
  537. package/dist/src/web/bridges/mcp-app-adapter.d.ts +0 -5
  538. package/dist/src/web/bridges/mcp-app-adapter.js +0 -56
  539. package/dist/src/web/bridges/mcp-app-adapter.js.map +0 -1
  540. package/dist/src/web/bridges/mcp-app-bridge.d.ts +0 -30
  541. package/dist/src/web/bridges/mcp-app-bridge.js +0 -139
  542. package/dist/src/web/bridges/mcp-app-bridge.js.map +0 -1
  543. package/dist/src/web/bridges/types.d.ts +0 -33
  544. package/dist/src/web/bridges/types.js.map +0 -1
  545. package/dist/src/web/create-store.d.ts +0 -3
  546. package/dist/src/web/create-store.js +0 -25
  547. package/dist/src/web/create-store.js.map +0 -1
  548. package/dist/src/web/create-store.test.js +0 -70
  549. package/dist/src/web/create-store.test.js.map +0 -1
  550. package/dist/src/web/data-llm.d.ts +0 -14
  551. package/dist/src/web/data-llm.js.map +0 -1
  552. package/dist/src/web/data-llm.test.js +0 -76
  553. package/dist/src/web/data-llm.test.js.map +0 -1
  554. package/dist/src/web/generate-helpers.js.map +0 -1
  555. package/dist/src/web/generate-helpers.test-d.js.map +0 -1
  556. package/dist/src/web/generate-helpers.test.js.map +0 -1
  557. package/dist/src/web/helpers/state.js +0 -40
  558. package/dist/src/web/helpers/state.js.map +0 -1
  559. package/dist/src/web/helpers/state.test.js.map +0 -1
  560. package/dist/src/web/hooks/index.d.ts +0 -11
  561. package/dist/src/web/hooks/index.js +0 -12
  562. package/dist/src/web/hooks/index.js.map +0 -1
  563. package/dist/src/web/hooks/use-call-tool.js +0 -60
  564. package/dist/src/web/hooks/use-call-tool.js.map +0 -1
  565. package/dist/src/web/hooks/use-call-tool.test-d.js.map +0 -1
  566. package/dist/src/web/hooks/use-call-tool.test.js.map +0 -1
  567. package/dist/src/web/hooks/use-display-mode.d.ts +0 -4
  568. package/dist/src/web/hooks/use-display-mode.js +0 -10
  569. package/dist/src/web/hooks/use-display-mode.js.map +0 -1
  570. package/dist/src/web/hooks/use-display-mode.test.js +0 -41
  571. package/dist/src/web/hooks/use-display-mode.test.js.map +0 -1
  572. package/dist/src/web/hooks/use-files.d.ts +0 -10
  573. package/dist/src/web/hooks/use-files.js +0 -7
  574. package/dist/src/web/hooks/use-files.js.map +0 -1
  575. package/dist/src/web/hooks/use-files.test.js +0 -29
  576. package/dist/src/web/hooks/use-files.test.js.map +0 -1
  577. package/dist/src/web/hooks/use-layout.d.ts +0 -22
  578. package/dist/src/web/hooks/use-layout.js +0 -23
  579. package/dist/src/web/hooks/use-layout.js.map +0 -1
  580. package/dist/src/web/hooks/use-layout.test.js +0 -46
  581. package/dist/src/web/hooks/use-layout.test.js.map +0 -1
  582. package/dist/src/web/hooks/use-open-external.d.ts +0 -1
  583. package/dist/src/web/hooks/use-open-external.js +0 -6
  584. package/dist/src/web/hooks/use-open-external.js.map +0 -1
  585. package/dist/src/web/hooks/use-open-external.test.js +0 -24
  586. package/dist/src/web/hooks/use-open-external.test.js.map +0 -1
  587. package/dist/src/web/hooks/use-openai-global.d.ts +0 -3
  588. package/dist/src/web/hooks/use-openai-global.js +0 -6
  589. package/dist/src/web/hooks/use-openai-global.js.map +0 -1
  590. package/dist/src/web/hooks/use-request-modal.d.ts +0 -9
  591. package/dist/src/web/hooks/use-request-modal.js +0 -14
  592. package/dist/src/web/hooks/use-request-modal.js.map +0 -1
  593. package/dist/src/web/hooks/use-request-modal.test.js.map +0 -1
  594. package/dist/src/web/hooks/use-send-follow-up-message.d.ts +0 -1
  595. package/dist/src/web/hooks/use-send-follow-up-message.js +0 -6
  596. package/dist/src/web/hooks/use-send-follow-up-message.js.map +0 -1
  597. package/dist/src/web/hooks/use-tool-info.d.ts +0 -25
  598. package/dist/src/web/hooks/use-tool-info.js +0 -20
  599. package/dist/src/web/hooks/use-tool-info.js.map +0 -1
  600. package/dist/src/web/hooks/use-tool-info.test-d.js.map +0 -1
  601. package/dist/src/web/hooks/use-tool-info.test.js +0 -60
  602. package/dist/src/web/hooks/use-tool-info.test.js.map +0 -1
  603. package/dist/src/web/hooks/use-user.js +0 -19
  604. package/dist/src/web/hooks/use-user.js.map +0 -1
  605. package/dist/src/web/hooks/use-user.test.js +0 -44
  606. package/dist/src/web/hooks/use-user.test.js.map +0 -1
  607. package/dist/src/web/hooks/use-widget-state.d.ts +0 -4
  608. package/dist/src/web/hooks/use-widget-state.js +0 -32
  609. package/dist/src/web/hooks/use-widget-state.js.map +0 -1
  610. package/dist/src/web/hooks/use-widget-state.test.js +0 -61
  611. package/dist/src/web/hooks/use-widget-state.test.js.map +0 -1
  612. package/dist/src/web/index.js.map +0 -1
  613. package/dist/src/web/mount-widget.d.ts +0 -1
  614. package/dist/src/web/mount-widget.js +0 -19
  615. package/dist/src/web/mount-widget.js.map +0 -1
  616. package/dist/src/web/plugin/data-llm.test.js +0 -81
  617. package/dist/src/web/plugin/data-llm.test.js.map +0 -1
  618. package/dist/src/web/plugin/plugin.d.ts +0 -2
  619. package/dist/src/web/plugin/plugin.js +0 -39
  620. package/dist/src/web/plugin/plugin.js.map +0 -1
  621. package/dist/src/web/plugin/transform-data-llm.d.ts +0 -12
  622. package/dist/src/web/plugin/transform-data-llm.js +0 -93
  623. package/dist/src/web/plugin/transform-data-llm.js.map +0 -1
  624. package/dist/src/web/plugin/transform-data-llm.test.js +0 -81
  625. package/dist/src/web/plugin/transform-data-llm.test.js.map +0 -1
  626. package/dist/src/web/proxy.js.map +0 -1
  627. package/dist/src/web/types.d.ts +0 -151
  628. package/dist/src/web/types.js.map +0 -1
  629. package/dist/vitest.config.d.ts +0 -2
  630. package/dist/vitest.config.js +0 -8
  631. package/dist/vitest.config.js.map +0 -1
  632. /package/dist/{src/test/widget.test.d.ts → cli/build-helpers.test.d.ts} +0 -0
  633. /package/dist/{src/web/bridges/hooks/use-mcp-app-bridge.test.d.ts → cli/build-steps.test.d.ts} +0 -0
  634. /package/dist/{src/web/create-store.test.d.ts → cli/tunnel-control-server.test.d.ts} +0 -0
  635. /package/dist/{src/web/data-llm.test.d.ts → cli/tunnel-handler.test.d.ts} +0 -0
  636. /package/dist/{src/web/generate-helpers.test-d.d.ts → cli/tunnel.test.d.ts} +0 -0
  637. /package/dist/{src/web/bridges/hooks → cli}/types.js +0 -0
  638. /package/dist/{src/web/generate-helpers.test.d.ts → context-warnings.test.d.ts} +0 -0
  639. /package/dist/{src/web/helpers/state.test.d.ts → server/app.test.d.ts} +0 -0
  640. /package/dist/{src/web/hooks/use-call-tool.test-d.d.ts → server/asset-base-url-transform-plugin.test.d.ts} +0 -0
  641. /package/dist/{src/web/hooks/use-display-mode.test.d.ts → server/auth/discovery.test.d.ts} +0 -0
  642. /package/dist/{src/web/hooks/use-files.test.d.ts → server/auth/providers/auth0.test.d.ts} +0 -0
  643. /package/dist/{src/web/hooks/use-layout.test.d.ts → server/auth/providers/authplane.test.d.ts} +0 -0
  644. /package/dist/{src/web/hooks/use-open-external.test.d.ts → server/auth/providers/clerk.test.d.ts} +0 -0
  645. /package/dist/{src/web/hooks/use-request-modal.test.d.ts → server/auth/providers/custom.test.d.ts} +0 -0
  646. /package/dist/{src/web/hooks/use-tool-info.test-d.d.ts → server/auth/providers/descope.test.d.ts} +0 -0
  647. /package/dist/{src/web/hooks/use-tool-info.test.d.ts → server/auth/providers/shared.test.d.ts} +0 -0
  648. /package/dist/{src/web/hooks/use-user.test.d.ts → server/auth/security-schemes.test.d.ts} +0 -0
  649. /package/dist/{src/web/hooks/use-widget-state.test.d.ts → server/auth/setup.test.d.ts} +0 -0
  650. /package/dist/{src/web/plugin/data-llm.test.d.ts → server/auth/verify.test.d.ts} +0 -0
  651. /package/dist/{src/web/hooks/use-call-tool.test.d.ts → server/auth-extra.test-d.d.ts} +0 -0
  652. /package/dist/{src/web/plugin/transform-data-llm.test.d.ts → server/build-manifest.test.d.ts} +0 -0
  653. /package/dist/{src/server → server}/inferUtilityTypes.js +0 -0
  654. /package/dist/{src/web/bridges → web/bridges/mcp-app}/types.js +0 -0
  655. /package/dist/{src/web → web}/hooks/use-call-tool.test-d.js +0 -0
  656. /package/dist/{src/web → web}/proxy.d.ts +0 -0
@@ -0,0 +1,103 @@
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 { useDownload } from "./use-download.js";
7
+ const params = {
8
+ contents: [
9
+ {
10
+ type: "resource",
11
+ resource: {
12
+ uri: "file:///export.json",
13
+ mimeType: "application/json",
14
+ text: '{"hello":"world"}',
15
+ },
16
+ },
17
+ ],
18
+ };
19
+ describe("useDownload", () => {
20
+ describe("apps-sdk host", () => {
21
+ beforeEach(() => {
22
+ vi.stubGlobal("openai", {});
23
+ vi.stubGlobal("skybridge", {});
24
+ vi.stubGlobal("ResizeObserver", MockResizeObserver);
25
+ vi.stubGlobal("parent", { postMessage: getMcpAppHostPostMessageMock() });
26
+ });
27
+ afterEach(() => {
28
+ vi.unstubAllGlobals();
29
+ vi.resetAllMocks();
30
+ HostAdaptor.resetInstance();
31
+ McpAppBridge.resetInstance();
32
+ });
33
+ it("returns { isError: true } and logs an error", async () => {
34
+ const errorSpy = vi.spyOn(console, "error").mockImplementation(() => { });
35
+ const { result } = renderHook(() => useDownload());
36
+ const res = await result.current(params);
37
+ expect(res).toEqual({ isError: true });
38
+ expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining("does not support ui/download-file"));
39
+ });
40
+ });
41
+ describe("mcp-app host without downloadFile capability", () => {
42
+ beforeEach(() => {
43
+ vi.stubGlobal("openai", undefined);
44
+ vi.stubGlobal("skybridge", {});
45
+ vi.stubGlobal("ResizeObserver", MockResizeObserver);
46
+ vi.stubGlobal("parent", { postMessage: getMcpAppHostPostMessageMock() });
47
+ });
48
+ afterEach(async () => {
49
+ vi.unstubAllGlobals();
50
+ vi.resetAllMocks();
51
+ HostAdaptor.resetInstance();
52
+ McpAppBridge.resetInstance();
53
+ });
54
+ it("returns { isError: true } and logs an error", async () => {
55
+ const errorSpy = vi.spyOn(console, "error").mockImplementation(() => { });
56
+ const { result } = renderHook(() => useDownload());
57
+ const res = await result.current(params);
58
+ expect(res).toEqual({ isError: true });
59
+ expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining("does not support ui/download-file"));
60
+ });
61
+ });
62
+ describe("mcp-app host with downloadFile capability", () => {
63
+ let postMessageMock;
64
+ beforeEach(() => {
65
+ vi.stubGlobal("openai", undefined);
66
+ vi.stubGlobal("skybridge", {});
67
+ vi.stubGlobal("ResizeObserver", MockResizeObserver);
68
+ postMessageMock = getMcpAppHostPostMessageMock({}, { hostCapabilities: { downloadFile: {} } });
69
+ vi.stubGlobal("parent", { postMessage: postMessageMock });
70
+ });
71
+ afterEach(async () => {
72
+ vi.unstubAllGlobals();
73
+ vi.resetAllMocks();
74
+ HostAdaptor.resetInstance();
75
+ McpAppBridge.resetInstance();
76
+ });
77
+ it("sends ui/download-file with the provided contents", async () => {
78
+ const { result } = renderHook(() => useDownload());
79
+ const res = await result.current(params);
80
+ expect(res).toEqual({});
81
+ await waitFor(() => {
82
+ expect(postMessageMock).toHaveBeenCalledWith(expect.objectContaining({
83
+ jsonrpc: "2.0",
84
+ method: "ui/download-file",
85
+ params,
86
+ }), "*");
87
+ });
88
+ });
89
+ it("returns { isError: true } when the host denies the request", async () => {
90
+ HostAdaptor.resetInstance();
91
+ McpAppBridge.resetInstance();
92
+ postMessageMock = getMcpAppHostPostMessageMock({}, {
93
+ hostCapabilities: { downloadFile: {} },
94
+ downloadFileResult: { isError: true },
95
+ });
96
+ vi.stubGlobal("parent", { postMessage: postMessageMock });
97
+ const { result } = renderHook(() => useDownload());
98
+ const res = await result.current(params);
99
+ expect(res).toEqual({ isError: true });
100
+ });
101
+ });
102
+ });
103
+ //# sourceMappingURL=use-download.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-download.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-download.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 type { DownloadParams } from \"../bridges/types.js\";\nimport {\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"./test/utils.js\";\nimport { useDownload } from \"./use-download.js\";\n\nconst params: DownloadParams = {\n contents: [\n {\n type: \"resource\",\n resource: {\n uri: \"file:///export.json\",\n mimeType: \"application/json\",\n text: '{\"hello\":\"world\"}',\n },\n },\n ],\n};\n\ndescribe(\"useDownload\", () => {\n describe(\"apps-sdk host\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"openai\", {});\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.stubGlobal(\"parent\", { postMessage: getMcpAppHostPostMessageMock() });\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n });\n\n it(\"returns { isError: true } and logs an error\", async () => {\n const errorSpy = vi.spyOn(console, \"error\").mockImplementation(() => {});\n const { result } = renderHook(() => useDownload());\n\n const res = await result.current(params);\n\n expect(res).toEqual({ isError: true });\n expect(errorSpy).toHaveBeenCalledWith(\n expect.stringContaining(\"does not support ui/download-file\"),\n );\n });\n });\n\n describe(\"mcp-app host without downloadFile capability\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"openai\", undefined);\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.stubGlobal(\"parent\", { postMessage: getMcpAppHostPostMessageMock() });\n });\n\n afterEach(async () => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n });\n\n it(\"returns { isError: true } and logs an error\", async () => {\n const errorSpy = vi.spyOn(console, \"error\").mockImplementation(() => {});\n const { result } = renderHook(() => useDownload());\n\n const res = await result.current(params);\n\n expect(res).toEqual({ isError: true });\n expect(errorSpy).toHaveBeenCalledWith(\n expect.stringContaining(\"does not support ui/download-file\"),\n );\n });\n });\n\n describe(\"mcp-app host with downloadFile capability\", () => {\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 {},\n { hostCapabilities: { downloadFile: {} } },\n );\n vi.stubGlobal(\"parent\", { postMessage: postMessageMock });\n });\n\n afterEach(async () => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n });\n\n it(\"sends ui/download-file with the provided contents\", async () => {\n const { result } = renderHook(() => useDownload());\n\n const res = await result.current(params);\n\n expect(res).toEqual({});\n await waitFor(() => {\n expect(postMessageMock).toHaveBeenCalledWith(\n expect.objectContaining({\n jsonrpc: \"2.0\",\n method: \"ui/download-file\",\n params,\n }),\n \"*\",\n );\n });\n });\n\n it(\"returns { isError: true } when the host denies the request\", async () => {\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n postMessageMock = getMcpAppHostPostMessageMock(\n {},\n {\n hostCapabilities: { downloadFile: {} },\n downloadFileResult: { isError: true },\n },\n );\n vi.stubGlobal(\"parent\", { postMessage: postMessageMock });\n\n const { result } = renderHook(() => useDownload());\n\n const res = await result.current(params);\n\n expect(res).toEqual({ isError: true });\n });\n });\n});\n"]}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * File operations bound to the current host: `upload` a `File`, resolve a
3
+ * `downloadUrl` for an uploaded file, and `selectFiles` to open the host's
4
+ * native file picker.
5
+ *
6
+ * Currently Apps-SDK-only — calling any of these from MCP Apps throws.
7
+ * `selectFiles` additionally requires a ChatGPT host version that exposes the
8
+ * picker; it throws if the capability is unavailable.
9
+ *
10
+ * `upload` returns `FileMetadata` (`fileId`, optional `fileName`, `mimeType`).
11
+ * To pass an uploaded file to a tool whose input uses {@link FileRef}, first
12
+ * call `getDownloadUrl` and then build the ref yourself — field names differ
13
+ * (camelCase on the client, snake_case in the schema) and `download_url` is
14
+ * required.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * const { upload, getDownloadUrl } = useFiles();
19
+ * const meta = await upload(file);
20
+ * const { downloadUrl } = await getDownloadUrl(meta);
21
+ * callTool({
22
+ * document: {
23
+ * file_id: meta.fileId,
24
+ * download_url: downloadUrl,
25
+ * file_name: meta.fileName,
26
+ * mime_type: meta.mimeType,
27
+ * },
28
+ * });
29
+ * ```
30
+ *
31
+ * @see https://docs.skybridge.tech/api-reference/use-files
32
+ */
33
+ export declare function useFiles(): {
34
+ upload: (file: File, options?: import("../index.js").UploadFileOptions) => Promise<import("../index.js").FileMetadata>;
35
+ getDownloadUrl: (file: import("../index.js").FileMetadata) => Promise<{
36
+ downloadUrl: string;
37
+ }>;
38
+ selectFiles: () => Promise<import("../index.js").FileMetadata[]>;
39
+ };
@@ -0,0 +1,42 @@
1
+ import { getAdaptor } from "../bridges/index.js";
2
+ /**
3
+ * File operations bound to the current host: `upload` a `File`, resolve a
4
+ * `downloadUrl` for an uploaded file, and `selectFiles` to open the host's
5
+ * native file picker.
6
+ *
7
+ * Currently Apps-SDK-only — calling any of these from MCP Apps throws.
8
+ * `selectFiles` additionally requires a ChatGPT host version that exposes the
9
+ * picker; it throws if the capability is unavailable.
10
+ *
11
+ * `upload` returns `FileMetadata` (`fileId`, optional `fileName`, `mimeType`).
12
+ * To pass an uploaded file to a tool whose input uses {@link FileRef}, first
13
+ * call `getDownloadUrl` and then build the ref yourself — field names differ
14
+ * (camelCase on the client, snake_case in the schema) and `download_url` is
15
+ * required.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * const { upload, getDownloadUrl } = useFiles();
20
+ * const meta = await upload(file);
21
+ * const { downloadUrl } = await getDownloadUrl(meta);
22
+ * callTool({
23
+ * document: {
24
+ * file_id: meta.fileId,
25
+ * download_url: downloadUrl,
26
+ * file_name: meta.fileName,
27
+ * mime_type: meta.mimeType,
28
+ * },
29
+ * });
30
+ * ```
31
+ *
32
+ * @see https://docs.skybridge.tech/api-reference/use-files
33
+ */
34
+ export function useFiles() {
35
+ const adaptor = getAdaptor();
36
+ return {
37
+ upload: adaptor.uploadFile,
38
+ getDownloadUrl: adaptor.getFileDownloadUrl,
39
+ selectFiles: adaptor.selectFiles,
40
+ };
41
+ }
42
+ //# sourceMappingURL=use-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-files.js","sourceRoot":"","sources":["../../../src/web/hooks/use-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,QAAQ;IACtB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,UAAU;QAC1B,cAAc,EAAE,OAAO,CAAC,kBAAkB;QAC1C,WAAW,EAAE,OAAO,CAAC,WAAW;KACjC,CAAC;AACJ,CAAC","sourcesContent":["import { getAdaptor } from \"../bridges/index.js\";\n\n/**\n * File operations bound to the current host: `upload` a `File`, resolve a\n * `downloadUrl` for an uploaded file, and `selectFiles` to open the host's\n * native file picker.\n *\n * Currently Apps-SDK-only — calling any of these from MCP Apps throws.\n * `selectFiles` additionally requires a ChatGPT host version that exposes the\n * picker; it throws if the capability is unavailable.\n *\n * `upload` returns `FileMetadata` (`fileId`, optional `fileName`, `mimeType`).\n * To pass an uploaded file to a tool whose input uses {@link FileRef}, first\n * call `getDownloadUrl` and then build the ref yourself — field names differ\n * (camelCase on the client, snake_case in the schema) and `download_url` is\n * required.\n *\n * @example\n * ```tsx\n * const { upload, getDownloadUrl } = useFiles();\n * const meta = await upload(file);\n * const { downloadUrl } = await getDownloadUrl(meta);\n * callTool({\n * document: {\n * file_id: meta.fileId,\n * download_url: downloadUrl,\n * file_name: meta.fileName,\n * mime_type: meta.mimeType,\n * },\n * });\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/use-files\n */\nexport function useFiles() {\n const adaptor = getAdaptor();\n return {\n upload: adaptor.uploadFile,\n getDownloadUrl: adaptor.getFileDownloadUrl,\n selectFiles: adaptor.selectFiles,\n };\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,62 @@
1
+ import { renderHook } from "@testing-library/react";
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";
6
+ import { useFiles } from "./use-files.js";
7
+ describe("useFiles", () => {
8
+ const OpenaiMock = {
9
+ uploadFile: vi.fn().mockResolvedValue({
10
+ fileId: `sediment://file_abc123`,
11
+ }),
12
+ getFileDownloadUrl: vi.fn(),
13
+ widgetState: null,
14
+ setWidgetState: vi.fn(),
15
+ };
16
+ beforeEach(() => {
17
+ HostAdaptor.resetInstance();
18
+ McpAppBridge.resetInstance();
19
+ AppsSdkBridge.resetInstance();
20
+ vi.stubGlobal("skybridge", {});
21
+ vi.stubGlobal("openai", OpenaiMock);
22
+ vi.stubGlobal("parent", { postMessage: vi.fn() });
23
+ });
24
+ afterEach(() => {
25
+ vi.unstubAllGlobals();
26
+ vi.clearAllMocks();
27
+ HostAdaptor.resetInstance();
28
+ McpAppBridge.resetInstance();
29
+ AppsSdkBridge.resetInstance();
30
+ });
31
+ const dummyFile = new File([], "test.txt");
32
+ it("should upload a file to ChatGPT", () => {
33
+ const { result } = renderHook(() => useFiles());
34
+ result.current.upload(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;
54
+ });
55
+ it("should download a file from ChatGPT", () => {
56
+ const fileId = "123";
57
+ const { result } = renderHook(() => useFiles());
58
+ result.current.getDownloadUrl({ fileId });
59
+ expect(OpenaiMock.getFileDownloadUrl).toHaveBeenCalledWith({ fileId });
60
+ });
61
+ });
62
+ //# sourceMappingURL=use-files.test.js.map
@@ -0,0 +1 @@
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"]}
@@ -0,0 +1,44 @@
1
+ import type { OpenAIHostContext } from "../bridges/mcp-app/types.js";
2
+ import type { ModelContextParams } from "../bridges/types.js";
3
+ /** Model context the view attached, as ChatGPT reports it back. */
4
+ export type ModelContextState = OpenAIHostContext["openai/modelContext"];
5
+ /**
6
+ * Send content to the model through the MCP Apps `ui/update-model-context`
7
+ * request. Each `update` replaces what this hook sent before. Outside ChatGPT
8
+ * it is merged with the {@link useViewState} state, which wins on shared
9
+ * `structuredContent` keys.
10
+ *
11
+ * ChatGPT also reads the OpenAI presentation metadata, shows each block as a
12
+ * composer attachment and reports the attached context back:
13
+ * `_meta["openai/title"]`, `_meta["openai/thumbnail"]` on text blocks, and
14
+ * `annotations.audience: ["assistant"]` to hide a block from the user.
15
+ *
16
+ * - `supported`: whether the host advertises `updateModelContext` or
17
+ * `openai/modelContext`.
18
+ * - `context`: ChatGPT only, the attached context; `null` once the user
19
+ * removed it, `undefined` when the host never reported one.
20
+ * - `update`: replaces the context and resolves with ChatGPT's `updateId`,
21
+ * to compare with `context.updateId`. Rejects with `NotSupportedError` on
22
+ * hosts that don't advertise model context updates.
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * const { supported, update } = useModelContext();
27
+ * update({
28
+ * content: [
29
+ * {
30
+ * type: "text",
31
+ * text: "Selected: M6 hex bolt",
32
+ * _meta: { "openai/title": "Hex bolt" },
33
+ * },
34
+ * ],
35
+ * });
36
+ * ```
37
+ *
38
+ * @see https://docs.skybridge.tech/api-reference/use-model-context
39
+ */
40
+ export declare function useModelContext(): {
41
+ supported: boolean;
42
+ context: ModelContextState;
43
+ update: (params: ModelContextParams) => Promise<string | undefined>;
44
+ };
@@ -0,0 +1,65 @@
1
+ import { ContentBlockSchema } from "@modelcontextprotocol/core";
2
+ import { useCallback, useMemo } from "react";
3
+ import * as z from "zod/v4";
4
+ import { getAdaptor, useMcpAppContext } from "../bridges/index.js";
5
+ import { useHost } from "./use-host.js";
6
+ const ModelContextSchema = z
7
+ .object({
8
+ updateId: z.string().min(1),
9
+ content: z.array(ContentBlockSchema).optional(),
10
+ structuredContent: z.record(z.string(), z.unknown()).optional(),
11
+ })
12
+ .nullable();
13
+ /**
14
+ * Send content to the model through the MCP Apps `ui/update-model-context`
15
+ * request. Each `update` replaces what this hook sent before. Outside ChatGPT
16
+ * it is merged with the {@link useViewState} state, which wins on shared
17
+ * `structuredContent` keys.
18
+ *
19
+ * ChatGPT also reads the OpenAI presentation metadata, shows each block as a
20
+ * composer attachment and reports the attached context back:
21
+ * `_meta["openai/title"]`, `_meta["openai/thumbnail"]` on text blocks, and
22
+ * `annotations.audience: ["assistant"]` to hide a block from the user.
23
+ *
24
+ * - `supported`: whether the host advertises `updateModelContext` or
25
+ * `openai/modelContext`.
26
+ * - `context`: ChatGPT only, the attached context; `null` once the user
27
+ * removed it, `undefined` when the host never reported one.
28
+ * - `update`: replaces the context and resolves with ChatGPT's `updateId`,
29
+ * to compare with `context.updateId`. Rejects with `NotSupportedError` on
30
+ * hosts that don't advertise model context updates.
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * const { supported, update } = useModelContext();
35
+ * update({
36
+ * content: [
37
+ * {
38
+ * type: "text",
39
+ * text: "Selected: M6 hex bolt",
40
+ * _meta: { "openai/title": "Hex bolt" },
41
+ * },
42
+ * ],
43
+ * });
44
+ * ```
45
+ *
46
+ * @see https://docs.skybridge.tech/api-reference/use-model-context
47
+ */
48
+ export function useModelContext() {
49
+ const { capabilities, openai } = useHost();
50
+ const reported = useMcpAppContext("openai/modelContext");
51
+ const context = useMemo(() => {
52
+ if (reported === undefined) {
53
+ return undefined;
54
+ }
55
+ const parsed = ModelContextSchema.safeParse(reported);
56
+ return parsed.success ? parsed.data : undefined;
57
+ }, [reported]);
58
+ const update = useCallback((params) => getAdaptor().updateModelContext(params), []);
59
+ return {
60
+ supported: Boolean(capabilities?.updateModelContext) || openai.modelContext,
61
+ context,
62
+ update,
63
+ };
64
+ }
65
+ //# sourceMappingURL=use-model-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-model-context.js","sourceRoot":"","sources":["../../../src/web/hooks/use-model-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGnE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,MAAM,kBAAkB,GAAG,CAAC;KACzB,MAAM,CAAC;IACN,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,QAAQ,EAAE;IAC/C,iBAAiB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;CAChE,CAAC;KACD,QAAQ,EAAE,CAAC;AAKd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,eAAe;IAK7B,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC;IAC3C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE;QAC3B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACtD,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAE,MAAM,CAAC,IAA0B,CAAC,CAAC,CAAC,SAAS,CAAC;IACzE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IACf,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,MAA0B,EAAE,EAAE,CAAC,UAAU,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,EACvE,EAAE,CACH,CAAC;IAEF,OAAO;QACL,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,kBAAkB,CAAC,IAAI,MAAM,CAAC,YAAY;QAC3E,OAAO;QACP,MAAM;KACP,CAAC;AACJ,CAAC","sourcesContent":["import { ContentBlockSchema } from \"@modelcontextprotocol/core\";\nimport { useCallback, useMemo } from \"react\";\nimport * as z from \"zod/v4\";\nimport { getAdaptor, useMcpAppContext } from \"../bridges/index.js\";\nimport type { OpenAIHostContext } from \"../bridges/mcp-app/types.js\";\nimport type { ModelContextParams } from \"../bridges/types.js\";\nimport { useHost } from \"./use-host.js\";\n\nconst ModelContextSchema = z\n .object({\n updateId: z.string().min(1),\n content: z.array(ContentBlockSchema).optional(),\n structuredContent: z.record(z.string(), z.unknown()).optional(),\n })\n .nullable();\n\n/** Model context the view attached, as ChatGPT reports it back. */\nexport type ModelContextState = OpenAIHostContext[\"openai/modelContext\"];\n\n/**\n * Send content to the model through the MCP Apps `ui/update-model-context`\n * request. Each `update` replaces what this hook sent before. Outside ChatGPT\n * it is merged with the {@link useViewState} state, which wins on shared\n * `structuredContent` keys.\n *\n * ChatGPT also reads the OpenAI presentation metadata, shows each block as a\n * composer attachment and reports the attached context back:\n * `_meta[\"openai/title\"]`, `_meta[\"openai/thumbnail\"]` on text blocks, and\n * `annotations.audience: [\"assistant\"]` to hide a block from the user.\n *\n * - `supported`: whether the host advertises `updateModelContext` or\n * `openai/modelContext`.\n * - `context`: ChatGPT only, the attached context; `null` once the user\n * removed it, `undefined` when the host never reported one.\n * - `update`: replaces the context and resolves with ChatGPT's `updateId`,\n * to compare with `context.updateId`. Rejects with `NotSupportedError` on\n * hosts that don't advertise model context updates.\n *\n * @example\n * ```tsx\n * const { supported, update } = useModelContext();\n * update({\n * content: [\n * {\n * type: \"text\",\n * text: \"Selected: M6 hex bolt\",\n * _meta: { \"openai/title\": \"Hex bolt\" },\n * },\n * ],\n * });\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/use-model-context\n */\nexport function useModelContext(): {\n supported: boolean;\n context: ModelContextState;\n update: (params: ModelContextParams) => Promise<string | undefined>;\n} {\n const { capabilities, openai } = useHost();\n const reported = useMcpAppContext(\"openai/modelContext\");\n const context = useMemo(() => {\n if (reported === undefined) {\n return undefined;\n }\n const parsed = ModelContextSchema.safeParse(reported);\n return parsed.success ? (parsed.data as ModelContextState) : undefined;\n }, [reported]);\n const update = useCallback(\n (params: ModelContextParams) => getAdaptor().updateModelContext(params),\n [],\n );\n\n return {\n supported: Boolean(capabilities?.updateModelContext) || openai.modelContext,\n context,\n update,\n };\n}\n"]}
@@ -0,0 +1,20 @@
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;
@@ -0,0 +1,24 @@
1
+ import { useCallback } from "react";
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
+ */
19
+ export function useOpenExternal() {
20
+ const adaptor = getAdaptor();
21
+ const openExternal = useCallback((href, options) => adaptor.openExternal(href, options), [adaptor]);
22
+ return openExternal;
23
+ }
24
+ //# sourceMappingURL=use-open-external.js.map