@frontmcp/ui 0.6.1 → 0.6.2

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 (292) hide show
  1. package/bridge/core/bridge-factory.d.ts +1 -0
  2. package/bridge/core/bridge-factory.d.ts.map +1 -1
  3. package/bridge/index.d.ts +1 -1
  4. package/bridge/index.d.ts.map +1 -1
  5. package/bridge/index.js +39 -881
  6. package/bundler/browser-components.d.ts +42 -0
  7. package/bundler/browser-components.d.ts.map +1 -0
  8. package/bundler/bundler.d.ts +78 -4
  9. package/bundler/bundler.d.ts.map +1 -1
  10. package/bundler/index.d.ts +8 -8
  11. package/bundler/index.d.ts.map +1 -1
  12. package/bundler/index.js +1315 -1854
  13. package/bundler/types.d.ts +188 -7
  14. package/bundler/types.d.ts.map +1 -1
  15. package/esm/bridge/{index.js → index.mjs} +40 -877
  16. package/esm/bundler/{index.js → index.mjs} +1391 -1895
  17. package/esm/{index.js → index.mjs} +215 -3091
  18. package/esm/layouts/{index.js → index.mjs} +3 -3
  19. package/esm/package.json +9 -8
  20. package/esm/react/index.mjs +1183 -0
  21. package/esm/renderers/index.mjs +611 -0
  22. package/esm/universal/{index.js → index.mjs} +266 -70
  23. package/index.d.ts +1 -4
  24. package/index.d.ts.map +1 -1
  25. package/index.js +208 -3113
  26. package/layouts/base.d.ts.map +1 -1
  27. package/layouts/index.js +3 -3
  28. package/layouts/presets.d.ts.map +1 -1
  29. package/package.json +9 -8
  30. package/react/Badge.d.ts.map +1 -1
  31. package/react/hooks/context.d.ts.map +1 -1
  32. package/react/index.d.ts +0 -1
  33. package/react/index.d.ts.map +1 -1
  34. package/react/index.js +57 -2001
  35. package/react/types.d.ts.map +1 -1
  36. package/renderers/index.d.ts +9 -4
  37. package/renderers/index.d.ts.map +1 -1
  38. package/renderers/index.js +328 -88
  39. package/renderers/mdx.renderer.d.ts +99 -0
  40. package/renderers/mdx.renderer.d.ts.map +1 -0
  41. package/renderers/react.renderer.d.ts +22 -13
  42. package/renderers/react.renderer.d.ts.map +1 -1
  43. package/renderers/transpiler.d.ts +49 -0
  44. package/renderers/transpiler.d.ts.map +1 -0
  45. package/universal/cached-runtime.d.ts +25 -1
  46. package/universal/cached-runtime.d.ts.map +1 -1
  47. package/universal/index.js +266 -70
  48. package/universal/runtime-builder.d.ts.map +1 -1
  49. package/universal/types.d.ts.map +1 -1
  50. package/web-components/elements/fmcp-input.d.ts.map +1 -1
  51. package/web-components/elements/fmcp-select.d.ts.map +1 -1
  52. package/web-components/index.d.ts +0 -1
  53. package/web-components/index.d.ts.map +1 -1
  54. package/bundler/cache.d.ts +0 -173
  55. package/bundler/cache.d.ts.map +0 -1
  56. package/bundler/file-cache/component-builder.d.ts +0 -167
  57. package/bundler/file-cache/component-builder.d.ts.map +0 -1
  58. package/bundler/file-cache/hash-calculator.d.ts +0 -155
  59. package/bundler/file-cache/hash-calculator.d.ts.map +0 -1
  60. package/bundler/file-cache/index.d.ts +0 -12
  61. package/bundler/file-cache/index.d.ts.map +0 -1
  62. package/bundler/file-cache/storage/filesystem.d.ts +0 -149
  63. package/bundler/file-cache/storage/filesystem.d.ts.map +0 -1
  64. package/bundler/file-cache/storage/index.d.ts +0 -11
  65. package/bundler/file-cache/storage/index.d.ts.map +0 -1
  66. package/bundler/file-cache/storage/interface.d.ts +0 -152
  67. package/bundler/file-cache/storage/interface.d.ts.map +0 -1
  68. package/bundler/file-cache/storage/redis.d.ts +0 -139
  69. package/bundler/file-cache/storage/redis.d.ts.map +0 -1
  70. package/bundler/sandbox/enclave-adapter.d.ts +0 -121
  71. package/bundler/sandbox/enclave-adapter.d.ts.map +0 -1
  72. package/bundler/sandbox/executor.d.ts +0 -14
  73. package/bundler/sandbox/executor.d.ts.map +0 -1
  74. package/bundler/sandbox/policy.d.ts +0 -62
  75. package/bundler/sandbox/policy.d.ts.map +0 -1
  76. package/esm/bridge/adapters/base-adapter.d.ts +0 -104
  77. package/esm/bridge/adapters/base-adapter.d.ts.map +0 -1
  78. package/esm/bridge/adapters/claude.adapter.d.ts +0 -67
  79. package/esm/bridge/adapters/claude.adapter.d.ts.map +0 -1
  80. package/esm/bridge/adapters/ext-apps.adapter.d.ts +0 -143
  81. package/esm/bridge/adapters/ext-apps.adapter.d.ts.map +0 -1
  82. package/esm/bridge/adapters/gemini.adapter.d.ts +0 -64
  83. package/esm/bridge/adapters/gemini.adapter.d.ts.map +0 -1
  84. package/esm/bridge/adapters/generic.adapter.d.ts +0 -56
  85. package/esm/bridge/adapters/generic.adapter.d.ts.map +0 -1
  86. package/esm/bridge/adapters/index.d.ts +0 -26
  87. package/esm/bridge/adapters/index.d.ts.map +0 -1
  88. package/esm/bridge/adapters/openai.adapter.d.ts +0 -65
  89. package/esm/bridge/adapters/openai.adapter.d.ts.map +0 -1
  90. package/esm/bridge/core/adapter-registry.d.ts +0 -122
  91. package/esm/bridge/core/adapter-registry.d.ts.map +0 -1
  92. package/esm/bridge/core/bridge-factory.d.ts +0 -199
  93. package/esm/bridge/core/bridge-factory.d.ts.map +0 -1
  94. package/esm/bridge/core/index.d.ts +0 -10
  95. package/esm/bridge/core/index.d.ts.map +0 -1
  96. package/esm/bridge/index.d.ts +0 -62
  97. package/esm/bridge/index.d.ts.map +0 -1
  98. package/esm/bridge/runtime/iife-generator.d.ts +0 -62
  99. package/esm/bridge/runtime/iife-generator.d.ts.map +0 -1
  100. package/esm/bridge/runtime/index.d.ts +0 -10
  101. package/esm/bridge/runtime/index.d.ts.map +0 -1
  102. package/esm/bridge/types.d.ts +0 -386
  103. package/esm/bridge/types.d.ts.map +0 -1
  104. package/esm/bundler/bundler.d.ts +0 -208
  105. package/esm/bundler/bundler.d.ts.map +0 -1
  106. package/esm/bundler/cache.d.ts +0 -173
  107. package/esm/bundler/cache.d.ts.map +0 -1
  108. package/esm/bundler/file-cache/component-builder.d.ts +0 -167
  109. package/esm/bundler/file-cache/component-builder.d.ts.map +0 -1
  110. package/esm/bundler/file-cache/hash-calculator.d.ts +0 -155
  111. package/esm/bundler/file-cache/hash-calculator.d.ts.map +0 -1
  112. package/esm/bundler/file-cache/index.d.ts +0 -12
  113. package/esm/bundler/file-cache/index.d.ts.map +0 -1
  114. package/esm/bundler/file-cache/storage/filesystem.d.ts +0 -149
  115. package/esm/bundler/file-cache/storage/filesystem.d.ts.map +0 -1
  116. package/esm/bundler/file-cache/storage/index.d.ts +0 -11
  117. package/esm/bundler/file-cache/storage/index.d.ts.map +0 -1
  118. package/esm/bundler/file-cache/storage/interface.d.ts +0 -152
  119. package/esm/bundler/file-cache/storage/interface.d.ts.map +0 -1
  120. package/esm/bundler/file-cache/storage/redis.d.ts +0 -139
  121. package/esm/bundler/file-cache/storage/redis.d.ts.map +0 -1
  122. package/esm/bundler/index.d.ts +0 -43
  123. package/esm/bundler/index.d.ts.map +0 -1
  124. package/esm/bundler/sandbox/enclave-adapter.d.ts +0 -121
  125. package/esm/bundler/sandbox/enclave-adapter.d.ts.map +0 -1
  126. package/esm/bundler/sandbox/executor.d.ts +0 -14
  127. package/esm/bundler/sandbox/executor.d.ts.map +0 -1
  128. package/esm/bundler/sandbox/policy.d.ts +0 -62
  129. package/esm/bundler/sandbox/policy.d.ts.map +0 -1
  130. package/esm/bundler/types.d.ts +0 -702
  131. package/esm/bundler/types.d.ts.map +0 -1
  132. package/esm/components/alert.d.ts +0 -66
  133. package/esm/components/alert.d.ts.map +0 -1
  134. package/esm/components/alert.schema.d.ts +0 -98
  135. package/esm/components/alert.schema.d.ts.map +0 -1
  136. package/esm/components/avatar.d.ts +0 -77
  137. package/esm/components/avatar.d.ts.map +0 -1
  138. package/esm/components/avatar.schema.d.ts +0 -170
  139. package/esm/components/avatar.schema.d.ts.map +0 -1
  140. package/esm/components/badge.d.ts +0 -64
  141. package/esm/components/badge.d.ts.map +0 -1
  142. package/esm/components/badge.schema.d.ts +0 -91
  143. package/esm/components/badge.schema.d.ts.map +0 -1
  144. package/esm/components/button.d.ts +0 -100
  145. package/esm/components/button.d.ts.map +0 -1
  146. package/esm/components/button.schema.d.ts +0 -120
  147. package/esm/components/button.schema.d.ts.map +0 -1
  148. package/esm/components/card.d.ts +0 -53
  149. package/esm/components/card.d.ts.map +0 -1
  150. package/esm/components/card.schema.d.ts +0 -93
  151. package/esm/components/card.schema.d.ts.map +0 -1
  152. package/esm/components/form.d.ts +0 -212
  153. package/esm/components/form.d.ts.map +0 -1
  154. package/esm/components/form.schema.d.ts +0 -365
  155. package/esm/components/form.schema.d.ts.map +0 -1
  156. package/esm/components/index.d.ts +0 -29
  157. package/esm/components/index.d.ts.map +0 -1
  158. package/esm/components/list.d.ts +0 -121
  159. package/esm/components/list.d.ts.map +0 -1
  160. package/esm/components/list.schema.d.ts +0 -129
  161. package/esm/components/list.schema.d.ts.map +0 -1
  162. package/esm/components/modal.d.ts +0 -100
  163. package/esm/components/modal.d.ts.map +0 -1
  164. package/esm/components/modal.schema.d.ts +0 -151
  165. package/esm/components/modal.schema.d.ts.map +0 -1
  166. package/esm/components/table.d.ts +0 -91
  167. package/esm/components/table.d.ts.map +0 -1
  168. package/esm/components/table.schema.d.ts +0 -123
  169. package/esm/components/table.schema.d.ts.map +0 -1
  170. package/esm/index.d.ts +0 -40
  171. package/esm/index.d.ts.map +0 -1
  172. package/esm/layouts/base.d.ts +0 -86
  173. package/esm/layouts/base.d.ts.map +0 -1
  174. package/esm/layouts/index.d.ts +0 -8
  175. package/esm/layouts/index.d.ts.map +0 -1
  176. package/esm/layouts/presets.d.ts +0 -134
  177. package/esm/layouts/presets.d.ts.map +0 -1
  178. package/esm/pages/consent.d.ts +0 -117
  179. package/esm/pages/consent.d.ts.map +0 -1
  180. package/esm/pages/error.d.ts +0 -101
  181. package/esm/pages/error.d.ts.map +0 -1
  182. package/esm/pages/index.d.ts +0 -9
  183. package/esm/pages/index.d.ts.map +0 -1
  184. package/esm/pages/index.js +0 -1036
  185. package/esm/react/Alert.d.ts +0 -101
  186. package/esm/react/Alert.d.ts.map +0 -1
  187. package/esm/react/Badge.d.ts +0 -100
  188. package/esm/react/Badge.d.ts.map +0 -1
  189. package/esm/react/Button.d.ts +0 -108
  190. package/esm/react/Button.d.ts.map +0 -1
  191. package/esm/react/Card.d.ts +0 -103
  192. package/esm/react/Card.d.ts.map +0 -1
  193. package/esm/react/hooks/context.d.ts +0 -179
  194. package/esm/react/hooks/context.d.ts.map +0 -1
  195. package/esm/react/hooks/index.d.ts +0 -42
  196. package/esm/react/hooks/index.d.ts.map +0 -1
  197. package/esm/react/hooks/tools.d.ts +0 -284
  198. package/esm/react/hooks/tools.d.ts.map +0 -1
  199. package/esm/react/index.d.ts +0 -80
  200. package/esm/react/index.d.ts.map +0 -1
  201. package/esm/react/index.js +0 -3124
  202. package/esm/react/types.d.ts +0 -105
  203. package/esm/react/types.d.ts.map +0 -1
  204. package/esm/react/utils.d.ts +0 -43
  205. package/esm/react/utils.d.ts.map +0 -1
  206. package/esm/render/index.d.ts +0 -8
  207. package/esm/render/index.d.ts.map +0 -1
  208. package/esm/render/prerender.d.ts +0 -57
  209. package/esm/render/prerender.d.ts.map +0 -1
  210. package/esm/renderers/index.d.ts +0 -21
  211. package/esm/renderers/index.d.ts.map +0 -1
  212. package/esm/renderers/index.js +0 -381
  213. package/esm/renderers/react.adapter.d.ts +0 -70
  214. package/esm/renderers/react.adapter.d.ts.map +0 -1
  215. package/esm/renderers/react.renderer.d.ts +0 -96
  216. package/esm/renderers/react.renderer.d.ts.map +0 -1
  217. package/esm/universal/UniversalApp.d.ts +0 -108
  218. package/esm/universal/UniversalApp.d.ts.map +0 -1
  219. package/esm/universal/cached-runtime.d.ts +0 -115
  220. package/esm/universal/cached-runtime.d.ts.map +0 -1
  221. package/esm/universal/context.d.ts +0 -122
  222. package/esm/universal/context.d.ts.map +0 -1
  223. package/esm/universal/index.d.ts +0 -57
  224. package/esm/universal/index.d.ts.map +0 -1
  225. package/esm/universal/renderers/html.renderer.d.ts +0 -37
  226. package/esm/universal/renderers/html.renderer.d.ts.map +0 -1
  227. package/esm/universal/renderers/index.d.ts +0 -112
  228. package/esm/universal/renderers/index.d.ts.map +0 -1
  229. package/esm/universal/renderers/markdown.renderer.d.ts +0 -33
  230. package/esm/universal/renderers/markdown.renderer.d.ts.map +0 -1
  231. package/esm/universal/renderers/mdx.renderer.d.ts +0 -38
  232. package/esm/universal/renderers/mdx.renderer.d.ts.map +0 -1
  233. package/esm/universal/renderers/react.renderer.d.ts +0 -46
  234. package/esm/universal/renderers/react.renderer.d.ts.map +0 -1
  235. package/esm/universal/runtime-builder.d.ts +0 -33
  236. package/esm/universal/runtime-builder.d.ts.map +0 -1
  237. package/esm/universal/store.d.ts +0 -135
  238. package/esm/universal/store.d.ts.map +0 -1
  239. package/esm/universal/types.d.ts +0 -199
  240. package/esm/universal/types.d.ts.map +0 -1
  241. package/esm/web-components/core/attribute-parser.d.ts +0 -82
  242. package/esm/web-components/core/attribute-parser.d.ts.map +0 -1
  243. package/esm/web-components/core/base-element.d.ts +0 -197
  244. package/esm/web-components/core/base-element.d.ts.map +0 -1
  245. package/esm/web-components/core/index.d.ts +0 -9
  246. package/esm/web-components/core/index.d.ts.map +0 -1
  247. package/esm/web-components/elements/fmcp-alert.d.ts +0 -46
  248. package/esm/web-components/elements/fmcp-alert.d.ts.map +0 -1
  249. package/esm/web-components/elements/fmcp-badge.d.ts +0 -47
  250. package/esm/web-components/elements/fmcp-badge.d.ts.map +0 -1
  251. package/esm/web-components/elements/fmcp-button.d.ts +0 -117
  252. package/esm/web-components/elements/fmcp-button.d.ts.map +0 -1
  253. package/esm/web-components/elements/fmcp-card.d.ts +0 -53
  254. package/esm/web-components/elements/fmcp-card.d.ts.map +0 -1
  255. package/esm/web-components/elements/fmcp-input.d.ts +0 -96
  256. package/esm/web-components/elements/fmcp-input.d.ts.map +0 -1
  257. package/esm/web-components/elements/fmcp-select.d.ts +0 -100
  258. package/esm/web-components/elements/fmcp-select.d.ts.map +0 -1
  259. package/esm/web-components/elements/index.d.ts +0 -13
  260. package/esm/web-components/elements/index.d.ts.map +0 -1
  261. package/esm/web-components/index.d.ts +0 -50
  262. package/esm/web-components/index.d.ts.map +0 -1
  263. package/esm/web-components/register.d.ts +0 -57
  264. package/esm/web-components/register.d.ts.map +0 -1
  265. package/esm/web-components/types.d.ts +0 -122
  266. package/esm/web-components/types.d.ts.map +0 -1
  267. package/esm/widgets/index.d.ts +0 -8
  268. package/esm/widgets/index.d.ts.map +0 -1
  269. package/esm/widgets/index.js +0 -883
  270. package/esm/widgets/progress.d.ts +0 -133
  271. package/esm/widgets/progress.d.ts.map +0 -1
  272. package/esm/widgets/resource.d.ts +0 -163
  273. package/esm/widgets/resource.d.ts.map +0 -1
  274. package/pages/consent.d.ts +0 -117
  275. package/pages/consent.d.ts.map +0 -1
  276. package/pages/error.d.ts +0 -101
  277. package/pages/error.d.ts.map +0 -1
  278. package/pages/index.d.ts +0 -9
  279. package/pages/index.d.ts.map +0 -1
  280. package/pages/index.js +0 -1065
  281. package/react/utils.d.ts +0 -43
  282. package/react/utils.d.ts.map +0 -1
  283. package/widgets/index.d.ts +0 -8
  284. package/widgets/index.d.ts.map +0 -1
  285. package/widgets/index.js +0 -910
  286. package/widgets/progress.d.ts +0 -133
  287. package/widgets/progress.d.ts.map +0 -1
  288. package/widgets/resource.d.ts +0 -163
  289. package/widgets/resource.d.ts.map +0 -1
  290. /package/esm/components/{index.js → index.mjs} +0 -0
  291. /package/esm/render/{index.js → index.mjs} +0 -0
  292. /package/esm/web-components/{index.js → index.mjs} +0 -0
package/react/index.js CHANGED
@@ -35,8 +35,6 @@ __export(react_exports, {
35
35
  Button: () => Button,
36
36
  Card: () => Card,
37
37
  McpBridgeProvider: () => McpBridgeProvider,
38
- isBrowser: () => isBrowser,
39
- isServer: () => isServer,
40
38
  renderAlert: () => renderAlert,
41
39
  renderAlertSync: () => renderAlertSync,
42
40
  renderBadge: () => renderBadge,
@@ -45,7 +43,6 @@ __export(react_exports, {
45
43
  renderButtonSync: () => renderButtonSync,
46
44
  renderCard: () => renderCard,
47
45
  renderCardSync: () => renderCardSync,
48
- renderChildrenToString: () => renderChildrenToString,
49
46
  useCallTool: () => useCallTool,
50
47
  useCapability: () => useCapability,
51
48
  useDisplayMode: () => useDisplayMode,
@@ -668,50 +665,50 @@ var FrontMcpBridge = class {
668
665
  * Get current theme.
669
666
  */
670
667
  getTheme() {
671
- this._ensureInitialized();
672
- return this._adapter.getTheme();
668
+ const adapter = this._ensureInitialized();
669
+ return adapter.getTheme();
673
670
  }
674
671
  /**
675
672
  * Get current display mode.
676
673
  */
677
674
  getDisplayMode() {
678
- this._ensureInitialized();
679
- return this._adapter.getDisplayMode();
675
+ const adapter = this._ensureInitialized();
676
+ return adapter.getDisplayMode();
680
677
  }
681
678
  /**
682
679
  * Get tool input arguments.
683
680
  */
684
681
  getToolInput() {
685
- this._ensureInitialized();
686
- return this._adapter.getToolInput();
682
+ const adapter = this._ensureInitialized();
683
+ return adapter.getToolInput();
687
684
  }
688
685
  /**
689
686
  * Get tool output/result.
690
687
  */
691
688
  getToolOutput() {
692
- this._ensureInitialized();
693
- return this._adapter.getToolOutput();
689
+ const adapter = this._ensureInitialized();
690
+ return adapter.getToolOutput();
694
691
  }
695
692
  /**
696
693
  * Get structured content (parsed output).
697
694
  */
698
695
  getStructuredContent() {
699
- this._ensureInitialized();
700
- return this._adapter.getStructuredContent();
696
+ const adapter = this._ensureInitialized();
697
+ return adapter.getStructuredContent();
701
698
  }
702
699
  /**
703
700
  * Get persisted widget state.
704
701
  */
705
702
  getWidgetState() {
706
- this._ensureInitialized();
707
- return this._adapter.getWidgetState();
703
+ const adapter = this._ensureInitialized();
704
+ return adapter.getWidgetState();
708
705
  }
709
706
  /**
710
707
  * Get full host context.
711
708
  */
712
709
  getHostContext() {
713
- this._ensureInitialized();
714
- return this._adapter.getHostContext();
710
+ const adapter = this._ensureInitialized();
711
+ return adapter.getHostContext();
715
712
  }
716
713
  // ============================================
717
714
  // Actions (delegate to adapter)
@@ -722,53 +719,53 @@ var FrontMcpBridge = class {
722
719
  * @param args - Tool arguments
723
720
  */
724
721
  async callTool(name, args) {
725
- this._ensureInitialized();
722
+ const adapter = this._ensureInitialized();
726
723
  if (!this.hasCapability("canCallTools")) {
727
724
  throw new Error("Tool calls are not supported by the current adapter");
728
725
  }
729
- return this._adapter.callTool(name, args);
726
+ return adapter.callTool(name, args);
730
727
  }
731
728
  /**
732
729
  * Send a follow-up message to the conversation.
733
730
  * @param content - Message content
734
731
  */
735
732
  async sendMessage(content) {
736
- this._ensureInitialized();
733
+ const adapter = this._ensureInitialized();
737
734
  if (!this.hasCapability("canSendMessages")) {
738
735
  throw new Error("Sending messages is not supported by the current adapter");
739
736
  }
740
- return this._adapter.sendMessage(content);
737
+ return adapter.sendMessage(content);
741
738
  }
742
739
  /**
743
740
  * Open an external link.
744
741
  * @param url - URL to open
745
742
  */
746
743
  async openLink(url) {
747
- this._ensureInitialized();
748
- return this._adapter.openLink(url);
744
+ const adapter = this._ensureInitialized();
745
+ return adapter.openLink(url);
749
746
  }
750
747
  /**
751
748
  * Request a display mode change.
752
749
  * @param mode - Desired display mode
753
750
  */
754
751
  async requestDisplayMode(mode) {
755
- this._ensureInitialized();
756
- return this._adapter.requestDisplayMode(mode);
752
+ const adapter = this._ensureInitialized();
753
+ return adapter.requestDisplayMode(mode);
757
754
  }
758
755
  /**
759
756
  * Request widget close.
760
757
  */
761
758
  async requestClose() {
762
- this._ensureInitialized();
763
- return this._adapter.requestClose();
759
+ const adapter = this._ensureInitialized();
760
+ return adapter.requestClose();
764
761
  }
765
762
  /**
766
763
  * Set widget state (persisted across sessions).
767
764
  * @param state - State object to persist
768
765
  */
769
766
  setWidgetState(state) {
770
- this._ensureInitialized();
771
- this._adapter.setWidgetState(state);
767
+ const adapter = this._ensureInitialized();
768
+ adapter.setWidgetState(state);
772
769
  }
773
770
  // ============================================
774
771
  // Events (delegate to adapter)
@@ -779,8 +776,8 @@ var FrontMcpBridge = class {
779
776
  * @returns Unsubscribe function
780
777
  */
781
778
  onContextChange(callback) {
782
- this._ensureInitialized();
783
- return this._adapter.onContextChange(callback);
779
+ const adapter = this._ensureInitialized();
780
+ return adapter.onContextChange(callback);
784
781
  }
785
782
  /**
786
783
  * Subscribe to tool result updates.
@@ -788,1954 +785,59 @@ var FrontMcpBridge = class {
788
785
  * @returns Unsubscribe function
789
786
  */
790
787
  onToolResult(callback) {
791
- this._ensureInitialized();
792
- return this._adapter.onToolResult(callback);
788
+ const adapter = this._ensureInitialized();
789
+ return adapter.onToolResult(callback);
793
790
  }
794
791
  // ============================================
795
792
  // Private Helpers
796
793
  // ============================================
797
794
  /**
798
795
  * Ensure the bridge is initialized before operations.
796
+ * Returns the adapter for type-safe access.
799
797
  */
800
798
  _ensureInitialized() {
801
799
  if (!this._initialized || !this._adapter) {
802
800
  throw new Error("FrontMcpBridge is not initialized. Call initialize() first.");
803
801
  }
802
+ return this._adapter;
804
803
  }
805
804
  /**
806
- * Wrap a promise with a timeout.
807
- */
808
- _withTimeout(promise, ms) {
809
- return new Promise((resolve, reject) => {
810
- const timer = setTimeout(() => {
811
- reject(new Error(`Operation timed out after ${ms}ms`));
812
- }, ms);
813
- promise.then((result) => {
814
- clearTimeout(timer);
815
- resolve(result);
816
- }).catch((error) => {
817
- clearTimeout(timer);
818
- reject(error);
819
- });
820
- });
821
- }
822
- /**
823
- * Emit a bridge event via CustomEvent.
824
- */
825
- _emitEvent(type, payload) {
826
- if (typeof window !== "undefined" && typeof CustomEvent !== "undefined") {
827
- try {
828
- const event = new CustomEvent(type, { detail: payload });
829
- window.dispatchEvent(event);
830
- } catch {
831
- }
832
- }
833
- }
834
- /**
835
- * Log debug message if debugging is enabled.
836
- */
837
- _log(message) {
838
- if (this._config.debug) {
839
- console.log(`[FrontMcpBridge] ${message}`);
840
- }
841
- }
842
- };
843
-
844
- // libs/ui/src/bridge/adapters/base-adapter.ts
845
- var DEFAULT_CAPABILITIES = {
846
- canCallTools: false,
847
- canSendMessages: false,
848
- canOpenLinks: false,
849
- canPersistState: true,
850
- // localStorage fallback
851
- hasNetworkAccess: true,
852
- supportsDisplayModes: false,
853
- supportsTheme: true
854
- };
855
- var DEFAULT_SAFE_AREA = {
856
- top: 0,
857
- bottom: 0,
858
- left: 0,
859
- right: 0
860
- };
861
- var BaseAdapter = class {
862
- _capabilities = { ...DEFAULT_CAPABILITIES };
863
- _hostContext;
864
- _widgetState = {};
865
- _toolInput = {};
866
- _toolOutput = void 0;
867
- _structuredContent = void 0;
868
- _initialized = false;
869
- _contextListeners = /* @__PURE__ */ new Set();
870
- _toolResultListeners = /* @__PURE__ */ new Set();
871
- constructor() {
872
- this._hostContext = this._createDefaultHostContext();
873
- }
874
- get capabilities() {
875
- return this._capabilities;
876
- }
877
- async initialize() {
878
- if (this._initialized) return;
879
- this._loadWidgetState();
880
- this._readInjectedData();
881
- this._initialized = true;
882
- }
883
- dispose() {
884
- this._contextListeners.clear();
885
- this._toolResultListeners.clear();
886
- this._initialized = false;
887
- }
888
- // ============================================
889
- // Data Access
890
- // ============================================
891
- getTheme() {
892
- return this._hostContext.theme;
893
- }
894
- getDisplayMode() {
895
- return this._hostContext.displayMode;
896
- }
897
- getUserAgent() {
898
- return this._hostContext.userAgent;
899
- }
900
- getLocale() {
901
- return this._hostContext.locale;
902
- }
903
- getToolInput() {
904
- return this._toolInput;
905
- }
906
- getToolOutput() {
907
- return this._toolOutput;
908
- }
909
- getStructuredContent() {
910
- return this._structuredContent;
911
- }
912
- getWidgetState() {
913
- return this._widgetState;
914
- }
915
- getSafeArea() {
916
- return this._hostContext.safeArea;
917
- }
918
- getViewport() {
919
- return this._hostContext.viewport;
920
- }
921
- getHostContext() {
922
- return { ...this._hostContext };
923
- }
924
- // ============================================
925
- // Actions (override in subclasses for real functionality)
926
- // ============================================
927
- async callTool(_name, _args) {
928
- if (!this._capabilities.canCallTools) {
929
- throw new Error(`Tool calls are not supported by ${this.name} adapter`);
930
- }
931
- throw new Error("callTool not implemented");
932
- }
933
- async sendMessage(_content) {
934
- if (!this._capabilities.canSendMessages) {
935
- throw new Error(`Sending messages is not supported by ${this.name} adapter`);
936
- }
937
- throw new Error("sendMessage not implemented");
938
- }
939
- async openLink(url) {
940
- if (!this._capabilities.canOpenLinks) {
941
- if (typeof window !== "undefined") {
942
- window.open(url, "_blank", "noopener,noreferrer");
943
- return;
944
- }
945
- throw new Error(`Opening links is not supported by ${this.name} adapter`);
946
- }
947
- throw new Error("openLink not implemented");
948
- }
949
- async requestDisplayMode(_mode) {
950
- if (!this._capabilities.supportsDisplayModes) {
951
- return;
952
- }
953
- throw new Error("requestDisplayMode not implemented");
954
- }
955
- async requestClose() {
956
- }
957
- setWidgetState(state) {
958
- this._widgetState = { ...this._widgetState, ...state };
959
- this._persistWidgetState();
960
- }
961
- // ============================================
962
- // Events
963
- // ============================================
964
- onContextChange(callback) {
965
- this._contextListeners.add(callback);
966
- return () => {
967
- this._contextListeners.delete(callback);
968
- };
969
- }
970
- onToolResult(callback) {
971
- this._toolResultListeners.add(callback);
972
- return () => {
973
- this._toolResultListeners.delete(callback);
974
- };
975
- }
976
- // ============================================
977
- // Protected Helpers
978
- // ============================================
979
- /**
980
- * Create default host context from environment detection.
981
- */
982
- _createDefaultHostContext() {
983
- return {
984
- theme: this._detectTheme(),
985
- displayMode: "inline",
986
- locale: this._detectLocale(),
987
- userAgent: this._detectUserAgent(),
988
- safeArea: DEFAULT_SAFE_AREA,
989
- viewport: this._detectViewport()
990
- };
991
- }
992
- /**
993
- * Detect theme from CSS media query.
994
- */
995
- _detectTheme() {
996
- if (typeof window !== "undefined" && window.matchMedia) {
997
- return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
998
- }
999
- return "light";
1000
- }
1001
- /**
1002
- * Detect locale from navigator.
1003
- */
1004
- _detectLocale() {
1005
- if (typeof navigator !== "undefined") {
1006
- return navigator.language || "en-US";
1007
- }
1008
- return "en-US";
1009
- }
1010
- /**
1011
- * Detect user agent capabilities.
1012
- */
1013
- _detectUserAgent() {
1014
- if (typeof navigator === "undefined") {
1015
- return { type: "web", hover: true, touch: false };
1016
- }
1017
- const ua = navigator.userAgent || "";
1018
- const isMobile = /iPhone|iPad|iPod|Android/i.test(ua);
1019
- const hasTouch = "ontouchstart" in window || navigator.maxTouchPoints > 0;
1020
- const hasHover = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(hover: hover)").matches;
1021
- return {
1022
- type: isMobile ? "mobile" : "web",
1023
- hover: hasHover !== false,
1024
- touch: hasTouch
1025
- };
1026
- }
1027
- /**
1028
- * Detect viewport dimensions.
1029
- */
1030
- _detectViewport() {
1031
- if (typeof window !== "undefined") {
1032
- return {
1033
- width: window.innerWidth,
1034
- height: window.innerHeight
1035
- };
1036
- }
1037
- return void 0;
1038
- }
1039
- /**
1040
- * Read injected tool data from window globals.
1041
- */
1042
- _readInjectedData() {
1043
- if (typeof window === "undefined") return;
1044
- const win = window;
1045
- if (win.__mcpToolInput) {
1046
- this._toolInput = win.__mcpToolInput;
1047
- }
1048
- if (win.__mcpToolOutput) {
1049
- this._toolOutput = win.__mcpToolOutput;
1050
- }
1051
- if (win.__mcpStructuredContent) {
1052
- this._structuredContent = win.__mcpStructuredContent;
1053
- }
1054
- if (win.__mcpHostContext) {
1055
- this._hostContext = { ...this._hostContext, ...win.__mcpHostContext };
1056
- }
1057
- }
1058
- /**
1059
- * Load widget state from localStorage.
1060
- */
1061
- _loadWidgetState() {
1062
- if (typeof localStorage === "undefined") return;
1063
- try {
1064
- const key = this._getStateKey();
1065
- const stored = localStorage.getItem(key);
1066
- if (stored) {
1067
- this._widgetState = JSON.parse(stored);
1068
- }
1069
- } catch {
1070
- }
1071
- }
1072
- /**
1073
- * Persist widget state to localStorage.
1074
- */
1075
- _persistWidgetState() {
1076
- if (typeof localStorage === "undefined") return;
1077
- try {
1078
- const key = this._getStateKey();
1079
- localStorage.setItem(key, JSON.stringify(this._widgetState));
1080
- } catch {
1081
- }
1082
- }
1083
- /**
1084
- * Get localStorage key for widget state.
1085
- */
1086
- _getStateKey() {
1087
- if (typeof window !== "undefined") {
1088
- const toolName = window.__mcpToolName || "unknown";
1089
- return `frontmcp:widget:${toolName}`;
1090
- }
1091
- return "frontmcp:widget:unknown";
1092
- }
1093
- /**
1094
- * Notify context change listeners.
1095
- */
1096
- _notifyContextChange(changes) {
1097
- this._hostContext = { ...this._hostContext, ...changes };
1098
- this._contextListeners.forEach((cb) => {
1099
- try {
1100
- cb(changes);
1101
- } catch (e) {
1102
- console.error("[FrontMcpBridge] Context change listener error:", e);
1103
- }
1104
- });
1105
- }
1106
- /**
1107
- * Notify tool result listeners.
1108
- */
1109
- _notifyToolResult(result) {
1110
- this._toolOutput = result;
1111
- this._toolResultListeners.forEach((cb) => {
1112
- try {
1113
- cb(result);
1114
- } catch (e) {
1115
- console.error("[FrontMcpBridge] Tool result listener error:", e);
1116
- }
1117
- });
1118
- }
1119
- };
1120
-
1121
- // libs/ui/src/bridge/adapters/openai.adapter.ts
1122
- var OpenAIAdapter = class extends BaseAdapter {
1123
- id = "openai";
1124
- name = "OpenAI ChatGPT";
1125
- priority = 100;
1126
- // Highest priority
1127
- _openai;
1128
- _unsubscribeContext;
1129
- _unsubscribeToolResult;
1130
- constructor() {
1131
- super();
1132
- this._capabilities = {
1133
- ...DEFAULT_CAPABILITIES,
1134
- canCallTools: true,
1135
- canSendMessages: true,
1136
- canOpenLinks: true,
1137
- canPersistState: true,
1138
- hasNetworkAccess: true,
1139
- supportsDisplayModes: true,
1140
- supportsTheme: true
1141
- };
1142
- }
1143
- /**
1144
- * Check if OpenAI Apps SDK is available.
1145
- */
1146
- canHandle() {
1147
- if (typeof window === "undefined") return false;
1148
- const win = window;
1149
- return Boolean(win.openai?.canvas);
1150
- }
1151
- /**
1152
- * Initialize the OpenAI adapter.
1153
- */
1154
- async initialize() {
1155
- if (this._initialized) return;
1156
- this._openai = window.openai;
1157
- await super.initialize();
1158
- this._syncContextFromSDK();
1159
- if (this._openai?.canvas?.onContextChange) {
1160
- this._unsubscribeContext = this._openai.canvas.onContextChange((changes) => {
1161
- this._notifyContextChange(changes);
1162
- });
1163
- }
1164
- if (this._openai?.canvas?.onToolResult) {
1165
- this._unsubscribeToolResult = this._openai.canvas.onToolResult((result) => {
1166
- this._notifyToolResult(result);
1167
- });
1168
- }
1169
- }
1170
- /**
1171
- * Dispose adapter resources.
1172
- */
1173
- dispose() {
1174
- if (this._unsubscribeContext) {
1175
- this._unsubscribeContext();
1176
- this._unsubscribeContext = void 0;
1177
- }
1178
- if (this._unsubscribeToolResult) {
1179
- this._unsubscribeToolResult();
1180
- this._unsubscribeToolResult = void 0;
1181
- }
1182
- this._openai = void 0;
1183
- super.dispose();
1184
- }
1185
- // ============================================
1186
- // Data Access (override with SDK calls)
1187
- // ============================================
1188
- getTheme() {
1189
- if (this._openai?.canvas?.getTheme) {
1190
- const theme = this._openai.canvas.getTheme();
1191
- return theme === "dark" ? "dark" : "light";
1192
- }
1193
- return super.getTheme();
1194
- }
1195
- getDisplayMode() {
1196
- if (this._openai?.canvas?.getDisplayMode) {
1197
- const mode = this._openai.canvas.getDisplayMode();
1198
- if (mode === "fullscreen" || mode === "pip" || mode === "carousel") {
1199
- return mode;
1200
- }
1201
- return "inline";
1202
- }
1203
- return super.getDisplayMode();
1204
- }
1205
- // ============================================
1206
- // Actions (proxy to SDK)
1207
- // ============================================
1208
- async callTool(name, args) {
1209
- if (!this._openai?.canvas?.callServerTool) {
1210
- throw new Error("callServerTool not available in OpenAI SDK");
1211
- }
1212
- return this._openai.canvas.callServerTool(name, args);
1213
- }
1214
- async sendMessage(content) {
1215
- if (!this._openai?.canvas?.sendMessage) {
1216
- throw new Error("sendMessage not available in OpenAI SDK");
1217
- }
1218
- await this._openai.canvas.sendMessage(content);
1219
- }
1220
- async openLink(url) {
1221
- if (!this._openai?.canvas?.openLink) {
1222
- return super.openLink(url);
1223
- }
1224
- await this._openai.canvas.openLink(url);
1225
- }
1226
- async requestDisplayMode(mode) {
1227
- if (!this._openai?.canvas?.setDisplayMode) {
1228
- return super.requestDisplayMode(mode);
1229
- }
1230
- await this._openai.canvas.setDisplayMode(mode);
1231
- this._hostContext = { ...this._hostContext, displayMode: mode };
1232
- }
1233
- async requestClose() {
1234
- if (this._openai?.canvas?.close) {
1235
- await this._openai.canvas.close();
1236
- }
1237
- }
1238
- // ============================================
1239
- // Private Helpers
1240
- // ============================================
1241
- /**
1242
- * Sync context from OpenAI SDK.
1243
- */
1244
- _syncContextFromSDK() {
1245
- if (!this._openai?.canvas) return;
1246
- if (this._openai.canvas.getTheme) {
1247
- const theme = this._openai.canvas.getTheme();
1248
- this._hostContext.theme = theme === "dark" ? "dark" : "light";
1249
- }
1250
- if (this._openai.canvas.getDisplayMode) {
1251
- const mode = this._openai.canvas.getDisplayMode();
1252
- if (mode === "fullscreen" || mode === "pip" || mode === "carousel" || mode === "inline") {
1253
- this._hostContext.displayMode = mode;
1254
- }
1255
- }
1256
- if (this._openai.canvas.getContext) {
1257
- const ctx = this._openai.canvas.getContext();
1258
- if (ctx) {
1259
- this._hostContext = { ...this._hostContext, ...ctx };
1260
- }
1261
- }
1262
- }
1263
- };
1264
- function createOpenAIAdapter() {
1265
- return new OpenAIAdapter();
1266
- }
1267
-
1268
- // libs/ui/src/bridge/adapters/ext-apps.adapter.ts
1269
- var ExtAppsAdapter = class extends BaseAdapter {
1270
- id = "ext-apps";
1271
- name = "ext-apps (SEP-1865)";
1272
- priority = 80;
1273
- // High priority, but below OpenAI native
1274
- _config;
1275
- _messageListener;
1276
- _pendingRequests = /* @__PURE__ */ new Map();
1277
- _requestId = 0;
1278
- _trustedOrigin;
1279
- _hostCapabilities = {};
1280
- constructor(config) {
1281
- super();
1282
- this._config = config || {};
1283
- this._capabilities = {
1284
- ...DEFAULT_CAPABILITIES,
1285
- canPersistState: true,
1286
- hasNetworkAccess: true,
1287
- // ext-apps usually allows network
1288
- supportsTheme: true
1289
- };
1290
- }
1291
- /**
1292
- * Check if we're in an iframe (potential ext-apps context).
1293
- */
1294
- canHandle() {
1295
- if (typeof window === "undefined") return false;
1296
- const inIframe = window.parent !== window;
1297
- if (!inIframe) return false;
1298
- const win = window;
1299
- if (win.openai?.canvas) return false;
1300
- if (win.__mcpPlatform === "ext-apps") return true;
1301
- return true;
1302
- }
1303
- /**
1304
- * Initialize the ext-apps adapter with protocol handshake.
1305
- */
1306
- async initialize() {
1307
- if (this._initialized) return;
1308
- this._setupMessageListener();
1309
- await super.initialize();
1310
- await this._performHandshake();
1311
- this._initialized = true;
1312
- }
1313
- /**
1314
- * Dispose adapter resources.
1315
- */
1316
- dispose() {
1317
- if (this._messageListener && typeof window !== "undefined") {
1318
- window.removeEventListener("message", this._messageListener);
1319
- this._messageListener = void 0;
1320
- }
1321
- for (const [id, pending] of this._pendingRequests) {
1322
- clearTimeout(pending.timeout);
1323
- pending.reject(new Error("Adapter disposed"));
1324
- }
1325
- this._pendingRequests.clear();
1326
- super.dispose();
1327
- }
1328
- // ============================================
1329
- // Actions (via JSON-RPC)
1330
- // ============================================
1331
- async callTool(name, args) {
1332
- if (!this._hostCapabilities.serverToolProxy) {
1333
- throw new Error("Server tool proxy not supported by host");
1334
- }
1335
- return this._sendRequest("ui/callServerTool", {
1336
- name,
1337
- arguments: args
1338
- });
1339
- }
1340
- async sendMessage(content) {
1341
- await this._sendRequest("ui/message", { content });
1342
- }
1343
- async openLink(url) {
1344
- if (!this._hostCapabilities.openLink) {
1345
- return super.openLink(url);
1346
- }
1347
- await this._sendRequest("ui/openLink", { url });
1348
- }
1349
- async requestDisplayMode(mode) {
1350
- await this._sendRequest("ui/setDisplayMode", { mode });
1351
- this._hostContext = { ...this._hostContext, displayMode: mode };
1352
- }
1353
- async requestClose() {
1354
- await this._sendRequest("ui/close", {});
1355
- }
1356
- // ============================================
1357
- // Private: Message Handling
1358
- // ============================================
1359
- /**
1360
- * Setup postMessage listener for incoming messages.
1361
- */
1362
- _setupMessageListener() {
1363
- if (typeof window === "undefined") return;
1364
- this._messageListener = (event) => {
1365
- this._handleMessage(event);
1366
- };
1367
- window.addEventListener("message", this._messageListener);
1368
- }
1369
- /**
1370
- * Handle incoming postMessage events.
1371
- */
1372
- _handleMessage(event) {
1373
- if (!this._isOriginTrusted(event.origin)) {
1374
- return;
1375
- }
1376
- const data = event.data;
1377
- if (!data || typeof data !== "object") return;
1378
- if (data.jsonrpc !== "2.0") return;
1379
- if ("id" in data && (data.result !== void 0 || data.error !== void 0)) {
1380
- this._handleResponse(data);
1381
- return;
1382
- }
1383
- if ("method" in data && !("id" in data)) {
1384
- this._handleNotification(data);
1385
- return;
1386
- }
1387
- }
1388
- /**
1389
- * Handle JSON-RPC response.
1390
- */
1391
- _handleResponse(response) {
1392
- const pending = this._pendingRequests.get(response.id);
1393
- if (!pending) return;
1394
- clearTimeout(pending.timeout);
1395
- this._pendingRequests.delete(response.id);
1396
- if (response.error) {
1397
- pending.reject(new Error(`${response.error.message} (code: ${response.error.code})`));
1398
- } else {
1399
- pending.resolve(response.result);
1400
- }
1401
- }
1402
- /**
1403
- * Handle JSON-RPC notification from host.
1404
- */
1405
- _handleNotification(notification) {
1406
- switch (notification.method) {
1407
- case "ui/notifications/tool-input":
1408
- this._handleToolInput(notification.params);
1409
- break;
1410
- case "ui/notifications/tool-input-partial":
1411
- this._handleToolInputPartial(notification.params);
1412
- break;
1413
- case "ui/notifications/tool-result":
1414
- this._handleToolResult(notification.params);
1415
- break;
1416
- case "ui/notifications/host-context-changed":
1417
- this._handleHostContextChange(notification.params);
1418
- break;
1419
- case "ui/notifications/initialized":
1420
- break;
1421
- case "ui/notifications/cancelled":
1422
- this._handleCancelled(notification.params);
1423
- break;
1424
- }
1425
- }
1426
- /**
1427
- * Handle tool input notification.
1428
- */
1429
- _handleToolInput(params) {
1430
- this._toolInput = params.arguments || {};
1431
- this._emitBridgeEvent("tool:input", { arguments: this._toolInput });
1432
- }
1433
- /**
1434
- * Handle partial tool input (streaming).
1435
- */
1436
- _handleToolInputPartial(params) {
1437
- this._toolInput = { ...this._toolInput, ...params.arguments };
1438
- this._emitBridgeEvent("tool:input-partial", { arguments: this._toolInput });
1439
- }
1440
- /**
1441
- * Handle tool result notification.
1442
- */
1443
- _handleToolResult(params) {
1444
- this._toolOutput = params.content;
1445
- this._structuredContent = params.structuredContent;
1446
- this._notifyToolResult(params.content);
1447
- this._emitBridgeEvent("tool:result", {
1448
- content: params.content,
1449
- structuredContent: params.structuredContent
1450
- });
1451
- }
1452
- /**
1453
- * Handle host context change notification.
1454
- */
1455
- _handleHostContextChange(params) {
1456
- const changes = {};
1457
- if (params.theme !== void 0) {
1458
- changes.theme = params.theme;
1459
- }
1460
- if (params.displayMode !== void 0) {
1461
- changes.displayMode = params.displayMode;
1462
- }
1463
- if (params.viewport !== void 0) {
1464
- changes.viewport = params.viewport;
1465
- }
1466
- if (params.locale !== void 0) {
1467
- changes.locale = params.locale;
1468
- }
1469
- if (params.timezone !== void 0) {
1470
- changes.timezone = params.timezone;
1471
- }
1472
- this._notifyContextChange(changes);
1473
- }
1474
- /**
1475
- * Handle cancellation notification.
1476
- */
1477
- _handleCancelled(params) {
1478
- const reason = params?.reason;
1479
- this._emitBridgeEvent("tool:cancelled", { reason });
1480
- }
1481
- // ============================================
1482
- // Private: JSON-RPC Transport
1483
- // ============================================
1484
- /**
1485
- * Send a JSON-RPC request to the host.
1486
- */
1487
- _sendRequest(method, params) {
1488
- return new Promise((resolve, reject) => {
1489
- const id = ++this._requestId;
1490
- const timeout = this._config.options?.initTimeout || 1e4;
1491
- const request = {
1492
- jsonrpc: "2.0",
1493
- id,
1494
- method,
1495
- params
1496
- };
1497
- const timeoutHandle = setTimeout(() => {
1498
- this._pendingRequests.delete(id);
1499
- reject(new Error(`Request ${method} timed out after ${timeout}ms`));
1500
- }, timeout);
1501
- this._pendingRequests.set(id, {
1502
- resolve,
1503
- reject,
1504
- timeout: timeoutHandle
1505
- });
1506
- this._postMessage(request);
1507
- });
1508
- }
1509
- /**
1510
- * Send a JSON-RPC notification (no response expected).
1511
- */
1512
- _sendNotification(method, params) {
1513
- const notification = {
1514
- jsonrpc: "2.0",
1515
- method,
1516
- params
1517
- };
1518
- this._postMessage(notification);
1519
- }
1520
- /**
1521
- * Post a message to the parent window.
1522
- */
1523
- _postMessage(message) {
1524
- if (typeof window === "undefined") return;
1525
- const targetOrigin = this._trustedOrigin || "*";
1526
- window.parent.postMessage(message, targetOrigin);
1527
- }
1528
- // ============================================
1529
- // Private: Handshake
1530
- // ============================================
1531
- /**
1532
- * Perform the ui/initialize handshake with the host.
1533
- */
1534
- async _performHandshake() {
1535
- const params = {
1536
- appInfo: {
1537
- name: this._config.options?.appName || "FrontMCP Widget",
1538
- version: this._config.options?.appVersion || "1.0.0"
1539
- },
1540
- appCapabilities: {
1541
- tools: {
1542
- listChanged: false
1543
- }
1544
- },
1545
- protocolVersion: this._config.options?.protocolVersion || "2024-11-05"
1546
- };
1547
- try {
1548
- const result = await this._sendRequest("ui/initialize", params);
1549
- this._hostCapabilities = result.hostCapabilities || {};
1550
- this._capabilities = {
1551
- ...this._capabilities,
1552
- canCallTools: Boolean(this._hostCapabilities.serverToolProxy),
1553
- canSendMessages: true,
1554
- canOpenLinks: Boolean(this._hostCapabilities.openLink),
1555
- supportsDisplayModes: true
1556
- };
1557
- if (result.hostContext) {
1558
- this._hostContext = {
1559
- ...this._hostContext,
1560
- ...result.hostContext
1561
- };
1562
- }
1563
- if (!this._config.options?.trustedOrigins?.length) {
1564
- }
1565
- } catch (error) {
1566
- throw new Error(`ext-apps handshake failed: ${error}`);
1567
- }
1568
- }
1569
- // ============================================
1570
- // Private: Origin Security
1571
- // ============================================
1572
- /**
1573
- * Check if an origin is trusted.
1574
- * Uses trust-on-first-use if no explicit origins configured.
1575
- */
1576
- _isOriginTrusted(origin) {
1577
- const trustedOrigins = this._config.options?.trustedOrigins;
1578
- if (trustedOrigins && trustedOrigins.length > 0) {
1579
- return trustedOrigins.includes(origin);
1580
- }
1581
- if (!this._trustedOrigin) {
1582
- this._trustedOrigin = origin;
1583
- return true;
1584
- }
1585
- return this._trustedOrigin === origin;
1586
- }
1587
- // ============================================
1588
- // Private: Events
1589
- // ============================================
1590
- /**
1591
- * Emit a bridge event via CustomEvent.
1592
- */
1593
- _emitBridgeEvent(type, detail) {
1594
- if (typeof window !== "undefined" && typeof CustomEvent !== "undefined") {
1595
- try {
1596
- const event = new CustomEvent(type, { detail });
1597
- window.dispatchEvent(event);
1598
- } catch {
1599
- }
1600
- }
1601
- }
1602
- };
1603
- function createExtAppsAdapter(config) {
1604
- return new ExtAppsAdapter(config);
1605
- }
1606
-
1607
- // libs/ui/src/bridge/adapters/claude.adapter.ts
1608
- var ClaudeAdapter = class extends BaseAdapter {
1609
- id = "claude";
1610
- name = "Claude (Anthropic)";
1611
- priority = 60;
1612
- constructor() {
1613
- super();
1614
- this._capabilities = {
1615
- ...DEFAULT_CAPABILITIES,
1616
- canCallTools: false,
1617
- // Claude artifacts can't call tools
1618
- canSendMessages: false,
1619
- // Can't send messages back to conversation
1620
- canOpenLinks: true,
1621
- // Can open links via window.open
1622
- canPersistState: true,
1623
- // localStorage works
1624
- hasNetworkAccess: false,
1625
- // Network is blocked
1626
- supportsDisplayModes: false,
1627
- // No display mode control
1628
- supportsTheme: true
1629
- // Can detect system theme
1630
- };
1631
- }
1632
- /**
1633
- * Check if we're running in a Claude artifact/widget context.
1634
- */
1635
- canHandle() {
1636
- if (typeof window === "undefined") return false;
1637
- const win = window;
1638
- if (win.__mcpPlatform === "claude") return true;
1639
- if (win.claude) return true;
1640
- if (win.__claudeArtifact) return true;
1641
- if (typeof location !== "undefined") {
1642
- const href = location.href;
1643
- if (href.includes("claude.ai") || href.includes("anthropic.com")) {
1644
- return true;
1645
- }
1646
- }
1647
- return false;
1648
- }
1649
- /**
1650
- * Initialize the Claude adapter.
1651
- */
1652
- async initialize() {
1653
- if (this._initialized) return;
1654
- await super.initialize();
1655
- this._setupThemeListener();
1656
- }
1657
- /**
1658
- * Open a link in a new tab.
1659
- * This is one of the few actions available in Claude artifacts.
1660
- */
1661
- async openLink(url) {
1662
- if (typeof window !== "undefined") {
1663
- window.open(url, "_blank", "noopener,noreferrer");
1664
- }
1665
- }
1666
- /**
1667
- * Request display mode change (no-op for Claude).
1668
- */
1669
- async requestDisplayMode(_mode) {
1670
- }
1671
- /**
1672
- * Request close (no-op for Claude).
1673
- */
1674
- async requestClose() {
1675
- }
1676
- // ============================================
1677
- // Private Helpers
1678
- // ============================================
1679
- /**
1680
- * Setup listener for system theme changes.
1681
- */
1682
- _setupThemeListener() {
1683
- if (typeof window === "undefined" || !window.matchMedia) return;
1684
- const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
1685
- const handleChange = (e) => {
1686
- const newTheme = e.matches ? "dark" : "light";
1687
- if (newTheme !== this._hostContext.theme) {
1688
- this._notifyContextChange({ theme: newTheme });
1689
- }
1690
- };
1691
- if (mediaQuery.addEventListener) {
1692
- mediaQuery.addEventListener("change", handleChange);
1693
- } else if (mediaQuery.addListener) {
1694
- mediaQuery.addListener(handleChange);
1695
- }
1696
- }
1697
- };
1698
- function createClaudeAdapter() {
1699
- return new ClaudeAdapter();
1700
- }
1701
-
1702
- // libs/ui/src/bridge/adapters/gemini.adapter.ts
1703
- var GeminiAdapter = class extends BaseAdapter {
1704
- id = "gemini";
1705
- name = "Google Gemini";
1706
- priority = 40;
1707
- _gemini;
1708
- constructor() {
1709
- super();
1710
- this._capabilities = {
1711
- ...DEFAULT_CAPABILITIES,
1712
- canCallTools: false,
1713
- // May be enabled if SDK supports it
1714
- canSendMessages: false,
1715
- // May be enabled if SDK supports it
1716
- canOpenLinks: true,
1717
- canPersistState: true,
1718
- hasNetworkAccess: true,
1719
- supportsDisplayModes: false,
1720
- supportsTheme: true
1721
- };
1722
- }
1723
- /**
1724
- * Check if we're running in a Gemini context.
1725
- */
1726
- canHandle() {
1727
- if (typeof window === "undefined") return false;
1728
- const win = window;
1729
- if (win.__mcpPlatform === "gemini") return true;
1730
- if (win.gemini) return true;
1731
- if (typeof location !== "undefined") {
1732
- const href = location.href;
1733
- if (href.includes("gemini.google.com") || href.includes("bard.google.com")) {
1734
- return true;
1735
- }
1736
- }
1737
- return false;
1738
- }
1739
- /**
1740
- * Initialize the Gemini adapter.
1741
- */
1742
- async initialize() {
1743
- if (this._initialized) return;
1744
- const win = window;
1745
- this._gemini = win.gemini;
1746
- if (this._gemini?.ui) {
1747
- if (this._gemini.ui.sendMessage) {
1748
- this._capabilities = { ...this._capabilities, canSendMessages: true };
1749
- }
1750
- }
1751
- await super.initialize();
1752
- this._setupThemeListener();
1753
- }
1754
- /**
1755
- * Get current theme.
1756
- */
1757
- getTheme() {
1758
- if (this._gemini?.ui?.getTheme) {
1759
- const theme = this._gemini.ui.getTheme();
1760
- return theme === "dark" ? "dark" : "light";
1761
- }
1762
- return super.getTheme();
1763
- }
1764
- /**
1765
- * Send a message (if supported by SDK).
1766
- */
1767
- async sendMessage(content) {
1768
- if (this._gemini?.ui?.sendMessage) {
1769
- await this._gemini.ui.sendMessage(content);
1770
- return;
1771
- }
1772
- throw new Error("Sending messages is not supported by Gemini adapter");
1773
- }
1774
- /**
1775
- * Open a link.
805
+ * Wrap a promise with a timeout.
1776
806
  */
1777
- async openLink(url) {
1778
- if (this._gemini?.ui?.openLink) {
1779
- await this._gemini.ui.openLink(url);
1780
- return;
1781
- }
1782
- return super.openLink(url);
807
+ _withTimeout(promise, ms) {
808
+ return new Promise((resolve, reject) => {
809
+ const timer = setTimeout(() => {
810
+ reject(new Error(`Operation timed out after ${ms}ms`));
811
+ }, ms);
812
+ promise.then((result) => {
813
+ clearTimeout(timer);
814
+ resolve(result);
815
+ }).catch((error) => {
816
+ clearTimeout(timer);
817
+ reject(error);
818
+ });
819
+ });
1783
820
  }
1784
- // ============================================
1785
- // Private Helpers
1786
- // ============================================
1787
821
  /**
1788
- * Setup listener for system theme changes.
822
+ * Emit a bridge event via CustomEvent.
1789
823
  */
1790
- _setupThemeListener() {
1791
- if (typeof window === "undefined" || !window.matchMedia) return;
1792
- const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
1793
- const handleChange = (e) => {
1794
- if (!this._gemini?.ui?.getTheme) {
1795
- const newTheme = e.matches ? "dark" : "light";
1796
- if (newTheme !== this._hostContext.theme) {
1797
- this._notifyContextChange({ theme: newTheme });
1798
- }
824
+ _emitEvent(type, payload) {
825
+ if (typeof window !== "undefined" && typeof CustomEvent !== "undefined") {
826
+ try {
827
+ const event = new CustomEvent(type, { detail: payload });
828
+ window.dispatchEvent(event);
829
+ } catch {
1799
830
  }
1800
- };
1801
- if (mediaQuery.addEventListener) {
1802
- mediaQuery.addEventListener("change", handleChange);
1803
- } else if (mediaQuery.addListener) {
1804
- mediaQuery.addListener(handleChange);
1805
831
  }
1806
832
  }
1807
- };
1808
- function createGeminiAdapter() {
1809
- return new GeminiAdapter();
1810
- }
1811
-
1812
- // libs/ui/src/bridge/adapters/generic.adapter.ts
1813
- var GenericAdapter = class extends BaseAdapter {
1814
- id = "generic";
1815
- name = "Generic Web";
1816
- priority = 0;
1817
- // Lowest priority - fallback only
1818
- constructor() {
1819
- super();
1820
- this._capabilities = {
1821
- ...DEFAULT_CAPABILITIES,
1822
- canCallTools: false,
1823
- canSendMessages: false,
1824
- canOpenLinks: true,
1825
- // window.open works
1826
- canPersistState: true,
1827
- // localStorage works
1828
- hasNetworkAccess: true,
1829
- // Assume network available
1830
- supportsDisplayModes: false,
1831
- supportsTheme: true
1832
- // System theme detection
1833
- };
1834
- }
1835
- /**
1836
- * Generic adapter can always handle the environment.
1837
- * It serves as the fallback when no other adapter matches.
1838
- */
1839
- canHandle() {
1840
- return typeof window !== "undefined";
1841
- }
1842
- /**
1843
- * Initialize the generic adapter.
1844
- */
1845
- async initialize() {
1846
- if (this._initialized) return;
1847
- await super.initialize();
1848
- this._setupThemeListener();
1849
- }
1850
- /**
1851
- * Open a link using window.open.
1852
- */
1853
- async openLink(url) {
1854
- if (typeof window !== "undefined") {
1855
- window.open(url, "_blank", "noopener,noreferrer");
1856
- }
1857
- }
1858
- // ============================================
1859
- // Private Helpers
1860
- // ============================================
1861
833
  /**
1862
- * Setup listener for system theme changes.
834
+ * Log debug message if debugging is enabled.
1863
835
  */
1864
- _setupThemeListener() {
1865
- if (typeof window === "undefined" || !window.matchMedia) return;
1866
- const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
1867
- const handleChange = (e) => {
1868
- const newTheme = e.matches ? "dark" : "light";
1869
- if (newTheme !== this._hostContext.theme) {
1870
- this._notifyContextChange({ theme: newTheme });
1871
- }
1872
- };
1873
- if (mediaQuery.addEventListener) {
1874
- mediaQuery.addEventListener("change", handleChange);
1875
- } else if (mediaQuery.addListener) {
1876
- mediaQuery.addListener(handleChange);
1877
- }
1878
- }
1879
- };
1880
- function createGenericAdapter() {
1881
- return new GenericAdapter();
1882
- }
1883
-
1884
- // libs/ui/src/bridge/adapters/index.ts
1885
- function registerBuiltInAdapters() {
1886
- defaultRegistry.register("openai", createOpenAIAdapter);
1887
- defaultRegistry.register("ext-apps", createExtAppsAdapter);
1888
- defaultRegistry.register("claude", createClaudeAdapter);
1889
- defaultRegistry.register("gemini", createGeminiAdapter);
1890
- defaultRegistry.register("generic", createGenericAdapter);
1891
- }
1892
- registerBuiltInAdapters();
1893
-
1894
- // libs/ui/src/bridge/runtime/iife-generator.ts
1895
- function generateBridgeIIFE(options = {}) {
1896
- const { debug = false, trustedOrigins = [], minify = false } = options;
1897
- const adapters = options.adapters || ["openai", "ext-apps", "claude", "gemini", "generic"];
1898
- const parts = [];
1899
- parts.push("(function() {");
1900
- parts.push('"use strict";');
1901
- parts.push("");
1902
- if (debug) {
1903
- parts.push('function log(msg) { console.log("[FrontMcpBridge] " + msg); }');
1904
- } else {
1905
- parts.push("function log() {}");
1906
- }
1907
- parts.push("");
1908
- parts.push("var DEFAULT_SAFE_AREA = { top: 0, bottom: 0, left: 0, right: 0 };");
1909
- parts.push("");
1910
- parts.push(generateContextDetection());
1911
- parts.push("");
1912
- parts.push(generateBaseCapabilities());
1913
- parts.push("");
1914
- if (adapters.includes("openai")) {
1915
- parts.push(generateOpenAIAdapter());
1916
- parts.push("");
1917
- }
1918
- if (adapters.includes("ext-apps")) {
1919
- parts.push(generateExtAppsAdapter(trustedOrigins));
1920
- parts.push("");
1921
- }
1922
- if (adapters.includes("claude")) {
1923
- parts.push(generateClaudeAdapter());
1924
- parts.push("");
1925
- }
1926
- if (adapters.includes("gemini")) {
1927
- parts.push(generateGeminiAdapter());
1928
- parts.push("");
1929
- }
1930
- if (adapters.includes("generic")) {
1931
- parts.push(generateGenericAdapter());
1932
- parts.push("");
1933
- }
1934
- parts.push(generatePlatformDetection(adapters));
1935
- parts.push("");
1936
- parts.push(generateBridgeClass());
1937
- parts.push("");
1938
- parts.push("var bridge = new FrontMcpBridge();");
1939
- parts.push("bridge.initialize().then(function() {");
1940
- parts.push(' log("Bridge initialized with adapter: " + bridge.adapterId);');
1941
- parts.push(' window.dispatchEvent(new CustomEvent("bridge:ready", { detail: { adapter: bridge.adapterId } }));');
1942
- parts.push("}).catch(function(err) {");
1943
- parts.push(' console.error("[FrontMcpBridge] Init failed:", err);');
1944
- parts.push(' window.dispatchEvent(new CustomEvent("bridge:error", { detail: { error: err } }));');
1945
- parts.push("});");
1946
- parts.push("");
1947
- parts.push("window.FrontMcpBridge = bridge;");
1948
- parts.push("})();");
1949
- const code = parts.join("\n");
1950
- if (minify) {
1951
- return minifyJS(code);
1952
- }
1953
- return code;
1954
- }
1955
- function generateContextDetection() {
1956
- return `
1957
- function detectTheme() {
1958
- if (typeof window !== 'undefined' && window.matchMedia) {
1959
- return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
1960
- }
1961
- return 'light';
1962
- }
1963
-
1964
- function detectLocale() {
1965
- if (typeof navigator !== 'undefined') {
1966
- return navigator.language || 'en-US';
1967
- }
1968
- return 'en-US';
1969
- }
1970
-
1971
- function detectUserAgent() {
1972
- if (typeof navigator === 'undefined') {
1973
- return { type: 'web', hover: true, touch: false };
1974
- }
1975
- var ua = navigator.userAgent || '';
1976
- var isMobile = /iPhone|iPad|iPod|Android/i.test(ua);
1977
- var hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
1978
- var hasHover = window.matchMedia && window.matchMedia('(hover: hover)').matches;
1979
- return { type: isMobile ? 'mobile' : 'web', hover: hasHover !== false, touch: hasTouch };
1980
- }
1981
-
1982
- function detectViewport() {
1983
- if (typeof window !== 'undefined') {
1984
- return { width: window.innerWidth, height: window.innerHeight };
1985
- }
1986
- return undefined;
1987
- }
1988
-
1989
- function readInjectedData() {
1990
- var data = { toolInput: {}, toolOutput: undefined, structuredContent: undefined };
1991
- if (typeof window !== 'undefined') {
1992
- if (window.__mcpToolInput) data.toolInput = window.__mcpToolInput;
1993
- if (window.__mcpToolOutput) data.toolOutput = window.__mcpToolOutput;
1994
- if (window.__mcpStructuredContent) data.structuredContent = window.__mcpStructuredContent;
1995
- }
1996
- return data;
1997
- }
1998
- `.trim();
1999
- }
2000
- function generateBaseCapabilities() {
2001
- return `
2002
- var DEFAULT_CAPABILITIES = {
2003
- canCallTools: false,
2004
- canSendMessages: false,
2005
- canOpenLinks: false,
2006
- canPersistState: true,
2007
- hasNetworkAccess: true,
2008
- supportsDisplayModes: false,
2009
- supportsTheme: true
2010
- };
2011
- `.trim();
2012
- }
2013
- function generateOpenAIAdapter() {
2014
- return `
2015
- var OpenAIAdapter = {
2016
- id: 'openai',
2017
- name: 'OpenAI ChatGPT',
2018
- priority: 100,
2019
- capabilities: Object.assign({}, DEFAULT_CAPABILITIES, {
2020
- canCallTools: true,
2021
- canSendMessages: true,
2022
- canOpenLinks: true,
2023
- supportsDisplayModes: true
2024
- }),
2025
- canHandle: function() {
2026
- if (typeof window === 'undefined') return false;
2027
- // Check for window.openai.callTool (the actual OpenAI SDK API)
2028
- if (window.openai && typeof window.openai.callTool === 'function') return true;
2029
- // Also check if we're being injected with tool metadata (OpenAI injects toolOutput)
2030
- if (window.openai && (window.openai.toolOutput !== undefined || window.openai.toolInput !== undefined)) return true;
2031
- return false;
2032
- },
2033
- initialize: function(context) {
2034
- var sdk = window.openai;
2035
- context.sdk = sdk;
2036
- // OpenAI SDK exposes theme and displayMode directly as properties
2037
- if (sdk.theme) {
2038
- context.hostContext.theme = sdk.theme;
2039
- }
2040
- if (sdk.displayMode) {
2041
- context.hostContext.displayMode = sdk.displayMode;
2042
- }
2043
- // Note: OpenAI SDK does not have an onContextChange equivalent
2044
- return Promise.resolve();
2045
- },
2046
- callTool: function(context, name, args) {
2047
- return context.sdk.callTool(name, args);
2048
- },
2049
- sendMessage: function(context, content) {
2050
- if (typeof context.sdk.sendFollowUpMessage === 'function') {
2051
- return context.sdk.sendFollowUpMessage(content);
2052
- }
2053
- return Promise.reject(new Error('Messages not supported'));
2054
- },
2055
- openLink: function(context, url) {
2056
- window.open(url, '_blank', 'noopener,noreferrer');
2057
- return Promise.resolve();
2058
- },
2059
- requestDisplayMode: function(context, mode) {
2060
- return Promise.resolve();
2061
- },
2062
- requestClose: function(context) {
2063
- return Promise.resolve();
2064
- }
2065
- };
2066
- `.trim();
2067
- }
2068
- function generateExtAppsAdapter(trustedOrigins) {
2069
- const originsArray = trustedOrigins.length > 0 ? JSON.stringify(trustedOrigins) : "[]";
2070
- return `
2071
- var ExtAppsAdapter = {
2072
- id: 'ext-apps',
2073
- name: 'ext-apps (SEP-1865)',
2074
- priority: 80,
2075
- capabilities: Object.assign({}, DEFAULT_CAPABILITIES, { canPersistState: true, hasNetworkAccess: true }),
2076
- trustedOrigins: ${originsArray},
2077
- trustedOrigin: null,
2078
- pendingRequests: {},
2079
- requestId: 0,
2080
- hostCapabilities: {},
2081
- canHandle: function() {
2082
- if (typeof window === 'undefined') return false;
2083
- if (window.parent === window) return false;
2084
- // Check for OpenAI SDK (window.openai.callTool) - defer to OpenAIAdapter
2085
- if (window.openai && typeof window.openai.callTool === 'function') return false;
2086
- if (window.__mcpPlatform === 'ext-apps') return true;
2087
- return true;
2088
- },
2089
- initialize: function(context) {
2090
- var self = this;
2091
- context.extApps = this;
2092
-
2093
- window.addEventListener('message', function(event) {
2094
- self.handleMessage(context, event);
2095
- });
2096
-
2097
- return self.performHandshake(context);
2098
- },
2099
- handleMessage: function(context, event) {
2100
- if (!this.isOriginTrusted(event.origin)) return;
2101
- var data = event.data;
2102
- if (!data || typeof data !== 'object' || data.jsonrpc !== '2.0') return;
2103
-
2104
- if ('id' in data && (data.result !== undefined || data.error !== undefined)) {
2105
- var pending = this.pendingRequests[data.id];
2106
- if (pending) {
2107
- clearTimeout(pending.timeout);
2108
- delete this.pendingRequests[data.id];
2109
- if (data.error) {
2110
- pending.reject(new Error(data.error.message + ' (code: ' + data.error.code + ')'));
2111
- } else {
2112
- pending.resolve(data.result);
2113
- }
2114
- }
2115
- return;
2116
- }
2117
-
2118
- if ('method' in data && !('id' in data)) {
2119
- this.handleNotification(context, data);
2120
- }
2121
- },
2122
- handleNotification: function(context, notification) {
2123
- var params = notification.params || {};
2124
- switch (notification.method) {
2125
- case 'ui/notifications/tool-input':
2126
- context.toolInput = params.arguments || {};
2127
- window.dispatchEvent(new CustomEvent('tool:input', { detail: { arguments: context.toolInput } }));
2128
- break;
2129
- case 'ui/notifications/tool-result':
2130
- context.toolOutput = params.content;
2131
- context.structuredContent = params.structuredContent;
2132
- context.notifyToolResult(params.content);
2133
- window.dispatchEvent(new CustomEvent('tool:result', { detail: params }));
2134
- break;
2135
- case 'ui/notifications/host-context-changed':
2136
- Object.assign(context.hostContext, params);
2137
- context.notifyContextChange(params);
2138
- break;
2139
- }
2140
- },
2141
- isOriginTrusted: function(origin) {
2142
- if (this.trustedOrigins.length > 0) {
2143
- return this.trustedOrigins.indexOf(origin) !== -1;
2144
- }
2145
- // When no trusted origins configured, only trust first message in iframe context
2146
- // This helps mitigate race conditions where a malicious iframe could establish trust
2147
- if (!this.trustedOrigin) {
2148
- if (window.parent !== window && origin) {
2149
- this.trustedOrigin = origin;
2150
- return true;
2151
- }
2152
- return false;
2153
- }
2154
- return this.trustedOrigin === origin;
2155
- },
2156
- sendRequest: function(method, params) {
2157
- var self = this;
2158
- return new Promise(function(resolve, reject) {
2159
- // Security: Require trusted origin before sending requests to prevent message leaks
2160
- if (!self.trustedOrigin && self.trustedOrigins.length === 0) {
2161
- reject(new Error('Cannot send request: no trusted origin established'));
2162
- return;
2163
- }
2164
-
2165
- var id = ++self.requestId;
2166
- var timeout = setTimeout(function() {
2167
- delete self.pendingRequests[id];
2168
- reject(new Error('Request ' + method + ' timed out'));
2169
- }, 10000);
2170
-
2171
- self.pendingRequests[id] = { resolve: resolve, reject: reject, timeout: timeout };
2172
-
2173
- var targetOrigin = self.trustedOrigin || self.trustedOrigins[0];
2174
- window.parent.postMessage({ jsonrpc: '2.0', id: id, method: method, params: params }, targetOrigin);
2175
- });
2176
- },
2177
- performHandshake: function(context) {
2178
- var self = this;
2179
- var params = {
2180
- appInfo: { name: 'FrontMCP Widget', version: '1.0.0' },
2181
- appCapabilities: { tools: { listChanged: false } },
2182
- protocolVersion: '2024-11-05'
2183
- };
2184
-
2185
- return this.sendRequest('ui/initialize', params).then(function(result) {
2186
- self.hostCapabilities = result.hostCapabilities || {};
2187
- self.capabilities = Object.assign({}, self.capabilities, {
2188
- canCallTools: Boolean(self.hostCapabilities.serverToolProxy),
2189
- canSendMessages: true,
2190
- canOpenLinks: Boolean(self.hostCapabilities.openLink),
2191
- supportsDisplayModes: true
2192
- });
2193
- if (result.hostContext) {
2194
- Object.assign(context.hostContext, result.hostContext);
2195
- }
2196
- });
2197
- },
2198
- callTool: function(context, name, args) {
2199
- if (!this.hostCapabilities.serverToolProxy) {
2200
- return Promise.reject(new Error('Server tool proxy not supported'));
2201
- }
2202
- return this.sendRequest('ui/callServerTool', { name: name, arguments: args });
2203
- },
2204
- sendMessage: function(context, content) {
2205
- return this.sendRequest('ui/message', { content: content });
2206
- },
2207
- openLink: function(context, url) {
2208
- if (!this.hostCapabilities.openLink) {
2209
- window.open(url, '_blank', 'noopener,noreferrer');
2210
- return Promise.resolve();
2211
- }
2212
- return this.sendRequest('ui/openLink', { url: url });
2213
- },
2214
- requestDisplayMode: function(context, mode) {
2215
- return this.sendRequest('ui/setDisplayMode', { mode: mode });
2216
- },
2217
- requestClose: function(context) {
2218
- return this.sendRequest('ui/close', {});
2219
- }
2220
- };
2221
- `.trim();
2222
- }
2223
- function generateClaudeAdapter() {
2224
- return `
2225
- var ClaudeAdapter = {
2226
- id: 'claude',
2227
- name: 'Claude (Anthropic)',
2228
- priority: 60,
2229
- capabilities: Object.assign({}, DEFAULT_CAPABILITIES, {
2230
- canCallTools: false,
2231
- canSendMessages: false,
2232
- canOpenLinks: true,
2233
- hasNetworkAccess: false,
2234
- supportsDisplayModes: false
2235
- }),
2236
- canHandle: function() {
2237
- if (typeof window === 'undefined') return false;
2238
- if (window.__mcpPlatform === 'claude') return true;
2239
- if (window.claude) return true;
2240
- if (window.__claudeArtifact) return true;
2241
- if (typeof location !== 'undefined') {
2242
- var href = location.href;
2243
- if (href.indexOf('claude.ai') !== -1 || href.indexOf('anthropic.com') !== -1) return true;
2244
- }
2245
- return false;
2246
- },
2247
- initialize: function(context) {
2248
- return Promise.resolve();
2249
- },
2250
- callTool: function() {
2251
- return Promise.reject(new Error('Tool calls not supported in Claude'));
2252
- },
2253
- sendMessage: function() {
2254
- return Promise.reject(new Error('Messages not supported in Claude'));
2255
- },
2256
- openLink: function(context, url) {
2257
- window.open(url, '_blank', 'noopener,noreferrer');
2258
- return Promise.resolve();
2259
- },
2260
- requestDisplayMode: function() {
2261
- return Promise.resolve();
2262
- },
2263
- requestClose: function() {
2264
- return Promise.resolve();
2265
- }
2266
- };
2267
- `.trim();
2268
- }
2269
- function generateGeminiAdapter() {
2270
- return `
2271
- var GeminiAdapter = {
2272
- id: 'gemini',
2273
- name: 'Google Gemini',
2274
- priority: 40,
2275
- capabilities: Object.assign({}, DEFAULT_CAPABILITIES, {
2276
- canOpenLinks: true,
2277
- hasNetworkAccess: true
2278
- }),
2279
- canHandle: function() {
2280
- if (typeof window === 'undefined') return false;
2281
- if (window.__mcpPlatform === 'gemini') return true;
2282
- if (window.gemini) return true;
2283
- if (typeof location !== 'undefined') {
2284
- var href = location.href;
2285
- if (href.indexOf('gemini.google.com') !== -1 || href.indexOf('bard.google.com') !== -1) return true;
2286
- }
2287
- return false;
2288
- },
2289
- initialize: function(context) {
2290
- if (window.gemini && window.gemini.ui && window.gemini.ui.getTheme) {
2291
- context.hostContext.theme = window.gemini.ui.getTheme() === 'dark' ? 'dark' : 'light';
2292
- }
2293
- return Promise.resolve();
2294
- },
2295
- callTool: function() {
2296
- return Promise.reject(new Error('Tool calls not supported in Gemini'));
2297
- },
2298
- sendMessage: function(context, content) {
2299
- if (window.gemini && window.gemini.ui && window.gemini.ui.sendMessage) {
2300
- return window.gemini.ui.sendMessage(content);
2301
- }
2302
- return Promise.reject(new Error('Messages not supported in Gemini'));
2303
- },
2304
- openLink: function(context, url) {
2305
- if (window.gemini && window.gemini.ui && window.gemini.ui.openLink) {
2306
- return window.gemini.ui.openLink(url);
2307
- }
2308
- window.open(url, '_blank', 'noopener,noreferrer');
2309
- return Promise.resolve();
2310
- },
2311
- requestDisplayMode: function() {
2312
- return Promise.resolve();
2313
- },
2314
- requestClose: function() {
2315
- return Promise.resolve();
2316
- }
2317
- };
2318
- `.trim();
2319
- }
2320
- function generateGenericAdapter() {
2321
- return `
2322
- var GenericAdapter = {
2323
- id: 'generic',
2324
- name: 'Generic Web',
2325
- priority: 0,
2326
- capabilities: Object.assign({}, DEFAULT_CAPABILITIES, {
2327
- canOpenLinks: true,
2328
- hasNetworkAccess: true
2329
- }),
2330
- canHandle: function() {
2331
- return typeof window !== 'undefined';
2332
- },
2333
- initialize: function(context) {
2334
- return Promise.resolve();
2335
- },
2336
- callTool: function() {
2337
- return Promise.reject(new Error('Tool calls not supported'));
2338
- },
2339
- sendMessage: function() {
2340
- return Promise.reject(new Error('Messages not supported'));
2341
- },
2342
- openLink: function(context, url) {
2343
- window.open(url, '_blank', 'noopener,noreferrer');
2344
- return Promise.resolve();
2345
- },
2346
- requestDisplayMode: function() {
2347
- return Promise.resolve();
2348
- },
2349
- requestClose: function() {
2350
- return Promise.resolve();
2351
- }
2352
- };
2353
- `.trim();
2354
- }
2355
- function generatePlatformDetection(adapters) {
2356
- const adapterVars = adapters.map((a) => {
2357
- switch (a) {
2358
- case "openai":
2359
- return "OpenAIAdapter";
2360
- case "ext-apps":
2361
- return "ExtAppsAdapter";
2362
- case "claude":
2363
- return "ClaudeAdapter";
2364
- case "gemini":
2365
- return "GeminiAdapter";
2366
- case "generic":
2367
- return "GenericAdapter";
2368
- default:
2369
- return "";
2370
- }
2371
- }).filter(Boolean);
2372
- return `
2373
- var ADAPTERS = [${adapterVars.join(", ")}].sort(function(a, b) { return b.priority - a.priority; });
2374
-
2375
- function detectPlatform() {
2376
- for (var i = 0; i < ADAPTERS.length; i++) {
2377
- if (ADAPTERS[i].canHandle()) {
2378
- log('Detected platform: ' + ADAPTERS[i].id);
2379
- return ADAPTERS[i];
2380
- }
2381
- }
2382
- log('No platform detected, using generic');
2383
- return GenericAdapter;
2384
- }
2385
- `.trim();
2386
- }
2387
- function generateBridgeClass() {
2388
- return `
2389
- function FrontMcpBridge() {
2390
- this._adapter = null;
2391
- this._initialized = false;
2392
- this._context = {
2393
- hostContext: {
2394
- theme: detectTheme(),
2395
- displayMode: 'inline',
2396
- locale: detectLocale(),
2397
- userAgent: detectUserAgent(),
2398
- safeArea: DEFAULT_SAFE_AREA,
2399
- viewport: detectViewport()
2400
- },
2401
- toolInput: {},
2402
- toolOutput: undefined,
2403
- structuredContent: undefined,
2404
- widgetState: {},
2405
- contextListeners: [],
2406
- toolResultListeners: [],
2407
- notifyContextChange: function(changes) {
2408
- Object.assign(this.hostContext, changes);
2409
- for (var i = 0; i < this.contextListeners.length; i++) {
2410
- try { this.contextListeners[i](changes); } catch(e) {}
2411
- }
2412
- },
2413
- notifyToolResult: function(result) {
2414
- this.toolOutput = result;
2415
- for (var i = 0; i < this.toolResultListeners.length; i++) {
2416
- try { this.toolResultListeners[i](result); } catch(e) {}
2417
- }
2418
- }
2419
- };
2420
-
2421
- var injected = readInjectedData();
2422
- this._context.toolInput = injected.toolInput;
2423
- this._context.toolOutput = injected.toolOutput;
2424
- this._context.structuredContent = injected.structuredContent;
2425
-
2426
- this._loadWidgetState();
2427
- }
2428
-
2429
- FrontMcpBridge.prototype._loadWidgetState = function() {
2430
- try {
2431
- var key = 'frontmcp:widget:' + (window.__mcpToolName || 'unknown');
2432
- var stored = localStorage.getItem(key);
2433
- if (stored) this._context.widgetState = JSON.parse(stored);
2434
- } catch(e) {}
2435
- };
2436
-
2437
- FrontMcpBridge.prototype._saveWidgetState = function() {
2438
- try {
2439
- var key = 'frontmcp:widget:' + (window.__mcpToolName || 'unknown');
2440
- localStorage.setItem(key, JSON.stringify(this._context.widgetState));
2441
- } catch(e) {}
2442
- };
2443
-
2444
- FrontMcpBridge.prototype.initialize = function() {
2445
- if (this._initialized) return Promise.resolve();
2446
- var self = this;
2447
- this._adapter = detectPlatform();
2448
- return this._adapter.initialize(this._context).then(function() {
2449
- self._initialized = true;
2450
- // Set up the data-tool-call click handler after initialization
2451
- self._setupDataToolCallHandler();
2452
- });
2453
- };
2454
-
2455
- Object.defineProperty(FrontMcpBridge.prototype, 'initialized', { get: function() { return this._initialized; } });
2456
- Object.defineProperty(FrontMcpBridge.prototype, 'adapterId', { get: function() { return this._adapter ? this._adapter.id : undefined; } });
2457
- Object.defineProperty(FrontMcpBridge.prototype, 'capabilities', { get: function() { return this._adapter ? this._adapter.capabilities : DEFAULT_CAPABILITIES; } });
2458
-
2459
- FrontMcpBridge.prototype.getTheme = function() { return this._context.hostContext.theme; };
2460
- FrontMcpBridge.prototype.getDisplayMode = function() { return this._context.hostContext.displayMode; };
2461
- FrontMcpBridge.prototype.getToolInput = function() { return this._context.toolInput; };
2462
- FrontMcpBridge.prototype.getToolOutput = function() { return this._context.toolOutput; };
2463
- FrontMcpBridge.prototype.getStructuredContent = function() { return this._context.structuredContent; };
2464
- FrontMcpBridge.prototype.getWidgetState = function() { return this._context.widgetState; };
2465
- FrontMcpBridge.prototype.getHostContext = function() { return Object.assign({}, this._context.hostContext); };
2466
- FrontMcpBridge.prototype.hasCapability = function(cap) { return this._adapter && this._adapter.capabilities[cap] === true; };
2467
-
2468
- // Get tool response metadata (platform-agnostic)
2469
- // Used by inline mode widgets to detect when ui/html arrives
2470
- FrontMcpBridge.prototype.getToolResponseMetadata = function() {
2471
- // OpenAI injects toolResponseMetadata for widget-producing tools
2472
- if (typeof window !== 'undefined' && window.openai && window.openai.toolResponseMetadata) {
2473
- return window.openai.toolResponseMetadata;
2474
- }
2475
- // Claude (future support)
2476
- if (typeof window !== 'undefined' && window.claude && window.claude.toolResponseMetadata) {
2477
- return window.claude.toolResponseMetadata;
2478
- }
2479
- // FrontMCP direct injection (for testing/ext-apps)
2480
- if (typeof window !== 'undefined' && window.__mcpToolResponseMetadata) {
2481
- return window.__mcpToolResponseMetadata;
2482
- }
2483
- return null;
2484
- };
2485
-
2486
- // Subscribe to tool response metadata changes (for inline mode injection)
2487
- FrontMcpBridge.prototype.onToolResponseMetadata = function(callback) {
2488
- var self = this;
2489
- var called = false;
2490
-
2491
- // Check if already available
2492
- var existing = self.getToolResponseMetadata();
2493
- if (existing) {
2494
- called = true;
2495
- callback(existing);
2496
- }
2497
-
2498
- // Set up property interceptors for OpenAI
2499
- if (typeof window !== 'undefined') {
2500
- // OpenAI: Intercept toolResponseMetadata assignment
2501
- if (!window.__frontmcpMetadataIntercepted) {
2502
- window.__frontmcpMetadataIntercepted = true;
2503
- window.__frontmcpMetadataCallbacks = [];
2504
-
2505
- // Create openai object if it doesn't exist
2506
- if (!window.openai) window.openai = {};
2507
-
2508
- var originalMetadata = window.openai.toolResponseMetadata;
2509
- Object.defineProperty(window.openai, 'toolResponseMetadata', {
2510
- get: function() { return originalMetadata; },
2511
- set: function(val) {
2512
- originalMetadata = val;
2513
- log('toolResponseMetadata set, notifying ' + window.__frontmcpMetadataCallbacks.length + ' listeners');
2514
- for (var i = 0; i < window.__frontmcpMetadataCallbacks.length; i++) {
2515
- try { window.__frontmcpMetadataCallbacks[i](val); } catch(e) {}
2516
- }
2517
- },
2518
- configurable: true
2519
- });
836
+ _log(message) {
837
+ if (this._config.debug) {
838
+ console.log(`[FrontMcpBridge] ${message}`);
2520
839
  }
2521
-
2522
- // Register callback wrapper (store reference for unsubscribe)
2523
- var wrapper = function(metadata) {
2524
- if (!called) {
2525
- called = true;
2526
- callback(metadata);
2527
- }
2528
- };
2529
- window.__frontmcpMetadataCallbacks.push(wrapper);
2530
-
2531
- // Return unsubscribe function that removes the wrapper (not the original callback)
2532
- return function() {
2533
- if (window.__frontmcpMetadataCallbacks) {
2534
- var idx = window.__frontmcpMetadataCallbacks.indexOf(wrapper);
2535
- if (idx !== -1) window.__frontmcpMetadataCallbacks.splice(idx, 1);
2536
- }
2537
- };
2538
- }
2539
-
2540
- // Return no-op unsubscribe for non-window environments
2541
- return function() {};
2542
- };
2543
-
2544
- FrontMcpBridge.prototype.callTool = function(name, args) {
2545
- // Priority 1: Direct OpenAI SDK call (most reliable in OpenAI iframe)
2546
- // This bypasses adapter abstraction for maximum compatibility
2547
- if (typeof window !== 'undefined' && window.openai && typeof window.openai.callTool === 'function') {
2548
- log('callTool: Using OpenAI SDK directly');
2549
- return window.openai.callTool(name, args);
2550
- }
2551
-
2552
- // Priority 2: Use adapter (if initialized and supports tool calls)
2553
- if (this._adapter && this._adapter.capabilities && this._adapter.capabilities.canCallTools) {
2554
- log('callTool: Using adapter ' + this._adapter.id);
2555
- return this._adapter.callTool(this._context, name, args);
2556
- }
2557
-
2558
- // Not initialized or no tool support
2559
- if (!this._adapter) {
2560
- return Promise.reject(new Error('Bridge not initialized. Wait for bridge:ready event.'));
2561
840
  }
2562
- return Promise.reject(new Error('Tool calls not supported on this platform (' + this._adapter.id + ')'));
2563
- };
2564
-
2565
- FrontMcpBridge.prototype.sendMessage = function(content) {
2566
- if (!this._adapter) return Promise.reject(new Error('Not initialized'));
2567
- return this._adapter.sendMessage(this._context, content);
2568
- };
2569
-
2570
- FrontMcpBridge.prototype.openLink = function(url) {
2571
- if (!this._adapter) return Promise.reject(new Error('Not initialized'));
2572
- return this._adapter.openLink(this._context, url);
2573
- };
2574
-
2575
- FrontMcpBridge.prototype.requestDisplayMode = function(mode) {
2576
- if (!this._adapter) return Promise.reject(new Error('Not initialized'));
2577
- var self = this;
2578
- return this._adapter.requestDisplayMode(this._context, mode).then(function() {
2579
- self._context.hostContext.displayMode = mode;
2580
- });
2581
- };
2582
-
2583
- FrontMcpBridge.prototype.requestClose = function() {
2584
- if (!this._adapter) return Promise.reject(new Error('Not initialized'));
2585
- return this._adapter.requestClose(this._context);
2586
- };
2587
-
2588
- FrontMcpBridge.prototype.setWidgetState = function(state) {
2589
- Object.assign(this._context.widgetState, state);
2590
- this._saveWidgetState();
2591
- };
2592
-
2593
- FrontMcpBridge.prototype.onContextChange = function(callback) {
2594
- var listeners = this._context.contextListeners;
2595
- listeners.push(callback);
2596
- return function() {
2597
- var idx = listeners.indexOf(callback);
2598
- if (idx !== -1) listeners.splice(idx, 1);
2599
- };
2600
- };
2601
-
2602
- FrontMcpBridge.prototype.onToolResult = function(callback) {
2603
- var listeners = this._context.toolResultListeners;
2604
- listeners.push(callback);
2605
- return function() {
2606
- var idx = listeners.indexOf(callback);
2607
- if (idx !== -1) listeners.splice(idx, 1);
2608
- };
2609
- };
2610
-
2611
- // ==================== data-tool-call Click Handler ====================
2612
-
2613
- FrontMcpBridge.prototype._setupDataToolCallHandler = function() {
2614
- var self = this;
2615
-
2616
- document.addEventListener('click', function(e) {
2617
- // Find the closest element with data-tool-call attribute
2618
- var target = e.target;
2619
- while (target && target !== document) {
2620
- if (target.hasAttribute && target.hasAttribute('data-tool-call')) {
2621
- var toolName = target.getAttribute('data-tool-call');
2622
- var argsAttr = target.getAttribute('data-tool-args');
2623
- var args = {};
2624
-
2625
- try {
2626
- if (argsAttr) {
2627
- args = JSON.parse(argsAttr);
2628
- }
2629
- } catch (parseErr) {
2630
- console.error('[frontmcp] Failed to parse data-tool-args:', parseErr);
2631
- }
2632
-
2633
- log('data-tool-call clicked: ' + toolName);
2634
-
2635
- // Show loading state - save original content first
2636
- var originalContent = target.innerHTML;
2637
- var originalDisabled = target.disabled;
2638
- target.disabled = true;
2639
- target.classList.add('opacity-50', 'cursor-not-allowed');
2640
-
2641
- // Add spinner for buttons
2642
- var spinner = '<svg class="animate-spin -ml-1 mr-2 h-4 w-4 inline" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>';
2643
- if (target.tagName === 'BUTTON') {
2644
- target.innerHTML = spinner + 'Loading...';
2645
- }
2646
-
2647
- // Helper to reset button state
2648
- function resetButton() {
2649
- target.innerHTML = originalContent;
2650
- target.disabled = originalDisabled;
2651
- target.classList.remove('opacity-50', 'cursor-not-allowed');
2652
- }
2653
-
2654
- // Determine how to call the tool
2655
- var toolCallPromise;
2656
-
2657
- // Priority 1: Direct OpenAI SDK call (bypasses adapter abstraction)
2658
- if (typeof window !== 'undefined' && window.openai && typeof window.openai.callTool === 'function') {
2659
- log('Using OpenAI SDK directly for tool call');
2660
- toolCallPromise = window.openai.callTool(toolName, args);
2661
- }
2662
- // Priority 2: Use adapter (if it supports tool calls)
2663
- else if (self.hasCapability('canCallTools')) {
2664
- log('Using adapter for tool call');
2665
- toolCallPromise = self.callTool(toolName, args);
2666
- }
2667
- // No tool call capability
2668
- else {
2669
- console.error('[frontmcp] Tool calls not supported on this platform (' + self.adapterId + ')');
2670
- resetButton();
2671
- target.dispatchEvent(new CustomEvent('tool:error', {
2672
- detail: { name: toolName, args: args, error: 'Tool calls not supported on this platform' },
2673
- bubbles: true
2674
- }));
2675
- e.preventDefault();
2676
- return;
2677
- }
2678
-
2679
- // Handle the tool call result
2680
- toolCallPromise.then(function(result) {
2681
- log('Tool call succeeded: ' + toolName);
2682
- resetButton();
2683
-
2684
- // Update bridge state to trigger widget re-render
2685
- // React isn't hydrated in OpenAI iframe, so useState doesn't work
2686
- // Instead, we use the bridge's reactive state system
2687
- if (result && window.__frontmcp && window.__frontmcp.bridge && typeof window.__frontmcp.bridge.setWidgetState === 'function') {
2688
- var newData = result.structuredContent || result;
2689
- log('Updating bridge state with new data');
2690
- window.__frontmcp.bridge.setWidgetState(newData);
2691
- }
2692
-
2693
- // Dispatch success event
2694
- target.dispatchEvent(new CustomEvent('tool:success', {
2695
- detail: { name: toolName, args: args, result: result },
2696
- bubbles: true
2697
- }));
2698
- }).catch(function(err) {
2699
- console.error('[frontmcp] Tool call failed: ' + toolName, err);
2700
- resetButton();
2701
- // Dispatch error event
2702
- target.dispatchEvent(new CustomEvent('tool:error', {
2703
- detail: { name: toolName, args: args, error: err.message || err },
2704
- bubbles: true
2705
- }));
2706
- });
2707
-
2708
- // Prevent default behavior (e.g., form submission)
2709
- e.preventDefault();
2710
- return;
2711
- }
2712
- target = target.parentElement;
2713
- }
2714
- }, true); // Use capture phase to handle before React handlers
2715
- };
2716
- `.trim();
2717
- }
2718
- function minifyJS(code) {
2719
- return code.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "").replace(/\s+/g, " ").replace(/\s*([{};,:()[\]])\s*/g, "$1").replace(/;\}/g, "}").trim();
2720
- }
2721
- function generatePlatformBundle(platform, options = {}) {
2722
- const platformAdapters = {
2723
- chatgpt: ["openai", "generic"],
2724
- claude: ["claude", "generic"],
2725
- gemini: ["gemini", "generic"],
2726
- universal: ["openai", "ext-apps", "claude", "gemini", "generic"]
2727
- };
2728
- return generateBridgeIIFE({
2729
- ...options,
2730
- adapters: platformAdapters[platform]
2731
- });
2732
- }
2733
- var UNIVERSAL_BRIDGE_SCRIPT = generateBridgeIIFE();
2734
- var BRIDGE_SCRIPT_TAGS = {
2735
- universal: `<script>${UNIVERSAL_BRIDGE_SCRIPT}</script>`,
2736
- chatgpt: `<script>${generatePlatformBundle("chatgpt")}</script>`,
2737
- claude: `<script>${generatePlatformBundle("claude")}</script>`,
2738
- gemini: `<script>${generatePlatformBundle("gemini")}</script>`
2739
841
  };
2740
842
 
2741
843
  // libs/ui/src/react/hooks/context.tsx
@@ -3083,49 +1185,6 @@ function useOpenLink() {
3083
1185
  [bridge]
3084
1186
  );
3085
1187
  }
3086
-
3087
- // libs/ui/src/react/utils.ts
3088
- var import_utils = require("@frontmcp/uipack/utils");
3089
- var cachedReactDOMServer = null;
3090
- function getReactDOMServer() {
3091
- if (!cachedReactDOMServer) {
3092
- try {
3093
- cachedReactDOMServer = require("react-dom/server");
3094
- } catch {
3095
- return null;
3096
- }
3097
- }
3098
- return cachedReactDOMServer;
3099
- }
3100
- function renderChildrenToString(children) {
3101
- if (children == null) {
3102
- return "";
3103
- }
3104
- if (typeof children === "string") {
3105
- return (0, import_utils.escapeHtml)(children);
3106
- }
3107
- if (typeof children === "number") {
3108
- return String(children);
3109
- }
3110
- if (typeof children === "boolean") {
3111
- return "";
3112
- }
3113
- try {
3114
- const server = getReactDOMServer();
3115
- if (server) {
3116
- return server.renderToStaticMarkup(children);
3117
- }
3118
- return String(children);
3119
- } catch {
3120
- return String(children);
3121
- }
3122
- }
3123
- function isBrowser() {
3124
- return typeof window !== "undefined";
3125
- }
3126
- function isServer() {
3127
- return typeof window === "undefined";
3128
- }
3129
1188
  // Annotate the CommonJS export names for ESM import in node:
3130
1189
  0 && (module.exports = {
3131
1190
  Alert,
@@ -3133,8 +1192,6 @@ function isServer() {
3133
1192
  Button,
3134
1193
  Card,
3135
1194
  McpBridgeProvider,
3136
- isBrowser,
3137
- isServer,
3138
1195
  renderAlert,
3139
1196
  renderAlertSync,
3140
1197
  renderBadge,
@@ -3143,7 +1200,6 @@ function isServer() {
3143
1200
  renderButtonSync,
3144
1201
  renderCard,
3145
1202
  renderCardSync,
3146
- renderChildrenToString,
3147
1203
  useCallTool,
3148
1204
  useCapability,
3149
1205
  useDisplayMode,