skybridge 0.0.0-dev.7df6177 → 0.0.0-dev.7ec1179

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 (318) hide show
  1. package/README.md +132 -124
  2. package/dist/cli/build-helpers.d.ts +7 -0
  3. package/dist/cli/build-helpers.js +82 -0
  4. package/dist/cli/build-helpers.js.map +1 -0
  5. package/dist/cli/build-helpers.test.js +64 -0
  6. package/dist/cli/build-helpers.test.js.map +1 -0
  7. package/dist/cli/detect-port.d.ts +2 -2
  8. package/dist/cli/detect-port.js +9 -20
  9. package/dist/cli/detect-port.js.map +1 -1
  10. package/dist/cli/header.js.map +1 -1
  11. package/dist/cli/resolve-views-dir.d.ts +1 -0
  12. package/dist/cli/resolve-views-dir.js +17 -0
  13. package/dist/cli/resolve-views-dir.js.map +1 -0
  14. package/dist/cli/run-command.js.map +1 -1
  15. package/dist/cli/telemetry.js.map +1 -1
  16. package/dist/cli/tunnel-control-server.d.ts +9 -0
  17. package/dist/cli/tunnel-control-server.js +31 -0
  18. package/dist/cli/tunnel-control-server.js.map +1 -0
  19. package/dist/cli/tunnel-control-server.test.d.ts +1 -0
  20. package/dist/cli/tunnel-control-server.test.js +39 -0
  21. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  22. package/dist/cli/tunnel-handler.d.ts +3 -0
  23. package/dist/cli/tunnel-handler.js +48 -0
  24. package/dist/cli/tunnel-handler.js.map +1 -0
  25. package/dist/cli/tunnel-handler.test.d.ts +1 -0
  26. package/dist/cli/tunnel-handler.test.js +105 -0
  27. package/dist/cli/tunnel-handler.test.js.map +1 -0
  28. package/dist/cli/tunnel.d.ts +57 -0
  29. package/dist/cli/tunnel.js +154 -0
  30. package/dist/cli/tunnel.js.map +1 -0
  31. package/dist/cli/tunnel.test.d.ts +1 -0
  32. package/dist/cli/tunnel.test.js +190 -0
  33. package/dist/cli/tunnel.test.js.map +1 -0
  34. package/dist/cli/types.js.map +1 -1
  35. package/dist/cli/use-execute-steps.js.map +1 -1
  36. package/dist/cli/use-messages.js.map +1 -1
  37. package/dist/cli/use-nodemon.js +11 -2
  38. package/dist/cli/use-nodemon.js.map +1 -1
  39. package/dist/cli/use-open-browser.d.ts +1 -0
  40. package/dist/cli/use-open-browser.js +44 -0
  41. package/dist/cli/use-open-browser.js.map +1 -0
  42. package/dist/cli/use-tunnel.d.ts +1 -1
  43. package/dist/cli/use-tunnel.js +102 -68
  44. package/dist/cli/use-tunnel.js.map +1 -1
  45. package/dist/cli/use-typescript-check.d.ts +1 -0
  46. package/dist/cli/use-typescript-check.js +42 -7
  47. package/dist/cli/use-typescript-check.js.map +1 -1
  48. package/dist/commands/build.d.ts +0 -1
  49. package/dist/commands/build.js +42 -24
  50. package/dist/commands/build.js.map +1 -1
  51. package/dist/commands/create.d.ts +9 -0
  52. package/dist/commands/create.js +30 -0
  53. package/dist/commands/create.js.map +1 -0
  54. package/dist/commands/dev.d.ts +1 -0
  55. package/dist/commands/dev.js +49 -2
  56. package/dist/commands/dev.js.map +1 -1
  57. package/dist/commands/start.js +7 -1
  58. package/dist/commands/start.js.map +1 -1
  59. package/dist/commands/telemetry/disable.js.map +1 -1
  60. package/dist/commands/telemetry/enable.js.map +1 -1
  61. package/dist/commands/telemetry/status.js.map +1 -1
  62. package/dist/server/asset-base-url-transform-plugin.d.ts +1 -0
  63. package/dist/server/asset-base-url-transform-plugin.js +17 -2
  64. package/dist/server/asset-base-url-transform-plugin.js.map +1 -1
  65. package/dist/server/asset-base-url-transform-plugin.test.js +80 -1
  66. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -1
  67. package/dist/server/auth/discovery.d.ts +32 -0
  68. package/dist/server/auth/discovery.js +44 -0
  69. package/dist/server/auth/discovery.js.map +1 -0
  70. package/dist/server/auth/discovery.test.d.ts +1 -0
  71. package/dist/server/auth/discovery.test.js +71 -0
  72. package/dist/server/auth/discovery.test.js.map +1 -0
  73. package/dist/server/auth/index.d.ts +18 -0
  74. package/dist/server/auth/index.js +2 -0
  75. package/dist/server/auth/index.js.map +1 -0
  76. package/dist/server/auth/providers/custom.d.ts +12 -0
  77. package/dist/server/auth/providers/custom.js +28 -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 +91 -0
  81. package/dist/server/auth/providers/custom.test.js.map +1 -0
  82. package/dist/server/auth/setup.d.ts +4 -0
  83. package/dist/server/auth/setup.js +51 -0
  84. package/dist/server/auth/setup.js.map +1 -0
  85. package/dist/server/auth/setup.test.d.ts +1 -0
  86. package/dist/server/auth/setup.test.js +185 -0
  87. package/dist/server/auth/setup.test.js.map +1 -0
  88. package/dist/server/auth/verify.d.ts +11 -0
  89. package/dist/server/auth/verify.js +37 -0
  90. package/dist/server/auth/verify.js.map +1 -0
  91. package/dist/server/auth/verify.test.d.ts +1 -0
  92. package/dist/server/auth/verify.test.js +87 -0
  93. package/dist/server/auth/verify.test.js.map +1 -0
  94. package/dist/server/auth.d.ts +20 -0
  95. package/dist/server/auth.js +28 -0
  96. package/dist/server/auth.js.map +1 -0
  97. package/dist/server/build-manifest.test.d.ts +1 -0
  98. package/dist/server/build-manifest.test.js +27 -0
  99. package/dist/server/build-manifest.test.js.map +1 -0
  100. package/dist/server/content-helpers.d.ts +40 -0
  101. package/dist/server/content-helpers.js +33 -0
  102. package/dist/server/content-helpers.js.map +1 -1
  103. package/dist/server/content-helpers.test.js.map +1 -1
  104. package/dist/server/express.d.ts +1 -5
  105. package/dist/server/express.js +32 -8
  106. package/dist/server/express.js.map +1 -1
  107. package/dist/server/express.test.js +308 -69
  108. package/dist/server/express.test.js.map +1 -1
  109. package/dist/server/file-ref.d.ts +28 -0
  110. package/dist/server/file-ref.js +27 -0
  111. package/dist/server/file-ref.js.map +1 -0
  112. package/dist/server/index.d.ts +6 -2
  113. package/dist/server/index.js +4 -1
  114. package/dist/server/index.js.map +1 -1
  115. package/dist/server/inferUtilityTypes.d.ts +6 -6
  116. package/dist/server/inferUtilityTypes.js.map +1 -1
  117. package/dist/server/metric.js.map +1 -1
  118. package/dist/server/middleware.d.ts +16 -3
  119. package/dist/server/middleware.js.map +1 -1
  120. package/dist/server/middleware.test-d.js.map +1 -1
  121. package/dist/server/middleware.test.js.map +1 -1
  122. package/dist/server/requestOrigin.d.ts +7 -0
  123. package/dist/server/requestOrigin.js +25 -0
  124. package/dist/server/requestOrigin.js.map +1 -0
  125. package/dist/server/server.d.ts +256 -10
  126. package/dist/server/server.js +343 -87
  127. package/dist/server/server.js.map +1 -1
  128. package/dist/server/templateHelper.d.ts +0 -2
  129. package/dist/server/templateHelper.js +3 -22
  130. package/dist/server/templateHelper.js.map +1 -1
  131. package/dist/server/templates.generated.d.ts +4 -0
  132. package/dist/server/templates.generated.js +47 -0
  133. package/dist/server/templates.generated.js.map +1 -0
  134. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  135. package/dist/server/tunnel-proxy-router.js +110 -0
  136. package/dist/server/tunnel-proxy-router.js.map +1 -0
  137. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  138. package/dist/server/tunnel-proxy-router.test.js +229 -0
  139. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  140. package/dist/server/view-resource-resolution.test.d.ts +6 -0
  141. package/dist/server/view-resource-resolution.test.js +88 -0
  142. package/dist/server/view-resource-resolution.test.js.map +1 -0
  143. package/dist/server/viewsDevServer.js.map +1 -1
  144. package/dist/test/utils.js.map +1 -1
  145. package/dist/test/view.test.js +156 -42
  146. package/dist/test/view.test.js.map +1 -1
  147. package/dist/version.js +1 -3
  148. package/dist/version.js.map +1 -1
  149. package/dist/web/bridges/apps-sdk/adaptor.d.ts +8 -3
  150. package/dist/web/bridges/apps-sdk/adaptor.js +35 -5
  151. package/dist/web/bridges/apps-sdk/adaptor.js.map +1 -1
  152. package/dist/web/bridges/apps-sdk/bridge.d.ts +1 -0
  153. package/dist/web/bridges/apps-sdk/bridge.js +1 -0
  154. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  155. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  156. package/dist/web/bridges/apps-sdk/types.d.ts +8 -1
  157. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  158. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +11 -0
  159. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +11 -0
  160. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  161. package/dist/web/bridges/get-adaptor.d.ts +7 -0
  162. package/dist/web/bridges/get-adaptor.js +7 -0
  163. package/dist/web/bridges/get-adaptor.js.map +1 -1
  164. package/dist/web/bridges/index.js.map +1 -1
  165. package/dist/web/bridges/mcp-app/adaptor.d.ts +12 -7
  166. package/dist/web/bridges/mcp-app/adaptor.js +45 -30
  167. package/dist/web/bridges/mcp-app/adaptor.js.map +1 -1
  168. package/dist/web/bridges/mcp-app/bridge.d.ts +4 -2
  169. package/dist/web/bridges/mcp-app/bridge.js +23 -1
  170. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  171. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  172. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  173. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +12 -0
  174. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +12 -0
  175. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  176. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  177. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  178. package/dist/web/bridges/mcp-app/view-tools.test.js +144 -0
  179. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  180. package/dist/web/bridges/types.d.ts +103 -8
  181. package/dist/web/bridges/types.js.map +1 -1
  182. package/dist/web/bridges/use-host-context.d.ts +5 -0
  183. package/dist/web/bridges/use-host-context.js +5 -0
  184. package/dist/web/bridges/use-host-context.js.map +1 -1
  185. package/dist/web/components/modal-provider.js +1 -1
  186. package/dist/web/components/modal-provider.js.map +1 -1
  187. package/dist/web/create-store.d.ts +26 -0
  188. package/dist/web/create-store.js +35 -9
  189. package/dist/web/create-store.js.map +1 -1
  190. package/dist/web/create-store.test.js +14 -16
  191. package/dist/web/create-store.test.js.map +1 -1
  192. package/dist/web/data-llm.d.ts +34 -1
  193. package/dist/web/data-llm.js +31 -3
  194. package/dist/web/data-llm.js.map +1 -1
  195. package/dist/web/data-llm.test.js +22 -22
  196. package/dist/web/data-llm.test.js.map +1 -1
  197. package/dist/web/generate-helpers.d.ts +2 -0
  198. package/dist/web/generate-helpers.js +2 -0
  199. package/dist/web/generate-helpers.js.map +1 -1
  200. package/dist/web/generate-helpers.test-d.js +11 -9
  201. package/dist/web/generate-helpers.test-d.js.map +1 -1
  202. package/dist/web/generate-helpers.test.js.map +1 -1
  203. package/dist/web/helpers/state.d.ts +2 -2
  204. package/dist/web/helpers/state.js +11 -11
  205. package/dist/web/helpers/state.js.map +1 -1
  206. package/dist/web/helpers/state.test.js +9 -9
  207. package/dist/web/helpers/state.test.js.map +1 -1
  208. package/dist/web/hooks/index.d.ts +5 -1
  209. package/dist/web/hooks/index.js +5 -1
  210. package/dist/web/hooks/index.js.map +1 -1
  211. package/dist/web/hooks/test/utils.d.ts +6 -2
  212. package/dist/web/hooks/test/utils.js +13 -2
  213. package/dist/web/hooks/test/utils.js.map +1 -1
  214. package/dist/web/hooks/use-call-tool.d.ts +45 -0
  215. package/dist/web/hooks/use-call-tool.js +28 -0
  216. package/dist/web/hooks/use-call-tool.js.map +1 -1
  217. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  218. package/dist/web/hooks/use-call-tool.test.js +27 -6
  219. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  220. package/dist/web/hooks/use-display-mode.d.ts +20 -0
  221. package/dist/web/hooks/use-display-mode.js +20 -0
  222. package/dist/web/hooks/use-display-mode.js.map +1 -1
  223. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -1
  224. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  225. package/dist/web/hooks/use-download.d.ts +5 -0
  226. package/dist/web/hooks/use-download.js +8 -0
  227. package/dist/web/hooks/use-download.js.map +1 -0
  228. package/dist/web/hooks/use-download.test.d.ts +1 -0
  229. package/dist/web/hooks/use-download.test.js +95 -0
  230. package/dist/web/hooks/use-download.test.js.map +1 -0
  231. package/dist/web/hooks/use-files.d.ts +32 -0
  232. package/dist/web/hooks/use-files.js +32 -0
  233. package/dist/web/hooks/use-files.js.map +1 -1
  234. package/dist/web/hooks/use-files.test.js.map +1 -1
  235. package/dist/web/hooks/use-layout.d.ts +2 -0
  236. package/dist/web/hooks/use-layout.js +2 -0
  237. package/dist/web/hooks/use-layout.js.map +1 -1
  238. package/dist/web/hooks/use-layout.test.js.map +1 -1
  239. package/dist/web/hooks/use-open-external.d.ts +17 -0
  240. package/dist/web/hooks/use-open-external.js +16 -0
  241. package/dist/web/hooks/use-open-external.js.map +1 -1
  242. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  243. package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
  244. package/dist/web/hooks/use-register-view-tool.js +50 -0
  245. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  246. package/dist/web/hooks/use-request-close.d.ts +16 -0
  247. package/dist/web/hooks/use-request-close.js +21 -0
  248. package/dist/web/hooks/use-request-close.js.map +1 -0
  249. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  250. package/dist/web/hooks/use-request-close.test.js +52 -0
  251. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  252. package/dist/web/hooks/use-request-modal.d.ts +16 -1
  253. package/dist/web/hooks/use-request-modal.js +19 -4
  254. package/dist/web/hooks/use-request-modal.js.map +1 -1
  255. package/dist/web/hooks/use-request-modal.test.js +1 -1
  256. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  257. package/dist/web/hooks/use-request-size.d.ts +20 -0
  258. package/dist/web/hooks/use-request-size.js +24 -0
  259. package/dist/web/hooks/use-request-size.js.map +1 -0
  260. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  261. package/dist/web/hooks/use-request-size.test.js +65 -0
  262. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  263. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -1
  264. package/dist/web/hooks/use-send-follow-up-message.js +19 -2
  265. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  266. package/dist/web/hooks/use-set-open-in-app-url.d.ts +17 -0
  267. package/dist/web/hooks/use-set-open-in-app-url.js +17 -0
  268. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -1
  269. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  270. package/dist/web/hooks/use-tool-info.d.ts +53 -2
  271. package/dist/web/hooks/use-tool-info.js +30 -7
  272. package/dist/web/hooks/use-tool-info.js.map +1 -1
  273. package/dist/web/hooks/use-tool-info.test-d.js +11 -29
  274. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  275. package/dist/web/hooks/use-tool-info.test.js +5 -5
  276. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  277. package/dist/web/hooks/use-user.d.ts +2 -0
  278. package/dist/web/hooks/use-user.js +2 -0
  279. package/dist/web/hooks/use-user.js.map +1 -1
  280. package/dist/web/hooks/use-user.test.js.map +1 -1
  281. package/dist/web/hooks/use-view-state.d.ts +25 -0
  282. package/dist/web/hooks/use-view-state.js +32 -0
  283. package/dist/web/hooks/use-view-state.js.map +1 -0
  284. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  285. package/dist/web/hooks/{use-widget-state.test.js → use-view-state.test.js} +17 -17
  286. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  287. package/dist/web/index.d.ts +1 -3
  288. package/dist/web/index.js +1 -2
  289. package/dist/web/index.js.map +1 -1
  290. package/dist/web/mount-view.d.ts +20 -0
  291. package/dist/web/{mount-widget.js → mount-view.js} +21 -2
  292. package/dist/web/mount-view.js.map +1 -0
  293. package/dist/web/plugin/data-llm.test.js.map +1 -1
  294. package/dist/web/plugin/plugin.d.ts +28 -0
  295. package/dist/web/plugin/plugin.js +70 -22
  296. package/dist/web/plugin/plugin.js.map +1 -1
  297. package/dist/web/plugin/scan-views.d.ts +8 -0
  298. package/dist/web/plugin/scan-views.js +26 -8
  299. package/dist/web/plugin/scan-views.js.map +1 -1
  300. package/dist/web/plugin/scan-views.test.js +36 -34
  301. package/dist/web/plugin/scan-views.test.js.map +1 -1
  302. package/dist/web/plugin/transform-data-llm.js.map +1 -1
  303. package/dist/web/plugin/transform-data-llm.test.js.map +1 -1
  304. package/dist/web/plugin/validate-view.js.map +1 -1
  305. package/dist/web/plugin/validate-view.test.js.map +1 -1
  306. package/dist/web/proxy.js.map +1 -1
  307. package/dist/web/types.d.ts +4 -0
  308. package/dist/web/types.js.map +1 -1
  309. package/package.json +21 -8
  310. package/dist/server/templates/development.hbs +0 -12
  311. package/dist/server/templates/production.hbs +0 -6
  312. package/dist/web/hooks/use-widget-state.d.ts +0 -4
  313. package/dist/web/hooks/use-widget-state.js +0 -32
  314. package/dist/web/hooks/use-widget-state.js.map +0 -1
  315. package/dist/web/hooks/use-widget-state.test.js.map +0 -1
  316. package/dist/web/mount-widget.d.ts +0 -1
  317. package/dist/web/mount-widget.js.map +0 -1
  318. /package/dist/{web/hooks/use-widget-state.test.d.ts → cli/build-helpers.test.d.ts} +0 -0
@@ -1,7 +1,33 @@
1
1
  import { dequal } from "dequal/lite";
2
2
  import { create } from "zustand";
3
3
  import { getAdaptor } from "./bridges/index.js";
4
- import { filterWidgetContext, getInitialState, injectWidgetContext, serializeState, } from "./helpers/state.js";
4
+ import { filterViewContext, getInitialState, injectViewContext, serializeState, } from "./helpers/state.js";
5
+ /**
6
+ * Create a Zustand store that is bidirectionally synced with the host's
7
+ * `viewState`. Local store updates persist to the host, and external host
8
+ * updates rehydrate the store — making the store the single source of truth
9
+ * for state that should survive view remounts.
10
+ *
11
+ * Use this when you outgrow {@link useViewState} and want first-class Zustand
12
+ * ergonomics (selectors, actions, middleware). Otherwise prefer `useViewState`.
13
+ *
14
+ * Skybridge-internal context fields (see {@link DataLLM}) are filtered out
15
+ * automatically before reaching your store.
16
+ *
17
+ * @typeParam State - Shape of the store's state. Must be a plain object.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * export const useStore = createStore<{ count: number; inc: () => void }>(
22
+ * (set) => ({
23
+ * count: 0,
24
+ * inc: () => set((s) => ({ count: s.count + 1 })),
25
+ * }),
26
+ * );
27
+ * ```
28
+ *
29
+ * @see https://docs.skybridge.tech/api-reference/create-store
30
+ */
5
31
  export function createStore(storeCreator, defaultState) {
6
32
  const initialState = getInitialState(defaultState);
7
33
  const store = create()((...args) => {
@@ -11,22 +37,22 @@ export function createStore(storeCreator, defaultState) {
11
37
  }
12
38
  return baseStore;
13
39
  });
14
- // Bidirectional sync between the Zustand store and the adaptor's widgetState.
15
- // Store changes persist to the host; external widgetState changes rehydrate the store.
40
+ // Bidirectional sync between the Zustand store and the adaptor's viewState.
41
+ // Store changes persist to the host; external viewState changes rehydrate the store.
16
42
  store.subscribe((state) => {
17
43
  const serializedState = serializeState(state);
18
44
  if (serializedState !== null && serializedState !== undefined) {
19
- const stateToPersist = injectWidgetContext(serializedState);
45
+ const stateToPersist = injectViewContext(serializedState);
20
46
  if (stateToPersist !== null) {
21
- getAdaptor().setWidgetState(stateToPersist);
47
+ getAdaptor().setViewState(stateToPersist);
22
48
  }
23
49
  }
24
50
  });
25
- const widgetStateStore = getAdaptor().getHostContextStore("widgetState");
26
- widgetStateStore.subscribe(() => {
27
- const externalState = widgetStateStore.getSnapshot();
51
+ const viewStateStore = getAdaptor().getHostContextStore("viewState");
52
+ viewStateStore.subscribe(() => {
53
+ const externalState = viewStateStore.getSnapshot();
28
54
  if (externalState !== null) {
29
- const filtered = filterWidgetContext(externalState);
55
+ const filtered = filterViewContext(externalState);
30
56
  const current = serializeState(store.getState());
31
57
  if (!dequal(filtered, current)) {
32
58
  store.setState(filtered);
@@ -1 +1 @@
1
- {"version":3,"file":"create-store.js","sourceRoot":"","sources":["../../src/web/create-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,cAAc,GACf,MAAM,oBAAoB,CAAC;AAG5B,MAAM,UAAU,WAAW,CACzB,YAAgD,EAChD,YAAoC;IAEpC,MAAM,YAAY,GAAG,eAAe,CAAC,YAAY,CAAC,CAAC;IAEnD,MAAM,KAAK,GAAG,MAAM,EAAS,CAC3B,CAAC,GAAG,IAAoD,EAAE,EAAE;QAC1D,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC;QAExC,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;YAC1B,OAAO,EAAE,GAAG,SAAS,EAAE,GAAG,YAAY,EAAE,CAAC;QAC3C,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC,CACF,CAAC;IAEF,8EAA8E;IAC9E,uFAAuF;IACvF,KAAK,CAAC,SAAS,CAAC,CAAC,KAAY,EAAE,EAAE;QAC/B,MAAM,eAAe,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,eAAe,KAAK,IAAI,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;YAC9D,MAAM,cAAc,GAAG,mBAAmB,CAAC,eAAwB,CAAC,CAAC;YACrE,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;gBAC5B,UAAU,EAAE,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,gBAAgB,GAAG,UAAU,EAAE,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;IACzE,gBAAgB,CAAC,SAAS,CAAC,GAAG,EAAE;QAC9B,MAAM,aAAa,GAAG,gBAAgB,CAAC,WAAW,EAAE,CAAC;QACrD,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,mBAAmB,CAAC,aAAa,CAAU,CAAC;YAC7D,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAU,CAAC;YAC1D,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;gBAC/B,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"create-store.js","sourceRoot":"","sources":["../../src/web/create-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,cAAc,GACf,MAAM,oBAAoB,CAAC;AAG5B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,WAAW,CACzB,YAAgD,EAChD,YAAoC;IAEpC,MAAM,YAAY,GAAG,eAAe,CAAC,YAAY,CAAC,CAAC;IAEnD,MAAM,KAAK,GAAG,MAAM,EAAS,CAC3B,CAAC,GAAG,IAAoD,EAAE,EAAE;QAC1D,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC;QAExC,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;YAC1B,OAAO,EAAE,GAAG,SAAS,EAAE,GAAG,YAAY,EAAE,CAAC;QAC3C,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC,CACF,CAAC;IAEF,4EAA4E;IAC5E,qFAAqF;IACrF,KAAK,CAAC,SAAS,CAAC,CAAC,KAAY,EAAE,EAAE;QAC/B,MAAM,eAAe,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,eAAe,KAAK,IAAI,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;YAC9D,MAAM,cAAc,GAAG,iBAAiB,CAAC,eAAwB,CAAC,CAAC;YACnE,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;gBAC5B,UAAU,EAAE,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,UAAU,EAAE,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;IACrE,cAAc,CAAC,SAAS,CAAC,GAAG,EAAE;QAC5B,MAAM,aAAa,GAAG,cAAc,CAAC,WAAW,EAAE,CAAC;QACnD,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,aAAa,CAAU,CAAC;YAC3D,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAU,CAAC;YAC1D,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;gBAC/B,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import { dequal } from \"dequal/lite\";\nimport { create, type StateCreator } from \"zustand\";\nimport { getAdaptor } from \"./bridges/index.js\";\nimport {\n filterViewContext,\n getInitialState,\n injectViewContext,\n serializeState,\n} from \"./helpers/state.js\";\nimport type { UnknownObject } from \"./types.js\";\n\n/**\n * Create a Zustand store that is bidirectionally synced with the host's\n * `viewState`. Local store updates persist to the host, and external host\n * updates rehydrate the store — making the store the single source of truth\n * for state that should survive view remounts.\n *\n * Use this when you outgrow {@link useViewState} and want first-class Zustand\n * ergonomics (selectors, actions, middleware). Otherwise prefer `useViewState`.\n *\n * Skybridge-internal context fields (see {@link DataLLM}) are filtered out\n * automatically before reaching your store.\n *\n * @typeParam State - Shape of the store's state. Must be a plain object.\n *\n * @example\n * ```ts\n * export const useStore = createStore<{ count: number; inc: () => void }>(\n * (set) => ({\n * count: 0,\n * inc: () => set((s) => ({ count: s.count + 1 })),\n * }),\n * );\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/create-store\n */\nexport function createStore<State extends UnknownObject>(\n storeCreator: StateCreator<State, [], [], State>,\n defaultState?: State | (() => State),\n) {\n const initialState = getInitialState(defaultState);\n\n const store = create<State>()(\n (...args: Parameters<StateCreator<State, [], [], State>>) => {\n const baseStore = storeCreator(...args);\n\n if (initialState !== null) {\n return { ...baseStore, ...initialState };\n }\n\n return baseStore;\n },\n );\n\n // Bidirectional sync between the Zustand store and the adaptor's viewState.\n // Store changes persist to the host; external viewState changes rehydrate the store.\n store.subscribe((state: State) => {\n const serializedState = serializeState(state);\n if (serializedState !== null && serializedState !== undefined) {\n const stateToPersist = injectViewContext(serializedState as State);\n if (stateToPersist !== null) {\n getAdaptor().setViewState(stateToPersist);\n }\n }\n });\n\n const viewStateStore = getAdaptor().getHostContextStore(\"viewState\");\n viewStateStore.subscribe(() => {\n const externalState = viewStateStore.getSnapshot();\n if (externalState !== null) {\n const filtered = filterViewContext(externalState) as State;\n const current = serializeState(store.getState()) as State;\n if (!dequal(filtered, current)) {\n store.setState(filtered);\n }\n }\n });\n\n return store;\n}\n"]}
@@ -3,7 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, vi, } from "vitest";
3
3
  import { McpAppAdaptor } from "./bridges/mcp-app/adaptor.js";
4
4
  import { McpAppBridge } from "./bridges/mcp-app/bridge.js";
5
5
  import { createStore } from "./create-store.js";
6
- import { WIDGET_CONTEXT_KEY } from "./data-llm.js";
6
+ import { VIEW_CONTEXT_KEY } from "./data-llm.js";
7
7
  import { getMcpAppHostPostMessageMock, MockResizeObserver, } from "./hooks/test/utils.js";
8
8
  describe("createStore", () => {
9
9
  afterEach(() => {
@@ -62,18 +62,18 @@ describe("createStore", () => {
62
62
  privateContent: {},
63
63
  });
64
64
  });
65
- it("should filter widget context from initial state", () => {
65
+ it("should filter view context from initial state", () => {
66
66
  const storeCreator = () => ({
67
67
  count: 0,
68
68
  });
69
69
  const windowState = {
70
70
  count: 5,
71
- [WIDGET_CONTEXT_KEY]: "context-value",
71
+ [VIEW_CONTEXT_KEY]: "context-value",
72
72
  };
73
73
  OpenaiMock.widgetState = { modelContent: windowState };
74
74
  const store = createStore(storeCreator);
75
75
  expect(store.getState()).toEqual({ count: 5 });
76
- expect(store.getState()[WIDGET_CONTEXT_KEY]).toBeUndefined();
76
+ expect(store.getState()[VIEW_CONTEXT_KEY]).toBeUndefined();
77
77
  });
78
78
  });
79
79
  describe("mcp-app mode", () => {
@@ -86,12 +86,10 @@ describe("createStore", () => {
86
86
  McpAppBridge.resetInstance();
87
87
  McpAppAdaptor.resetInstance();
88
88
  });
89
- it("should initialize with null widgetState", () => {
89
+ it("should initialize with null viewState", () => {
90
90
  const adaptor = McpAppAdaptor.getInstance();
91
- const widgetState = adaptor
92
- .getHostContextStore("widgetState")
93
- .getSnapshot();
94
- expect(widgetState).toBeNull();
91
+ const viewState = adaptor.getHostContextStore("viewState").getSnapshot();
92
+ expect(viewState).toBeNull();
95
93
  });
96
94
  it("should create a store with default state when no persisted state exists", () => {
97
95
  const storeCreator = () => ({
@@ -100,9 +98,9 @@ describe("createStore", () => {
100
98
  const store = createStore(storeCreator);
101
99
  expect(store.getState()).toEqual({ count: 0 });
102
100
  });
103
- it("should update in-memory state via setWidgetState", async () => {
101
+ it("should update in-memory state via setViewState", async () => {
104
102
  const adaptor = McpAppAdaptor.getInstance();
105
- vi.spyOn(adaptor, "setWidgetState").mockResolvedValue(undefined);
103
+ vi.spyOn(adaptor, "setViewState").mockResolvedValue(undefined);
106
104
  const storeCreator = (set) => ({
107
105
  count: 0,
108
106
  increment: () => set((state) => ({ count: state.count + 1 })),
@@ -110,19 +108,19 @@ describe("createStore", () => {
110
108
  const store = createStore(storeCreator);
111
109
  store.getState().increment();
112
110
  await vi.waitFor(() => {
113
- expect(adaptor.setWidgetState).toHaveBeenCalledWith({ count: 1 });
111
+ expect(adaptor.setViewState).toHaveBeenCalledWith({ count: 1 });
114
112
  });
115
113
  });
116
- it("should notify listeners when widget state changes", async () => {
114
+ it("should notify listeners when view state changes", async () => {
117
115
  const postMessageMock = getMcpAppHostPostMessageMock();
118
116
  vi.stubGlobal("parent", { postMessage: postMessageMock });
119
117
  const adaptor = McpAppAdaptor.getInstance();
120
118
  const listener = vi.fn();
121
- adaptor.getHostContextStore("widgetState").subscribe(listener);
122
- await adaptor.setWidgetState({ count: 42 });
119
+ adaptor.getHostContextStore("viewState").subscribe(listener);
120
+ await adaptor.setViewState({ count: 42 });
123
121
  expect(postMessageMock).toHaveBeenCalledWith(expect.objectContaining({ method: "ui/update-model-context" }), "*");
124
122
  expect(listener).toHaveBeenCalled();
125
- expect(adaptor.getHostContextStore("widgetState").getSnapshot()).toEqual({
123
+ expect(adaptor.getHostContextStore("viewState").getSnapshot()).toEqual({
126
124
  count: 42,
127
125
  });
128
126
  });
@@ -1 +1 @@
1
- {"version":3,"file":"create-store.test.js","sourceRoot":"","sources":["../../src/web/create-store.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"create-store.test.js","sourceRoot":"","sources":["../../src/web/create-store.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { cleanup } from \"@testing-library/react\";\nimport {\n afterEach,\n beforeEach,\n describe,\n expect,\n it,\n type Mock,\n vi,\n} from \"vitest\";\nimport type { StateCreator } from \"zustand\";\nimport { McpAppAdaptor } from \"./bridges/mcp-app/adaptor.js\";\nimport { McpAppBridge } from \"./bridges/mcp-app/bridge.js\";\nimport { createStore } from \"./create-store.js\";\nimport { VIEW_CONTEXT_KEY } from \"./data-llm.js\";\nimport {\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"./hooks/test/utils.js\";\n\ndescribe(\"createStore\", () => {\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n });\n\n describe(\"apps-sdk mode\", () => {\n let OpenaiMock: {\n widgetState: unknown;\n setWidgetState: Mock;\n };\n\n beforeEach(() => {\n OpenaiMock = {\n widgetState: null,\n setWidgetState: vi.fn().mockResolvedValue(undefined),\n };\n vi.stubGlobal(\"openai\", OpenaiMock);\n vi.stubGlobal(\"skybridge\", { hostType: \"apps-sdk\" });\n });\n\n it(\"should create a store without default state\", () => {\n type TestState = { count: number };\n const storeCreator: StateCreator<TestState, [], [], TestState> = () => ({\n count: 0,\n });\n\n const store = createStore(storeCreator);\n\n expect(store.getState()).toEqual({ count: 0 });\n });\n\n it(\"should create a store with default state\", () => {\n type TestState = { count: number; name: string };\n const storeCreator: StateCreator<TestState, [], [], TestState> = () => ({\n count: 0,\n name: \"initial\",\n });\n const defaultState = { count: 5, name: \"default\" };\n\n const store = createStore(storeCreator, defaultState);\n\n expect(store.getState()).toEqual({ count: 5, name: \"default\" });\n });\n\n it(\"should initialize from window.openai.widgetState when available\", () => {\n type TestState = { count: number; name: string };\n const storeCreator: StateCreator<TestState, [], [], TestState> = () => ({\n count: 0,\n name: \"initial\",\n });\n const windowState = { count: 20, name: \"window\" };\n OpenaiMock.widgetState = { modelContent: windowState };\n\n const store = createStore(storeCreator);\n\n expect(store.getState()).toEqual({ count: 20, name: \"window\" });\n });\n\n it(\"should persist state changes to window.openai.setWidgetState\", async () => {\n type TestState = { count: number; increment: () => void };\n const storeCreator: StateCreator<TestState, [], [], TestState> = (\n set,\n ) => ({\n count: 0,\n increment: () => set((state) => ({ count: state.count + 1 })),\n });\n\n const store = createStore(storeCreator);\n store.getState().increment();\n\n await vi.waitFor(() => {\n expect(OpenaiMock.setWidgetState).toHaveBeenCalled();\n });\n\n const callArgs = OpenaiMock.setWidgetState.mock.calls[0]?.[0];\n expect(callArgs).toEqual({\n modelContent: { count: 1 },\n privateContent: {},\n });\n });\n\n it(\"should filter view context from initial state\", () => {\n type TestState = { count: number };\n const storeCreator: StateCreator<TestState, [], [], TestState> = () => ({\n count: 0,\n });\n const windowState = {\n count: 5,\n [VIEW_CONTEXT_KEY]: \"context-value\",\n };\n OpenaiMock.widgetState = { modelContent: windowState };\n\n const store = createStore(storeCreator);\n\n expect(store.getState()).toEqual({ count: 5 });\n expect(\n (store.getState() as Record<string, unknown>)[VIEW_CONTEXT_KEY],\n ).toBeUndefined();\n });\n });\n\n describe(\"mcp-app mode\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"skybridge\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n });\n\n afterEach(async () => {\n cleanup();\n McpAppBridge.resetInstance();\n McpAppAdaptor.resetInstance();\n });\n\n it(\"should initialize with null viewState\", () => {\n const adaptor = McpAppAdaptor.getInstance();\n const viewState = adaptor.getHostContextStore(\"viewState\").getSnapshot();\n\n expect(viewState).toBeNull();\n });\n\n it(\"should create a store with default state when no persisted state exists\", () => {\n type TestState = { count: number };\n const storeCreator: StateCreator<TestState, [], [], TestState> = () => ({\n count: 0,\n });\n\n const store = createStore(storeCreator);\n\n expect(store.getState()).toEqual({ count: 0 });\n });\n\n it(\"should update in-memory state via setViewState\", async () => {\n const adaptor = McpAppAdaptor.getInstance();\n vi.spyOn(adaptor, \"setViewState\").mockResolvedValue(undefined);\n\n type TestState = { count: number; increment: () => void };\n const storeCreator: StateCreator<TestState, [], [], TestState> = (\n set,\n ) => ({\n count: 0,\n increment: () => set((state) => ({ count: state.count + 1 })),\n });\n\n const store = createStore(storeCreator);\n store.getState().increment();\n\n await vi.waitFor(() => {\n expect(adaptor.setViewState).toHaveBeenCalledWith({ count: 1 });\n });\n });\n\n it(\"should notify listeners when view state changes\", async () => {\n const postMessageMock = getMcpAppHostPostMessageMock();\n vi.stubGlobal(\"parent\", { postMessage: postMessageMock });\n\n const adaptor = McpAppAdaptor.getInstance();\n const listener = vi.fn();\n\n adaptor.getHostContextStore(\"viewState\").subscribe(listener);\n await adaptor.setViewState({ count: 42 });\n\n expect(postMessageMock).toHaveBeenCalledWith(\n expect.objectContaining({ method: \"ui/update-model-context\" }),\n \"*\",\n );\n expect(listener).toHaveBeenCalled();\n expect(adaptor.getHostContextStore(\"viewState\").getSnapshot()).toEqual({\n count: 42,\n });\n });\n });\n});\n"]}
@@ -1,14 +1,47 @@
1
1
  import { type ReactNode } from "react";
2
+ /** Text content surfaced to the model by a {@link DataLLM} component. */
2
3
  export type DataLLMContent = string;
4
+ /**
5
+ * A node in the {@link DataLLM} tree. Nested `<DataLLM>` elements form a
6
+ * hierarchy that is serialized as an indented bullet list for the model.
7
+ */
3
8
  export interface DataLLMNode {
4
9
  id: string;
5
10
  parentId: string | null;
6
11
  content: string | null;
7
12
  }
8
- export declare const WIDGET_CONTEXT_KEY: "__widget_context";
13
+ /**
14
+ * Key under which the serialized {@link DataLLM} tree is persisted on the
15
+ * host's `viewState`. The host exposes the value to the model on subsequent
16
+ * turns.
17
+ */
18
+ export declare const VIEW_CONTEXT_KEY: "__view_context";
9
19
  interface DataLLMProps {
10
20
  content: DataLLMContent | null | undefined;
11
21
  children?: ReactNode;
12
22
  }
23
+ /**
24
+ * Surface in-view content to the LLM so it can reason about what the user is
25
+ * seeing without an extra tool call.
26
+ *
27
+ * Each `<DataLLM>` registers `content` as a node in a tree (parented by any
28
+ * enclosing `<DataLLM>`). The flattened tree is serialized as an indented
29
+ * bullet list and persisted on the host's `viewState` under
30
+ * {@link VIEW_CONTEXT_KEY}; the host then surfaces it to the model as part of
31
+ * the next turn's context.
32
+ *
33
+ * Pass `null`/`undefined` for `content` to register only as a structural
34
+ * parent (useful for grouping).
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * <DataLLM content="Active filters">
39
+ * <DataLLM content={`Sort: ${sort}`} />
40
+ * <DataLLM content={`Page: ${page}`} />
41
+ * </DataLLM>
42
+ * ```
43
+ *
44
+ * @see https://docs.skybridge.tech/api-reference/data-llm
45
+ */
13
46
  export declare function DataLLM({ content, children }: DataLLMProps): import("react/jsx-runtime").JSX.Element;
14
47
  export {};
@@ -1,7 +1,12 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createContext, useContext, useEffect, useId, } from "react";
3
3
  import { getAdaptor } from "./bridges/index.js";
4
- export const WIDGET_CONTEXT_KEY = "__widget_context";
4
+ /**
5
+ * Key under which the serialized {@link DataLLM} tree is persisted on the
6
+ * host's `viewState`. The host exposes the value to the model on subsequent
7
+ * turns.
8
+ */
9
+ export const VIEW_CONTEXT_KEY = "__view_context";
5
10
  const nodes = new Map();
6
11
  function setNode(node) {
7
12
  nodes.set(node.id, node);
@@ -14,12 +19,35 @@ function removeNode(id) {
14
19
  function onChange() {
15
20
  const description = getLLMDescriptionString();
16
21
  const adaptor = getAdaptor();
17
- adaptor.setWidgetState((prevState) => ({
22
+ adaptor.setViewState((prevState) => ({
18
23
  ...prevState,
19
- [WIDGET_CONTEXT_KEY]: description,
24
+ [VIEW_CONTEXT_KEY]: description,
20
25
  }));
21
26
  }
22
27
  const ParentIdContext = createContext(null);
28
+ /**
29
+ * Surface in-view content to the LLM so it can reason about what the user is
30
+ * seeing without an extra tool call.
31
+ *
32
+ * Each `<DataLLM>` registers `content` as a node in a tree (parented by any
33
+ * enclosing `<DataLLM>`). The flattened tree is serialized as an indented
34
+ * bullet list and persisted on the host's `viewState` under
35
+ * {@link VIEW_CONTEXT_KEY}; the host then surfaces it to the model as part of
36
+ * the next turn's context.
37
+ *
38
+ * Pass `null`/`undefined` for `content` to register only as a structural
39
+ * parent (useful for grouping).
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * <DataLLM content="Active filters">
44
+ * <DataLLM content={`Sort: ${sort}`} />
45
+ * <DataLLM content={`Page: ${page}`} />
46
+ * </DataLLM>
47
+ * ```
48
+ *
49
+ * @see https://docs.skybridge.tech/api-reference/data-llm
50
+ */
23
51
  export function DataLLM({ content, children }) {
24
52
  const parentId = useContext(ParentIdContext);
25
53
  const id = useId();
@@ -1 +1 @@
1
- {"version":3,"file":"data-llm.js","sourceRoot":"","sources":["../../src/web/data-llm.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data-llm.js","sourceRoot":"","sources":["../../src/web/data-llm.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,aAAa,EAEb,UAAU,EACV,SAAS,EACT,KAAK,GACN,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAehD;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAyB,CAAC;AAE1D,MAAM,KAAK,GAAG,IAAI,GAAG,EAAuB,CAAC;AAE7C,SAAS,OAAO,CAAC,IAAiB;IAChC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACzB,QAAQ,EAAE,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,EAAU;IAC5B,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACjB,QAAQ,EAAE,CAAC;AACb,CAAC;AAED,SAAS,QAAQ;IACf,MAAM,WAAW,GAAG,uBAAuB,EAAE,CAAC;IAC9C,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,OAAO,CAAC,YAAY,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACnC,GAAG,SAAS;QACZ,CAAC,gBAAgB,CAAC,EAAE,WAAW;KAChC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,eAAe,GAAG,aAAa,CAAgB,IAAI,CAAC,CAAC;AAO3D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,OAAO,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAgB;IACzD,MAAM,QAAQ,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC;IAC7C,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IAEnB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC;gBACN,EAAE;gBACF,QAAQ;gBACR,OAAO;aACR,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;QAED,OAAO,GAAG,EAAE;YACV,UAAU,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAE5B,OAAO,CACL,KAAC,eAAe,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,YAAG,QAAQ,GAA4B,CAC3E,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB;IAC9B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAgC,CAAC;IACzD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC;QAClC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACxB,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,SAAS,YAAY,CAAC,QAAuB,EAAE,KAAa;QAC1D,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO;QACT,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,IAAI,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;gBAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAClC,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,KAAK,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACnD,CAAC;YACD,YAAY,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAEtB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC","sourcesContent":["import {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useId,\n} from \"react\";\nimport { getAdaptor } from \"./bridges/index.js\";\n\n/** Text content surfaced to the model by a {@link DataLLM} component. */\nexport type DataLLMContent = string;\n\n/**\n * A node in the {@link DataLLM} tree. Nested `<DataLLM>` elements form a\n * hierarchy that is serialized as an indented bullet list for the model.\n */\nexport interface DataLLMNode {\n id: string;\n parentId: string | null;\n content: string | null;\n}\n\n/**\n * Key under which the serialized {@link DataLLM} tree is persisted on the\n * host's `viewState`. The host exposes the value to the model on subsequent\n * turns.\n */\nexport const VIEW_CONTEXT_KEY = \"__view_context\" as const;\n\nconst nodes = new Map<string, DataLLMNode>();\n\nfunction setNode(node: DataLLMNode) {\n nodes.set(node.id, node);\n onChange();\n}\n\nfunction removeNode(id: string) {\n nodes.delete(id);\n onChange();\n}\n\nfunction onChange() {\n const description = getLLMDescriptionString();\n const adaptor = getAdaptor();\n adaptor.setViewState((prevState) => ({\n ...prevState,\n [VIEW_CONTEXT_KEY]: description,\n }));\n}\n\nconst ParentIdContext = createContext<string | null>(null);\n\ninterface DataLLMProps {\n content: DataLLMContent | null | undefined;\n children?: ReactNode;\n}\n\n/**\n * Surface in-view content to the LLM so it can reason about what the user is\n * seeing without an extra tool call.\n *\n * Each `<DataLLM>` registers `content` as a node in a tree (parented by any\n * enclosing `<DataLLM>`). The flattened tree is serialized as an indented\n * bullet list and persisted on the host's `viewState` under\n * {@link VIEW_CONTEXT_KEY}; the host then surfaces it to the model as part of\n * the next turn's context.\n *\n * Pass `null`/`undefined` for `content` to register only as a structural\n * parent (useful for grouping).\n *\n * @example\n * ```tsx\n * <DataLLM content=\"Active filters\">\n * <DataLLM content={`Sort: ${sort}`} />\n * <DataLLM content={`Page: ${page}`} />\n * </DataLLM>\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/data-llm\n */\nexport function DataLLM({ content, children }: DataLLMProps) {\n const parentId = useContext(ParentIdContext);\n const id = useId();\n\n useEffect(() => {\n if (content) {\n setNode({\n id,\n parentId,\n content,\n });\n } else {\n removeNode(id);\n }\n\n return () => {\n removeNode(id);\n };\n }, [id, parentId, content]);\n\n return (\n <ParentIdContext.Provider value={id}>{children}</ParentIdContext.Provider>\n );\n}\n\nfunction getLLMDescriptionString(): string {\n const byParent = new Map<string | null, DataLLMNode[]>();\n for (const node of Array.from(nodes.values())) {\n const key = node.parentId ?? null;\n if (!byParent.has(key)) {\n byParent.set(key, []);\n }\n byParent.get(key)?.push(node);\n }\n\n for (const list of byParent.values()) {\n list.sort((a, b) => a.id.localeCompare(b.id));\n }\n\n const lines: string[] = [];\n\n function traverseTree(parentId: string | null, depth: number) {\n const children = byParent.get(parentId);\n if (!children) {\n return;\n }\n\n for (const child of children) {\n if (child.content?.trim()) {\n const indent = \" \".repeat(depth);\n lines.push(`${indent}- ${child.content.trim()}`);\n }\n traverseTree(child.id, depth + 1);\n }\n }\n\n traverseTree(null, 0);\n\n return lines.join(\"\\n\");\n}\n"]}
@@ -42,26 +42,26 @@ describe("DataLLM", () => {
42
42
  window.openai.widgetState = { modelContent: {}, privateContent: {} };
43
43
  }
44
44
  });
45
- it("should register a node with content and call setWidgetState", () => {
45
+ it("should register a node with content and call setViewState", () => {
46
46
  render(_jsx(DataLLM, { content: "Test content", children: _jsx("div", { children: "Child" }) }));
47
47
  expect(OpenaiMock.setWidgetState).toHaveBeenCalled();
48
48
  const callArgs = OpenaiMock.setWidgetState.mock.calls[0]?.[0]?.modelContent;
49
- expect(callArgs).toHaveProperty("__widget_context");
50
- expect(callArgs?.__widget_context).toContain("- Test content");
49
+ expect(callArgs).toHaveProperty("__view_context");
50
+ expect(callArgs?.__view_context).toContain("- Test content");
51
51
  });
52
- it("should preserve existing widgetState when updating context", () => {
52
+ it("should preserve existing viewState when updating context", () => {
53
53
  OpenaiMock.widgetState = {
54
54
  modelContent: { existingKey: "existingValue" },
55
55
  };
56
56
  render(_jsx(DataLLM, { content: "Test content", children: _jsx("div", { children: "Child" }) }));
57
57
  const callArgs = OpenaiMock.setWidgetState.mock.calls[0]?.[0]?.modelContent;
58
58
  expect(callArgs).toHaveProperty("existingKey", "existingValue");
59
- expect(callArgs).toHaveProperty("__widget_context");
59
+ expect(callArgs).toHaveProperty("__view_context");
60
60
  });
61
61
  it("should handle deeply nested DataLLM components", () => {
62
62
  render(_jsxs(DataLLM, { content: "Level 1", children: [_jsx(DataLLM, { content: "Level 2A" }), _jsx(DataLLM, { content: "Level 2B", children: _jsx(DataLLM, { content: "Level 3", children: _jsx("div", { children: "Content" }) }) })] }));
63
63
  const callArgs = OpenaiMock.setWidgetState.mock.calls[OpenaiMock.setWidgetState.mock.calls.length - 1]?.[0]?.modelContent;
64
- const context = callArgs?.__widget_context;
64
+ const context = callArgs?.__view_context;
65
65
  expect(context).toContain("- Level 1");
66
66
  expect(context).toContain(" - Level 2A");
67
67
  expect(context).toContain(" - Level 2B");
@@ -73,7 +73,7 @@ describe("DataLLM", () => {
73
73
  rerender(_jsx(DataLLM, { content: "Updated content", children: _jsx("div", { children: "Child" }) }));
74
74
  expect(OpenaiMock.setWidgetState.mock.calls.length).toBeGreaterThan(initialCalls);
75
75
  const lastCallArgs = OpenaiMock.setWidgetState.mock.calls[OpenaiMock.setWidgetState.mock.calls.length - 1]?.[0]?.modelContent;
76
- expect(lastCallArgs?.__widget_context).toContain("- Updated content");
76
+ expect(lastCallArgs?.__view_context).toContain("- Updated content");
77
77
  });
78
78
  it("should remove node and update context when component unmounts", () => {
79
79
  const { unmount } = render(_jsx(DataLLM, { content: "Content to remove", children: _jsx("div", { children: "Child" }) }));
@@ -81,7 +81,7 @@ describe("DataLLM", () => {
81
81
  unmount();
82
82
  expect(OpenaiMock.setWidgetState.mock.calls.length).toBeGreaterThan(callsBeforeUnmount);
83
83
  const lastCallArgs = OpenaiMock.setWidgetState.mock.calls[OpenaiMock.setWidgetState.mock.calls.length - 1]?.[0]?.modelContent;
84
- expect(lastCallArgs?.__widget_context).not.toContain("Content to remove");
84
+ expect(lastCallArgs?.__view_context).not.toContain("Content to remove");
85
85
  });
86
86
  });
87
87
  describe("mcp-app mode", () => {
@@ -97,41 +97,41 @@ describe("DataLLM", () => {
97
97
  McpAppBridge.resetInstance();
98
98
  McpAppAdaptor.resetInstance();
99
99
  });
100
- it("should register a node and update widget state via adaptor", async () => {
100
+ it("should register a node and update view state via adaptor", async () => {
101
101
  const adaptor = McpAppAdaptor.getInstance();
102
102
  render(_jsx(DataLLM, { content: "Test content", children: _jsx("div", { children: "Child" }) }));
103
103
  await vi.waitFor(() => {
104
- const widgetState = adaptor
105
- .getHostContextStore("widgetState")
104
+ const viewState = adaptor
105
+ .getHostContextStore("viewState")
106
106
  .getSnapshot();
107
- expect(widgetState?.__widget_context).toContain("- Test content");
107
+ expect(viewState?.__view_context).toContain("- Test content");
108
108
  });
109
109
  });
110
- it("should preserve existing widget state when updating context", async () => {
110
+ it("should preserve existing view state when updating context", async () => {
111
111
  const adaptor = McpAppAdaptor.getInstance();
112
- await adaptor.setWidgetState({ existingKey: "existingValue" });
112
+ await adaptor.setViewState({ existingKey: "existingValue" });
113
113
  render(_jsx(DataLLM, { content: "Test content", children: _jsx("div", { children: "Child" }) }));
114
114
  await vi.waitFor(() => {
115
- const widgetState = adaptor
116
- .getHostContextStore("widgetState")
115
+ const viewState = adaptor
116
+ .getHostContextStore("viewState")
117
117
  .getSnapshot();
118
- expect(widgetState?.existingKey).toBe("existingValue");
119
- expect(widgetState?.__widget_context).toContain("- Test content");
118
+ expect(viewState?.existingKey).toBe("existingValue");
119
+ expect(viewState?.__view_context).toContain("- Test content");
120
120
  });
121
121
  });
122
122
  it("should handle multiple DataLLM components sharing state through adaptor", async () => {
123
123
  const adaptor = McpAppAdaptor.getInstance();
124
124
  render(_jsxs(_Fragment, { children: [_jsx(DataLLM, { content: "First component", children: _jsx("div", { children: "First" }) }), _jsx(DataLLM, { content: "Second component", children: _jsx("div", { children: "Second" }) })] }));
125
125
  await vi.waitFor(() => {
126
- const widgetState = adaptor
127
- .getHostContextStore("widgetState")
126
+ const viewState = adaptor
127
+ .getHostContextStore("viewState")
128
128
  .getSnapshot();
129
- const context = widgetState?.__widget_context;
129
+ const context = viewState?.__view_context;
130
130
  expect(context).toContain("- First component");
131
131
  expect(context).toContain("- Second component");
132
132
  });
133
133
  });
134
- it("should call ui/update-model-context when widget state changes", async () => {
134
+ it("should call ui/update-model-context when view state changes", async () => {
135
135
  render(_jsx(DataLLM, { content: "Test content", children: _jsx("div", { children: "Child" }) }));
136
136
  await vi.waitFor(() => {
137
137
  expect(postMessageMock).toHaveBeenCalledWith(expect.objectContaining({ method: "ui/update-model-context" }), "*");
@@ -1 +1 @@
1
- {"version":3,"file":"data-llm.test.js","sourceRoot":"","sources":["../../src/web/data-llm.test.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data-llm.test.js","sourceRoot":"","sources":["../../src/web/data-llm.test.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EACL,SAAS,EACT,UAAU,EACV,QAAQ,EACR,MAAM,EACN,EAAE,EAEF,EAAE,GACH,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EACL,4BAA4B,EAC5B,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAE/B,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;IACvB,SAAS,CAAC,GAAG,EAAE;QACb,sDAAsD;QACtD,OAAO,EAAE,CAAC;QACV,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,IAAI,UAA0D,CAAC;QAE/D,UAAU,CAAC,GAAG,EAAE;YACd,UAAU,GAAG;gBACX,WAAW,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE;gBACjC,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE;aACxB,CAAC;YACF,kDAAkD;YAClD,MAAM,CAAC,cAAc,CAAC,UAAU,EAAE,QAAQ,EAAE;gBAC1C,KAAK,EAAE,UAAU;gBACjB,QAAQ,EAAE,IAAI;gBACd,YAAY,EAAE,IAAI;aACnB,CAAC,CAAC;YACH,kDAAkD;YAClD,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;gBAClC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE;oBACtC,KAAK,EAAE,UAAU;oBACjB,QAAQ,EAAE,IAAI;oBACd,YAAY,EAAE,IAAI;iBACnB,CAAC,CAAC;YACL,CAAC;YACD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YACpC,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,SAAS,CAAC,GAAG,EAAE;YACb,0DAA0D;YAC1D,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBACnD,MAAM,CAAC,MAAM,CAAC,cAAc,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;gBACvC,MAAM,CAAC,MAAM,CAAC,WAAW,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC;YACvE,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;YACnE,MAAM,CACJ,KAAC,OAAO,IAAC,OAAO,EAAC,cAAc,YAC7B,kCAAgB,GACR,CACX,CAAC;YAEF,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,gBAAgB,EAAE,CAAC;YACrD,MAAM,QAAQ,GACZ,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC;YAC7D,MAAM,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;YAClD,MAAM,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;YAClE,UAAU,CAAC,WAAW,GAAG;gBACvB,YAAY,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE;aAC/C,CAAC;YAEF,MAAM,CACJ,KAAC,OAAO,IAAC,OAAO,EAAC,cAAc,YAC7B,kCAAgB,GACR,CACX,CAAC;YAEF,MAAM,QAAQ,GACZ,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC;YAC7D,MAAM,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;YAChE,MAAM,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;YACxD,MAAM,CACJ,MAAC,OAAO,IAAC,OAAO,EAAC,SAAS,aACxB,KAAC,OAAO,IAAC,OAAO,EAAC,UAAU,GAAG,EAC9B,KAAC,OAAO,IAAC,OAAO,EAAC,UAAU,YACzB,KAAC,OAAO,IAAC,OAAO,EAAC,SAAS,YACxB,oCAAkB,GACV,GACF,IACF,CACX,CAAC;YAEF,MAAM,QAAQ,GACZ,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAClC,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAChD,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC;YACvB,MAAM,OAAO,GAAG,QAAQ,EAAE,cAAwB,CAAC;YACnD,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;YACvC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;YAC1C,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;YAC1C,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CACzB,KAAC,OAAO,IAAC,OAAO,EAAC,iBAAiB,YAChC,kCAAgB,GACR,CACX,CAAC;YAEF,MAAM,YAAY,GAAG,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YAEjE,QAAQ,CACN,KAAC,OAAO,IAAC,OAAO,EAAC,iBAAiB,YAChC,kCAAgB,GACR,CACX,CAAC;YAEF,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,eAAe,CACjE,YAAY,CACb,CAAC;YACF,MAAM,YAAY,GAChB,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAClC,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAChD,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC;YACvB,MAAM,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;YACvE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CACxB,KAAC,OAAO,IAAC,OAAO,EAAC,mBAAmB,YAClC,kCAAgB,GACR,CACX,CAAC;YAEF,MAAM,kBAAkB,GAAG,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YAEvE,OAAO,EAAE,CAAC;YAEV,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,eAAe,CACjE,kBAAkB,CACnB,CAAC;YACF,MAAM,YAAY,GAChB,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAClC,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAChD,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC;YACvB,MAAM,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,IAAI,eAAgE,CAAC;QAErE,UAAU,CAAC,GAAG,EAAE;YACd,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;YACpD,EAAE,CAAC,UAAU,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;YACpD,eAAe,GAAG,4BAA4B,EAAE,CAAC;YACjD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,SAAS,CAAC,GAAG,EAAE;YACb,OAAO,EAAE,CAAC;YACV,YAAY,CAAC,aAAa,EAAE,CAAC;YAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;QAChC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;YACxE,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;YAE5C,MAAM,CACJ,KAAC,OAAO,IAAC,OAAO,EAAC,cAAc,YAC7B,kCAAgB,GACR,CACX,CAAC;YAEF,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;gBACpB,MAAM,SAAS,GAAG,OAAO;qBACtB,mBAAmB,CAAC,WAAW,CAAC;qBAChC,WAAW,EAAE,CAAC;gBACjB,MAAM,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;YAChE,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;YACzE,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;YAC5C,MAAM,OAAO,CAAC,YAAY,CAAC,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC,CAAC;YAE7D,MAAM,CACJ,KAAC,OAAO,IAAC,OAAO,EAAC,cAAc,YAC7B,kCAAgB,GACR,CACX,CAAC;YAEF,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;gBACpB,MAAM,SAAS,GAAG,OAAO;qBACtB,mBAAmB,CAAC,WAAW,CAAC;qBAChC,WAAW,EAAE,CAAC;gBACjB,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;gBACrD,MAAM,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;YAChE,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;YACvF,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;YAE5C,MAAM,CACJ,8BACE,KAAC,OAAO,IAAC,OAAO,EAAC,iBAAiB,YAChC,kCAAgB,GACR,EACV,KAAC,OAAO,IAAC,OAAO,EAAC,kBAAkB,YACjC,mCAAiB,GACT,IACT,CACJ,CAAC;YAEF,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;gBACpB,MAAM,SAAS,GAAG,OAAO;qBACtB,mBAAmB,CAAC,WAAW,CAAC;qBAChC,WAAW,EAAE,CAAC;gBACjB,MAAM,OAAO,GAAG,SAAS,EAAE,cAAwB,CAAC;gBACpD,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;gBAC/C,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;YAClD,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;YAC3E,MAAM,CACJ,KAAC,OAAO,IAAC,OAAO,EAAC,cAAc,YAC7B,kCAAgB,GACR,CACX,CAAC;YAEF,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;gBACpB,MAAM,CAAC,eAAe,CAAC,CAAC,oBAAoB,CAC1C,MAAM,CAAC,gBAAgB,CAAC,EAAE,MAAM,EAAE,yBAAyB,EAAE,CAAC,EAC9D,GAAG,CACJ,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { cleanup, render } from \"@testing-library/react\";\nimport {\n afterEach,\n beforeEach,\n describe,\n expect,\n it,\n type Mock,\n vi,\n} from \"vitest\";\nimport { McpAppAdaptor, McpAppBridge } from \"./bridges/mcp-app/index.js\";\nimport { DataLLM } from \"./data-llm.js\";\nimport {\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"./hooks/test/utils.js\";\n\ndescribe(\"DataLLM\", () => {\n afterEach(() => {\n // Clean up React components BEFORE unstubbing globals\n cleanup();\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n });\n\n describe(\"apps-sdk mode\", () => {\n let OpenaiMock: { widgetState: unknown; setWidgetState: Mock };\n\n beforeEach(() => {\n OpenaiMock = {\n widgetState: { modelContent: {} },\n setWidgetState: vi.fn(),\n };\n // Use Object.defineProperty to ensure it persists\n Object.defineProperty(globalThis, \"openai\", {\n value: OpenaiMock,\n writable: true,\n configurable: true,\n });\n // Also set on window for browser-like environment\n if (typeof window !== \"undefined\") {\n Object.defineProperty(window, \"openai\", {\n value: OpenaiMock,\n writable: true,\n configurable: true,\n });\n }\n vi.stubGlobal(\"openai\", OpenaiMock);\n vi.stubGlobal(\"skybridge\", { hostType: \"apps-sdk\" });\n });\n\n afterEach(() => {\n // Keep the mock available for React cleanup, but reset it\n if (typeof window !== \"undefined\" && window.openai) {\n window.openai.setWidgetState = vi.fn();\n window.openai.widgetState = { modelContent: {}, privateContent: {} };\n }\n });\n\n it(\"should register a node with content and call setViewState\", () => {\n render(\n <DataLLM content=\"Test content\">\n <div>Child</div>\n </DataLLM>,\n );\n\n expect(OpenaiMock.setWidgetState).toHaveBeenCalled();\n const callArgs =\n OpenaiMock.setWidgetState.mock.calls[0]?.[0]?.modelContent;\n expect(callArgs).toHaveProperty(\"__view_context\");\n expect(callArgs?.__view_context).toContain(\"- Test content\");\n });\n it(\"should preserve existing viewState when updating context\", () => {\n OpenaiMock.widgetState = {\n modelContent: { existingKey: \"existingValue\" },\n };\n\n render(\n <DataLLM content=\"Test content\">\n <div>Child</div>\n </DataLLM>,\n );\n\n const callArgs =\n OpenaiMock.setWidgetState.mock.calls[0]?.[0]?.modelContent;\n expect(callArgs).toHaveProperty(\"existingKey\", \"existingValue\");\n expect(callArgs).toHaveProperty(\"__view_context\");\n });\n\n it(\"should handle deeply nested DataLLM components\", () => {\n render(\n <DataLLM content=\"Level 1\">\n <DataLLM content=\"Level 2A\" />\n <DataLLM content=\"Level 2B\">\n <DataLLM content=\"Level 3\">\n <div>Content</div>\n </DataLLM>\n </DataLLM>\n </DataLLM>,\n );\n\n const callArgs =\n OpenaiMock.setWidgetState.mock.calls[\n OpenaiMock.setWidgetState.mock.calls.length - 1\n ]?.[0]?.modelContent;\n const context = callArgs?.__view_context as string;\n expect(context).toContain(\"- Level 1\");\n expect(context).toContain(\" - Level 2A\");\n expect(context).toContain(\" - Level 2B\");\n expect(context).toContain(\" - Level 3\");\n });\n\n it(\"should update context when content changes\", () => {\n const { rerender } = render(\n <DataLLM content=\"Initial content\">\n <div>Child</div>\n </DataLLM>,\n );\n\n const initialCalls = OpenaiMock.setWidgetState.mock.calls.length;\n\n rerender(\n <DataLLM content=\"Updated content\">\n <div>Child</div>\n </DataLLM>,\n );\n\n expect(OpenaiMock.setWidgetState.mock.calls.length).toBeGreaterThan(\n initialCalls,\n );\n const lastCallArgs =\n OpenaiMock.setWidgetState.mock.calls[\n OpenaiMock.setWidgetState.mock.calls.length - 1\n ]?.[0]?.modelContent;\n expect(lastCallArgs?.__view_context).toContain(\"- Updated content\");\n });\n\n it(\"should remove node and update context when component unmounts\", () => {\n const { unmount } = render(\n <DataLLM content=\"Content to remove\">\n <div>Child</div>\n </DataLLM>,\n );\n\n const callsBeforeUnmount = OpenaiMock.setWidgetState.mock.calls.length;\n\n unmount();\n\n expect(OpenaiMock.setWidgetState.mock.calls.length).toBeGreaterThan(\n callsBeforeUnmount,\n );\n const lastCallArgs =\n OpenaiMock.setWidgetState.mock.calls[\n OpenaiMock.setWidgetState.mock.calls.length - 1\n ]?.[0]?.modelContent;\n expect(lastCallArgs?.__view_context).not.toContain(\"Content to remove\");\n });\n });\n\n describe(\"mcp-app mode\", () => {\n let postMessageMock: ReturnType<typeof getMcpAppHostPostMessageMock>;\n\n beforeEach(() => {\n vi.stubGlobal(\"skybridge\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n postMessageMock = getMcpAppHostPostMessageMock();\n vi.stubGlobal(\"parent\", { postMessage: postMessageMock });\n });\n\n afterEach(() => {\n cleanup();\n McpAppBridge.resetInstance();\n McpAppAdaptor.resetInstance();\n });\n\n it(\"should register a node and update view state via adaptor\", async () => {\n const adaptor = McpAppAdaptor.getInstance();\n\n render(\n <DataLLM content=\"Test content\">\n <div>Child</div>\n </DataLLM>,\n );\n\n await vi.waitFor(() => {\n const viewState = adaptor\n .getHostContextStore(\"viewState\")\n .getSnapshot();\n expect(viewState?.__view_context).toContain(\"- Test content\");\n });\n });\n\n it(\"should preserve existing view state when updating context\", async () => {\n const adaptor = McpAppAdaptor.getInstance();\n await adaptor.setViewState({ existingKey: \"existingValue\" });\n\n render(\n <DataLLM content=\"Test content\">\n <div>Child</div>\n </DataLLM>,\n );\n\n await vi.waitFor(() => {\n const viewState = adaptor\n .getHostContextStore(\"viewState\")\n .getSnapshot();\n expect(viewState?.existingKey).toBe(\"existingValue\");\n expect(viewState?.__view_context).toContain(\"- Test content\");\n });\n });\n\n it(\"should handle multiple DataLLM components sharing state through adaptor\", async () => {\n const adaptor = McpAppAdaptor.getInstance();\n\n render(\n <>\n <DataLLM content=\"First component\">\n <div>First</div>\n </DataLLM>\n <DataLLM content=\"Second component\">\n <div>Second</div>\n </DataLLM>\n </>,\n );\n\n await vi.waitFor(() => {\n const viewState = adaptor\n .getHostContextStore(\"viewState\")\n .getSnapshot();\n const context = viewState?.__view_context as string;\n expect(context).toContain(\"- First component\");\n expect(context).toContain(\"- Second component\");\n });\n });\n\n it(\"should call ui/update-model-context when view state changes\", async () => {\n render(\n <DataLLM content=\"Test content\">\n <div>Child</div>\n </DataLLM>,\n );\n\n await vi.waitFor(() => {\n expect(postMessageMock).toHaveBeenCalledWith(\n expect.objectContaining({ method: \"ui/update-model-context\" }),\n \"*\",\n );\n });\n });\n });\n});\n"]}
@@ -64,6 +64,8 @@ type TypedToolInfoReturn<TInput, TOutput, TResponseMetadata> = ToolState<Objecti
64
64
  * // toolInfo.output.structuredContent is typed based on view output schema
65
65
  * }
66
66
  * ```
67
+ *
68
+ * @see https://docs.skybridge.tech/api-reference/generate-helpers
67
69
  */
68
70
  export declare function generateHelpers<ServerType = never>(): {
69
71
  /**
@@ -53,6 +53,8 @@ import { useToolInfo } from "./hooks/use-tool-info.js";
53
53
  * // toolInfo.output.structuredContent is typed based on view output schema
54
54
  * }
55
55
  * ```
56
+ *
57
+ * @see https://docs.skybridge.tech/api-reference/generate-helpers
56
58
  */
57
59
  export function generateHelpers() {
58
60
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"generate-helpers.js","sourceRoot":"","sources":["../../src/web/generate-helpers.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,WAAW,GACZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAkB,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAoBvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAM,UAAU,eAAe;IAI7B,OAAO;QACL;;;;;;;;;;;;;;;;;;WAkBG;QACH,WAAW,EAAE,CACX,IAAc,EAId,EAAE;YACF,OAAO,WAAW,CAAC,IAAI,CAGtB,CAAC;QACJ,CAAC;QAED;;;;;;;;;;;;;;;;;;;;;;;;;;WA0BG;QACH,WAAW,EAAE,GAIX,EAAE;YACF,OAAO,WAAW,EAIjB,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"generate-helpers.js","sourceRoot":"","sources":["../../src/web/generate-helpers.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,WAAW,GACZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAkB,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAoBvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,MAAM,UAAU,eAAe;IAI7B,OAAO;QACL;;;;;;;;;;;;;;;;;;WAkBG;QACH,WAAW,EAAE,CACX,IAAc,EAId,EAAE;YACF,OAAO,WAAW,CAAC,IAAI,CAGtB,CAAC;QACJ,CAAC;QAED;;;;;;;;;;;;;;;;;;;;;;;;;;WA0BG;QACH,WAAW,EAAE,GAIX,EAAE;YACF,OAAO,WAAW,EAIjB,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type {\n InferTools,\n ToolInput,\n ToolOutput,\n ToolResponseMetadata,\n} from \"../server/index.js\";\nimport type { CallToolResponse } from \"./bridges/types.js\";\nimport {\n type CallToolAsyncFn,\n type CallToolFn,\n type CallToolState,\n useCallTool,\n} from \"./hooks/use-call-tool.js\";\nimport { type ToolState, useToolInfo } from \"./hooks/use-tool-info.js\";\nimport type { Objectify, Prettify } from \"./types.js\";\n\ntype TypedCallToolResponse<TOutput> = CallToolResponse & {\n structuredContent: TOutput;\n};\n\ntype TypedCallToolReturn<TInput, TOutput> = Prettify<\n CallToolState<TypedCallToolResponse<TOutput>> & {\n callTool: CallToolFn<TInput, TypedCallToolResponse<TOutput>>;\n callToolAsync: CallToolAsyncFn<TInput, TypedCallToolResponse<TOutput>>;\n }\n>;\n\ntype TypedToolInfoReturn<TInput, TOutput, TResponseMetadata> = ToolState<\n Objectify<TInput>,\n Objectify<TOutput>,\n Objectify<TResponseMetadata>\n>;\n\n/**\n * Creates typed versions of skybridge hooks with full type inference\n * for tool names, inputs, and outputs.\n *\n * This is the recommended way to use skybridge hooks in your views.\n * Set this up once in a dedicated file and export the typed hooks for use across your app.\n *\n * @typeParam ServerType - The type of your McpServer instance (use `typeof server`).\n * Must be a server instance created with method chaining.\n * TypeScript will validate that tools can be inferred from this type.\n *\n * @example\n * ```typescript\n * // src/server.ts\n * const server = new McpServer({ name: \"my-app\", version: \"1.0\" }, {})\n * .registerTool({\n * name: \"search-trip\",\n * inputSchema: { destination: z.string() },\n * outputSchema: { results: z.array(z.string()) },\n * view: { component: \"search-trip\", description: \"Search trips\" },\n * }, async ({ destination }) => {\n * return { content: [{ type: \"text\", text: `Found trips to ${destination}` }] };\n * });\n *\n * export type AppType = typeof server;\n * ```\n *\n * @example\n * ```typescript\n * // src/helpers.ts (one-time setup)\n * import type { AppType } from \"./server\";\n * import { generateHelpers } from \"skybridge/web\";\n *\n * export const { useCallTool, useToolInfo } = generateHelpers<AppType>();\n * ```\n *\n * @example\n * ```typescript\n * // src/views/search.tsx (usage)\n * import { useCallTool, useToolInfo } from \"../helpers\";\n *\n * export function SearchView() {\n * const { callTool, data } = useCallTool(\"search-trip\");\n * // ^ autocomplete for tool names\n * callTool({ destination: \"Spain\" });\n * // ^ autocomplete for input fields\n *\n * const toolInfo = useToolInfo<\"search-trip\">();\n * // ^ autocomplete for view names\n * // toolInfo.input is typed based on view input schema\n * // toolInfo.output.structuredContent is typed based on view output schema\n * }\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/generate-helpers\n */\nexport function generateHelpers<ServerType = never>() {\n type Tools = InferTools<ServerType>;\n type ToolNames = keyof Tools & string;\n\n return {\n /**\n * Typed version of `useCallTool` that provides autocomplete for tool names\n * and type inference for inputs and outputs.\n *\n * @param name - The name of the tool to call. Autocompletes based on your server's tool registry.\n * @returns A hook with typed `callTool` function and `data` property.\n *\n * @example\n * ```typescript\n * const { callTool, data, isPending } = useCallTool(\"search-trip\");\n * // TypeScript knows callTool expects { destination: string }\n * callTool({ destination: \"Spain\" });\n *\n * // data.structuredContent is typed based on your outputSchema\n * if (data) {\n * console.log(data.structuredContent.results);\n * }\n * ```\n */\n useCallTool: <ToolName extends ToolNames>(\n name: ToolName,\n ): TypedCallToolReturn<\n ToolInput<ServerType, ToolName>,\n ToolOutput<ServerType, ToolName>\n > => {\n return useCallTool(name) as TypedCallToolReturn<\n ToolInput<ServerType, ToolName>,\n ToolOutput<ServerType, ToolName>\n >;\n },\n\n /**\n * Typed version of `useToolInfo` that provides autocomplete for tool names\n * and type inference for inputs, outputs, and responseMetadata.\n *\n * @typeParam K - The name of the tool. Autocompletes based on your server's tool registry.\n * @returns A discriminated union with `status: \"pending\" | \"success\"` that narrows correctly.\n *\n * @example\n * ```typescript\n * const toolInfo = useToolInfo<\"search-trip\">();\n * // toolInfo.input is typed as { destination: string; ... }\n * // toolInfo.output is typed as { results: Array<...>; ... }\n * // toolInfo.responseMetadata is typed based on _meta in callback return\n * // toolInfo.status narrows correctly: \"pending\" | \"success\"\n *\n * if (toolInfo.isPending) {\n * // TypeScript knows output and responseMetadata are undefined here\n * console.log(toolInfo.input.destination);\n * }\n *\n * if (toolInfo.isSuccess) {\n * // TypeScript knows output and responseMetadata are defined here\n * console.log(toolInfo.output.results);\n * console.log(toolInfo.responseMetadata);\n * }\n * ```\n */\n useToolInfo: <ToolName extends ToolNames>(): TypedToolInfoReturn<\n ToolInput<ServerType, ToolName>,\n ToolOutput<ServerType, ToolName>,\n ToolResponseMetadata<ServerType, ToolName>\n > => {\n return useToolInfo() as TypedToolInfoReturn<\n ToolInput<ServerType, ToolName>,\n ToolOutput<ServerType, ToolName>,\n ToolResponseMetadata<ServerType, ToolName>\n >;\n },\n };\n}\n"]}
@@ -3,7 +3,7 @@ import { createInterfaceTestServer, createTestServer } from "../test/utils.js";
3
3
  import { generateHelpers } from "./generate-helpers.js";
4
4
  const server = createTestServer();
5
5
  const interfaceServer = createInterfaceTestServer();
6
- test("InferTools extracts the tool registry type (widgets + registerTool)", () => {
6
+ test("InferTools extracts the tool registry type (views + registerTool)", () => {
7
7
  expectTypeOf().toHaveProperty("search-trip");
8
8
  expectTypeOf().toHaveProperty("get-trip-details");
9
9
  expectTypeOf().toHaveProperty("no-input-view");
@@ -14,7 +14,7 @@ test("InferTools extracts the tool registry type (widgets + registerTool)", () =
14
14
  expectTypeOf().toHaveProperty("tool-with-metadata");
15
15
  expectTypeOf().toHaveProperty("view-with-mixed-returns");
16
16
  });
17
- test("ToolNames returns a union of tool name literals (widgets + registerTool)", () => {
17
+ test("ToolNames returns a union of tool name literals (views + registerTool)", () => {
18
18
  expectTypeOf().toEqualTypeOf();
19
19
  });
20
20
  test("ToolInput extracts the correct input type from Zod schema", () => {
@@ -32,7 +32,7 @@ test("ToolOutput extracts the correct output type from callback (inferred)", ()
32
32
  expectTypeOf().toEqualTypeOf();
33
33
  expectTypeOf().toEqualTypeOf();
34
34
  });
35
- test("generateHelpers provides autocomplete for tool names (widgets + registerTool)", () => {
35
+ test("generateHelpers provides autocomplete for tool names (views + registerTool)", () => {
36
36
  const { useCallTool } = generateHelpers();
37
37
  useCallTool("search-trip");
38
38
  useCallTool("get-trip-details");
@@ -128,16 +128,16 @@ test("useCallTool returns correctly typed data", () => {
128
128
  });
129
129
  test("useCallTool returns correctly typed data for callback-inferred outputs", () => {
130
130
  const { useCallTool } = generateHelpers();
131
- const { data: widgetData } = useCallTool("inferred-output-view");
132
- if (widgetData) {
133
- expectTypeOf(widgetData.structuredContent).toExtend();
131
+ const { data: viewData } = useCallTool("inferred-output-view");
132
+ if (viewData) {
133
+ expectTypeOf(viewData.structuredContent).toExtend();
134
134
  }
135
135
  const { data: toolData } = useCallTool("inferred-tool");
136
136
  if (toolData) {
137
137
  expectTypeOf(toolData.structuredContent).toExtend();
138
138
  }
139
139
  });
140
- test("generateHelpers provides autocomplete for tool names in useToolInfo (widgets + registerTool)", () => {
140
+ test("generateHelpers provides autocomplete for tool names in useToolInfo (views + registerTool)", () => {
141
141
  const { useToolInfo } = generateHelpers();
142
142
  useToolInfo();
143
143
  useToolInfo();
@@ -154,11 +154,13 @@ test("generateHelpers provides autocomplete for tool names in useToolInfo (widge
154
154
  test("useToolInfo infers input and output types", () => {
155
155
  const { useToolInfo } = generateHelpers();
156
156
  const toolInfo = useToolInfo();
157
- // Input is only available when not in idle state
158
- if (!(toolInfo.status === "idle")) {
157
+ // Input is optional in pending — host may not have delivered args yet
158
+ if (toolInfo.status === "pending") {
159
159
  expectTypeOf(toolInfo.input).toExtend();
160
160
  }
161
161
  if (toolInfo.status === "success") {
162
+ // Input is optional in success — the host may not have surfaced args yet
163
+ expectTypeOf(toolInfo.input).toExtend();
162
164
  expectTypeOf(toolInfo.output).toExtend();
163
165
  expectTypeOf(toolInfo.output.results).toBeArray();
164
166
  expectTypeOf(toolInfo.output.totalCount).toBeNumber();