skybridge 0.0.0-dev.a660d12 → 0.0.0-dev.a664594

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 (319) hide show
  1. package/README.md +123 -124
  2. package/dist/cli/detect-port.js.map +1 -1
  3. package/dist/cli/header.js.map +1 -1
  4. package/dist/cli/resolve-views-dir.d.ts +1 -0
  5. package/dist/cli/resolve-views-dir.js +17 -0
  6. package/dist/cli/resolve-views-dir.js.map +1 -0
  7. package/dist/cli/run-command.js.map +1 -1
  8. package/dist/cli/telemetry.js.map +1 -1
  9. package/dist/cli/tunnel-control-server.d.ts +9 -0
  10. package/dist/cli/tunnel-control-server.js +31 -0
  11. package/dist/cli/tunnel-control-server.js.map +1 -0
  12. package/dist/cli/tunnel-control-server.test.js +39 -0
  13. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  14. package/dist/cli/tunnel-handler.d.ts +3 -0
  15. package/dist/cli/tunnel-handler.js +48 -0
  16. package/dist/cli/tunnel-handler.js.map +1 -0
  17. package/dist/cli/tunnel-handler.test.js +105 -0
  18. package/dist/cli/tunnel-handler.test.js.map +1 -0
  19. package/dist/cli/tunnel.d.ts +57 -0
  20. package/dist/cli/tunnel.js +154 -0
  21. package/dist/cli/tunnel.js.map +1 -0
  22. package/dist/cli/tunnel.test.js +190 -0
  23. package/dist/cli/tunnel.test.js.map +1 -0
  24. package/dist/cli/types.js.map +1 -1
  25. package/dist/cli/use-execute-steps.js.map +1 -1
  26. package/dist/cli/use-messages.js.map +1 -1
  27. package/dist/cli/use-nodemon.js +13 -4
  28. package/dist/cli/use-nodemon.js.map +1 -1
  29. package/dist/cli/use-open-browser.d.ts +1 -0
  30. package/dist/cli/use-open-browser.js +44 -0
  31. package/dist/cli/use-open-browser.js.map +1 -0
  32. package/dist/cli/use-tunnel.d.ts +1 -1
  33. package/dist/cli/use-tunnel.js +102 -68
  34. package/dist/cli/use-tunnel.js.map +1 -1
  35. package/dist/cli/use-typescript-check.d.ts +1 -0
  36. package/dist/cli/use-typescript-check.js +42 -7
  37. package/dist/cli/use-typescript-check.js.map +1 -1
  38. package/dist/commands/build.js +48 -7
  39. package/dist/commands/build.js.map +1 -1
  40. package/dist/commands/create.d.ts +9 -0
  41. package/dist/commands/create.js +30 -0
  42. package/dist/commands/create.js.map +1 -0
  43. package/dist/commands/dev.d.ts +1 -0
  44. package/dist/commands/dev.js +49 -2
  45. package/dist/commands/dev.js.map +1 -1
  46. package/dist/commands/start.js +2 -7
  47. package/dist/commands/start.js.map +1 -1
  48. package/dist/commands/telemetry/disable.js.map +1 -1
  49. package/dist/commands/telemetry/enable.js.map +1 -1
  50. package/dist/commands/telemetry/status.js.map +1 -1
  51. package/dist/server/asset-base-url-transform-plugin.d.ts +1 -0
  52. package/dist/server/asset-base-url-transform-plugin.js +17 -2
  53. package/dist/server/asset-base-url-transform-plugin.js.map +1 -1
  54. package/dist/server/asset-base-url-transform-plugin.test.js +80 -1
  55. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -1
  56. package/dist/server/auth.d.ts +20 -0
  57. package/dist/server/auth.js +28 -0
  58. package/dist/server/auth.js.map +1 -0
  59. package/dist/server/content-helpers.d.ts +67 -0
  60. package/dist/server/content-helpers.js +79 -0
  61. package/dist/server/content-helpers.js.map +1 -0
  62. package/dist/server/content-helpers.test.d.ts +1 -0
  63. package/dist/server/content-helpers.test.js +70 -0
  64. package/dist/server/content-helpers.test.js.map +1 -0
  65. package/dist/server/express.d.ts +1 -5
  66. package/dist/server/express.js +34 -10
  67. package/dist/server/express.js.map +1 -1
  68. package/dist/server/express.test.js +249 -71
  69. package/dist/server/express.test.js.map +1 -1
  70. package/dist/server/file-ref.d.ts +28 -0
  71. package/dist/server/file-ref.js +27 -0
  72. package/dist/server/file-ref.js.map +1 -0
  73. package/dist/server/index.d.ts +6 -3
  74. package/dist/server/index.js +5 -2
  75. package/dist/server/index.js.map +1 -1
  76. package/dist/server/inferUtilityTypes.d.ts +6 -6
  77. package/dist/server/inferUtilityTypes.js.map +1 -1
  78. package/dist/server/metric.js.map +1 -1
  79. package/dist/server/middleware.d.ts +16 -3
  80. package/dist/server/middleware.js.map +1 -1
  81. package/dist/server/middleware.test-d.js.map +1 -1
  82. package/dist/server/middleware.test.js +12 -9
  83. package/dist/server/middleware.test.js.map +1 -1
  84. package/dist/server/server.d.ts +321 -73
  85. package/dist/server/server.js +401 -145
  86. package/dist/server/server.js.map +1 -1
  87. package/dist/server/templateHelper.d.ts +5 -7
  88. package/dist/server/templateHelper.js +3 -22
  89. package/dist/server/templateHelper.js.map +1 -1
  90. package/dist/server/templates.generated.d.ts +4 -0
  91. package/dist/server/templates.generated.js +47 -0
  92. package/dist/server/templates.generated.js.map +1 -0
  93. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  94. package/dist/server/tunnel-proxy-router.js +110 -0
  95. package/dist/server/tunnel-proxy-router.js.map +1 -0
  96. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  97. package/dist/server/tunnel-proxy-router.test.js +229 -0
  98. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  99. package/dist/server/viewsDevServer.d.ts +14 -0
  100. package/dist/server/viewsDevServer.js +45 -0
  101. package/dist/server/viewsDevServer.js.map +1 -0
  102. package/dist/test/utils.d.ts +8 -20
  103. package/dist/test/utils.js +39 -35
  104. package/dist/test/utils.js.map +1 -1
  105. package/dist/test/view.test.d.ts +1 -0
  106. package/dist/test/view.test.js +568 -0
  107. package/dist/test/view.test.js.map +1 -0
  108. package/dist/version.js +1 -3
  109. package/dist/version.js.map +1 -1
  110. package/dist/web/bridges/adaptor.d.ts +48 -0
  111. package/dist/web/bridges/adaptor.js +308 -0
  112. package/dist/web/bridges/adaptor.js.map +1 -0
  113. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  114. package/dist/web/bridges/adaptor.test.js +375 -0
  115. package/dist/web/bridges/adaptor.test.js.map +1 -0
  116. package/dist/web/bridges/apps-sdk/bridge.d.ts +1 -0
  117. package/dist/web/bridges/apps-sdk/bridge.js +3 -3
  118. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  119. package/dist/web/bridges/apps-sdk/index.d.ts +0 -1
  120. package/dist/web/bridges/apps-sdk/index.js +0 -1
  121. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  122. package/dist/web/bridges/apps-sdk/types.d.ts +8 -1
  123. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  124. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +11 -0
  125. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +11 -0
  126. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  127. package/dist/web/bridges/get-adaptor.d.ts +9 -0
  128. package/dist/web/bridges/get-adaptor.js +27 -5
  129. package/dist/web/bridges/get-adaptor.js.map +1 -1
  130. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  131. package/dist/web/bridges/get-adaptor.test.js +48 -0
  132. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  133. package/dist/web/bridges/host-context-stores.d.ts +27 -0
  134. package/dist/web/bridges/host-context-stores.js +73 -0
  135. package/dist/web/bridges/host-context-stores.js.map +1 -0
  136. package/dist/web/bridges/index.js.map +1 -1
  137. package/dist/web/bridges/mcp-app/bridge.d.ts +1 -0
  138. package/dist/web/bridges/mcp-app/bridge.js +1 -3
  139. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  140. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  141. package/dist/web/bridges/mcp-app/bridge.test.js +21 -0
  142. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  143. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  144. package/dist/web/bridges/mcp-app/index.js +0 -1
  145. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  146. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  147. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +12 -0
  148. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +12 -0
  149. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  150. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  151. package/dist/web/bridges/types.d.ts +87 -10
  152. package/dist/web/bridges/types.js +14 -1
  153. package/dist/web/bridges/types.js.map +1 -1
  154. package/dist/web/bridges/types.test.d.ts +1 -0
  155. package/dist/web/bridges/types.test.js +19 -0
  156. package/dist/web/bridges/types.test.js.map +1 -0
  157. package/dist/web/bridges/use-host-context.d.ts +5 -0
  158. package/dist/web/bridges/use-host-context.js +5 -0
  159. package/dist/web/bridges/use-host-context.js.map +1 -1
  160. package/dist/web/components/modal-provider.js +4 -3
  161. package/dist/web/components/modal-provider.js.map +1 -1
  162. package/dist/web/create-store.d.ts +26 -0
  163. package/dist/web/create-store.js +35 -9
  164. package/dist/web/create-store.js.map +1 -1
  165. package/dist/web/create-store.test.js +21 -21
  166. package/dist/web/create-store.test.js.map +1 -1
  167. package/dist/web/data-llm.d.ts +34 -1
  168. package/dist/web/data-llm.js +31 -3
  169. package/dist/web/data-llm.js.map +1 -1
  170. package/dist/web/data-llm.test.js +30 -27
  171. package/dist/web/data-llm.test.js.map +1 -1
  172. package/dist/web/generate-helpers.d.ts +22 -18
  173. package/dist/web/generate-helpers.js +22 -18
  174. package/dist/web/generate-helpers.js.map +1 -1
  175. package/dist/web/generate-helpers.test-d.js +26 -26
  176. package/dist/web/generate-helpers.test-d.js.map +1 -1
  177. package/dist/web/generate-helpers.test.js.map +1 -1
  178. package/dist/web/helpers/state.d.ts +2 -2
  179. package/dist/web/helpers/state.js +11 -11
  180. package/dist/web/helpers/state.js.map +1 -1
  181. package/dist/web/helpers/state.test.js +9 -9
  182. package/dist/web/helpers/state.test.js.map +1 -1
  183. package/dist/web/hooks/index.d.ts +4 -1
  184. package/dist/web/hooks/index.js +4 -1
  185. package/dist/web/hooks/index.js.map +1 -1
  186. package/dist/web/hooks/test/utils.d.ts +6 -2
  187. package/dist/web/hooks/test/utils.js +13 -2
  188. package/dist/web/hooks/test/utils.js.map +1 -1
  189. package/dist/web/hooks/use-call-tool.d.ts +45 -0
  190. package/dist/web/hooks/use-call-tool.js +28 -0
  191. package/dist/web/hooks/use-call-tool.js.map +1 -1
  192. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  193. package/dist/web/hooks/use-call-tool.test.js +61 -27
  194. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  195. package/dist/web/hooks/use-display-mode.d.ts +20 -0
  196. package/dist/web/hooks/use-display-mode.js +20 -0
  197. package/dist/web/hooks/use-display-mode.js.map +1 -1
  198. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -1
  199. package/dist/web/hooks/use-display-mode.test.js +55 -20
  200. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  201. package/dist/web/hooks/use-download.d.ts +5 -0
  202. package/dist/web/hooks/use-download.js +8 -0
  203. package/dist/web/hooks/use-download.js.map +1 -0
  204. package/dist/web/hooks/use-download.test.d.ts +1 -0
  205. package/dist/web/hooks/use-download.test.js +103 -0
  206. package/dist/web/hooks/use-download.test.js.map +1 -0
  207. package/dist/web/hooks/use-files.d.ts +32 -0
  208. package/dist/web/hooks/use-files.js +32 -0
  209. package/dist/web/hooks/use-files.js.map +1 -1
  210. package/dist/web/hooks/use-files.test.js +10 -2
  211. package/dist/web/hooks/use-files.test.js.map +1 -1
  212. package/dist/web/hooks/use-layout.d.ts +2 -0
  213. package/dist/web/hooks/use-layout.js +2 -0
  214. package/dist/web/hooks/use-layout.js.map +1 -1
  215. package/dist/web/hooks/use-layout.test.js +59 -26
  216. package/dist/web/hooks/use-layout.test.js.map +1 -1
  217. package/dist/web/hooks/use-open-external.d.ts +17 -0
  218. package/dist/web/hooks/use-open-external.js +16 -0
  219. package/dist/web/hooks/use-open-external.js.map +1 -1
  220. package/dist/web/hooks/use-open-external.test.js +19 -5
  221. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  222. package/dist/web/hooks/use-request-close.d.ts +16 -0
  223. package/dist/web/hooks/use-request-close.js +21 -0
  224. package/dist/web/hooks/use-request-close.js.map +1 -0
  225. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  226. package/dist/web/hooks/use-request-close.test.js +46 -0
  227. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  228. package/dist/web/hooks/use-request-modal.d.ts +16 -1
  229. package/dist/web/hooks/use-request-modal.js +19 -4
  230. package/dist/web/hooks/use-request-modal.js.map +1 -1
  231. package/dist/web/hooks/use-request-modal.test.js +11 -1
  232. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  233. package/dist/web/hooks/use-request-size.d.ts +20 -0
  234. package/dist/web/hooks/use-request-size.js +24 -0
  235. package/dist/web/hooks/use-request-size.js.map +1 -0
  236. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  237. package/dist/web/hooks/use-request-size.test.js +47 -0
  238. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  239. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -1
  240. package/dist/web/hooks/use-send-follow-up-message.js +19 -2
  241. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  242. package/dist/web/hooks/use-set-open-in-app-url.d.ts +17 -0
  243. package/dist/web/hooks/use-set-open-in-app-url.js +17 -0
  244. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -1
  245. package/dist/web/hooks/use-set-open-in-app-url.test.js +28 -8
  246. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  247. package/dist/web/hooks/use-tool-info.d.ts +33 -0
  248. package/dist/web/hooks/use-tool-info.js +26 -0
  249. package/dist/web/hooks/use-tool-info.js.map +1 -1
  250. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  251. package/dist/web/hooks/use-tool-info.test.js +37 -27
  252. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  253. package/dist/web/hooks/use-user.d.ts +2 -0
  254. package/dist/web/hooks/use-user.js +2 -0
  255. package/dist/web/hooks/use-user.js.map +1 -1
  256. package/dist/web/hooks/use-user.test.js +81 -35
  257. package/dist/web/hooks/use-user.test.js.map +1 -1
  258. package/dist/web/hooks/use-view-state.d.ts +25 -0
  259. package/dist/web/hooks/use-view-state.js +32 -0
  260. package/dist/web/hooks/use-view-state.js.map +1 -0
  261. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  262. package/dist/web/hooks/{use-widget-state.test.js → use-view-state.test.js} +23 -19
  263. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  264. package/dist/web/index.d.ts +1 -2
  265. package/dist/web/index.js +1 -2
  266. package/dist/web/index.js.map +1 -1
  267. package/dist/web/mount-view.d.ts +20 -0
  268. package/dist/web/{mount-widget.js → mount-view.js} +21 -2
  269. package/dist/web/mount-view.js.map +1 -0
  270. package/dist/web/plugin/data-llm.test.js.map +1 -1
  271. package/dist/web/plugin/plugin.d.ts +32 -1
  272. package/dist/web/plugin/plugin.js +160 -25
  273. package/dist/web/plugin/plugin.js.map +1 -1
  274. package/dist/web/plugin/scan-views.d.ts +16 -0
  275. package/dist/web/plugin/scan-views.js +88 -0
  276. package/dist/web/plugin/scan-views.js.map +1 -0
  277. package/dist/web/plugin/scan-views.test.d.ts +1 -0
  278. package/dist/web/plugin/scan-views.test.js +99 -0
  279. package/dist/web/plugin/scan-views.test.js.map +1 -0
  280. package/dist/web/plugin/transform-data-llm.js.map +1 -1
  281. package/dist/web/plugin/transform-data-llm.test.js.map +1 -1
  282. package/dist/web/plugin/validate-view.d.ts +1 -0
  283. package/dist/web/plugin/validate-view.js +9 -0
  284. package/dist/web/plugin/validate-view.js.map +1 -0
  285. package/dist/web/plugin/validate-view.test.d.ts +1 -0
  286. package/dist/web/plugin/validate-view.test.js +24 -0
  287. package/dist/web/plugin/validate-view.test.js.map +1 -0
  288. package/dist/web/proxy.js.map +1 -1
  289. package/dist/web/types.d.ts +4 -0
  290. package/dist/web/types.js.map +1 -1
  291. package/package.json +30 -17
  292. package/tsconfig.base.json +2 -0
  293. package/dist/server/templates/development.hbs +0 -12
  294. package/dist/server/templates/production.hbs +0 -6
  295. package/dist/server/widgetsDevServer.d.ts +0 -13
  296. package/dist/server/widgetsDevServer.js +0 -52
  297. package/dist/server/widgetsDevServer.js.map +0 -1
  298. package/dist/test/widget.test.js +0 -334
  299. package/dist/test/widget.test.js.map +0 -1
  300. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -24
  301. package/dist/web/bridges/apps-sdk/adaptor.js +0 -87
  302. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  303. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -48
  304. package/dist/web/bridges/mcp-app/adaptor.js +0 -268
  305. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
  306. package/dist/web/hooks/use-widget-state.d.ts +0 -4
  307. package/dist/web/hooks/use-widget-state.js +0 -32
  308. package/dist/web/hooks/use-widget-state.js.map +0 -1
  309. package/dist/web/hooks/use-widget-state.test.js.map +0 -1
  310. package/dist/web/mount-widget.d.ts +0 -1
  311. package/dist/web/mount-widget.js.map +0 -1
  312. package/dist/web/plugin/validate-widget.d.ts +0 -5
  313. package/dist/web/plugin/validate-widget.js +0 -27
  314. package/dist/web/plugin/validate-widget.js.map +0 -1
  315. package/dist/web/plugin/validate-widget.test.js +0 -42
  316. package/dist/web/plugin/validate-widget.test.js.map +0 -1
  317. /package/dist/{test/widget.test.d.ts → cli/tunnel-control-server.test.d.ts} +0 -0
  318. /package/dist/{web/hooks/use-widget-state.test.d.ts → cli/tunnel-handler.test.d.ts} +0 -0
  319. /package/dist/{web/plugin/validate-widget.test.d.ts → cli/tunnel.test.d.ts} +0 -0
@@ -0,0 +1,375 @@
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 { McpAppBridge } from "./mcp-app/bridge.js";
5
+ import { NotSupportedError } from "./types.js";
6
+ describe("HostAdaptor constructor", () => {
7
+ beforeEach(() => {
8
+ McpAppBridge.resetInstance();
9
+ AppsSdkBridge.resetInstance();
10
+ vi.stubGlobal("skybridge", { hostType: "mcp-app" });
11
+ vi.stubGlobal("parent", { postMessage: vi.fn() });
12
+ });
13
+ afterEach(() => {
14
+ vi.unstubAllGlobals();
15
+ McpAppBridge.resetInstance();
16
+ AppsSdkBridge.resetInstance();
17
+ });
18
+ it("instantiates without window.openai (oai is null)", () => {
19
+ vi.stubGlobal("openai", undefined);
20
+ const adaptor = new HostAdaptor();
21
+ expect(adaptor.hasAppsSdkOverlay()).toBe(false);
22
+ });
23
+ it("captures window.openai when present (oai is set)", () => {
24
+ vi.stubGlobal("openai", { widgetState: null });
25
+ const adaptor = new HostAdaptor();
26
+ expect(adaptor.hasAppsSdkOverlay()).toBe(true);
27
+ });
28
+ });
29
+ describe("HostAdaptor MCP-routed methods", () => {
30
+ beforeEach(() => {
31
+ McpAppBridge.resetInstance();
32
+ AppsSdkBridge.resetInstance();
33
+ vi.stubGlobal("skybridge", { hostType: "mcp-app" });
34
+ vi.stubGlobal("parent", { postMessage: vi.fn() });
35
+ vi.stubGlobal("openai", undefined);
36
+ });
37
+ afterEach(() => {
38
+ vi.unstubAllGlobals();
39
+ McpAppBridge.resetInstance();
40
+ AppsSdkBridge.resetInstance();
41
+ });
42
+ it("callTool delegates to mcp.callServerTool", async () => {
43
+ const adaptor = new HostAdaptor();
44
+ const fakeApp = {
45
+ callServerTool: vi.fn().mockResolvedValue({
46
+ content: [],
47
+ structuredContent: { ok: true },
48
+ isError: false,
49
+ _meta: { x: 1 },
50
+ }),
51
+ };
52
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
53
+ adaptor.mcp.getApp = vi.fn().mockResolvedValue(fakeApp);
54
+ const result = await adaptor.callTool("greet", { name: "alice" });
55
+ expect(fakeApp.callServerTool).toHaveBeenCalledWith({
56
+ name: "greet",
57
+ arguments: { name: "alice" },
58
+ });
59
+ expect(result.structuredContent).toEqual({ ok: true });
60
+ expect(result.meta).toEqual({ x: 1 });
61
+ });
62
+ it("requestDisplayMode delegates to mcp.requestDisplayMode", async () => {
63
+ const adaptor = new HostAdaptor();
64
+ const fakeApp = {
65
+ requestDisplayMode: vi.fn().mockResolvedValue({ mode: "fullscreen" }),
66
+ };
67
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
68
+ adaptor.mcp.getApp = vi.fn().mockResolvedValue(fakeApp);
69
+ const r = await adaptor.requestDisplayMode("fullscreen");
70
+ expect(r.mode).toBe("fullscreen");
71
+ expect(fakeApp.requestDisplayMode).toHaveBeenCalledWith({
72
+ mode: "fullscreen",
73
+ });
74
+ });
75
+ it("requestClose delegates to mcp.requestTeardown", async () => {
76
+ const adaptor = new HostAdaptor();
77
+ const fakeApp = { requestTeardown: vi.fn().mockResolvedValue(undefined) };
78
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
79
+ adaptor.mcp.getApp = vi.fn().mockResolvedValue(fakeApp);
80
+ await adaptor.requestClose();
81
+ expect(fakeApp.requestTeardown).toHaveBeenCalled();
82
+ });
83
+ it("requestSize delegates to mcp.sendSizeChanged", async () => {
84
+ const adaptor = new HostAdaptor();
85
+ const fakeApp = { sendSizeChanged: vi.fn().mockResolvedValue(undefined) };
86
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
87
+ adaptor.mcp.getApp = vi.fn().mockResolvedValue(fakeApp);
88
+ await adaptor.requestSize({ width: 100, height: 200 });
89
+ expect(fakeApp.sendSizeChanged).toHaveBeenCalledWith({
90
+ width: 100,
91
+ height: 200,
92
+ });
93
+ });
94
+ it("download returns isError when host lacks downloadFile capability", async () => {
95
+ const adaptor = new HostAdaptor();
96
+ const fakeApp = {
97
+ getHostCapabilities: () => ({}),
98
+ downloadFile: vi.fn(),
99
+ };
100
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
101
+ adaptor.mcp.getApp = vi.fn().mockResolvedValue(fakeApp);
102
+ const r = await adaptor.download({ contents: [] });
103
+ expect(r.isError).toBe(true);
104
+ expect(fakeApp.downloadFile).not.toHaveBeenCalled();
105
+ });
106
+ });
107
+ describe("HostAdaptor conditional routing", () => {
108
+ beforeEach(() => {
109
+ McpAppBridge.resetInstance();
110
+ AppsSdkBridge.resetInstance();
111
+ vi.stubGlobal("skybridge", { hostType: "apps-sdk" });
112
+ vi.stubGlobal("parent", { postMessage: vi.fn() });
113
+ });
114
+ afterEach(() => {
115
+ vi.unstubAllGlobals();
116
+ McpAppBridge.resetInstance();
117
+ AppsSdkBridge.resetInstance();
118
+ });
119
+ it("sendFollowUpMessage uses oai when scrollToBottom set", async () => {
120
+ const sendFollowUpMessage = vi.fn().mockResolvedValue(undefined);
121
+ vi.stubGlobal("openai", { sendFollowUpMessage });
122
+ const adaptor = new HostAdaptor();
123
+ await adaptor.sendFollowUpMessage("hi", { scrollToBottom: false });
124
+ expect(sendFollowUpMessage).toHaveBeenCalledWith({
125
+ prompt: "hi",
126
+ scrollToBottom: false,
127
+ });
128
+ });
129
+ it("sendFollowUpMessage uses mcp when no options", async () => {
130
+ vi.stubGlobal("openai", undefined);
131
+ const adaptor = new HostAdaptor();
132
+ const fakeApp = { sendMessage: vi.fn().mockResolvedValue(undefined) };
133
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
134
+ adaptor.mcp.getApp = vi.fn().mockResolvedValue(fakeApp);
135
+ await adaptor.sendFollowUpMessage("hi");
136
+ expect(fakeApp.sendMessage).toHaveBeenCalledWith({
137
+ role: "user",
138
+ content: [{ type: "text", text: "hi" }],
139
+ });
140
+ });
141
+ it("openExternal uses oai when redirectUrl: false", async () => {
142
+ const openExternal = vi.fn();
143
+ vi.stubGlobal("openai", { openExternal });
144
+ const adaptor = new HostAdaptor();
145
+ adaptor.openExternal("https://x", { redirectUrl: false });
146
+ expect(openExternal).toHaveBeenCalledWith({
147
+ href: "https://x",
148
+ redirectUrl: false,
149
+ });
150
+ });
151
+ it("openExternal uses mcp.openLink for default case", async () => {
152
+ vi.stubGlobal("openai", undefined);
153
+ const adaptor = new HostAdaptor();
154
+ const openLink = vi.fn();
155
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
156
+ adaptor.mcp.getApp = vi.fn().mockResolvedValue({ openLink });
157
+ adaptor.openExternal("https://x");
158
+ // openExternal is sync but mcp.openLink resolves async
159
+ await new Promise((r) => setTimeout(r, 0));
160
+ expect(openLink).toHaveBeenCalledWith({ url: "https://x" });
161
+ });
162
+ });
163
+ describe("HostAdaptor Apps-SDK-only methods", () => {
164
+ beforeEach(() => {
165
+ McpAppBridge.resetInstance();
166
+ AppsSdkBridge.resetInstance();
167
+ vi.stubGlobal("skybridge", { hostType: "apps-sdk" });
168
+ vi.stubGlobal("parent", { postMessage: vi.fn() });
169
+ });
170
+ afterEach(() => {
171
+ vi.unstubAllGlobals();
172
+ McpAppBridge.resetInstance();
173
+ AppsSdkBridge.resetInstance();
174
+ });
175
+ it("uploadFile throws NotSupportedError when oai is null", async () => {
176
+ vi.stubGlobal("openai", undefined);
177
+ const adaptor = new HostAdaptor();
178
+ await expect(adaptor.uploadFile(new File([], "x"))).rejects.toThrow(NotSupportedError);
179
+ });
180
+ it("uploadFile delegates to oai.uploadFile and tracks fileId", async () => {
181
+ const setWidgetState = vi.fn().mockResolvedValue(undefined);
182
+ const uploadFile = vi
183
+ .fn()
184
+ .mockResolvedValue({ fileId: "abc", fileName: "x" });
185
+ vi.stubGlobal("openai", {
186
+ uploadFile,
187
+ setWidgetState,
188
+ widgetState: null,
189
+ });
190
+ const adaptor = new HostAdaptor();
191
+ const file = new File([], "x");
192
+ const r = await adaptor.uploadFile(file, { library: true });
193
+ expect(uploadFile).toHaveBeenCalledWith(file, { library: true });
194
+ expect(r.fileId).toBe("abc");
195
+ expect(setWidgetState).toHaveBeenCalledWith(expect.objectContaining({ imageIds: ["abc"] }));
196
+ });
197
+ it("selectFiles throws when oai is null", async () => {
198
+ vi.stubGlobal("openai", undefined);
199
+ const adaptor = new HostAdaptor();
200
+ await expect(adaptor.selectFiles()).rejects.toThrow(NotSupportedError);
201
+ });
202
+ it("selectFiles throws when host version lacks support", async () => {
203
+ vi.stubGlobal("openai", { selectFiles: undefined });
204
+ const adaptor = new HostAdaptor();
205
+ await expect(adaptor.selectFiles()).rejects.toThrow(/selectFiles/);
206
+ });
207
+ it("getFileDownloadUrl throws when oai is null", async () => {
208
+ vi.stubGlobal("openai", undefined);
209
+ const adaptor = new HostAdaptor();
210
+ await expect(adaptor.getFileDownloadUrl({ fileId: "x" })).rejects.toThrow(NotSupportedError);
211
+ });
212
+ it("setOpenInAppUrl throws when oai is null", async () => {
213
+ vi.stubGlobal("openai", undefined);
214
+ const adaptor = new HostAdaptor();
215
+ await expect(adaptor.setOpenInAppUrl("https://x")).rejects.toThrow(NotSupportedError);
216
+ });
217
+ });
218
+ describe("HostAdaptor modal", () => {
219
+ beforeEach(() => {
220
+ McpAppBridge.resetInstance();
221
+ AppsSdkBridge.resetInstance();
222
+ vi.stubGlobal("skybridge", { hostType: "apps-sdk" });
223
+ vi.stubGlobal("parent", { postMessage: vi.fn() });
224
+ });
225
+ afterEach(() => {
226
+ vi.unstubAllGlobals();
227
+ McpAppBridge.resetInstance();
228
+ AppsSdkBridge.resetInstance();
229
+ });
230
+ it("openModal delegates to oai.requestModal when present", () => {
231
+ const requestModal = vi.fn();
232
+ vi.stubGlobal("openai", { requestModal });
233
+ const adaptor = new HostAdaptor();
234
+ adaptor.openModal({ title: "Hi" });
235
+ expect(requestModal).toHaveBeenCalledWith({ title: "Hi" });
236
+ });
237
+ it("closeModal is a no-op when oai is present", () => {
238
+ vi.stubGlobal("openai", { requestModal: vi.fn() });
239
+ const adaptor = new HostAdaptor();
240
+ expect(() => adaptor.closeModal()).not.toThrow();
241
+ });
242
+ it("openModal sets polyfill display state when oai is null", () => {
243
+ vi.stubGlobal("openai", undefined);
244
+ const adaptor = new HostAdaptor();
245
+ const listener = vi.fn();
246
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
247
+ adaptor.polyfillDisplayListeners.add(listener);
248
+ adaptor.openModal({ params: { x: 1 } });
249
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
250
+ expect(adaptor._polyfillDisplay).toEqual({
251
+ mode: "modal",
252
+ params: { x: 1 },
253
+ });
254
+ expect(listener).toHaveBeenCalled();
255
+ });
256
+ it("closeModal resets polyfill display state when oai is null", () => {
257
+ vi.stubGlobal("openai", undefined);
258
+ const adaptor = new HostAdaptor();
259
+ adaptor.openModal({});
260
+ adaptor.closeModal();
261
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
262
+ expect(adaptor._polyfillDisplay).toEqual({ mode: "inline" });
263
+ });
264
+ });
265
+ describe("HostAdaptor setViewState", () => {
266
+ beforeEach(() => {
267
+ McpAppBridge.resetInstance();
268
+ AppsSdkBridge.resetInstance();
269
+ vi.stubGlobal("skybridge", { hostType: "apps-sdk" });
270
+ vi.stubGlobal("parent", { postMessage: vi.fn() });
271
+ localStorage.clear();
272
+ });
273
+ afterEach(() => {
274
+ vi.unstubAllGlobals();
275
+ McpAppBridge.resetInstance();
276
+ AppsSdkBridge.resetInstance();
277
+ localStorage.clear();
278
+ });
279
+ it("uses window.openai.setWidgetState when oai is present", async () => {
280
+ const setWidgetState = vi.fn().mockResolvedValue(undefined);
281
+ vi.stubGlobal("openai", { setWidgetState, widgetState: null });
282
+ const adaptor = new HostAdaptor();
283
+ await adaptor.setViewState({ count: 1 });
284
+ expect(setWidgetState).toHaveBeenCalledWith(expect.objectContaining({ modelContent: { count: 1 } }));
285
+ });
286
+ it("calls mcp.updateModelContext and writes localStorage when oai is null", async () => {
287
+ vi.stubGlobal("openai", undefined);
288
+ const adaptor = new HostAdaptor();
289
+ const updateModelContext = vi.fn().mockResolvedValue(undefined);
290
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
291
+ adaptor.mcp.getApp = vi
292
+ .fn()
293
+ .mockResolvedValue({ updateModelContext });
294
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
295
+ adaptor._viewUUID = "view-1";
296
+ await adaptor.setViewState({ count: 2 });
297
+ expect(updateModelContext).toHaveBeenCalledWith({
298
+ structuredContent: { count: 2 },
299
+ content: [{ type: "text", text: JSON.stringify({ count: 2 }) }],
300
+ });
301
+ const keys = [];
302
+ for (let i = 0; i < localStorage.length; i++) {
303
+ const key = localStorage.key(i);
304
+ if (key !== null) {
305
+ keys.push(key);
306
+ }
307
+ }
308
+ expect(keys.some((k) => k.endsWith(":view-1"))).toBe(true);
309
+ });
310
+ it("accepts an updater function form", async () => {
311
+ vi.stubGlobal("openai", undefined);
312
+ const adaptor = new HostAdaptor();
313
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
314
+ adaptor.mcp.getApp = vi.fn().mockResolvedValue({
315
+ updateModelContext: vi.fn().mockResolvedValue(undefined),
316
+ });
317
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
318
+ adaptor._viewState = { count: 1 };
319
+ await adaptor.setViewState((prev) => ({
320
+ // biome-ignore lint/suspicious/noExplicitAny: test
321
+ count: prev.count + 1,
322
+ }));
323
+ // biome-ignore lint/suspicious/noExplicitAny: test seam
324
+ expect(adaptor._viewState).toEqual({ count: 2 });
325
+ });
326
+ });
327
+ describe("HostAdaptor getHostContextStore", () => {
328
+ beforeEach(() => {
329
+ McpAppBridge.resetInstance();
330
+ AppsSdkBridge.resetInstance();
331
+ vi.stubGlobal("skybridge", { hostType: "apps-sdk" });
332
+ vi.stubGlobal("parent", { postMessage: vi.fn() });
333
+ });
334
+ afterEach(() => {
335
+ vi.unstubAllGlobals();
336
+ McpAppBridge.resetInstance();
337
+ AppsSdkBridge.resetInstance();
338
+ });
339
+ it("routes `display` to oai when overlay is present", () => {
340
+ vi.stubGlobal("openai", { view: { mode: "fullscreen" } });
341
+ const adaptor = new HostAdaptor();
342
+ const store = adaptor.getHostContextStore("display");
343
+ expect(store.getSnapshot()).toEqual({ mode: "fullscreen" });
344
+ });
345
+ it("routes `viewState` to oai.widgetState.modelContent when overlay present", () => {
346
+ vi.stubGlobal("openai", {
347
+ widgetState: { modelContent: { count: 5 }, privateContent: {} },
348
+ });
349
+ const adaptor = new HostAdaptor();
350
+ const store = adaptor.getHostContextStore("viewState");
351
+ expect(store.getSnapshot()).toEqual({ count: 5 });
352
+ });
353
+ it("routes `display` to polyfill when oai is null", () => {
354
+ vi.stubGlobal("openai", undefined);
355
+ const adaptor = new HostAdaptor();
356
+ const store = adaptor.getHostContextStore("display");
357
+ expect(store.getSnapshot()).toEqual({ mode: "inline" });
358
+ adaptor.openModal({});
359
+ expect(store.getSnapshot()).toEqual({ mode: "modal", params: undefined });
360
+ });
361
+ it("routes `viewState` to local LRU state when oai is null", () => {
362
+ vi.stubGlobal("openai", undefined);
363
+ const adaptor = new HostAdaptor();
364
+ const store = adaptor.getHostContextStore("viewState");
365
+ expect(store.getSnapshot()).toBe(null);
366
+ });
367
+ it("routes other keys (theme, locale, etc.) to mcp regardless of overlay", () => {
368
+ vi.stubGlobal("openai", { view: { mode: "inline" } });
369
+ const adaptor = new HostAdaptor();
370
+ const theme = adaptor.getHostContextStore("theme");
371
+ // default fallback when no notification yet
372
+ expect(theme.getSnapshot()).toBe("light");
373
+ });
374
+ });
375
+ //# 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":"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,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,UAAU,CAAC,GAAG,EAAE;QACd,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;QAC9B,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QACpD,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,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,UAAU,CAAC,GAAG,EAAE;QACd,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;QAC9B,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QACpD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAClD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG;YACd,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;gBACxC,OAAO,EAAE,EAAE;gBACX,iBAAiB,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE;aAChB,CAAC;SACH,CAAC;QACF,wDAAwD;QACvD,OAAe,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAEjE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAClE,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,oBAAoB,CAAC;YAClD,IAAI,EAAE,OAAO;YACb,SAAS,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;SAC7B,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG;YACd,kBAAkB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;SACtE,CAAC;QACF,wDAAwD;QACvD,OAAe,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACjE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;QACzD,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAClC,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,oBAAoB,CAAC;YACtD,IAAI,EAAE,YAAY;SACnB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG,EAAE,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1E,wDAAwD;QACvD,OAAe,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACjE,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC;QAC7B,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,gBAAgB,EAAE,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG,EAAE,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1E,wDAAwD;QACvD,OAAe,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACjE,MAAM,OAAO,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACvD,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,oBAAoB,CAAC;YACnD,KAAK,EAAE,GAAG;YACV,MAAM,EAAE,GAAG;SACZ,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QAChF,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG;YACd,mBAAmB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;YAC/B,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE;SACtB,CAAC;QACF,wDAAwD;QACvD,OAAe,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACjE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QACnD,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,UAAU,CAAC,GAAG,EAAE;QACd,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;QAC9B,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACrD,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,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,mBAAmB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QACjE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,OAAO,CAAC,mBAAmB,CAAC,IAAI,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC;QACnE,MAAM,CAAC,mBAAmB,CAAC,CAAC,oBAAoB,CAAC;YAC/C,MAAM,EAAE,IAAI;YACZ,cAAc,EAAE,KAAK;SACtB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;QACtE,wDAAwD;QACvD,OAAe,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACjE,MAAM,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,oBAAoB,CAAC;YAC/C,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;SACxC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,YAAY,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,OAAO,CAAC,YAAY,CAAC,WAAW,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1D,MAAM,CAAC,YAAY,CAAC,CAAC,oBAAoB,CAAC;YACxC,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,KAAK;SACnB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACzB,wDAAwD;QACvD,OAAe,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QACtE,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;QAClC,uDAAuD;QACvD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,mCAAmC,EAAE,GAAG,EAAE;IACjD,UAAU,CAAC,GAAG,EAAE;QACd,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;QAC9B,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACrD,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,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACjE,iBAAiB,CAClB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,cAAc,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAC5D,MAAM,UAAU,GAAG,EAAE;aAClB,EAAE,EAAE;aACJ,iBAAiB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;QACvD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE;YACtB,UAAU;YACV,cAAc;YACd,WAAW,EAAE,IAAI;SAClB,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,CAAC,UAAU,CAAC,CAAC,oBAAoB,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACjE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,MAAM,CAAC,cAAc,CAAC,CAAC,oBAAoB,CACzC,MAAM,CAAC,gBAAgB,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAC/C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;QACpD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACvE,iBAAiB,CAClB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAChE,iBAAiB,CAClB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,UAAU,CAAC,GAAG,EAAE;QACd,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;QAC9B,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACrD,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,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,YAAY,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,OAAO,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnC,MAAM,CAAC,YAAY,CAAC,CAAC,oBAAoB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACzB,wDAAwD;QACvD,OAAe,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxD,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACxC,wDAAwD;QACxD,MAAM,CAAE,OAAe,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC;YAChD,IAAI,EAAE,OAAO;YACb,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE;SACjB,CAAC,CAAC;QACH,MAAM,CAAC,QAAQ,CAAC,CAAC,gBAAgB,EAAE,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACtB,OAAO,CAAC,UAAU,EAAE,CAAC;QACrB,wDAAwD;QACxD,MAAM,CAAE,OAAe,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,UAAU,CAAC,GAAG,EAAE;QACd,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;QAC9B,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACrD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAClD,YAAY,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;QAC9B,YAAY,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,cAAc,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAC5D,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,OAAO,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACzC,MAAM,CAAC,cAAc,CAAC,CAAC,oBAAoB,CACzC,MAAM,CAAC,gBAAgB,CAAC,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CACxD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QACrF,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,kBAAkB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAChE,wDAAwD;QACvD,OAAe,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE;aAC7B,EAAE,EAAE;aACJ,iBAAiB,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC7C,wDAAwD;QACvD,OAAe,CAAC,SAAS,GAAG,QAAQ,CAAC;QACtC,MAAM,OAAO,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACzC,MAAM,CAAC,kBAAkB,CAAC,CAAC,oBAAoB,CAAC;YAC9C,iBAAiB,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE;YAC/B,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;SAChE,CAAC,CAAC;QACH,MAAM,IAAI,GAAa,EAAE,CAAC;QAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACjB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACjB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,wDAAwD;QACvD,OAAe,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;YACtD,kBAAkB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;SACzD,CAAC,CAAC;QACH,wDAAwD;QACvD,OAAe,CAAC,UAAU,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAC3C,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACpC,mDAAmD;YACnD,KAAK,EAAG,IAAY,CAAC,KAAK,GAAG,CAAC;SAC/B,CAAC,CAAC,CAAC;QACJ,wDAAwD;QACxD,MAAM,CAAE,OAAe,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,UAAU,CAAC,GAAG,EAAE;QACd,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;QAC9B,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACrD,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,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;QAC1D,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,OAAO,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACjF,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE;YACtB,WAAW,EAAE,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE;SAChE,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,OAAO,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,OAAO,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QACxD,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACtB,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,OAAO,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACnD,4CAA4C;QAC5C,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,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 { McpAppBridge } from \"./mcp-app/bridge.js\";\nimport { NotSupportedError } from \"./types.js\";\n\ndescribe(\"HostAdaptor constructor\", () => {\n beforeEach(() => {\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"skybridge\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n afterEach(() => {\n vi.unstubAllGlobals();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n });\n\n it(\"instantiates without window.openai (oai is null)\", () => {\n vi.stubGlobal(\"openai\", undefined);\n const adaptor = new HostAdaptor();\n expect(adaptor.hasAppsSdkOverlay()).toBe(false);\n });\n\n it(\"captures window.openai when present (oai is set)\", () => {\n vi.stubGlobal(\"openai\", { widgetState: null });\n const adaptor = new HostAdaptor();\n expect(adaptor.hasAppsSdkOverlay()).toBe(true);\n });\n});\n\ndescribe(\"HostAdaptor MCP-routed methods\", () => {\n beforeEach(() => {\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"skybridge\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n vi.stubGlobal(\"openai\", undefined);\n });\n afterEach(() => {\n vi.unstubAllGlobals();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n });\n\n it(\"callTool delegates to mcp.callServerTool\", async () => {\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 name: \"greet\",\n arguments: { name: \"alice\" },\n });\n expect(result.structuredContent).toEqual({ ok: true });\n expect(result.meta).toEqual({ x: 1 });\n });\n\n it(\"requestDisplayMode delegates to mcp.requestDisplayMode\", async () => {\n const adaptor = new HostAdaptor();\n const fakeApp = {\n requestDisplayMode: vi.fn().mockResolvedValue({ mode: \"fullscreen\" }),\n };\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n (adaptor as any).mcp.getApp = vi.fn().mockResolvedValue(fakeApp);\n const r = await adaptor.requestDisplayMode(\"fullscreen\");\n expect(r.mode).toBe(\"fullscreen\");\n expect(fakeApp.requestDisplayMode).toHaveBeenCalledWith({\n mode: \"fullscreen\",\n });\n });\n\n it(\"requestClose delegates to mcp.requestTeardown\", async () => {\n const adaptor = new HostAdaptor();\n const fakeApp = { requestTeardown: vi.fn().mockResolvedValue(undefined) };\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n (adaptor as any).mcp.getApp = vi.fn().mockResolvedValue(fakeApp);\n await adaptor.requestClose();\n expect(fakeApp.requestTeardown).toHaveBeenCalled();\n });\n\n it(\"requestSize delegates to mcp.sendSizeChanged\", async () => {\n const adaptor = new HostAdaptor();\n const fakeApp = { sendSizeChanged: vi.fn().mockResolvedValue(undefined) };\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n (adaptor as any).mcp.getApp = vi.fn().mockResolvedValue(fakeApp);\n await adaptor.requestSize({ width: 100, height: 200 });\n expect(fakeApp.sendSizeChanged).toHaveBeenCalledWith({\n width: 100,\n height: 200,\n });\n });\n\n it(\"download returns isError when host lacks downloadFile capability\", async () => {\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\ndescribe(\"HostAdaptor conditional routing\", () => {\n beforeEach(() => {\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"skybridge\", { hostType: \"apps-sdk\" });\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n afterEach(() => {\n vi.unstubAllGlobals();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n });\n\n it(\"sendFollowUpMessage uses oai when scrollToBottom set\", async () => {\n const sendFollowUpMessage = vi.fn().mockResolvedValue(undefined);\n vi.stubGlobal(\"openai\", { sendFollowUpMessage });\n const adaptor = new HostAdaptor();\n await adaptor.sendFollowUpMessage(\"hi\", { scrollToBottom: false });\n expect(sendFollowUpMessage).toHaveBeenCalledWith({\n prompt: \"hi\",\n scrollToBottom: false,\n });\n });\n\n it(\"sendFollowUpMessage uses mcp when no options\", async () => {\n vi.stubGlobal(\"openai\", undefined);\n const adaptor = new HostAdaptor();\n const fakeApp = { sendMessage: vi.fn().mockResolvedValue(undefined) };\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n (adaptor as any).mcp.getApp = vi.fn().mockResolvedValue(fakeApp);\n await adaptor.sendFollowUpMessage(\"hi\");\n expect(fakeApp.sendMessage).toHaveBeenCalledWith({\n role: \"user\",\n content: [{ type: \"text\", text: \"hi\" }],\n });\n });\n\n it(\"openExternal uses oai when redirectUrl: false\", async () => {\n const openExternal = vi.fn();\n vi.stubGlobal(\"openai\", { openExternal });\n const adaptor = new HostAdaptor();\n adaptor.openExternal(\"https://x\", { redirectUrl: false });\n expect(openExternal).toHaveBeenCalledWith({\n href: \"https://x\",\n redirectUrl: false,\n });\n });\n\n it(\"openExternal uses mcp.openLink for default case\", async () => {\n vi.stubGlobal(\"openai\", undefined);\n const 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 // openExternal is sync but mcp.openLink resolves async\n await new Promise((r) => setTimeout(r, 0));\n expect(openLink).toHaveBeenCalledWith({ url: \"https://x\" });\n });\n});\n\ndescribe(\"HostAdaptor Apps-SDK-only methods\", () => {\n beforeEach(() => {\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"skybridge\", { hostType: \"apps-sdk\" });\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n afterEach(() => {\n vi.unstubAllGlobals();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n });\n\n it(\"uploadFile throws NotSupportedError when oai 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 });\n\n it(\"uploadFile delegates to oai.uploadFile and tracks fileId\", async () => {\n const setWidgetState = vi.fn().mockResolvedValue(undefined);\n const uploadFile = vi\n .fn()\n .mockResolvedValue({ fileId: \"abc\", fileName: \"x\" });\n vi.stubGlobal(\"openai\", {\n uploadFile,\n setWidgetState,\n widgetState: null,\n });\n const adaptor = new HostAdaptor();\n const file = new File([], \"x\");\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(\"selectFiles throws when oai is null\", async () => {\n vi.stubGlobal(\"openai\", undefined);\n const adaptor = new HostAdaptor();\n await expect(adaptor.selectFiles()).rejects.toThrow(NotSupportedError);\n });\n\n it(\"selectFiles throws when host version lacks support\", async () => {\n vi.stubGlobal(\"openai\", { selectFiles: undefined });\n const adaptor = new HostAdaptor();\n await expect(adaptor.selectFiles()).rejects.toThrow(/selectFiles/);\n });\n\n it(\"getFileDownloadUrl throws when oai is null\", async () => {\n vi.stubGlobal(\"openai\", undefined);\n const adaptor = new HostAdaptor();\n await expect(adaptor.getFileDownloadUrl({ fileId: \"x\" })).rejects.toThrow(\n NotSupportedError,\n );\n });\n\n it(\"setOpenInAppUrl throws when oai is null\", async () => {\n vi.stubGlobal(\"openai\", undefined);\n const adaptor = new HostAdaptor();\n await expect(adaptor.setOpenInAppUrl(\"https://x\")).rejects.toThrow(\n NotSupportedError,\n );\n });\n});\n\ndescribe(\"HostAdaptor modal\", () => {\n beforeEach(() => {\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"skybridge\", { hostType: \"apps-sdk\" });\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n afterEach(() => {\n vi.unstubAllGlobals();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n });\n\n it(\"openModal delegates to oai.requestModal when present\", () => {\n const requestModal = vi.fn();\n vi.stubGlobal(\"openai\", { requestModal });\n const adaptor = new HostAdaptor();\n adaptor.openModal({ title: \"Hi\" });\n expect(requestModal).toHaveBeenCalledWith({ title: \"Hi\" });\n });\n\n it(\"closeModal is a no-op when oai is present\", () => {\n vi.stubGlobal(\"openai\", { requestModal: vi.fn() });\n const adaptor = new HostAdaptor();\n expect(() => adaptor.closeModal()).not.toThrow();\n });\n\n it(\"openModal sets polyfill display state when oai is null\", () => {\n vi.stubGlobal(\"openai\", undefined);\n const adaptor = new HostAdaptor();\n const listener = vi.fn();\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n (adaptor as any).polyfillDisplayListeners.add(listener);\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 expect(listener).toHaveBeenCalled();\n });\n\n it(\"closeModal resets polyfill display state when oai is null\", () => {\n vi.stubGlobal(\"openai\", undefined);\n const adaptor = new HostAdaptor();\n adaptor.openModal({});\n adaptor.closeModal();\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n expect((adaptor as any)._polyfillDisplay).toEqual({ mode: \"inline\" });\n });\n});\n\ndescribe(\"HostAdaptor setViewState\", () => {\n beforeEach(() => {\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"skybridge\", { hostType: \"apps-sdk\" });\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(\"uses window.openai.setWidgetState when oai is 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(\"calls mcp.updateModelContext and writes localStorage when oai is null\", 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: [{ type: \"text\", text: JSON.stringify({ count: 2 }) }],\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(\"accepts an updater function form\", async () => {\n vi.stubGlobal(\"openai\", undefined);\n const adaptor = new HostAdaptor();\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n (adaptor as any).mcp.getApp = vi.fn().mockResolvedValue({\n updateModelContext: vi.fn().mockResolvedValue(undefined),\n });\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n (adaptor as any)._viewState = { count: 1 };\n await adaptor.setViewState((prev) => ({\n // biome-ignore lint/suspicious/noExplicitAny: test\n count: (prev as any).count + 1,\n }));\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n expect((adaptor as any)._viewState).toEqual({ count: 2 });\n });\n});\n\ndescribe(\"HostAdaptor getHostContextStore\", () => {\n beforeEach(() => {\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"skybridge\", { hostType: \"apps-sdk\" });\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n afterEach(() => {\n vi.unstubAllGlobals();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n });\n\n it(\"routes `display` to oai when overlay is present\", () => {\n vi.stubGlobal(\"openai\", { view: { mode: \"fullscreen\" } });\n const adaptor = new HostAdaptor();\n const store = adaptor.getHostContextStore(\"display\");\n expect(store.getSnapshot()).toEqual({ mode: \"fullscreen\" });\n });\n\n it(\"routes `viewState` to oai.widgetState.modelContent when overlay present\", () => {\n vi.stubGlobal(\"openai\", {\n widgetState: { modelContent: { count: 5 }, privateContent: {} },\n });\n const adaptor = new HostAdaptor();\n const store = adaptor.getHostContextStore(\"viewState\");\n expect(store.getSnapshot()).toEqual({ count: 5 });\n });\n\n it(\"routes `display` to polyfill when oai is null\", () => {\n vi.stubGlobal(\"openai\", undefined);\n const adaptor = new HostAdaptor();\n const store = adaptor.getHostContextStore(\"display\");\n expect(store.getSnapshot()).toEqual({ mode: \"inline\" });\n adaptor.openModal({});\n expect(store.getSnapshot()).toEqual({ mode: \"modal\", params: undefined });\n });\n\n it(\"routes `viewState` to local LRU state when oai is null\", () => {\n vi.stubGlobal(\"openai\", undefined);\n const adaptor = new HostAdaptor();\n const store = adaptor.getHostContextStore(\"viewState\");\n expect(store.getSnapshot()).toBe(null);\n });\n\n it(\"routes other keys (theme, locale, etc.) to mcp regardless of overlay\", () => {\n vi.stubGlobal(\"openai\", { view: { mode: \"inline\" } });\n const adaptor = new HostAdaptor();\n const theme = adaptor.getHostContextStore(\"theme\");\n // default fallback when no notification yet\n expect(theme.getSnapshot()).toBe(\"light\");\n });\n});\n"]}
@@ -1,5 +1,6 @@
1
1
  import type { Bridge, Subscribe } from "../types.js";
2
2
  import { type AppsSdkContext } from "./types.js";
3
+ /** @internal Singleton bridge over `window.openai` events. Used by `HostAdaptor`. */
3
4
  export declare class AppsSdkBridge implements Bridge<AppsSdkContext> {
4
5
  private static instance;
5
6
  static getInstance(): AppsSdkBridge;
@@ -1,10 +1,10 @@
1
1
  import { SET_GLOBALS_EVENT_TYPE, } from "./types.js";
2
+ /** @internal Singleton bridge over `window.openai` events. Used by `HostAdaptor`. */
2
3
  export class AppsSdkBridge {
3
4
  static instance = null;
4
5
  static getInstance() {
5
- if (window.skybridge.hostType !== "apps-sdk" ||
6
- window.openai === undefined) {
7
- 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).");
8
8
  }
9
9
  if (AppsSdkBridge.instance === null) {
10
10
  AppsSdkBridge.instance = new AppsSdkBridge();
@@ -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,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"}
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","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 `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"]}
@@ -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"}
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"]}
@@ -42,9 +42,14 @@ export type AppsSdkContext<ToolInput extends UnknownObject = Record<never, unkno
42
42
  export type AppsSdkMethods<WS extends AppsSdkWidgetState = AppsSdkWidgetState> = {
43
43
  /** Calls a tool on your MCP. Returns the full response. */
44
44
  callTool: <ToolArgs extends CallToolArgs = null, ToolResponse extends CallToolResponse = CallToolResponse>(name: string, args: ToolArgs) => Promise<ToolResponse>;
45
- /** Triggers a followup turn in the ChatGPT conversation */
45
+ /**
46
+ * Triggers a followup turn in the ChatGPT conversation
47
+ * scrollToBottom is optional, defaults to true, and can be
48
+ * set to false to prevent auto-scroll.
49
+ */
46
50
  sendFollowUpMessage: (args: {
47
51
  prompt: string;
52
+ scrollToBottom?: boolean;
48
53
  }) => Promise<void>;
49
54
  /** Opens an external link, redirects web page or mobile app */
50
55
  openExternal(args: {
@@ -61,6 +66,8 @@ export type AppsSdkMethods<WS extends AppsSdkWidgetState = AppsSdkWidgetState> =
61
66
  */
62
67
  mode: RequestDisplayMode;
63
68
  }>;
69
+ /** Requests the host to close (dismiss) the widget. */
70
+ requestClose: () => Promise<void>;
64
71
  /**
65
72
  * Sets the widget state.
66
73
  * This state is persisted across widget renders.
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/web/bridges/apps-sdk/types.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,wBAAwB,GAAG,sBAAsB,CAAC;AAC/D,MAAM,OAAO,iBAAkB,SAAQ,WAErC;IACkB,IAAI,GAAG,wBAAwB,CAAC;CACnD;AAoGD,sDAAsD;AACtD,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAC3D,MAAM,OAAO,eAAgB,SAAQ,WAEnC;IACkB,IAAI,GAAG,sBAAsB,CAAC;CACjD"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/web/bridges/apps-sdk/types.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,wBAAwB,GAAG,sBAAsB,CAAC;AAC/D,MAAM,OAAO,iBAAkB,SAAQ,WAErC;IACkB,IAAI,GAAG,wBAAwB,CAAC;CACnD;AA8GD,sDAAsD;AACtD,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAC3D,MAAM,OAAO,eAAgB,SAAQ,WAEnC;IACkB,IAAI,GAAG,sBAAsB,CAAC;CACjD","sourcesContent":["import type { UnknownObject } from \"../../types.js\";\nimport type {\n CallToolArgs,\n CallToolResponse,\n FileMetadata,\n RequestModalOptions,\n UploadFileOptions,\n} from \"../types.js\";\n\ntype DisplayMode = \"pip\" | \"inline\" | \"fullscreen\" | \"modal\";\ntype RequestDisplayMode = Exclude<DisplayMode, \"modal\">;\n\nexport type AppsSdkWidgetState = {\n modelContent: Record<string, unknown>;\n privateContent: Record<string, unknown>;\n imageIds?: string[];\n};\n\nexport const TOOL_RESPONSE_EVENT_TYPE = \"openai:tool_response\";\nexport class ToolResponseEvent extends CustomEvent<{\n tool: { name: string; args: UnknownObject };\n}> {\n override readonly type = TOOL_RESPONSE_EVENT_TYPE;\n}\n\ndeclare global {\n interface Window {\n openai: AppsSdkMethods & AppsSdkContext;\n }\n\n interface WindowEventMap {\n [SET_GLOBALS_EVENT_TYPE]: SetGlobalsEvent;\n }\n}\n\nexport type AppsSdkContext<\n ToolInput extends UnknownObject = Record<never, unknown>,\n ToolOutput extends UnknownObject = UnknownObject,\n ToolResponseMetadata extends UnknownObject = UnknownObject,\n WS extends AppsSdkWidgetState = AppsSdkWidgetState,\n> = {\n theme: Theme;\n userAgent: UserAgent;\n locale: string;\n\n // layout\n maxHeight: number | undefined;\n displayMode: DisplayMode;\n safeArea: SafeArea;\n view: View;\n\n // state\n toolInput: ToolInput;\n toolOutput: ToolOutput | { text: string } | null;\n toolResponseMetadata: ToolResponseMetadata | null;\n widgetState: WS | null;\n};\n\nexport type AppsSdkMethods<WS extends AppsSdkWidgetState = AppsSdkWidgetState> =\n {\n /** Calls a tool on your MCP. Returns the full response. */\n callTool: <\n ToolArgs extends CallToolArgs = null,\n ToolResponse extends CallToolResponse = CallToolResponse,\n >(\n name: string,\n args: ToolArgs,\n ) => Promise<ToolResponse>;\n\n /**\n * Triggers a followup turn in the ChatGPT conversation\n * scrollToBottom is optional, defaults to true, and can be\n * set to false to prevent auto-scroll.\n */\n sendFollowUpMessage: (args: {\n prompt: string;\n scrollToBottom?: boolean;\n }) => Promise<void>;\n\n /** Opens an external link, redirects web page or mobile app */\n openExternal(args: { href: string; redirectUrl?: false }): void;\n\n /** For transitioning an app from inline to fullscreen or pip */\n requestDisplayMode: (args: { mode: RequestDisplayMode }) => Promise<{\n /**\n * The granted display mode. The host may reject the request.\n * For mobile, PiP is always coerced to fullscreen.\n */\n mode: RequestDisplayMode;\n }>;\n\n /** Requests the host to close (dismiss) the widget. */\n requestClose: () => Promise<void>;\n\n /**\n * Sets the widget state.\n * This state is persisted across widget renders.\n */\n setWidgetState: (state: WS) => Promise<void>;\n\n /**\n * Opens a modal portaled outside of the widget iFrame.\n * This ensures the modal is correctly displayed and not limited to the widget's area.\n */\n requestModal: (args: RequestModalOptions) => Promise<void>;\n\n /** Uploads a new file to the host. Pass `{ library: true }` to also save to the user's ChatGPT file library. */\n uploadFile: (\n file: File,\n options?: UploadFileOptions,\n ) => Promise<FileMetadata>;\n\n /**\n * Opens ChatGPT's file library picker and returns app-authorized files.\n * Feature-detect before using: this method may not be available on all host versions.\n */\n selectFiles?: () => Promise<FileMetadata[]>;\n\n /**\n * Downloads a file from the host. Works for files uploaded by the widget,\n * files selected via selectFiles(), or files provided via tool/file params.\n */\n getFileDownloadUrl: (\n file: FileMetadata,\n ) => Promise<{ downloadUrl: string }>;\n\n /**\n * Sets the open in app URL.\n * This URL will be opened in the app when the user clicks on the top right button in fullscreen mode.\n */\n setOpenInAppUrl: (args: { href: string }) => Promise<void>;\n };\n\n// Dispatched when any global changes in the host page\nexport const SET_GLOBALS_EVENT_TYPE = \"openai:set_globals\";\nexport class SetGlobalsEvent extends CustomEvent<{\n globals: Partial<AppsSdkContext>;\n}> {\n override readonly type = SET_GLOBALS_EVENT_TYPE;\n}\n\ntype View = {\n mode: DisplayMode;\n params?: Record<string, unknown>;\n};\n\ntype Theme = \"light\" | \"dark\";\n\ntype SafeAreaInsets = {\n top: number;\n bottom: number;\n left: number;\n right: number;\n};\n\ntype SafeArea = {\n insets: SafeAreaInsets;\n};\n\ntype DeviceType = \"mobile\" | \"tablet\" | \"desktop\" | \"unknown\";\n\ntype UserAgent = {\n device: { type: DeviceType };\n capabilities: {\n hover: boolean;\n touch: boolean;\n };\n};\n"]}
@@ -1,2 +1,13 @@
1
1
  import type { AppsSdkContext } from "./types.js";
2
+ /**
3
+ * Read a single key from the raw Apps SDK (`window.openai`) context.
4
+ *
5
+ * Advanced escape hatch — prefer the cross-host hooks (`useLayout`, `useUser`,
6
+ * `useToolInfo`, etc.) which work in both Apps SDK and MCP Apps. Reach for
7
+ * this when you need ChatGPT-only fields not surfaced by the public hooks.
8
+ *
9
+ * Throws if called outside the Apps SDK runtime.
10
+ *
11
+ * @see https://docs.skybridge.tech/api-reference/use-apps-sdk-context
12
+ */
2
13
  export declare function useAppsSdkContext<K extends keyof AppsSdkContext>(key: K): AppsSdkContext[K];
@@ -1,5 +1,16 @@
1
1
  import { useSyncExternalStore } from "react";
2
2
  import { AppsSdkBridge } from "./bridge.js";
3
+ /**
4
+ * Read a single key from the raw Apps SDK (`window.openai`) context.
5
+ *
6
+ * Advanced escape hatch — prefer the cross-host hooks (`useLayout`, `useUser`,
7
+ * `useToolInfo`, etc.) which work in both Apps SDK and MCP Apps. Reach for
8
+ * this when you need ChatGPT-only fields not surfaced by the public hooks.
9
+ *
10
+ * Throws if called outside the Apps SDK runtime.
11
+ *
12
+ * @see https://docs.skybridge.tech/api-reference/use-apps-sdk-context
13
+ */
3
14
  export function useAppsSdkContext(key) {
4
15
  const bridge = AppsSdkBridge.getInstance();
5
16
  return useSyncExternalStore(bridge.subscribe(key), () => bridge.getSnapshot(key));
@@ -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,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"}
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,2 +1,11 @@
1
1
  import type { Adaptor } from "./types.js";
2
+ /**
3
+ * @internal
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
+ */
2
9
  export declare const getAdaptor: () => Adaptor;
10
+ /** @internal Test-only. */
11
+ export declare const _resetAdaptor: () => void;
@@ -1,8 +1,30 @@
1
- import { AppsSdkAdaptor } from "./apps-sdk/adaptor.js";
2
- import { McpAppAdaptor } from "./mcp-app/adaptor.js";
1
+ import { HostAdaptor } from "./adaptor.js";
2
+ let cached = null;
3
+ /**
4
+ * @internal
5
+ * Resolve the single host {@link Adaptor} instance. Prefer the documented
6
+ * hooks (`useCallTool`, `useViewState`, etc.) over calling this directly;
7
+ * it's the escape hatch used by the hooks themselves and by advanced
8
+ * integrations.
9
+ */
3
10
  export const getAdaptor = () => {
4
- return window.skybridge.hostType === "apps-sdk"
5
- ? AppsSdkAdaptor.getInstance()
6
- : McpAppAdaptor.getInstance();
11
+ if (cached) {
12
+ return cached;
13
+ }
14
+ const hostType = typeof window !== "undefined" ? window.skybridge?.hostType : undefined;
15
+ const hasOai = typeof window !== "undefined" && window.openai !== undefined;
16
+ if (hostType === "mcp-app" && hasOai) {
17
+ console.warn("[skybridge] hostType is 'mcp-app' but window.openai is present; trusting the probe.");
18
+ }
19
+ else if (hostType === "apps-sdk" && !hasOai) {
20
+ console.warn("[skybridge] hostType is 'apps-sdk' but window.openai is absent; trusting the probe.");
21
+ }
22
+ cached = new HostAdaptor();
23
+ return cached;
24
+ };
25
+ /** @internal Test-only. */
26
+ export const _resetAdaptor = () => {
27
+ cached?.cleanup();
28
+ cached = null;
7
29
  };
8
30
  //# sourceMappingURL=get-adaptor.js.map