skybridge 0.0.0-dev.8a1f1de → 0.0.0-dev.8a4b6f5

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 (530) hide show
  1. package/README.md +155 -0
  2. package/dist/cli/build-helpers.d.ts +11 -0
  3. package/dist/cli/build-helpers.js +107 -0
  4. package/dist/cli/build-helpers.js.map +1 -0
  5. package/dist/cli/build-helpers.test.js +132 -0
  6. package/dist/cli/build-helpers.test.js.map +1 -0
  7. package/dist/cli/build-steps.d.ts +2 -0
  8. package/dist/cli/build-steps.js +73 -0
  9. package/dist/cli/build-steps.js.map +1 -0
  10. package/dist/cli/build-steps.test.js +52 -0
  11. package/dist/cli/build-steps.test.js.map +1 -0
  12. package/dist/cli/detect-port.d.ts +18 -0
  13. package/dist/cli/detect-port.js +50 -0
  14. package/dist/cli/detect-port.js.map +1 -0
  15. package/dist/cli/header.d.ts +4 -0
  16. package/dist/cli/header.js +6 -0
  17. package/dist/cli/header.js.map +1 -0
  18. package/dist/cli/resolve-skybridge-config.d.ts +5 -0
  19. package/dist/cli/resolve-skybridge-config.js +18 -0
  20. package/dist/cli/resolve-skybridge-config.js.map +1 -0
  21. package/dist/cli/run-command.d.ts +2 -0
  22. package/dist/cli/run-command.js +43 -0
  23. package/dist/cli/run-command.js.map +1 -0
  24. package/dist/cli/run-plain.d.ts +18 -0
  25. package/dist/cli/run-plain.js +89 -0
  26. package/dist/cli/run-plain.js.map +1 -0
  27. package/dist/cli/telemetry.d.ts +7 -0
  28. package/dist/cli/telemetry.js +123 -0
  29. package/dist/cli/telemetry.js.map +1 -0
  30. package/dist/cli/tunnel-control-server.d.ts +9 -0
  31. package/dist/cli/tunnel-control-server.js +31 -0
  32. package/dist/cli/tunnel-control-server.js.map +1 -0
  33. package/dist/cli/tunnel-control-server.test.js +39 -0
  34. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  35. package/dist/cli/tunnel-handler.d.ts +3 -0
  36. package/dist/cli/tunnel-handler.js +48 -0
  37. package/dist/cli/tunnel-handler.js.map +1 -0
  38. package/dist/cli/tunnel-handler.test.js +105 -0
  39. package/dist/cli/tunnel-handler.test.js.map +1 -0
  40. package/dist/cli/tunnel.d.ts +57 -0
  41. package/dist/cli/tunnel.js +154 -0
  42. package/dist/cli/tunnel.js.map +1 -0
  43. package/dist/cli/tunnel.test.js +190 -0
  44. package/dist/cli/tunnel.test.js.map +1 -0
  45. package/dist/cli/types.d.ts +5 -0
  46. package/dist/cli/types.js +2 -0
  47. package/dist/cli/types.js.map +1 -0
  48. package/dist/cli/use-execute-steps.d.ts +11 -0
  49. package/dist/cli/use-execute-steps.js +36 -0
  50. package/dist/cli/use-execute-steps.js.map +1 -0
  51. package/dist/cli/use-messages.d.ts +3 -0
  52. package/dist/cli/use-messages.js +11 -0
  53. package/dist/cli/use-messages.js.map +1 -0
  54. package/dist/cli/use-nodemon.d.ts +16 -0
  55. package/dist/cli/use-nodemon.js +84 -0
  56. package/dist/cli/use-nodemon.js.map +1 -0
  57. package/dist/cli/use-open-browser.d.ts +1 -0
  58. package/dist/cli/use-open-browser.js +44 -0
  59. package/dist/cli/use-open-browser.js.map +1 -0
  60. package/dist/cli/use-tunnel.d.ts +14 -0
  61. package/dist/cli/use-tunnel.js +131 -0
  62. package/dist/cli/use-tunnel.js.map +1 -0
  63. package/dist/cli/use-typescript-check.d.ts +15 -0
  64. package/dist/cli/use-typescript-check.js +97 -0
  65. package/dist/cli/use-typescript-check.js.map +1 -0
  66. package/dist/commands/build.d.ts +6 -0
  67. package/dist/commands/build.js +31 -0
  68. package/dist/commands/build.js.map +1 -0
  69. package/dist/commands/create.d.ts +9 -0
  70. package/dist/commands/create.js +30 -0
  71. package/dist/commands/create.js.map +1 -0
  72. package/dist/commands/dev.d.ts +13 -0
  73. package/dist/commands/dev.js +128 -0
  74. package/dist/commands/dev.js.map +1 -0
  75. package/dist/commands/start.d.ts +9 -0
  76. package/dist/commands/start.js +55 -0
  77. package/dist/commands/start.js.map +1 -0
  78. package/dist/commands/telemetry/disable.d.ts +5 -0
  79. package/dist/commands/telemetry/disable.js +14 -0
  80. package/dist/commands/telemetry/disable.js.map +1 -0
  81. package/dist/commands/telemetry/enable.d.ts +5 -0
  82. package/dist/commands/telemetry/enable.js +14 -0
  83. package/dist/commands/telemetry/enable.js.map +1 -0
  84. package/dist/commands/telemetry/status.d.ts +5 -0
  85. package/dist/commands/telemetry/status.js +14 -0
  86. package/dist/commands/telemetry/status.js.map +1 -0
  87. package/dist/context-warnings.d.ts +5 -0
  88. package/dist/context-warnings.js +31 -0
  89. package/dist/context-warnings.js.map +1 -0
  90. package/dist/context-warnings.test.d.ts +1 -0
  91. package/dist/context-warnings.test.js +28 -0
  92. package/dist/context-warnings.test.js.map +1 -0
  93. package/dist/server/asset-base-url-transform-plugin.d.ts +11 -0
  94. package/dist/server/asset-base-url-transform-plugin.js +48 -0
  95. package/dist/server/asset-base-url-transform-plugin.js.map +1 -0
  96. package/dist/server/asset-base-url-transform-plugin.test.d.ts +1 -0
  97. package/dist/server/asset-base-url-transform-plugin.test.js +134 -0
  98. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -0
  99. package/dist/server/auth/discovery.d.ts +32 -0
  100. package/dist/server/auth/discovery.js +56 -0
  101. package/dist/server/auth/discovery.js.map +1 -0
  102. package/dist/server/auth/discovery.test.d.ts +1 -0
  103. package/dist/server/auth/discovery.test.js +93 -0
  104. package/dist/server/auth/discovery.test.js.map +1 -0
  105. package/dist/server/auth/index.d.ts +44 -0
  106. package/dist/server/auth/index.js +2 -0
  107. package/dist/server/auth/index.js.map +1 -0
  108. package/dist/server/auth/providers/auth0.d.ts +40 -0
  109. package/dist/server/auth/providers/auth0.js +31 -0
  110. package/dist/server/auth/providers/auth0.js.map +1 -0
  111. package/dist/server/auth/providers/auth0.test.d.ts +1 -0
  112. package/dist/server/auth/providers/auth0.test.js +50 -0
  113. package/dist/server/auth/providers/auth0.test.js.map +1 -0
  114. package/dist/server/auth/providers/authplane.d.ts +49 -0
  115. package/dist/server/auth/providers/authplane.js +57 -0
  116. package/dist/server/auth/providers/authplane.js.map +1 -0
  117. package/dist/server/auth/providers/authplane.test.d.ts +1 -0
  118. package/dist/server/auth/providers/authplane.test.js +140 -0
  119. package/dist/server/auth/providers/authplane.test.js.map +1 -0
  120. package/dist/server/auth/providers/clerk.d.ts +51 -0
  121. package/dist/server/auth/providers/clerk.js +19 -0
  122. package/dist/server/auth/providers/clerk.js.map +1 -0
  123. package/dist/server/auth/providers/clerk.test.d.ts +1 -0
  124. package/dist/server/auth/providers/clerk.test.js +30 -0
  125. package/dist/server/auth/providers/clerk.test.js.map +1 -0
  126. package/dist/server/auth/providers/custom.d.ts +40 -0
  127. package/dist/server/auth/providers/custom.js +56 -0
  128. package/dist/server/auth/providers/custom.js.map +1 -0
  129. package/dist/server/auth/providers/custom.test.d.ts +1 -0
  130. package/dist/server/auth/providers/custom.test.js +158 -0
  131. package/dist/server/auth/providers/custom.test.js.map +1 -0
  132. package/dist/server/auth/providers/descope.d.ts +44 -0
  133. package/dist/server/auth/providers/descope.js +44 -0
  134. package/dist/server/auth/providers/descope.js.map +1 -0
  135. package/dist/server/auth/providers/descope.test.d.ts +1 -0
  136. package/dist/server/auth/providers/descope.test.js +62 -0
  137. package/dist/server/auth/providers/descope.test.js.map +1 -0
  138. package/dist/server/auth/providers/shared.d.ts +2 -0
  139. package/dist/server/auth/providers/shared.js +6 -0
  140. package/dist/server/auth/providers/shared.js.map +1 -0
  141. package/dist/server/auth/providers/shared.test.d.ts +1 -0
  142. package/dist/server/auth/providers/shared.test.js +10 -0
  143. package/dist/server/auth/providers/shared.test.js.map +1 -0
  144. package/dist/server/auth/providers/stytch.d.ts +25 -0
  145. package/dist/server/auth/providers/stytch.js +16 -0
  146. package/dist/server/auth/providers/stytch.js.map +1 -0
  147. package/dist/server/auth/providers/verify-spy.d.ts +12 -0
  148. package/dist/server/auth/providers/verify-spy.js +21 -0
  149. package/dist/server/auth/providers/verify-spy.js.map +1 -0
  150. package/dist/server/auth/providers/workos.d.ts +33 -0
  151. package/dist/server/auth/providers/workos.js +15 -0
  152. package/dist/server/auth/providers/workos.js.map +1 -0
  153. package/dist/server/auth/security-schemes.d.ts +23 -0
  154. package/dist/server/auth/security-schemes.js +64 -0
  155. package/dist/server/auth/security-schemes.js.map +1 -0
  156. package/dist/server/auth/security-schemes.test.d.ts +1 -0
  157. package/dist/server/auth/security-schemes.test.js +99 -0
  158. package/dist/server/auth/security-schemes.test.js.map +1 -0
  159. package/dist/server/auth/setup.d.ts +6 -0
  160. package/dist/server/auth/setup.js +92 -0
  161. package/dist/server/auth/setup.js.map +1 -0
  162. package/dist/server/auth/setup.test.d.ts +1 -0
  163. package/dist/server/auth/setup.test.js +508 -0
  164. package/dist/server/auth/setup.test.js.map +1 -0
  165. package/dist/server/auth/verify.d.ts +46 -0
  166. package/dist/server/auth/verify.js +62 -0
  167. package/dist/server/auth/verify.js.map +1 -0
  168. package/dist/server/auth/verify.test.d.ts +1 -0
  169. package/dist/server/auth/verify.test.js +149 -0
  170. package/dist/server/auth/verify.test.js.map +1 -0
  171. package/dist/server/auth-extra.test-d.d.ts +1 -0
  172. package/dist/server/auth-extra.test-d.js +82 -0
  173. package/dist/server/auth-extra.test-d.js.map +1 -0
  174. package/dist/server/auth.d.ts +58 -0
  175. package/dist/server/auth.js +28 -0
  176. package/dist/server/auth.js.map +1 -0
  177. package/dist/server/build-manifest.test.d.ts +1 -0
  178. package/dist/server/build-manifest.test.js +27 -0
  179. package/dist/server/build-manifest.test.js.map +1 -0
  180. package/dist/server/content-helpers.d.ts +67 -0
  181. package/dist/server/content-helpers.js +79 -0
  182. package/dist/server/content-helpers.js.map +1 -0
  183. package/dist/server/content-helpers.test.d.ts +1 -0
  184. package/dist/server/content-helpers.test.js +70 -0
  185. package/dist/server/content-helpers.test.js.map +1 -0
  186. package/dist/server/express.d.ts +11 -0
  187. package/dist/server/express.js +101 -0
  188. package/dist/server/express.js.map +1 -0
  189. package/dist/server/express.test.d.ts +1 -0
  190. package/dist/server/express.test.js +491 -0
  191. package/dist/server/express.test.js.map +1 -0
  192. package/dist/server/file-ref.d.ts +28 -0
  193. package/dist/server/file-ref.js +27 -0
  194. package/dist/server/file-ref.js.map +1 -0
  195. package/dist/server/host.d.ts +2 -0
  196. package/dist/server/host.js +11 -0
  197. package/dist/server/host.js.map +1 -0
  198. package/dist/server/host.test.d.ts +1 -0
  199. package/dist/server/host.test.js +13 -0
  200. package/dist/server/host.test.js.map +1 -0
  201. package/dist/server/index.d.ts +18 -4
  202. package/dist/server/index.js +15 -3
  203. package/dist/server/index.js.map +1 -1
  204. package/dist/server/inferUtilityTypes.d.ts +6 -6
  205. package/dist/server/inferUtilityTypes.js.map +1 -1
  206. package/dist/server/metric.d.ts +14 -0
  207. package/dist/server/metric.js +62 -0
  208. package/dist/server/metric.js.map +1 -0
  209. package/dist/server/middleware.d.ts +162 -0
  210. package/dist/server/middleware.js +126 -0
  211. package/dist/server/middleware.js.map +1 -0
  212. package/dist/server/middleware.test-d.d.ts +1 -0
  213. package/dist/server/middleware.test-d.js +75 -0
  214. package/dist/server/middleware.test-d.js.map +1 -0
  215. package/dist/server/middleware.test.d.ts +1 -0
  216. package/dist/server/middleware.test.js +529 -0
  217. package/dist/server/middleware.test.js.map +1 -0
  218. package/dist/server/register-tool.test.d.ts +1 -0
  219. package/dist/server/register-tool.test.js +26 -0
  220. package/dist/server/register-tool.test.js.map +1 -0
  221. package/dist/server/requestOrigin.d.ts +7 -0
  222. package/dist/server/requestOrigin.js +25 -0
  223. package/dist/server/requestOrigin.js.map +1 -0
  224. package/dist/server/server.d.ts +435 -41
  225. package/dist/server/server.js +714 -54
  226. package/dist/server/server.js.map +1 -1
  227. package/dist/server/skills-integration.test.d.ts +1 -0
  228. package/dist/server/skills-integration.test.js +79 -0
  229. package/dist/server/skills-integration.test.js.map +1 -0
  230. package/dist/server/skills.d.ts +29 -0
  231. package/dist/server/skills.js +195 -0
  232. package/dist/server/skills.js.map +1 -0
  233. package/dist/server/skills.test.d.ts +1 -0
  234. package/dist/server/skills.test.js +247 -0
  235. package/dist/server/skills.test.js.map +1 -0
  236. package/dist/server/templateHelper.d.ts +5 -7
  237. package/dist/server/templateHelper.js +3 -22
  238. package/dist/server/templateHelper.js.map +1 -1
  239. package/dist/server/templates.generated.d.ts +4 -0
  240. package/dist/server/templates.generated.js +47 -0
  241. package/dist/server/templates.generated.js.map +1 -0
  242. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  243. package/dist/server/tunnel-proxy-router.js +110 -0
  244. package/dist/server/tunnel-proxy-router.js.map +1 -0
  245. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  246. package/dist/server/tunnel-proxy-router.test.js +229 -0
  247. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  248. package/dist/server/view-name.test-d.d.ts +1 -0
  249. package/dist/server/view-name.test-d.js +8 -0
  250. package/dist/server/view-name.test-d.js.map +1 -0
  251. package/dist/server/view-resource-resolution.test.d.ts +6 -0
  252. package/dist/server/view-resource-resolution.test.js +171 -0
  253. package/dist/server/view-resource-resolution.test.js.map +1 -0
  254. package/dist/server/viewsDevServer.d.ts +14 -0
  255. package/dist/server/viewsDevServer.js +48 -0
  256. package/dist/server/viewsDevServer.js.map +1 -0
  257. package/dist/test/utils.d.ts +16 -24
  258. package/dist/test/utils.js +42 -37
  259. package/dist/test/utils.js.map +1 -1
  260. package/dist/test/view.test.d.ts +1 -0
  261. package/dist/test/view.test.js +552 -0
  262. package/dist/test/view.test.js.map +1 -0
  263. package/dist/version.d.ts +1 -0
  264. package/dist/version.js +3 -0
  265. package/dist/version.js.map +1 -0
  266. package/dist/views/index.d.ts +3 -0
  267. package/dist/views/index.js +3 -0
  268. package/dist/views/index.js.map +1 -0
  269. package/dist/views/scan-views.d.ts +16 -0
  270. package/dist/views/scan-views.js +88 -0
  271. package/dist/views/scan-views.js.map +1 -0
  272. package/dist/views/scan-views.test.d.ts +1 -0
  273. package/dist/views/scan-views.test.js +99 -0
  274. package/dist/views/scan-views.test.js.map +1 -0
  275. package/dist/views/validate-view.d.ts +1 -0
  276. package/dist/views/validate-view.js +9 -0
  277. package/dist/views/validate-view.js.map +1 -0
  278. package/dist/views/validate-view.test.d.ts +1 -0
  279. package/dist/views/validate-view.test.js +24 -0
  280. package/dist/views/validate-view.test.js.map +1 -0
  281. package/dist/web/bridges/adaptor.d.ts +51 -0
  282. package/dist/web/bridges/adaptor.js +327 -0
  283. package/dist/web/bridges/adaptor.js.map +1 -0
  284. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  285. package/dist/web/bridges/adaptor.test.js +225 -0
  286. package/dist/web/bridges/adaptor.test.js.map +1 -0
  287. package/dist/web/bridges/apps-sdk/bridge.d.ts +15 -0
  288. package/dist/web/bridges/{apps-sdk-bridge.js → apps-sdk/bridge.js} +17 -5
  289. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -0
  290. package/dist/web/bridges/apps-sdk/index.d.ts +4 -0
  291. package/dist/web/bridges/apps-sdk/index.js +4 -0
  292. package/dist/web/bridges/apps-sdk/index.js.map +1 -0
  293. package/dist/web/bridges/apps-sdk/types.d.ts +133 -0
  294. package/dist/web/bridges/apps-sdk/types.js +10 -0
  295. package/dist/web/bridges/apps-sdk/types.js.map +1 -0
  296. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +13 -0
  297. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +18 -0
  298. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -0
  299. package/dist/web/bridges/get-adaptor.d.ts +9 -0
  300. package/dist/web/bridges/get-adaptor.js +10 -0
  301. package/dist/web/bridges/get-adaptor.js.map +1 -0
  302. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  303. package/dist/web/bridges/get-adaptor.test.js +32 -0
  304. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  305. package/dist/web/bridges/index.d.ts +5 -4
  306. package/dist/web/bridges/index.js +5 -4
  307. package/dist/web/bridges/index.js.map +1 -1
  308. package/dist/web/bridges/mcp-app/bridge.d.ts +39 -0
  309. package/dist/web/bridges/mcp-app/bridge.js +168 -0
  310. package/dist/web/bridges/mcp-app/bridge.js.map +1 -0
  311. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  312. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  313. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  314. package/dist/web/bridges/mcp-app/index.d.ts +3 -0
  315. package/dist/web/bridges/mcp-app/index.js +3 -0
  316. package/dist/web/bridges/mcp-app/index.js.map +1 -0
  317. package/dist/web/bridges/mcp-app/types.d.ts +10 -0
  318. package/dist/web/bridges/mcp-app/types.js +2 -0
  319. package/dist/web/bridges/mcp-app/types.js.map +1 -0
  320. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +19 -0
  321. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +19 -0
  322. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -0
  323. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.d.ts +1 -0
  324. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +26 -0
  325. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -0
  326. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  327. package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
  328. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  329. package/dist/web/bridges/types.d.ts +187 -30
  330. package/dist/web/bridges/types.js +14 -1
  331. package/dist/web/bridges/types.js.map +1 -1
  332. package/dist/web/bridges/types.test.d.ts +1 -0
  333. package/dist/web/bridges/types.test.js +19 -0
  334. package/dist/web/bridges/types.test.js.map +1 -0
  335. package/dist/web/bridges/use-host-context.d.ts +7 -0
  336. package/dist/web/bridges/use-host-context.js +13 -0
  337. package/dist/web/bridges/use-host-context.js.map +1 -0
  338. package/dist/web/components/modal-provider.d.ts +4 -0
  339. package/dist/web/components/modal-provider.js +46 -0
  340. package/dist/web/components/modal-provider.js.map +1 -0
  341. package/dist/web/create-store.d.ts +26 -0
  342. package/dist/web/create-store.js +47 -8
  343. package/dist/web/create-store.js.map +1 -1
  344. package/dist/web/create-store.test.js +115 -53
  345. package/dist/web/create-store.test.js.map +1 -1
  346. package/dist/web/data-llm.d.ts +35 -2
  347. package/dist/web/data-llm.js +35 -5
  348. package/dist/web/data-llm.js.map +1 -1
  349. package/dist/web/data-llm.test.js +144 -65
  350. package/dist/web/data-llm.test.js.map +1 -1
  351. package/dist/web/generate-helpers.d.ts +24 -19
  352. package/dist/web/generate-helpers.js +22 -18
  353. package/dist/web/generate-helpers.js.map +1 -1
  354. package/dist/web/generate-helpers.test-d.js +30 -28
  355. package/dist/web/generate-helpers.test-d.js.map +1 -1
  356. package/dist/web/generate-helpers.test.js.map +1 -1
  357. package/dist/web/helpers/state.d.ts +2 -2
  358. package/dist/web/helpers/state.js +17 -12
  359. package/dist/web/helpers/state.js.map +1 -1
  360. package/dist/web/helpers/state.test.js +9 -9
  361. package/dist/web/helpers/state.test.js.map +1 -1
  362. package/dist/web/hooks/index.d.ts +8 -3
  363. package/dist/web/hooks/index.js +7 -2
  364. package/dist/web/hooks/index.js.map +1 -1
  365. package/dist/web/hooks/test/utils.d.ts +13 -2
  366. package/dist/web/hooks/test/utils.js +49 -14
  367. package/dist/web/hooks/test/utils.js.map +1 -1
  368. package/dist/web/hooks/use-call-tool.d.ts +48 -2
  369. package/dist/web/hooks/use-call-tool.js +30 -2
  370. package/dist/web/hooks/use-call-tool.js.map +1 -1
  371. package/dist/web/hooks/use-call-tool.test-d.js +1 -1
  372. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  373. package/dist/web/hooks/use-call-tool.test.js +65 -30
  374. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  375. package/dist/web/hooks/use-display-mode.d.ts +23 -3
  376. package/dist/web/hooks/use-display-mode.js +23 -4
  377. package/dist/web/hooks/use-display-mode.js.map +1 -1
  378. package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
  379. package/dist/web/hooks/use-display-mode.test-d.js +8 -0
  380. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
  381. package/dist/web/hooks/use-display-mode.test.js +56 -20
  382. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  383. package/dist/web/hooks/use-download.d.ts +5 -0
  384. package/dist/web/hooks/use-download.js +8 -0
  385. package/dist/web/hooks/use-download.js.map +1 -0
  386. package/dist/web/hooks/use-download.test.d.ts +1 -0
  387. package/dist/web/hooks/use-download.test.js +103 -0
  388. package/dist/web/hooks/use-download.test.js.map +1 -0
  389. package/dist/web/hooks/use-files.d.ts +35 -6
  390. package/dist/web/hooks/use-files.js +37 -2
  391. package/dist/web/hooks/use-files.js.map +1 -1
  392. package/dist/web/hooks/use-files.test.js +40 -7
  393. package/dist/web/hooks/use-files.test.js.map +1 -1
  394. package/dist/web/hooks/use-host-info.d.ts +22 -0
  395. package/dist/web/hooks/use-host-info.js +30 -0
  396. package/dist/web/hooks/use-host-info.js.map +1 -0
  397. package/dist/web/hooks/use-host-info.test.d.ts +1 -0
  398. package/dist/web/hooks/use-host-info.test.js +59 -0
  399. package/dist/web/hooks/use-host-info.test.js.map +1 -0
  400. package/dist/web/hooks/use-layout.d.ts +4 -2
  401. package/dist/web/hooks/use-layout.js +6 -4
  402. package/dist/web/hooks/use-layout.js.map +1 -1
  403. package/dist/web/hooks/use-layout.test.js +65 -31
  404. package/dist/web/hooks/use-layout.test.js.map +1 -1
  405. package/dist/web/hooks/use-open-external.d.ts +20 -1
  406. package/dist/web/hooks/use-open-external.js +19 -3
  407. package/dist/web/hooks/use-open-external.js.map +1 -1
  408. package/dist/web/hooks/use-open-external.test.js +39 -14
  409. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  410. package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
  411. package/dist/web/hooks/use-register-view-tool.js +50 -0
  412. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  413. package/dist/web/hooks/use-request-close.d.ts +16 -0
  414. package/dist/web/hooks/use-request-close.js +21 -0
  415. package/dist/web/hooks/use-request-close.js.map +1 -0
  416. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  417. package/dist/web/hooks/use-request-close.test.js +47 -0
  418. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  419. package/dist/web/hooks/use-request-modal.d.ts +18 -3
  420. package/dist/web/hooks/use-request-modal.js +25 -8
  421. package/dist/web/hooks/use-request-modal.js.map +1 -1
  422. package/dist/web/hooks/use-request-modal.test.js +15 -1
  423. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  424. package/dist/web/hooks/use-request-size.d.ts +20 -0
  425. package/dist/web/hooks/use-request-size.js +24 -0
  426. package/dist/web/hooks/use-request-size.js.map +1 -0
  427. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  428. package/dist/web/hooks/use-request-size.test.js +47 -0
  429. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  430. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -1
  431. package/dist/web/hooks/use-send-follow-up-message.js +20 -3
  432. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  433. package/dist/web/hooks/use-set-open-in-app-url.d.ts +18 -0
  434. package/dist/web/hooks/use-set-open-in-app-url.js +25 -0
  435. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -0
  436. package/dist/web/hooks/use-set-open-in-app-url.test.d.ts +1 -0
  437. package/dist/web/hooks/use-set-open-in-app-url.test.js +63 -0
  438. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -0
  439. package/dist/web/hooks/use-tool-info.d.ts +53 -2
  440. package/dist/web/hooks/use-tool-info.js +34 -11
  441. package/dist/web/hooks/use-tool-info.js.map +1 -1
  442. package/dist/web/hooks/use-tool-info.test-d.js +11 -29
  443. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  444. package/dist/web/hooks/use-tool-info.test.js +45 -35
  445. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  446. package/dist/web/hooks/use-user.d.ts +3 -1
  447. package/dist/web/hooks/use-user.js +22 -4
  448. package/dist/web/hooks/use-user.js.map +1 -1
  449. package/dist/web/hooks/use-user.test.js +104 -29
  450. package/dist/web/hooks/use-user.test.js.map +1 -1
  451. package/dist/web/hooks/use-view-state.d.ts +25 -0
  452. package/dist/web/hooks/use-view-state.js +42 -0
  453. package/dist/web/hooks/use-view-state.js.map +1 -0
  454. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  455. package/dist/web/hooks/use-view-state.test.js +212 -0
  456. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  457. package/dist/web/index.d.ts +1 -2
  458. package/dist/web/index.js +1 -2
  459. package/dist/web/index.js.map +1 -1
  460. package/dist/web/mount-view.d.ts +20 -0
  461. package/dist/web/mount-view.js +46 -0
  462. package/dist/web/mount-view.js.map +1 -0
  463. package/dist/web/proxy.js +0 -1
  464. package/dist/web/proxy.js.map +1 -1
  465. package/dist/web/types.d.ts +4 -133
  466. package/dist/web/types.js +0 -9
  467. package/dist/web/types.js.map +1 -1
  468. package/package.json +60 -30
  469. package/tsconfig.base.json +33 -0
  470. package/dist/server/devtoolsStaticServer.d.ts +0 -19
  471. package/dist/server/devtoolsStaticServer.js +0 -48
  472. package/dist/server/devtoolsStaticServer.js.map +0 -1
  473. package/dist/server/templates/development.hbs +0 -66
  474. package/dist/server/templates/production.hbs +0 -7
  475. package/dist/server/widgetsDevServer.d.ts +0 -12
  476. package/dist/server/widgetsDevServer.js +0 -47
  477. package/dist/server/widgetsDevServer.js.map +0 -1
  478. package/dist/test/widget.test.js +0 -173
  479. package/dist/test/widget.test.js.map +0 -1
  480. package/dist/web/bridges/adaptors/apps-sdk-adaptor.d.ts +0 -13
  481. package/dist/web/bridges/adaptors/apps-sdk-adaptor.js +0 -33
  482. package/dist/web/bridges/adaptors/apps-sdk-adaptor.js.map +0 -1
  483. package/dist/web/bridges/adaptors/mcp-app-adaptor.d.ts +0 -16
  484. package/dist/web/bridges/adaptors/mcp-app-adaptor.js +0 -115
  485. package/dist/web/bridges/adaptors/mcp-app-adaptor.js.map +0 -1
  486. package/dist/web/bridges/apps-sdk-bridge.d.ts +0 -10
  487. package/dist/web/bridges/apps-sdk-bridge.js.map +0 -1
  488. package/dist/web/bridges/hooks/use-adaptor.d.ts +0 -2
  489. package/dist/web/bridges/hooks/use-adaptor.js +0 -8
  490. package/dist/web/bridges/hooks/use-adaptor.js.map +0 -1
  491. package/dist/web/bridges/hooks/use-apps-sdk-bridge.d.ts +0 -2
  492. package/dist/web/bridges/hooks/use-apps-sdk-bridge.js +0 -7
  493. package/dist/web/bridges/hooks/use-apps-sdk-bridge.js.map +0 -1
  494. package/dist/web/bridges/hooks/use-bridge.d.ts +0 -2
  495. package/dist/web/bridges/hooks/use-bridge.js +0 -8
  496. package/dist/web/bridges/hooks/use-bridge.js.map +0 -1
  497. package/dist/web/bridges/hooks/use-mcp-app-bridge.d.ts +0 -5
  498. package/dist/web/bridges/hooks/use-mcp-app-bridge.js +0 -7
  499. package/dist/web/bridges/hooks/use-mcp-app-bridge.js.map +0 -1
  500. package/dist/web/bridges/hooks/use-mcp-app-bridge.test.js +0 -41
  501. package/dist/web/bridges/hooks/use-mcp-app-bridge.test.js.map +0 -1
  502. package/dist/web/bridges/mcp-app-bridge.d.ts +0 -38
  503. package/dist/web/bridges/mcp-app-bridge.js +0 -162
  504. package/dist/web/bridges/mcp-app-bridge.js.map +0 -1
  505. package/dist/web/hooks/use-openai-global.d.ts +0 -3
  506. package/dist/web/hooks/use-openai-global.js +0 -6
  507. package/dist/web/hooks/use-openai-global.js.map +0 -1
  508. package/dist/web/hooks/use-widget-state.d.ts +0 -4
  509. package/dist/web/hooks/use-widget-state.js +0 -32
  510. package/dist/web/hooks/use-widget-state.js.map +0 -1
  511. package/dist/web/hooks/use-widget-state.test.js +0 -61
  512. package/dist/web/hooks/use-widget-state.test.js.map +0 -1
  513. package/dist/web/mount-widget.d.ts +0 -1
  514. package/dist/web/mount-widget.js +0 -19
  515. package/dist/web/mount-widget.js.map +0 -1
  516. package/dist/web/plugin/data-llm.test.js +0 -81
  517. package/dist/web/plugin/data-llm.test.js.map +0 -1
  518. package/dist/web/plugin/plugin.d.ts +0 -2
  519. package/dist/web/plugin/plugin.js +0 -39
  520. package/dist/web/plugin/plugin.js.map +0 -1
  521. package/dist/web/plugin/transform-data-llm.d.ts +0 -12
  522. package/dist/web/plugin/transform-data-llm.js +0 -96
  523. package/dist/web/plugin/transform-data-llm.js.map +0 -1
  524. package/dist/web/plugin/transform-data-llm.test.js +0 -81
  525. package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
  526. /package/dist/{test/widget.test.d.ts → cli/build-helpers.test.d.ts} +0 -0
  527. /package/dist/{web/bridges/hooks/use-mcp-app-bridge.test.d.ts → cli/build-steps.test.d.ts} +0 -0
  528. /package/dist/{web/hooks/use-widget-state.test.d.ts → cli/tunnel-control-server.test.d.ts} +0 -0
  529. /package/dist/{web/plugin/data-llm.test.d.ts → cli/tunnel-handler.test.d.ts} +0 -0
  530. /package/dist/{web/plugin/transform-data-llm.test.d.ts → cli/tunnel.test.d.ts} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-view-state.js","sourceRoot":"","sources":["../../../src/web/hooks/use-view-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EACX,SAAS,EACT,MAAM,EACN,QAAQ,GACT,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AA8B3E,MAAM,UAAU,YAAY,CAC1B,YAA0C;IAE1C,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,mBAAmB,GAAG,cAAc,CAAC,WAAW,CAAa,CAAC;IAEpE,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAW,GAAG,EAAE;QACzD,IAAI,mBAAmB,KAAK,IAAI,EAAE,CAAC;YACjC,OAAO,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;QAChD,CAAC;QAED,OAAO,OAAO,YAAY,KAAK,UAAU;YACvC,CAAC,CAAC,YAAY,EAAE;YAChB,CAAC,CAAC,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,MAAM,eAAe,GAAG,MAAM,CAAuB,SAAS,CAAC,CAAC;IAEhE,SAAS,CAAC,GAAG,EAAE;QACb,eAAe,CAAC,OAAO,GAAG,SAAS,CAAC;QAEpC,OAAO,GAAG,EAAE;YACV,eAAe,CAAC,OAAO,GAAG,SAAS,CAAC;QACtC,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAEhB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,mBAAmB,KAAK,IAAI,EAAE,CAAC;YACjC,aAAa,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC,CAAC;QACxD,CAAC;IACH,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAE1B,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,KAA+B,EAAE,EAAE;QAClC,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC;QAE1C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QACxE,MAAM,UAAU,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAE/C,eAAe,CAAC,OAAO,GAAG,QAAQ,CAAC;QACnC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAExB,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,OAAO,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QACnC,CAAC;IACH,CAAC,EACD,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,OAAO,CAAC,SAAS,EAAE,YAAY,CAAU,CAAC;AAC5C,CAAC","sourcesContent":["import {\n type SetStateAction,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { getAdaptor, useHostContext } from \"../bridges/index.js\";\nimport { filterViewContext, injectViewContext } from \"../helpers/state.js\";\nimport type { UnknownObject } from \"../types.js\";\n\n/**\n * Persist a piece of UI state on the host, so it survives view remounts and\n * is restored on subsequent renders of the same tool invocation.\n *\n * Returns a `[state, setState]` pair with the same ergonomics as\n * `useState`. State is filtered to strip Skybridge-internal context fields\n * (see {@link DataLLM}) before being returned to your component.\n *\n * Provide a `defaultState` (value or lazy initializer) to get a non-nullable\n * tuple; omit it for `T | null`.\n *\n * @typeParam T - Shape of the persisted state. Must be a plain object.\n *\n * @example\n * ```tsx\n * const [filters, setFilters] = useViewState({ sort: \"newest\", page: 1 });\n * setFilters((f) => ({ ...f, page: f.page + 1 }));\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/use-view-state\n */\nexport function useViewState<T extends UnknownObject>(\n defaultState: T | (() => T),\n): readonly [T, (state: SetStateAction<T>) => void];\nexport function useViewState<T extends UnknownObject>(\n defaultState?: T | (() => T | null) | null,\n): readonly [T | null, (state: SetStateAction<T | null>) => void];\nexport function useViewState<T extends UnknownObject>(\n defaultState?: T | (() => T | null) | null,\n): readonly [T | null, (state: SetStateAction<T | null>) => void] {\n const adaptor = getAdaptor();\n const viewStateFromBridge = useHostContext(\"viewState\") as T | null;\n\n const [viewState, _setViewState] = useState<T | null>(() => {\n if (viewStateFromBridge !== null) {\n return filterViewContext(viewStateFromBridge);\n }\n\n return typeof defaultState === \"function\"\n ? defaultState()\n : (defaultState ?? null);\n });\n\n const mountedStateRef = useRef<T | null | undefined>(viewState);\n\n useEffect(() => {\n mountedStateRef.current = viewState;\n\n return () => {\n mountedStateRef.current = undefined;\n };\n }, [viewState]);\n\n useEffect(() => {\n if (viewStateFromBridge !== null) {\n _setViewState(filterViewContext(viewStateFromBridge));\n }\n }, [viewStateFromBridge]);\n\n const setViewState = useCallback(\n (state: SetStateAction<T | null>) => {\n const prevState = mountedStateRef.current;\n\n if (prevState === undefined) {\n return;\n }\n\n const newState = typeof state === \"function\" ? state(prevState) : state;\n const stateToSet = injectViewContext(newState);\n\n mountedStateRef.current = newState;\n _setViewState(newState);\n\n if (stateToSet !== null) {\n adaptor.setViewState(stateToSet);\n }\n },\n [adaptor],\n );\n\n return [viewState, setViewState] as const;\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,212 @@
1
+ import { act, renderHook, waitFor } from "@testing-library/react";
2
+ import { StrictMode } from "react";
3
+ import { afterEach, beforeEach, describe, expect, it, vi, } from "vitest";
4
+ import { HostAdaptor } from "../bridges/adaptor.js";
5
+ import { McpAppBridge } from "../bridges/mcp-app/index.js";
6
+ import { fireToolResultNotification, getMcpAppHostPostMessageMock, MockResizeObserver, } from "./test/utils.js";
7
+ import { useViewState } from "./use-view-state.js";
8
+ describe("useViewState", () => {
9
+ let OpenaiMock;
10
+ beforeEach(() => {
11
+ OpenaiMock = {
12
+ widgetState: null,
13
+ setWidgetState: vi.fn().mockResolvedValue(undefined),
14
+ };
15
+ vi.stubGlobal("openai", OpenaiMock);
16
+ vi.stubGlobal("skybridge", { hostType: "apps-sdk" });
17
+ });
18
+ afterEach(() => {
19
+ vi.unstubAllGlobals();
20
+ vi.resetAllMocks();
21
+ HostAdaptor.resetInstance();
22
+ McpAppBridge.resetInstance();
23
+ });
24
+ const defaultState = { count: 0, name: "test" };
25
+ const windowState = { count: 5, name: "window" };
26
+ it("should initialize with default state when window.openai.widgetState is null", () => {
27
+ OpenaiMock.widgetState = null;
28
+ const { result } = renderHook(() => useViewState(defaultState));
29
+ expect(result.current[0]).toEqual(defaultState);
30
+ });
31
+ it("should initialize with window.openai.widgetState when available", () => {
32
+ OpenaiMock.widgetState = { modelContent: windowState };
33
+ const { result } = renderHook(() => useViewState(defaultState));
34
+ expect(result.current[0]).toEqual(windowState);
35
+ });
36
+ it("should call window.openai.setWidgetState when setViewState is called with a new state", async () => {
37
+ const { result } = renderHook(() => useViewState(defaultState));
38
+ const newState = { count: 10, name: "updated" };
39
+ act(() => {
40
+ result.current[1](newState);
41
+ });
42
+ expect(OpenaiMock.setWidgetState).toHaveBeenCalledWith({
43
+ modelContent: newState,
44
+ privateContent: {},
45
+ });
46
+ expect(result.current[0]).toEqual(newState);
47
+ });
48
+ it("should call window.openai.setWidgetState when setViewState is called with a function updater", async () => {
49
+ const { result } = renderHook(() => useViewState(defaultState));
50
+ act(() => {
51
+ result.current[1]((prev) => ({ ...prev, count: prev.count + 1 }));
52
+ });
53
+ expect(OpenaiMock.setWidgetState).toHaveBeenCalledWith({
54
+ modelContent: { count: 1, name: "test" },
55
+ privateContent: {},
56
+ });
57
+ expect(result.current[0]).toEqual({ count: 1, name: "test" });
58
+ });
59
+ it("should call window.openai.setWidgetState once per update under StrictMode", () => {
60
+ const { result } = renderHook(() => useViewState(defaultState), {
61
+ wrapper: StrictMode,
62
+ });
63
+ act(() => {
64
+ result.current[1]({ count: 10, name: "updated" });
65
+ });
66
+ expect(OpenaiMock.setWidgetState).toHaveBeenCalledTimes(1);
67
+ });
68
+ it("should not persist anything on mount", () => {
69
+ renderHook(() => useViewState(defaultState), { wrapper: StrictMode });
70
+ expect(OpenaiMock.setWidgetState).not.toHaveBeenCalled();
71
+ });
72
+ it("should persist state when setViewState and unmount happen in the same tick", () => {
73
+ const { result, unmount } = renderHook(() => useViewState(defaultState));
74
+ act(() => {
75
+ result.current[1]({ count: 10, name: "updated" });
76
+ unmount();
77
+ });
78
+ expect(OpenaiMock.setWidgetState).toHaveBeenCalledTimes(1);
79
+ });
80
+ it("should not persist state when setViewState is called after unmount", () => {
81
+ const { result, unmount } = renderHook(() => useViewState(defaultState));
82
+ const setViewState = result.current[1];
83
+ unmount();
84
+ act(() => {
85
+ setViewState({ count: 10, name: "updated" });
86
+ });
87
+ expect(OpenaiMock.setWidgetState).not.toHaveBeenCalled();
88
+ });
89
+ it("should update state when window.openai.widgetState changes", () => {
90
+ OpenaiMock.widgetState = { modelContent: defaultState };
91
+ const { result, rerender } = renderHook(() => useViewState(defaultState));
92
+ expect(result.current[0]).toEqual(defaultState);
93
+ // Simulate window.openai.widgetState changing
94
+ OpenaiMock.widgetState = { modelContent: windowState };
95
+ // Trigger re-render to simulate the useEffect running
96
+ rerender();
97
+ expect(result.current[0]).toEqual(windowState);
98
+ });
99
+ });
100
+ describe("useViewState (mcp-app host — localStorage persistence)", () => {
101
+ beforeEach(() => {
102
+ vi.stubGlobal("parent", { postMessage: getMcpAppHostPostMessageMock() });
103
+ vi.stubGlobal("skybridge", { hostType: "mcp-app" });
104
+ vi.stubGlobal("openai", undefined);
105
+ vi.stubGlobal("ResizeObserver", MockResizeObserver);
106
+ localStorage.clear();
107
+ });
108
+ afterEach(() => {
109
+ vi.unstubAllGlobals();
110
+ vi.resetAllMocks();
111
+ HostAdaptor.resetInstance();
112
+ McpAppBridge.resetInstance();
113
+ localStorage.clear();
114
+ });
115
+ it("should persist state to localStorage when viewUUID is available", async () => {
116
+ const viewUUID = "test-uuid-123";
117
+ const { result } = renderHook(() => useViewState({ page: 1, zoom: 100 }));
118
+ await act(async () => {
119
+ fireToolResultNotification({
120
+ content: [{ type: "text", text: "result" }],
121
+ structuredContent: {},
122
+ _meta: { viewUUID },
123
+ });
124
+ });
125
+ act(() => {
126
+ result.current[1]({ page: 3, zoom: 150 });
127
+ });
128
+ expect(result.current[0]).toEqual({ page: 3, zoom: 150 });
129
+ expect(localStorage.length).toBe(1);
130
+ });
131
+ it("should restore state from localStorage when viewUUID arrives", async () => {
132
+ const viewUUID = "test-uuid-456";
133
+ // Pre-seed with the sb:{timestamp}:{viewUUID} format
134
+ localStorage.setItem(`sb:1700000000000:${viewUUID}`, JSON.stringify({ page: 5, zoom: 200 }));
135
+ const { result } = renderHook(() => useViewState({ page: 1, zoom: 100 }));
136
+ act(() => {
137
+ fireToolResultNotification({
138
+ content: [{ type: "text", text: "result" }],
139
+ structuredContent: {},
140
+ _meta: { viewUUID },
141
+ });
142
+ });
143
+ await waitFor(() => {
144
+ expect(result.current[0]).toEqual({ page: 5, zoom: 200 });
145
+ });
146
+ });
147
+ it("should not persist when no viewUUID is available", () => {
148
+ const { result } = renderHook(() => useViewState({ page: 1 }));
149
+ act(() => {
150
+ result.current[1]({ page: 2 });
151
+ });
152
+ expect(result.current[0]).toEqual({ page: 2 });
153
+ expect(localStorage.length).toBe(0);
154
+ });
155
+ it("should handle corrupted localStorage data gracefully", async () => {
156
+ const viewUUID = "test-uuid-corrupt";
157
+ localStorage.setItem(`sb:1700000000000:${viewUUID}`, "not valid json{{{");
158
+ const { result } = renderHook(() => useViewState({ page: 1 }));
159
+ act(() => {
160
+ fireToolResultNotification({
161
+ content: [{ type: "text", text: "result" }],
162
+ structuredContent: {},
163
+ _meta: { viewUUID },
164
+ });
165
+ });
166
+ await waitFor(() => {
167
+ expect(result.current[0]).toEqual({ page: 1 });
168
+ });
169
+ });
170
+ it("should refresh localStorage timestamp on each persist (LRU)", async () => {
171
+ const viewUUID = "lru-test-uuid";
172
+ const oldKey = `sb:1000000000000:${viewUUID}`;
173
+ localStorage.setItem(oldKey, JSON.stringify({ page: 1 }));
174
+ const { result } = renderHook(() => useViewState({ page: 1 }));
175
+ await act(async () => {
176
+ fireToolResultNotification({
177
+ content: [{ type: "text", text: "result" }],
178
+ structuredContent: {},
179
+ _meta: { viewUUID },
180
+ });
181
+ });
182
+ act(() => {
183
+ result.current[1]({ page: 2 });
184
+ });
185
+ // Old key removed, replaced with a new one (still just 1 entry)
186
+ expect(localStorage.getItem(oldKey)).toBeNull();
187
+ expect(localStorage.length).toBe(1);
188
+ });
189
+ it("should evict oldest entries when exceeding max storage entries", async () => {
190
+ // Fill localStorage with 200 entries (the max)
191
+ for (let i = 0; i < 200; i++) {
192
+ localStorage.setItem(`sb:${String(1000000000000 + i)}:old-uuid-${String(i).padStart(4, "0")}`, JSON.stringify({ i }));
193
+ }
194
+ expect(localStorage.length).toBe(200);
195
+ const viewUUID = "eviction-test-uuid";
196
+ const { result } = renderHook(() => useViewState({ page: 1 }));
197
+ await act(async () => {
198
+ fireToolResultNotification({
199
+ content: [{ type: "text", text: "result" }],
200
+ structuredContent: {},
201
+ _meta: { viewUUID },
202
+ });
203
+ });
204
+ act(() => {
205
+ result.current[1]({ page: 99 });
206
+ });
207
+ // Should have evicted the oldest entry to stay at 200
208
+ expect(localStorage.length).toBe(200);
209
+ expect(localStorage.getItem("sb:1000000000000:old-uuid-0000")).toBeNull();
210
+ });
211
+ });
212
+ //# sourceMappingURL=use-view-state.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-view-state.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-view-state.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { act, renderHook, waitFor } from \"@testing-library/react\";\nimport { StrictMode } from \"react\";\nimport {\n afterEach,\n beforeEach,\n describe,\n expect,\n it,\n type Mock,\n vi,\n} from \"vitest\";\nimport { HostAdaptor } from \"../bridges/adaptor.js\";\nimport { McpAppBridge } from \"../bridges/mcp-app/index.js\";\nimport {\n fireToolResultNotification,\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"./test/utils.js\";\nimport { useViewState } from \"./use-view-state.js\";\n\ndescribe(\"useViewState\", () => {\n let OpenaiMock: { widgetState: unknown; setWidgetState: Mock };\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 afterEach(() => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n });\n\n const defaultState = { count: 0, name: \"test\" };\n const windowState = { count: 5, name: \"window\" };\n\n it(\"should initialize with default state when window.openai.widgetState is null\", () => {\n OpenaiMock.widgetState = null;\n const { result } = renderHook(() => useViewState(defaultState));\n\n expect(result.current[0]).toEqual(defaultState);\n });\n\n it(\"should initialize with window.openai.widgetState when available\", () => {\n OpenaiMock.widgetState = { modelContent: windowState };\n const { result } = renderHook(() => useViewState(defaultState));\n\n expect(result.current[0]).toEqual(windowState);\n });\n\n it(\"should call window.openai.setWidgetState when setViewState is called with a new state\", async () => {\n const { result } = renderHook(() => useViewState(defaultState));\n const newState = { count: 10, name: \"updated\" };\n\n act(() => {\n result.current[1](newState);\n });\n\n expect(OpenaiMock.setWidgetState).toHaveBeenCalledWith({\n modelContent: newState,\n privateContent: {},\n });\n expect(result.current[0]).toEqual(newState);\n });\n\n it(\"should call window.openai.setWidgetState when setViewState is called with a function updater\", async () => {\n const { result } = renderHook(() => useViewState(defaultState));\n\n act(() => {\n result.current[1]((prev) => ({ ...prev, count: prev.count + 1 }));\n });\n\n expect(OpenaiMock.setWidgetState).toHaveBeenCalledWith({\n modelContent: { count: 1, name: \"test\" },\n privateContent: {},\n });\n expect(result.current[0]).toEqual({ count: 1, name: \"test\" });\n });\n\n it(\"should call window.openai.setWidgetState once per update under StrictMode\", () => {\n const { result } = renderHook(() => useViewState(defaultState), {\n wrapper: StrictMode,\n });\n\n act(() => {\n result.current[1]({ count: 10, name: \"updated\" });\n });\n\n expect(OpenaiMock.setWidgetState).toHaveBeenCalledTimes(1);\n });\n\n it(\"should not persist anything on mount\", () => {\n renderHook(() => useViewState(defaultState), { wrapper: StrictMode });\n\n expect(OpenaiMock.setWidgetState).not.toHaveBeenCalled();\n });\n\n it(\"should persist state when setViewState and unmount happen in the same tick\", () => {\n const { result, unmount } = renderHook(() => useViewState(defaultState));\n\n act(() => {\n result.current[1]({ count: 10, name: \"updated\" });\n unmount();\n });\n\n expect(OpenaiMock.setWidgetState).toHaveBeenCalledTimes(1);\n });\n\n it(\"should not persist state when setViewState is called after unmount\", () => {\n const { result, unmount } = renderHook(() => useViewState(defaultState));\n const setViewState = result.current[1];\n\n unmount();\n\n act(() => {\n setViewState({ count: 10, name: \"updated\" });\n });\n\n expect(OpenaiMock.setWidgetState).not.toHaveBeenCalled();\n });\n\n it(\"should update state when window.openai.widgetState changes\", () => {\n OpenaiMock.widgetState = { modelContent: defaultState };\n const { result, rerender } = renderHook(() => useViewState(defaultState));\n\n expect(result.current[0]).toEqual(defaultState);\n\n // Simulate window.openai.widgetState changing\n OpenaiMock.widgetState = { modelContent: windowState };\n // Trigger re-render to simulate the useEffect running\n rerender();\n\n expect(result.current[0]).toEqual(windowState);\n });\n});\n\ndescribe(\"useViewState (mcp-app host — localStorage persistence)\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"parent\", { postMessage: getMcpAppHostPostMessageMock() });\n vi.stubGlobal(\"skybridge\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"openai\", undefined);\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n localStorage.clear();\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n localStorage.clear();\n });\n\n it(\"should persist state to localStorage when viewUUID is available\", async () => {\n const viewUUID = \"test-uuid-123\";\n const { result } = renderHook(() => useViewState({ page: 1, zoom: 100 }));\n\n await act(async () => {\n fireToolResultNotification({\n content: [{ type: \"text\", text: \"result\" }],\n structuredContent: {},\n _meta: { viewUUID },\n });\n });\n\n act(() => {\n result.current[1]({ page: 3, zoom: 150 });\n });\n\n expect(result.current[0]).toEqual({ page: 3, zoom: 150 });\n expect(localStorage.length).toBe(1);\n });\n\n it(\"should restore state from localStorage when viewUUID arrives\", async () => {\n const viewUUID = \"test-uuid-456\";\n // Pre-seed with the sb:{timestamp}:{viewUUID} format\n localStorage.setItem(\n `sb:1700000000000:${viewUUID}`,\n JSON.stringify({ page: 5, zoom: 200 }),\n );\n\n const { result } = renderHook(() => useViewState({ page: 1, zoom: 100 }));\n\n act(() => {\n fireToolResultNotification({\n content: [{ type: \"text\", text: \"result\" }],\n structuredContent: {},\n _meta: { viewUUID },\n });\n });\n\n await waitFor(() => {\n expect(result.current[0]).toEqual({ page: 5, zoom: 200 });\n });\n });\n\n it(\"should not persist when no viewUUID is available\", () => {\n const { result } = renderHook(() => useViewState({ page: 1 }));\n\n act(() => {\n result.current[1]({ page: 2 });\n });\n\n expect(result.current[0]).toEqual({ page: 2 });\n expect(localStorage.length).toBe(0);\n });\n\n it(\"should handle corrupted localStorage data gracefully\", async () => {\n const viewUUID = \"test-uuid-corrupt\";\n localStorage.setItem(`sb:1700000000000:${viewUUID}`, \"not valid json{{{\");\n\n const { result } = renderHook(() => useViewState({ page: 1 }));\n\n act(() => {\n fireToolResultNotification({\n content: [{ type: \"text\", text: \"result\" }],\n structuredContent: {},\n _meta: { viewUUID },\n });\n });\n\n await waitFor(() => {\n expect(result.current[0]).toEqual({ page: 1 });\n });\n });\n\n it(\"should refresh localStorage timestamp on each persist (LRU)\", async () => {\n const viewUUID = \"lru-test-uuid\";\n const oldKey = `sb:1000000000000:${viewUUID}`;\n localStorage.setItem(oldKey, JSON.stringify({ page: 1 }));\n\n const { result } = renderHook(() => useViewState({ page: 1 }));\n\n await act(async () => {\n fireToolResultNotification({\n content: [{ type: \"text\", text: \"result\" }],\n structuredContent: {},\n _meta: { viewUUID },\n });\n });\n\n act(() => {\n result.current[1]({ page: 2 });\n });\n\n // Old key removed, replaced with a new one (still just 1 entry)\n expect(localStorage.getItem(oldKey)).toBeNull();\n expect(localStorage.length).toBe(1);\n });\n\n it(\"should evict oldest entries when exceeding max storage entries\", async () => {\n // Fill localStorage with 200 entries (the max)\n for (let i = 0; i < 200; i++) {\n localStorage.setItem(\n `sb:${String(1000000000000 + i)}:old-uuid-${String(i).padStart(4, \"0\")}`,\n JSON.stringify({ i }),\n );\n }\n expect(localStorage.length).toBe(200);\n\n const viewUUID = \"eviction-test-uuid\";\n const { result } = renderHook(() => useViewState({ page: 1 }));\n\n await act(async () => {\n fireToolResultNotification({\n content: [{ type: \"text\", text: \"result\" }],\n structuredContent: {},\n _meta: { viewUUID },\n });\n });\n\n act(() => {\n result.current[1]({ page: 99 });\n });\n\n // Should have evicted the oldest entry to stay at 200\n expect(localStorage.length).toBe(200);\n expect(localStorage.getItem(\"sb:1000000000000:old-uuid-0000\")).toBeNull();\n });\n});\n"]}
@@ -3,6 +3,5 @@ export { createStore } from "./create-store.js";
3
3
  export * from "./data-llm.js";
4
4
  export { generateHelpers } from "./generate-helpers.js";
5
5
  export * from "./hooks/index.js";
6
- export { mountWidget } from "./mount-widget.js";
7
- export { skybridge } from "./plugin/plugin.js";
6
+ export { mountView } from "./mount-view.js";
8
7
  export * from "./types.js";
package/dist/web/index.js CHANGED
@@ -3,7 +3,6 @@ export { createStore } from "./create-store.js";
3
3
  export * from "./data-llm.js";
4
4
  export { generateHelpers } from "./generate-helpers.js";
5
5
  export * from "./hooks/index.js";
6
- export { mountWidget } from "./mount-widget.js";
7
- export { skybridge } from "./plugin/plugin.js";
6
+ export { mountView } from "./mount-view.js";
8
7
  export * from "./types.js";
9
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/web/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/web/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,cAAc,YAAY,CAAC","sourcesContent":["export * from \"./bridges/index.js\";\nexport { createStore } from \"./create-store.js\";\nexport * from \"./data-llm.js\";\nexport { generateHelpers } from \"./generate-helpers.js\";\nexport * from \"./hooks/index.js\";\nexport { mountView } from \"./mount-view.js\";\nexport * from \"./types.js\";\n"]}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Mount a view's root React component into `#root`. Each view file's entry
3
+ * point should call this exactly once.
4
+ *
5
+ * Wraps the component in `StrictMode`, applies host-specific providers
6
+ * automatically (e.g. modal support for MCP Apps), and installs the dev-mode
7
+ * logging proxy for `window.openai` calls.
8
+ *
9
+ * @param component - Your root React element (already constructed, e.g. `<App />`).
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * // src/views/search.tsx
14
+ * import { mountView } from "skybridge/web";
15
+ * import { App } from "./App";
16
+ *
17
+ * mountView(<App />);
18
+ * ```
19
+ */
20
+ export declare const mountView: (component: React.ReactNode) => void;
@@ -0,0 +1,46 @@
1
+ /// <reference types="vite/client" />
2
+ import { createElement, StrictMode } from "react";
3
+ import { createRoot } from "react-dom/client";
4
+ import { installOpenAILoggingProxy } from "./proxy.js";
5
+ let rootInstance = null;
6
+ /**
7
+ * Mount a view's root React component into `#root`. Each view file's entry
8
+ * point should call this exactly once.
9
+ *
10
+ * Wraps the component in `StrictMode`, applies host-specific providers
11
+ * automatically (e.g. modal support for MCP Apps), and installs the dev-mode
12
+ * logging proxy for `window.openai` calls.
13
+ *
14
+ * @param component - Your root React element (already constructed, e.g. `<App />`).
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * // src/views/search.tsx
19
+ * import { mountView } from "skybridge/web";
20
+ * import { App } from "./App";
21
+ *
22
+ * mountView(<App />);
23
+ * ```
24
+ */
25
+ export const mountView = (component) => {
26
+ const rootElement = document.getElementById("root");
27
+ if (!rootElement) {
28
+ throw new Error("Root element not found");
29
+ }
30
+ if (!rootInstance) {
31
+ rootInstance = createRoot(rootElement);
32
+ }
33
+ if (import.meta.env.DEV) {
34
+ installOpenAILoggingProxy();
35
+ }
36
+ const hostType = window.skybridge?.hostType;
37
+ (async () => {
38
+ let app = component;
39
+ if (hostType === "mcp-app") {
40
+ const { ModalProvider } = await import("./components/modal-provider.js");
41
+ app = createElement(ModalProvider, null, component);
42
+ }
43
+ rootInstance.render(createElement(StrictMode, null, app));
44
+ })();
45
+ };
46
+ //# sourceMappingURL=mount-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-view.js","sourceRoot":"","sources":["../../src/web/mount-view.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAErC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAClD,OAAO,EAAE,UAAU,EAAa,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAEvD,IAAI,YAAY,GAAgB,IAAI,CAAC;AAErC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,SAA0B,EAAE,EAAE;IACtD,MAAM,WAAW,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;IACpD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QACxB,yBAAyB,EAAE,CAAC;IAC9B,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC;IAE5C,CAAC,KAAK,IAAI,EAAE;QACV,IAAI,GAAG,GAAG,SAAS,CAAC;QACpB,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,gCAAgC,CAAC,CAAC;YACzE,GAAG,GAAG,aAAa,CAAC,aAAa,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;QACtD,CAAC;QACD,YAAY,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;IAC5D,CAAC,CAAC,EAAE,CAAC;AACP,CAAC,CAAC","sourcesContent":["/// <reference types=\"vite/client\" />\n\nimport { createElement, StrictMode } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { installOpenAILoggingProxy } from \"./proxy.js\";\n\nlet rootInstance: Root | null = null;\n\n/**\n * Mount a view's root React component into `#root`. Each view file's entry\n * point should call this exactly once.\n *\n * Wraps the component in `StrictMode`, applies host-specific providers\n * automatically (e.g. modal support for MCP Apps), and installs the dev-mode\n * logging proxy for `window.openai` calls.\n *\n * @param component - Your root React element (already constructed, e.g. `<App />`).\n *\n * @example\n * ```tsx\n * // src/views/search.tsx\n * import { mountView } from \"skybridge/web\";\n * import { App } from \"./App\";\n *\n * mountView(<App />);\n * ```\n */\nexport const mountView = (component: React.ReactNode) => {\n const rootElement = document.getElementById(\"root\");\n if (!rootElement) {\n throw new Error(\"Root element not found\");\n }\n\n if (!rootInstance) {\n rootInstance = createRoot(rootElement);\n }\n\n if (import.meta.env.DEV) {\n installOpenAILoggingProxy();\n }\n\n const hostType = window.skybridge?.hostType;\n\n (async () => {\n let app = component;\n if (hostType === \"mcp-app\") {\n const { ModalProvider } = await import(\"./components/modal-provider.js\");\n app = createElement(ModalProvider, null, component);\n }\n rootInstance.render(createElement(StrictMode, null, app));\n })();\n};\n"]}
package/dist/web/proxy.js CHANGED
@@ -6,7 +6,6 @@ const colors = {
6
6
  };
7
7
  export function installOpenAILoggingProxy() {
8
8
  if (typeof window === "undefined" || !window.openai) {
9
- console.warn("[openai-proxy] window.openai not found, skipping proxy installation");
10
9
  return;
11
10
  }
12
11
  const descriptor = Object.getOwnPropertyDescriptor(window, "openai");
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/web/proxy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/web/proxy.ts"],"names":[],"mappings":"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","sourcesContent":["const colors = {\n brand: \"#6366f1\",\n info: \"#22223b\",\n success: \"#22c55e\",\n error: \"#ef4444\",\n} as const;\n\nexport function installOpenAILoggingProxy() {\n if (typeof window === \"undefined\" || !window.openai) {\n return;\n }\n\n const descriptor = Object.getOwnPropertyDescriptor(window, \"openai\");\n if (descriptor?.configurable === false || descriptor?.writable === false) {\n console.warn(\n \"[openai-proxy] window.openai is not configurable or writable, skipping proxy installation\",\n );\n return;\n }\n\n const originalOpenAI = window.openai;\n\n const handler: ProxyHandler<typeof originalOpenAI> = {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n\n if (typeof value !== \"function\") {\n return value;\n }\n\n return (...args: unknown[]) => {\n const methodName = String(prop);\n\n console.group(\n `%c[openai] %cmethod %c${methodName}`,\n `color: ${colors.brand}; font-weight: normal`,\n `color: ${colors.info}; font-weight: normal`,\n `color: ${colors.success}`,\n );\n console.log(\"%c← args:\", `color: ${colors.info}`, args);\n\n const result = value.apply(target, args);\n\n if (result && typeof result.then === \"function\") {\n return result.then(\n (resolved: unknown) => {\n console.log(\n \"%c→ resolved:\",\n `color: ${colors.success}`,\n resolved,\n );\n console.groupEnd();\n return resolved;\n },\n (error: unknown) => {\n console.error(\"%c→ rejected:\", `color: ${colors.error}`, error);\n console.groupEnd();\n throw error;\n },\n );\n }\n\n console.log(\"%c→ returned:\", `color: ${colors.success}`, result);\n console.groupEnd();\n\n return result;\n };\n },\n\n set(target, prop, value, receiver) {\n console.log(\n `%c[openai] %cupdate %c${String(prop)}`,\n `color: ${colors.brand}`,\n `color: ${colors.info}`,\n `color: ${colors.success}; font-weight: bold`,\n \"←\",\n value,\n );\n\n return Reflect.set(target, prop, value, receiver);\n },\n };\n\n window.openai = new Proxy(originalOpenAI, handler);\n\n console.log(\n \"%c[openai-proxy] %cInstalled logging proxy for window.openai\",\n `color: ${colors.brand}`,\n `color: ${colors.info}`,\n );\n}\n"]}
@@ -1,149 +1,20 @@
1
1
  import "react";
2
- import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
- import type { WidgetHostType } from "../server/index.js";
4
2
  declare module "react" {
5
3
  interface HTMLAttributes<T> {
6
4
  "data-llm"?: string;
7
5
  }
8
6
  }
7
+ /** Shorthand for an arbitrary plain object — `Record<string, unknown>`. */
9
8
  export type UnknownObject = Record<string, unknown>;
9
+ /** Flatten an intersection so it appears as a single object type in hovers and error messages. */
10
10
  export type Prettify<T> = {
11
11
  [K in keyof T]: T[K];
12
12
  } & {};
13
+ /** Widen `T` to also satisfy {@link UnknownObject}, useful for tool input/output narrowing. */
13
14
  export type Objectify<T> = T & UnknownObject;
14
15
  type RequiredKeys<T> = {
15
16
  [K in keyof T]-?: Record<string, never> extends Pick<T, K> ? never : K;
16
17
  }[keyof T];
18
+ /** `true` if `T` has at least one required key, `false` if every key is optional. */
17
19
  export type HasRequiredKeys<T> = RequiredKeys<T> extends never ? false : true;
18
- type WidgetState = UnknownObject;
19
- type FileMetadata = {
20
- fileId: string;
21
- };
22
- export declare const TOOL_RESPONSE_EVENT_TYPE = "openai:tool_response";
23
- export declare class ToolResponseEvent extends CustomEvent<{
24
- tool: {
25
- name: string;
26
- args: UnknownObject;
27
- };
28
- }> {
29
- readonly type = "openai:tool_response";
30
- }
31
- declare global {
32
- interface Window {
33
- skybridge: SkybridgeProperties;
34
- openai: OpenAiMethods<WidgetState> & OpenAiProperties;
35
- }
36
- interface WindowEventMap {
37
- [SET_GLOBALS_EVENT_TYPE]: SetGlobalsEvent;
38
- }
39
- }
40
- export type SkybridgeProperties = {
41
- hostType: WidgetHostType;
42
- };
43
- export type OpenAiProperties<ToolInput extends UnknownObject = Record<never, unknown>, ToolOutput extends UnknownObject = UnknownObject, ToolResponseMetadata extends UnknownObject = UnknownObject, WidgetState extends UnknownObject = UnknownObject> = {
44
- theme: Theme;
45
- userAgent: UserAgent;
46
- locale: string;
47
- maxHeight: number;
48
- displayMode: DisplayMode;
49
- safeArea: SafeArea;
50
- view: View;
51
- toolInput: ToolInput;
52
- toolOutput: ToolOutput | {
53
- text: string;
54
- } | null;
55
- toolResponseMetadata: ToolResponseMetadata | null;
56
- widgetState: WidgetState | null;
57
- };
58
- export type CallToolArgs = Record<string, unknown> | null;
59
- export type CallToolResponse = {
60
- content: CallToolResult["content"];
61
- structuredContent: Record<string, unknown>;
62
- isError: boolean;
63
- result: string;
64
- _meta?: CallToolResult["_meta"];
65
- };
66
- export type RequestModalOptions = {
67
- title?: string;
68
- params?: Record<string, unknown>;
69
- anchor?: {
70
- top?: number;
71
- left?: number;
72
- width?: number;
73
- height?: number;
74
- };
75
- };
76
- export type OpenAiMethods<WidgetState extends UnknownObject = UnknownObject> = {
77
- /** Calls a tool on your MCP. Returns the full response. */
78
- callTool: <ToolArgs extends CallToolArgs = null, ToolResponse extends CallToolResponse = CallToolResponse>(name: string, args: ToolArgs) => Promise<ToolResponse>;
79
- /** Triggers a followup turn in the ChatGPT conversation */
80
- sendFollowUpMessage: (args: {
81
- prompt: string;
82
- }) => Promise<void>;
83
- /** Opens an external link, redirects web page or mobile app */
84
- openExternal(args: {
85
- href: string;
86
- }): void;
87
- /** For transitioning an app from inline to fullscreen or pip */
88
- requestDisplayMode: (args: {
89
- mode: DisplayMode;
90
- }) => Promise<{
91
- /**
92
- * The granted display mode. The host may reject the request.
93
- * For mobile, PiP is always coerced to fullscreen.
94
- */
95
- mode: DisplayMode;
96
- }>;
97
- /**
98
- * Sets the widget state.
99
- * This state is persisted across widget renders.
100
- */
101
- setWidgetState: (state: WidgetState) => Promise<void>;
102
- /**
103
- * Opens a modal portaled outside of the widget iFrame.
104
- * This ensures the modal is correctly displayed and not limited to the widget's area.
105
- */
106
- requestModal: (args: RequestModalOptions) => Promise<void>;
107
- /** Uploads a new file to the host */
108
- uploadFile: (file: File) => Promise<FileMetadata>;
109
- /**
110
- * Downloads a file from the host that was previously uploaded.
111
- * Only files uploaded by the same connector instance can be downloaded.
112
- */
113
- downloadFile: (file: FileMetadata) => Promise<{
114
- downloadUrl: string;
115
- }>;
116
- };
117
- export declare const SET_GLOBALS_EVENT_TYPE = "openai:set_globals";
118
- export declare class SetGlobalsEvent extends CustomEvent<{
119
- globals: Partial<OpenAiProperties>;
120
- }> {
121
- readonly type = "openai:set_globals";
122
- }
123
- export type CallTool = (name: string, args: Record<string, unknown>) => Promise<CallToolResponse>;
124
- export type DisplayMode = "pip" | "inline" | "fullscreen" | "modal";
125
- export type View = {
126
- mode: DisplayMode;
127
- params?: Record<string, unknown>;
128
- };
129
- export type Theme = "light" | "dark";
130
- export type SafeAreaInsets = {
131
- top: number;
132
- bottom: number;
133
- left: number;
134
- right: number;
135
- };
136
- export type SafeArea = {
137
- insets: SafeAreaInsets;
138
- };
139
- export type DeviceType = "mobile" | "tablet" | "desktop" | "unknown";
140
- export type UserAgent = {
141
- device: {
142
- type: DeviceType;
143
- };
144
- capabilities: {
145
- hover: boolean;
146
- touch: boolean;
147
- };
148
- };
149
20
  export {};
package/dist/web/types.js CHANGED
@@ -1,11 +1,2 @@
1
1
  import "react";
2
- export const TOOL_RESPONSE_EVENT_TYPE = "openai:tool_response";
3
- export class ToolResponseEvent extends CustomEvent {
4
- type = TOOL_RESPONSE_EVENT_TYPE;
5
- }
6
- // Dispatched when any global changes in the host page
7
- export const SET_GLOBALS_EVENT_TYPE = "openai:set_globals";
8
- export class SetGlobalsEvent extends CustomEvent {
9
- type = SET_GLOBALS_EVENT_TYPE;
10
- }
11
2
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/web/types.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,CAAC;AAyBf,MAAM,CAAC,MAAM,wBAAwB,GAAG,sBAAsB,CAAC;AAC/D,MAAM,OAAO,iBAAkB,SAAQ,WAErC;IACkB,IAAI,GAAG,wBAAwB,CAAC;CACnD;AAuGD,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/types.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,CAAC","sourcesContent":["import \"react\";\n\ndeclare module \"react\" {\n interface HTMLAttributes<T> {\n \"data-llm\"?: string;\n }\n}\n\n/** Shorthand for an arbitrary plain object — `Record<string, unknown>`. */\nexport type UnknownObject = Record<string, unknown>;\n\n/** Flatten an intersection so it appears as a single object type in hovers and error messages. */\nexport type Prettify<T> = { [K in keyof T]: T[K] } & {};\n/** Widen `T` to also satisfy {@link UnknownObject}, useful for tool input/output narrowing. */\nexport type Objectify<T> = T & UnknownObject;\n\ntype RequiredKeys<T> = {\n [K in keyof T]-?: Record<string, never> extends Pick<T, K> ? never : K;\n}[keyof T];\n/** `true` if `T` has at least one required key, `false` if every key is optional. */\nexport type HasRequiredKeys<T> = RequiredKeys<T> extends never ? false : true;\n"]}