@frontmcp/ui 0.5.0

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 (393) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +438 -0
  3. package/package.json +147 -0
  4. package/src/adapters/index.d.ts +10 -0
  5. package/src/adapters/index.js +18 -0
  6. package/src/adapters/index.js.map +1 -0
  7. package/src/adapters/platform-meta.d.ts +165 -0
  8. package/src/adapters/platform-meta.js +310 -0
  9. package/src/adapters/platform-meta.js.map +1 -0
  10. package/src/base-template/bridge.d.ts +89 -0
  11. package/src/base-template/bridge.js +452 -0
  12. package/src/base-template/bridge.js.map +1 -0
  13. package/src/base-template/default-base-template.d.ts +91 -0
  14. package/src/base-template/default-base-template.js +435 -0
  15. package/src/base-template/default-base-template.js.map +1 -0
  16. package/src/base-template/index.d.ts +14 -0
  17. package/src/base-template/index.js +30 -0
  18. package/src/base-template/index.js.map +1 -0
  19. package/src/base-template/polyfills.d.ts +30 -0
  20. package/src/base-template/polyfills.js +190 -0
  21. package/src/base-template/polyfills.js.map +1 -0
  22. package/src/base-template/theme-styles.d.ts +73 -0
  23. package/src/base-template/theme-styles.js +95 -0
  24. package/src/base-template/theme-styles.js.map +1 -0
  25. package/src/bridge/adapters/base-adapter.d.ts +103 -0
  26. package/src/bridge/adapters/base-adapter.js +314 -0
  27. package/src/bridge/adapters/base-adapter.js.map +1 -0
  28. package/src/bridge/adapters/claude.adapter.d.ts +66 -0
  29. package/src/bridge/adapters/claude.adapter.js +145 -0
  30. package/src/bridge/adapters/claude.adapter.js.map +1 -0
  31. package/src/bridge/adapters/ext-apps.adapter.d.ts +142 -0
  32. package/src/bridge/adapters/ext-apps.adapter.js +416 -0
  33. package/src/bridge/adapters/ext-apps.adapter.js.map +1 -0
  34. package/src/bridge/adapters/gemini.adapter.d.ts +63 -0
  35. package/src/bridge/adapters/gemini.adapter.js +160 -0
  36. package/src/bridge/adapters/gemini.adapter.js.map +1 -0
  37. package/src/bridge/adapters/generic.adapter.d.ts +55 -0
  38. package/src/bridge/adapters/generic.adapter.js +108 -0
  39. package/src/bridge/adapters/generic.adapter.js.map +1 -0
  40. package/src/bridge/adapters/index.d.ts +25 -0
  41. package/src/bridge/adapters/index.js +65 -0
  42. package/src/bridge/adapters/index.js.map +1 -0
  43. package/src/bridge/adapters/openai.adapter.d.ts +64 -0
  44. package/src/bridge/adapters/openai.adapter.js +194 -0
  45. package/src/bridge/adapters/openai.adapter.js.map +1 -0
  46. package/src/bridge/core/adapter-registry.d.ts +121 -0
  47. package/src/bridge/core/adapter-registry.js +271 -0
  48. package/src/bridge/core/adapter-registry.js.map +1 -0
  49. package/src/bridge/core/bridge-factory.d.ts +198 -0
  50. package/src/bridge/core/bridge-factory.js +428 -0
  51. package/src/bridge/core/bridge-factory.js.map +1 -0
  52. package/src/bridge/core/index.d.ts +9 -0
  53. package/src/bridge/core/index.js +22 -0
  54. package/src/bridge/core/index.js.map +1 -0
  55. package/src/bridge/index.d.ts +61 -0
  56. package/src/bridge/index.js +94 -0
  57. package/src/bridge/index.js.map +1 -0
  58. package/src/bridge/runtime/iife-generator.d.ts +61 -0
  59. package/src/bridge/runtime/iife-generator.js +940 -0
  60. package/src/bridge/runtime/iife-generator.js.map +1 -0
  61. package/src/bridge/runtime/index.d.ts +8 -0
  62. package/src/bridge/runtime/index.js +16 -0
  63. package/src/bridge/runtime/index.js.map +1 -0
  64. package/src/bridge/types.d.ts +385 -0
  65. package/src/bridge/types.js +11 -0
  66. package/src/bridge/types.js.map +1 -0
  67. package/src/build/cdn-resources.d.ts +140 -0
  68. package/src/build/cdn-resources.js +314 -0
  69. package/src/build/cdn-resources.js.map +1 -0
  70. package/src/build/index.d.ts +294 -0
  71. package/src/build/index.js +325 -0
  72. package/src/build/index.js.map +1 -0
  73. package/src/build/widget-manifest.d.ts +212 -0
  74. package/src/build/widget-manifest.js +652 -0
  75. package/src/build/widget-manifest.js.map +1 -0
  76. package/src/bundler/bundler.d.ts +110 -0
  77. package/src/bundler/bundler.js +432 -0
  78. package/src/bundler/bundler.js.map +1 -0
  79. package/src/bundler/cache.d.ts +172 -0
  80. package/src/bundler/cache.js +250 -0
  81. package/src/bundler/cache.js.map +1 -0
  82. package/src/bundler/index.d.ts +41 -0
  83. package/src/bundler/index.js +73 -0
  84. package/src/bundler/index.js.map +1 -0
  85. package/src/bundler/sandbox/enclave-adapter.d.ts +120 -0
  86. package/src/bundler/sandbox/enclave-adapter.js +339 -0
  87. package/src/bundler/sandbox/enclave-adapter.js.map +1 -0
  88. package/src/bundler/sandbox/executor.d.ts +13 -0
  89. package/src/bundler/sandbox/executor.js +22 -0
  90. package/src/bundler/sandbox/executor.js.map +1 -0
  91. package/src/bundler/sandbox/policy.d.ts +61 -0
  92. package/src/bundler/sandbox/policy.js +238 -0
  93. package/src/bundler/sandbox/policy.js.map +1 -0
  94. package/src/bundler/types.d.ts +347 -0
  95. package/src/bundler/types.js +132 -0
  96. package/src/bundler/types.js.map +1 -0
  97. package/src/components/alert.d.ts +71 -0
  98. package/src/components/alert.js +189 -0
  99. package/src/components/alert.js.map +1 -0
  100. package/src/components/alert.schema.d.ts +114 -0
  101. package/src/components/alert.schema.js +105 -0
  102. package/src/components/alert.schema.js.map +1 -0
  103. package/src/components/avatar.d.ts +76 -0
  104. package/src/components/avatar.js +176 -0
  105. package/src/components/avatar.js.map +1 -0
  106. package/src/components/avatar.schema.d.ts +169 -0
  107. package/src/components/avatar.schema.js +103 -0
  108. package/src/components/avatar.schema.js.map +1 -0
  109. package/src/components/badge.d.ts +70 -0
  110. package/src/components/badge.js +149 -0
  111. package/src/components/badge.js.map +1 -0
  112. package/src/components/badge.schema.d.ts +109 -0
  113. package/src/components/badge.schema.js +96 -0
  114. package/src/components/badge.schema.js.map +1 -0
  115. package/src/components/button.d.ts +111 -0
  116. package/src/components/button.js +336 -0
  117. package/src/components/button.js.map +1 -0
  118. package/src/components/button.schema.d.ts +148 -0
  119. package/src/components/button.schema.js +121 -0
  120. package/src/components/button.schema.js.map +1 -0
  121. package/src/components/card.d.ts +60 -0
  122. package/src/components/card.js +117 -0
  123. package/src/components/card.js.map +1 -0
  124. package/src/components/card.schema.d.ts +113 -0
  125. package/src/components/card.schema.js +98 -0
  126. package/src/components/card.schema.js.map +1 -0
  127. package/src/components/form.d.ts +239 -0
  128. package/src/components/form.js +420 -0
  129. package/src/components/form.js.map +1 -0
  130. package/src/components/form.schema.d.ts +441 -0
  131. package/src/components/form.schema.js +406 -0
  132. package/src/components/form.schema.js.map +1 -0
  133. package/src/components/index.d.ts +29 -0
  134. package/src/components/index.js +98 -0
  135. package/src/components/index.js.map +1 -0
  136. package/src/components/list.d.ts +127 -0
  137. package/src/components/list.js +279 -0
  138. package/src/components/list.js.map +1 -0
  139. package/src/components/list.schema.d.ts +134 -0
  140. package/src/components/list.schema.js +168 -0
  141. package/src/components/list.schema.js.map +1 -0
  142. package/src/components/modal.d.ts +111 -0
  143. package/src/components/modal.js +260 -0
  144. package/src/components/modal.js.map +1 -0
  145. package/src/components/modal.schema.d.ts +186 -0
  146. package/src/components/modal.schema.js +167 -0
  147. package/src/components/modal.schema.js.map +1 -0
  148. package/src/components/table.d.ts +105 -0
  149. package/src/components/table.js +283 -0
  150. package/src/components/table.js.map +1 -0
  151. package/src/components/table.schema.d.ts +159 -0
  152. package/src/components/table.schema.js +173 -0
  153. package/src/components/table.schema.js.map +1 -0
  154. package/src/handlebars/helpers.d.ts +348 -0
  155. package/src/handlebars/helpers.js +605 -0
  156. package/src/handlebars/helpers.js.map +1 -0
  157. package/src/handlebars/index.d.ts +193 -0
  158. package/src/handlebars/index.js +350 -0
  159. package/src/handlebars/index.js.map +1 -0
  160. package/src/index.d.ts +50 -0
  161. package/src/index.js +192 -0
  162. package/src/index.js.map +1 -0
  163. package/src/layouts/base.d.ts +88 -0
  164. package/src/layouts/base.js +227 -0
  165. package/src/layouts/base.js.map +1 -0
  166. package/src/layouts/index.d.ts +7 -0
  167. package/src/layouts/index.js +25 -0
  168. package/src/layouts/index.js.map +1 -0
  169. package/src/layouts/presets.d.ts +133 -0
  170. package/src/layouts/presets.js +277 -0
  171. package/src/layouts/presets.js.map +1 -0
  172. package/src/pages/consent.d.ts +116 -0
  173. package/src/pages/consent.js +218 -0
  174. package/src/pages/consent.js.map +1 -0
  175. package/src/pages/error.d.ts +100 -0
  176. package/src/pages/error.js +263 -0
  177. package/src/pages/error.js.map +1 -0
  178. package/src/pages/index.d.ts +8 -0
  179. package/src/pages/index.js +27 -0
  180. package/src/pages/index.js.map +1 -0
  181. package/src/react/Alert.d.ts +101 -0
  182. package/src/react/Alert.js +51 -0
  183. package/src/react/Alert.js.map +1 -0
  184. package/src/react/Badge.d.ts +100 -0
  185. package/src/react/Badge.js +55 -0
  186. package/src/react/Badge.js.map +1 -0
  187. package/src/react/Button.d.ts +108 -0
  188. package/src/react/Button.js +52 -0
  189. package/src/react/Button.js.map +1 -0
  190. package/src/react/Card.d.ts +103 -0
  191. package/src/react/Card.js +55 -0
  192. package/src/react/Card.js.map +1 -0
  193. package/src/react/hooks/context.d.ts +178 -0
  194. package/src/react/hooks/context.js +287 -0
  195. package/src/react/hooks/context.js.map +1 -0
  196. package/src/react/hooks/index.d.ts +41 -0
  197. package/src/react/hooks/index.js +61 -0
  198. package/src/react/hooks/index.js.map +1 -0
  199. package/src/react/hooks/tools.d.ts +283 -0
  200. package/src/react/hooks/tools.js +465 -0
  201. package/src/react/hooks/tools.js.map +1 -0
  202. package/src/react/index.d.ts +80 -0
  203. package/src/react/index.js +113 -0
  204. package/src/react/index.js.map +1 -0
  205. package/src/react/types.d.ts +105 -0
  206. package/src/react/types.js +12 -0
  207. package/src/react/types.js.map +1 -0
  208. package/src/react/utils.d.ts +42 -0
  209. package/src/react/utils.js +99 -0
  210. package/src/react/utils.js.map +1 -0
  211. package/src/registry/index.d.ts +45 -0
  212. package/src/registry/index.js +67 -0
  213. package/src/registry/index.js.map +1 -0
  214. package/src/registry/render-template.d.ts +86 -0
  215. package/src/registry/render-template.js +239 -0
  216. package/src/registry/render-template.js.map +1 -0
  217. package/src/registry/tool-ui.registry.d.ts +260 -0
  218. package/src/registry/tool-ui.registry.js +438 -0
  219. package/src/registry/tool-ui.registry.js.map +1 -0
  220. package/src/registry/uri-utils.d.ts +55 -0
  221. package/src/registry/uri-utils.js +97 -0
  222. package/src/registry/uri-utils.js.map +1 -0
  223. package/src/render/index.d.ts +7 -0
  224. package/src/render/index.js +14 -0
  225. package/src/render/index.js.map +1 -0
  226. package/src/render/prerender.d.ts +56 -0
  227. package/src/render/prerender.js +98 -0
  228. package/src/render/prerender.js.map +1 -0
  229. package/src/renderers/cache.d.ts +144 -0
  230. package/src/renderers/cache.js +240 -0
  231. package/src/renderers/cache.js.map +1 -0
  232. package/src/renderers/html.renderer.d.ts +122 -0
  233. package/src/renderers/html.renderer.js +204 -0
  234. package/src/renderers/html.renderer.js.map +1 -0
  235. package/src/renderers/index.d.ts +35 -0
  236. package/src/renderers/index.js +70 -0
  237. package/src/renderers/index.js.map +1 -0
  238. package/src/renderers/mdx.renderer.d.ts +119 -0
  239. package/src/renderers/mdx.renderer.js +305 -0
  240. package/src/renderers/mdx.renderer.js.map +1 -0
  241. package/src/renderers/react.renderer.d.ts +95 -0
  242. package/src/renderers/react.renderer.js +260 -0
  243. package/src/renderers/react.renderer.js.map +1 -0
  244. package/src/renderers/registry.d.ts +133 -0
  245. package/src/renderers/registry.js +232 -0
  246. package/src/renderers/registry.js.map +1 -0
  247. package/src/renderers/types.d.ts +341 -0
  248. package/src/renderers/types.js +9 -0
  249. package/src/renderers/types.js.map +1 -0
  250. package/src/renderers/utils/detect.d.ts +106 -0
  251. package/src/renderers/utils/detect.js +267 -0
  252. package/src/renderers/utils/detect.js.map +1 -0
  253. package/src/renderers/utils/hash.d.ts +39 -0
  254. package/src/renderers/utils/hash.js +75 -0
  255. package/src/renderers/utils/hash.js.map +1 -0
  256. package/src/renderers/utils/index.d.ts +8 -0
  257. package/src/renderers/utils/index.js +28 -0
  258. package/src/renderers/utils/index.js.map +1 -0
  259. package/src/renderers/utils/transpiler.d.ts +88 -0
  260. package/src/renderers/utils/transpiler.js +215 -0
  261. package/src/renderers/utils/transpiler.js.map +1 -0
  262. package/src/runtime/adapters/html.adapter.d.ts +58 -0
  263. package/src/runtime/adapters/html.adapter.js +131 -0
  264. package/src/runtime/adapters/html.adapter.js.map +1 -0
  265. package/src/runtime/adapters/index.d.ts +25 -0
  266. package/src/runtime/adapters/index.js +54 -0
  267. package/src/runtime/adapters/index.js.map +1 -0
  268. package/src/runtime/adapters/mdx.adapter.d.ts +72 -0
  269. package/src/runtime/adapters/mdx.adapter.js +241 -0
  270. package/src/runtime/adapters/mdx.adapter.js.map +1 -0
  271. package/src/runtime/adapters/react.adapter.d.ts +69 -0
  272. package/src/runtime/adapters/react.adapter.js +245 -0
  273. package/src/runtime/adapters/react.adapter.js.map +1 -0
  274. package/src/runtime/adapters/types.d.ts +94 -0
  275. package/src/runtime/adapters/types.js +11 -0
  276. package/src/runtime/adapters/types.js.map +1 -0
  277. package/src/runtime/csp.d.ts +37 -0
  278. package/src/runtime/csp.js +140 -0
  279. package/src/runtime/csp.js.map +1 -0
  280. package/src/runtime/index.d.ts +16 -0
  281. package/src/runtime/index.js +72 -0
  282. package/src/runtime/index.js.map +1 -0
  283. package/src/runtime/mcp-bridge.d.ts +100 -0
  284. package/src/runtime/mcp-bridge.js +581 -0
  285. package/src/runtime/mcp-bridge.js.map +1 -0
  286. package/src/runtime/renderer-runtime.d.ts +132 -0
  287. package/src/runtime/renderer-runtime.js +389 -0
  288. package/src/runtime/renderer-runtime.js.map +1 -0
  289. package/src/runtime/sanitizer.d.ts +171 -0
  290. package/src/runtime/sanitizer.js +318 -0
  291. package/src/runtime/sanitizer.js.map +1 -0
  292. package/src/runtime/types.d.ts +414 -0
  293. package/src/runtime/types.js +12 -0
  294. package/src/runtime/types.js.map +1 -0
  295. package/src/runtime/wrapper.d.ts +375 -0
  296. package/src/runtime/wrapper.js +1793 -0
  297. package/src/runtime/wrapper.js.map +1 -0
  298. package/src/styles/index.d.ts +7 -0
  299. package/src/styles/index.js +11 -0
  300. package/src/styles/index.js.map +1 -0
  301. package/src/styles/variants.d.ts +50 -0
  302. package/src/styles/variants.js +175 -0
  303. package/src/styles/variants.js.map +1 -0
  304. package/src/theme/cdn.d.ts +194 -0
  305. package/src/theme/cdn.js +375 -0
  306. package/src/theme/cdn.js.map +1 -0
  307. package/src/theme/index.d.ts +17 -0
  308. package/src/theme/index.js +57 -0
  309. package/src/theme/index.js.map +1 -0
  310. package/src/theme/platforms.d.ts +106 -0
  311. package/src/theme/platforms.js +161 -0
  312. package/src/theme/platforms.js.map +1 -0
  313. package/src/theme/presets/github-openai.d.ts +49 -0
  314. package/src/theme/presets/github-openai.js +189 -0
  315. package/src/theme/presets/github-openai.js.map +1 -0
  316. package/src/theme/presets/index.d.ts +10 -0
  317. package/src/theme/presets/index.js +17 -0
  318. package/src/theme/presets/index.js.map +1 -0
  319. package/src/theme/theme.d.ts +395 -0
  320. package/src/theme/theme.js +332 -0
  321. package/src/theme/theme.js.map +1 -0
  322. package/src/tool-template/builder.d.ts +212 -0
  323. package/src/tool-template/builder.js +397 -0
  324. package/src/tool-template/builder.js.map +1 -0
  325. package/src/tool-template/index.d.ts +15 -0
  326. package/src/tool-template/index.js +38 -0
  327. package/src/tool-template/index.js.map +1 -0
  328. package/src/types/index.d.ts +13 -0
  329. package/src/types/index.js +26 -0
  330. package/src/types/index.js.map +1 -0
  331. package/src/types/ui-config.d.ts +357 -0
  332. package/src/types/ui-config.js +12 -0
  333. package/src/types/ui-config.js.map +1 -0
  334. package/src/types/ui-runtime.d.ts +965 -0
  335. package/src/types/ui-runtime.js +117 -0
  336. package/src/types/ui-runtime.js.map +1 -0
  337. package/src/validation/error-box.d.ts +55 -0
  338. package/src/validation/error-box.js +75 -0
  339. package/src/validation/error-box.js.map +1 -0
  340. package/src/validation/index.d.ts +12 -0
  341. package/src/validation/index.js +21 -0
  342. package/src/validation/index.js.map +1 -0
  343. package/src/validation/wrapper.d.ts +96 -0
  344. package/src/validation/wrapper.js +117 -0
  345. package/src/validation/wrapper.js.map +1 -0
  346. package/src/web-components/core/attribute-parser.d.ts +85 -0
  347. package/src/web-components/core/attribute-parser.js +189 -0
  348. package/src/web-components/core/attribute-parser.js.map +1 -0
  349. package/src/web-components/core/base-element.d.ts +197 -0
  350. package/src/web-components/core/base-element.js +289 -0
  351. package/src/web-components/core/base-element.js.map +1 -0
  352. package/src/web-components/core/index.d.ts +8 -0
  353. package/src/web-components/core/index.js +18 -0
  354. package/src/web-components/core/index.js.map +1 -0
  355. package/src/web-components/elements/fmcp-alert.d.ts +45 -0
  356. package/src/web-components/elements/fmcp-alert.js +93 -0
  357. package/src/web-components/elements/fmcp-alert.js.map +1 -0
  358. package/src/web-components/elements/fmcp-badge.d.ts +46 -0
  359. package/src/web-components/elements/fmcp-badge.js +99 -0
  360. package/src/web-components/elements/fmcp-badge.js.map +1 -0
  361. package/src/web-components/elements/fmcp-button.d.ts +124 -0
  362. package/src/web-components/elements/fmcp-button.js +233 -0
  363. package/src/web-components/elements/fmcp-button.js.map +1 -0
  364. package/src/web-components/elements/fmcp-card.d.ts +52 -0
  365. package/src/web-components/elements/fmcp-card.js +115 -0
  366. package/src/web-components/elements/fmcp-card.js.map +1 -0
  367. package/src/web-components/elements/fmcp-input.d.ts +95 -0
  368. package/src/web-components/elements/fmcp-input.js +248 -0
  369. package/src/web-components/elements/fmcp-input.js.map +1 -0
  370. package/src/web-components/elements/fmcp-select.d.ts +99 -0
  371. package/src/web-components/elements/fmcp-select.js +243 -0
  372. package/src/web-components/elements/fmcp-select.js.map +1 -0
  373. package/src/web-components/elements/index.d.ts +12 -0
  374. package/src/web-components/elements/index.js +34 -0
  375. package/src/web-components/elements/index.js.map +1 -0
  376. package/src/web-components/index.d.ts +49 -0
  377. package/src/web-components/index.js +75 -0
  378. package/src/web-components/index.js.map +1 -0
  379. package/src/web-components/register.d.ts +56 -0
  380. package/src/web-components/register.js +80 -0
  381. package/src/web-components/register.js.map +1 -0
  382. package/src/web-components/types.d.ts +121 -0
  383. package/src/web-components/types.js +25 -0
  384. package/src/web-components/types.js.map +1 -0
  385. package/src/widgets/index.d.ts +7 -0
  386. package/src/widgets/index.js +24 -0
  387. package/src/widgets/index.js.map +1 -0
  388. package/src/widgets/progress.d.ts +132 -0
  389. package/src/widgets/progress.js +303 -0
  390. package/src/widgets/progress.js.map +1 -0
  391. package/src/widgets/resource.d.ts +162 -0
  392. package/src/widgets/resource.js +340 -0
  393. package/src/widgets/resource.js.map +1 -0
@@ -0,0 +1,239 @@
1
+ "use strict";
2
+ /**
3
+ * Template Rendering
4
+ *
5
+ * Executes tool UI templates with proper context and helpers.
6
+ * Supports sync rendering for HTML strings/template functions,
7
+ * async rendering for React components via SSR, and MDX rendering.
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.containsMdxSyntax = containsMdxSyntax;
13
+ exports.isReactComponent = isReactComponent;
14
+ exports.renderToolTemplate = renderToolTemplate;
15
+ exports.hasUIConfig = hasUIConfig;
16
+ exports.renderToolTemplateAsync = renderToolTemplateAsync;
17
+ const wrapper_1 = require("../runtime/wrapper");
18
+ /**
19
+ * Check if a string contains MDX syntax (Markdown + JSX).
20
+ *
21
+ * Looks for:
22
+ * - JSX component tags (PascalCase): `<Component />`
23
+ * - JS expressions: `{variable}` or `{items.map(...)}`
24
+ * - Import/export statements
25
+ * - Frontmatter: `---\n...\n---`
26
+ */
27
+ function containsMdxSyntax(source) {
28
+ // Has JSX component tags (PascalCase)
29
+ if (/<[A-Z][a-zA-Z0-9]*/.test(source)) {
30
+ return true;
31
+ }
32
+ // Has import/export statements (ESM)
33
+ if (/^(import|export)\s/m.test(source)) {
34
+ return true;
35
+ }
36
+ // Has JSX-specific attributes (className, onClick, etc.)
37
+ // These are only valid in JSX, not in regular HTML
38
+ if (/\s(className|onClick|onChange|onSubmit|htmlFor|dangerouslySetInnerHTML)=/.test(source)) {
39
+ return true;
40
+ }
41
+ // Has JS expressions in curly braces (not just HTML attributes)
42
+ if (/\{[^}"'\n]*\}/.test(source) && !/=\s*["'][^"']*\{/.test(source)) {
43
+ return true;
44
+ }
45
+ // Has frontmatter
46
+ if (/^---[\s\S]*?---/m.test(source)) {
47
+ return true;
48
+ }
49
+ // Has Markdown headers with JSX or expressions
50
+ if (/^#{1,6}\s.*\{.*\}/m.test(source)) {
51
+ return true;
52
+ }
53
+ // Has JSX fragments
54
+ if (/<>|<\/>/.test(source)) {
55
+ return true;
56
+ }
57
+ return false;
58
+ }
59
+ /**
60
+ * Render MDX content to HTML string.
61
+ *
62
+ * Uses the MDX renderer from @frontmcp/ui.
63
+ * Falls back to plain text if MDX rendering is not available.
64
+ */
65
+ async function renderMdxContent(mdxContent, context,
66
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
+ mdxComponents) {
68
+ try {
69
+ // Import the MDX renderer from renderers module
70
+ const { mdxRenderer } = await import('../renderers/index.js');
71
+ // Render MDX to HTML with custom components
72
+ const html = await mdxRenderer.render(mdxContent, context, { mdxComponents });
73
+ return html;
74
+ }
75
+ catch (error) {
76
+ // If MDX rendering fails, warn and return escaped content
77
+ console.error('[@frontmcp/ui] MDX rendering failed:', error instanceof Error ? error.stack || error.message : String(error));
78
+ // Return the raw MDX as escaped HTML (fallback)
79
+ const escaped = mdxContent.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
80
+ return `<pre class="mdx-fallback">${escaped}</pre>`;
81
+ }
82
+ }
83
+ /**
84
+ * Check if a template is a React component (not a template builder function).
85
+ *
86
+ * React components are distinguished from template builder functions by:
87
+ * - Having $$typeof symbol (React.memo, forwardRef, etc.)
88
+ * - Having prototype.isReactComponent (class components)
89
+ * - PascalCase naming convention (function components)
90
+ *
91
+ * Template builder functions take (ctx) and return a string, while
92
+ * React components take props and return JSX.Element.
93
+ */
94
+ function isReactComponent(template) {
95
+ if (typeof template !== 'function')
96
+ return false;
97
+ // Template builder functions take (ctx) and return string
98
+ // React components have different signatures
99
+ // Check for React component markers
100
+ const fn = template;
101
+ // React.memo, forwardRef, etc. have $$typeof
102
+ if (fn.$$typeof)
103
+ return true;
104
+ // Class components have prototype.isReactComponent
105
+ if (fn.prototype?.isReactComponent)
106
+ return true;
107
+ // Function components: PascalCase name convention
108
+ // This is a heuristic - function names starting with uppercase are likely React components
109
+ if (fn.name && /^[A-Z]/.test(fn.name))
110
+ return true;
111
+ return false;
112
+ }
113
+ /**
114
+ * Render a tool UI template.
115
+ *
116
+ * @param options - Template and context data
117
+ * @returns Rendered HTML string
118
+ * @throws Error if template execution fails
119
+ */
120
+ function renderToolTemplate(options) {
121
+ const { template, input, output, structuredContent } = options;
122
+ // If template is already a string, return it directly
123
+ if (typeof template === 'string') {
124
+ return template;
125
+ }
126
+ // Create template context with helpers
127
+ const ctx = {
128
+ input,
129
+ output,
130
+ structuredContent,
131
+ helpers: (0, wrapper_1.createTemplateHelpers)(),
132
+ };
133
+ // Execute the template function
134
+ try {
135
+ return template(ctx);
136
+ }
137
+ catch (error) {
138
+ const message = error instanceof Error ? error.message : String(error);
139
+ throw new Error(`Template rendering failed: ${message}`);
140
+ }
141
+ }
142
+ /**
143
+ * Check if a tool has UI configuration.
144
+ * Uses loose typing to handle variance issues with generic tool metadata.
145
+ */
146
+ function hasUIConfig(metadata) {
147
+ const ui = metadata.ui;
148
+ return ui !== undefined && ui.template !== undefined;
149
+ }
150
+ /**
151
+ * Render a tool UI template asynchronously.
152
+ *
153
+ * This version supports:
154
+ * - React components via SSR
155
+ * - MDX strings (Markdown + JSX) via @mdx-js/mdx
156
+ * - HTML strings and template builder functions
157
+ *
158
+ * For React components:
159
+ * - Dynamically imports react and react-dom/server
160
+ * - Uses renderToString for SSR
161
+ * - React components receive the template context as props
162
+ *
163
+ * For MDX templates:
164
+ * - Detects MDX syntax (Markdown headers, JSX components, expressions)
165
+ * - Compiles and renders via @frontmcp/ui's MDX renderer
166
+ *
167
+ * @param options - Template and context data
168
+ * @returns Promise resolving to rendered HTML string
169
+ * @throws Error if template execution or rendering fails
170
+ */
171
+ async function renderToolTemplateAsync(options) {
172
+ const { template, input, output, structuredContent, mdxComponents } = options;
173
+ // Create template context with helpers
174
+ const ctx = {
175
+ input,
176
+ output,
177
+ structuredContent,
178
+ helpers: (0, wrapper_1.createTemplateHelpers)(),
179
+ };
180
+ // If template is already a string, check if it's MDX
181
+ if (typeof template === 'string') {
182
+ if (containsMdxSyntax(template)) {
183
+ return renderMdxContent(template, ctx, mdxComponents);
184
+ }
185
+ return template;
186
+ }
187
+ // Check if it's a React component
188
+ if (isReactComponent(template)) {
189
+ // Get component name for error reporting
190
+ const componentName = template.displayName || template.name || 'UnknownComponent';
191
+ try {
192
+ // Dynamically import React and ReactDOMServer
193
+ // This allows UI package to work without React as a hard dependency
194
+ const [React, ReactDOMServer] = await Promise.all([
195
+ import('react').catch(() => {
196
+ throw new Error('React is required for React component templates. Install react as a dependency.');
197
+ }),
198
+ import('react-dom/server').catch(() => {
199
+ throw new Error('react-dom/server is required for React component templates. Install react-dom as a dependency.');
200
+ }),
201
+ ]);
202
+ // React components receive props, which is our context
203
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
204
+ const element = React.createElement(template, ctx);
205
+ return ReactDOMServer.renderToString(element);
206
+ }
207
+ catch (error) {
208
+ const errorMessage = error instanceof Error ? error.message : String(error);
209
+ const errorStack = error instanceof Error ? error.stack : undefined;
210
+ // Log detailed error for debugging
211
+ if (process.env['DEBUG'] || process.env['NODE_ENV'] === 'development') {
212
+ console.error('[FrontMCP] React SSR Error:', {
213
+ component: componentName,
214
+ error: errorMessage,
215
+ stack: errorStack,
216
+ propsKeys: Object.keys(ctx),
217
+ hasInput: 'input' in ctx,
218
+ hasOutput: 'output' in ctx,
219
+ hasStructuredContent: 'structuredContent' in ctx,
220
+ });
221
+ }
222
+ throw new Error(`React template rendering failed for "${componentName}": ${errorMessage}`);
223
+ }
224
+ }
225
+ // Execute as regular template builder function
226
+ try {
227
+ const result = template(ctx);
228
+ // Check if the result is an MDX string (template function returned MDX)
229
+ if (typeof result === 'string' && containsMdxSyntax(result)) {
230
+ return renderMdxContent(result, ctx, mdxComponents);
231
+ }
232
+ return result;
233
+ }
234
+ catch (error) {
235
+ const message = error instanceof Error ? error.message : String(error);
236
+ throw new Error(`Template rendering failed: ${message}`);
237
+ }
238
+ }
239
+ //# sourceMappingURL=render-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-template.js","sourceRoot":"","sources":["../../../src/registry/render-template.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Template Rendering\n *\n * Executes tool UI templates with proper context and helpers.\n * Supports sync rendering for HTML strings/template functions,\n * async rendering for React components via SSR, and MDX rendering.\n *\n * @packageDocumentation\n */\n\nimport type { UITemplateConfig, TemplateContext, TemplateBuilderFn } from '../types';\nimport { createTemplateHelpers } from '../runtime/wrapper';\n\n/**\n * Check if a string contains MDX syntax (Markdown + JSX).\n *\n * Looks for:\n * - JSX component tags (PascalCase): `<Component />`\n * - JS expressions: `{variable}` or `{items.map(...)}`\n * - Import/export statements\n * - Frontmatter: `---\\n...\\n---`\n */\nexport function containsMdxSyntax(source: string): boolean {\n // Has JSX component tags (PascalCase)\n if (/<[A-Z][a-zA-Z0-9]*/.test(source)) {\n return true;\n }\n\n // Has import/export statements (ESM)\n if (/^(import|export)\\s/m.test(source)) {\n return true;\n }\n\n // Has JSX-specific attributes (className, onClick, etc.)\n // These are only valid in JSX, not in regular HTML\n if (/\\s(className|onClick|onChange|onSubmit|htmlFor|dangerouslySetInnerHTML)=/.test(source)) {\n return true;\n }\n\n // Has JS expressions in curly braces (not just HTML attributes)\n if (/\\{[^}\"'\\n]*\\}/.test(source) && !/=\\s*[\"'][^\"']*\\{/.test(source)) {\n return true;\n }\n\n // Has frontmatter\n if (/^---[\\s\\S]*?---/m.test(source)) {\n return true;\n }\n\n // Has Markdown headers with JSX or expressions\n if (/^#{1,6}\\s.*\\{.*\\}/m.test(source)) {\n return true;\n }\n\n // Has JSX fragments\n if (/<>|<\\/>/.test(source)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Render MDX content to HTML string.\n *\n * Uses the MDX renderer from @frontmcp/ui.\n * Falls back to plain text if MDX rendering is not available.\n */\nasync function renderMdxContent<In, Out>(\n mdxContent: string,\n context: TemplateContext<In, Out>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mdxComponents?: Record<string, any>,\n): Promise<string> {\n try {\n // Import the MDX renderer from renderers module\n const { mdxRenderer } = await import('../renderers/index.js');\n\n // Render MDX to HTML with custom components\n const html = await mdxRenderer.render(mdxContent, context, { mdxComponents });\n return html;\n } catch (error) {\n // If MDX rendering fails, warn and return escaped content\n console.error(\n '[@frontmcp/ui] MDX rendering failed:',\n error instanceof Error ? error.stack || error.message : String(error),\n );\n\n // Return the raw MDX as escaped HTML (fallback)\n const escaped = mdxContent.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n return `<pre class=\"mdx-fallback\">${escaped}</pre>`;\n }\n}\n\n/**\n * Check if a template is a React component (not a template builder function).\n *\n * React components are distinguished from template builder functions by:\n * - Having $$typeof symbol (React.memo, forwardRef, etc.)\n * - Having prototype.isReactComponent (class components)\n * - PascalCase naming convention (function components)\n *\n * Template builder functions take (ctx) and return a string, while\n * React components take props and return JSX.Element.\n */\nexport function isReactComponent(template: unknown): boolean {\n if (typeof template !== 'function') return false;\n\n // Template builder functions take (ctx) and return string\n // React components have different signatures\n\n // Check for React component markers\n const fn = template as Function & {\n $$typeof?: symbol;\n displayName?: string;\n render?: Function;\n prototype?: { isReactComponent?: boolean };\n };\n\n // React.memo, forwardRef, etc. have $$typeof\n if (fn.$$typeof) return true;\n\n // Class components have prototype.isReactComponent\n if (fn.prototype?.isReactComponent) return true;\n\n // Function components: PascalCase name convention\n // This is a heuristic - function names starting with uppercase are likely React components\n if (fn.name && /^[A-Z]/.test(fn.name)) return true;\n\n return false;\n}\n\n/**\n * Options for rendering a tool template.\n */\nexport interface RenderTemplateOptions {\n /** The template configuration from the tool */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n template: TemplateBuilderFn<unknown, unknown> | string | ((props: any) => any);\n /** Tool input arguments */\n input: Record<string, unknown>;\n /** Tool output (raw result from execute) */\n output: unknown;\n /** Structured content parsed from output */\n structuredContent?: unknown;\n /** Custom MDX components to use in MDX templates */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mdxComponents?: Record<string, any>;\n}\n\n/**\n * Render a tool UI template.\n *\n * @param options - Template and context data\n * @returns Rendered HTML string\n * @throws Error if template execution fails\n */\nexport function renderToolTemplate(options: RenderTemplateOptions): string {\n const { template, input, output, structuredContent } = options;\n\n // If template is already a string, return it directly\n if (typeof template === 'string') {\n return template;\n }\n\n // Create template context with helpers\n const ctx: TemplateContext<Record<string, unknown>, unknown> = {\n input,\n output,\n structuredContent,\n helpers: createTemplateHelpers(),\n };\n\n // Execute the template function\n try {\n return template(ctx);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Template rendering failed: ${message}`);\n }\n}\n\n/**\n * Check if a tool has UI configuration.\n * Uses loose typing to handle variance issues with generic tool metadata.\n */\nexport function hasUIConfig(metadata: { ui?: unknown }): metadata is { ui: UITemplateConfig<unknown, unknown> } {\n const ui = metadata.ui as UITemplateConfig<unknown, unknown> | undefined;\n return ui !== undefined && ui.template !== undefined;\n}\n\n/**\n * Render a tool UI template asynchronously.\n *\n * This version supports:\n * - React components via SSR\n * - MDX strings (Markdown + JSX) via @mdx-js/mdx\n * - HTML strings and template builder functions\n *\n * For React components:\n * - Dynamically imports react and react-dom/server\n * - Uses renderToString for SSR\n * - React components receive the template context as props\n *\n * For MDX templates:\n * - Detects MDX syntax (Markdown headers, JSX components, expressions)\n * - Compiles and renders via @frontmcp/ui's MDX renderer\n *\n * @param options - Template and context data\n * @returns Promise resolving to rendered HTML string\n * @throws Error if template execution or rendering fails\n */\nexport async function renderToolTemplateAsync(options: RenderTemplateOptions): Promise<string> {\n const { template, input, output, structuredContent, mdxComponents } = options;\n\n // Create template context with helpers\n const ctx: TemplateContext<Record<string, unknown>, unknown> = {\n input,\n output,\n structuredContent,\n helpers: createTemplateHelpers(),\n };\n\n // If template is already a string, check if it's MDX\n if (typeof template === 'string') {\n if (containsMdxSyntax(template)) {\n return renderMdxContent(template, ctx, mdxComponents);\n }\n return template;\n }\n\n // Check if it's a React component\n if (isReactComponent(template)) {\n // Get component name for error reporting\n const componentName =\n (template as React.ComponentType).displayName || (template as React.ComponentType).name || 'UnknownComponent';\n\n try {\n // Dynamically import React and ReactDOMServer\n // This allows UI package to work without React as a hard dependency\n const [React, ReactDOMServer] = await Promise.all([\n import('react').catch(() => {\n throw new Error('React is required for React component templates. Install react as a dependency.');\n }),\n import('react-dom/server').catch(() => {\n throw new Error(\n 'react-dom/server is required for React component templates. Install react-dom as a dependency.',\n );\n }),\n ]);\n\n // React components receive props, which is our context\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const element = React.createElement(template as React.ComponentType<any>, ctx);\n return ReactDOMServer.renderToString(element);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n const errorStack = error instanceof Error ? error.stack : undefined;\n\n // Log detailed error for debugging\n if (process.env['DEBUG'] || process.env['NODE_ENV'] === 'development') {\n console.error('[FrontMCP] React SSR Error:', {\n component: componentName,\n error: errorMessage,\n stack: errorStack,\n propsKeys: Object.keys(ctx),\n hasInput: 'input' in ctx,\n hasOutput: 'output' in ctx,\n hasStructuredContent: 'structuredContent' in ctx,\n });\n }\n\n throw new Error(`React template rendering failed for \"${componentName}\": ${errorMessage}`);\n }\n }\n\n // Execute as regular template builder function\n try {\n const result = (template as TemplateBuilderFn<unknown, unknown>)(ctx);\n\n // Check if the result is an MDX string (template function returned MDX)\n if (typeof result === 'string' && containsMdxSyntax(result)) {\n return renderMdxContent(result, ctx, mdxComponents);\n }\n\n return result;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Template rendering failed: ${message}`);\n }\n}\n"]}
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Tool UI Registry
3
+ *
4
+ * Manages UI template rendering for tool responses.
5
+ * Provides platform-specific metadata generation for MCP clients.
6
+ *
7
+ * Three serving modes:
8
+ * - **inline**: HTML is rendered per-request and embedded in _meta['ui/html']
9
+ * - **static**: Static widget is pre-compiled at startup, client fetches via resources/read
10
+ * - **hybrid**: Shell (React + renderer) cached at startup, component + data in response
11
+ *
12
+ * @packageDocumentation
13
+ */
14
+ import type { UITemplateConfig, WidgetManifest, BuildManifestResult } from '../types';
15
+ import type { AIPlatformType, UIMetadata } from '../adapters';
16
+ /**
17
+ * Options for renderAndRegisterAsync (inline mode).
18
+ */
19
+ export interface RenderOptions {
20
+ /** Tool name */
21
+ toolName: string;
22
+ /** Unique request identifier */
23
+ requestId: string;
24
+ /** Tool input arguments */
25
+ input: Record<string, unknown>;
26
+ /** Raw tool output */
27
+ output: unknown;
28
+ /** Structured content (parsed from output) */
29
+ structuredContent?: unknown;
30
+ /** Tool UI configuration */
31
+ uiConfig: UITemplateConfig;
32
+ /** Detected platform type */
33
+ platformType: AIPlatformType;
34
+ /** Widget access token (optional) */
35
+ token?: string;
36
+ /** Direct URL for widget serving (optional) */
37
+ directUrl?: string;
38
+ }
39
+ /**
40
+ * Result of rendering UI for inline mode.
41
+ */
42
+ export interface UIRenderResult {
43
+ /** Rendered HTML content */
44
+ html: string;
45
+ /** Platform-specific metadata for _meta field */
46
+ meta: UIMetadata;
47
+ }
48
+ /**
49
+ * ToolUIRegistry manages UI template rendering for tool responses.
50
+ *
51
+ * It provides:
52
+ * - Static widget compilation for static mode (pre-compiled at startup)
53
+ * - Per-request HTML rendering for inline mode (embedded in _meta)
54
+ * - Platform-specific _meta generation
55
+ * - Widget manifest management
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const registry = new ToolUIRegistry();
60
+ *
61
+ * // For inline mode: render HTML per-request
62
+ * const result = await registry.renderAndRegisterAsync({
63
+ * toolName: 'get_weather',
64
+ * requestId: 'abc123',
65
+ * input: { location: 'London' },
66
+ * output: { temp: 72, conditions: 'Sunny' },
67
+ * uiConfig: tool.metadata.ui,
68
+ * platformType: 'openai',
69
+ * });
70
+ *
71
+ * // result.meta can be spread into tool result _meta
72
+ * return { content: [...], _meta: { ...result.meta } };
73
+ * ```
74
+ */
75
+ /**
76
+ * Options for compiling a static widget.
77
+ */
78
+ export interface CompileStaticWidgetOptions {
79
+ /** Tool name (used for cache key and URI) */
80
+ toolName: string;
81
+ /** The template to compile (React component, HTML string, or builder function) */
82
+ template: UITemplateConfig['template'];
83
+ /** Tool UI configuration */
84
+ uiConfig: UITemplateConfig;
85
+ }
86
+ /**
87
+ * Payload for hybrid mode component delivery.
88
+ * Sent in `_meta['ui/component']` at tool call time.
89
+ */
90
+ export interface HybridComponentPayload {
91
+ /** Transpiled component JavaScript code (ES module format) */
92
+ code: string;
93
+ /** Renderer type for the component */
94
+ type: 'react' | 'mdx' | 'html';
95
+ /** Tool name for identification */
96
+ toolName: string;
97
+ /** Content hash for cache validation */
98
+ hash: string;
99
+ }
100
+ /**
101
+ * Options for building a hybrid component payload.
102
+ */
103
+ export interface BuildHybridComponentPayloadOptions {
104
+ /** Tool name */
105
+ toolName: string;
106
+ /** The template to transpile */
107
+ template: UITemplateConfig['template'];
108
+ /** Tool UI configuration */
109
+ uiConfig: UITemplateConfig;
110
+ }
111
+ export declare class ToolUIRegistry {
112
+ /**
113
+ * Cache for static widgets (keyed by tool name).
114
+ * Static widgets are pre-compiled at server startup for tools with servingMode: 'static'.
115
+ * These widgets read data from the FrontMCP Bridge at runtime (window.openai.toolOutput).
116
+ */
117
+ private readonly staticWidgetCache;
118
+ /**
119
+ * Cache for widget manifests (keyed by tool name).
120
+ * Manifests describe the widget's renderer type, CSP, and other metadata.
121
+ */
122
+ private readonly manifestCache;
123
+ /**
124
+ * Cache for build results (keyed by tool name).
125
+ * Includes HTML, manifest, and hash for cache validation.
126
+ */
127
+ private readonly buildResultCache;
128
+ /**
129
+ * Compile a static widget template for a tool at server startup.
130
+ *
131
+ * For tools with `servingMode: 'static'`, the widget HTML is pre-compiled
132
+ * WITHOUT embedded data. The widget reads data from the FrontMCP Bridge at runtime
133
+ * (via window.openai.toolOutput or window.__frontmcp.toolOutput).
134
+ *
135
+ * This is called during tool registration, not during tool calls.
136
+ *
137
+ * @param options - Static widget compilation options
138
+ */
139
+ compileStaticWidgetAsync(options: CompileStaticWidgetOptions): Promise<void>;
140
+ /**
141
+ * Compile a lean widget shell for inline mode tools at server startup.
142
+ *
143
+ * For tools with `servingMode: 'inline'`, we create a minimal HTML shell that:
144
+ * - Contains only HTML structure, theme CSS, and fonts
145
+ * - NO React runtime, NO component code, NO bridge
146
+ * - OpenAI caches this at discovery time
147
+ * - The actual React widget comes in each tool response with embedded data
148
+ *
149
+ * @param options - Options for lean widget compilation
150
+ */
151
+ compileLeanWidgetAsync(options: {
152
+ toolName: string;
153
+ uiConfig: UITemplateConfig;
154
+ }): void;
155
+ /**
156
+ * Compile a hybrid widget shell at server startup.
157
+ *
158
+ * For tools with `servingMode: 'hybrid'`, we create a shell that:
159
+ * - Contains React 19 runtime from esm.sh CDN
160
+ * - Contains FrontMCP Bridge (universal)
161
+ * - Contains all FrontMCP hooks (useMcpBridgeContext, useToolOutput, etc.)
162
+ * - Contains all FrontMCP UI components (Card, Badge, Button)
163
+ * - Contains dynamic renderer script that imports components via blob URL
164
+ * - NO component code (comes at tool call time via `_meta['ui/component']`)
165
+ *
166
+ * The shell listens for `ui/component` in tool response metadata and dynamically
167
+ * imports the transpiled component code, then renders it with tool output data.
168
+ *
169
+ * @param options - Options for hybrid widget compilation
170
+ */
171
+ compileHybridWidgetAsync(options: {
172
+ toolName: string;
173
+ uiConfig: UITemplateConfig;
174
+ }): void;
175
+ /**
176
+ * Build a component payload for hybrid mode tool responses.
177
+ *
178
+ * For tools with `servingMode: 'hybrid'`, this method is called at tool call time
179
+ * to build the transpiled component code that gets delivered in `_meta['ui/component']`.
180
+ *
181
+ * The component code is in ES module format so it can be dynamically imported
182
+ * via blob URL in the hybrid shell's renderer.
183
+ *
184
+ * @param options - Options for building the component payload
185
+ * @returns The hybrid component payload, or undefined if template is not a function
186
+ */
187
+ buildHybridComponentPayload(options: BuildHybridComponentPayloadOptions): HybridComponentPayload | undefined;
188
+ /**
189
+ * Get the pre-compiled static widget HTML for a tool.
190
+ *
191
+ * @param toolName - The tool name to look up
192
+ * @returns Pre-compiled widget HTML, or undefined if not cached
193
+ */
194
+ getStaticWidget(toolName: string): string | undefined;
195
+ /**
196
+ * Check if a tool has a pre-compiled static widget.
197
+ *
198
+ * @param toolName - The tool name to check
199
+ * @returns true if the tool has a cached static widget
200
+ */
201
+ hasStaticWidget(toolName: string): boolean;
202
+ /**
203
+ * Get the widget manifest for a tool.
204
+ *
205
+ * @param toolName - The tool name to look up
206
+ * @returns Widget manifest, or undefined if not cached
207
+ */
208
+ getManifest(toolName: string): WidgetManifest | undefined;
209
+ /**
210
+ * Check if a tool has a cached manifest.
211
+ *
212
+ * @param toolName - The tool name to check
213
+ * @returns true if the tool has a cached manifest
214
+ */
215
+ hasManifest(toolName: string): boolean;
216
+ /**
217
+ * Get the full build result for a tool.
218
+ *
219
+ * @param toolName - The tool name to look up
220
+ * @returns Build result, or undefined if not cached
221
+ */
222
+ getBuildResult(toolName: string): BuildManifestResult | undefined;
223
+ /**
224
+ * Detect the UI type for a template.
225
+ *
226
+ * @param template - The template to analyze
227
+ * @returns Detected UI type
228
+ */
229
+ detectUIType(template: UITemplateConfig['template']): string;
230
+ /**
231
+ * Render a tool's UI template for inline mode.
232
+ *
233
+ * This version supports all template types including React components.
234
+ * The rendered HTML is embedded directly in _meta['ui/html'] for the client.
235
+ *
236
+ * For React/MDX components, the output is wrapped using wrapStaticWidgetUniversal
237
+ * which includes the React 19 CDN, client-side rendering script, and all the
238
+ * FrontMCP hooks/components. This provides the same rendering capability as
239
+ * static mode, but with data embedded in each response.
240
+ *
241
+ * @param options - Rendering options
242
+ * @returns Promise resolving to render result with HTML and metadata
243
+ */
244
+ renderAndRegisterAsync(options: RenderOptions): Promise<UIRenderResult>;
245
+ /**
246
+ * Build component code string for embedding in widget HTML.
247
+ *
248
+ * @param template - The React component
249
+ * @param toolName - Tool name for naming the component
250
+ * @returns JavaScript code string that defines and registers the component
251
+ */
252
+ private buildComponentCode;
253
+ /**
254
+ * Check if a template requires async rendering (e.g., React components).
255
+ *
256
+ * @param template - The template to check
257
+ * @returns true if the template requires async rendering
258
+ */
259
+ requiresAsyncRendering(template: UITemplateConfig['template']): boolean;
260
+ }