@frontmcp/ui 0.6.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) hide show
  1. package/bridge/core/bridge-factory.d.ts +1 -0
  2. package/bridge/core/bridge-factory.d.ts.map +1 -1
  3. package/bridge/index.d.ts +1 -1
  4. package/bridge/index.d.ts.map +1 -1
  5. package/bridge/index.js +39 -881
  6. package/bundler/browser-components.d.ts +42 -0
  7. package/bundler/browser-components.d.ts.map +1 -0
  8. package/bundler/bundler.d.ts +78 -4
  9. package/bundler/bundler.d.ts.map +1 -1
  10. package/bundler/index.d.ts +8 -8
  11. package/bundler/index.d.ts.map +1 -1
  12. package/bundler/index.js +1315 -1854
  13. package/bundler/types.d.ts +188 -7
  14. package/bundler/types.d.ts.map +1 -1
  15. package/esm/bridge/{index.js → index.mjs} +40 -877
  16. package/esm/bundler/{index.js → index.mjs} +1391 -1895
  17. package/esm/{index.js → index.mjs} +215 -3091
  18. package/esm/layouts/{index.js → index.mjs} +3 -3
  19. package/esm/package.json +9 -8
  20. package/esm/react/index.mjs +1183 -0
  21. package/esm/renderers/index.mjs +611 -0
  22. package/esm/universal/{index.js → index.mjs} +266 -70
  23. package/index.d.ts +1 -4
  24. package/index.d.ts.map +1 -1
  25. package/index.js +208 -3113
  26. package/layouts/base.d.ts.map +1 -1
  27. package/layouts/index.js +3 -3
  28. package/layouts/presets.d.ts.map +1 -1
  29. package/package.json +9 -8
  30. package/react/Badge.d.ts.map +1 -1
  31. package/react/hooks/context.d.ts.map +1 -1
  32. package/react/index.d.ts +0 -1
  33. package/react/index.d.ts.map +1 -1
  34. package/react/index.js +57 -2001
  35. package/react/types.d.ts.map +1 -1
  36. package/renderers/index.d.ts +9 -4
  37. package/renderers/index.d.ts.map +1 -1
  38. package/renderers/index.js +328 -88
  39. package/renderers/mdx.renderer.d.ts +99 -0
  40. package/renderers/mdx.renderer.d.ts.map +1 -0
  41. package/renderers/react.renderer.d.ts +22 -13
  42. package/renderers/react.renderer.d.ts.map +1 -1
  43. package/renderers/transpiler.d.ts +49 -0
  44. package/renderers/transpiler.d.ts.map +1 -0
  45. package/universal/cached-runtime.d.ts +25 -1
  46. package/universal/cached-runtime.d.ts.map +1 -1
  47. package/universal/index.js +266 -70
  48. package/universal/runtime-builder.d.ts.map +1 -1
  49. package/universal/types.d.ts.map +1 -1
  50. package/web-components/elements/fmcp-input.d.ts.map +1 -1
  51. package/web-components/elements/fmcp-select.d.ts.map +1 -1
  52. package/web-components/index.d.ts +0 -1
  53. package/web-components/index.d.ts.map +1 -1
  54. package/bundler/cache.d.ts +0 -173
  55. package/bundler/cache.d.ts.map +0 -1
  56. package/bundler/file-cache/component-builder.d.ts +0 -167
  57. package/bundler/file-cache/component-builder.d.ts.map +0 -1
  58. package/bundler/file-cache/hash-calculator.d.ts +0 -155
  59. package/bundler/file-cache/hash-calculator.d.ts.map +0 -1
  60. package/bundler/file-cache/index.d.ts +0 -12
  61. package/bundler/file-cache/index.d.ts.map +0 -1
  62. package/bundler/file-cache/storage/filesystem.d.ts +0 -149
  63. package/bundler/file-cache/storage/filesystem.d.ts.map +0 -1
  64. package/bundler/file-cache/storage/index.d.ts +0 -11
  65. package/bundler/file-cache/storage/index.d.ts.map +0 -1
  66. package/bundler/file-cache/storage/interface.d.ts +0 -152
  67. package/bundler/file-cache/storage/interface.d.ts.map +0 -1
  68. package/bundler/file-cache/storage/redis.d.ts +0 -139
  69. package/bundler/file-cache/storage/redis.d.ts.map +0 -1
  70. package/bundler/sandbox/enclave-adapter.d.ts +0 -121
  71. package/bundler/sandbox/enclave-adapter.d.ts.map +0 -1
  72. package/bundler/sandbox/executor.d.ts +0 -14
  73. package/bundler/sandbox/executor.d.ts.map +0 -1
  74. package/bundler/sandbox/policy.d.ts +0 -62
  75. package/bundler/sandbox/policy.d.ts.map +0 -1
  76. package/esm/bridge/adapters/base-adapter.d.ts +0 -104
  77. package/esm/bridge/adapters/base-adapter.d.ts.map +0 -1
  78. package/esm/bridge/adapters/claude.adapter.d.ts +0 -67
  79. package/esm/bridge/adapters/claude.adapter.d.ts.map +0 -1
  80. package/esm/bridge/adapters/ext-apps.adapter.d.ts +0 -143
  81. package/esm/bridge/adapters/ext-apps.adapter.d.ts.map +0 -1
  82. package/esm/bridge/adapters/gemini.adapter.d.ts +0 -64
  83. package/esm/bridge/adapters/gemini.adapter.d.ts.map +0 -1
  84. package/esm/bridge/adapters/generic.adapter.d.ts +0 -56
  85. package/esm/bridge/adapters/generic.adapter.d.ts.map +0 -1
  86. package/esm/bridge/adapters/index.d.ts +0 -26
  87. package/esm/bridge/adapters/index.d.ts.map +0 -1
  88. package/esm/bridge/adapters/openai.adapter.d.ts +0 -65
  89. package/esm/bridge/adapters/openai.adapter.d.ts.map +0 -1
  90. package/esm/bridge/core/adapter-registry.d.ts +0 -122
  91. package/esm/bridge/core/adapter-registry.d.ts.map +0 -1
  92. package/esm/bridge/core/bridge-factory.d.ts +0 -199
  93. package/esm/bridge/core/bridge-factory.d.ts.map +0 -1
  94. package/esm/bridge/core/index.d.ts +0 -10
  95. package/esm/bridge/core/index.d.ts.map +0 -1
  96. package/esm/bridge/index.d.ts +0 -62
  97. package/esm/bridge/index.d.ts.map +0 -1
  98. package/esm/bridge/runtime/iife-generator.d.ts +0 -62
  99. package/esm/bridge/runtime/iife-generator.d.ts.map +0 -1
  100. package/esm/bridge/runtime/index.d.ts +0 -10
  101. package/esm/bridge/runtime/index.d.ts.map +0 -1
  102. package/esm/bridge/types.d.ts +0 -386
  103. package/esm/bridge/types.d.ts.map +0 -1
  104. package/esm/bundler/bundler.d.ts +0 -208
  105. package/esm/bundler/bundler.d.ts.map +0 -1
  106. package/esm/bundler/cache.d.ts +0 -173
  107. package/esm/bundler/cache.d.ts.map +0 -1
  108. package/esm/bundler/file-cache/component-builder.d.ts +0 -167
  109. package/esm/bundler/file-cache/component-builder.d.ts.map +0 -1
  110. package/esm/bundler/file-cache/hash-calculator.d.ts +0 -155
  111. package/esm/bundler/file-cache/hash-calculator.d.ts.map +0 -1
  112. package/esm/bundler/file-cache/index.d.ts +0 -12
  113. package/esm/bundler/file-cache/index.d.ts.map +0 -1
  114. package/esm/bundler/file-cache/storage/filesystem.d.ts +0 -149
  115. package/esm/bundler/file-cache/storage/filesystem.d.ts.map +0 -1
  116. package/esm/bundler/file-cache/storage/index.d.ts +0 -11
  117. package/esm/bundler/file-cache/storage/index.d.ts.map +0 -1
  118. package/esm/bundler/file-cache/storage/interface.d.ts +0 -152
  119. package/esm/bundler/file-cache/storage/interface.d.ts.map +0 -1
  120. package/esm/bundler/file-cache/storage/redis.d.ts +0 -139
  121. package/esm/bundler/file-cache/storage/redis.d.ts.map +0 -1
  122. package/esm/bundler/index.d.ts +0 -43
  123. package/esm/bundler/index.d.ts.map +0 -1
  124. package/esm/bundler/sandbox/enclave-adapter.d.ts +0 -121
  125. package/esm/bundler/sandbox/enclave-adapter.d.ts.map +0 -1
  126. package/esm/bundler/sandbox/executor.d.ts +0 -14
  127. package/esm/bundler/sandbox/executor.d.ts.map +0 -1
  128. package/esm/bundler/sandbox/policy.d.ts +0 -62
  129. package/esm/bundler/sandbox/policy.d.ts.map +0 -1
  130. package/esm/bundler/types.d.ts +0 -702
  131. package/esm/bundler/types.d.ts.map +0 -1
  132. package/esm/components/alert.d.ts +0 -66
  133. package/esm/components/alert.d.ts.map +0 -1
  134. package/esm/components/alert.schema.d.ts +0 -98
  135. package/esm/components/alert.schema.d.ts.map +0 -1
  136. package/esm/components/avatar.d.ts +0 -77
  137. package/esm/components/avatar.d.ts.map +0 -1
  138. package/esm/components/avatar.schema.d.ts +0 -170
  139. package/esm/components/avatar.schema.d.ts.map +0 -1
  140. package/esm/components/badge.d.ts +0 -64
  141. package/esm/components/badge.d.ts.map +0 -1
  142. package/esm/components/badge.schema.d.ts +0 -91
  143. package/esm/components/badge.schema.d.ts.map +0 -1
  144. package/esm/components/button.d.ts +0 -100
  145. package/esm/components/button.d.ts.map +0 -1
  146. package/esm/components/button.schema.d.ts +0 -120
  147. package/esm/components/button.schema.d.ts.map +0 -1
  148. package/esm/components/card.d.ts +0 -53
  149. package/esm/components/card.d.ts.map +0 -1
  150. package/esm/components/card.schema.d.ts +0 -93
  151. package/esm/components/card.schema.d.ts.map +0 -1
  152. package/esm/components/form.d.ts +0 -212
  153. package/esm/components/form.d.ts.map +0 -1
  154. package/esm/components/form.schema.d.ts +0 -365
  155. package/esm/components/form.schema.d.ts.map +0 -1
  156. package/esm/components/index.d.ts +0 -29
  157. package/esm/components/index.d.ts.map +0 -1
  158. package/esm/components/list.d.ts +0 -121
  159. package/esm/components/list.d.ts.map +0 -1
  160. package/esm/components/list.schema.d.ts +0 -129
  161. package/esm/components/list.schema.d.ts.map +0 -1
  162. package/esm/components/modal.d.ts +0 -100
  163. package/esm/components/modal.d.ts.map +0 -1
  164. package/esm/components/modal.schema.d.ts +0 -151
  165. package/esm/components/modal.schema.d.ts.map +0 -1
  166. package/esm/components/table.d.ts +0 -91
  167. package/esm/components/table.d.ts.map +0 -1
  168. package/esm/components/table.schema.d.ts +0 -123
  169. package/esm/components/table.schema.d.ts.map +0 -1
  170. package/esm/index.d.ts +0 -40
  171. package/esm/index.d.ts.map +0 -1
  172. package/esm/layouts/base.d.ts +0 -86
  173. package/esm/layouts/base.d.ts.map +0 -1
  174. package/esm/layouts/index.d.ts +0 -8
  175. package/esm/layouts/index.d.ts.map +0 -1
  176. package/esm/layouts/presets.d.ts +0 -134
  177. package/esm/layouts/presets.d.ts.map +0 -1
  178. package/esm/pages/consent.d.ts +0 -117
  179. package/esm/pages/consent.d.ts.map +0 -1
  180. package/esm/pages/error.d.ts +0 -101
  181. package/esm/pages/error.d.ts.map +0 -1
  182. package/esm/pages/index.d.ts +0 -9
  183. package/esm/pages/index.d.ts.map +0 -1
  184. package/esm/pages/index.js +0 -1036
  185. package/esm/react/Alert.d.ts +0 -101
  186. package/esm/react/Alert.d.ts.map +0 -1
  187. package/esm/react/Badge.d.ts +0 -100
  188. package/esm/react/Badge.d.ts.map +0 -1
  189. package/esm/react/Button.d.ts +0 -108
  190. package/esm/react/Button.d.ts.map +0 -1
  191. package/esm/react/Card.d.ts +0 -103
  192. package/esm/react/Card.d.ts.map +0 -1
  193. package/esm/react/hooks/context.d.ts +0 -179
  194. package/esm/react/hooks/context.d.ts.map +0 -1
  195. package/esm/react/hooks/index.d.ts +0 -42
  196. package/esm/react/hooks/index.d.ts.map +0 -1
  197. package/esm/react/hooks/tools.d.ts +0 -284
  198. package/esm/react/hooks/tools.d.ts.map +0 -1
  199. package/esm/react/index.d.ts +0 -80
  200. package/esm/react/index.d.ts.map +0 -1
  201. package/esm/react/index.js +0 -3124
  202. package/esm/react/types.d.ts +0 -105
  203. package/esm/react/types.d.ts.map +0 -1
  204. package/esm/react/utils.d.ts +0 -43
  205. package/esm/react/utils.d.ts.map +0 -1
  206. package/esm/render/index.d.ts +0 -8
  207. package/esm/render/index.d.ts.map +0 -1
  208. package/esm/render/prerender.d.ts +0 -57
  209. package/esm/render/prerender.d.ts.map +0 -1
  210. package/esm/renderers/index.d.ts +0 -21
  211. package/esm/renderers/index.d.ts.map +0 -1
  212. package/esm/renderers/index.js +0 -381
  213. package/esm/renderers/react.adapter.d.ts +0 -70
  214. package/esm/renderers/react.adapter.d.ts.map +0 -1
  215. package/esm/renderers/react.renderer.d.ts +0 -96
  216. package/esm/renderers/react.renderer.d.ts.map +0 -1
  217. package/esm/universal/UniversalApp.d.ts +0 -108
  218. package/esm/universal/UniversalApp.d.ts.map +0 -1
  219. package/esm/universal/cached-runtime.d.ts +0 -115
  220. package/esm/universal/cached-runtime.d.ts.map +0 -1
  221. package/esm/universal/context.d.ts +0 -122
  222. package/esm/universal/context.d.ts.map +0 -1
  223. package/esm/universal/index.d.ts +0 -57
  224. package/esm/universal/index.d.ts.map +0 -1
  225. package/esm/universal/renderers/html.renderer.d.ts +0 -37
  226. package/esm/universal/renderers/html.renderer.d.ts.map +0 -1
  227. package/esm/universal/renderers/index.d.ts +0 -112
  228. package/esm/universal/renderers/index.d.ts.map +0 -1
  229. package/esm/universal/renderers/markdown.renderer.d.ts +0 -33
  230. package/esm/universal/renderers/markdown.renderer.d.ts.map +0 -1
  231. package/esm/universal/renderers/mdx.renderer.d.ts +0 -38
  232. package/esm/universal/renderers/mdx.renderer.d.ts.map +0 -1
  233. package/esm/universal/renderers/react.renderer.d.ts +0 -46
  234. package/esm/universal/renderers/react.renderer.d.ts.map +0 -1
  235. package/esm/universal/runtime-builder.d.ts +0 -33
  236. package/esm/universal/runtime-builder.d.ts.map +0 -1
  237. package/esm/universal/store.d.ts +0 -135
  238. package/esm/universal/store.d.ts.map +0 -1
  239. package/esm/universal/types.d.ts +0 -199
  240. package/esm/universal/types.d.ts.map +0 -1
  241. package/esm/web-components/core/attribute-parser.d.ts +0 -82
  242. package/esm/web-components/core/attribute-parser.d.ts.map +0 -1
  243. package/esm/web-components/core/base-element.d.ts +0 -197
  244. package/esm/web-components/core/base-element.d.ts.map +0 -1
  245. package/esm/web-components/core/index.d.ts +0 -9
  246. package/esm/web-components/core/index.d.ts.map +0 -1
  247. package/esm/web-components/elements/fmcp-alert.d.ts +0 -46
  248. package/esm/web-components/elements/fmcp-alert.d.ts.map +0 -1
  249. package/esm/web-components/elements/fmcp-badge.d.ts +0 -47
  250. package/esm/web-components/elements/fmcp-badge.d.ts.map +0 -1
  251. package/esm/web-components/elements/fmcp-button.d.ts +0 -117
  252. package/esm/web-components/elements/fmcp-button.d.ts.map +0 -1
  253. package/esm/web-components/elements/fmcp-card.d.ts +0 -53
  254. package/esm/web-components/elements/fmcp-card.d.ts.map +0 -1
  255. package/esm/web-components/elements/fmcp-input.d.ts +0 -96
  256. package/esm/web-components/elements/fmcp-input.d.ts.map +0 -1
  257. package/esm/web-components/elements/fmcp-select.d.ts +0 -100
  258. package/esm/web-components/elements/fmcp-select.d.ts.map +0 -1
  259. package/esm/web-components/elements/index.d.ts +0 -13
  260. package/esm/web-components/elements/index.d.ts.map +0 -1
  261. package/esm/web-components/index.d.ts +0 -50
  262. package/esm/web-components/index.d.ts.map +0 -1
  263. package/esm/web-components/register.d.ts +0 -57
  264. package/esm/web-components/register.d.ts.map +0 -1
  265. package/esm/web-components/types.d.ts +0 -122
  266. package/esm/web-components/types.d.ts.map +0 -1
  267. package/esm/widgets/index.d.ts +0 -8
  268. package/esm/widgets/index.d.ts.map +0 -1
  269. package/esm/widgets/index.js +0 -883
  270. package/esm/widgets/progress.d.ts +0 -133
  271. package/esm/widgets/progress.d.ts.map +0 -1
  272. package/esm/widgets/resource.d.ts +0 -163
  273. package/esm/widgets/resource.d.ts.map +0 -1
  274. package/pages/consent.d.ts +0 -117
  275. package/pages/consent.d.ts.map +0 -1
  276. package/pages/error.d.ts +0 -101
  277. package/pages/error.d.ts.map +0 -1
  278. package/pages/index.d.ts +0 -9
  279. package/pages/index.d.ts.map +0 -1
  280. package/pages/index.js +0 -1065
  281. package/react/utils.d.ts +0 -43
  282. package/react/utils.d.ts.map +0 -1
  283. package/widgets/index.d.ts +0 -8
  284. package/widgets/index.d.ts.map +0 -1
  285. package/widgets/index.js +0 -910
  286. package/widgets/progress.d.ts +0 -133
  287. package/widgets/progress.d.ts.map +0 -1
  288. package/widgets/resource.d.ts +0 -163
  289. package/widgets/resource.d.ts.map +0 -1
  290. /package/esm/components/{index.js → index.mjs} +0 -0
  291. /package/esm/render/{index.js → index.mjs} +0 -0
  292. /package/esm/web-components/{index.js → index.mjs} +0 -0
@@ -0,0 +1,611 @@
1
+ // libs/ui/src/renderers/react.renderer.ts
2
+ import { isReactComponent, containsJsx, hashString, transpileJsx } from "@frontmcp/uipack/renderers";
3
+ var VALID_JS_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
4
+ function isValidComponentName(name) {
5
+ return VALID_JS_IDENTIFIER.test(name);
6
+ }
7
+ function sanitizeComponentName(name) {
8
+ if (isValidComponentName(name)) {
9
+ return name;
10
+ }
11
+ const sanitized = name.replace(/[^a-zA-Z0-9_$]/g, "_").replace(/^[0-9]/, "_$&");
12
+ return sanitized || "Component";
13
+ }
14
+ var REACT_CDN = {
15
+ react: "https://esm.sh/react@19",
16
+ reactDom: "https://esm.sh/react-dom@19/client"
17
+ };
18
+ var INLINE_REACT_PLACEHOLDER = `
19
+ // React runtime not available inline yet.
20
+ // For blocked-network platforms, use pre-rendered HTML templates.
21
+ console.warn('[FrontMCP] React hydration not available on this platform.');
22
+ `;
23
+ var ReactRenderer = class {
24
+ type = "react";
25
+ priority = 20;
26
+ // Higher priority than HTML
27
+ /**
28
+ * Check if this renderer can handle the given template.
29
+ *
30
+ * Accepts:
31
+ * - React component functions (imported, already transpiled)
32
+ * - Strings containing JSX syntax
33
+ */
34
+ canHandle(template) {
35
+ if (typeof template === "function" && isReactComponent(template)) {
36
+ return true;
37
+ }
38
+ if (typeof template === "string" && containsJsx(template)) {
39
+ return true;
40
+ }
41
+ return false;
42
+ }
43
+ /**
44
+ * Transpile the template if needed.
45
+ *
46
+ * For imported React components, no transpilation is needed.
47
+ * For JSX strings, SWC transpilation is performed.
48
+ */
49
+ async transpile(template, options) {
50
+ if (typeof template === "function") {
51
+ const hash = hashString(template.toString());
52
+ return {
53
+ code: "",
54
+ // No transpiled code for already-compiled components
55
+ hash,
56
+ cached: true
57
+ };
58
+ }
59
+ if (typeof template === "string") {
60
+ return transpileJsx(template, {
61
+ development: options?.sourceMaps ?? false
62
+ });
63
+ }
64
+ throw new Error("Invalid template type for ReactRenderer");
65
+ }
66
+ /**
67
+ * Render the template to HTML for client-side rendering.
68
+ *
69
+ * Unlike SSR, this method generates HTML that will be rendered
70
+ * client-side by React in the browser. No server-side React required.
71
+ *
72
+ * The generated HTML includes:
73
+ * - A container div for the React root
74
+ * - The component code (transpiled if needed)
75
+ * - Props embedded as a data attribute
76
+ * - A render script that initializes the component
77
+ */
78
+ async render(template, context, _options) {
79
+ const props = {
80
+ input: context.input,
81
+ output: context.output,
82
+ structuredContent: context.structuredContent,
83
+ helpers: context.helpers
84
+ };
85
+ const escapedProps = JSON.stringify(props).replace(/&/g, "&amp;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
86
+ const rootId = `frontmcp-react-${hashString(Date.now().toString()).slice(0, 8)}`;
87
+ let componentCode;
88
+ let componentName;
89
+ if (typeof template === "function") {
90
+ const rawName = template.name || "Component";
91
+ componentName = sanitizeComponentName(rawName);
92
+ componentCode = `
93
+ // Component should be registered via window.__frontmcp_components['${componentName}']
94
+ (function() {
95
+ if (!window.__frontmcp_components || !window.__frontmcp_components['${componentName}']) {
96
+ console.error('[FrontMCP] Component "${componentName}" not registered. Use buildHydrationScript() to register components.');
97
+ }
98
+ })();
99
+ `;
100
+ } else if (typeof template === "string") {
101
+ const transpiled = await this.transpile(template);
102
+ const match = transpiled.code.match(/function\s+(\w+)/);
103
+ const rawName = match?.[1] || "Widget";
104
+ componentName = sanitizeComponentName(rawName);
105
+ componentCode = transpiled.code;
106
+ } else {
107
+ throw new Error("Invalid template type for ReactRenderer");
108
+ }
109
+ const html = `
110
+ <div id="${rootId}" data-frontmcp-react data-component="${componentName}" data-props='${escapedProps}'>
111
+ <div class="flex items-center justify-center p-4 text-gray-500">
112
+ <svg class="animate-spin h-5 w-5 mr-2" viewBox="0 0 24 24">
113
+ <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none"></circle>
114
+ <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
115
+ </svg>
116
+ Loading...
117
+ </div>
118
+ </div>
119
+ <script type="module">
120
+ (function() {
121
+ ${componentCode}
122
+
123
+ // Wait for React to be available
124
+ function waitForReact(callback, maxAttempts) {
125
+ var attempts = 0;
126
+ var check = function() {
127
+ if (typeof React !== 'undefined' && typeof ReactDOM !== 'undefined') {
128
+ callback();
129
+ } else if (attempts < maxAttempts) {
130
+ attempts++;
131
+ setTimeout(check, 50);
132
+ } else {
133
+ console.error('[FrontMCP] React not loaded after ' + maxAttempts + ' attempts');
134
+ }
135
+ };
136
+ check();
137
+ }
138
+
139
+ waitForReact(function() {
140
+ try {
141
+ var root = document.getElementById('${rootId}');
142
+ if (!root) return;
143
+
144
+ var propsJson = root.getAttribute('data-props');
145
+ var props = propsJson ? JSON.parse(propsJson.replace(/&amp;/g, '&').replace(/&#39;/g, "'").replace(/&lt;/g, '<').replace(/&gt;/g, '>')) : {};
146
+
147
+ // Get the component
148
+ var Component = ${componentName};
149
+
150
+ // Check if it's registered globally
151
+ if (typeof Component === 'undefined' && window.__frontmcp_components) {
152
+ Component = window.__frontmcp_components['${componentName}'];
153
+ }
154
+
155
+ if (typeof Component === 'function') {
156
+ var element = React.createElement(Component, props);
157
+ var reactRoot = ReactDOM.createRoot(root);
158
+ reactRoot.render(element);
159
+ } else {
160
+ console.error('[FrontMCP] Component "${componentName}" not found');
161
+ }
162
+ } catch (err) {
163
+ console.error('[FrontMCP] React render error:', err);
164
+ }
165
+ }, 100);
166
+ })();
167
+ </script>
168
+ `;
169
+ return html.trim();
170
+ }
171
+ /**
172
+ * Get runtime scripts for client-side functionality.
173
+ */
174
+ getRuntimeScripts(platform) {
175
+ if (platform.networkMode === "blocked") {
176
+ return {
177
+ headScripts: "",
178
+ inlineScripts: INLINE_REACT_PLACEHOLDER,
179
+ isInline: true
180
+ };
181
+ }
182
+ return {
183
+ headScripts: `
184
+ <script crossorigin src="${REACT_CDN.react}"></script>
185
+ <script crossorigin src="${REACT_CDN.reactDom}"></script>
186
+ `,
187
+ isInline: false
188
+ };
189
+ }
190
+ };
191
+ var reactRenderer = new ReactRenderer();
192
+
193
+ // libs/ui/src/renderers/react.adapter.ts
194
+ var mountedRoots = /* @__PURE__ */ new WeakMap();
195
+ var ReactRendererAdapter = class {
196
+ type = "react";
197
+ // Lazy-loaded React runtime
198
+ react = null;
199
+ reactDOM = null;
200
+ loadPromise = null;
201
+ /**
202
+ * Check if this adapter can handle the given content.
203
+ */
204
+ canHandle(content) {
205
+ if (typeof content === "function") {
206
+ return true;
207
+ }
208
+ if (typeof content === "string") {
209
+ return content.includes("React.createElement") || content.includes("jsx(") || content.includes("jsxs(") || /function\s+\w+\s*\([^)]*\)\s*\{[\s\S]*return\s*[\s\S]*</.test(content);
210
+ }
211
+ return false;
212
+ }
213
+ /**
214
+ * Render React component to a string.
215
+ * This is a client-side fallback - SSR should be done at build time.
216
+ */
217
+ async render(content, context, _options) {
218
+ return `<div data-frontmcp-react data-tool="${context.toolName}">${content}</div>`;
219
+ }
220
+ /**
221
+ * Render React component directly to the DOM.
222
+ */
223
+ async renderToDOM(content, target, context, options) {
224
+ try {
225
+ await this.ensureReactLoaded();
226
+ if (!this.react || !this.reactDOM) {
227
+ throw new Error("React runtime not available");
228
+ }
229
+ const componentName = target.getAttribute("data-component");
230
+ const component = this.getComponent(componentName, content);
231
+ if (!component) {
232
+ target.innerHTML = content;
233
+ return { success: true };
234
+ }
235
+ const element = this.react.createElement(component, {
236
+ input: context.input,
237
+ output: context.output,
238
+ structuredContent: context.structuredContent,
239
+ toolName: context.toolName
240
+ });
241
+ if (options?.hydrate && this.reactDOM.hydrateRoot) {
242
+ const root = this.reactDOM.hydrateRoot(target, element);
243
+ mountedRoots.set(target, root);
244
+ } else if (this.reactDOM.createRoot) {
245
+ const root = this.reactDOM.createRoot(target);
246
+ root.render(element);
247
+ mountedRoots.set(target, root);
248
+ } else if (this.reactDOM.render) {
249
+ this.reactDOM.render(element, target);
250
+ mountedRoots.set(target, {
251
+ unmount: () => this.reactDOM?.unmountComponentAtNode?.(target)
252
+ });
253
+ } else {
254
+ throw new Error("No suitable React render method available");
255
+ }
256
+ target.dispatchEvent(
257
+ new CustomEvent("frontmcp:rendered", {
258
+ bubbles: true,
259
+ detail: { type: "react", toolName: context.toolName }
260
+ })
261
+ );
262
+ return { success: true };
263
+ } catch (error) {
264
+ const message = error instanceof Error ? error.message : String(error);
265
+ console.error("[FrontMCP] React render failed:", message);
266
+ return { success: false, error: message };
267
+ }
268
+ }
269
+ /**
270
+ * Hydrate existing SSR content with React.
271
+ */
272
+ async hydrate(target, context, options) {
273
+ return this.renderToDOM("", target, context, { ...options, hydrate: true });
274
+ }
275
+ /**
276
+ * Update rendered React component with new data.
277
+ */
278
+ async update(target, context) {
279
+ try {
280
+ await this.ensureReactLoaded();
281
+ if (!this.react) {
282
+ throw new Error("React runtime not available");
283
+ }
284
+ const existingRoot = mountedRoots.get(target);
285
+ const componentName = target.getAttribute("data-component");
286
+ const component = this.getComponent(componentName, "");
287
+ if (!component) {
288
+ return { success: false, error: "No component found for update" };
289
+ }
290
+ const element = this.react.createElement(component, {
291
+ input: context.input,
292
+ output: context.output,
293
+ structuredContent: context.structuredContent,
294
+ toolName: context.toolName
295
+ });
296
+ if (existingRoot && "render" in existingRoot) {
297
+ existingRoot.render(element);
298
+ return { success: true };
299
+ }
300
+ return this.renderToDOM("", target, context);
301
+ } catch (error) {
302
+ const message = error instanceof Error ? error.message : String(error);
303
+ console.error("[FrontMCP] React update failed:", message);
304
+ return { success: false, error: message };
305
+ }
306
+ }
307
+ /**
308
+ * Clean up React root.
309
+ */
310
+ destroy(target) {
311
+ const root = mountedRoots.get(target);
312
+ if (root) {
313
+ root.unmount();
314
+ mountedRoots.delete(target);
315
+ }
316
+ }
317
+ /**
318
+ * Ensure React is loaded.
319
+ */
320
+ async ensureReactLoaded() {
321
+ if (this.react && this.reactDOM) {
322
+ return;
323
+ }
324
+ if (this.loadPromise) {
325
+ return this.loadPromise;
326
+ }
327
+ this.loadPromise = this.loadReact();
328
+ return this.loadPromise;
329
+ }
330
+ /**
331
+ * Load React runtime.
332
+ */
333
+ async loadReact() {
334
+ const win = typeof window !== "undefined" ? window : globalThis;
335
+ if (win.React) {
336
+ this.react = win.React;
337
+ }
338
+ if (win.ReactDOM) {
339
+ this.reactDOM = win.ReactDOM;
340
+ }
341
+ if (this.react && this.reactDOM) {
342
+ return;
343
+ }
344
+ try {
345
+ if (!this.react) {
346
+ const reactModule = await import(
347
+ /* webpackIgnore: true */
348
+ "react"
349
+ );
350
+ this.react = reactModule.default || reactModule;
351
+ }
352
+ if (!this.reactDOM) {
353
+ const reactDOMModule = await import(
354
+ /* webpackIgnore: true */
355
+ "react-dom/client"
356
+ );
357
+ this.reactDOM = reactDOMModule.default || reactDOMModule;
358
+ }
359
+ } catch {
360
+ if (!this.react || !this.reactDOM) {
361
+ console.warn("[FrontMCP] React runtime not available. Ensure React is loaded via CDN or bundled.");
362
+ }
363
+ }
364
+ }
365
+ /**
366
+ * Get a React component by name or from content.
367
+ */
368
+ getComponent(componentName, content) {
369
+ const win = typeof window !== "undefined" ? window : globalThis;
370
+ if (componentName && win.__frontmcp_components) {
371
+ const registered = win.__frontmcp_components?.[componentName];
372
+ if (registered) {
373
+ return registered;
374
+ }
375
+ }
376
+ if (content && typeof content === "function") {
377
+ return content;
378
+ }
379
+ return null;
380
+ }
381
+ };
382
+ function createReactAdapter() {
383
+ return new ReactRendererAdapter();
384
+ }
385
+ async function loadReactAdapter() {
386
+ return createReactAdapter();
387
+ }
388
+
389
+ // libs/ui/src/renderers/mdx.renderer.ts
390
+ import { containsMdxSyntax, hashString as hashString2, transpileCache, componentCache } from "@frontmcp/uipack/renderers";
391
+ function buildReactCdnUrls(version = "19") {
392
+ return {
393
+ react: `https://esm.sh/react@${version}`,
394
+ reactDom: `https://esm.sh/react-dom@${version}/client`
395
+ };
396
+ }
397
+ var REACT_CDN2 = buildReactCdnUrls("19");
398
+ var INLINE_MDX_PLACEHOLDER = `
399
+ // MDX runtime not available inline yet.
400
+ // For blocked-network platforms, use pre-rendered HTML templates.
401
+ console.warn('[FrontMCP] MDX hydration not available on this platform.');
402
+ `;
403
+ var MdxRenderer = class {
404
+ type = "mdx";
405
+ priority = 10;
406
+ // Between HTML (0) and React (20)
407
+ /**
408
+ * Lazy-loaded modules.
409
+ */
410
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
411
+ React = null;
412
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
413
+ ReactDOMServer = null;
414
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
415
+ jsxRuntime = null;
416
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
417
+ mdxEvaluate = null;
418
+ /**
419
+ * Check if this renderer can handle the given template.
420
+ *
421
+ * Accepts strings containing MDX syntax (Markdown + JSX).
422
+ */
423
+ canHandle(template) {
424
+ if (typeof template !== "string") {
425
+ return false;
426
+ }
427
+ return containsMdxSyntax(template);
428
+ }
429
+ /**
430
+ * Prepare MDX template for rendering.
431
+ * Caches the template hash for deduplication. Actual MDX compilation
432
+ * happens during render() via @mdx-js/mdx evaluate().
433
+ */
434
+ async transpile(template, _options) {
435
+ const hash = hashString2(template);
436
+ const cached = transpileCache.getByKey(hash);
437
+ if (cached) {
438
+ return { ...cached, cached: true };
439
+ }
440
+ const transpileResult = {
441
+ code: template,
442
+ hash,
443
+ cached: false
444
+ };
445
+ transpileCache.setByKey(hash, transpileResult);
446
+ return transpileResult;
447
+ }
448
+ /**
449
+ * Render MDX template to HTML string.
450
+ *
451
+ * Uses @mdx-js/mdx's evaluate() for clean compilation + execution,
452
+ * then renders the resulting React component to HTML via SSR.
453
+ */
454
+ async render(template, context, options) {
455
+ await this.loadReact();
456
+ await this.loadMdx();
457
+ if (!this.mdxEvaluate) {
458
+ throw new Error("MDX compilation requires @mdx-js/mdx. Install it: npm install @mdx-js/mdx");
459
+ }
460
+ const templateHash = hashString2(template);
461
+ const cacheKey = `mdx-component:${templateHash}`;
462
+ let Content = componentCache.get(cacheKey);
463
+ if (!Content) {
464
+ const result = await this.mdxEvaluate(template, {
465
+ ...this.jsxRuntime,
466
+ Fragment: this.React.Fragment,
467
+ development: false
468
+ });
469
+ Content = result.default;
470
+ componentCache.set(cacheKey, Content);
471
+ }
472
+ const mdxComponents = {
473
+ ...options?.mdxComponents,
474
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
475
+ wrapper: ({ children }) => {
476
+ return this.React.createElement("div", { className: "mdx-content" }, children);
477
+ }
478
+ };
479
+ const props = {
480
+ input: context.input,
481
+ output: context.output,
482
+ structuredContent: context.structuredContent,
483
+ helpers: context.helpers
484
+ };
485
+ const reservedProps = /* @__PURE__ */ new Set(["input", "output", "structuredContent", "helpers", "components"]);
486
+ const outputProps = typeof context.output === "object" && context.output !== null ? Object.fromEntries(Object.entries(context.output).filter(([key]) => !reservedProps.has(key))) : {};
487
+ const spreadProps = {
488
+ ...outputProps,
489
+ ...props
490
+ };
491
+ const element = this.React.createElement(Content, {
492
+ components: mdxComponents,
493
+ ...spreadProps
494
+ });
495
+ const html = this.ReactDOMServer.renderToString(element);
496
+ if (options?.hydrate) {
497
+ const escapedProps = JSON.stringify(props).replace(/&/g, "&amp;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
498
+ return `<div data-mdx-hydrate="true" data-props='${escapedProps}'>${html}</div>`;
499
+ }
500
+ return html;
501
+ }
502
+ /**
503
+ * Get runtime scripts for client-side functionality.
504
+ */
505
+ getRuntimeScripts(platform) {
506
+ if (platform.networkMode === "blocked") {
507
+ return {
508
+ headScripts: "",
509
+ inlineScripts: INLINE_MDX_PLACEHOLDER,
510
+ isInline: true
511
+ };
512
+ }
513
+ return {
514
+ headScripts: `
515
+ <script crossorigin src="${REACT_CDN2.react}"></script>
516
+ <script crossorigin src="${REACT_CDN2.reactDom}"></script>
517
+ `,
518
+ isInline: false
519
+ };
520
+ }
521
+ /**
522
+ * Load React and ReactDOMServer modules.
523
+ */
524
+ async loadReact() {
525
+ if (this.React && this.ReactDOMServer && this.jsxRuntime) {
526
+ return;
527
+ }
528
+ try {
529
+ const [react, reactDomServer, jsxRuntime] = await Promise.all([
530
+ import("react"),
531
+ import("react-dom/server"),
532
+ import("react/jsx-runtime")
533
+ ]);
534
+ this.React = react;
535
+ this.ReactDOMServer = reactDomServer;
536
+ this.jsxRuntime = jsxRuntime;
537
+ } catch {
538
+ throw new Error("React is required for MdxRenderer. Install react and react-dom: npm install react react-dom");
539
+ }
540
+ }
541
+ /**
542
+ * Load @mdx-js/mdx evaluate function.
543
+ */
544
+ async loadMdx() {
545
+ if (this.mdxEvaluate) {
546
+ return;
547
+ }
548
+ try {
549
+ const mdx = await import("@mdx-js/mdx");
550
+ this.mdxEvaluate = mdx.evaluate;
551
+ } catch {
552
+ console.warn(
553
+ "[@frontmcp/ui] @mdx-js/mdx not available. MDX rendering disabled. Install @mdx-js/mdx to enable: npm install @mdx-js/mdx"
554
+ );
555
+ }
556
+ }
557
+ };
558
+ var mdxRenderer = new MdxRenderer();
559
+
560
+ // libs/ui/src/renderers/transpiler.ts
561
+ import { transpileJsx as transpileJsx2 } from "@frontmcp/uipack/renderers";
562
+ async function executeTranspiledCode(code, context = {}) {
563
+ let React;
564
+ let jsxRuntime;
565
+ try {
566
+ React = await import("react");
567
+ jsxRuntime = await import("react/jsx-runtime");
568
+ } catch {
569
+ throw new Error("React is required for JSX templates. Install react: npm install react react-dom");
570
+ }
571
+ const exports = {};
572
+ const module = { exports };
573
+ const require2 = (id) => {
574
+ switch (id) {
575
+ case "react":
576
+ return React;
577
+ case "react/jsx-runtime":
578
+ return jsxRuntime;
579
+ case "react/jsx-dev-runtime":
580
+ return jsxRuntime;
581
+ default:
582
+ if (context[id]) {
583
+ return context[id];
584
+ }
585
+ throw new Error(`Module '${id}' not available in JSX template context`);
586
+ }
587
+ };
588
+ try {
589
+ const fn = new Function("exports", "require", "module", "__filename", "__dirname", "React", "context", code);
590
+ fn(exports, require2, module, "template.js", "/", React, context);
591
+ const exportKeys = Object.keys(module.exports);
592
+ return module.exports["default"] || (exportKeys.length > 0 ? module.exports[exportKeys[0]] : null) || module.exports;
593
+ } catch (error) {
594
+ throw new Error(`Failed to execute transpiled JSX: ${error instanceof Error ? error.message : String(error)}`);
595
+ }
596
+ }
597
+ async function transpileAndExecute(source, context = {}) {
598
+ const result = await transpileJsx2(source);
599
+ return executeTranspiledCode(result.code, context);
600
+ }
601
+ export {
602
+ MdxRenderer,
603
+ ReactRenderer,
604
+ ReactRendererAdapter,
605
+ createReactAdapter,
606
+ executeTranspiledCode,
607
+ loadReactAdapter,
608
+ mdxRenderer,
609
+ reactRenderer,
610
+ transpileAndExecute
611
+ };