skybridge 0.0.0-dev.94e2024 → 0.0.0-dev.9520814

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 (396) hide show
  1. package/README.md +10 -7
  2. package/dist/cli/build-helpers.d.ts +11 -0
  3. package/dist/cli/build-helpers.js +107 -0
  4. package/dist/cli/build-helpers.js.map +1 -0
  5. package/dist/cli/build-helpers.test.js +132 -0
  6. package/dist/cli/build-helpers.test.js.map +1 -0
  7. package/dist/cli/build-steps.d.ts +2 -0
  8. package/dist/cli/build-steps.js +73 -0
  9. package/dist/cli/build-steps.js.map +1 -0
  10. package/dist/cli/build-steps.test.js +52 -0
  11. package/dist/cli/build-steps.test.js.map +1 -0
  12. package/dist/cli/detect-port.d.ts +2 -2
  13. package/dist/cli/detect-port.js +8 -20
  14. package/dist/cli/detect-port.js.map +1 -1
  15. package/dist/cli/header.d.ts +1 -1
  16. package/dist/cli/resolve-skybridge-config.d.ts +5 -0
  17. package/dist/cli/resolve-skybridge-config.js +18 -0
  18. package/dist/cli/resolve-skybridge-config.js.map +1 -0
  19. package/dist/cli/run-plain.d.ts +18 -0
  20. package/dist/cli/run-plain.js +90 -0
  21. package/dist/cli/run-plain.js.map +1 -0
  22. package/dist/cli/telemetry.js +2 -0
  23. package/dist/cli/telemetry.js.map +1 -1
  24. package/dist/cli/use-execute-steps.d.ts +1 -1
  25. package/dist/cli/use-nodemon.d.ts +25 -1
  26. package/dist/cli/use-nodemon.js +96 -63
  27. package/dist/cli/use-nodemon.js.map +1 -1
  28. package/dist/cli/use-typescript-check.d.ts +8 -2
  29. package/dist/cli/use-typescript-check.js +70 -67
  30. package/dist/cli/use-typescript-check.js.map +1 -1
  31. package/dist/commands/build.d.ts +0 -3
  32. package/dist/commands/build.js +2 -73
  33. package/dist/commands/build.js.map +1 -1
  34. package/dist/commands/dev.d.ts +1 -0
  35. package/dist/commands/dev.js +51 -3
  36. package/dist/commands/dev.js.map +1 -1
  37. package/dist/commands/start.js +7 -1
  38. package/dist/commands/start.js.map +1 -1
  39. package/dist/context-warnings.d.ts +5 -0
  40. package/dist/context-warnings.js +31 -0
  41. package/dist/context-warnings.js.map +1 -0
  42. package/dist/context-warnings.test.js +28 -0
  43. package/dist/context-warnings.test.js.map +1 -0
  44. package/dist/server/app.d.ts +194 -0
  45. package/dist/server/app.js +266 -0
  46. package/dist/server/app.js.map +1 -0
  47. package/dist/server/app.test.js +97 -0
  48. package/dist/server/app.test.js.map +1 -0
  49. package/dist/server/auth/discovery.d.ts +33 -0
  50. package/dist/server/auth/discovery.js +56 -0
  51. package/dist/server/auth/discovery.js.map +1 -0
  52. package/dist/server/auth/discovery.test.d.ts +1 -0
  53. package/dist/server/auth/discovery.test.js +93 -0
  54. package/dist/server/auth/discovery.test.js.map +1 -0
  55. package/dist/server/auth/index.d.ts +48 -0
  56. package/dist/server/auth/index.js +2 -0
  57. package/dist/server/auth/index.js.map +1 -0
  58. package/dist/server/auth/providers/auth0.d.ts +40 -0
  59. package/dist/server/auth/providers/auth0.js +36 -0
  60. package/dist/server/auth/providers/auth0.js.map +1 -0
  61. package/dist/server/auth/providers/auth0.test.d.ts +1 -0
  62. package/dist/server/auth/providers/auth0.test.js +50 -0
  63. package/dist/server/auth/providers/auth0.test.js.map +1 -0
  64. package/dist/server/auth/providers/authplane.d.ts +49 -0
  65. package/dist/server/auth/providers/authplane.js +57 -0
  66. package/dist/server/auth/providers/authplane.js.map +1 -0
  67. package/dist/server/auth/providers/authplane.test.d.ts +1 -0
  68. package/dist/server/auth/providers/authplane.test.js +143 -0
  69. package/dist/server/auth/providers/authplane.test.js.map +1 -0
  70. package/dist/server/auth/providers/clerk.d.ts +51 -0
  71. package/dist/server/auth/providers/clerk.js +19 -0
  72. package/dist/server/auth/providers/clerk.js.map +1 -0
  73. package/dist/server/auth/providers/clerk.test.d.ts +1 -0
  74. package/dist/server/auth/providers/clerk.test.js +30 -0
  75. package/dist/server/auth/providers/clerk.test.js.map +1 -0
  76. package/dist/server/auth/providers/custom.d.ts +42 -0
  77. package/dist/server/auth/providers/custom.js +59 -0
  78. package/dist/server/auth/providers/custom.js.map +1 -0
  79. package/dist/server/auth/providers/custom.test.d.ts +1 -0
  80. package/dist/server/auth/providers/custom.test.js +161 -0
  81. package/dist/server/auth/providers/custom.test.js.map +1 -0
  82. package/dist/server/auth/providers/descope.d.ts +44 -0
  83. package/dist/server/auth/providers/descope.js +44 -0
  84. package/dist/server/auth/providers/descope.js.map +1 -0
  85. package/dist/server/auth/providers/descope.test.d.ts +1 -0
  86. package/dist/server/auth/providers/descope.test.js +62 -0
  87. package/dist/server/auth/providers/descope.test.js.map +1 -0
  88. package/dist/server/auth/providers/shared.d.ts +2 -0
  89. package/dist/server/auth/providers/shared.js +6 -0
  90. package/dist/server/auth/providers/shared.js.map +1 -0
  91. package/dist/server/auth/providers/shared.test.d.ts +1 -0
  92. package/dist/server/auth/providers/shared.test.js +10 -0
  93. package/dist/server/auth/providers/shared.test.js.map +1 -0
  94. package/dist/server/auth/providers/stytch.d.ts +25 -0
  95. package/dist/server/auth/providers/stytch.js +16 -0
  96. package/dist/server/auth/providers/stytch.js.map +1 -0
  97. package/dist/server/auth/providers/verify-spy.d.ts +12 -0
  98. package/dist/server/auth/providers/verify-spy.js +21 -0
  99. package/dist/server/auth/providers/verify-spy.js.map +1 -0
  100. package/dist/server/auth/providers/workos.d.ts +34 -0
  101. package/dist/server/auth/providers/workos.js +16 -0
  102. package/dist/server/auth/providers/workos.js.map +1 -0
  103. package/dist/server/auth/security-schemes.d.ts +23 -0
  104. package/dist/server/auth/security-schemes.js +64 -0
  105. package/dist/server/auth/security-schemes.js.map +1 -0
  106. package/dist/server/auth/security-schemes.test.d.ts +1 -0
  107. package/dist/server/auth/security-schemes.test.js +99 -0
  108. package/dist/server/auth/security-schemes.test.js.map +1 -0
  109. package/dist/server/auth/setup.d.ts +6 -0
  110. package/dist/server/auth/setup.js +91 -0
  111. package/dist/server/auth/setup.js.map +1 -0
  112. package/dist/server/auth/setup.test.d.ts +1 -0
  113. package/dist/server/auth/setup.test.js +514 -0
  114. package/dist/server/auth/setup.test.js.map +1 -0
  115. package/dist/server/auth/verify.d.ts +48 -0
  116. package/dist/server/auth/verify.js +62 -0
  117. package/dist/server/auth/verify.js.map +1 -0
  118. package/dist/server/auth/verify.test.d.ts +1 -0
  119. package/dist/server/auth/verify.test.js +165 -0
  120. package/dist/server/auth/verify.test.js.map +1 -0
  121. package/dist/server/auth-extra.test-d.js +130 -0
  122. package/dist/server/auth-extra.test-d.js.map +1 -0
  123. package/dist/server/auth.d.ts +43 -6
  124. package/dist/server/auth.js +4 -5
  125. package/dist/server/auth.js.map +1 -1
  126. package/dist/server/build-manifest.test.d.ts +1 -0
  127. package/dist/server/build-manifest.test.js +28 -0
  128. package/dist/server/build-manifest.test.js.map +1 -0
  129. package/dist/server/content-helpers.d.ts +1 -1
  130. package/dist/server/content-helpers.js.map +1 -1
  131. package/dist/server/express.d.ts +23 -3
  132. package/dist/server/express.js +38 -32
  133. package/dist/server/express.js.map +1 -1
  134. package/dist/server/express.test.js +268 -90
  135. package/dist/server/express.test.js.map +1 -1
  136. package/dist/server/file-ref.d.ts +1 -1
  137. package/dist/server/file-ref.js +1 -1
  138. package/dist/server/file-ref.js.map +1 -1
  139. package/dist/server/host.d.ts +2 -0
  140. package/dist/server/host.js +11 -0
  141. package/dist/server/host.js.map +1 -0
  142. package/dist/server/host.test.d.ts +1 -0
  143. package/dist/server/host.test.js +13 -0
  144. package/dist/server/host.test.js.map +1 -0
  145. package/dist/server/index.d.ts +17 -3
  146. package/dist/server/index.js +14 -2
  147. package/dist/server/index.js.map +1 -1
  148. package/dist/server/mcp-errors.test.d.ts +1 -0
  149. package/dist/server/mcp-errors.test.js +41 -0
  150. package/dist/server/mcp-errors.test.js.map +1 -0
  151. package/dist/server/middleware.d.ts +35 -10
  152. package/dist/server/middleware.js +33 -0
  153. package/dist/server/middleware.js.map +1 -1
  154. package/dist/server/middleware.test-d.js +1 -1
  155. package/dist/server/middleware.test-d.js.map +1 -1
  156. package/dist/server/middleware.test.js +242 -134
  157. package/dist/server/middleware.test.js.map +1 -1
  158. package/dist/server/register-tool.test.d.ts +1 -0
  159. package/dist/server/register-tool.test.js +110 -0
  160. package/dist/server/register-tool.test.js.map +1 -0
  161. package/dist/server/requestOrigin.d.ts +7 -0
  162. package/dist/server/requestOrigin.js +25 -0
  163. package/dist/server/requestOrigin.js.map +1 -0
  164. package/dist/server/server.d.ts +257 -122
  165. package/dist/server/server.js +390 -330
  166. package/dist/server/server.js.map +1 -1
  167. package/dist/server/skills-integration.test.d.ts +1 -0
  168. package/dist/server/skills-integration.test.js +86 -0
  169. package/dist/server/skills-integration.test.js.map +1 -0
  170. package/dist/server/skills.d.ts +27 -0
  171. package/dist/server/skills.js +188 -0
  172. package/dist/server/skills.js.map +1 -0
  173. package/dist/server/skills.test.d.ts +1 -0
  174. package/dist/server/skills.test.js +243 -0
  175. package/dist/server/skills.test.js.map +1 -0
  176. package/dist/server/templateHelper.d.ts +0 -3
  177. package/dist/server/templateHelper.js.map +1 -1
  178. package/dist/server/templates.generated.js +4 -8
  179. package/dist/server/templates.generated.js.map +1 -1
  180. package/dist/server/tool-extra.test.d.ts +1 -0
  181. package/dist/server/tool-extra.test.js +88 -0
  182. package/dist/server/tool-extra.test.js.map +1 -0
  183. package/dist/server/view-name.test-d.d.ts +1 -0
  184. package/dist/server/view-name.test-d.js +8 -0
  185. package/dist/server/view-name.test-d.js.map +1 -0
  186. package/dist/server/view-resource-resolution.test.d.ts +6 -0
  187. package/dist/server/view-resource-resolution.test.js +176 -0
  188. package/dist/server/view-resource-resolution.test.js.map +1 -0
  189. package/dist/server/viewsDevServer.js +4 -1
  190. package/dist/server/viewsDevServer.js.map +1 -1
  191. package/dist/test/utils.d.ts +9 -11
  192. package/dist/test/utils.js +220 -201
  193. package/dist/test/utils.js.map +1 -1
  194. package/dist/test/view.test.js +105 -133
  195. package/dist/test/view.test.js.map +1 -1
  196. package/dist/views/index.d.ts +10 -0
  197. package/dist/views/index.js +3 -0
  198. package/dist/views/index.js.map +1 -0
  199. package/dist/{web/plugin → views}/scan-views.js +1 -1
  200. package/dist/views/scan-views.js.map +1 -0
  201. package/dist/views/scan-views.test.d.ts +1 -0
  202. package/dist/views/scan-views.test.js.map +1 -0
  203. package/dist/views/validate-view.d.ts +1 -0
  204. package/dist/{web/plugin → views}/validate-view.js +2 -2
  205. package/dist/views/validate-view.js.map +1 -0
  206. package/dist/views/validate-view.test.d.ts +1 -0
  207. package/dist/views/validate-view.test.js.map +1 -0
  208. package/dist/web/bridges/adaptor.d.ts +61 -0
  209. package/dist/web/bridges/adaptor.js +476 -0
  210. package/dist/web/bridges/adaptor.js.map +1 -0
  211. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  212. package/dist/web/bridges/adaptor.test.js +264 -0
  213. package/dist/web/bridges/adaptor.test.js.map +1 -0
  214. package/dist/web/bridges/apps-sdk/bridge.d.ts +6 -2
  215. package/dist/web/bridges/apps-sdk/bridge.js +15 -4
  216. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  217. package/dist/web/bridges/apps-sdk/index.d.ts +0 -1
  218. package/dist/web/bridges/apps-sdk/index.js +0 -1
  219. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  220. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +1 -1
  221. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +1 -1
  222. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  223. package/dist/web/bridges/get-adaptor.d.ts +4 -4
  224. package/dist/web/bridges/get-adaptor.js +6 -11
  225. package/dist/web/bridges/get-adaptor.js.map +1 -1
  226. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  227. package/dist/web/bridges/get-adaptor.test.js +32 -0
  228. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  229. package/dist/web/bridges/mcp-app/bridge.d.ts +15 -3
  230. package/dist/web/bridges/mcp-app/bridge.js +80 -8
  231. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  232. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  233. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  234. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  235. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  236. package/dist/web/bridges/mcp-app/index.js +0 -1
  237. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  238. package/dist/web/bridges/mcp-app/types.d.ts +19 -2
  239. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  240. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +2 -2
  241. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +1 -1
  242. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  243. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -1
  244. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  245. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  246. package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
  247. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  248. package/dist/web/bridges/types.d.ts +113 -9
  249. package/dist/web/bridges/types.js +14 -1
  250. package/dist/web/bridges/types.js.map +1 -1
  251. package/dist/web/bridges/types.test.d.ts +1 -0
  252. package/dist/web/bridges/types.test.js +19 -0
  253. package/dist/web/bridges/types.test.js.map +1 -0
  254. package/dist/web/components/modal-provider.d.ts +1 -1
  255. package/dist/web/components/modal-provider.js +4 -3
  256. package/dist/web/components/modal-provider.js.map +1 -1
  257. package/dist/web/create-store.test.js +10 -7
  258. package/dist/web/create-store.test.js.map +1 -1
  259. package/dist/web/data-llm.d.ts +1 -1
  260. package/dist/web/data-llm.js +3 -2
  261. package/dist/web/data-llm.js.map +1 -1
  262. package/dist/web/data-llm.test.js +26 -7
  263. package/dist/web/data-llm.test.js.map +1 -1
  264. package/dist/web/generate-helpers.d.ts +23 -19
  265. package/dist/web/generate-helpers.js +21 -17
  266. package/dist/web/generate-helpers.js.map +1 -1
  267. package/dist/web/generate-helpers.test-d.js +7 -5
  268. package/dist/web/generate-helpers.test-d.js.map +1 -1
  269. package/dist/web/generate-helpers.test.js +2 -2
  270. package/dist/web/generate-helpers.test.js.map +1 -1
  271. package/dist/web/hooks/index.d.ts +7 -1
  272. package/dist/web/hooks/index.js +7 -1
  273. package/dist/web/hooks/index.js.map +1 -1
  274. package/dist/web/hooks/openai-extensions.test.d.ts +1 -0
  275. package/dist/web/hooks/openai-extensions.test.js +107 -0
  276. package/dist/web/hooks/openai-extensions.test.js.map +1 -0
  277. package/dist/web/hooks/test/utils.d.ts +2 -1
  278. package/dist/web/hooks/test/utils.js +1 -1
  279. package/dist/web/hooks/test/utils.js.map +1 -1
  280. package/dist/web/hooks/use-call-tool.d.ts +2 -2
  281. package/dist/web/hooks/use-call-tool.js +15 -10
  282. package/dist/web/hooks/use-call-tool.js.map +1 -1
  283. package/dist/web/hooks/use-call-tool.test.js +50 -25
  284. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  285. package/dist/web/hooks/use-deep-link.d.ts +22 -0
  286. package/dist/web/hooks/use-deep-link.js +34 -0
  287. package/dist/web/hooks/use-deep-link.js.map +1 -0
  288. package/dist/web/hooks/use-display-mode.d.ts +1 -1
  289. package/dist/web/hooks/use-display-mode.js +1 -1
  290. package/dist/web/hooks/use-display-mode.js.map +1 -1
  291. package/dist/web/hooks/use-display-mode.test.js +57 -21
  292. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  293. package/dist/web/hooks/use-download.d.ts +1 -3
  294. package/dist/web/hooks/use-download.js +1 -2
  295. package/dist/web/hooks/use-download.js.map +1 -1
  296. package/dist/web/hooks/use-download.test.js +18 -10
  297. package/dist/web/hooks/use-download.test.js.map +1 -1
  298. package/dist/web/hooks/use-file-resource.d.ts +37 -0
  299. package/dist/web/hooks/use-file-resource.js +101 -0
  300. package/dist/web/hooks/use-file-resource.js.map +1 -0
  301. package/dist/web/hooks/use-file-resource.test.d.ts +1 -0
  302. package/dist/web/hooks/use-file-resource.test.js +65 -0
  303. package/dist/web/hooks/use-file-resource.test.js.map +1 -0
  304. package/dist/web/hooks/use-files.test.js +11 -3
  305. package/dist/web/hooks/use-files.test.js.map +1 -1
  306. package/dist/web/hooks/use-host.d.ts +44 -0
  307. package/dist/web/hooks/use-host.js +45 -0
  308. package/dist/web/hooks/use-host.js.map +1 -0
  309. package/dist/web/hooks/use-host.test.d.ts +1 -0
  310. package/dist/web/hooks/use-host.test.js +59 -0
  311. package/dist/web/hooks/use-host.test.js.map +1 -0
  312. package/dist/web/hooks/use-model-context.d.ts +44 -0
  313. package/dist/web/hooks/use-model-context.js +63 -0
  314. package/dist/web/hooks/use-model-context.js.map +1 -0
  315. package/dist/web/hooks/use-open-external.test.js +15 -5
  316. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  317. package/dist/web/hooks/use-open-file.d.ts +19 -0
  318. package/dist/web/hooks/use-open-file.js +24 -0
  319. package/dist/web/hooks/use-open-file.js.map +1 -0
  320. package/dist/web/hooks/use-register-view-tool.d.ts +37 -0
  321. package/dist/web/hooks/use-register-view-tool.js +50 -0
  322. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  323. package/dist/web/hooks/use-request-close.test.js +35 -40
  324. package/dist/web/hooks/use-request-close.test.js.map +1 -1
  325. package/dist/web/hooks/use-request-modal.test.js +11 -1
  326. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  327. package/dist/web/hooks/use-request-size.d.ts +1 -1
  328. package/dist/web/hooks/use-request-size.js +1 -1
  329. package/dist/web/hooks/use-request-size.js.map +1 -1
  330. package/dist/web/hooks/use-request-size.test.js +35 -53
  331. package/dist/web/hooks/use-request-size.test.js.map +1 -1
  332. package/dist/web/hooks/use-send-follow-up-message.d.ts +8 -2
  333. package/dist/web/hooks/use-send-follow-up-message.js +6 -0
  334. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  335. package/dist/web/hooks/use-set-open-in-app-url.test.js +26 -12
  336. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  337. package/dist/web/hooks/use-tool-info.d.ts +18 -19
  338. package/dist/web/hooks/use-tool-info.js +4 -8
  339. package/dist/web/hooks/use-tool-info.js.map +1 -1
  340. package/dist/web/hooks/use-tool-info.test-d.js +11 -34
  341. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  342. package/dist/web/hooks/use-tool-info.test.js +42 -37
  343. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  344. package/dist/web/hooks/use-user.d.ts +3 -2
  345. package/dist/web/hooks/use-user.js +4 -3
  346. package/dist/web/hooks/use-user.js.map +1 -1
  347. package/dist/web/hooks/use-user.test.js +85 -37
  348. package/dist/web/hooks/use-user.test.js.map +1 -1
  349. package/dist/web/hooks/use-view-state.js +19 -9
  350. package/dist/web/hooks/use-view-state.js.map +1 -1
  351. package/dist/web/hooks/use-view-state.test.js +39 -4
  352. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  353. package/dist/web/hooks/use-viewport.d.ts +20 -0
  354. package/dist/web/hooks/use-viewport.js +21 -0
  355. package/dist/web/hooks/use-viewport.js.map +1 -0
  356. package/dist/web/hooks/use-viewport.test.d.ts +1 -0
  357. package/dist/web/hooks/use-viewport.test.js +109 -0
  358. package/dist/web/hooks/use-viewport.test.js.map +1 -0
  359. package/dist/web/mount-view.d.ts +3 -2
  360. package/dist/web/mount-view.js +5 -8
  361. package/dist/web/mount-view.js.map +1 -1
  362. package/package.json +28 -22
  363. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -28
  364. package/dist/web/bridges/apps-sdk/adaptor.js +0 -113
  365. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  366. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -52
  367. package/dist/web/bridges/mcp-app/adaptor.js +0 -280
  368. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
  369. package/dist/web/hooks/use-layout.d.ts +0 -24
  370. package/dist/web/hooks/use-layout.js +0 -25
  371. package/dist/web/hooks/use-layout.js.map +0 -1
  372. package/dist/web/hooks/use-layout.test.js +0 -96
  373. package/dist/web/hooks/use-layout.test.js.map +0 -1
  374. package/dist/web/plugin/data-llm.test.js +0 -81
  375. package/dist/web/plugin/data-llm.test.js.map +0 -1
  376. package/dist/web/plugin/plugin.d.ts +0 -33
  377. package/dist/web/plugin/plugin.js +0 -189
  378. package/dist/web/plugin/plugin.js.map +0 -1
  379. package/dist/web/plugin/scan-views.js.map +0 -1
  380. package/dist/web/plugin/scan-views.test.js.map +0 -1
  381. package/dist/web/plugin/transform-data-llm.d.ts +0 -12
  382. package/dist/web/plugin/transform-data-llm.js +0 -96
  383. package/dist/web/plugin/transform-data-llm.js.map +0 -1
  384. package/dist/web/plugin/transform-data-llm.test.js +0 -81
  385. package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
  386. package/dist/web/plugin/validate-view.d.ts +0 -1
  387. package/dist/web/plugin/validate-view.js.map +0 -1
  388. package/dist/web/plugin/validate-view.test.js.map +0 -1
  389. /package/dist/{web/hooks/use-layout.test.d.ts → cli/build-helpers.test.d.ts} +0 -0
  390. /package/dist/{web/plugin/data-llm.test.d.ts → cli/build-steps.test.d.ts} +0 -0
  391. /package/dist/{web/plugin/scan-views.test.d.ts → context-warnings.test.d.ts} +0 -0
  392. /package/dist/{web/plugin/transform-data-llm.test.d.ts → server/app.test.d.ts} +0 -0
  393. /package/dist/{web/plugin/validate-view.test.d.ts → server/auth-extra.test-d.d.ts} +0 -0
  394. /package/dist/{web/plugin → views}/scan-views.d.ts +0 -0
  395. /package/dist/{web/plugin → views}/scan-views.test.js +0 -0
  396. /package/dist/{web/plugin → views}/validate-view.test.js +0 -0
@@ -0,0 +1,264 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { VIEW_STATE_WARNING_TOKENS } from "../../context-warnings.js";
3
+ import { HostAdaptor } from "./adaptor.js";
4
+ import { AppsSdkBridge } from "./apps-sdk/bridge.js";
5
+ import { McpAppBridge } from "./mcp-app/bridge.js";
6
+ import { NotSupportedError } from "./types.js";
7
+ function stubApp(adaptor, app) {
8
+ adaptor.mcp.getApp = () => Promise.resolve(app);
9
+ }
10
+ describe("HostAdaptor", () => {
11
+ beforeEach(() => {
12
+ McpAppBridge.resetInstance();
13
+ AppsSdkBridge.resetInstance();
14
+ vi.stubGlobal("skybridge", {});
15
+ vi.stubGlobal("parent", { postMessage: vi.fn() });
16
+ localStorage.clear();
17
+ });
18
+ afterEach(() => {
19
+ vi.unstubAllGlobals();
20
+ McpAppBridge.resetInstance();
21
+ AppsSdkBridge.resetInstance();
22
+ localStorage.clear();
23
+ });
24
+ it("callTool always routes to mcp.callServerTool", async () => {
25
+ vi.stubGlobal("openai", { callTool: vi.fn() });
26
+ const adaptor = new HostAdaptor();
27
+ const fakeApp = {
28
+ callServerTool: vi.fn().mockResolvedValue({
29
+ content: [],
30
+ structuredContent: { ok: true },
31
+ isError: false,
32
+ _meta: { x: 1 },
33
+ }),
34
+ };
35
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
36
+ adaptor.mcp.getApp = vi.fn().mockResolvedValue(fakeApp);
37
+ const result = await adaptor.callTool("greet", { name: "alice" });
38
+ expect(fakeApp.callServerTool).toHaveBeenCalledWith({
39
+ name: "greet",
40
+ arguments: { name: "alice" },
41
+ }, { timeout: undefined });
42
+ expect(result.structuredContent).toEqual({ ok: true });
43
+ expect(result.meta).toEqual({ x: 1 });
44
+ });
45
+ it("download returns isError when host lacks downloadFile capability", async () => {
46
+ vi.stubGlobal("openai", undefined);
47
+ const adaptor = new HostAdaptor();
48
+ const fakeApp = {
49
+ getHostCapabilities: () => ({}),
50
+ downloadFile: vi.fn(),
51
+ };
52
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
53
+ adaptor.mcp.getApp = vi.fn().mockResolvedValue(fakeApp);
54
+ const r = await adaptor.download({ contents: [] });
55
+ expect(r.isError).toBe(true);
56
+ expect(fakeApp.downloadFile).not.toHaveBeenCalled();
57
+ });
58
+ it("sendFollowUpMessage uses window.openai for plain text and ui/message for content blocks or a target", async () => {
59
+ const sendFollowUpMessage = vi.fn().mockResolvedValue(undefined);
60
+ vi.stubGlobal("openai", { sendFollowUpMessage });
61
+ let adaptor = new HostAdaptor();
62
+ await adaptor.sendFollowUpMessage("hi", { scrollToBottom: false });
63
+ expect(sendFollowUpMessage).toHaveBeenCalledWith({
64
+ prompt: "hi",
65
+ scrollToBottom: false,
66
+ });
67
+ // Default case falls through to MCP
68
+ McpAppBridge.resetInstance();
69
+ AppsSdkBridge.resetInstance();
70
+ vi.stubGlobal("openai", undefined);
71
+ adaptor = new HostAdaptor();
72
+ const sendMessage = vi.fn().mockResolvedValue(undefined);
73
+ const getHostCapabilities = () => ({
74
+ experimental: { "openai/message": {} },
75
+ });
76
+ stubApp(adaptor, { sendMessage });
77
+ await adaptor.sendFollowUpMessage("hi");
78
+ expect(sendMessage).toHaveBeenCalledWith({
79
+ role: "user",
80
+ content: [{ type: "text", text: "hi" }],
81
+ });
82
+ McpAppBridge.resetInstance();
83
+ AppsSdkBridge.resetInstance();
84
+ vi.stubGlobal("openai", { sendFollowUpMessage });
85
+ adaptor = new HostAdaptor();
86
+ stubApp(adaptor, { sendMessage, getHostCapabilities });
87
+ const item = {
88
+ type: "text",
89
+ text: "M6 hex bolt",
90
+ _meta: { "openai/title": "Hex bolt" },
91
+ };
92
+ await adaptor.sendFollowUpMessage([item], { target: "new" });
93
+ expect(sendMessage).toHaveBeenLastCalledWith({
94
+ role: "user",
95
+ content: [item],
96
+ _meta: { "openai/message": { target: "new" } },
97
+ });
98
+ expect(sendFollowUpMessage).toHaveBeenCalledTimes(1);
99
+ });
100
+ it("openFile sends openai/files/open only on hosts advertising openai/files", async () => {
101
+ const adaptor = new HostAdaptor();
102
+ const request = vi.fn().mockResolvedValue({});
103
+ let capabilities = {};
104
+ stubApp(adaptor, { request, getHostCapabilities: () => capabilities });
105
+ await expect(adaptor.openFile("/tmp/part.stl")).rejects.toThrow("openai/files");
106
+ expect(request).not.toHaveBeenCalled();
107
+ capabilities = { experimental: { "openai/files": {} } };
108
+ await adaptor.openFile("/tmp/part.stl");
109
+ expect(request).toHaveBeenCalledWith({ method: "openai/files/open", params: { path: "/tmp/part.stl" } }, expect.anything());
110
+ });
111
+ it("openExternal routes to window.openai only when redirectUrl: false", async () => {
112
+ const openExternal = vi.fn();
113
+ vi.stubGlobal("openai", { openExternal });
114
+ let adaptor = new HostAdaptor();
115
+ adaptor.openExternal("https://x", { redirectUrl: false });
116
+ expect(openExternal).toHaveBeenCalledWith({
117
+ href: "https://x",
118
+ redirectUrl: false,
119
+ });
120
+ // Default case falls through to MCP openLink
121
+ McpAppBridge.resetInstance();
122
+ AppsSdkBridge.resetInstance();
123
+ vi.stubGlobal("openai", undefined);
124
+ adaptor = new HostAdaptor();
125
+ const openLink = vi.fn();
126
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
127
+ adaptor.mcp.getApp = vi.fn().mockResolvedValue({ openLink });
128
+ adaptor.openExternal("https://x");
129
+ await new Promise((r) => setTimeout(r, 0));
130
+ expect(openLink).toHaveBeenCalledWith({ url: "https://x" });
131
+ });
132
+ it("Apps-SDK-exclusive methods throw NotSupportedError when window.openai is null", async () => {
133
+ vi.stubGlobal("openai", undefined);
134
+ const adaptor = new HostAdaptor();
135
+ await expect(adaptor.uploadFile(new File([], "x"))).rejects.toThrow(NotSupportedError);
136
+ await expect(adaptor.selectFiles()).rejects.toThrow(NotSupportedError);
137
+ await expect(adaptor.getFileDownloadUrl({ fileId: "x" })).rejects.toThrow(NotSupportedError);
138
+ await expect(adaptor.setOpenInAppUrl("https://x")).rejects.toThrow(NotSupportedError);
139
+ });
140
+ it("uploadFile delegates to window.openai.uploadFile and tracks fileId in widgetState", async () => {
141
+ const setWidgetState = vi.fn().mockResolvedValue(undefined);
142
+ const uploadFile = vi.fn().mockResolvedValue({
143
+ fileId: "abc",
144
+ fileName: "x",
145
+ mimeType: "image/png",
146
+ });
147
+ vi.stubGlobal("openai", { uploadFile, setWidgetState, widgetState: null });
148
+ const adaptor = new HostAdaptor();
149
+ const file = new File([], "x", { type: "image/png" });
150
+ const r = await adaptor.uploadFile(file, { library: true });
151
+ expect(uploadFile).toHaveBeenCalledWith(file, { library: true });
152
+ expect(r.fileId).toBe("abc");
153
+ expect(setWidgetState).toHaveBeenCalledWith(expect.objectContaining({ imageIds: ["abc"] }));
154
+ });
155
+ it("uploadFile does not track a non-image fileId in widgetState.imageIds", async () => {
156
+ const setWidgetState = vi.fn().mockResolvedValue(undefined);
157
+ const uploadFile = vi.fn().mockResolvedValue({
158
+ fileId: "sediment://file_txt",
159
+ fileName: "notes.txt",
160
+ mimeType: "text/plain",
161
+ });
162
+ vi.stubGlobal("openai", { uploadFile, setWidgetState, widgetState: null });
163
+ const adaptor = new HostAdaptor();
164
+ await adaptor.uploadFile(new File([], "notes.txt", { type: "text/plain" }));
165
+ for (const call of setWidgetState.mock.calls) {
166
+ expect(call[0].imageIds ?? []).not.toContain("sediment://file_txt");
167
+ }
168
+ });
169
+ it("setViewState uses window.openai.setWidgetState when present", async () => {
170
+ const setWidgetState = vi.fn().mockResolvedValue(undefined);
171
+ vi.stubGlobal("openai", { setWidgetState, widgetState: null });
172
+ const adaptor = new HostAdaptor();
173
+ await adaptor.setViewState({ count: 1 });
174
+ expect(setWidgetState).toHaveBeenCalledWith(expect.objectContaining({ modelContent: { count: 1 } }));
175
+ });
176
+ it("warns when setViewState reaches 20K tokens", async () => {
177
+ const setWidgetState = vi.fn().mockResolvedValue(undefined);
178
+ vi.stubGlobal("openai", { setWidgetState, widgetState: null });
179
+ const adaptor = new HostAdaptor();
180
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => { });
181
+ await adaptor.setViewState({
182
+ longText: "x".repeat(VIEW_STATE_WARNING_TOKENS * 4),
183
+ });
184
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("setWidgetState is persisting"));
185
+ warnSpy.mockRestore();
186
+ });
187
+ it("setViewState falls back to MCP updateModelContext + localStorage when window.openai is absent", async () => {
188
+ vi.stubGlobal("openai", undefined);
189
+ const adaptor = new HostAdaptor();
190
+ const updateModelContext = vi.fn().mockResolvedValue(undefined);
191
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
192
+ adaptor.mcp.getApp = vi
193
+ .fn()
194
+ .mockResolvedValue({ updateModelContext });
195
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
196
+ adaptor._viewUUID = "view-1";
197
+ await adaptor.setViewState({ count: 2 });
198
+ expect(updateModelContext).toHaveBeenCalledWith({
199
+ structuredContent: { count: 2 },
200
+ content: [
201
+ {
202
+ type: "text",
203
+ text: JSON.stringify({ count: 2 }),
204
+ annotations: { audience: ["assistant"] },
205
+ },
206
+ ],
207
+ });
208
+ const keys = [];
209
+ for (let i = 0; i < localStorage.length; i++) {
210
+ const key = localStorage.key(i);
211
+ if (key !== null) {
212
+ keys.push(key);
213
+ }
214
+ }
215
+ expect(keys.some((k) => k.endsWith(":view-1"))).toBe(true);
216
+ });
217
+ it("openModal/closeModal: delegates to window.openai.requestModal when present, polyfill state otherwise", () => {
218
+ const requestModal = vi.fn();
219
+ vi.stubGlobal("openai", { requestModal });
220
+ let adaptor = new HostAdaptor();
221
+ adaptor.openModal({ title: "Hi" });
222
+ expect(requestModal).toHaveBeenCalledWith({ title: "Hi" });
223
+ expect(() => adaptor.closeModal()).not.toThrow();
224
+ // Polyfill path
225
+ McpAppBridge.resetInstance();
226
+ AppsSdkBridge.resetInstance();
227
+ vi.stubGlobal("openai", undefined);
228
+ adaptor = new HostAdaptor();
229
+ adaptor.openModal({ params: { x: 1 } });
230
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
231
+ expect(adaptor._polyfillDisplay).toEqual({
232
+ mode: "modal",
233
+ params: { x: 1 },
234
+ });
235
+ adaptor.closeModal();
236
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
237
+ expect(adaptor._polyfillDisplay).toEqual({ mode: "inline" });
238
+ });
239
+ it("getHostContextStore: display/viewState route to Apps SDK overlay when present, MCP otherwise", () => {
240
+ vi.stubGlobal("openai", {
241
+ view: { mode: "fullscreen" },
242
+ widgetState: { modelContent: { count: 5 }, privateContent: {} },
243
+ });
244
+ let adaptor = new HostAdaptor();
245
+ expect(adaptor.getHostContextStore("display").getSnapshot()).toEqual({
246
+ mode: "fullscreen",
247
+ });
248
+ expect(adaptor.getHostContextStore("viewState").getSnapshot()).toEqual({
249
+ count: 5,
250
+ });
251
+ // Other keys (theme) always flow through MCP; default fallback when no notification
252
+ expect(adaptor.getHostContextStore("theme").getSnapshot()).toBe("light");
253
+ // Polyfill / local-state path
254
+ McpAppBridge.resetInstance();
255
+ AppsSdkBridge.resetInstance();
256
+ vi.stubGlobal("openai", undefined);
257
+ adaptor = new HostAdaptor();
258
+ expect(adaptor.getHostContextStore("display").getSnapshot()).toEqual({
259
+ mode: "inline",
260
+ });
261
+ expect(adaptor.getHostContextStore("viewState").getSnapshot()).toBe(null);
262
+ });
263
+ });
264
+ //# sourceMappingURL=adaptor.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adaptor.test.js","sourceRoot":"","sources":["../../../src/web/bridges/adaptor.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { VIEW_STATE_WARNING_TOKENS } from \"../../context-warnings.js\";\nimport { HostAdaptor } from \"./adaptor.js\";\nimport { AppsSdkBridge } from \"./apps-sdk/bridge.js\";\nimport { McpAppBridge } from \"./mcp-app/bridge.js\";\nimport { NotSupportedError } from \"./types.js\";\n\nfunction stubApp(adaptor: HostAdaptor, app: object) {\n (\n adaptor as unknown as { mcp: { getApp: () => Promise<object> } }\n ).mcp.getApp = () => Promise.resolve(app);\n}\n\ndescribe(\"HostAdaptor\", () => {\n beforeEach(() => {\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n localStorage.clear();\n });\n afterEach(() => {\n vi.unstubAllGlobals();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n localStorage.clear();\n });\n\n it(\"callTool always routes to mcp.callServerTool\", async () => {\n vi.stubGlobal(\"openai\", { callTool: vi.fn() });\n const adaptor = new HostAdaptor();\n const fakeApp = {\n callServerTool: vi.fn().mockResolvedValue({\n content: [],\n structuredContent: { ok: true },\n isError: false,\n _meta: { x: 1 },\n }),\n };\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n (adaptor as any).mcp.getApp = vi.fn().mockResolvedValue(fakeApp);\n\n const result = await adaptor.callTool(\"greet\", { name: \"alice\" });\n expect(fakeApp.callServerTool).toHaveBeenCalledWith(\n {\n name: \"greet\",\n arguments: { name: \"alice\" },\n },\n { timeout: undefined },\n );\n expect(result.structuredContent).toEqual({ ok: true });\n expect(result.meta).toEqual({ x: 1 });\n });\n\n it(\"download returns isError when host lacks downloadFile capability\", async () => {\n vi.stubGlobal(\"openai\", undefined);\n const adaptor = new HostAdaptor();\n const fakeApp = {\n getHostCapabilities: () => ({}),\n downloadFile: vi.fn(),\n };\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n (adaptor as any).mcp.getApp = vi.fn().mockResolvedValue(fakeApp);\n const r = await adaptor.download({ contents: [] });\n expect(r.isError).toBe(true);\n expect(fakeApp.downloadFile).not.toHaveBeenCalled();\n });\n\n it(\"sendFollowUpMessage uses window.openai for plain text and ui/message for content blocks or a target\", async () => {\n const sendFollowUpMessage = vi.fn().mockResolvedValue(undefined);\n vi.stubGlobal(\"openai\", { sendFollowUpMessage });\n let adaptor = new HostAdaptor();\n await adaptor.sendFollowUpMessage(\"hi\", { scrollToBottom: false });\n expect(sendFollowUpMessage).toHaveBeenCalledWith({\n prompt: \"hi\",\n scrollToBottom: false,\n });\n\n // Default case falls through to MCP\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"openai\", undefined);\n adaptor = new HostAdaptor();\n const sendMessage = vi.fn().mockResolvedValue(undefined);\n const getHostCapabilities = () => ({\n experimental: { \"openai/message\": {} },\n });\n stubApp(adaptor, { sendMessage });\n await adaptor.sendFollowUpMessage(\"hi\");\n expect(sendMessage).toHaveBeenCalledWith({\n role: \"user\",\n content: [{ type: \"text\", text: \"hi\" }],\n });\n\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"openai\", { sendFollowUpMessage });\n adaptor = new HostAdaptor();\n stubApp(adaptor, { sendMessage, getHostCapabilities });\n const item = {\n type: \"text\" as const,\n text: \"M6 hex bolt\",\n _meta: { \"openai/title\": \"Hex bolt\" },\n };\n await adaptor.sendFollowUpMessage([item], { target: \"new\" });\n expect(sendMessage).toHaveBeenLastCalledWith({\n role: \"user\",\n content: [item],\n _meta: { \"openai/message\": { target: \"new\" } },\n });\n expect(sendFollowUpMessage).toHaveBeenCalledTimes(1);\n });\n\n it(\"openFile sends openai/files/open only on hosts advertising openai/files\", async () => {\n const adaptor = new HostAdaptor();\n const request = vi.fn().mockResolvedValue({});\n let capabilities: Record<string, unknown> = {};\n stubApp(adaptor, { request, getHostCapabilities: () => capabilities });\n\n await expect(adaptor.openFile(\"/tmp/part.stl\")).rejects.toThrow(\n \"openai/files\",\n );\n expect(request).not.toHaveBeenCalled();\n\n capabilities = { experimental: { \"openai/files\": {} } };\n await adaptor.openFile(\"/tmp/part.stl\");\n expect(request).toHaveBeenCalledWith(\n { method: \"openai/files/open\", params: { path: \"/tmp/part.stl\" } },\n expect.anything(),\n );\n });\n\n it(\"openExternal routes to window.openai only when redirectUrl: false\", async () => {\n const openExternal = vi.fn();\n vi.stubGlobal(\"openai\", { openExternal });\n let adaptor = new HostAdaptor();\n adaptor.openExternal(\"https://x\", { redirectUrl: false });\n expect(openExternal).toHaveBeenCalledWith({\n href: \"https://x\",\n redirectUrl: false,\n });\n\n // Default case falls through to MCP openLink\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"openai\", undefined);\n adaptor = new HostAdaptor();\n const openLink = vi.fn();\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n (adaptor as any).mcp.getApp = vi.fn().mockResolvedValue({ openLink });\n adaptor.openExternal(\"https://x\");\n await new Promise((r) => setTimeout(r, 0));\n expect(openLink).toHaveBeenCalledWith({ url: \"https://x\" });\n });\n\n it(\"Apps-SDK-exclusive methods throw NotSupportedError when window.openai is null\", async () => {\n vi.stubGlobal(\"openai\", undefined);\n const adaptor = new HostAdaptor();\n await expect(adaptor.uploadFile(new File([], \"x\"))).rejects.toThrow(\n NotSupportedError,\n );\n await expect(adaptor.selectFiles()).rejects.toThrow(NotSupportedError);\n await expect(adaptor.getFileDownloadUrl({ fileId: \"x\" })).rejects.toThrow(\n NotSupportedError,\n );\n await expect(adaptor.setOpenInAppUrl(\"https://x\")).rejects.toThrow(\n NotSupportedError,\n );\n });\n\n it(\"uploadFile delegates to window.openai.uploadFile and tracks fileId in widgetState\", async () => {\n const setWidgetState = vi.fn().mockResolvedValue(undefined);\n const uploadFile = vi.fn().mockResolvedValue({\n fileId: \"abc\",\n fileName: \"x\",\n mimeType: \"image/png\",\n });\n vi.stubGlobal(\"openai\", { uploadFile, setWidgetState, widgetState: null });\n const adaptor = new HostAdaptor();\n const file = new File([], \"x\", { type: \"image/png\" });\n const r = await adaptor.uploadFile(file, { library: true });\n expect(uploadFile).toHaveBeenCalledWith(file, { library: true });\n expect(r.fileId).toBe(\"abc\");\n expect(setWidgetState).toHaveBeenCalledWith(\n expect.objectContaining({ imageIds: [\"abc\"] }),\n );\n });\n\n it(\"uploadFile does not track a non-image fileId in widgetState.imageIds\", async () => {\n const setWidgetState = vi.fn().mockResolvedValue(undefined);\n const uploadFile = vi.fn().mockResolvedValue({\n fileId: \"sediment://file_txt\",\n fileName: \"notes.txt\",\n mimeType: \"text/plain\",\n });\n vi.stubGlobal(\"openai\", { uploadFile, setWidgetState, widgetState: null });\n const adaptor = new HostAdaptor();\n\n await adaptor.uploadFile(new File([], \"notes.txt\", { type: \"text/plain\" }));\n\n for (const call of setWidgetState.mock.calls) {\n expect(call[0].imageIds ?? []).not.toContain(\"sediment://file_txt\");\n }\n });\n\n it(\"setViewState uses window.openai.setWidgetState when present\", async () => {\n const setWidgetState = vi.fn().mockResolvedValue(undefined);\n vi.stubGlobal(\"openai\", { setWidgetState, widgetState: null });\n const adaptor = new HostAdaptor();\n await adaptor.setViewState({ count: 1 });\n expect(setWidgetState).toHaveBeenCalledWith(\n expect.objectContaining({ modelContent: { count: 1 } }),\n );\n });\n\n it(\"warns when setViewState reaches 20K tokens\", async () => {\n const setWidgetState = vi.fn().mockResolvedValue(undefined);\n vi.stubGlobal(\"openai\", { setWidgetState, widgetState: null });\n const adaptor = new HostAdaptor();\n const warnSpy = vi.spyOn(console, \"warn\").mockImplementation(() => {});\n\n await adaptor.setViewState({\n longText: \"x\".repeat(VIEW_STATE_WARNING_TOKENS * 4),\n });\n\n expect(warnSpy).toHaveBeenCalledWith(\n expect.stringContaining(\"setWidgetState is persisting\"),\n );\n\n warnSpy.mockRestore();\n });\n\n it(\"setViewState falls back to MCP updateModelContext + localStorage when window.openai is absent\", async () => {\n vi.stubGlobal(\"openai\", undefined);\n const adaptor = new HostAdaptor();\n const updateModelContext = vi.fn().mockResolvedValue(undefined);\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n (adaptor as any).mcp.getApp = vi\n .fn()\n .mockResolvedValue({ updateModelContext });\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n (adaptor as any)._viewUUID = \"view-1\";\n await adaptor.setViewState({ count: 2 });\n expect(updateModelContext).toHaveBeenCalledWith({\n structuredContent: { count: 2 },\n content: [\n {\n type: \"text\",\n text: JSON.stringify({ count: 2 }),\n annotations: { audience: [\"assistant\"] },\n },\n ],\n });\n const keys: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key !== null) {\n keys.push(key);\n }\n }\n expect(keys.some((k) => k.endsWith(\":view-1\"))).toBe(true);\n });\n\n it(\"openModal/closeModal: delegates to window.openai.requestModal when present, polyfill state otherwise\", () => {\n const requestModal = vi.fn();\n vi.stubGlobal(\"openai\", { requestModal });\n let adaptor = new HostAdaptor();\n adaptor.openModal({ title: \"Hi\" });\n expect(requestModal).toHaveBeenCalledWith({ title: \"Hi\" });\n expect(() => adaptor.closeModal()).not.toThrow();\n\n // Polyfill path\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"openai\", undefined);\n adaptor = new HostAdaptor();\n adaptor.openModal({ params: { x: 1 } });\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n expect((adaptor as any)._polyfillDisplay).toEqual({\n mode: \"modal\",\n params: { x: 1 },\n });\n adaptor.closeModal();\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n expect((adaptor as any)._polyfillDisplay).toEqual({ mode: \"inline\" });\n });\n\n it(\"getHostContextStore: display/viewState route to Apps SDK overlay when present, MCP otherwise\", () => {\n vi.stubGlobal(\"openai\", {\n view: { mode: \"fullscreen\" },\n widgetState: { modelContent: { count: 5 }, privateContent: {} },\n });\n let adaptor = new HostAdaptor();\n expect(adaptor.getHostContextStore(\"display\").getSnapshot()).toEqual({\n mode: \"fullscreen\",\n });\n expect(adaptor.getHostContextStore(\"viewState\").getSnapshot()).toEqual({\n count: 5,\n });\n // Other keys (theme) always flow through MCP; default fallback when no notification\n expect(adaptor.getHostContextStore(\"theme\").getSnapshot()).toBe(\"light\");\n\n // Polyfill / local-state path\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"openai\", undefined);\n adaptor = new HostAdaptor();\n expect(adaptor.getHostContextStore(\"display\").getSnapshot()).toEqual({\n mode: \"inline\",\n });\n expect(adaptor.getHostContextStore(\"viewState\").getSnapshot()).toBe(null);\n });\n});\n"]}
@@ -1,6 +1,6 @@
1
- import type { Bridge, Subscribe } from "../types.js";
1
+ import type { Bridge, HostContextStore, Subscribe } from "../types.js";
2
2
  import { type AppsSdkContext } from "./types.js";
3
- /** @internal Singleton bridge over `window.openai` events. Used by {@link AppsSdkAdaptor}. */
3
+ /** @internal Singleton bridge over `window.openai` events. Used by `HostAdaptor`. */
4
4
  export declare class AppsSdkBridge implements Bridge<AppsSdkContext> {
5
5
  private static instance;
6
6
  static getInstance(): AppsSdkBridge;
@@ -8,4 +8,8 @@ export declare class AppsSdkBridge implements Bridge<AppsSdkContext> {
8
8
  subscribe(key: keyof AppsSdkContext): Subscribe;
9
9
  subscribe(keys: readonly (keyof AppsSdkContext)[]): Subscribe;
10
10
  getSnapshot: <K extends keyof AppsSdkContext>(key: K) => (import("./types.js").AppsSdkMethods<import("./types.js").AppsSdkWidgetState> & AppsSdkContext<Record<never, unknown>, import("../../types.js").UnknownObject, import("../../types.js").UnknownObject, import("./types.js").AppsSdkWidgetState>)[K];
11
+ createOverlayStores(): {
12
+ display: HostContextStore<"display">;
13
+ viewState: HostContextStore<"viewState">;
14
+ };
11
15
  }
@@ -1,11 +1,10 @@
1
1
  import { SET_GLOBALS_EVENT_TYPE, } from "./types.js";
2
- /** @internal Singleton bridge over `window.openai` events. Used by {@link AppsSdkAdaptor}. */
2
+ /** @internal Singleton bridge over `window.openai` events. Used by `HostAdaptor`. */
3
3
  export class AppsSdkBridge {
4
4
  static instance = null;
5
5
  static getInstance() {
6
- if (window.skybridge.hostType !== "apps-sdk" ||
7
- window.openai === undefined) {
8
- throw new Error("Apps SDK Bridge can only be used in the apps-sdk runtime");
6
+ if (window.openai === undefined) {
7
+ throw new Error("Apps SDK Bridge requires window.openai (Apps SDK runtime).");
9
8
  }
10
9
  if (AppsSdkBridge.instance === null) {
11
10
  AppsSdkBridge.instance = new AppsSdkBridge();
@@ -43,5 +42,17 @@ export class AppsSdkBridge {
43
42
  }
44
43
  return window.openai[key];
45
44
  };
45
+ createOverlayStores() {
46
+ return {
47
+ display: {
48
+ subscribe: this.subscribe("view"),
49
+ getSnapshot: () => this.getSnapshot("view"),
50
+ },
51
+ viewState: {
52
+ subscribe: this.subscribe("widgetState"),
53
+ getSnapshot: () => this.getSnapshot("widgetState")?.modelContent ?? null,
54
+ },
55
+ };
56
+ }
46
57
  }
47
58
  //# sourceMappingURL=bridge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../../../src/web/bridges/apps-sdk/bridge.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,sBAAsB,GAEvB,MAAM,YAAY,CAAC;AAEpB,8FAA8F;AAC9F,MAAM,OAAO,aAAa;IAChB,MAAM,CAAC,QAAQ,GAAyB,IAAI,CAAC;IAE9C,MAAM,CAAC,WAAW;QACvB,IACE,MAAM,CAAC,SAAS,CAAC,QAAQ,KAAK,UAAU;YACxC,MAAM,CAAC,MAAM,KAAK,SAAS,EAC3B,CAAC;YACD,MAAM,IAAI,KAAK,CACb,0DAA0D,CAC3D,CAAC;QACJ,CAAC;QACD,IAAI,aAAa,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YACpC,aAAa,CAAC,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;QAC/C,CAAC;QACD,OAAO,aAAa,CAAC,QAAQ,CAAC;IAChC,CAAC;IAEM,MAAM,CAAC,aAAa;QACzB,IAAI,aAAa,CAAC,QAAQ,EAAE,CAAC;YAC3B,aAAa,CAAC,QAAQ,GAAG,IAAI,CAAC;QAChC,CAAC;IACH,CAAC;IAIM,SAAS,CACd,SAAmE;QAEnE,MAAM,IAAI,GAAsC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;YACtE,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAChB,OAAO,CAAC,QAAoB,EAAE,EAAE;YAC9B,MAAM,eAAe,GAAG,CAAC,KAAsB,EAAE,EAAE;gBACjD,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CACjC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,CACjD,CAAC;gBACF,IAAI,CAAC,iBAAiB,EAAE,CAAC;oBACvB,OAAO;gBACT,CAAC;gBACD,QAAQ,EAAE,CAAC;YACb,CAAC,CAAC;YAEF,MAAM,CAAC,gBAAgB,CAAC,sBAAsB,EAAE,eAAe,EAAE;gBAC/D,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;YAEH,OAAO,GAAG,EAAE;gBACV,MAAM,CAAC,mBAAmB,CAAC,sBAAsB,EAAE,eAAe,CAAC,CAAC;YACtE,CAAC,CAAC;QACJ,CAAC,CAAC;IACJ,CAAC;IAEM,WAAW,GAAG,CAAiC,GAAM,EAAE,EAAE;QAC9D,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,+EAA+E,GAAG,8CAA8C,CACjI,CAAC;QACJ,CAAC;QAED,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC,CAAC","sourcesContent":["import type { Bridge, Subscribe } from \"../types.js\";\nimport {\n type AppsSdkContext,\n SET_GLOBALS_EVENT_TYPE,\n type SetGlobalsEvent,\n} from \"./types.js\";\n\n/** @internal Singleton bridge over `window.openai` events. Used by {@link AppsSdkAdaptor}. */\nexport class AppsSdkBridge implements Bridge<AppsSdkContext> {\n private static instance: AppsSdkBridge | null = null;\n\n public static getInstance(): AppsSdkBridge {\n if (\n window.skybridge.hostType !== \"apps-sdk\" ||\n window.openai === undefined\n ) {\n throw new Error(\n \"Apps SDK Bridge can only be used in the apps-sdk runtime\",\n );\n }\n if (AppsSdkBridge.instance === null) {\n AppsSdkBridge.instance = new AppsSdkBridge();\n }\n return AppsSdkBridge.instance;\n }\n\n public static resetInstance(): void {\n if (AppsSdkBridge.instance) {\n AppsSdkBridge.instance = null;\n }\n }\n\n public subscribe(key: keyof AppsSdkContext): Subscribe;\n public subscribe(keys: readonly (keyof AppsSdkContext)[]): Subscribe;\n public subscribe(\n keyOrKeys: keyof AppsSdkContext | readonly (keyof AppsSdkContext)[],\n ): Subscribe {\n const keys: readonly (keyof AppsSdkContext)[] = Array.isArray(keyOrKeys)\n ? keyOrKeys\n : [keyOrKeys];\n return (onChange: () => void) => {\n const handleSetGlobal = (event: SetGlobalsEvent) => {\n const hasRelevantChange = keys.some(\n (key) => event.detail.globals[key] !== undefined,\n );\n if (!hasRelevantChange) {\n return;\n }\n onChange();\n };\n\n window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal, {\n passive: true,\n });\n\n return () => {\n window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);\n };\n };\n }\n\n public getSnapshot = <K extends keyof AppsSdkContext>(key: K) => {\n if (window.openai === undefined) {\n throw new Error(\n `window.openai is not available. Make sure you're calling the hook requiring ${key} within the OpenAI iFrame skybridge runtime.`,\n );\n }\n\n return window.openai[key];\n };\n}\n"]}
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../../../src/web/bridges/apps-sdk/bridge.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,sBAAsB,GAEvB,MAAM,YAAY,CAAC;AAEpB,qFAAqF;AACrF,MAAM,OAAO,aAAa;IAChB,MAAM,CAAC,QAAQ,GAAyB,IAAI,CAAC;IAE9C,MAAM,CAAC,WAAW;QACvB,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,4DAA4D,CAC7D,CAAC;QACJ,CAAC;QACD,IAAI,aAAa,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YACpC,aAAa,CAAC,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;QAC/C,CAAC;QACD,OAAO,aAAa,CAAC,QAAQ,CAAC;IAChC,CAAC;IAEM,MAAM,CAAC,aAAa;QACzB,IAAI,aAAa,CAAC,QAAQ,EAAE,CAAC;YAC3B,aAAa,CAAC,QAAQ,GAAG,IAAI,CAAC;QAChC,CAAC;IACH,CAAC;IAIM,SAAS,CACd,SAAmE;QAEnE,MAAM,IAAI,GAAsC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;YACtE,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAChB,OAAO,CAAC,QAAoB,EAAE,EAAE;YAC9B,MAAM,eAAe,GAAG,CAAC,KAAsB,EAAE,EAAE;gBACjD,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CACjC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,CACjD,CAAC;gBACF,IAAI,CAAC,iBAAiB,EAAE,CAAC;oBACvB,OAAO;gBACT,CAAC;gBACD,QAAQ,EAAE,CAAC;YACb,CAAC,CAAC;YAEF,MAAM,CAAC,gBAAgB,CAAC,sBAAsB,EAAE,eAAe,EAAE;gBAC/D,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;YAEH,OAAO,GAAG,EAAE;gBACV,MAAM,CAAC,mBAAmB,CAAC,sBAAsB,EAAE,eAAe,CAAC,CAAC;YACtE,CAAC,CAAC;QACJ,CAAC,CAAC;IACJ,CAAC;IAEM,WAAW,GAAG,CAAiC,GAAM,EAAE,EAAE;QAC9D,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,+EAA+E,GAAG,8CAA8C,CACjI,CAAC;QACJ,CAAC;QAED,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC,CAAC;IAEK,mBAAmB;QAIxB,OAAO;YACL,OAAO,EAAE;gBACP,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;gBACjC,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;aAC5C;YACD,SAAS,EAAE;gBACT,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC;gBACxC,WAAW,EAAE,GAAG,EAAE,CAChB,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,EAAE,YAAY,IAAI,IAAI;aACxD;SACF,CAAC;IACJ,CAAC","sourcesContent":["import type { Bridge, HostContextStore, Subscribe } from \"../types.js\";\nimport {\n type AppsSdkContext,\n SET_GLOBALS_EVENT_TYPE,\n type SetGlobalsEvent,\n} from \"./types.js\";\n\n/** @internal Singleton bridge over `window.openai` events. Used by `HostAdaptor`. */\nexport class AppsSdkBridge implements Bridge<AppsSdkContext> {\n private static instance: AppsSdkBridge | null = null;\n\n public static getInstance(): AppsSdkBridge {\n if (window.openai === undefined) {\n throw new Error(\n \"Apps SDK Bridge requires window.openai (Apps SDK runtime).\",\n );\n }\n if (AppsSdkBridge.instance === null) {\n AppsSdkBridge.instance = new AppsSdkBridge();\n }\n return AppsSdkBridge.instance;\n }\n\n public static resetInstance(): void {\n if (AppsSdkBridge.instance) {\n AppsSdkBridge.instance = null;\n }\n }\n\n public subscribe(key: keyof AppsSdkContext): Subscribe;\n public subscribe(keys: readonly (keyof AppsSdkContext)[]): Subscribe;\n public subscribe(\n keyOrKeys: keyof AppsSdkContext | readonly (keyof AppsSdkContext)[],\n ): Subscribe {\n const keys: readonly (keyof AppsSdkContext)[] = Array.isArray(keyOrKeys)\n ? keyOrKeys\n : [keyOrKeys];\n return (onChange: () => void) => {\n const handleSetGlobal = (event: SetGlobalsEvent) => {\n const hasRelevantChange = keys.some(\n (key) => event.detail.globals[key] !== undefined,\n );\n if (!hasRelevantChange) {\n return;\n }\n onChange();\n };\n\n window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal, {\n passive: true,\n });\n\n return () => {\n window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);\n };\n };\n }\n\n public getSnapshot = <K extends keyof AppsSdkContext>(key: K) => {\n if (window.openai === undefined) {\n throw new Error(\n `window.openai is not available. Make sure you're calling the hook requiring ${key} within the OpenAI iFrame skybridge runtime.`,\n );\n }\n\n return window.openai[key];\n };\n\n public createOverlayStores(): {\n display: HostContextStore<\"display\">;\n viewState: HostContextStore<\"viewState\">;\n } {\n return {\n display: {\n subscribe: this.subscribe(\"view\"),\n getSnapshot: () => this.getSnapshot(\"view\"),\n },\n viewState: {\n subscribe: this.subscribe(\"widgetState\"),\n getSnapshot: () =>\n this.getSnapshot(\"widgetState\")?.modelContent ?? null,\n },\n };\n }\n}\n"]}
@@ -1,4 +1,3 @@
1
- export { AppsSdkAdaptor } from "./adaptor.js";
2
1
  export { AppsSdkBridge } from "./bridge.js";
3
2
  export type { AppsSdkContext, AppsSdkMethods, AppsSdkWidgetState, ToolResponseEvent, } from "./types.js";
4
3
  export { SET_GLOBALS_EVENT_TYPE, SetGlobalsEvent, TOOL_RESPONSE_EVENT_TYPE, } from "./types.js";
@@ -1,4 +1,3 @@
1
- export { AppsSdkAdaptor } from "./adaptor.js";
2
1
  export { AppsSdkBridge } from "./bridge.js";
3
2
  export { SET_GLOBALS_EVENT_TYPE, SetGlobalsEvent, TOOL_RESPONSE_EVENT_TYPE, } from "./types.js";
4
3
  export { useAppsSdkContext } from "./use-apps-sdk-context.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/web/bridges/apps-sdk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAO5C,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,wBAAwB,GACzB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC","sourcesContent":["export { AppsSdkAdaptor } from \"./adaptor.js\";\nexport { AppsSdkBridge } from \"./bridge.js\";\nexport type {\n AppsSdkContext,\n AppsSdkMethods,\n AppsSdkWidgetState,\n ToolResponseEvent,\n} from \"./types.js\";\nexport {\n SET_GLOBALS_EVENT_TYPE,\n SetGlobalsEvent,\n TOOL_RESPONSE_EVENT_TYPE,\n} from \"./types.js\";\nexport { useAppsSdkContext } from \"./use-apps-sdk-context.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/web/bridges/apps-sdk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAO5C,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,wBAAwB,GACzB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC","sourcesContent":["export { AppsSdkBridge } from \"./bridge.js\";\nexport type {\n AppsSdkContext,\n AppsSdkMethods,\n AppsSdkWidgetState,\n ToolResponseEvent,\n} from \"./types.js\";\nexport {\n SET_GLOBALS_EVENT_TYPE,\n SetGlobalsEvent,\n TOOL_RESPONSE_EVENT_TYPE,\n} from \"./types.js\";\nexport { useAppsSdkContext } from \"./use-apps-sdk-context.js\";\n"]}
@@ -2,7 +2,7 @@ import type { AppsSdkContext } from "./types.js";
2
2
  /**
3
3
  * Read a single key from the raw Apps SDK (`window.openai`) context.
4
4
  *
5
- * Advanced escape hatch — prefer the cross-host hooks (`useLayout`, `useUser`,
5
+ * Advanced escape hatch — prefer the cross-host hooks (`useViewport`, `useUser`,
6
6
  * `useToolInfo`, etc.) which work in both Apps SDK and MCP Apps. Reach for
7
7
  * this when you need ChatGPT-only fields not surfaced by the public hooks.
8
8
  *
@@ -3,7 +3,7 @@ import { AppsSdkBridge } from "./bridge.js";
3
3
  /**
4
4
  * Read a single key from the raw Apps SDK (`window.openai`) context.
5
5
  *
6
- * Advanced escape hatch — prefer the cross-host hooks (`useLayout`, `useUser`,
6
+ * Advanced escape hatch — prefer the cross-host hooks (`useViewport`, `useUser`,
7
7
  * `useToolInfo`, etc.) which work in both Apps SDK and MCP Apps. Reach for
8
8
  * this when you need ChatGPT-only fields not surfaced by the public hooks.
9
9
  *
@@ -1 +1 @@
1
- {"version":3,"file":"use-apps-sdk-context.js","sourceRoot":"","sources":["../../../../src/web/bridges/apps-sdk/use-apps-sdk-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAM;IAEN,MAAM,MAAM,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;IAC3C,OAAO,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CACtD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CACxB,CAAC;AACJ,CAAC","sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport { AppsSdkBridge } from \"./bridge.js\";\nimport type { AppsSdkContext } from \"./types.js\";\n\n/**\n * Read a single key from the raw Apps SDK (`window.openai`) context.\n *\n * Advanced escape hatch — prefer the cross-host hooks (`useLayout`, `useUser`,\n * `useToolInfo`, etc.) which work in both Apps SDK and MCP Apps. Reach for\n * this when you need ChatGPT-only fields not surfaced by the public hooks.\n *\n * Throws if called outside the Apps SDK runtime.\n *\n * @see https://docs.skybridge.tech/api-reference/use-apps-sdk-context\n */\nexport function useAppsSdkContext<K extends keyof AppsSdkContext>(\n key: K,\n): AppsSdkContext[K] {\n const bridge = AppsSdkBridge.getInstance();\n return useSyncExternalStore(bridge.subscribe(key), () =>\n bridge.getSnapshot(key),\n );\n}\n"]}
1
+ {"version":3,"file":"use-apps-sdk-context.js","sourceRoot":"","sources":["../../../../src/web/bridges/apps-sdk/use-apps-sdk-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAM;IAEN,MAAM,MAAM,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;IAC3C,OAAO,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CACtD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CACxB,CAAC;AACJ,CAAC","sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport { AppsSdkBridge } from \"./bridge.js\";\nimport type { AppsSdkContext } from \"./types.js\";\n\n/**\n * Read a single key from the raw Apps SDK (`window.openai`) context.\n *\n * Advanced escape hatch — prefer the cross-host hooks (`useViewport`, `useUser`,\n * `useToolInfo`, etc.) which work in both Apps SDK and MCP Apps. Reach for\n * this when you need ChatGPT-only fields not surfaced by the public hooks.\n *\n * Throws if called outside the Apps SDK runtime.\n *\n * @see https://docs.skybridge.tech/api-reference/use-apps-sdk-context\n */\nexport function useAppsSdkContext<K extends keyof AppsSdkContext>(\n key: K,\n): AppsSdkContext[K] {\n const bridge = AppsSdkBridge.getInstance();\n return useSyncExternalStore(bridge.subscribe(key), () =>\n bridge.getSnapshot(key),\n );\n}\n"]}
@@ -1,9 +1,9 @@
1
1
  import type { Adaptor } from "./types.js";
2
2
  /**
3
3
  * @internal
4
- * Resolve the host-specific {@link Adaptor} based on `window.skybridge.hostType`.
5
- * Prefer the documented hooks (`useCallTool`, `useViewState`, etc.) over
6
- * calling this directly — it's the escape hatch used by the hooks themselves
7
- * and by advanced integrations.
4
+ * Resolve the single host {@link Adaptor} instance. Prefer the documented
5
+ * hooks (`useCallTool`, `useViewState`, etc.) over calling this directly;
6
+ * it's the escape hatch used by the hooks themselves and by advanced
7
+ * integrations.
8
8
  */
9
9
  export declare const getAdaptor: () => Adaptor;
@@ -1,15 +1,10 @@
1
- import { AppsSdkAdaptor } from "./apps-sdk/adaptor.js";
2
- import { McpAppAdaptor } from "./mcp-app/adaptor.js";
1
+ import { HostAdaptor } from "./adaptor.js";
3
2
  /**
4
3
  * @internal
5
- * Resolve the host-specific {@link Adaptor} based on `window.skybridge.hostType`.
6
- * Prefer the documented hooks (`useCallTool`, `useViewState`, etc.) over
7
- * calling this directly — it's the escape hatch used by the hooks themselves
8
- * and by advanced integrations.
4
+ * Resolve the single host {@link Adaptor} instance. Prefer the documented
5
+ * hooks (`useCallTool`, `useViewState`, etc.) over calling this directly;
6
+ * it's the escape hatch used by the hooks themselves and by advanced
7
+ * integrations.
9
8
  */
10
- export const getAdaptor = () => {
11
- return window.skybridge.hostType === "apps-sdk"
12
- ? AppsSdkAdaptor.getInstance()
13
- : McpAppAdaptor.getInstance();
14
- };
9
+ export const getAdaptor = () => HostAdaptor.getInstance();
15
10
  //# sourceMappingURL=get-adaptor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-adaptor.js","sourceRoot":"","sources":["../../../src/web/bridges/get-adaptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,GAAY,EAAE;IACtC,OAAO,MAAM,CAAC,SAAS,CAAC,QAAQ,KAAK,UAAU;QAC7C,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE;QAC9B,CAAC,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC,CAAC","sourcesContent":["import { AppsSdkAdaptor } from \"./apps-sdk/adaptor.js\";\nimport { McpAppAdaptor } from \"./mcp-app/adaptor.js\";\nimport type { Adaptor } from \"./types.js\";\n\n/**\n * @internal\n * Resolve the host-specific {@link Adaptor} based on `window.skybridge.hostType`.\n * Prefer the documented hooks (`useCallTool`, `useViewState`, etc.) over\n * calling this directly — it's the escape hatch used by the hooks themselves\n * and by advanced integrations.\n */\nexport const getAdaptor = (): Adaptor => {\n return window.skybridge.hostType === \"apps-sdk\"\n ? AppsSdkAdaptor.getInstance()\n : McpAppAdaptor.getInstance();\n};\n"]}
1
+ {"version":3,"file":"get-adaptor.js","sourceRoot":"","sources":["../../../src/web/bridges/get-adaptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG3C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,GAAY,EAAE,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC","sourcesContent":["import { HostAdaptor } from \"./adaptor.js\";\nimport type { Adaptor } from \"./types.js\";\n\n/**\n * @internal\n * Resolve the single host {@link Adaptor} instance. Prefer the documented\n * hooks (`useCallTool`, `useViewState`, etc.) over calling this directly;\n * it's the escape hatch used by the hooks themselves and by advanced\n * integrations.\n */\nexport const getAdaptor = (): Adaptor => HostAdaptor.getInstance();\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,32 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { HostAdaptor } from "./adaptor.js";
3
+ import { AppsSdkBridge } from "./apps-sdk/bridge.js";
4
+ import { getAdaptor } from "./get-adaptor.js";
5
+ import { McpAppBridge } from "./mcp-app/bridge.js";
6
+ describe("getAdaptor", () => {
7
+ beforeEach(() => {
8
+ HostAdaptor.resetInstance();
9
+ McpAppBridge.resetInstance();
10
+ AppsSdkBridge.resetInstance();
11
+ vi.stubGlobal("parent", { postMessage: vi.fn() });
12
+ });
13
+ afterEach(() => {
14
+ vi.unstubAllGlobals();
15
+ HostAdaptor.resetInstance();
16
+ McpAppBridge.resetInstance();
17
+ AppsSdkBridge.resetInstance();
18
+ });
19
+ it("returns a HostAdaptor instance", () => {
20
+ vi.stubGlobal("skybridge", {});
21
+ vi.stubGlobal("openai", undefined);
22
+ expect(getAdaptor()).toBeInstanceOf(HostAdaptor);
23
+ });
24
+ it("memoizes the instance", () => {
25
+ vi.stubGlobal("skybridge", {});
26
+ vi.stubGlobal("openai", undefined);
27
+ const a = getAdaptor();
28
+ const b = getAdaptor();
29
+ expect(a).toBe(b);
30
+ });
31
+ });
32
+ //# sourceMappingURL=get-adaptor.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-adaptor.test.js","sourceRoot":"","sources":["../../../src/web/bridges/get-adaptor.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,UAAU,CAAC,GAAG,EAAE;QACd,WAAW,CAAC,aAAa,EAAE,CAAC;QAC5B,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;QAC9B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,WAAW,CAAC,aAAa,EAAE,CAAC;QAC5B,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC/B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC/B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;QACvB,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { HostAdaptor } from \"./adaptor.js\";\nimport { AppsSdkBridge } from \"./apps-sdk/bridge.js\";\nimport { getAdaptor } from \"./get-adaptor.js\";\nimport { McpAppBridge } from \"./mcp-app/bridge.js\";\n\ndescribe(\"getAdaptor\", () => {\n beforeEach(() => {\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n afterEach(() => {\n vi.unstubAllGlobals();\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n });\n\n it(\"returns a HostAdaptor instance\", () => {\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"openai\", undefined);\n expect(getAdaptor()).toBeInstanceOf(HostAdaptor);\n });\n\n it(\"memoizes the instance\", () => {\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"openai\", undefined);\n const a = getAdaptor();\n const b = getAdaptor();\n expect(a).toBe(b);\n });\n});\n"]}
@@ -1,8 +1,8 @@
1
+ import type { Implementation } from "@modelcontextprotocol/client";
1
2
  import { App } from "@modelcontextprotocol/ext-apps";
2
- import type { Implementation } from "@modelcontextprotocol/sdk/types.js";
3
- import type { Bridge, Subscribe } from "../types.js";
3
+ import type { AnyViewToolHandler, Bridge, HostContextStore, Subscribe, ViewToolConfig } from "../types.js";
4
4
  import type { McpAppContext, McpAppContextKey } from "./types.js";
5
- /** @internal Singleton bridge over the `ext-apps` JSON-RPC App connection. Used by {@link McpAppAdaptor}. */
5
+ /** @internal Singleton bridge over the `ext-apps` JSON-RPC App connection. Used by `HostAdaptor`. */
6
6
  export declare class McpAppBridge implements Bridge<McpAppContext> {
7
7
  private static instance;
8
8
  context: McpAppContext;
@@ -14,12 +14,24 @@ export declare class McpAppBridge implements Bridge<McpAppContext> {
14
14
  });
15
15
  private connect;
16
16
  getApp(): Promise<App>;
17
+ registerViewTool(config: ViewToolConfig, handler: AnyViewToolHandler): () => void;
17
18
  static getInstance(options?: Partial<{
18
19
  appInfo: Implementation;
19
20
  }>): McpAppBridge;
20
21
  subscribe(key: McpAppContextKey): Subscribe;
21
22
  subscribe(keys: readonly McpAppContextKey[]): Subscribe;
22
23
  getSnapshot<K extends keyof McpAppContext>(key: K): McpAppContext[K];
24
+ createContextStores(): {
25
+ theme: HostContextStore<"theme">;
26
+ locale: HostContextStore<"locale">;
27
+ safeArea: HostContextStore<"safeArea">;
28
+ displayMode: HostContextStore<"displayMode">;
29
+ maxHeight: HostContextStore<"maxHeight">;
30
+ userAgent: HostContextStore<"userAgent">;
31
+ toolInput: HostContextStore<"toolInput">;
32
+ toolOutput: HostContextStore<"toolOutput">;
33
+ toolResponseMetadata: HostContextStore<"toolResponseMetadata">;
34
+ };
23
35
  cleanup: () => void;
24
36
  static resetInstance(): void;
25
37
  private emit;