skybridge 0.0.0-dev.ecfdeac → 0.0.0-dev.ed005a8

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 (345) hide show
  1. package/README.md +10 -16
  2. package/dist/cli/build-helpers.d.ts +6 -2
  3. package/dist/cli/build-helpers.js +39 -14
  4. package/dist/cli/build-helpers.js.map +1 -1
  5. package/dist/cli/build-helpers.test.js +73 -5
  6. package/dist/cli/build-helpers.test.js.map +1 -1
  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.js +0 -1
  13. package/dist/cli/detect-port.js.map +1 -1
  14. package/dist/cli/header.d.ts +1 -1
  15. package/dist/cli/resolve-skybridge-config.d.ts +5 -0
  16. package/dist/cli/{resolve-views-dir.js → resolve-skybridge-config.js} +4 -3
  17. package/dist/cli/resolve-skybridge-config.js.map +1 -0
  18. package/dist/cli/run-plain.d.ts +18 -0
  19. package/dist/cli/run-plain.js +89 -0
  20. package/dist/cli/run-plain.js.map +1 -0
  21. package/dist/cli/use-execute-steps.d.ts +1 -1
  22. package/dist/cli/use-nodemon.d.ts +14 -0
  23. package/dist/cli/use-nodemon.js +81 -62
  24. package/dist/cli/use-nodemon.js.map +1 -1
  25. package/dist/cli/use-typescript-check.d.ts +8 -2
  26. package/dist/cli/use-typescript-check.js +70 -67
  27. package/dist/cli/use-typescript-check.js.map +1 -1
  28. package/dist/commands/build.d.ts +0 -2
  29. package/dist/commands/build.js +2 -61
  30. package/dist/commands/build.js.map +1 -1
  31. package/dist/commands/dev.d.ts +1 -0
  32. package/dist/commands/dev.js +35 -3
  33. package/dist/commands/dev.js.map +1 -1
  34. package/dist/commands/start.js +2 -2
  35. package/dist/commands/start.js.map +1 -1
  36. package/dist/context-warnings.d.ts +5 -0
  37. package/dist/context-warnings.js +31 -0
  38. package/dist/context-warnings.js.map +1 -0
  39. package/dist/context-warnings.test.js +28 -0
  40. package/dist/context-warnings.test.js.map +1 -0
  41. package/dist/server/app.d.ts +194 -0
  42. package/dist/server/app.js +266 -0
  43. package/dist/server/app.js.map +1 -0
  44. package/dist/server/app.test.js +97 -0
  45. package/dist/server/app.test.js.map +1 -0
  46. package/dist/server/auth/discovery.d.ts +2 -1
  47. package/dist/server/auth/discovery.js +2 -2
  48. package/dist/server/auth/discovery.js.map +1 -1
  49. package/dist/server/auth/index.d.ts +35 -5
  50. package/dist/server/auth/index.js.map +1 -1
  51. package/dist/server/auth/providers/auth0.d.ts +25 -3
  52. package/dist/server/auth/providers/auth0.js +13 -8
  53. package/dist/server/auth/providers/auth0.js.map +1 -1
  54. package/dist/server/auth/providers/auth0.test.js +5 -3
  55. package/dist/server/auth/providers/auth0.test.js.map +1 -1
  56. package/dist/server/auth/providers/authplane.d.ts +49 -0
  57. package/dist/server/auth/providers/authplane.js +57 -0
  58. package/dist/server/auth/providers/authplane.js.map +1 -0
  59. package/dist/server/auth/providers/authplane.test.js +143 -0
  60. package/dist/server/auth/providers/authplane.test.js.map +1 -0
  61. package/dist/server/auth/providers/clerk.d.ts +40 -3
  62. package/dist/server/auth/providers/clerk.js +4 -1
  63. package/dist/server/auth/providers/clerk.js.map +1 -1
  64. package/dist/server/auth/providers/clerk.test.js +5 -3
  65. package/dist/server/auth/providers/clerk.test.js.map +1 -1
  66. package/dist/server/auth/providers/custom.d.ts +20 -4
  67. package/dist/server/auth/providers/custom.js +33 -11
  68. package/dist/server/auth/providers/custom.js.map +1 -1
  69. package/dist/server/auth/providers/custom.test.js +71 -17
  70. package/dist/server/auth/providers/custom.test.js.map +1 -1
  71. package/dist/server/auth/providers/descope.d.ts +37 -6
  72. package/dist/server/auth/providers/descope.js +18 -5
  73. package/dist/server/auth/providers/descope.js.map +1 -1
  74. package/dist/server/auth/providers/descope.test.js +42 -17
  75. package/dist/server/auth/providers/descope.test.js.map +1 -1
  76. package/dist/server/auth/providers/stytch.d.ts +16 -3
  77. package/dist/server/auth/providers/stytch.js +4 -1
  78. package/dist/server/auth/providers/stytch.js.map +1 -1
  79. package/dist/server/auth/providers/verify-spy.d.ts +12 -0
  80. package/dist/server/auth/providers/verify-spy.js +21 -0
  81. package/dist/server/auth/providers/verify-spy.js.map +1 -0
  82. package/dist/server/auth/providers/workos.d.ts +25 -3
  83. package/dist/server/auth/providers/workos.js +4 -1
  84. package/dist/server/auth/providers/workos.js.map +1 -1
  85. package/dist/server/auth/security-schemes.d.ts +23 -0
  86. package/dist/server/auth/security-schemes.js +64 -0
  87. package/dist/server/auth/security-schemes.js.map +1 -0
  88. package/dist/server/auth/security-schemes.test.d.ts +1 -0
  89. package/dist/server/auth/security-schemes.test.js +99 -0
  90. package/dist/server/auth/security-schemes.test.js.map +1 -0
  91. package/dist/server/auth/setup.d.ts +3 -1
  92. package/dist/server/auth/setup.js +66 -26
  93. package/dist/server/auth/setup.js.map +1 -1
  94. package/dist/server/auth/setup.test.js +349 -20
  95. package/dist/server/auth/setup.test.js.map +1 -1
  96. package/dist/server/auth/verify.d.ts +37 -3
  97. package/dist/server/auth/verify.js +27 -3
  98. package/dist/server/auth/verify.js.map +1 -1
  99. package/dist/server/auth/verify.test.js +49 -0
  100. package/dist/server/auth/verify.test.js.map +1 -1
  101. package/dist/server/auth-extra.test-d.js +130 -0
  102. package/dist/server/auth-extra.test-d.js.map +1 -0
  103. package/dist/server/auth.d.ts +43 -6
  104. package/dist/server/auth.js +4 -5
  105. package/dist/server/auth.js.map +1 -1
  106. package/dist/server/build-manifest.test.js +7 -6
  107. package/dist/server/build-manifest.test.js.map +1 -1
  108. package/dist/server/content-helpers.d.ts +1 -1
  109. package/dist/server/content-helpers.js.map +1 -1
  110. package/dist/server/express.d.ts +23 -3
  111. package/dist/server/express.js +38 -32
  112. package/dist/server/express.js.map +1 -1
  113. package/dist/server/express.test.js +220 -103
  114. package/dist/server/express.test.js.map +1 -1
  115. package/dist/server/file-ref.d.ts +1 -1
  116. package/dist/server/file-ref.js +1 -1
  117. package/dist/server/file-ref.js.map +1 -1
  118. package/dist/server/host.d.ts +2 -0
  119. package/dist/server/host.js +11 -0
  120. package/dist/server/host.js.map +1 -0
  121. package/dist/server/host.test.d.ts +1 -0
  122. package/dist/server/host.test.js +13 -0
  123. package/dist/server/host.test.js.map +1 -0
  124. package/dist/server/index.d.ts +16 -9
  125. package/dist/server/index.js +9 -3
  126. package/dist/server/index.js.map +1 -1
  127. package/dist/server/mcp-errors.test.d.ts +1 -0
  128. package/dist/server/mcp-errors.test.js +41 -0
  129. package/dist/server/mcp-errors.test.js.map +1 -0
  130. package/dist/server/middleware.d.ts +35 -10
  131. package/dist/server/middleware.js +33 -0
  132. package/dist/server/middleware.js.map +1 -1
  133. package/dist/server/middleware.test-d.js +1 -1
  134. package/dist/server/middleware.test-d.js.map +1 -1
  135. package/dist/server/middleware.test.js +242 -134
  136. package/dist/server/middleware.test.js.map +1 -1
  137. package/dist/server/register-tool.test.d.ts +1 -0
  138. package/dist/server/register-tool.test.js +27 -0
  139. package/dist/server/register-tool.test.js.map +1 -0
  140. package/dist/server/server.d.ts +133 -116
  141. package/dist/server/server.js +251 -346
  142. package/dist/server/server.js.map +1 -1
  143. package/dist/server/skills-integration.test.d.ts +1 -0
  144. package/dist/server/skills-integration.test.js +86 -0
  145. package/dist/server/skills-integration.test.js.map +1 -0
  146. package/dist/server/skills.d.ts +27 -0
  147. package/dist/server/skills.js +188 -0
  148. package/dist/server/skills.js.map +1 -0
  149. package/dist/server/skills.test.d.ts +1 -0
  150. package/dist/server/skills.test.js +243 -0
  151. package/dist/server/skills.test.js.map +1 -0
  152. package/dist/server/templateHelper.d.ts +0 -3
  153. package/dist/server/templateHelper.js.map +1 -1
  154. package/dist/server/templates.generated.js +4 -8
  155. package/dist/server/templates.generated.js.map +1 -1
  156. package/dist/server/tool-extra.test.d.ts +1 -0
  157. package/dist/server/tool-extra.test.js +88 -0
  158. package/dist/server/tool-extra.test.js.map +1 -0
  159. package/dist/server/view-name.test-d.d.ts +1 -0
  160. package/dist/server/view-name.test-d.js +8 -0
  161. package/dist/server/view-name.test-d.js.map +1 -0
  162. package/dist/server/view-resource-resolution.test.js +105 -17
  163. package/dist/server/view-resource-resolution.test.js.map +1 -1
  164. package/dist/server/viewsDevServer.js +4 -1
  165. package/dist/server/viewsDevServer.js.map +1 -1
  166. package/dist/test/utils.d.ts +9 -11
  167. package/dist/test/utils.js +220 -201
  168. package/dist/test/utils.js.map +1 -1
  169. package/dist/test/view.test.js +105 -133
  170. package/dist/test/view.test.js.map +1 -1
  171. package/dist/views/index.d.ts +10 -0
  172. package/dist/views/index.js +3 -0
  173. package/dist/views/index.js.map +1 -0
  174. package/dist/{web/plugin → views}/scan-views.js +1 -1
  175. package/dist/views/scan-views.js.map +1 -0
  176. package/dist/views/scan-views.test.d.ts +1 -0
  177. package/dist/views/scan-views.test.js.map +1 -0
  178. package/dist/views/validate-view.d.ts +1 -0
  179. package/dist/{web/plugin → views}/validate-view.js +2 -2
  180. package/dist/views/validate-view.js.map +1 -0
  181. package/dist/views/validate-view.test.d.ts +1 -0
  182. package/dist/views/validate-view.test.js.map +1 -0
  183. package/dist/web/bridges/adaptor.d.ts +51 -0
  184. package/dist/web/bridges/adaptor.js +327 -0
  185. package/dist/web/bridges/adaptor.js.map +1 -0
  186. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  187. package/dist/web/bridges/adaptor.test.js +225 -0
  188. package/dist/web/bridges/adaptor.test.js.map +1 -0
  189. package/dist/web/bridges/apps-sdk/bridge.d.ts +6 -2
  190. package/dist/web/bridges/apps-sdk/bridge.js +15 -4
  191. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  192. package/dist/web/bridges/apps-sdk/index.d.ts +0 -1
  193. package/dist/web/bridges/apps-sdk/index.js +0 -1
  194. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  195. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +1 -1
  196. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +1 -1
  197. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  198. package/dist/web/bridges/get-adaptor.d.ts +4 -4
  199. package/dist/web/bridges/get-adaptor.js +6 -11
  200. package/dist/web/bridges/get-adaptor.js.map +1 -1
  201. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  202. package/dist/web/bridges/get-adaptor.test.js +32 -0
  203. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  204. package/dist/web/bridges/mcp-app/bridge.d.ts +13 -2
  205. package/dist/web/bridges/mcp-app/bridge.js +52 -8
  206. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  207. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  208. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  209. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  210. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  211. package/dist/web/bridges/mcp-app/index.js +0 -1
  212. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  213. package/dist/web/bridges/mcp-app/types.d.ts +2 -0
  214. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  215. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +1 -1
  216. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +1 -1
  217. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  218. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -1
  219. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  220. package/dist/web/bridges/mcp-app/view-tools.test.js +6 -7
  221. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -1
  222. package/dist/web/bridges/types.d.ts +27 -12
  223. package/dist/web/bridges/types.js +14 -1
  224. package/dist/web/bridges/types.js.map +1 -1
  225. package/dist/web/bridges/types.test.d.ts +1 -0
  226. package/dist/web/bridges/types.test.js +19 -0
  227. package/dist/web/bridges/types.test.js.map +1 -0
  228. package/dist/web/components/modal-provider.d.ts +1 -1
  229. package/dist/web/components/modal-provider.js +4 -3
  230. package/dist/web/components/modal-provider.js.map +1 -1
  231. package/dist/web/create-store.test.js +10 -7
  232. package/dist/web/create-store.test.js.map +1 -1
  233. package/dist/web/data-llm.d.ts +1 -1
  234. package/dist/web/data-llm.test.js +20 -7
  235. package/dist/web/data-llm.test.js.map +1 -1
  236. package/dist/web/generate-helpers.d.ts +22 -18
  237. package/dist/web/generate-helpers.js +19 -15
  238. package/dist/web/generate-helpers.js.map +1 -1
  239. package/dist/web/generate-helpers.test-d.js +3 -3
  240. package/dist/web/generate-helpers.test-d.js.map +1 -1
  241. package/dist/web/generate-helpers.test.js +2 -2
  242. package/dist/web/generate-helpers.test.js.map +1 -1
  243. package/dist/web/hooks/index.d.ts +2 -1
  244. package/dist/web/hooks/index.js +2 -1
  245. package/dist/web/hooks/index.js.map +1 -1
  246. package/dist/web/hooks/test/utils.d.ts +2 -1
  247. package/dist/web/hooks/test/utils.js +1 -1
  248. package/dist/web/hooks/test/utils.js.map +1 -1
  249. package/dist/web/hooks/use-call-tool.test.js +39 -25
  250. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  251. package/dist/web/hooks/use-display-mode.d.ts +1 -1
  252. package/dist/web/hooks/use-display-mode.js +1 -1
  253. package/dist/web/hooks/use-display-mode.js.map +1 -1
  254. package/dist/web/hooks/use-display-mode.test.js +57 -21
  255. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  256. package/dist/web/hooks/use-download.d.ts +1 -3
  257. package/dist/web/hooks/use-download.js +1 -2
  258. package/dist/web/hooks/use-download.js.map +1 -1
  259. package/dist/web/hooks/use-download.test.js +18 -10
  260. package/dist/web/hooks/use-download.test.js.map +1 -1
  261. package/dist/web/hooks/use-files.test.js +11 -3
  262. package/dist/web/hooks/use-files.test.js.map +1 -1
  263. package/dist/web/hooks/use-host.d.ts +22 -0
  264. package/dist/web/hooks/use-host.js +30 -0
  265. package/dist/web/hooks/use-host.js.map +1 -0
  266. package/dist/web/hooks/use-host.test.d.ts +1 -0
  267. package/dist/web/hooks/use-host.test.js +59 -0
  268. package/dist/web/hooks/use-host.test.js.map +1 -0
  269. package/dist/web/hooks/use-open-external.test.js +15 -5
  270. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  271. package/dist/web/hooks/use-register-view-tool.d.ts +2 -3
  272. package/dist/web/hooks/use-register-view-tool.js.map +1 -1
  273. package/dist/web/hooks/use-request-close.test.js +35 -40
  274. package/dist/web/hooks/use-request-close.test.js.map +1 -1
  275. package/dist/web/hooks/use-request-modal.test.js +11 -1
  276. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  277. package/dist/web/hooks/use-request-size.d.ts +1 -1
  278. package/dist/web/hooks/use-request-size.js +1 -1
  279. package/dist/web/hooks/use-request-size.js.map +1 -1
  280. package/dist/web/hooks/use-request-size.test.js +35 -53
  281. package/dist/web/hooks/use-request-size.test.js.map +1 -1
  282. package/dist/web/hooks/use-set-open-in-app-url.test.js +26 -12
  283. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  284. package/dist/web/hooks/use-tool-info.d.ts +1 -20
  285. package/dist/web/hooks/use-tool-info.js +0 -1
  286. package/dist/web/hooks/use-tool-info.js.map +1 -1
  287. package/dist/web/hooks/use-tool-info.test-d.js +0 -5
  288. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  289. package/dist/web/hooks/use-tool-info.test.js +38 -33
  290. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  291. package/dist/web/hooks/use-user.d.ts +3 -2
  292. package/dist/web/hooks/use-user.js +4 -3
  293. package/dist/web/hooks/use-user.js.map +1 -1
  294. package/dist/web/hooks/use-user.test.js +85 -37
  295. package/dist/web/hooks/use-user.test.js.map +1 -1
  296. package/dist/web/hooks/use-view-state.js +19 -9
  297. package/dist/web/hooks/use-view-state.js.map +1 -1
  298. package/dist/web/hooks/use-view-state.test.js +39 -4
  299. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  300. package/dist/web/hooks/use-viewport.d.ts +20 -0
  301. package/dist/web/hooks/use-viewport.js +21 -0
  302. package/dist/web/hooks/use-viewport.js.map +1 -0
  303. package/dist/web/hooks/use-viewport.test.d.ts +1 -0
  304. package/dist/web/hooks/use-viewport.test.js +109 -0
  305. package/dist/web/hooks/use-viewport.test.js.map +1 -0
  306. package/dist/web/mount-view.d.ts +3 -2
  307. package/dist/web/mount-view.js +5 -8
  308. package/dist/web/mount-view.js.map +1 -1
  309. package/package.json +31 -28
  310. package/dist/cli/resolve-views-dir.d.ts +0 -1
  311. package/dist/cli/resolve-views-dir.js.map +0 -1
  312. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -29
  313. package/dist/web/bridges/apps-sdk/adaptor.js +0 -117
  314. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  315. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -53
  316. package/dist/web/bridges/mcp-app/adaptor.js +0 -283
  317. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
  318. package/dist/web/hooks/use-layout.d.ts +0 -24
  319. package/dist/web/hooks/use-layout.js +0 -25
  320. package/dist/web/hooks/use-layout.js.map +0 -1
  321. package/dist/web/hooks/use-layout.test.js +0 -96
  322. package/dist/web/hooks/use-layout.test.js.map +0 -1
  323. package/dist/web/plugin/data-llm.test.js +0 -81
  324. package/dist/web/plugin/data-llm.test.js.map +0 -1
  325. package/dist/web/plugin/plugin.d.ts +0 -33
  326. package/dist/web/plugin/plugin.js +0 -189
  327. package/dist/web/plugin/plugin.js.map +0 -1
  328. package/dist/web/plugin/scan-views.js.map +0 -1
  329. package/dist/web/plugin/scan-views.test.js.map +0 -1
  330. package/dist/web/plugin/transform-data-llm.d.ts +0 -12
  331. package/dist/web/plugin/transform-data-llm.js +0 -96
  332. package/dist/web/plugin/transform-data-llm.js.map +0 -1
  333. package/dist/web/plugin/transform-data-llm.test.js +0 -81
  334. package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
  335. package/dist/web/plugin/validate-view.d.ts +0 -1
  336. package/dist/web/plugin/validate-view.js.map +0 -1
  337. package/dist/web/plugin/validate-view.test.js.map +0 -1
  338. /package/dist/{web/hooks/use-layout.test.d.ts → cli/build-steps.test.d.ts} +0 -0
  339. /package/dist/{web/plugin/data-llm.test.d.ts → context-warnings.test.d.ts} +0 -0
  340. /package/dist/{web/plugin/scan-views.test.d.ts → server/app.test.d.ts} +0 -0
  341. /package/dist/{web/plugin/validate-view.test.d.ts → server/auth/providers/authplane.test.d.ts} +0 -0
  342. /package/dist/{web/plugin/transform-data-llm.test.d.ts → server/auth-extra.test-d.d.ts} +0 -0
  343. /package/dist/{web/plugin → views}/scan-views.d.ts +0 -0
  344. /package/dist/{web/plugin → views}/scan-views.test.js +0 -0
  345. /package/dist/{web/plugin → views}/validate-view.test.js +0 -0
@@ -1,21 +1,4 @@
1
1
  import type { UnknownObject } from "../types.js";
2
- /**
3
- * {@link useToolInfo} state before the tool has been invoked.
4
- *
5
- * @deprecated `useToolInfo` no longer returns the idle state — it starts in
6
- * `"pending"` and transitions to `"success"`, so `isIdle` is always `false` at
7
- * runtime. This type is retained in {@link ToolState} for backwards
8
- * compatibility and will be removed in the next major.
9
- */
10
- export type ToolIdleState = {
11
- status: "idle";
12
- isIdle: true;
13
- isPending: false;
14
- isSuccess: false;
15
- input: undefined;
16
- output: undefined;
17
- responseMetadata: undefined;
18
- };
19
2
  /**
20
3
  * {@link useToolInfo} state while the tool is executing — `output` is not yet
21
4
  * available.
@@ -25,7 +8,6 @@ export type ToolIdleState = {
25
8
  */
26
9
  export type ToolPendingState<ToolInput extends UnknownObject> = {
27
10
  status: "pending";
28
- isIdle: false;
29
11
  isPending: true;
30
12
  isSuccess: false;
31
13
  input: ToolInput | undefined;
@@ -40,7 +22,6 @@ export type ToolPendingState<ToolInput extends UnknownObject> = {
40
22
  */
41
23
  export type ToolSuccessState<ToolInput extends UnknownObject, ToolOutput extends UnknownObject, ToolResponseMetadata extends UnknownObject> = {
42
24
  status: "success";
43
- isIdle: false;
44
25
  isPending: false;
45
26
  isSuccess: true;
46
27
  input: ToolInput | undefined;
@@ -51,7 +32,7 @@ export type ToolSuccessState<ToolInput extends UnknownObject, ToolOutput extends
51
32
  * Discriminated union describing the tool invocation that triggered the
52
33
  * current view render. Use `isPending` / `isSuccess` to narrow.
53
34
  */
54
- export type ToolState<ToolInput extends UnknownObject, ToolOutput extends UnknownObject, ToolResponseMetadata extends UnknownObject> = ToolIdleState | ToolPendingState<ToolInput> | ToolSuccessState<ToolInput, ToolOutput, ToolResponseMetadata>;
35
+ export type ToolState<ToolInput extends UnknownObject, ToolOutput extends UnknownObject, ToolResponseMetadata extends UnknownObject> = ToolPendingState<ToolInput> | ToolSuccessState<ToolInput, ToolOutput, ToolResponseMetadata>;
55
36
  type ToolSignature = {
56
37
  input: UnknownObject;
57
38
  output: UnknownObject;
@@ -39,7 +39,6 @@ export function useToolInfo() {
39
39
  return {
40
40
  input: input ?? undefined,
41
41
  status,
42
- isIdle: false,
43
42
  isPending: status === "pending",
44
43
  isSuccess: status === "success",
45
44
  output,
@@ -1 +1 @@
1
- {"version":3,"file":"use-tool-info.js","sourceRoot":"","sources":["../../../src/web/hooks/use-tool-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AA6ErD,SAAS,YAAY,CACnB,MAAsC,EACtC,gBAAgD;IAEhD,IAAI,MAAM,KAAK,IAAI,IAAI,gBAAgB,KAAK,IAAI,EAAE,CAAC;QACjD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,WAAW;IAGzB,MAAM,KAAK,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC;IAC5C,MAAM,gBAAgB,GAAG,cAAc,CAAC,sBAAsB,CAAC,CAAC;IAEhE,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAMtD,OAAO;QACL,KAAK,EAAE,KAAK,IAAI,SAAS;QACzB,MAAM;QACN,MAAM,EAAE,KAAK;QACb,SAAS,EAAE,MAAM,KAAK,SAAS;QAC/B,SAAS,EAAE,MAAM,KAAK,SAAS;QAC/B,MAAM;QACN,gBAAgB;KACqB,CAAC;AAC1C,CAAC","sourcesContent":["import { useHostContext } from \"../bridges/index.js\";\nimport type { UnknownObject } from \"../types.js\";\n\n/**\n * {@link useToolInfo} state before the tool has been invoked.\n *\n * @deprecated `useToolInfo` no longer returns the idle state — it starts in\n * `\"pending\"` and transitions to `\"success\"`, so `isIdle` is always `false` at\n * runtime. This type is retained in {@link ToolState} for backwards\n * compatibility and will be removed in the next major.\n */\nexport type ToolIdleState = {\n status: \"idle\";\n isIdle: true;\n isPending: false;\n isSuccess: false;\n input: undefined;\n output: undefined;\n responseMetadata: undefined;\n};\n\n/**\n * {@link useToolInfo} state while the tool is executing — `output` is not yet\n * available.\n *\n * `input` is optional: the host may render the view before delivering the\n * tool arguments.\n */\nexport type ToolPendingState<ToolInput extends UnknownObject> = {\n status: \"pending\";\n isIdle: false;\n isPending: true;\n isSuccess: false;\n input: ToolInput | undefined;\n output: undefined;\n responseMetadata: undefined;\n};\n\n/**\n * {@link useToolInfo} state once the tool returned — `output` is available.\n *\n * `input` is optional: the host may not have surfaced the tool arguments by\n * the time `output` arrives.\n */\nexport type ToolSuccessState<\n ToolInput extends UnknownObject,\n ToolOutput extends UnknownObject,\n ToolResponseMetadata extends UnknownObject,\n> = {\n status: \"success\";\n isIdle: false;\n isPending: false;\n isSuccess: true;\n input: ToolInput | undefined;\n output: ToolOutput;\n responseMetadata: ToolResponseMetadata;\n};\n\n/**\n * Discriminated union describing the tool invocation that triggered the\n * current view render. Use `isPending` / `isSuccess` to narrow.\n */\nexport type ToolState<\n ToolInput extends UnknownObject,\n ToolOutput extends UnknownObject,\n ToolResponseMetadata extends UnknownObject,\n> =\n | ToolIdleState\n | ToolPendingState<ToolInput>\n | ToolSuccessState<ToolInput, ToolOutput, ToolResponseMetadata>;\n\ntype ToolSignature = {\n input: UnknownObject;\n output: UnknownObject;\n responseMetadata: UnknownObject;\n};\n\nfunction deriveStatus(\n output: Record<string, unknown> | null,\n responseMetadata: Record<string, unknown> | null,\n): \"pending\" | \"success\" {\n if (output === null && responseMetadata === null) {\n return \"pending\";\n }\n return \"success\";\n}\n\n/**\n * Access the tool invocation that produced the current view: its `input`,\n * resulting `output`, and `responseMetadata`. The shape evolves as the tool\n * runs (pending → success), exposed through {@link ToolState}.\n *\n * For full input/output typing per tool name, prefer the typed `useToolInfo`\n * returned by {@link generateHelpers} over the generic form.\n *\n * @typeParam TS - Optional partial shape `{ input, output, responseMetadata }`\n * to refine each field's type. When omitted, each typed field resolves to\n * `never` — pass an explicit shape or use the typed helper from\n * {@link generateHelpers} to get usable types.\n *\n * @example\n * ```tsx\n * const { isSuccess, input, output } = useToolInfo<{\n * input: { query: string };\n * output: { results: Result[] };\n * }>();\n *\n * if (!isSuccess || !output) return <Skeleton />;\n * return <Results items={output.results} />;\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/use-tool-info\n */\nexport function useToolInfo<\n TS extends Partial<ToolSignature> = Record<string, never>,\n>() {\n const input = useHostContext(\"toolInput\");\n const output = useHostContext(\"toolOutput\");\n const responseMetadata = useHostContext(\"toolResponseMetadata\");\n\n const status = deriveStatus(output, responseMetadata);\n\n type Input = UnknownObject & TS[\"input\"];\n type Output = UnknownObject & TS[\"output\"];\n type Metadata = UnknownObject & TS[\"responseMetadata\"];\n\n return {\n input: input ?? undefined,\n status,\n isIdle: false,\n isPending: status === \"pending\",\n isSuccess: status === \"success\",\n output,\n responseMetadata,\n } as ToolState<Input, Output, Metadata>;\n}\n"]}
1
+ {"version":3,"file":"use-tool-info.js","sourceRoot":"","sources":["../../../src/web/hooks/use-tool-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAwDrD,SAAS,YAAY,CACnB,MAAsC,EACtC,gBAAgD;IAEhD,IAAI,MAAM,KAAK,IAAI,IAAI,gBAAgB,KAAK,IAAI,EAAE,CAAC;QACjD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,WAAW;IAGzB,MAAM,KAAK,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC;IAC5C,MAAM,gBAAgB,GAAG,cAAc,CAAC,sBAAsB,CAAC,CAAC;IAEhE,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAMtD,OAAO;QACL,KAAK,EAAE,KAAK,IAAI,SAAS;QACzB,MAAM;QACN,SAAS,EAAE,MAAM,KAAK,SAAS;QAC/B,SAAS,EAAE,MAAM,KAAK,SAAS;QAC/B,MAAM;QACN,gBAAgB;KACqB,CAAC;AAC1C,CAAC","sourcesContent":["import { useHostContext } from \"../bridges/index.js\";\nimport type { UnknownObject } from \"../types.js\";\n\n/**\n * {@link useToolInfo} state while the tool is executing — `output` is not yet\n * available.\n *\n * `input` is optional: the host may render the view before delivering the\n * tool arguments.\n */\nexport type ToolPendingState<ToolInput extends UnknownObject> = {\n status: \"pending\";\n isPending: true;\n isSuccess: false;\n input: ToolInput | undefined;\n output: undefined;\n responseMetadata: undefined;\n};\n\n/**\n * {@link useToolInfo} state once the tool returned — `output` is available.\n *\n * `input` is optional: the host may not have surfaced the tool arguments by\n * the time `output` arrives.\n */\nexport type ToolSuccessState<\n ToolInput extends UnknownObject,\n ToolOutput extends UnknownObject,\n ToolResponseMetadata extends UnknownObject,\n> = {\n status: \"success\";\n isPending: false;\n isSuccess: true;\n input: ToolInput | undefined;\n output: ToolOutput;\n responseMetadata: ToolResponseMetadata;\n};\n\n/**\n * Discriminated union describing the tool invocation that triggered the\n * current view render. Use `isPending` / `isSuccess` to narrow.\n */\nexport type ToolState<\n ToolInput extends UnknownObject,\n ToolOutput extends UnknownObject,\n ToolResponseMetadata extends UnknownObject,\n> =\n | ToolPendingState<ToolInput>\n | ToolSuccessState<ToolInput, ToolOutput, ToolResponseMetadata>;\n\ntype ToolSignature = {\n input: UnknownObject;\n output: UnknownObject;\n responseMetadata: UnknownObject;\n};\n\nfunction deriveStatus(\n output: Record<string, unknown> | null,\n responseMetadata: Record<string, unknown> | null,\n): \"pending\" | \"success\" {\n if (output === null && responseMetadata === null) {\n return \"pending\";\n }\n return \"success\";\n}\n\n/**\n * Access the tool invocation that produced the current view: its `input`,\n * resulting `output`, and `responseMetadata`. The shape evolves as the tool\n * runs (pending → success), exposed through {@link ToolState}.\n *\n * For full input/output typing per tool name, prefer the typed `useToolInfo`\n * returned by {@link generateHelpers} over the generic form.\n *\n * @typeParam TS - Optional partial shape `{ input, output, responseMetadata }`\n * to refine each field's type. When omitted, each typed field resolves to\n * `never` — pass an explicit shape or use the typed helper from\n * {@link generateHelpers} to get usable types.\n *\n * @example\n * ```tsx\n * const { isSuccess, input, output } = useToolInfo<{\n * input: { query: string };\n * output: { results: Result[] };\n * }>();\n *\n * if (!isSuccess || !output) return <Skeleton />;\n * return <Results items={output.results} />;\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/use-tool-info\n */\nexport function useToolInfo<\n TS extends Partial<ToolSignature> = Record<string, never>,\n>() {\n const input = useHostContext(\"toolInput\");\n const output = useHostContext(\"toolOutput\");\n const responseMetadata = useHostContext(\"toolResponseMetadata\");\n\n const status = deriveStatus(output, responseMetadata);\n\n type Input = UnknownObject & TS[\"input\"];\n type Output = UnknownObject & TS[\"output\"];\n type Metadata = UnknownObject & TS[\"responseMetadata\"];\n\n return {\n input: input ?? undefined,\n status,\n isPending: status === \"pending\",\n isSuccess: status === \"success\",\n output,\n responseMetadata,\n } as ToolState<Input, Output, Metadata>;\n}\n"]}
@@ -6,7 +6,6 @@ test("useToolInfo - TypeScript typing", () => {
6
6
  expectTypeOf(result.status);
7
7
  expectTypeOf(result.isPending);
8
8
  expectTypeOf(result.isSuccess);
9
- expectTypeOf(result.isIdle);
10
9
  expectTypeOf(result.input);
11
10
  });
12
11
  test("should correctly type input, output, and responseMetadata with explicit ToolSignature", () => {
@@ -31,7 +30,6 @@ test("useToolInfo - TypeScript typing", () => {
31
30
  // Test type narrowing for pending
32
31
  if (result.isPending) {
33
32
  expectTypeOf(result.status);
34
- expectTypeOf(result.isIdle);
35
33
  expectTypeOf(result.isPending);
36
34
  expectTypeOf(result.isSuccess);
37
35
  expectTypeOf(result.input);
@@ -40,7 +38,6 @@ test("useToolInfo - TypeScript typing", () => {
40
38
  }
41
39
  if (result.isSuccess) {
42
40
  expectTypeOf(result.status);
43
- expectTypeOf(result.isIdle);
44
41
  expectTypeOf(result.isPending);
45
42
  expectTypeOf(result.isSuccess);
46
43
  expectTypeOf(result.input);
@@ -49,7 +46,6 @@ test("useToolInfo - TypeScript typing", () => {
49
46
  }
50
47
  if (result.status === "pending") {
51
48
  expectTypeOf(result.input);
52
- expectTypeOf(result.isIdle);
53
49
  expectTypeOf(result.isPending);
54
50
  expectTypeOf(result.isSuccess);
55
51
  expectTypeOf(result.output);
@@ -57,7 +53,6 @@ test("useToolInfo - TypeScript typing", () => {
57
53
  }
58
54
  if (result.status === "success") {
59
55
  expectTypeOf(result.input);
60
- expectTypeOf(result.isIdle);
61
56
  expectTypeOf(result.isPending);
62
57
  expectTypeOf(result.isSuccess);
63
58
  expectTypeOf(result.output);
@@ -1 +1 @@
1
- {"version":3,"file":"use-tool-info.test-d.js","sourceRoot":"","sources":["../../../src/web/hooks/use-tool-info.test-d.ts"],"names":[],"mappings":"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","sourcesContent":["import { expectTypeOf, test } from \"vitest\";\nimport { useToolInfo } from \"./use-tool-info.js\";\n\ntest(\"useToolInfo - TypeScript typing\", () => {\n test(\"should have correct types when no generic parameter is provided\", () => {\n const result = useToolInfo();\n\n expectTypeOf<\"idle\" | \"pending\" | \"success\">(result.status);\n expectTypeOf<boolean>(result.isPending);\n expectTypeOf<boolean>(result.isSuccess);\n expectTypeOf<boolean>(result.isIdle);\n expectTypeOf<Record<string, unknown> | undefined>(result.input);\n });\n\n test(\"should correctly type input, output, and responseMetadata with explicit ToolSignature\", () => {\n type TestInput = { name: string; args: { name: string } };\n type TestOutput = { name: string; color: string };\n type TestMetadata = { id: number };\n\n const result = useToolInfo<{\n input: TestInput;\n output: TestOutput;\n responseMetadata: TestMetadata;\n }>();\n\n // When pending, input may be undefined (host hasn't delivered args yet,\n // or the tool has no input schema)\n if (result.status === \"pending\") {\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<undefined>(result.output);\n expectTypeOf<undefined>(result.responseMetadata);\n }\n\n // When success, output and responseMetadata are defined; input may still\n // be undefined if the host hasn't surfaced the tool arguments\n if (result.status === \"success\") {\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<TestOutput>(result.output);\n expectTypeOf<TestMetadata>(result.responseMetadata);\n }\n });\n\n test(\"should correctly narrow types based on status discriminated union\", () => {\n type TestInput = { query: string };\n type TestOutput = { result: string };\n type TestMetadata = { timestamp: number };\n\n const result = useToolInfo<{\n input: TestInput;\n output: TestOutput;\n responseMetadata: TestMetadata;\n }>();\n\n // Test type narrowing for pending\n if (result.isPending) {\n expectTypeOf<\"pending\">(result.status);\n expectTypeOf<false>(result.isIdle);\n expectTypeOf<true>(result.isPending);\n expectTypeOf<false>(result.isSuccess);\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<undefined>(result.output);\n expectTypeOf<undefined>(result.responseMetadata);\n }\n\n if (result.isSuccess) {\n expectTypeOf<\"success\">(result.status);\n expectTypeOf<false>(result.isIdle);\n expectTypeOf<false>(result.isPending);\n expectTypeOf<true>(result.isSuccess);\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<TestOutput>(result.output);\n expectTypeOf<TestMetadata>(result.responseMetadata);\n }\n\n if (result.status === \"pending\") {\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<false>(result.isIdle);\n expectTypeOf<true>(result.isPending);\n expectTypeOf<false>(result.isSuccess);\n expectTypeOf<undefined>(result.output);\n expectTypeOf<undefined>(result.responseMetadata);\n }\n\n if (result.status === \"success\") {\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<false>(result.isIdle);\n expectTypeOf<false>(result.isPending);\n expectTypeOf<true>(result.isSuccess);\n expectTypeOf<TestOutput>(result.output);\n expectTypeOf<TestMetadata>(result.responseMetadata);\n }\n });\n\n test(\"should handle partial ToolSignature with only input specified\", () => {\n type TestInput = { id: number };\n\n const result = useToolInfo<{\n input: TestInput;\n }>();\n\n // Input is optional in both states — undefined while args haven't arrived\n // (pending) and for no-input tools (success).\n if (result.status === \"pending\") {\n expectTypeOf<TestInput | undefined>(result.input);\n }\n\n if (result.status === \"success\") {\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<Record<string, unknown>>(result.output);\n expectTypeOf<Record<string, unknown>>(result.responseMetadata);\n }\n });\n\n test(\"should handle ToolSignature with only output specified\", () => {\n type TestOutput = { data: string[] };\n\n const result = useToolInfo<{\n output: TestOutput;\n }>();\n\n if (result.status === \"pending\") {\n expectTypeOf<Record<string, unknown> | undefined>(result.input);\n }\n\n if (result.status === \"success\") {\n expectTypeOf<Record<string, unknown> | undefined>(result.input);\n expectTypeOf<TestOutput>(result.output);\n }\n });\n});\n"]}
1
+ {"version":3,"file":"use-tool-info.test-d.js","sourceRoot":"","sources":["../../../src/web/hooks/use-tool-info.test-d.ts"],"names":[],"mappings":"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","sourcesContent":["import { expectTypeOf, test } from \"vitest\";\nimport { useToolInfo } from \"./use-tool-info.js\";\n\ntest(\"useToolInfo - TypeScript typing\", () => {\n test(\"should have correct types when no generic parameter is provided\", () => {\n const result = useToolInfo();\n\n expectTypeOf<\"pending\" | \"success\">(result.status);\n expectTypeOf<boolean>(result.isPending);\n expectTypeOf<boolean>(result.isSuccess);\n expectTypeOf<Record<string, unknown> | undefined>(result.input);\n });\n\n test(\"should correctly type input, output, and responseMetadata with explicit ToolSignature\", () => {\n type TestInput = { name: string; args: { name: string } };\n type TestOutput = { name: string; color: string };\n type TestMetadata = { id: number };\n\n const result = useToolInfo<{\n input: TestInput;\n output: TestOutput;\n responseMetadata: TestMetadata;\n }>();\n\n // When pending, input may be undefined (host hasn't delivered args yet,\n // or the tool has no input schema)\n if (result.status === \"pending\") {\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<undefined>(result.output);\n expectTypeOf<undefined>(result.responseMetadata);\n }\n\n // When success, output and responseMetadata are defined; input may still\n // be undefined if the host hasn't surfaced the tool arguments\n if (result.status === \"success\") {\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<TestOutput>(result.output);\n expectTypeOf<TestMetadata>(result.responseMetadata);\n }\n });\n\n test(\"should correctly narrow types based on status discriminated union\", () => {\n type TestInput = { query: string };\n type TestOutput = { result: string };\n type TestMetadata = { timestamp: number };\n\n const result = useToolInfo<{\n input: TestInput;\n output: TestOutput;\n responseMetadata: TestMetadata;\n }>();\n\n // Test type narrowing for pending\n if (result.isPending) {\n expectTypeOf<\"pending\">(result.status);\n expectTypeOf<true>(result.isPending);\n expectTypeOf<false>(result.isSuccess);\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<undefined>(result.output);\n expectTypeOf<undefined>(result.responseMetadata);\n }\n\n if (result.isSuccess) {\n expectTypeOf<\"success\">(result.status);\n expectTypeOf<false>(result.isPending);\n expectTypeOf<true>(result.isSuccess);\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<TestOutput>(result.output);\n expectTypeOf<TestMetadata>(result.responseMetadata);\n }\n\n if (result.status === \"pending\") {\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<true>(result.isPending);\n expectTypeOf<false>(result.isSuccess);\n expectTypeOf<undefined>(result.output);\n expectTypeOf<undefined>(result.responseMetadata);\n }\n\n if (result.status === \"success\") {\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<false>(result.isPending);\n expectTypeOf<true>(result.isSuccess);\n expectTypeOf<TestOutput>(result.output);\n expectTypeOf<TestMetadata>(result.responseMetadata);\n }\n });\n\n test(\"should handle partial ToolSignature with only input specified\", () => {\n type TestInput = { id: number };\n\n const result = useToolInfo<{\n input: TestInput;\n }>();\n\n // Input is optional in both states — undefined while args haven't arrived\n // (pending) and for no-input tools (success).\n if (result.status === \"pending\") {\n expectTypeOf<TestInput | undefined>(result.input);\n }\n\n if (result.status === \"success\") {\n expectTypeOf<TestInput | undefined>(result.input);\n expectTypeOf<Record<string, unknown>>(result.output);\n expectTypeOf<Record<string, unknown>>(result.responseMetadata);\n }\n });\n\n test(\"should handle ToolSignature with only output specified\", () => {\n type TestOutput = { data: string[] };\n\n const result = useToolInfo<{\n output: TestOutput;\n }>();\n\n if (result.status === \"pending\") {\n expectTypeOf<Record<string, unknown> | undefined>(result.input);\n }\n\n if (result.status === \"success\") {\n expectTypeOf<Record<string, unknown> | undefined>(result.input);\n expectTypeOf<TestOutput>(result.output);\n }\n });\n});\n"]}
@@ -1,36 +1,45 @@
1
- import { act, fireEvent, renderHook, waitFor } from "@testing-library/react";
1
+ import { act, renderHook, waitFor } from "@testing-library/react";
2
2
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
- import { SET_GLOBALS_EVENT_TYPE, SetGlobalsEvent, } from "../bridges/apps-sdk/index.js";
4
- import { McpAppAdaptor, McpAppBridge } from "../bridges/mcp-app/index.js";
3
+ import { HostAdaptor } from "../bridges/adaptor.js";
4
+ import { McpAppBridge } from "../bridges/mcp-app/index.js";
5
5
  import { fireToolInputNotification, fireToolResultNotification, getMcpAppHostPostMessageMock, MockResizeObserver, } from "./test/utils.js";
6
6
  import { useToolInfo } from "./use-tool-info.js";
7
7
  describe("useToolInfo", () => {
8
8
  describe("apps-sdk host", () => {
9
- let OpenaiMock;
10
9
  beforeEach(() => {
11
- OpenaiMock = {
12
- toolInput: { name: "pokemon", args: { name: "pikachu" } },
10
+ vi.stubGlobal("parent", { postMessage: getMcpAppHostPostMessageMock() });
11
+ vi.stubGlobal("openai", {
12
+ toolInput: null,
13
13
  toolOutput: null,
14
14
  toolResponseMetadata: null,
15
- };
16
- vi.stubGlobal("openai", OpenaiMock);
17
- vi.stubGlobal("skybridge", { hostType: "apps-sdk" });
15
+ });
16
+ vi.stubGlobal("skybridge", {});
17
+ vi.stubGlobal("ResizeObserver", MockResizeObserver);
18
18
  });
19
19
  afterEach(() => {
20
+ HostAdaptor.resetInstance();
20
21
  vi.unstubAllGlobals();
21
22
  vi.resetAllMocks();
23
+ McpAppBridge.resetInstance();
22
24
  });
23
- it("should return toolInput on initial mount window.openai", () => {
25
+ it("should return pending state with tool input from tool-input notification", async () => {
24
26
  const { result } = renderHook(() => useToolInfo());
25
- expect(result.current).toMatchObject({
26
- input: { name: "pokemon", args: { name: "pikachu" } },
27
- status: "pending",
28
- isIdle: false,
29
- isPending: true,
30
- isSuccess: false,
27
+ act(() => {
28
+ fireToolInputNotification({
29
+ name: "pokemon",
30
+ args: { name: "pikachu" },
31
+ });
32
+ });
33
+ await waitFor(() => {
34
+ expect(result.current).toMatchObject({
35
+ input: { name: "pokemon", args: { name: "pikachu" } },
36
+ status: "pending",
37
+ isPending: true,
38
+ isSuccess: false,
39
+ });
31
40
  });
32
41
  });
33
- it("should eventually return tool output and response metadata once tool call completes", async () => {
42
+ it("should return success state once tool-result notification arrives", async () => {
34
43
  const toolOutput = {
35
44
  name: "pikachu",
36
45
  color: "yellow",
@@ -39,21 +48,19 @@ describe("useToolInfo", () => {
39
48
  const toolResponseMetadata = { id: 12 };
40
49
  const { result } = renderHook(() => useToolInfo());
41
50
  act(() => {
42
- OpenaiMock.toolOutput = toolOutput;
43
- OpenaiMock.toolResponseMetadata = toolResponseMetadata;
44
- fireEvent(window, new SetGlobalsEvent(SET_GLOBALS_EVENT_TYPE, {
45
- detail: {
46
- globals: {
47
- toolOutput,
48
- toolResponseMetadata,
49
- },
50
- },
51
- }));
51
+ fireToolInputNotification({
52
+ name: "pokemon",
53
+ args: { name: "pikachu" },
54
+ });
55
+ fireToolResultNotification({
56
+ content: [{ type: "text", text: JSON.stringify(toolOutput) }],
57
+ structuredContent: toolOutput,
58
+ _meta: toolResponseMetadata,
59
+ });
52
60
  });
53
61
  await waitFor(() => {
54
62
  expect(result.current).toMatchObject({
55
63
  status: "success",
56
- isIdle: false,
57
64
  isPending: false,
58
65
  isSuccess: true,
59
66
  output: toolOutput,
@@ -65,21 +72,21 @@ describe("useToolInfo", () => {
65
72
  describe("mcp-app host", () => {
66
73
  beforeEach(() => {
67
74
  vi.stubGlobal("parent", { postMessage: getMcpAppHostPostMessageMock() });
68
- vi.stubGlobal("skybridge", { hostType: "mcp-app" });
75
+ vi.stubGlobal("skybridge", {});
76
+ vi.stubGlobal("openai", undefined);
69
77
  vi.stubGlobal("ResizeObserver", MockResizeObserver);
70
78
  });
71
79
  afterEach(async () => {
80
+ HostAdaptor.resetInstance();
72
81
  vi.unstubAllGlobals();
73
82
  vi.resetAllMocks();
74
83
  McpAppBridge.resetInstance();
75
- McpAppAdaptor.resetInstance();
76
84
  });
77
85
  it("should return pending state with undefined input before tool-input notification arrives", async () => {
78
86
  const { result } = renderHook(() => useToolInfo());
79
87
  await waitFor(() => {
80
88
  expect(result.current).toMatchObject({
81
89
  status: "pending",
82
- isIdle: false,
83
90
  isPending: true,
84
91
  isSuccess: false,
85
92
  input: undefined,
@@ -96,7 +103,6 @@ describe("useToolInfo", () => {
96
103
  await waitFor(() => {
97
104
  expect(result.current).toMatchObject({
98
105
  status: "pending",
99
- isIdle: false,
100
106
  isPending: true,
101
107
  isSuccess: false,
102
108
  input: { name: "pokemon", query: "pikachu" },
@@ -116,7 +122,6 @@ describe("useToolInfo", () => {
116
122
  await waitFor(() => {
117
123
  expect(result.current).toMatchObject({
118
124
  status: "success",
119
- isIdle: false,
120
125
  isPending: false,
121
126
  isSuccess: true,
122
127
  input: { name: "pokemon", query: "pikachu" },
@@ -1 +1 @@
1
- {"version":3,"file":"use-tool-info.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-tool-info.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { act, fireEvent, renderHook, waitFor } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport {\n type AppsSdkContext,\n SET_GLOBALS_EVENT_TYPE,\n SetGlobalsEvent,\n} from \"../bridges/apps-sdk/index.js\";\nimport { McpAppAdaptor, McpAppBridge } from \"../bridges/mcp-app/index.js\";\nimport {\n fireToolInputNotification,\n fireToolResultNotification,\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"./test/utils.js\";\nimport { useToolInfo } from \"./use-tool-info.js\";\n\ndescribe(\"useToolInfo\", () => {\n describe(\"apps-sdk host\", () => {\n let OpenaiMock: Pick<\n AppsSdkContext,\n \"toolInput\" | \"toolOutput\" | \"toolResponseMetadata\"\n >;\n\n beforeEach(() => {\n OpenaiMock = {\n toolInput: { name: \"pokemon\", args: { name: \"pikachu\" } },\n toolOutput: null,\n toolResponseMetadata: null,\n };\n vi.stubGlobal(\"openai\", OpenaiMock);\n vi.stubGlobal(\"skybridge\", { hostType: \"apps-sdk\" });\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n });\n\n it(\"should return toolInput on initial mount window.openai\", () => {\n const { result } = renderHook(() => useToolInfo());\n\n expect(result.current).toMatchObject({\n input: { name: \"pokemon\", args: { name: \"pikachu\" } },\n status: \"pending\",\n isIdle: false,\n isPending: true,\n isSuccess: false,\n });\n });\n\n it(\"should eventually return tool output and response metadata once tool call completes\", async () => {\n const toolOutput = {\n name: \"pikachu\",\n color: \"yellow\",\n description:\n \"When several of these POKéMON gather, their\\felectricity could build and cause lightning storms.\",\n };\n const toolResponseMetadata = { id: 12 };\n const { result } = renderHook(() => useToolInfo());\n\n act(() => {\n OpenaiMock.toolOutput = toolOutput;\n OpenaiMock.toolResponseMetadata = toolResponseMetadata;\n fireEvent(\n window,\n new SetGlobalsEvent(SET_GLOBALS_EVENT_TYPE, {\n detail: {\n globals: {\n toolOutput,\n toolResponseMetadata,\n },\n },\n }),\n );\n });\n\n await waitFor(() => {\n expect(result.current).toMatchObject({\n status: \"success\",\n isIdle: false,\n isPending: false,\n isSuccess: true,\n output: toolOutput,\n responseMetadata: toolResponseMetadata,\n });\n });\n });\n });\n\n describe(\"mcp-app host\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"parent\", { postMessage: getMcpAppHostPostMessageMock() });\n vi.stubGlobal(\"skybridge\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n });\n\n afterEach(async () => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n McpAppBridge.resetInstance();\n McpAppAdaptor.resetInstance();\n });\n\n it(\"should return pending state with undefined input before tool-input notification arrives\", async () => {\n const { result } = renderHook(() => useToolInfo());\n\n await waitFor(() => {\n expect(result.current).toMatchObject({\n status: \"pending\",\n isIdle: false,\n isPending: true,\n isSuccess: false,\n input: undefined,\n output: null,\n responseMetadata: null,\n });\n });\n });\n\n it(\"should return pending state with tool input from tool-input notification\", async () => {\n const { result } = renderHook(() => useToolInfo());\n\n act(() => {\n fireToolInputNotification({ name: \"pokemon\", query: \"pikachu\" });\n });\n\n await waitFor(() => {\n expect(result.current).toMatchObject({\n status: \"pending\",\n isIdle: false,\n isPending: true,\n isSuccess: false,\n input: { name: \"pokemon\", query: \"pikachu\" },\n });\n });\n });\n\n it(\"should return success state with output from tool-result notification\", async () => {\n const { result } = renderHook(() => useToolInfo());\n\n act(() => {\n fireToolInputNotification({ name: \"pokemon\", query: \"pikachu\" });\n fireToolResultNotification({\n content: [{ type: \"text\", text: \"Pikachu data\" }],\n structuredContent: { name: \"pikachu\", color: \"yellow\" },\n _meta: { requestId: \"123\" },\n });\n });\n\n await waitFor(() => {\n expect(result.current).toMatchObject({\n status: \"success\",\n isIdle: false,\n isPending: false,\n isSuccess: true,\n input: { name: \"pokemon\", query: \"pikachu\" },\n output: { name: \"pikachu\", color: \"yellow\" },\n responseMetadata: { requestId: \"123\" },\n });\n });\n });\n });\n});\n"]}
1
+ {"version":3,"file":"use-tool-info.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-tool-info.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { act, 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/index.js\";\nimport {\n fireToolInputNotification,\n fireToolResultNotification,\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"./test/utils.js\";\nimport { useToolInfo } from \"./use-tool-info.js\";\n\ndescribe(\"useToolInfo\", () => {\n describe(\"apps-sdk host\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"parent\", { postMessage: getMcpAppHostPostMessageMock() });\n vi.stubGlobal(\"openai\", {\n toolInput: null,\n toolOutput: null,\n toolResponseMetadata: null,\n });\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n });\n\n afterEach(() => {\n HostAdaptor.resetInstance();\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n McpAppBridge.resetInstance();\n });\n\n it(\"should return pending state with tool input from tool-input notification\", async () => {\n const { result } = renderHook(() => useToolInfo());\n\n act(() => {\n fireToolInputNotification({\n name: \"pokemon\",\n args: { name: \"pikachu\" },\n });\n });\n\n await waitFor(() => {\n expect(result.current).toMatchObject({\n input: { name: \"pokemon\", args: { name: \"pikachu\" } },\n status: \"pending\",\n isPending: true,\n isSuccess: false,\n });\n });\n });\n\n it(\"should return success state once tool-result notification arrives\", async () => {\n const toolOutput = {\n name: \"pikachu\",\n color: \"yellow\",\n description:\n \"When several of these POKéMON gather, their\\felectricity could build and cause lightning storms.\",\n };\n const toolResponseMetadata = { id: 12 };\n const { result } = renderHook(() => useToolInfo());\n\n act(() => {\n fireToolInputNotification({\n name: \"pokemon\",\n args: { name: \"pikachu\" },\n });\n fireToolResultNotification({\n content: [{ type: \"text\", text: JSON.stringify(toolOutput) }],\n structuredContent: toolOutput,\n _meta: toolResponseMetadata,\n });\n });\n\n await waitFor(() => {\n expect(result.current).toMatchObject({\n status: \"success\",\n isPending: false,\n isSuccess: true,\n output: toolOutput,\n responseMetadata: toolResponseMetadata,\n });\n });\n });\n });\n\n describe(\"mcp-app host\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"parent\", { postMessage: getMcpAppHostPostMessageMock() });\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"openai\", undefined);\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n });\n\n afterEach(async () => {\n HostAdaptor.resetInstance();\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n McpAppBridge.resetInstance();\n });\n\n it(\"should return pending state with undefined input before tool-input notification arrives\", async () => {\n const { result } = renderHook(() => useToolInfo());\n\n await waitFor(() => {\n expect(result.current).toMatchObject({\n status: \"pending\",\n isPending: true,\n isSuccess: false,\n input: undefined,\n output: null,\n responseMetadata: null,\n });\n });\n });\n\n it(\"should return pending state with tool input from tool-input notification\", async () => {\n const { result } = renderHook(() => useToolInfo());\n\n act(() => {\n fireToolInputNotification({ name: \"pokemon\", query: \"pikachu\" });\n });\n\n await waitFor(() => {\n expect(result.current).toMatchObject({\n status: \"pending\",\n isPending: true,\n isSuccess: false,\n input: { name: \"pokemon\", query: \"pikachu\" },\n });\n });\n });\n\n it(\"should return success state with output from tool-result notification\", async () => {\n const { result } = renderHook(() => useToolInfo());\n\n act(() => {\n fireToolInputNotification({ name: \"pokemon\", query: \"pikachu\" });\n fireToolResultNotification({\n content: [{ type: \"text\", text: \"Pikachu data\" }],\n structuredContent: { name: \"pikachu\", color: \"yellow\" },\n _meta: { requestId: \"123\" },\n });\n });\n\n await waitFor(() => {\n expect(result.current).toMatchObject({\n status: \"success\",\n isPending: false,\n isSuccess: true,\n input: { name: \"pokemon\", query: \"pikachu\" },\n output: { name: \"pikachu\", color: \"yellow\" },\n responseMetadata: { requestId: \"123\" },\n });\n });\n });\n });\n});\n"]}
@@ -1,6 +1,7 @@
1
- import { type UserAgent } from "../bridges/index.js";
1
+ import { type Theme, type UserAgent } from "../bridges/index.js";
2
2
  export type UserState = {
3
3
  locale: string;
4
+ theme: Theme;
4
5
  userAgent: UserAgent;
5
6
  };
6
7
  /**
@@ -9,7 +10,7 @@ export type UserState = {
9
10
  *
10
11
  * @example
11
12
  * ```tsx
12
- * const { locale, userAgent } = useUser();
13
+ * const { locale, theme, userAgent } = useUser();
13
14
  *
14
15
  * // Access device type
15
16
  * const isMobile = userAgent.device.type === "mobile";
@@ -1,4 +1,4 @@
1
- import { useHostContext } from "../bridges/index.js";
1
+ import { useHostContext, } from "../bridges/index.js";
2
2
  const DEFAULT_LOCALE = "en-US";
3
3
  /**
4
4
  * Normalizes a locale string to canonical BCP 47 format using {@link Intl.Locale}.
@@ -21,7 +21,7 @@ function normalizeLocale(locale) {
21
21
  *
22
22
  * @example
23
23
  * ```tsx
24
- * const { locale, userAgent } = useUser();
24
+ * const { locale, theme, userAgent } = useUser();
25
25
  *
26
26
  * // Access device type
27
27
  * const isMobile = userAgent.device.type === "mobile";
@@ -31,7 +31,8 @@ function normalizeLocale(locale) {
31
31
  */
32
32
  export function useUser() {
33
33
  const rawLocale = useHostContext("locale");
34
+ const theme = useHostContext("theme");
34
35
  const userAgent = useHostContext("userAgent");
35
- return { locale: normalizeLocale(rawLocale), userAgent };
36
+ return { locale: normalizeLocale(rawLocale), theme, userAgent };
36
37
  }
37
38
  //# sourceMappingURL=use-user.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-user.js","sourceRoot":"","sources":["../../../src/web/hooks/use-user.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAOrE,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,MAAc;IACrC,IAAI,CAAC;QACH,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,cAAc,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,OAAO;IACrB,MAAM,SAAS,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAE9C,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,CAAC;AAC3D,CAAC","sourcesContent":["import { type UserAgent, useHostContext } from \"../bridges/index.js\";\n\nexport type UserState = {\n locale: string;\n userAgent: UserAgent;\n};\n\nconst DEFAULT_LOCALE = \"en-US\";\n\n/**\n * Normalizes a locale string to canonical BCP 47 format using {@link Intl.Locale}.\n *\n * Handles underscored identifiers returned by the ChatGPT mobile app (e.g. \"fr_FR\" → \"fr-FR\"),\n * incorrect casing (e.g. \"en-us\" → \"en-US\"), and complex subtags (e.g. \"zh_Hans_CN\" → \"zh-Hans-CN\").\n * Falls back to \"en-US\" if the locale is invalid.\n */\nfunction normalizeLocale(locale: string): string {\n try {\n return new Intl.Locale(locale.replace(/_/g, \"-\")).toString();\n } catch {\n return DEFAULT_LOCALE;\n }\n}\n\n/**\n * Hook for accessing session-stable user information.\n * These values are set once at initialization and do not change during the session.\n *\n * @example\n * ```tsx\n * const { locale, userAgent } = useUser();\n *\n * // Access device type\n * const isMobile = userAgent.device.type === \"mobile\";\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/use-user\n */\nexport function useUser(): UserState {\n const rawLocale = useHostContext(\"locale\");\n const userAgent = useHostContext(\"userAgent\");\n\n return { locale: normalizeLocale(rawLocale), userAgent };\n}\n"]}
1
+ {"version":3,"file":"use-user.js","sourceRoot":"","sources":["../../../src/web/hooks/use-user.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,cAAc,GACf,MAAM,qBAAqB,CAAC;AAQ7B,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,MAAc;IACrC,IAAI,CAAC;QACH,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,cAAc,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,OAAO;IACrB,MAAM,SAAS,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAE9C,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AAClE,CAAC","sourcesContent":["import {\n type Theme,\n type UserAgent,\n useHostContext,\n} from \"../bridges/index.js\";\n\nexport type UserState = {\n locale: string;\n theme: Theme;\n userAgent: UserAgent;\n};\n\nconst DEFAULT_LOCALE = \"en-US\";\n\n/**\n * Normalizes a locale string to canonical BCP 47 format using {@link Intl.Locale}.\n *\n * Handles underscored identifiers returned by the ChatGPT mobile app (e.g. \"fr_FR\" → \"fr-FR\"),\n * incorrect casing (e.g. \"en-us\" → \"en-US\"), and complex subtags (e.g. \"zh_Hans_CN\" → \"zh-Hans-CN\").\n * Falls back to \"en-US\" if the locale is invalid.\n */\nfunction normalizeLocale(locale: string): string {\n try {\n return new Intl.Locale(locale.replace(/_/g, \"-\")).toString();\n } catch {\n return DEFAULT_LOCALE;\n }\n}\n\n/**\n * Hook for accessing session-stable user information.\n * These values are set once at initialization and do not change during the session.\n *\n * @example\n * ```tsx\n * const { locale, theme, userAgent } = useUser();\n *\n * // Access device type\n * const isMobile = userAgent.device.type === \"mobile\";\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/use-user\n */\nexport function useUser(): UserState {\n const rawLocale = useHostContext(\"locale\");\n const theme = useHostContext(\"theme\");\n const userAgent = useHostContext(\"userAgent\");\n\n return { locale: normalizeLocale(rawLocale), theme, userAgent };\n}\n"]}
@@ -1,75 +1,123 @@
1
1
  import { renderHook, waitFor } from "@testing-library/react";
2
2
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
- import { McpAppAdaptor } from "../bridges/mcp-app/adaptor.js";
3
+ import { HostAdaptor } from "../bridges/adaptor.js";
4
4
  import { McpAppBridge } from "../bridges/mcp-app/bridge.js";
5
5
  import { getMcpAppHostPostMessageMock, MockResizeObserver, } from "./test/utils.js";
6
6
  import { useUser } from "./use-user.js";
7
7
  describe("useUser", () => {
8
8
  describe("apps-sdk host type", () => {
9
- let OpenaiMock;
10
9
  beforeEach(() => {
11
- OpenaiMock = {
12
- locale: "en-US",
13
- userAgent: {
14
- device: { type: "desktop" },
15
- capabilities: { hover: true, touch: false },
16
- },
17
- };
18
- vi.stubGlobal("openai", OpenaiMock);
19
- vi.stubGlobal("skybridge", { hostType: "apps-sdk" });
10
+ HostAdaptor.resetInstance();
11
+ McpAppBridge.resetInstance();
12
+ vi.stubGlobal("openai", { locale: "en-US" });
13
+ vi.stubGlobal("skybridge", {});
14
+ vi.stubGlobal("ResizeObserver", MockResizeObserver);
20
15
  });
21
16
  afterEach(() => {
22
17
  vi.unstubAllGlobals();
23
18
  vi.resetAllMocks();
19
+ McpAppBridge.resetInstance();
20
+ HostAdaptor.resetInstance();
24
21
  });
25
- it("should return locale and userAgent from window.openai", () => {
22
+ it("should return locale, theme and userAgent from mcp host context", async () => {
23
+ vi.stubGlobal("parent", {
24
+ postMessage: getMcpAppHostPostMessageMock({
25
+ locale: "en-US",
26
+ theme: "dark",
27
+ platform: "web",
28
+ deviceCapabilities: { hover: true, touch: false },
29
+ }),
30
+ });
26
31
  const { result } = renderHook(() => useUser());
27
- expect(result.current.locale).toBe("en-US");
28
- expect(result.current.userAgent).toEqual({
29
- device: { type: "desktop" },
30
- capabilities: { hover: true, touch: false },
32
+ await waitFor(() => {
33
+ expect(result.current.locale).toBe("en-US");
34
+ expect(result.current.theme).toBe("dark");
35
+ expect(result.current.userAgent).toEqual({
36
+ device: { type: "desktop" },
37
+ capabilities: { hover: true, touch: false },
38
+ });
31
39
  });
32
40
  });
33
- it("should return mobile userAgent when set to mobile", () => {
34
- OpenaiMock.userAgent = {
35
- device: { type: "mobile" },
36
- capabilities: { hover: false, touch: true },
37
- };
41
+ it("should return mobile userAgent when set to mobile", async () => {
42
+ vi.stubGlobal("parent", {
43
+ postMessage: getMcpAppHostPostMessageMock({
44
+ locale: "en-US",
45
+ platform: "mobile",
46
+ deviceCapabilities: { hover: false, touch: true },
47
+ }),
48
+ });
38
49
  const { result } = renderHook(() => useUser());
39
- expect(result.current.userAgent.device.type).toBe("mobile");
40
- expect(result.current.userAgent.capabilities.touch).toBe(true);
50
+ await waitFor(() => {
51
+ expect(result.current.userAgent.device.type).toBe("mobile");
52
+ expect(result.current.userAgent.capabilities.touch).toBe(true);
53
+ });
41
54
  });
42
- it("should return different locale when set", () => {
43
- OpenaiMock.locale = "es-ES";
55
+ it("should return different locale when set", async () => {
56
+ vi.stubGlobal("parent", {
57
+ postMessage: getMcpAppHostPostMessageMock({
58
+ locale: "es-ES",
59
+ platform: "web",
60
+ deviceCapabilities: { hover: true, touch: false },
61
+ }),
62
+ });
44
63
  const { result } = renderHook(() => useUser());
45
- expect(result.current.locale).toBe("es-ES");
64
+ await waitFor(() => {
65
+ expect(result.current.locale).toBe("es-ES");
66
+ });
46
67
  });
47
- it("should normalize underscore locale to BCP 47 hyphen format", () => {
48
- OpenaiMock.locale = "fr_FR";
68
+ it("should normalize underscore locale to BCP 47 hyphen format", async () => {
69
+ vi.stubGlobal("parent", {
70
+ postMessage: getMcpAppHostPostMessageMock({
71
+ locale: "fr_FR",
72
+ platform: "web",
73
+ deviceCapabilities: { hover: true, touch: false },
74
+ }),
75
+ });
49
76
  const { result } = renderHook(() => useUser());
50
- expect(result.current.locale).toBe("fr-FR");
77
+ await waitFor(() => {
78
+ expect(result.current.locale).toBe("fr-FR");
79
+ });
51
80
  });
52
- it("should canonicalize locale casing", () => {
53
- OpenaiMock.locale = "en-us";
81
+ it("should canonicalize locale casing", async () => {
82
+ vi.stubGlobal("parent", {
83
+ postMessage: getMcpAppHostPostMessageMock({
84
+ locale: "en-us",
85
+ platform: "web",
86
+ deviceCapabilities: { hover: true, touch: false },
87
+ }),
88
+ });
54
89
  const { result } = renderHook(() => useUser());
55
- expect(result.current.locale).toBe("en-US");
90
+ await waitFor(() => {
91
+ expect(result.current.locale).toBe("en-US");
92
+ });
56
93
  });
57
- it("should fall back to en-US for invalid locale", () => {
58
- OpenaiMock.locale = "not-a-locale-!!";
94
+ it("should fall back to en-US for invalid locale", async () => {
95
+ vi.stubGlobal("parent", {
96
+ postMessage: getMcpAppHostPostMessageMock({
97
+ locale: "not-a-locale-!!",
98
+ platform: "web",
99
+ deviceCapabilities: { hover: true, touch: false },
100
+ }),
101
+ });
59
102
  const { result } = renderHook(() => useUser());
60
- expect(result.current.locale).toBe("en-US");
103
+ await waitFor(() => {
104
+ expect(result.current.locale).toBe("en-US");
105
+ });
61
106
  });
62
107
  });
63
108
  describe("mcp-app host type", () => {
64
109
  beforeEach(() => {
65
- vi.stubGlobal("skybridge", { hostType: "mcp-app" });
110
+ HostAdaptor.resetInstance();
111
+ McpAppBridge.resetInstance();
112
+ vi.stubGlobal("openai", undefined);
113
+ vi.stubGlobal("skybridge", {});
66
114
  vi.stubGlobal("ResizeObserver", MockResizeObserver);
67
115
  });
68
116
  afterEach(async () => {
69
117
  vi.unstubAllGlobals();
70
118
  vi.resetAllMocks();
71
119
  McpAppBridge.resetInstance();
72
- McpAppAdaptor.resetInstance();
120
+ HostAdaptor.resetInstance();
73
121
  });
74
122
  it("should return locale and userAgent from mcp host context", async () => {
75
123
  vi.stubGlobal("parent", {