@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,305 @@
1
+ "use strict";
2
+ /**
3
+ * MDX Renderer
4
+ *
5
+ * Handles MDX templates - Markdown with embedded JSX components.
6
+ * Uses @mdx-js/mdx for compilation and react-dom/server for SSR.
7
+ *
8
+ * MDX allows mixing Markdown with React components:
9
+ * - Markdown headings, lists, code blocks
10
+ * - JSX component tags: `<Card />`
11
+ * - JS expressions: `{output.items.map(...)}`
12
+ * - Frontmatter for metadata
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.mdxRenderer = exports.MdxRenderer = void 0;
16
+ exports.buildMdxHydrationScript = buildMdxHydrationScript;
17
+ const detect_1 = require("./utils/detect");
18
+ const hash_1 = require("./utils/hash");
19
+ const cache_1 = require("./cache");
20
+ /**
21
+ * Runtime CDN URLs (same as React since MDX compiles to React).
22
+ */
23
+ const REACT_CDN = {
24
+ react: 'https://unpkg.com/react@18/umd/react.production.min.js',
25
+ reactDom: 'https://unpkg.com/react-dom@18/umd/react-dom.production.min.js',
26
+ };
27
+ /**
28
+ * Placeholder for blocked-network platforms.
29
+ */
30
+ const INLINE_MDX_PLACEHOLDER = `
31
+ // MDX runtime not available inline yet.
32
+ // For blocked-network platforms, use pre-rendered HTML templates.
33
+ console.warn('[FrontMCP] MDX hydration not available on this platform.');
34
+ `;
35
+ /**
36
+ * MDX Renderer Implementation.
37
+ *
38
+ * Compiles MDX (Markdown + JSX) to React components using @mdx-js/mdx,
39
+ * then renders to HTML using react-dom/server.
40
+ *
41
+ * @example Basic MDX template
42
+ * ```typescript
43
+ * @Tool({
44
+ * ui: {
45
+ * template: `
46
+ * # User Profile
47
+ *
48
+ * <UserCard name={output.name} email={output.email} />
49
+ *
50
+ * ## Recent Activity
51
+ * {output.items.map(item => <ActivityItem key={item.id} {...item} />)}
52
+ * `,
53
+ * mdxComponents: { UserCard, ActivityItem }
54
+ * }
55
+ * })
56
+ * ```
57
+ *
58
+ * @example MDX with frontmatter
59
+ * ```typescript
60
+ * @Tool({
61
+ * ui: {
62
+ * template: `
63
+ * ---
64
+ * title: Dashboard
65
+ * ---
66
+ *
67
+ * # {frontmatter.title}
68
+ *
69
+ * <Dashboard data={output} />
70
+ * `
71
+ * }
72
+ * })
73
+ * ```
74
+ */
75
+ class MdxRenderer {
76
+ type = 'mdx';
77
+ priority = 10; // Between HTML (0) and React (20)
78
+ /**
79
+ * Lazy-loaded modules.
80
+ */
81
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
82
+ React = null;
83
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
84
+ ReactDOMServer = null;
85
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
86
+ jsxRuntime = null;
87
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
88
+ mdxEvaluate = null;
89
+ /**
90
+ * Check if this renderer can handle the given template.
91
+ *
92
+ * Accepts strings containing MDX syntax (Markdown + JSX).
93
+ */
94
+ canHandle(template) {
95
+ if (typeof template !== 'string') {
96
+ return false;
97
+ }
98
+ return (0, detect_1.containsMdxSyntax)(template);
99
+ }
100
+ /**
101
+ * Transpile MDX to executable JavaScript.
102
+ *
103
+ * Uses @mdx-js/mdx to compile MDX source to a module.
104
+ * Note: For MDX, we use evaluate() which combines compile + run,
105
+ * so this method just returns the source hash for caching purposes.
106
+ */
107
+ async transpile(template, _options) {
108
+ const hash = (0, hash_1.hashString)(template);
109
+ // Check cache - for MDX, the "code" is just the original source
110
+ // since we use evaluate() which handles compilation internally
111
+ const cached = cache_1.transpileCache.getByKey(hash);
112
+ if (cached) {
113
+ return { ...cached, cached: true };
114
+ }
115
+ const transpileResult = {
116
+ code: template, // Store original MDX for evaluate()
117
+ hash,
118
+ cached: false,
119
+ };
120
+ // Cache the result
121
+ cache_1.transpileCache.setByKey(hash, transpileResult);
122
+ return transpileResult;
123
+ }
124
+ /**
125
+ * Render MDX template to HTML string.
126
+ *
127
+ * Uses @mdx-js/mdx's evaluate() for clean compilation + execution,
128
+ * then renders the resulting React component to HTML via SSR.
129
+ */
130
+ async render(template, context, options) {
131
+ // Ensure dependencies are loaded
132
+ await this.loadReact();
133
+ await this.loadMdx();
134
+ if (!this.mdxEvaluate) {
135
+ throw new Error('MDX compilation requires @mdx-js/mdx. Install it: npm install @mdx-js/mdx');
136
+ }
137
+ // Create a cache key based on the template hash
138
+ const templateHash = (0, hash_1.hashString)(template);
139
+ const cacheKey = `mdx-component:${templateHash}`;
140
+ // Check component cache
141
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
142
+ let Content = cache_1.componentCache.get(cacheKey);
143
+ if (!Content) {
144
+ // Evaluate MDX source to get the component
145
+ // evaluate() combines compile + run in one step
146
+ const result = await this.mdxEvaluate(template, {
147
+ ...this.jsxRuntime,
148
+ Fragment: this.React.Fragment,
149
+ development: false,
150
+ });
151
+ Content = result.default;
152
+ // Cache the compiled component
153
+ cache_1.componentCache.set(cacheKey, Content);
154
+ }
155
+ // Build component map with custom MDX components
156
+ const mdxComponents = {
157
+ // User-provided components from tool config
158
+ ...options?.mdxComponents,
159
+ // Wrapper that provides context to the content
160
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
161
+ wrapper: ({ children }) => {
162
+ return this.React.createElement('div', { className: 'mdx-content' }, children);
163
+ },
164
+ };
165
+ // Create props that MDX can access
166
+ // These become available in MDX as {props.input}, {props.output}, etc.
167
+ const props = {
168
+ input: context.input,
169
+ output: context.output,
170
+ structuredContent: context.structuredContent,
171
+ helpers: context.helpers,
172
+ };
173
+ // Also spread output properties at top level for convenience
174
+ // This allows accessing {output.name} or just {name} in MDX
175
+ const spreadProps = {
176
+ ...props,
177
+ ...(typeof context.output === 'object' && context.output !== null ? context.output : {}),
178
+ };
179
+ // Create the element with components and props
180
+ const element = this.React.createElement(Content, {
181
+ components: mdxComponents,
182
+ ...spreadProps,
183
+ });
184
+ // Render to HTML
185
+ const html = this.ReactDOMServer.renderToString(element);
186
+ // If hydration is enabled, wrap with markers
187
+ if (options?.hydrate) {
188
+ // Full HTML attribute escaping to prevent XSS
189
+ const escapedProps = JSON.stringify(props)
190
+ .replace(/&/g, '&amp;')
191
+ .replace(/'/g, '&#39;')
192
+ .replace(/</g, '&lt;')
193
+ .replace(/>/g, '&gt;');
194
+ return `<div data-mdx-hydrate="true" data-props='${escapedProps}'>${html}</div>`;
195
+ }
196
+ return html;
197
+ }
198
+ /**
199
+ * Get runtime scripts for client-side functionality.
200
+ */
201
+ getRuntimeScripts(platform) {
202
+ // For blocked-network platforms (Claude), scripts must be inline
203
+ if (platform.networkMode === 'blocked') {
204
+ return {
205
+ headScripts: '',
206
+ inlineScripts: INLINE_MDX_PLACEHOLDER,
207
+ isInline: true,
208
+ };
209
+ }
210
+ // For platforms with network access, use CDN (React required for MDX)
211
+ return {
212
+ headScripts: `
213
+ <script crossorigin src="${REACT_CDN.react}"></script>
214
+ <script crossorigin src="${REACT_CDN.reactDom}"></script>
215
+ `,
216
+ isInline: false,
217
+ };
218
+ }
219
+ /**
220
+ * Load React and ReactDOMServer modules.
221
+ */
222
+ async loadReact() {
223
+ if (this.React && this.ReactDOMServer && this.jsxRuntime) {
224
+ return;
225
+ }
226
+ try {
227
+ const [react, reactDomServer, jsxRuntime] = await Promise.all([
228
+ import('react'),
229
+ import('react-dom/server'),
230
+ import('react/jsx-runtime'),
231
+ ]);
232
+ this.React = react;
233
+ this.ReactDOMServer = reactDomServer;
234
+ this.jsxRuntime = jsxRuntime;
235
+ }
236
+ catch {
237
+ throw new Error('React is required for MdxRenderer. Install react and react-dom: npm install react react-dom');
238
+ }
239
+ }
240
+ /**
241
+ * Load @mdx-js/mdx evaluate function.
242
+ *
243
+ * evaluate() is the cleanest way to run MDX - it combines
244
+ * compile and run in a single step, handling all the runtime
245
+ * injection automatically.
246
+ */
247
+ async loadMdx() {
248
+ if (this.mdxEvaluate) {
249
+ return;
250
+ }
251
+ try {
252
+ const mdx = await import('@mdx-js/mdx');
253
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
254
+ this.mdxEvaluate = mdx.evaluate;
255
+ }
256
+ catch {
257
+ console.warn('[@frontmcp/ui] @mdx-js/mdx not available. MDX rendering disabled. ' +
258
+ 'Install @mdx-js/mdx to enable: npm install @mdx-js/mdx');
259
+ }
260
+ }
261
+ }
262
+ exports.MdxRenderer = MdxRenderer;
263
+ /**
264
+ * Singleton instance of the MDX renderer.
265
+ */
266
+ exports.mdxRenderer = new MdxRenderer();
267
+ /**
268
+ * Build MDX hydration script for client-side interactivity.
269
+ *
270
+ * Note: MDX hydration is more complex than React hydration
271
+ * because it needs the MDX runtime and component definitions.
272
+ */
273
+ function buildMdxHydrationScript() {
274
+ return `
275
+ <script>
276
+ (function() {
277
+ // MDX hydration requires React and component definitions
278
+ if (typeof React === 'undefined' || typeof ReactDOM === 'undefined') {
279
+ console.warn('[FrontMCP] React not available for MDX hydration');
280
+ return;
281
+ }
282
+
283
+ // Find all elements marked for MDX hydration
284
+ document.querySelectorAll('[data-mdx-hydrate]').forEach(function(root) {
285
+ var propsJson = root.getAttribute('data-props');
286
+ var props = propsJson ? JSON.parse(propsJson) : {};
287
+
288
+ // MDX content is pre-rendered, hydration mainly attaches event handlers
289
+ // For full interactivity, components need to be available client-side
290
+ if (window.__frontmcp_mdx_content) {
291
+ try {
292
+ ReactDOM.hydrateRoot(root, React.createElement(
293
+ window.__frontmcp_mdx_content,
294
+ props
295
+ ));
296
+ } catch (e) {
297
+ console.error('[FrontMCP] MDX hydration failed', e);
298
+ }
299
+ }
300
+ });
301
+ })();
302
+ </script>
303
+ `;
304
+ }
305
+ //# sourceMappingURL=mdx.renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mdx.renderer.js","sourceRoot":"","sources":["../../../src/renderers/mdx.renderer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MDX Renderer\n *\n * Handles MDX templates - Markdown with embedded JSX components.\n * Uses @mdx-js/mdx for compilation and react-dom/server for SSR.\n *\n * MDX allows mixing Markdown with React components:\n * - Markdown headings, lists, code blocks\n * - JSX component tags: `<Card />`\n * - JS expressions: `{output.items.map(...)}`\n * - Frontmatter for metadata\n */\n\nimport type { TemplateContext } from '../runtime/types';\nimport type { PlatformCapabilities } from '../theme';\nimport type {\n UIRenderer,\n TranspileResult,\n TranspileOptions,\n RenderOptions,\n RuntimeScripts,\n ToolUIProps,\n} from './types';\nimport { containsMdxSyntax } from './utils/detect';\nimport { hashString } from './utils/hash';\nimport { transpileCache, componentCache } from './cache';\n\n/**\n * Types this renderer can handle - MDX strings.\n */\ntype MdxTemplate = string;\n\n/**\n * Runtime CDN URLs (same as React since MDX compiles to React).\n */\nconst REACT_CDN = {\n react: 'https://unpkg.com/react@18/umd/react.production.min.js',\n reactDom: 'https://unpkg.com/react-dom@18/umd/react-dom.production.min.js',\n};\n\n/**\n * Placeholder for blocked-network platforms.\n */\nconst INLINE_MDX_PLACEHOLDER = `\n// MDX runtime not available inline yet.\n// For blocked-network platforms, use pre-rendered HTML templates.\nconsole.warn('[FrontMCP] MDX hydration not available on this platform.');\n`;\n\n/**\n * MDX Renderer Implementation.\n *\n * Compiles MDX (Markdown + JSX) to React components using @mdx-js/mdx,\n * then renders to HTML using react-dom/server.\n *\n * @example Basic MDX template\n * ```typescript\n * @Tool({\n * ui: {\n * template: `\n * # User Profile\n *\n * <UserCard name={output.name} email={output.email} />\n *\n * ## Recent Activity\n * {output.items.map(item => <ActivityItem key={item.id} {...item} />)}\n * `,\n * mdxComponents: { UserCard, ActivityItem }\n * }\n * })\n * ```\n *\n * @example MDX with frontmatter\n * ```typescript\n * @Tool({\n * ui: {\n * template: `\n * ---\n * title: Dashboard\n * ---\n *\n * # {frontmatter.title}\n *\n * <Dashboard data={output} />\n * `\n * }\n * })\n * ```\n */\nexport class MdxRenderer implements UIRenderer<MdxTemplate> {\n readonly type = 'mdx' as const;\n readonly priority = 10; // Between HTML (0) and React (20)\n\n /**\n * Lazy-loaded modules.\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private React: any = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private ReactDOMServer: any = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private jsxRuntime: any = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private mdxEvaluate: ((source: string, options: object) => Promise<{ default: any }>) | null = null;\n\n /**\n * Check if this renderer can handle the given template.\n *\n * Accepts strings containing MDX syntax (Markdown + JSX).\n */\n canHandle(template: unknown): template is MdxTemplate {\n if (typeof template !== 'string') {\n return false;\n }\n\n return containsMdxSyntax(template);\n }\n\n /**\n * Transpile MDX to executable JavaScript.\n *\n * Uses @mdx-js/mdx to compile MDX source to a module.\n * Note: For MDX, we use evaluate() which combines compile + run,\n * so this method just returns the source hash for caching purposes.\n */\n async transpile(template: MdxTemplate, _options?: TranspileOptions): Promise<TranspileResult> {\n const hash = hashString(template);\n\n // Check cache - for MDX, the \"code\" is just the original source\n // since we use evaluate() which handles compilation internally\n const cached = transpileCache.getByKey(hash);\n if (cached) {\n return { ...cached, cached: true };\n }\n\n const transpileResult: TranspileResult = {\n code: template, // Store original MDX for evaluate()\n hash,\n cached: false,\n };\n\n // Cache the result\n transpileCache.setByKey(hash, transpileResult);\n\n return transpileResult;\n }\n\n /**\n * Render MDX template to HTML string.\n *\n * Uses @mdx-js/mdx's evaluate() for clean compilation + execution,\n * then renders the resulting React component to HTML via SSR.\n */\n async render<In, Out>(\n template: MdxTemplate,\n context: TemplateContext<In, Out>,\n options?: RenderOptions,\n ): Promise<string> {\n // Ensure dependencies are loaded\n await this.loadReact();\n await this.loadMdx();\n\n if (!this.mdxEvaluate) {\n throw new Error('MDX compilation requires @mdx-js/mdx. Install it: npm install @mdx-js/mdx');\n }\n\n // Create a cache key based on the template hash\n const templateHash = hashString(template);\n const cacheKey = `mdx-component:${templateHash}`;\n\n // Check component cache\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let Content: any = componentCache.get(cacheKey);\n\n if (!Content) {\n // Evaluate MDX source to get the component\n // evaluate() combines compile + run in one step\n const result = await this.mdxEvaluate(template, {\n ...this.jsxRuntime,\n Fragment: this.React.Fragment,\n development: false,\n });\n\n Content = result.default;\n\n // Cache the compiled component\n componentCache.set(cacheKey, Content);\n }\n\n // Build component map with custom MDX components\n const mdxComponents = {\n // User-provided components from tool config\n ...options?.mdxComponents,\n // Wrapper that provides context to the content\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n wrapper: ({ children }: { children: any }) => {\n return this.React.createElement('div', { className: 'mdx-content' }, children);\n },\n };\n\n // Create props that MDX can access\n // These become available in MDX as {props.input}, {props.output}, etc.\n const props: ToolUIProps<In, Out> = {\n input: context.input,\n output: context.output,\n structuredContent: context.structuredContent,\n helpers: context.helpers,\n };\n\n // Also spread output properties at top level for convenience\n // This allows accessing {output.name} or just {name} in MDX\n const spreadProps = {\n ...props,\n ...(typeof context.output === 'object' && context.output !== null ? context.output : {}),\n };\n\n // Create the element with components and props\n const element = this.React.createElement(Content, {\n components: mdxComponents,\n ...spreadProps,\n });\n\n // Render to HTML\n const html = this.ReactDOMServer.renderToString(element);\n\n // If hydration is enabled, wrap with markers\n if (options?.hydrate) {\n // Full HTML attribute escaping to prevent XSS\n const escapedProps = JSON.stringify(props)\n .replace(/&/g, '&amp;')\n .replace(/'/g, '&#39;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n return `<div data-mdx-hydrate=\"true\" data-props='${escapedProps}'>${html}</div>`;\n }\n\n return html;\n }\n\n /**\n * Get runtime scripts for client-side functionality.\n */\n getRuntimeScripts(platform: PlatformCapabilities): RuntimeScripts {\n // For blocked-network platforms (Claude), scripts must be inline\n if (platform.networkMode === 'blocked') {\n return {\n headScripts: '',\n inlineScripts: INLINE_MDX_PLACEHOLDER,\n isInline: true,\n };\n }\n\n // For platforms with network access, use CDN (React required for MDX)\n return {\n headScripts: `\n <script crossorigin src=\"${REACT_CDN.react}\"></script>\n <script crossorigin src=\"${REACT_CDN.reactDom}\"></script>\n `,\n isInline: false,\n };\n }\n\n /**\n * Load React and ReactDOMServer modules.\n */\n private async loadReact(): Promise<void> {\n if (this.React && this.ReactDOMServer && this.jsxRuntime) {\n return;\n }\n\n try {\n const [react, reactDomServer, jsxRuntime] = await Promise.all([\n import('react'),\n import('react-dom/server'),\n import('react/jsx-runtime'),\n ]);\n\n this.React = react;\n this.ReactDOMServer = reactDomServer;\n this.jsxRuntime = jsxRuntime;\n } catch {\n throw new Error('React is required for MdxRenderer. Install react and react-dom: npm install react react-dom');\n }\n }\n\n /**\n * Load @mdx-js/mdx evaluate function.\n *\n * evaluate() is the cleanest way to run MDX - it combines\n * compile and run in a single step, handling all the runtime\n * injection automatically.\n */\n private async loadMdx(): Promise<void> {\n if (this.mdxEvaluate) {\n return;\n }\n\n try {\n const mdx = await import('@mdx-js/mdx');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this.mdxEvaluate = mdx.evaluate as any;\n } catch {\n console.warn(\n '[@frontmcp/ui] @mdx-js/mdx not available. MDX rendering disabled. ' +\n 'Install @mdx-js/mdx to enable: npm install @mdx-js/mdx',\n );\n }\n }\n}\n\n/**\n * Singleton instance of the MDX renderer.\n */\nexport const mdxRenderer = new MdxRenderer();\n\n/**\n * Build MDX hydration script for client-side interactivity.\n *\n * Note: MDX hydration is more complex than React hydration\n * because it needs the MDX runtime and component definitions.\n */\nexport function buildMdxHydrationScript(): string {\n return `\n<script>\n(function() {\n // MDX hydration requires React and component definitions\n if (typeof React === 'undefined' || typeof ReactDOM === 'undefined') {\n console.warn('[FrontMCP] React not available for MDX hydration');\n return;\n }\n\n // Find all elements marked for MDX hydration\n document.querySelectorAll('[data-mdx-hydrate]').forEach(function(root) {\n var propsJson = root.getAttribute('data-props');\n var props = propsJson ? JSON.parse(propsJson) : {};\n\n // MDX content is pre-rendered, hydration mainly attaches event handlers\n // For full interactivity, components need to be available client-side\n if (window.__frontmcp_mdx_content) {\n try {\n ReactDOM.hydrateRoot(root, React.createElement(\n window.__frontmcp_mdx_content,\n props\n ));\n } catch (e) {\n console.error('[FrontMCP] MDX hydration failed', e);\n }\n }\n });\n})();\n</script>\n`;\n}\n"]}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * React Renderer
3
+ *
4
+ * Handles React component templates:
5
+ * - Imported React components (already transpiled)
6
+ * - JSX string templates (transpiled at runtime with SWC)
7
+ *
8
+ * Uses react-dom/server for SSR to HTML.
9
+ */
10
+ import type { TemplateContext } from '../runtime/types';
11
+ import type { PlatformCapabilities } from '../theme';
12
+ import type { UIRenderer, TranspileResult, TranspileOptions, RenderOptions, RuntimeScripts, ToolUIProps } from './types';
13
+ /**
14
+ * Types this renderer can handle.
15
+ */
16
+ type ReactTemplate<In = unknown, Out = unknown> = ((props: ToolUIProps<In, Out>) => unknown) | string;
17
+ /**
18
+ * React Renderer Implementation.
19
+ *
20
+ * Handles:
21
+ * - Imported React components (FC or class)
22
+ * - JSX string templates (transpiled with SWC at runtime)
23
+ *
24
+ * Renders to HTML using react-dom/server's renderToString.
25
+ *
26
+ * @example Imported component
27
+ * ```typescript
28
+ * import { MyWidget } from './my-widget.tsx';
29
+ *
30
+ * @Tool({
31
+ * ui: { template: MyWidget }
32
+ * })
33
+ * ```
34
+ *
35
+ * @example JSX string (runtime transpilation)
36
+ * ```typescript
37
+ * @Tool({
38
+ * ui: {
39
+ * template: `
40
+ * function Widget({ output }) {
41
+ * return <div>{output.name}</div>;
42
+ * }
43
+ * `
44
+ * }
45
+ * })
46
+ * ```
47
+ */
48
+ export declare class ReactRenderer implements UIRenderer<ReactTemplate> {
49
+ readonly type: "react";
50
+ readonly priority = 20;
51
+ /**
52
+ * Lazy-loaded React modules.
53
+ */
54
+ private React;
55
+ private ReactDOMServer;
56
+ /**
57
+ * Check if this renderer can handle the given template.
58
+ *
59
+ * Accepts:
60
+ * - React component functions (imported, already transpiled)
61
+ * - Strings containing JSX syntax
62
+ */
63
+ canHandle(template: unknown): template is ReactTemplate;
64
+ /**
65
+ * Transpile the template if needed.
66
+ *
67
+ * For imported React components, no transpilation is needed.
68
+ * For JSX strings, SWC transpilation is performed.
69
+ */
70
+ transpile(template: ReactTemplate, options?: TranspileOptions): Promise<TranspileResult>;
71
+ /**
72
+ * Render the template to HTML string using react-dom/server.
73
+ */
74
+ render<In, Out>(template: ReactTemplate<In, Out>, context: TemplateContext<In, Out>, options?: RenderOptions): Promise<string>;
75
+ /**
76
+ * Get runtime scripts for client-side functionality.
77
+ */
78
+ getRuntimeScripts(platform: PlatformCapabilities): RuntimeScripts;
79
+ /**
80
+ * Load React and ReactDOMServer modules.
81
+ */
82
+ private loadReact;
83
+ }
84
+ /**
85
+ * Singleton instance of the React renderer.
86
+ */
87
+ export declare const reactRenderer: ReactRenderer;
88
+ /**
89
+ * Build React hydration script for client-side interactivity.
90
+ *
91
+ * This script finds elements with data-hydrate attributes and
92
+ * hydrates them with the corresponding React component.
93
+ */
94
+ export declare function buildHydrationScript(): string;
95
+ export {};
@@ -0,0 +1,260 @@
1
+ "use strict";
2
+ /**
3
+ * React Renderer
4
+ *
5
+ * Handles React component templates:
6
+ * - Imported React components (already transpiled)
7
+ * - JSX string templates (transpiled at runtime with SWC)
8
+ *
9
+ * Uses react-dom/server for SSR to HTML.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.reactRenderer = exports.ReactRenderer = void 0;
13
+ exports.buildHydrationScript = buildHydrationScript;
14
+ const detect_1 = require("./utils/detect");
15
+ const hash_1 = require("./utils/hash");
16
+ const transpiler_1 = require("./utils/transpiler");
17
+ const cache_1 = require("./cache");
18
+ /**
19
+ * React runtime CDN URLs.
20
+ * Using esm.sh for React 19 (ES modules).
21
+ */
22
+ const REACT_CDN = {
23
+ react: 'https://esm.sh/react@19',
24
+ reactDom: 'https://esm.sh/react-dom@19/client',
25
+ };
26
+ /**
27
+ * Minimal inline React runtime for blocked-network platforms (Claude).
28
+ * This is a placeholder - in production, we'd bundle a minified React.
29
+ */
30
+ const INLINE_REACT_PLACEHOLDER = `
31
+ // React runtime not available inline yet.
32
+ // For blocked-network platforms, use pre-rendered HTML templates.
33
+ console.warn('[FrontMCP] React hydration not available on this platform.');
34
+ `;
35
+ /**
36
+ * React Renderer Implementation.
37
+ *
38
+ * Handles:
39
+ * - Imported React components (FC or class)
40
+ * - JSX string templates (transpiled with SWC at runtime)
41
+ *
42
+ * Renders to HTML using react-dom/server's renderToString.
43
+ *
44
+ * @example Imported component
45
+ * ```typescript
46
+ * import { MyWidget } from './my-widget.tsx';
47
+ *
48
+ * @Tool({
49
+ * ui: { template: MyWidget }
50
+ * })
51
+ * ```
52
+ *
53
+ * @example JSX string (runtime transpilation)
54
+ * ```typescript
55
+ * @Tool({
56
+ * ui: {
57
+ * template: `
58
+ * function Widget({ output }) {
59
+ * return <div>{output.name}</div>;
60
+ * }
61
+ * `
62
+ * }
63
+ * })
64
+ * ```
65
+ */
66
+ class ReactRenderer {
67
+ type = 'react';
68
+ priority = 20; // Higher priority than HTML
69
+ /**
70
+ * Lazy-loaded React modules.
71
+ */
72
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
73
+ React = null;
74
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
75
+ ReactDOMServer = null;
76
+ /**
77
+ * Check if this renderer can handle the given template.
78
+ *
79
+ * Accepts:
80
+ * - React component functions (imported, already transpiled)
81
+ * - Strings containing JSX syntax
82
+ */
83
+ canHandle(template) {
84
+ // React component function
85
+ if (typeof template === 'function' && (0, detect_1.isReactComponent)(template)) {
86
+ return true;
87
+ }
88
+ // JSX string
89
+ if (typeof template === 'string' && (0, detect_1.containsJsx)(template)) {
90
+ return true;
91
+ }
92
+ return false;
93
+ }
94
+ /**
95
+ * Transpile the template if needed.
96
+ *
97
+ * For imported React components, no transpilation is needed.
98
+ * For JSX strings, SWC transpilation is performed.
99
+ */
100
+ async transpile(template, options) {
101
+ // Imported component - no transpilation needed
102
+ if (typeof template === 'function') {
103
+ const hash = (0, hash_1.hashString)(template.toString());
104
+ return {
105
+ code: '', // No transpiled code for already-compiled components
106
+ hash,
107
+ cached: true,
108
+ };
109
+ }
110
+ // JSX string - transpile with SWC
111
+ if (typeof template === 'string') {
112
+ return (0, transpiler_1.transpileJsx)(template, {
113
+ development: options?.sourceMaps ?? false,
114
+ });
115
+ }
116
+ throw new Error('Invalid template type for ReactRenderer');
117
+ }
118
+ /**
119
+ * Render the template to HTML string using react-dom/server.
120
+ */
121
+ async render(template, context, options) {
122
+ // Ensure React is loaded
123
+ await this.loadReact();
124
+ // Get the component function
125
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
126
+ let Component;
127
+ if (typeof template === 'function') {
128
+ // Already a component function
129
+ Component = template;
130
+ }
131
+ else if (typeof template === 'string') {
132
+ // Transpile and execute the JSX string
133
+ const transpiled = await this.transpile(template);
134
+ // Check cache for the executed component
135
+ const cached = cache_1.transpileCache.getByKey(`exec:${transpiled.hash}`);
136
+ if (cached) {
137
+ Component = cached.code;
138
+ }
139
+ else {
140
+ // Execute the transpiled code to get the component
141
+ Component = await (0, transpiler_1.executeTranspiledCode)(transpiled.code, {
142
+ // Provide any additional MDX components if specified
143
+ ...options?.mdxComponents,
144
+ });
145
+ // Cache the component function
146
+ cache_1.transpileCache.setByKey(`exec:${transpiled.hash}`, {
147
+ code: Component,
148
+ hash: transpiled.hash,
149
+ cached: false,
150
+ });
151
+ }
152
+ }
153
+ else {
154
+ throw new Error('Invalid template type for ReactRenderer');
155
+ }
156
+ // Build props from context
157
+ const props = {
158
+ input: context.input,
159
+ output: context.output,
160
+ structuredContent: context.structuredContent,
161
+ helpers: context.helpers,
162
+ };
163
+ // Create React element
164
+ const element = this.React.createElement(Component, props);
165
+ // Render to HTML string
166
+ const html = this.ReactDOMServer.renderToString(element);
167
+ // If hydration is enabled, wrap with hydration markers
168
+ if (options?.hydrate) {
169
+ const componentName = Component.name || 'Component';
170
+ // Full HTML attribute escaping to prevent XSS
171
+ const escapedProps = JSON.stringify(props)
172
+ .replace(/&/g, '&amp;')
173
+ .replace(/'/g, '&#39;')
174
+ .replace(/</g, '&lt;')
175
+ .replace(/>/g, '&gt;');
176
+ return `<div data-hydrate="${componentName}" data-props='${escapedProps}'>${html}</div>`;
177
+ }
178
+ return html;
179
+ }
180
+ /**
181
+ * Get runtime scripts for client-side functionality.
182
+ */
183
+ getRuntimeScripts(platform) {
184
+ // For blocked-network platforms (Claude), scripts must be inline
185
+ if (platform.networkMode === 'blocked') {
186
+ return {
187
+ headScripts: '',
188
+ inlineScripts: INLINE_REACT_PLACEHOLDER,
189
+ isInline: true,
190
+ };
191
+ }
192
+ // For platforms with network access, use CDN
193
+ return {
194
+ headScripts: `
195
+ <script crossorigin src="${REACT_CDN.react}"></script>
196
+ <script crossorigin src="${REACT_CDN.reactDom}"></script>
197
+ `,
198
+ isInline: false,
199
+ };
200
+ }
201
+ /**
202
+ * Load React and ReactDOMServer modules.
203
+ */
204
+ async loadReact() {
205
+ if (this.React && this.ReactDOMServer) {
206
+ return;
207
+ }
208
+ try {
209
+ this.React = await import('react');
210
+ this.ReactDOMServer = await import('react-dom/server');
211
+ }
212
+ catch {
213
+ throw new Error('React is required for ReactRenderer. Install react and react-dom: npm install react react-dom');
214
+ }
215
+ }
216
+ }
217
+ exports.ReactRenderer = ReactRenderer;
218
+ /**
219
+ * Singleton instance of the React renderer.
220
+ */
221
+ exports.reactRenderer = new ReactRenderer();
222
+ /**
223
+ * Build React hydration script for client-side interactivity.
224
+ *
225
+ * This script finds elements with data-hydrate attributes and
226
+ * hydrates them with the corresponding React component.
227
+ */
228
+ function buildHydrationScript() {
229
+ return `
230
+ <script>
231
+ (function() {
232
+ // Wait for React to be available
233
+ if (typeof React === 'undefined' || typeof ReactDOM === 'undefined') {
234
+ console.warn('[FrontMCP] React not available for hydration');
235
+ return;
236
+ }
237
+
238
+ // Find all elements marked for hydration
239
+ document.querySelectorAll('[data-hydrate]').forEach(function(root) {
240
+ var componentName = root.getAttribute('data-hydrate');
241
+ var propsJson = root.getAttribute('data-props');
242
+ var props = propsJson ? JSON.parse(propsJson) : {};
243
+
244
+ // Look for the component in the global scope
245
+ if (window.__frontmcp_components && window.__frontmcp_components[componentName]) {
246
+ try {
247
+ ReactDOM.hydrateRoot(root, React.createElement(
248
+ window.__frontmcp_components[componentName],
249
+ props
250
+ ));
251
+ } catch (e) {
252
+ console.error('[FrontMCP] Hydration failed for', componentName, e);
253
+ }
254
+ }
255
+ });
256
+ })();
257
+ </script>
258
+ `;
259
+ }
260
+ //# sourceMappingURL=react.renderer.js.map