@frontmcp/uipack 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 (315) hide show
  1. package/CLAUDE.md +88 -105
  2. package/README.md +1 -0
  3. package/adapters/index.d.ts +1 -1
  4. package/adapters/index.d.ts.map +1 -1
  5. package/adapters/index.js +35 -2
  6. package/adapters/platform-meta.d.ts +29 -0
  7. package/adapters/platform-meta.d.ts.map +1 -1
  8. package/base-template/default-base-template.d.ts +0 -1
  9. package/base-template/default-base-template.d.ts.map +1 -1
  10. package/base-template/index.js +32 -37
  11. package/build/builders/base-builder.d.ts +122 -0
  12. package/build/builders/base-builder.d.ts.map +1 -0
  13. package/build/builders/esbuild-config.d.ts +94 -0
  14. package/build/builders/esbuild-config.d.ts.map +1 -0
  15. package/build/builders/hybrid-builder.d.ts +93 -0
  16. package/build/builders/hybrid-builder.d.ts.map +1 -0
  17. package/build/builders/index.d.ts +17 -0
  18. package/build/builders/index.d.ts.map +1 -0
  19. package/build/builders/inline-builder.d.ts +83 -0
  20. package/build/builders/inline-builder.d.ts.map +1 -0
  21. package/build/builders/static-builder.d.ts +78 -0
  22. package/build/builders/static-builder.d.ts.map +1 -0
  23. package/build/builders/types.d.ts +341 -0
  24. package/build/builders/types.d.ts.map +1 -0
  25. package/build/cdn-resources.d.ts +3 -2
  26. package/build/cdn-resources.d.ts.map +1 -1
  27. package/build/hybrid-data.d.ts +127 -0
  28. package/build/hybrid-data.d.ts.map +1 -0
  29. package/build/index.d.ts +4 -0
  30. package/build/index.d.ts.map +1 -1
  31. package/build/index.js +1885 -171
  32. package/build/ui-components-browser.d.ts +64 -0
  33. package/build/ui-components-browser.d.ts.map +1 -0
  34. package/build/widget-manifest.d.ts.map +1 -1
  35. package/bundler/file-cache/component-builder.d.ts.map +1 -1
  36. package/bundler/file-cache/storage/redis.d.ts.map +1 -1
  37. package/bundler/index.js +6 -4
  38. package/dependency/cdn-registry.d.ts +1 -1
  39. package/dependency/cdn-registry.d.ts.map +1 -1
  40. package/dependency/import-map.d.ts.map +1 -1
  41. package/dependency/index.js +93 -121
  42. package/dependency/resolver.d.ts.map +1 -1
  43. package/esm/adapters/{index.js → index.mjs} +34 -2
  44. package/esm/base-template/{index.js → index.mjs} +32 -37
  45. package/esm/build/{index.js → index.mjs} +1855 -170
  46. package/esm/bundler/{index.js → index.mjs} +6 -4
  47. package/esm/dependency/{index.js → index.mjs} +93 -121
  48. package/esm/handlebars/{index.js → index.mjs} +0 -1
  49. package/esm/{index.js → index.mjs} +2516 -830
  50. package/esm/package.json +7 -6
  51. package/esm/registry/{index.js → index.mjs} +196 -264
  52. package/esm/renderers/{index.js → index.mjs} +106 -200
  53. package/esm/runtime/{index.js → index.mjs} +44 -35
  54. package/esm/styles/{index.js → index.mjs} +6 -6
  55. package/esm/theme/{index.js → index.mjs} +90 -42
  56. package/esm/tool-template/{index.js → index.mjs} +35 -28
  57. package/esm/typings/{index.js → index.mjs} +157 -1
  58. package/esm/utils/{index.js → index.mjs} +24 -0
  59. package/esm/validation/{index.js → index.mjs} +0 -1
  60. package/handlebars/expression-extractor.d.ts.map +1 -1
  61. package/handlebars/index.d.ts.map +1 -1
  62. package/handlebars/index.js +0 -1
  63. package/index.d.ts +2 -1
  64. package/index.d.ts.map +1 -1
  65. package/index.js +2545 -835
  66. package/package.json +7 -6
  67. package/preview/claude-preview.d.ts +67 -0
  68. package/preview/claude-preview.d.ts.map +1 -0
  69. package/preview/generic-preview.d.ts +67 -0
  70. package/preview/generic-preview.d.ts.map +1 -0
  71. package/preview/index.d.ts +36 -0
  72. package/preview/index.d.ts.map +1 -0
  73. package/preview/openai-preview.d.ts +70 -0
  74. package/preview/openai-preview.d.ts.map +1 -0
  75. package/preview/types.d.ts +185 -0
  76. package/preview/types.d.ts.map +1 -0
  77. package/registry/index.js +196 -264
  78. package/registry/render-template.d.ts.map +1 -1
  79. package/renderers/index.d.ts +2 -2
  80. package/renderers/index.d.ts.map +1 -1
  81. package/renderers/index.js +110 -204
  82. package/renderers/mdx-client.renderer.d.ts +124 -0
  83. package/renderers/mdx-client.renderer.d.ts.map +1 -0
  84. package/renderers/registry.d.ts +2 -2
  85. package/renderers/registry.d.ts.map +1 -1
  86. package/renderers/types.d.ts +3 -2
  87. package/renderers/types.d.ts.map +1 -1
  88. package/renderers/utils/transpiler.d.ts +8 -27
  89. package/renderers/utils/transpiler.d.ts.map +1 -1
  90. package/runtime/index.js +44 -35
  91. package/runtime/mcp-bridge.d.ts.map +1 -1
  92. package/runtime/renderer-runtime.d.ts.map +1 -1
  93. package/runtime/wrapper.d.ts.map +1 -1
  94. package/styles/index.js +6 -6
  95. package/styles/variants.d.ts +1 -1
  96. package/styles/variants.d.ts.map +1 -1
  97. package/theme/cdn.d.ts.map +1 -1
  98. package/theme/css-to-theme.d.ts +91 -0
  99. package/theme/css-to-theme.d.ts.map +1 -0
  100. package/theme/index.d.ts +2 -1
  101. package/theme/index.d.ts.map +1 -1
  102. package/theme/index.js +92 -43
  103. package/theme/platforms.d.ts +1 -6
  104. package/theme/platforms.d.ts.map +1 -1
  105. package/theme/theme.d.ts.map +1 -1
  106. package/tool-template/builder.d.ts.map +1 -1
  107. package/tool-template/index.js +35 -28
  108. package/typings/index.d.ts +4 -4
  109. package/typings/index.d.ts.map +1 -1
  110. package/typings/index.js +162 -1
  111. package/typings/schemas.d.ts +30 -0
  112. package/typings/schemas.d.ts.map +1 -1
  113. package/typings/type-fetcher.d.ts +74 -1
  114. package/typings/type-fetcher.d.ts.map +1 -1
  115. package/typings/types.d.ts +72 -1
  116. package/typings/types.d.ts.map +1 -1
  117. package/utils/escape-html.d.ts +44 -0
  118. package/utils/escape-html.d.ts.map +1 -1
  119. package/utils/index.d.ts +1 -1
  120. package/utils/index.d.ts.map +1 -1
  121. package/utils/index.js +26 -0
  122. package/validation/index.js +0 -1
  123. package/validation/template-validator.d.ts.map +1 -1
  124. package/esm/adapters/index.d.ts +0 -13
  125. package/esm/adapters/index.d.ts.map +0 -1
  126. package/esm/adapters/platform-meta.d.ts +0 -166
  127. package/esm/adapters/platform-meta.d.ts.map +0 -1
  128. package/esm/adapters/response-builder.d.ts +0 -108
  129. package/esm/adapters/response-builder.d.ts.map +0 -1
  130. package/esm/adapters/serving-mode.d.ts +0 -107
  131. package/esm/adapters/serving-mode.d.ts.map +0 -1
  132. package/esm/base-template/bridge.d.ts +0 -90
  133. package/esm/base-template/bridge.d.ts.map +0 -1
  134. package/esm/base-template/default-base-template.d.ts +0 -92
  135. package/esm/base-template/default-base-template.d.ts.map +0 -1
  136. package/esm/base-template/index.d.ts +0 -15
  137. package/esm/base-template/index.d.ts.map +0 -1
  138. package/esm/base-template/polyfills.d.ts +0 -31
  139. package/esm/base-template/polyfills.d.ts.map +0 -1
  140. package/esm/base-template/theme-styles.d.ts +0 -74
  141. package/esm/base-template/theme-styles.d.ts.map +0 -1
  142. package/esm/bridge-runtime/iife-generator.d.ts +0 -62
  143. package/esm/bridge-runtime/iife-generator.d.ts.map +0 -1
  144. package/esm/bridge-runtime/index.d.ts +0 -10
  145. package/esm/bridge-runtime/index.d.ts.map +0 -1
  146. package/esm/build/cdn-resources.d.ts +0 -243
  147. package/esm/build/cdn-resources.d.ts.map +0 -1
  148. package/esm/build/index.d.ts +0 -295
  149. package/esm/build/index.d.ts.map +0 -1
  150. package/esm/build/widget-manifest.d.ts +0 -362
  151. package/esm/build/widget-manifest.d.ts.map +0 -1
  152. package/esm/bundler/cache.d.ts +0 -173
  153. package/esm/bundler/cache.d.ts.map +0 -1
  154. package/esm/bundler/file-cache/component-builder.d.ts +0 -167
  155. package/esm/bundler/file-cache/component-builder.d.ts.map +0 -1
  156. package/esm/bundler/file-cache/hash-calculator.d.ts +0 -155
  157. package/esm/bundler/file-cache/hash-calculator.d.ts.map +0 -1
  158. package/esm/bundler/file-cache/index.d.ts +0 -12
  159. package/esm/bundler/file-cache/index.d.ts.map +0 -1
  160. package/esm/bundler/file-cache/storage/filesystem.d.ts +0 -149
  161. package/esm/bundler/file-cache/storage/filesystem.d.ts.map +0 -1
  162. package/esm/bundler/file-cache/storage/index.d.ts +0 -11
  163. package/esm/bundler/file-cache/storage/index.d.ts.map +0 -1
  164. package/esm/bundler/file-cache/storage/interface.d.ts +0 -152
  165. package/esm/bundler/file-cache/storage/interface.d.ts.map +0 -1
  166. package/esm/bundler/file-cache/storage/redis.d.ts +0 -139
  167. package/esm/bundler/file-cache/storage/redis.d.ts.map +0 -1
  168. package/esm/bundler/index.d.ts +0 -35
  169. package/esm/bundler/index.d.ts.map +0 -1
  170. package/esm/bundler/sandbox/enclave-adapter.d.ts +0 -121
  171. package/esm/bundler/sandbox/enclave-adapter.d.ts.map +0 -1
  172. package/esm/bundler/sandbox/executor.d.ts +0 -14
  173. package/esm/bundler/sandbox/executor.d.ts.map +0 -1
  174. package/esm/bundler/sandbox/policy.d.ts +0 -62
  175. package/esm/bundler/sandbox/policy.d.ts.map +0 -1
  176. package/esm/bundler/types.d.ts +0 -702
  177. package/esm/bundler/types.d.ts.map +0 -1
  178. package/esm/dependency/cdn-registry.d.ts +0 -98
  179. package/esm/dependency/cdn-registry.d.ts.map +0 -1
  180. package/esm/dependency/import-map.d.ts +0 -186
  181. package/esm/dependency/import-map.d.ts.map +0 -1
  182. package/esm/dependency/import-parser.d.ts +0 -82
  183. package/esm/dependency/import-parser.d.ts.map +0 -1
  184. package/esm/dependency/index.d.ts +0 -17
  185. package/esm/dependency/index.d.ts.map +0 -1
  186. package/esm/dependency/resolver.d.ts +0 -164
  187. package/esm/dependency/resolver.d.ts.map +0 -1
  188. package/esm/dependency/schemas.d.ts +0 -486
  189. package/esm/dependency/schemas.d.ts.map +0 -1
  190. package/esm/dependency/template-loader.d.ts +0 -204
  191. package/esm/dependency/template-loader.d.ts.map +0 -1
  192. package/esm/dependency/template-processor.d.ts +0 -118
  193. package/esm/dependency/template-processor.d.ts.map +0 -1
  194. package/esm/dependency/types.d.ts +0 -739
  195. package/esm/dependency/types.d.ts.map +0 -1
  196. package/esm/handlebars/expression-extractor.d.ts +0 -147
  197. package/esm/handlebars/expression-extractor.d.ts.map +0 -1
  198. package/esm/handlebars/helpers.d.ts +0 -339
  199. package/esm/handlebars/helpers.d.ts.map +0 -1
  200. package/esm/handlebars/index.d.ts +0 -195
  201. package/esm/handlebars/index.d.ts.map +0 -1
  202. package/esm/index.d.ts +0 -50
  203. package/esm/index.d.ts.map +0 -1
  204. package/esm/registry/index.d.ts +0 -46
  205. package/esm/registry/index.d.ts.map +0 -1
  206. package/esm/registry/render-template.d.ts +0 -91
  207. package/esm/registry/render-template.d.ts.map +0 -1
  208. package/esm/registry/tool-ui.registry.d.ts +0 -294
  209. package/esm/registry/tool-ui.registry.d.ts.map +0 -1
  210. package/esm/registry/uri-utils.d.ts +0 -56
  211. package/esm/registry/uri-utils.d.ts.map +0 -1
  212. package/esm/renderers/cache.d.ts +0 -145
  213. package/esm/renderers/cache.d.ts.map +0 -1
  214. package/esm/renderers/html.renderer.d.ts +0 -123
  215. package/esm/renderers/html.renderer.d.ts.map +0 -1
  216. package/esm/renderers/index.d.ts +0 -36
  217. package/esm/renderers/index.d.ts.map +0 -1
  218. package/esm/renderers/mdx.renderer.d.ts +0 -120
  219. package/esm/renderers/mdx.renderer.d.ts.map +0 -1
  220. package/esm/renderers/registry.d.ts +0 -133
  221. package/esm/renderers/registry.d.ts.map +0 -1
  222. package/esm/renderers/types.d.ts +0 -342
  223. package/esm/renderers/types.d.ts.map +0 -1
  224. package/esm/renderers/utils/detect.d.ts +0 -107
  225. package/esm/renderers/utils/detect.d.ts.map +0 -1
  226. package/esm/renderers/utils/hash.d.ts +0 -40
  227. package/esm/renderers/utils/hash.d.ts.map +0 -1
  228. package/esm/renderers/utils/index.d.ts +0 -9
  229. package/esm/renderers/utils/index.d.ts.map +0 -1
  230. package/esm/renderers/utils/transpiler.d.ts +0 -89
  231. package/esm/renderers/utils/transpiler.d.ts.map +0 -1
  232. package/esm/runtime/adapters/html.adapter.d.ts +0 -59
  233. package/esm/runtime/adapters/html.adapter.d.ts.map +0 -1
  234. package/esm/runtime/adapters/index.d.ts +0 -26
  235. package/esm/runtime/adapters/index.d.ts.map +0 -1
  236. package/esm/runtime/adapters/mdx.adapter.d.ts +0 -73
  237. package/esm/runtime/adapters/mdx.adapter.d.ts.map +0 -1
  238. package/esm/runtime/adapters/types.d.ts +0 -95
  239. package/esm/runtime/adapters/types.d.ts.map +0 -1
  240. package/esm/runtime/csp.d.ts +0 -48
  241. package/esm/runtime/csp.d.ts.map +0 -1
  242. package/esm/runtime/index.d.ts +0 -17
  243. package/esm/runtime/index.d.ts.map +0 -1
  244. package/esm/runtime/mcp-bridge.d.ts +0 -101
  245. package/esm/runtime/mcp-bridge.d.ts.map +0 -1
  246. package/esm/runtime/renderer-runtime.d.ts +0 -133
  247. package/esm/runtime/renderer-runtime.d.ts.map +0 -1
  248. package/esm/runtime/sanitizer.d.ts +0 -172
  249. package/esm/runtime/sanitizer.d.ts.map +0 -1
  250. package/esm/runtime/types.d.ts +0 -415
  251. package/esm/runtime/types.d.ts.map +0 -1
  252. package/esm/runtime/wrapper.d.ts +0 -421
  253. package/esm/runtime/wrapper.d.ts.map +0 -1
  254. package/esm/styles/index.d.ts +0 -8
  255. package/esm/styles/index.d.ts.map +0 -1
  256. package/esm/styles/variants.d.ts +0 -51
  257. package/esm/styles/variants.d.ts.map +0 -1
  258. package/esm/theme/cdn.d.ts +0 -195
  259. package/esm/theme/cdn.d.ts.map +0 -1
  260. package/esm/theme/index.d.ts +0 -18
  261. package/esm/theme/index.d.ts.map +0 -1
  262. package/esm/theme/platforms.d.ts +0 -107
  263. package/esm/theme/platforms.d.ts.map +0 -1
  264. package/esm/theme/presets/github-openai.d.ts +0 -50
  265. package/esm/theme/presets/github-openai.d.ts.map +0 -1
  266. package/esm/theme/presets/index.d.ts +0 -11
  267. package/esm/theme/presets/index.d.ts.map +0 -1
  268. package/esm/theme/theme.d.ts +0 -396
  269. package/esm/theme/theme.d.ts.map +0 -1
  270. package/esm/tool-template/builder.d.ts +0 -213
  271. package/esm/tool-template/builder.d.ts.map +0 -1
  272. package/esm/tool-template/index.d.ts +0 -16
  273. package/esm/tool-template/index.d.ts.map +0 -1
  274. package/esm/types/index.d.ts +0 -14
  275. package/esm/types/index.d.ts.map +0 -1
  276. package/esm/types/ui-config.d.ts +0 -641
  277. package/esm/types/ui-config.d.ts.map +0 -1
  278. package/esm/types/ui-runtime.d.ts +0 -1008
  279. package/esm/types/ui-runtime.d.ts.map +0 -1
  280. package/esm/typings/cache/cache-adapter.d.ts +0 -125
  281. package/esm/typings/cache/cache-adapter.d.ts.map +0 -1
  282. package/esm/typings/cache/index.d.ts +0 -10
  283. package/esm/typings/cache/index.d.ts.map +0 -1
  284. package/esm/typings/cache/memory-cache.d.ts +0 -92
  285. package/esm/typings/cache/memory-cache.d.ts.map +0 -1
  286. package/esm/typings/dts-parser.d.ts +0 -90
  287. package/esm/typings/dts-parser.d.ts.map +0 -1
  288. package/esm/typings/index.d.ts +0 -48
  289. package/esm/typings/index.d.ts.map +0 -1
  290. package/esm/typings/schemas.d.ts +0 -232
  291. package/esm/typings/schemas.d.ts.map +0 -1
  292. package/esm/typings/type-fetcher.d.ts +0 -89
  293. package/esm/typings/type-fetcher.d.ts.map +0 -1
  294. package/esm/typings/types.d.ts +0 -320
  295. package/esm/typings/types.d.ts.map +0 -1
  296. package/esm/utils/escape-html.d.ts +0 -58
  297. package/esm/utils/escape-html.d.ts.map +0 -1
  298. package/esm/utils/index.d.ts +0 -10
  299. package/esm/utils/index.d.ts.map +0 -1
  300. package/esm/utils/safe-stringify.d.ts +0 -30
  301. package/esm/utils/safe-stringify.d.ts.map +0 -1
  302. package/esm/validation/error-box.d.ts +0 -56
  303. package/esm/validation/error-box.d.ts.map +0 -1
  304. package/esm/validation/index.d.ts +0 -13
  305. package/esm/validation/index.d.ts.map +0 -1
  306. package/esm/validation/schema-paths.d.ts +0 -118
  307. package/esm/validation/schema-paths.d.ts.map +0 -1
  308. package/esm/validation/template-validator.d.ts +0 -143
  309. package/esm/validation/template-validator.d.ts.map +0 -1
  310. package/esm/validation/wrapper.d.ts +0 -97
  311. package/esm/validation/wrapper.d.ts.map +0 -1
  312. package/renderers/mdx.renderer.d.ts +0 -120
  313. package/renderers/mdx.renderer.d.ts.map +0 -1
  314. /package/esm/bridge-runtime/{index.js → index.mjs} +0 -0
  315. /package/esm/types/{index.js → index.mjs} +0 -0
package/build/index.js CHANGED
@@ -30,13 +30,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  ));
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
- // libs/uipack/src/utils/safe-stringify.ts
34
- var init_safe_stringify = __esm({
35
- "libs/uipack/src/utils/safe-stringify.ts"() {
36
- "use strict";
37
- }
38
- });
39
-
40
33
  // libs/uipack/src/utils/escape-html.ts
41
34
  function escapeHtml(str) {
42
35
  if (str === null || str === void 0) {
@@ -48,6 +41,12 @@ function escapeHtml(str) {
48
41
  function escapeHtmlAttr(str) {
49
42
  return str.replace(/&/g, "&").replace(/"/g, """);
50
43
  }
44
+ function escapeJsString(str) {
45
+ return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
46
+ }
47
+ function escapeScriptClose(jsonString) {
48
+ return jsonString.replace(/<\//g, "<\\/");
49
+ }
51
50
  var init_escape_html = __esm({
52
51
  "libs/uipack/src/utils/escape-html.ts"() {
53
52
  "use strict";
@@ -58,7 +57,6 @@ var init_escape_html = __esm({
58
57
  var init_utils = __esm({
59
58
  "libs/uipack/src/utils/index.ts"() {
60
59
  "use strict";
61
- init_safe_stringify();
62
60
  init_escape_html();
63
61
  }
64
62
  });
@@ -289,7 +287,6 @@ var init_helpers = __esm({
289
287
  // libs/uipack/src/handlebars/expression-extractor.ts
290
288
  function extractExpressions(template) {
291
289
  const expressions = [];
292
- const lines = template.split("\n");
293
290
  const positionMap = buildPositionMap(template);
294
291
  let match;
295
292
  EXPRESSION_REGEX.lastIndex = 0;
@@ -684,7 +681,7 @@ async function calculateComponentHash(options) {
684
681
  const {
685
682
  entryPath,
686
683
  baseDir = (0, import_path.dirname)(entryPath),
687
- externals = [],
684
+ externals: _externals = [],
688
685
  dependencies = {},
689
686
  bundleOptions = {},
690
687
  maxDepth = 10
@@ -816,7 +813,7 @@ function getPackagePeerDependencies(packageName, registry = DEFAULT_CDN_REGISTRY
816
813
  }
817
814
  return [];
818
815
  }
819
- function resolveAllDependencies(packageNames, platform = "unknown", registry = DEFAULT_CDN_REGISTRY) {
816
+ function resolveAllDependencies(packageNames, _platform = "unknown", registry = DEFAULT_CDN_REGISTRY) {
820
817
  const resolved = /* @__PURE__ */ new Set();
821
818
  const queue = [...packageNames];
822
819
  while (queue.length > 0) {
@@ -2731,8 +2728,10 @@ var init_component_builder = __esm({
2731
2728
  return void 0;
2732
2729
  }
2733
2730
  try {
2734
- const React = await import("react");
2735
- const ReactDOMServer = await import("react-dom/server");
2731
+ const reactPkg = "react";
2732
+ const reactDomServerPkg = "react-dom/server";
2733
+ const React = await import(reactPkg);
2734
+ const ReactDOMServer = await import(reactDomServerPkg);
2736
2735
  const exports2 = {};
2737
2736
  const module2 = { exports: exports2 };
2738
2737
  if (executeCode) {
@@ -2760,51 +2759,80 @@ var init_component_builder = __esm({
2760
2759
  // libs/uipack/src/build/index.ts
2761
2760
  var build_exports = {};
2762
2761
  __export(build_exports, {
2762
+ BaseBuilder: () => BaseBuilder,
2763
+ CDN_URLS: () => CDN_URLS,
2763
2764
  CLAUDE_PLATFORM: () => CLAUDE_PLATFORM,
2764
2765
  CLOUDFLARE_CDN: () => CLOUDFLARE_CDN,
2766
+ CLOUDFLARE_CDN_URLS: () => CLOUDFLARE_CDN_URLS,
2765
2767
  DEFAULT_CSP_BY_TYPE: () => DEFAULT_CSP_BY_TYPE,
2768
+ DEFAULT_EXTERNALS: () => DEFAULT_EXTERNALS,
2766
2769
  DEFAULT_RENDERER_ASSETS: () => DEFAULT_RENDERER_ASSETS,
2767
2770
  DEFAULT_THEME: () => DEFAULT_THEME,
2771
+ EXTERNAL_GLOBALS: () => EXTERNAL_GLOBALS,
2768
2772
  HANDLEBARS_CDN: () => HANDLEBARS_CDN,
2773
+ HYBRID_DATA_PLACEHOLDER: () => HYBRID_DATA_PLACEHOLDER,
2774
+ HYBRID_INPUT_PLACEHOLDER: () => HYBRID_INPUT_PLACEHOLDER,
2775
+ HybridBuilder: () => HybridBuilder,
2776
+ InlineBuilder: () => InlineBuilder,
2769
2777
  MARKED_CDN: () => MARKED_CDN,
2770
2778
  MDX_RUNTIME_CDN: () => MDX_RUNTIME_CDN,
2771
2779
  OPENAI_PLATFORM: () => OPENAI_PLATFORM,
2772
- REACT_CDN: () => REACT_CDN2,
2780
+ REACT_CDN: () => REACT_CDN,
2773
2781
  REACT_DOM_CDN: () => REACT_DOM_CDN,
2782
+ StaticBuilder: () => StaticBuilder,
2774
2783
  TAILWIND_CDN: () => TAILWIND_CDN,
2775
2784
  batchBuildWidgets: () => batchBuildWidgets,
2785
+ buildAlertComponent: () => buildAlertComponent,
2786
+ buildBadgeComponent: () => buildBadgeComponent,
2787
+ buildButtonComponent: () => buildButtonComponent,
2776
2788
  buildCDNInfoForUIType: () => buildCDNInfoForUIType,
2777
2789
  buildCDNScriptTag: () => buildCDNScriptTag,
2778
2790
  buildCSPForType: () => buildCSPForType,
2779
2791
  buildCSPMetaContent: () => buildCSPMetaContent,
2792
+ buildCardComponent: () => buildCardComponent,
2780
2793
  buildCloudflareScriptTag: () => buildCloudflareScriptTag,
2781
2794
  buildCloudflareStylesheetTag: () => buildCloudflareStylesheetTag,
2782
2795
  buildFileComponent: () => buildFileComponent,
2783
2796
  buildFileComponents: () => buildFileComponents,
2797
+ buildNamespaceExport: () => buildNamespaceExport,
2784
2798
  buildScriptsForUIType: () => buildScriptsForUIType,
2785
2799
  buildStaticWidget: () => buildStaticWidget,
2800
+ buildStyleConstants: () => buildStyleConstants,
2786
2801
  buildTailwindScriptTag: () => buildTailwindScriptTag,
2787
2802
  buildToolResponseMeta: () => buildToolResponseMeta,
2788
2803
  buildToolUI: () => buildToolUI,
2789
2804
  buildToolUIMulti: () => buildToolUIMulti,
2790
2805
  buildToolWidgetManifest: () => buildToolWidgetManifest,
2806
+ buildUIComponentsRuntime: () => buildUIComponentsRuntime,
2807
+ createExternalizedConfig: () => createExternalizedConfig,
2808
+ createExternalsBanner: () => createExternalsBanner,
2809
+ createInlineConfig: () => createInlineConfig,
2791
2810
  createTemplateHelpers: () => createTemplateHelpers,
2811
+ createTransformConfig: () => createTransformConfig,
2792
2812
  detectUIType: () => detectUIType,
2813
+ generateCdnScriptTags: () => generateCdnScriptTags,
2814
+ generateGlobalsSetupScript: () => generateGlobalsSetupScript,
2793
2815
  getCachedFileComponent: () => getCachedFileComponent,
2794
2816
  getDefaultAssets: () => getDefaultAssets,
2817
+ getHybridPlaceholders: () => getHybridPlaceholders,
2795
2818
  getOutputModeForClient: () => getOutputModeForClient,
2796
2819
  getPlatformFromClientInfo: () => getPlatformFromClientInfo,
2797
2820
  getRendererAssets: () => getRendererAssets,
2798
2821
  getTailwindForPlatform: () => getTailwindForPlatform,
2799
2822
  getURLsToPreFetch: () => getURLsToPreFetch,
2800
2823
  hasInlineScripts: () => hasInlineScripts,
2824
+ injectHybridData: () => injectHybridData,
2825
+ injectHybridDataFull: () => injectHybridDataFull,
2826
+ injectHybridDataWithTrigger: () => injectHybridDataWithTrigger,
2801
2827
  isBundlingMode: () => isBundlingMode,
2802
2828
  isDisplayMode: () => isDisplayMode,
2803
2829
  isFilePathTemplate: () => isFilePathTemplate,
2830
+ isHybridShell: () => isHybridShell,
2804
2831
  isOutputMode: () => isOutputMode,
2805
2832
  isResourceMode: () => isResourceMode,
2806
2833
  isUIType: () => isUIType,
2807
- needsFileComponentRebuild: () => needsFileComponentRebuild
2834
+ needsFileComponentRebuild: () => needsFileComponentRebuild,
2835
+ needsInputInjection: () => needsInputInjection
2808
2836
  });
2809
2837
  module.exports = __toCommonJS(build_exports);
2810
2838
 
@@ -3656,9 +3684,6 @@ var BRIDGE_SCRIPT_TAGS = {
3656
3684
  gemini: `<script>${generatePlatformBundle("gemini")}</script>`
3657
3685
  };
3658
3686
 
3659
- // libs/uipack/src/runtime/mcp-bridge.ts
3660
- var FRONTMCP_BRIDGE_RUNTIME = BRIDGE_SCRIPT_TAGS.universal;
3661
-
3662
3687
  // libs/uipack/src/runtime/csp.ts
3663
3688
  var DEFAULT_CDN_DOMAINS = [
3664
3689
  "https://cdn.jsdelivr.net",
@@ -3781,9 +3806,6 @@ var scriptCache = /* @__PURE__ */ new Map();
3781
3806
  function getCachedScript(url) {
3782
3807
  return scriptCache.get(url);
3783
3808
  }
3784
- function isScriptCached(url) {
3785
- return scriptCache.has(url);
3786
- }
3787
3809
  function buildFontPreconnect() {
3788
3810
  return CDN.fonts.preconnect.map((url, i) => `<link rel="preconnect" href="${url}"${i > 0 ? " crossorigin" : ""}>`).join("\n ");
3789
3811
  }
@@ -3816,8 +3838,9 @@ function buildCdnScripts(options = {}) {
3816
3838
  const scripts = [];
3817
3839
  if (inline) {
3818
3840
  if (tailwind) {
3819
- if (isScriptCached(CDN.tailwind)) {
3820
- scripts.push(buildInlineScriptTag(getCachedScript(CDN.tailwind)));
3841
+ const cached = getCachedScript(CDN.tailwind);
3842
+ if (cached) {
3843
+ scripts.push(buildInlineScriptTag(cached));
3821
3844
  } else {
3822
3845
  console.warn(
3823
3846
  "[frontmcp/ui] Inline mode requested but Tailwind script not cached. Call fetchAndCacheScripts() first."
@@ -3825,8 +3848,9 @@ function buildCdnScripts(options = {}) {
3825
3848
  }
3826
3849
  }
3827
3850
  if (htmx) {
3828
- if (isScriptCached(CDN.htmx.url)) {
3829
- scripts.push(buildInlineScriptTag(getCachedScript(CDN.htmx.url)));
3851
+ const cached = getCachedScript(CDN.htmx.url);
3852
+ if (cached) {
3853
+ scripts.push(buildInlineScriptTag(cached));
3830
3854
  } else {
3831
3855
  console.warn(
3832
3856
  "[frontmcp/ui] Inline mode requested but HTMX script not cached. Call fetchAndCacheScripts() first."
@@ -3834,8 +3858,9 @@ function buildCdnScripts(options = {}) {
3834
3858
  }
3835
3859
  }
3836
3860
  if (alpine) {
3837
- if (isScriptCached(CDN.alpine.url)) {
3838
- scripts.push(buildInlineScriptTag(getCachedScript(CDN.alpine.url)));
3861
+ const cached = getCachedScript(CDN.alpine.url);
3862
+ if (cached) {
3863
+ scripts.push(buildInlineScriptTag(cached));
3839
3864
  } else {
3840
3865
  console.warn(
3841
3866
  "[frontmcp/ui] Inline mode requested but Alpine.js script not cached. Call fetchAndCacheScripts() first."
@@ -3843,8 +3868,9 @@ function buildCdnScripts(options = {}) {
3843
3868
  }
3844
3869
  }
3845
3870
  if (icons) {
3846
- if (isScriptCached(CDN.icons.url)) {
3847
- scripts.push(buildInlineScriptTag(getCachedScript(CDN.icons.url)));
3871
+ const cached = getCachedScript(CDN.icons.url);
3872
+ if (cached) {
3873
+ scripts.push(buildInlineScriptTag(cached));
3848
3874
  } else {
3849
3875
  console.warn(
3850
3876
  "[frontmcp/ui] Inline mode requested but Lucide icons script not cached. Call fetchAndCacheScripts() first."
@@ -3886,11 +3912,12 @@ var CLAUDE_PLATFORM = {
3886
3912
  id: "claude",
3887
3913
  name: "Claude (Artifacts)",
3888
3914
  supportsWidgets: true,
3915
+ // Claude Artifacts support interactive widgets
3889
3916
  supportsTailwind: true,
3890
3917
  supportsHtmx: false,
3891
3918
  // Network blocked, HTMX won't work for API calls
3892
- networkMode: "blocked",
3893
- scriptStrategy: "inline",
3919
+ networkMode: "limited",
3920
+ scriptStrategy: "cdn",
3894
3921
  maxInlineSize: 100 * 1024,
3895
3922
  // 100KB limit for artifacts
3896
3923
  cspRestrictions: ["script-src 'unsafe-inline'", "connect-src 'none'"],
@@ -4140,17 +4167,31 @@ function emitColorScale(lines, name, scale) {
4140
4167
  if (value) lines.push(`--color-${name}-${shade}: ${value};`);
4141
4168
  }
4142
4169
  }
4170
+ var OPACITY_VARIANTS = [10, 20, 30, 50, 70, 90];
4171
+ function emitColorWithOpacityVariants(lines, name, value) {
4172
+ lines.push(`--color-${name}: ${value};`);
4173
+ for (const opacity of OPACITY_VARIANTS) {
4174
+ lines.push(`--color-${name}-${opacity}: color-mix(in oklch, ${value} ${opacity}%, transparent);`);
4175
+ }
4176
+ }
4177
+ function emitBrandColorWithVariants(lines, name, value) {
4178
+ lines.push(`--color-${name}: ${value};`);
4179
+ lines.push(`--color-${name}-hover: color-mix(in oklch, ${value} 85%, black);`);
4180
+ for (const opacity of OPACITY_VARIANTS) {
4181
+ lines.push(`--color-${name}-${opacity}: color-mix(in oklch, ${value} ${opacity}%, transparent);`);
4182
+ }
4183
+ }
4143
4184
  function buildThemeCss(theme) {
4144
4185
  const lines = [];
4145
4186
  const semantic = theme.colors.semantic;
4146
4187
  if (typeof semantic.primary === "string") {
4147
- lines.push(`--color-primary: ${semantic.primary};`);
4188
+ emitBrandColorWithVariants(lines, "primary", semantic.primary);
4148
4189
  } else if (semantic.primary) {
4149
4190
  emitColorScale(lines, "primary", semantic.primary);
4150
4191
  }
4151
4192
  if (semantic.secondary) {
4152
4193
  if (typeof semantic.secondary === "string") {
4153
- lines.push(`--color-secondary: ${semantic.secondary};`);
4194
+ emitBrandColorWithVariants(lines, "secondary", semantic.secondary);
4154
4195
  } else {
4155
4196
  emitColorScale(lines, "secondary", semantic.secondary);
4156
4197
  }
@@ -4169,10 +4210,10 @@ function buildThemeCss(theme) {
4169
4210
  emitColorScale(lines, "neutral", semantic.neutral);
4170
4211
  }
4171
4212
  }
4172
- if (semantic.success) lines.push(`--color-success: ${semantic.success};`);
4173
- if (semantic.warning) lines.push(`--color-warning: ${semantic.warning};`);
4174
- if (semantic.danger) lines.push(`--color-danger: ${semantic.danger};`);
4175
- if (semantic.info) lines.push(`--color-info: ${semantic.info};`);
4213
+ if (semantic.success) emitColorWithOpacityVariants(lines, "success", semantic.success);
4214
+ if (semantic.warning) emitColorWithOpacityVariants(lines, "warning", semantic.warning);
4215
+ if (semantic.danger) emitColorWithOpacityVariants(lines, "danger", semantic.danger);
4216
+ if (semantic.info) emitColorWithOpacityVariants(lines, "info", semantic.info);
4176
4217
  const surface = theme.colors.surface;
4177
4218
  if (surface?.background) lines.push(`--color-background: ${surface.background};`);
4178
4219
  if (surface?.surface) lines.push(`--color-surface: ${surface.surface};`);
@@ -5055,35 +5096,25 @@ var ComponentCache = class {
5055
5096
  };
5056
5097
  var componentCache = new ComponentCache();
5057
5098
 
5058
- // libs/uipack/src/renderers/mdx.renderer.ts
5059
- var REACT_CDN = {
5060
- react: "https://unpkg.com/react@18/umd/react.production.min.js",
5061
- reactDom: "https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"
5099
+ // libs/uipack/src/renderers/mdx-client.renderer.ts
5100
+ init_utils();
5101
+ function buildReactCdnUrls(version = "19") {
5102
+ return {
5103
+ react: `https://esm.sh/react@${version}`,
5104
+ reactDom: `https://esm.sh/react-dom@${version}/client`,
5105
+ jsxRuntime: `https://esm.sh/react@${version}/jsx-runtime`
5106
+ };
5107
+ }
5108
+ var DEFAULT_CDN = {
5109
+ mdx: "https://esm.sh/@mdx-js/mdx@3",
5110
+ ...buildReactCdnUrls("19")
5062
5111
  };
5063
- var INLINE_MDX_PLACEHOLDER = `
5064
- // MDX runtime not available inline yet.
5065
- // For blocked-network platforms, use pre-rendered HTML templates.
5066
- console.warn('[FrontMCP] MDX hydration not available on this platform.');
5067
- `;
5068
- var MdxRenderer = class {
5069
- type = "mdx";
5070
- priority = 10;
5071
- // Between HTML (0) and React (20)
5072
- /**
5073
- * Lazy-loaded modules.
5074
- */
5075
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5076
- React = null;
5077
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5078
- ReactDOMServer = null;
5079
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5080
- jsxRuntime = null;
5081
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5082
- mdxEvaluate = null;
5112
+ var MdxClientRenderer = class {
5113
+ type = "mdx-client";
5114
+ priority = 8;
5115
+ // Lower than server-side MDX (10)
5083
5116
  /**
5084
5117
  * Check if this renderer can handle the given template.
5085
- *
5086
- * Accepts strings containing MDX syntax (Markdown + JSX).
5087
5118
  */
5088
5119
  canHandle(template) {
5089
5120
  if (typeof template !== "string") {
@@ -5092,11 +5123,9 @@ var MdxRenderer = class {
5092
5123
  return containsMdxSyntax(template);
5093
5124
  }
5094
5125
  /**
5095
- * Transpile MDX to executable JavaScript.
5096
- *
5097
- * Uses @mdx-js/mdx to compile MDX source to a module.
5098
- * Note: For MDX, we use evaluate() which combines compile + run,
5099
- * so this method just returns the source hash for caching purposes.
5126
+ * Prepare MDX template for rendering.
5127
+ * Caches the template hash for deduplication. Actual MDX compilation
5128
+ * happens client-side via CDN-loaded @mdx-js/mdx in the browser.
5100
5129
  */
5101
5130
  async transpile(template, _options) {
5102
5131
  const hash = hashString(template);
@@ -5106,7 +5135,6 @@ var MdxRenderer = class {
5106
5135
  }
5107
5136
  const transpileResult = {
5108
5137
  code: template,
5109
- // Store original MDX for evaluate()
5110
5138
  hash,
5111
5139
  cached: false
5112
5140
  };
@@ -5114,37 +5142,20 @@ var MdxRenderer = class {
5114
5142
  return transpileResult;
5115
5143
  }
5116
5144
  /**
5117
- * Render MDX template to HTML string.
5145
+ * Render MDX template to HTML with CDN scripts.
5118
5146
  *
5119
- * Uses @mdx-js/mdx's evaluate() for clean compilation + execution,
5120
- * then renders the resulting React component to HTML via SSR.
5147
+ * The returned HTML includes:
5148
+ * - A container div for the rendered content
5149
+ * - Script tags that load React and MDX from CDN
5150
+ * - Inline script that compiles and renders the MDX
5121
5151
  */
5122
5152
  async render(template, context, options) {
5123
- await this.loadReact();
5124
- await this.loadMdx();
5125
- if (!this.mdxEvaluate) {
5126
- throw new Error("MDX compilation requires @mdx-js/mdx. Install it: npm install @mdx-js/mdx");
5127
- }
5128
- const templateHash = hashString(template);
5129
- const cacheKey = `mdx-component:${templateHash}`;
5130
- let Content = componentCache.get(cacheKey);
5131
- if (!Content) {
5132
- const result = await this.mdxEvaluate(template, {
5133
- ...this.jsxRuntime,
5134
- Fragment: this.React.Fragment,
5135
- development: false
5136
- });
5137
- Content = result.default;
5138
- componentCache.set(cacheKey, Content);
5139
- }
5140
- const mdxComponents = {
5141
- // User-provided components from tool config
5142
- ...options?.mdxComponents,
5143
- // Wrapper that provides context to the content
5144
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5145
- wrapper: ({ children }) => {
5146
- return this.React.createElement("div", { className: "mdx-content" }, children);
5147
- }
5153
+ const containerId = options?.containerId || "mdx-content";
5154
+ const showLoading = options?.showLoading !== false;
5155
+ const loadingMessage = options?.loadingMessage || "Loading...";
5156
+ const cdn = {
5157
+ ...DEFAULT_CDN,
5158
+ ...options?.cdn
5148
5159
  };
5149
5160
  const props = {
5150
5161
  input: context.input,
@@ -5152,82 +5163,80 @@ var MdxRenderer = class {
5152
5163
  structuredContent: context.structuredContent,
5153
5164
  helpers: context.helpers
5154
5165
  };
5166
+ const reservedProps = /* @__PURE__ */ new Set(["input", "output", "structuredContent", "helpers", "components"]);
5167
+ const outputProps = typeof context.output === "object" && context.output !== null ? Object.fromEntries(Object.entries(context.output).filter(([key]) => !reservedProps.has(key))) : {};
5155
5168
  const spreadProps = {
5156
- ...props,
5157
- ...typeof context.output === "object" && context.output !== null ? context.output : {}
5169
+ ...outputProps,
5170
+ ...props
5158
5171
  };
5159
- const element = this.React.createElement(Content, {
5160
- components: mdxComponents,
5161
- ...spreadProps
5172
+ const escapedMdx = escapeScriptClose(JSON.stringify(template));
5173
+ const escapedProps = escapeScriptClose(JSON.stringify(spreadProps));
5174
+ const safeContainerId = escapeJsString(containerId);
5175
+ const loadingHtml = showLoading ? `<div class="mdx-loading">${escapeHtml(loadingMessage)}</div>` : "";
5176
+ return `
5177
+ <div id="${escapeHtml(containerId)}">${loadingHtml}</div>
5178
+ <script type="module">
5179
+ (async function() {
5180
+ try {
5181
+ // Load dependencies from CDN
5182
+ const [
5183
+ { evaluate },
5184
+ runtime,
5185
+ React,
5186
+ { createRoot }
5187
+ ] = await Promise.all([
5188
+ import('${cdn.mdx}'),
5189
+ import('${cdn.jsxRuntime}'),
5190
+ import('${cdn.react}'),
5191
+ import('${cdn.reactDom}')
5192
+ ]);
5193
+
5194
+ // MDX content and props
5195
+ const mdxSource = ${escapedMdx};
5196
+ const props = ${escapedProps};
5197
+
5198
+ // Compile and evaluate MDX
5199
+ const { default: Content } = await evaluate(mdxSource, {
5200
+ ...runtime,
5201
+ Fragment: React.Fragment,
5202
+ development: false
5162
5203
  });
5163
- const html = this.ReactDOMServer.renderToString(element);
5164
- if (options?.hydrate) {
5165
- const escapedProps = JSON.stringify(props).replace(/&/g, "&amp;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5166
- return `<div data-mdx-hydrate="true" data-props='${escapedProps}'>${html}</div>`;
5204
+
5205
+ // Render to DOM
5206
+ const container = document.getElementById('${safeContainerId}');
5207
+ if (container) {
5208
+ const root = createRoot(container);
5209
+ root.render(React.createElement(Content, props));
5167
5210
  }
5168
- return html;
5211
+ } catch (error) {
5212
+ console.error('[FrontMCP] MDX client rendering failed:', error);
5213
+ const container = document.getElementById('${safeContainerId}');
5214
+ if (container) {
5215
+ container.innerHTML = '<div class="mdx-error">Failed to render MDX content</div>';
5216
+ }
5217
+ }
5218
+ })();
5219
+ </script>
5220
+ `;
5169
5221
  }
5170
5222
  /**
5171
- * Get runtime scripts for client-side functionality.
5223
+ * Get runtime scripts - not needed for client renderer since scripts are inline.
5172
5224
  */
5173
5225
  getRuntimeScripts(platform) {
5174
5226
  if (platform.networkMode === "blocked") {
5175
5227
  return {
5176
5228
  headScripts: "",
5177
- inlineScripts: INLINE_MDX_PLACEHOLDER,
5229
+ inlineScripts: `console.warn('[FrontMCP] Client-side MDX rendering requires network access. Use @frontmcp/ui for SSR.');`,
5178
5230
  isInline: true
5179
5231
  };
5180
5232
  }
5181
5233
  return {
5182
- headScripts: `
5183
- <script crossorigin src="${REACT_CDN.react}"></script>
5184
- <script crossorigin src="${REACT_CDN.reactDom}"></script>
5185
- `,
5234
+ headScripts: "",
5186
5235
  isInline: false
5187
5236
  };
5188
5237
  }
5189
- /**
5190
- * Load React and ReactDOMServer modules.
5191
- */
5192
- async loadReact() {
5193
- if (this.React && this.ReactDOMServer && this.jsxRuntime) {
5194
- return;
5195
- }
5196
- try {
5197
- const [react, reactDomServer, jsxRuntime] = await Promise.all([
5198
- import("react"),
5199
- import("react-dom/server"),
5200
- import("react/jsx-runtime")
5201
- ]);
5202
- this.React = react;
5203
- this.ReactDOMServer = reactDomServer;
5204
- this.jsxRuntime = jsxRuntime;
5205
- } catch {
5206
- throw new Error("React is required for MdxRenderer. Install react and react-dom: npm install react react-dom");
5207
- }
5208
- }
5209
- /**
5210
- * Load @mdx-js/mdx evaluate function.
5211
- *
5212
- * evaluate() is the cleanest way to run MDX - it combines
5213
- * compile and run in a single step, handling all the runtime
5214
- * injection automatically.
5215
- */
5216
- async loadMdx() {
5217
- if (this.mdxEvaluate) {
5218
- return;
5219
- }
5220
- try {
5221
- const mdx = await import("@mdx-js/mdx");
5222
- this.mdxEvaluate = mdx.evaluate;
5223
- } catch {
5224
- console.warn(
5225
- "[@frontmcp/ui] @mdx-js/mdx not available. MDX rendering disabled. Install @mdx-js/mdx to enable: npm install @mdx-js/mdx"
5226
- );
5227
- }
5228
- }
5229
5238
  };
5230
- var mdxRenderer = new MdxRenderer();
5239
+ var mdxClientRenderer = new MdxClientRenderer();
5231
5240
 
5232
5241
  // libs/uipack/src/types/ui-runtime.ts
5233
5242
  function isUIType(value) {
@@ -5297,7 +5306,7 @@ var DEFAULT_RENDERER_ASSETS = {
5297
5306
  };
5298
5307
 
5299
5308
  // libs/uipack/src/build/cdn-resources.ts
5300
- var REACT_CDN2 = {
5309
+ var REACT_CDN = {
5301
5310
  url: "https://esm.sh/react@19",
5302
5311
  crossorigin: "anonymous"
5303
5312
  };
@@ -5327,8 +5336,9 @@ var CLOUDFLARE_CDN = {
5327
5336
  * Use this instead of TAILWIND_CDN for Claude Artifacts.
5328
5337
  */
5329
5338
  tailwindCss: {
5330
- url: "https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css",
5331
- type: "stylesheet"
5339
+ url: "https://cdnjs.cloudflare.com/ajax/libs/tailwindcss-browser/4.1.13/index.global.min.js",
5340
+ integrity: "sha512-TscjjxDy2iXx5s55Ar78c01JDHUug0K5aw4YKId9Yuocjx3ueX/X9PFyH5XNRVWqagx3TtcQWQVBaHAIPFjiFA==",
5341
+ crossorigin: "anonymous"
5332
5342
  },
5333
5343
  /**
5334
5344
  * HTMX for dynamic interactions.
@@ -5368,7 +5378,7 @@ function getTailwindForPlatform(platform) {
5368
5378
  if (platform === "openai") {
5369
5379
  return buildCDNScriptTag(TAILWIND_CDN);
5370
5380
  }
5371
- return `<link href="${CLOUDFLARE_CDN.tailwindCss.url}" rel="stylesheet">`;
5381
+ return buildCDNScriptTag(CLOUDFLARE_CDN.tailwindCss);
5372
5382
  }
5373
5383
  function buildCloudflareStylesheetTag(url) {
5374
5384
  return `<link href="${url}" rel="stylesheet">`;
@@ -5395,13 +5405,13 @@ function getDefaultAssets(uiType, mode = "cdn") {
5395
5405
  case "react":
5396
5406
  return {
5397
5407
  ...baseAssets,
5398
- react: REACT_CDN2,
5408
+ react: REACT_CDN,
5399
5409
  reactDom: REACT_DOM_CDN
5400
5410
  };
5401
5411
  case "mdx":
5402
5412
  return {
5403
5413
  ...baseAssets,
5404
- react: REACT_CDN2,
5414
+ react: REACT_CDN,
5405
5415
  reactDom: REACT_DOM_CDN,
5406
5416
  mdxRuntime: MDX_RUNTIME_CDN,
5407
5417
  markdown: MARKED_CDN
@@ -5419,7 +5429,7 @@ function getDefaultAssets(uiType, mode = "cdn") {
5419
5429
  case "auto":
5420
5430
  return {
5421
5431
  ...baseAssets,
5422
- react: REACT_CDN2,
5432
+ react: REACT_CDN,
5423
5433
  reactDom: REACT_DOM_CDN,
5424
5434
  markdown: MARKED_CDN,
5425
5435
  handlebars: HANDLEBARS_CDN
@@ -5497,13 +5507,13 @@ function buildCDNInfoForUIType(uiType) {
5497
5507
  switch (uiType) {
5498
5508
  case "react":
5499
5509
  return {
5500
- react: REACT_CDN2.url,
5510
+ react: REACT_CDN.url,
5501
5511
  reactDom: REACT_DOM_CDN.url,
5502
5512
  tailwind: TAILWIND_CDN.url
5503
5513
  };
5504
5514
  case "mdx":
5505
5515
  return {
5506
- react: REACT_CDN2.url,
5516
+ react: REACT_CDN.url,
5507
5517
  reactDom: REACT_DOM_CDN.url,
5508
5518
  mdxRuntime: MDX_RUNTIME_CDN.url,
5509
5519
  marked: MARKED_CDN.url,
@@ -5522,7 +5532,7 @@ function buildCDNInfoForUIType(uiType) {
5522
5532
  case "auto":
5523
5533
  default:
5524
5534
  return {
5525
- react: REACT_CDN2.url,
5535
+ react: REACT_CDN.url,
5526
5536
  reactDom: REACT_DOM_CDN.url,
5527
5537
  handlebars: HANDLEBARS_CDN.url,
5528
5538
  marked: MARKED_CDN.url,
@@ -5567,9 +5577,6 @@ function detectFormatFromPath(pathOrUrl) {
5567
5577
  return "html";
5568
5578
  }
5569
5579
 
5570
- // libs/uipack/src/validation/error-box.ts
5571
- init_utils();
5572
-
5573
5580
  // libs/uipack/src/validation/schema-paths.ts
5574
5581
  var import_zod = require("zod");
5575
5582
  function extractSchemaPaths(schema, prefix = "output", options = {}) {
@@ -6113,7 +6120,7 @@ async function processTemplate(resolved, options) {
6113
6120
  structuredContent: context.structuredContent,
6114
6121
  helpers: defaultHelpers
6115
6122
  };
6116
- const html = await mdxRenderer.render(processedContent, templateContext);
6123
+ const html = await mdxClientRenderer.render(processedContent, templateContext);
6117
6124
  return {
6118
6125
  html,
6119
6126
  format: "mdx"
@@ -6239,7 +6246,7 @@ async function generateHash(content) {
6239
6246
  return Math.abs(hash).toString(16).padStart(8, "0");
6240
6247
  }
6241
6248
  async function buildToolWidgetManifest(options) {
6242
- const { toolName, uiConfig, schema, theme, sampleInput, sampleOutput, outputSchema, inputSchema } = options;
6249
+ const { toolName, uiConfig, schema, theme: _theme, sampleInput, sampleOutput, outputSchema, inputSchema } = options;
6243
6250
  const uiType = isUIType(uiConfig.uiType) ? uiConfig.uiType : detectUIType(uiConfig.template);
6244
6251
  const displayMode = uiConfig.displayMode ?? "inline";
6245
6252
  const bundlingMode = uiConfig.bundlingMode ?? "static";
@@ -6377,7 +6384,7 @@ function ensureRenderersRegistered() {
6377
6384
  return;
6378
6385
  }
6379
6386
  if (!rendererRegistry.has("mdx")) {
6380
- rendererRegistry.register(mdxRenderer);
6387
+ rendererRegistry.register(mdxClientRenderer);
6381
6388
  }
6382
6389
  renderersInitialized = true;
6383
6390
  }
@@ -6665,6 +6672,1684 @@ function getPlatformFromClientInfo(clientInfo) {
6665
6672
  return "unknown";
6666
6673
  }
6667
6674
 
6675
+ // libs/uipack/src/build/hybrid-data.ts
6676
+ var HYBRID_DATA_PLACEHOLDER = "__FRONTMCP_OUTPUT_PLACEHOLDER__";
6677
+ var HYBRID_INPUT_PLACEHOLDER = "__FRONTMCP_INPUT_PLACEHOLDER__";
6678
+ function injectHybridData(shell, data, placeholder = HYBRID_DATA_PLACEHOLDER) {
6679
+ let jsonData;
6680
+ try {
6681
+ jsonData = JSON.stringify(JSON.stringify(data));
6682
+ jsonData = jsonData.slice(1, -1);
6683
+ } catch {
6684
+ jsonData = "null";
6685
+ }
6686
+ return shell.replace(placeholder, jsonData);
6687
+ }
6688
+ function injectHybridDataFull(shell, input, output) {
6689
+ let result = shell;
6690
+ result = injectHybridData(result, output, HYBRID_DATA_PLACEHOLDER);
6691
+ result = injectHybridData(result, input, HYBRID_INPUT_PLACEHOLDER);
6692
+ return result;
6693
+ }
6694
+ function isHybridShell(html, placeholder = HYBRID_DATA_PLACEHOLDER) {
6695
+ return html.includes(placeholder);
6696
+ }
6697
+ function needsInputInjection(html) {
6698
+ return html.includes(HYBRID_INPUT_PLACEHOLDER);
6699
+ }
6700
+ function getHybridPlaceholders(html) {
6701
+ return {
6702
+ hasOutput: html.includes(HYBRID_DATA_PLACEHOLDER),
6703
+ hasInput: html.includes(HYBRID_INPUT_PLACEHOLDER)
6704
+ };
6705
+ }
6706
+ function injectHybridDataWithTrigger(shell, input, output) {
6707
+ let result = injectHybridDataFull(shell, input, output);
6708
+ let outputJson;
6709
+ try {
6710
+ outputJson = JSON.stringify(output);
6711
+ } catch {
6712
+ outputJson = "null";
6713
+ }
6714
+ const triggerScript = `
6715
+ <script>
6716
+ (function() {
6717
+ var data = ${outputJson};
6718
+
6719
+ function triggerUpdate() {
6720
+ if (window.__frontmcp && window.__frontmcp.updateOutput) {
6721
+ window.__frontmcp.updateOutput(data);
6722
+ } else if (window.mcpBridge) {
6723
+ // Trigger via bridge listeners
6724
+ window.dispatchEvent(new CustomEvent('frontmcp:toolResult', { detail: data }));
6725
+ }
6726
+ }
6727
+
6728
+ if (document.readyState === 'loading') {
6729
+ document.addEventListener('DOMContentLoaded', triggerUpdate);
6730
+ } else {
6731
+ // Small delay to ensure store is initialized
6732
+ setTimeout(triggerUpdate, 0);
6733
+ }
6734
+ })();
6735
+ </script>`;
6736
+ result = result.replace("</body>", triggerScript + "\n</body>");
6737
+ return result;
6738
+ }
6739
+
6740
+ // libs/uipack/src/styles/variants.ts
6741
+ var CARD_VARIANTS = {
6742
+ default: "bg-white border border-border rounded-xl shadow-sm",
6743
+ outlined: "bg-transparent border-2 border-border rounded-xl",
6744
+ elevated: "bg-white rounded-xl shadow-lg",
6745
+ filled: "bg-gray-50 rounded-xl",
6746
+ ghost: "bg-transparent"
6747
+ };
6748
+ var CARD_SIZES = {
6749
+ sm: "p-4",
6750
+ md: "p-6",
6751
+ lg: "p-8"
6752
+ };
6753
+ var BADGE_VARIANTS = {
6754
+ default: "bg-gray-100 text-gray-800",
6755
+ primary: "bg-primary/10 text-primary",
6756
+ secondary: "bg-secondary/10 text-secondary",
6757
+ success: "bg-success/10 text-success",
6758
+ warning: "bg-warning/10 text-warning",
6759
+ danger: "bg-danger/10 text-danger",
6760
+ info: "bg-info/10 text-info",
6761
+ outline: "border border-border text-text-primary bg-transparent"
6762
+ };
6763
+ var BADGE_SIZES = {
6764
+ sm: "px-2 py-0.5 text-xs",
6765
+ md: "px-2.5 py-1 text-xs",
6766
+ lg: "px-3 py-1.5 text-sm"
6767
+ };
6768
+ var BADGE_DOT_SIZES = {
6769
+ sm: "w-2 h-2",
6770
+ md: "w-2.5 h-2.5",
6771
+ lg: "w-3 h-3"
6772
+ };
6773
+ var BADGE_DOT_VARIANTS = {
6774
+ default: "bg-gray-400",
6775
+ primary: "bg-primary",
6776
+ secondary: "bg-secondary",
6777
+ success: "bg-success",
6778
+ warning: "bg-warning",
6779
+ danger: "bg-danger",
6780
+ info: "bg-info",
6781
+ outline: "border border-current"
6782
+ };
6783
+ var BUTTON_VARIANTS = {
6784
+ primary: "bg-primary hover:bg-primary/90 text-white shadow-sm",
6785
+ secondary: "bg-secondary hover:bg-secondary/90 text-white shadow-sm",
6786
+ outline: "border-2 border-primary text-primary bg-transparent hover:bg-primary/10",
6787
+ ghost: "text-text-primary hover:bg-gray-100",
6788
+ danger: "bg-danger hover:bg-danger/90 text-white shadow-sm",
6789
+ success: "bg-success hover:bg-success/90 text-white shadow-sm",
6790
+ link: "text-primary hover:text-primary/80 hover:underline"
6791
+ };
6792
+ var BUTTON_SIZES = {
6793
+ xs: "px-2.5 py-1.5 text-xs",
6794
+ sm: "px-3 py-2 text-sm",
6795
+ md: "px-4 py-2.5 text-sm",
6796
+ lg: "px-5 py-3 text-base",
6797
+ xl: "px-6 py-3.5 text-lg"
6798
+ };
6799
+ var BUTTON_ICON_SIZES = {
6800
+ xs: "p-1.5",
6801
+ sm: "p-2",
6802
+ md: "p-2.5",
6803
+ lg: "p-3",
6804
+ xl: "p-4"
6805
+ };
6806
+ var BUTTON_BASE_CLASSES = "cursor-pointer inline-flex items-center justify-center font-medium rounded-lg transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-primary/50 focus:ring-offset-2";
6807
+ var ALERT_VARIANTS = {
6808
+ info: {
6809
+ container: "bg-info/10 border-info/30 text-info",
6810
+ icon: "text-info"
6811
+ },
6812
+ success: {
6813
+ container: "bg-success/10 border-success/30 text-success",
6814
+ icon: "text-success"
6815
+ },
6816
+ warning: {
6817
+ container: "bg-warning/10 border-warning/30 text-warning",
6818
+ icon: "text-warning"
6819
+ },
6820
+ danger: {
6821
+ container: "bg-danger/10 border-danger/30 text-danger",
6822
+ icon: "text-danger"
6823
+ },
6824
+ neutral: {
6825
+ container: "bg-gray-50 border-gray-200 text-gray-800",
6826
+ icon: "text-gray-500"
6827
+ }
6828
+ };
6829
+ var ALERT_BASE_CLASSES = "rounded-lg border p-4";
6830
+ var ALERT_ICONS = {
6831
+ info: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6832
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
6833
+ </svg>`,
6834
+ success: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6835
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
6836
+ </svg>`,
6837
+ warning: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6838
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
6839
+ </svg>`,
6840
+ danger: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6841
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"/>
6842
+ </svg>`,
6843
+ neutral: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6844
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
6845
+ </svg>`
6846
+ };
6847
+ var CLOSE_ICON = `<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6848
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
6849
+ </svg>`;
6850
+ var LOADING_SPINNER = `<svg class="animate-spin -ml-1 mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24">
6851
+ <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
6852
+ <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>
6853
+ </svg>`;
6854
+
6855
+ // libs/uipack/src/build/ui-components-browser.ts
6856
+ function buildStyleConstants() {
6857
+ return `
6858
+ // Style Constants (from @frontmcp/uipack/styles)
6859
+ var CARD_VARIANTS = ${JSON.stringify(CARD_VARIANTS)};
6860
+ var CARD_SIZES = ${JSON.stringify(CARD_SIZES)};
6861
+
6862
+ var BUTTON_VARIANTS = ${JSON.stringify(BUTTON_VARIANTS)};
6863
+ var BUTTON_SIZES = ${JSON.stringify(BUTTON_SIZES)};
6864
+ var BUTTON_ICON_SIZES = ${JSON.stringify(BUTTON_ICON_SIZES)};
6865
+ var BUTTON_BASE_CLASSES = ${JSON.stringify(BUTTON_BASE_CLASSES)};
6866
+ var LOADING_SPINNER = ${JSON.stringify(LOADING_SPINNER)};
6867
+
6868
+ var BADGE_VARIANTS = ${JSON.stringify(BADGE_VARIANTS)};
6869
+ var BADGE_SIZES = ${JSON.stringify(BADGE_SIZES)};
6870
+ var BADGE_DOT_SIZES = ${JSON.stringify(BADGE_DOT_SIZES)};
6871
+ var BADGE_DOT_VARIANTS = ${JSON.stringify(BADGE_DOT_VARIANTS)};
6872
+
6873
+ var ALERT_VARIANTS = ${JSON.stringify(ALERT_VARIANTS)};
6874
+ var ALERT_BASE_CLASSES = ${JSON.stringify(ALERT_BASE_CLASSES)};
6875
+ var ALERT_ICONS = ${JSON.stringify(ALERT_ICONS)};
6876
+ var CLOSE_ICON = ${JSON.stringify(CLOSE_ICON)};
6877
+
6878
+ // Utility: Join CSS classes, filtering out falsy values
6879
+ function cn() {
6880
+ var result = [];
6881
+ for (var i = 0; i < arguments.length; i++) {
6882
+ if (arguments[i]) result.push(arguments[i]);
6883
+ }
6884
+ return result.join(' ');
6885
+ }
6886
+ `;
6887
+ }
6888
+ function buildCardComponent() {
6889
+ return `
6890
+ // Card Component (matches @frontmcp/ui/react/Card)
6891
+ window.Card = function Card(props) {
6892
+ var title = props.title;
6893
+ var subtitle = props.subtitle;
6894
+ var headerActions = props.headerActions;
6895
+ var footer = props.footer;
6896
+ var variant = props.variant || 'default';
6897
+ var size = props.size || 'md';
6898
+ var className = props.className;
6899
+ var id = props.id;
6900
+ var clickable = props.clickable;
6901
+ var href = props.href;
6902
+ var children = props.children;
6903
+
6904
+ var variantClasses = CARD_VARIANTS[variant] || CARD_VARIANTS.default;
6905
+ var sizeClasses = CARD_SIZES[size] || CARD_SIZES.md;
6906
+ var clickableClasses = clickable ? 'cursor-pointer hover:shadow-md transition-shadow' : '';
6907
+ var allClasses = cn(variantClasses, sizeClasses, clickableClasses, className);
6908
+
6909
+ var hasHeader = title || subtitle || headerActions;
6910
+
6911
+ var headerElement = hasHeader ? React.createElement('div', {
6912
+ className: 'flex items-start justify-between mb-4'
6913
+ }, [
6914
+ React.createElement('div', { key: 'titles' }, [
6915
+ title && React.createElement('h3', {
6916
+ key: 'title',
6917
+ className: 'text-lg font-semibold text-text-primary'
6918
+ }, title),
6919
+ subtitle && React.createElement('p', {
6920
+ key: 'subtitle',
6921
+ className: 'text-sm text-text-secondary mt-1'
6922
+ }, subtitle)
6923
+ ]),
6924
+ headerActions && React.createElement('div', {
6925
+ key: 'actions',
6926
+ className: 'flex items-center gap-2'
6927
+ }, headerActions)
6928
+ ]) : null;
6929
+
6930
+ var footerElement = footer ? React.createElement('div', {
6931
+ className: 'mt-4 pt-4 border-t border-divider'
6932
+ }, footer) : null;
6933
+
6934
+ var content = React.createElement(React.Fragment, null, [
6935
+ headerElement,
6936
+ children,
6937
+ footerElement
6938
+ ]);
6939
+
6940
+ if (href) {
6941
+ return React.createElement('a', {
6942
+ href: href,
6943
+ className: allClasses,
6944
+ id: id
6945
+ }, content);
6946
+ }
6947
+
6948
+ return React.createElement('div', {
6949
+ className: allClasses,
6950
+ id: id
6951
+ }, content);
6952
+ };
6953
+ `;
6954
+ }
6955
+ function buildButtonComponent() {
6956
+ return `
6957
+ // Button Component (matches @frontmcp/ui/react/Button)
6958
+ window.Button = function Button(props) {
6959
+ var variant = props.variant || 'primary';
6960
+ var size = props.size || 'md';
6961
+ var disabled = props.disabled || false;
6962
+ var loading = props.loading || false;
6963
+ var fullWidth = props.fullWidth || false;
6964
+ var iconPosition = props.iconPosition || 'left';
6965
+ var icon = props.icon;
6966
+ var iconOnly = props.iconOnly || false;
6967
+ var type = props.type || 'button';
6968
+ var className = props.className;
6969
+ var onClick = props.onClick;
6970
+ var children = props.children;
6971
+
6972
+ var variantClasses = BUTTON_VARIANTS[variant] || BUTTON_VARIANTS.primary;
6973
+ var sizeClasses = iconOnly
6974
+ ? (BUTTON_ICON_SIZES[size] || BUTTON_ICON_SIZES.md)
6975
+ : (BUTTON_SIZES[size] || BUTTON_SIZES.md);
6976
+
6977
+ var disabledClasses = (disabled || loading) ? 'opacity-50 cursor-not-allowed' : '';
6978
+ var widthClasses = fullWidth ? 'w-full' : '';
6979
+
6980
+ var allClasses = cn(BUTTON_BASE_CLASSES, variantClasses, sizeClasses, disabledClasses, widthClasses, className);
6981
+
6982
+ var iconElement = icon ? React.createElement('span', {
6983
+ className: iconPosition === 'left' ? 'mr-2' : 'ml-2'
6984
+ }, icon) : null;
6985
+
6986
+ var loadingSpinner = loading ? React.createElement('span', {
6987
+ className: 'mr-2',
6988
+ dangerouslySetInnerHTML: { __html: LOADING_SPINNER }
6989
+ }) : null;
6990
+
6991
+ return React.createElement('button', {
6992
+ type: type,
6993
+ className: allClasses,
6994
+ disabled: disabled || loading,
6995
+ onClick: onClick
6996
+ }, [
6997
+ loadingSpinner,
6998
+ !loading && icon && iconPosition === 'left' ? iconElement : null,
6999
+ !iconOnly ? children : null,
7000
+ !loading && icon && iconPosition === 'right' ? iconElement : null
7001
+ ]);
7002
+ };
7003
+ `;
7004
+ }
7005
+ function buildBadgeComponent() {
7006
+ return `
7007
+ // Badge Component (matches @frontmcp/ui/react/Badge)
7008
+ window.Badge = function Badge(props) {
7009
+ var variant = props.variant || 'default';
7010
+ var size = props.size || 'md';
7011
+ var pill = props.pill || false;
7012
+ var icon = props.icon;
7013
+ var dot = props.dot || false;
7014
+ var className = props.className;
7015
+ var removable = props.removable || false;
7016
+ var onRemove = props.onRemove;
7017
+ var children = props.children;
7018
+
7019
+ // Handle dot badge (status indicator)
7020
+ if (dot) {
7021
+ var dotSizeClasses = BADGE_DOT_SIZES[size] || BADGE_DOT_SIZES.md;
7022
+ var dotVariantClasses = BADGE_DOT_VARIANTS[variant] || BADGE_DOT_VARIANTS.default;
7023
+ var dotClasses = cn('inline-block rounded-full', dotSizeClasses, dotVariantClasses, className);
7024
+
7025
+ var label = typeof children === 'string' ? children : undefined;
7026
+
7027
+ return React.createElement('span', {
7028
+ className: dotClasses,
7029
+ 'aria-label': label,
7030
+ title: label
7031
+ });
7032
+ }
7033
+
7034
+ var variantClasses = BADGE_VARIANTS[variant] || BADGE_VARIANTS.default;
7035
+ var sizeClasses = BADGE_SIZES[size] || BADGE_SIZES.md;
7036
+
7037
+ var baseClasses = cn(
7038
+ 'inline-flex items-center font-medium',
7039
+ pill ? 'rounded-full' : 'rounded-md',
7040
+ variantClasses,
7041
+ sizeClasses,
7042
+ className
7043
+ );
7044
+
7045
+ var closeButton = removable ? React.createElement('button', {
7046
+ type: 'button',
7047
+ className: 'ml-1.5 -mr-1 hover:opacity-70 transition-opacity',
7048
+ 'aria-label': 'Remove',
7049
+ onClick: onRemove
7050
+ }, React.createElement('svg', {
7051
+ className: 'w-3 h-3',
7052
+ fill: 'none',
7053
+ stroke: 'currentColor',
7054
+ viewBox: '0 0 24 24'
7055
+ }, React.createElement('path', {
7056
+ strokeLinecap: 'round',
7057
+ strokeLinejoin: 'round',
7058
+ strokeWidth: '2',
7059
+ d: 'M6 18L18 6M6 6l12 12'
7060
+ }))) : null;
7061
+
7062
+ return React.createElement('span', {
7063
+ className: baseClasses
7064
+ }, [
7065
+ icon ? React.createElement('span', { key: 'icon', className: 'mr-1' }, icon) : null,
7066
+ children,
7067
+ closeButton
7068
+ ]);
7069
+ };
7070
+ `;
7071
+ }
7072
+ function buildAlertComponent() {
7073
+ return `
7074
+ // Alert Component (matches @frontmcp/ui/react/Alert)
7075
+ window.Alert = function Alert(props) {
7076
+ var variant = props.variant || 'info';
7077
+ var title = props.title;
7078
+ var icon = props.icon;
7079
+ var showIcon = props.showIcon !== false;
7080
+ var dismissible = props.dismissible || false;
7081
+ var onDismiss = props.onDismiss;
7082
+ var className = props.className;
7083
+ var children = props.children;
7084
+
7085
+ var variantStyles = ALERT_VARIANTS[variant] || ALERT_VARIANTS.info;
7086
+ var allClasses = cn(ALERT_BASE_CLASSES, variantStyles.container, className);
7087
+
7088
+ // Use custom icon or default variant icon
7089
+ var iconContent = icon || (showIcon ? React.createElement('span', {
7090
+ className: cn('flex-shrink-0', variantStyles.icon),
7091
+ dangerouslySetInnerHTML: { __html: ALERT_ICONS[variant] || ALERT_ICONS.info }
7092
+ }) : null);
7093
+
7094
+ var dismissButton = dismissible ? React.createElement('button', {
7095
+ type: 'button',
7096
+ className: 'flex-shrink-0 ml-3 hover:opacity-70 transition-opacity',
7097
+ 'aria-label': 'Dismiss',
7098
+ onClick: onDismiss
7099
+ }, React.createElement('span', {
7100
+ dangerouslySetInnerHTML: { __html: CLOSE_ICON }
7101
+ })) : null;
7102
+
7103
+ return React.createElement('div', {
7104
+ className: allClasses,
7105
+ role: 'alert'
7106
+ }, React.createElement('div', {
7107
+ className: 'flex'
7108
+ }, [
7109
+ iconContent ? React.createElement('div', {
7110
+ key: 'icon',
7111
+ className: 'flex-shrink-0 mr-3'
7112
+ }, iconContent) : null,
7113
+ React.createElement('div', {
7114
+ key: 'content',
7115
+ className: 'flex-1'
7116
+ }, [
7117
+ title ? React.createElement('h4', {
7118
+ key: 'title',
7119
+ className: 'font-semibold mb-1'
7120
+ }, title) : null,
7121
+ React.createElement('div', {
7122
+ key: 'body',
7123
+ className: 'text-sm'
7124
+ }, children)
7125
+ ]),
7126
+ dismissButton
7127
+ ]));
7128
+ };
7129
+ `;
7130
+ }
7131
+ function buildNamespaceExport() {
7132
+ return `
7133
+ // Export to namespace (for require('@frontmcp/ui/react') shim)
7134
+ window.frontmcp_ui_namespaceObject = Object.assign({}, window.React || {}, {
7135
+ // Hooks
7136
+ useToolOutput: window.useToolOutput,
7137
+ useToolInput: window.useToolInput,
7138
+ useMcpBridgeContext: function() { return window.__frontmcp.context; },
7139
+ useMcpBridge: function() { return window.__frontmcp.context; },
7140
+ useCallTool: function() {
7141
+ return function(name, args) {
7142
+ if (window.__frontmcp.context.callTool) {
7143
+ return window.__frontmcp.context.callTool(name, args);
7144
+ }
7145
+ console.warn('[FrontMCP] callTool not available');
7146
+ return Promise.resolve(null);
7147
+ };
7148
+ },
7149
+ useTheme: function() { return window.__frontmcp.theme || 'light'; },
7150
+ useDisplayMode: function() { return window.__frontmcp.displayMode || 'embedded'; },
7151
+ useHostContext: function() { return window.__frontmcp.hostContext || {}; },
7152
+ useCapability: function(cap) { return window.__frontmcp.capabilities?.[cap] || false; },
7153
+ useStructuredContent: function() { return window.__frontmcp.getState().structuredContent; },
7154
+ useToolCalls: function() { return []; },
7155
+ useSendMessage: function() { return function() { return Promise.resolve(); }; },
7156
+ useOpenLink: function() { return function() {}; },
7157
+
7158
+ // Components
7159
+ Card: window.Card,
7160
+ Badge: window.Badge,
7161
+ Button: window.Button,
7162
+ Alert: window.Alert,
7163
+
7164
+ // Re-export React stuff for convenience
7165
+ createElement: React.createElement,
7166
+ Fragment: React.Fragment,
7167
+ useState: React.useState,
7168
+ useEffect: React.useEffect,
7169
+ useCallback: React.useCallback,
7170
+ useMemo: React.useMemo,
7171
+ useRef: React.useRef,
7172
+ useContext: React.useContext
7173
+ });
7174
+ `;
7175
+ }
7176
+ function buildUIComponentsRuntime(options = {}) {
7177
+ const parts = [
7178
+ "// UI Components (Browser-Compatible)",
7179
+ "// Generated from @frontmcp/ui/react components",
7180
+ "(function() {",
7181
+ buildStyleConstants(),
7182
+ buildCardComponent(),
7183
+ buildButtonComponent(),
7184
+ buildBadgeComponent(),
7185
+ buildAlertComponent(),
7186
+ buildNamespaceExport(),
7187
+ "})();"
7188
+ ];
7189
+ let script = parts.join("\n");
7190
+ if (options.minify) {
7191
+ script = minifyScript(script);
7192
+ }
7193
+ return script;
7194
+ }
7195
+ function minifyScript(script) {
7196
+ return script.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/[^\n]*$/gm, "").replace(/\n\s*\n/g, "\n").replace(/^\s+/gm, "").trim();
7197
+ }
7198
+
7199
+ // libs/uipack/src/build/builders/base-builder.ts
7200
+ var import_esbuild = require("esbuild");
7201
+
7202
+ // libs/uipack/src/build/builders/esbuild-config.ts
7203
+ var DEFAULT_EXTERNALS = [
7204
+ "react",
7205
+ "react-dom",
7206
+ "react/jsx-runtime",
7207
+ "react/jsx-dev-runtime",
7208
+ "@frontmcp/ui",
7209
+ "@frontmcp/ui/*"
7210
+ ];
7211
+ var EXTERNAL_GLOBALS = {
7212
+ "react": "React",
7213
+ "react-dom": "ReactDOM",
7214
+ "react/jsx-runtime": "jsxRuntime",
7215
+ "react/jsx-dev-runtime": "jsxRuntime",
7216
+ "@frontmcp/ui": "FrontMcpUI"
7217
+ };
7218
+ function createTransformConfig(options = {}) {
7219
+ const {
7220
+ format = "esm",
7221
+ target = "es2020",
7222
+ minify = false,
7223
+ jsxImportSource = "react"
7224
+ } = options;
7225
+ return {
7226
+ loader: "tsx",
7227
+ format,
7228
+ target,
7229
+ minify,
7230
+ treeShaking: true,
7231
+ jsx: "automatic",
7232
+ jsxImportSource,
7233
+ sourcemap: options.minify ? false : "inline"
7234
+ };
7235
+ }
7236
+ function createExternalizedConfig(options = {}) {
7237
+ const baseConfig = createTransformConfig({
7238
+ ...options,
7239
+ format: "esm"
7240
+ });
7241
+ return {
7242
+ ...baseConfig,
7243
+ // Add banner to define external namespace objects
7244
+ banner: createExternalsBanner(options.externals || DEFAULT_EXTERNALS)
7245
+ };
7246
+ }
7247
+ function createExternalsBanner(externals) {
7248
+ const lines = [
7249
+ "// Externalized dependencies - loaded from shell globals"
7250
+ ];
7251
+ for (const pkg of externals) {
7252
+ const globalName = EXTERNAL_GLOBALS[pkg];
7253
+ if (globalName) {
7254
+ const safeName = pkg.replace(/[^a-zA-Z0-9]/g, "_");
7255
+ lines.push(`const __external_${safeName} = window.${globalName};`);
7256
+ }
7257
+ }
7258
+ return lines.join("\n");
7259
+ }
7260
+ function createInlineConfig(options = {}) {
7261
+ return createTransformConfig({
7262
+ ...options,
7263
+ format: "iife",
7264
+ minify: options.minify ?? true
7265
+ });
7266
+ }
7267
+ var CDN_URLS = {
7268
+ react: "https://esm.sh/react@19",
7269
+ reactDom: "https://esm.sh/react-dom@19",
7270
+ reactJsxRuntime: "https://esm.sh/react@19/jsx-runtime",
7271
+ frontmcpUI: "https://esm.sh/@frontmcp/ui",
7272
+ tailwind: "https://cdn.tailwindcss.com"
7273
+ };
7274
+ var CLOUDFLARE_CDN_URLS = {
7275
+ react: "https://cdnjs.cloudflare.com/ajax/libs/react/19.0.0/umd/react.production.min.js",
7276
+ reactDom: "https://cdnjs.cloudflare.com/ajax/libs/react-dom/19.0.0/umd/react-dom.production.min.js",
7277
+ tailwind: "https://cdn.tailwindcss.com"
7278
+ };
7279
+ function generateCdnScriptTags(useCloudflare = false) {
7280
+ const urls = useCloudflare ? CLOUDFLARE_CDN_URLS : CDN_URLS;
7281
+ if (useCloudflare) {
7282
+ return `
7283
+ <script src="${urls.react}"></script>
7284
+ <script src="${urls.reactDom}"></script>
7285
+ <script src="${urls.tailwind}"></script>
7286
+ `;
7287
+ }
7288
+ return `
7289
+ <script type="importmap">
7290
+ {
7291
+ "imports": {
7292
+ "react": "${CDN_URLS.react}",
7293
+ "react-dom": "${CDN_URLS.reactDom}",
7294
+ "react/jsx-runtime": "${CDN_URLS.reactJsxRuntime}",
7295
+ "@frontmcp/ui": "${CDN_URLS.frontmcpUI}"
7296
+ }
7297
+ }
7298
+ </script>
7299
+ <script src="${CDN_URLS.tailwind}"></script>
7300
+ `;
7301
+ }
7302
+ function generateGlobalsSetupScript() {
7303
+ return `
7304
+ <script type="module">
7305
+ import React from 'react';
7306
+ import ReactDOM from 'react-dom/client';
7307
+ import * as jsxRuntime from 'react/jsx-runtime';
7308
+
7309
+ // Expose as globals for externalized components
7310
+ window.React = React;
7311
+ window.ReactDOM = ReactDOM;
7312
+ window.jsxRuntime = jsxRuntime;
7313
+
7314
+ // Signal that runtime is ready
7315
+ window.__frontmcpRuntimeReady = true;
7316
+ window.dispatchEvent(new CustomEvent('frontmcp:runtime-ready'));
7317
+ </script>
7318
+ `;
7319
+ }
7320
+
7321
+ // libs/uipack/src/build/builders/base-builder.ts
7322
+ init_utils();
7323
+ var BaseBuilder = class {
7324
+ /**
7325
+ * CDN loading mode.
7326
+ */
7327
+ cdnMode;
7328
+ /**
7329
+ * Whether to minify output.
7330
+ */
7331
+ minify;
7332
+ /**
7333
+ * Theme configuration.
7334
+ */
7335
+ theme;
7336
+ /**
7337
+ * Whether to include source maps.
7338
+ */
7339
+ sourceMaps;
7340
+ constructor(options = {}) {
7341
+ this.cdnMode = options.cdnMode ?? "cdn";
7342
+ this.minify = options.minify ?? false;
7343
+ this.theme = options.theme ? mergeThemes(DEFAULT_THEME, options.theme) : DEFAULT_THEME;
7344
+ this.sourceMaps = options.sourceMaps ?? false;
7345
+ }
7346
+ // ============================================
7347
+ // Template Detection
7348
+ // ============================================
7349
+ /**
7350
+ * Detect the type of a template.
7351
+ *
7352
+ * @param template - Template to detect
7353
+ * @returns Detection result with type and renderer info
7354
+ */
7355
+ detectTemplate(template) {
7356
+ if (typeof template === "string") {
7357
+ return {
7358
+ type: "html-string",
7359
+ renderer: "html",
7360
+ needsTranspilation: false
7361
+ };
7362
+ }
7363
+ if (typeof template === "function") {
7364
+ const funcStr = template.toString();
7365
+ if (funcStr.includes("jsx") || funcStr.includes("createElement") || funcStr.includes("React") || template.$$typeof) {
7366
+ return {
7367
+ type: "react-component",
7368
+ renderer: "react",
7369
+ needsTranspilation: true
7370
+ };
7371
+ }
7372
+ return {
7373
+ type: "html-function",
7374
+ renderer: "html",
7375
+ needsTranspilation: false
7376
+ };
7377
+ }
7378
+ if (template && typeof template === "object" && template.$$typeof) {
7379
+ return {
7380
+ type: "react-element",
7381
+ renderer: "react",
7382
+ needsTranspilation: true
7383
+ };
7384
+ }
7385
+ return {
7386
+ type: "html-string",
7387
+ renderer: "html",
7388
+ needsTranspilation: false
7389
+ };
7390
+ }
7391
+ // ============================================
7392
+ // Transpilation
7393
+ // ============================================
7394
+ /**
7395
+ * Transpile a component using esbuild.
7396
+ *
7397
+ * @param source - Source code to transpile
7398
+ * @param options - Transpile options
7399
+ * @returns Transpile result
7400
+ */
7401
+ async transpile(source, options = {}) {
7402
+ const externals = options.externals || DEFAULT_EXTERNALS;
7403
+ const config = options.externals ? createExternalizedConfig(options) : createTransformConfig(options);
7404
+ const result = await (0, import_esbuild.transform)(source, config);
7405
+ return {
7406
+ code: result.code,
7407
+ map: result.map,
7408
+ size: Buffer.byteLength(result.code, "utf8"),
7409
+ externalizedImports: externals
7410
+ };
7411
+ }
7412
+ /**
7413
+ * Render an HTML template.
7414
+ *
7415
+ * @param template - HTML template (string or function)
7416
+ * @param context - Template context with input/output
7417
+ * @returns Rendered HTML string
7418
+ */
7419
+ renderHtmlTemplate(template, context) {
7420
+ if (typeof template === "string") {
7421
+ return template;
7422
+ }
7423
+ return template(context);
7424
+ }
7425
+ // ============================================
7426
+ // HTML Generation
7427
+ // ============================================
7428
+ /**
7429
+ * Build the <head> section of the HTML document.
7430
+ *
7431
+ * @param options - Head options
7432
+ * @returns HTML head content
7433
+ */
7434
+ buildHead(options) {
7435
+ const {
7436
+ title,
7437
+ includeBridge = true,
7438
+ includeCdn = this.cdnMode === "cdn",
7439
+ includeTheme = true,
7440
+ customStyles = ""
7441
+ } = options;
7442
+ const parts = [
7443
+ "<head>",
7444
+ '<meta charset="UTF-8">',
7445
+ '<meta name="viewport" content="width=device-width, initial-scale=1.0">',
7446
+ `<title>${escapeHtml(title)}</title>`
7447
+ ];
7448
+ parts.push(buildFontPreconnect());
7449
+ parts.push(buildFontStylesheets({ inter: true }));
7450
+ if (includeTheme) {
7451
+ const themeCss = buildThemeCss(this.theme);
7452
+ const customCss = this.theme.customCss || "";
7453
+ parts.push(`
7454
+ <style type="text/tailwindcss">
7455
+ @theme {
7456
+ ${themeCss}
7457
+ }
7458
+ ${customCss}
7459
+ </style>
7460
+ `);
7461
+ }
7462
+ if (customStyles) {
7463
+ parts.push(`<style>${customStyles}</style>`);
7464
+ }
7465
+ if (includeCdn) {
7466
+ parts.push('<script src="https://cdn.tailwindcss.com"></script>');
7467
+ }
7468
+ if (includeBridge) {
7469
+ parts.push(BRIDGE_SCRIPT_TAGS.universal);
7470
+ }
7471
+ parts.push("</head>");
7472
+ return parts.join("\n");
7473
+ }
7474
+ /**
7475
+ * Build data injection script.
7476
+ *
7477
+ * @param options - Injection options
7478
+ * @returns Script tag with data injection
7479
+ */
7480
+ buildDataInjectionScript(options) {
7481
+ const { toolName, input, output, usePlaceholders = false } = options;
7482
+ if (usePlaceholders) {
7483
+ return `
7484
+ <script>
7485
+ window.__mcpToolName = ${JSON.stringify(toolName)};
7486
+ window.__mcpToolInput = JSON.parse("${HYBRID_INPUT_PLACEHOLDER}");
7487
+ window.__mcpToolOutput = JSON.parse("${HYBRID_DATA_PLACEHOLDER}");
7488
+ window.__mcpStructuredContent = window.__mcpToolOutput;
7489
+ </script>
7490
+ `;
7491
+ }
7492
+ return `
7493
+ <script>
7494
+ window.__mcpToolName = ${JSON.stringify(toolName)};
7495
+ window.__mcpToolInput = ${JSON.stringify(input ?? {})};
7496
+ window.__mcpToolOutput = ${JSON.stringify(output ?? {})};
7497
+ window.__mcpStructuredContent = window.__mcpToolOutput;
7498
+ </script>
7499
+ `;
7500
+ }
7501
+ /**
7502
+ * Wrap content in a complete HTML document.
7503
+ *
7504
+ * @param options - Wrap options
7505
+ * @returns Complete HTML document
7506
+ */
7507
+ wrapInHtmlDocument(options) {
7508
+ const { head, body, bodyClass = "" } = options;
7509
+ return `<!DOCTYPE html>
7510
+ <html lang="en">
7511
+ ${head}
7512
+ <body${bodyClass ? ` class="${bodyClass}"` : ""}>
7513
+ ${body}
7514
+ </body>
7515
+ </html>`;
7516
+ }
7517
+ // ============================================
7518
+ // Utility Methods
7519
+ // ============================================
7520
+ /**
7521
+ * Calculate content hash.
7522
+ *
7523
+ * @param content - Content to hash
7524
+ * @returns Hash string
7525
+ */
7526
+ async calculateHash(content) {
7527
+ if (typeof crypto !== "undefined" && crypto.subtle) {
7528
+ const encoder = new TextEncoder();
7529
+ const data = encoder.encode(content);
7530
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
7531
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
7532
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 16);
7533
+ }
7534
+ let hash = 0;
7535
+ for (let i = 0; i < content.length; i++) {
7536
+ const char = content.charCodeAt(i);
7537
+ hash = (hash << 5) - hash + char;
7538
+ hash = hash & hash;
7539
+ }
7540
+ return Math.abs(hash).toString(16).padStart(8, "0");
7541
+ }
7542
+ /**
7543
+ * Estimate gzipped size.
7544
+ *
7545
+ * @param content - Content to estimate
7546
+ * @returns Estimated gzipped size in bytes
7547
+ */
7548
+ estimateGzipSize(content) {
7549
+ return Math.round(Buffer.byteLength(content, "utf8") * 0.25);
7550
+ }
7551
+ /**
7552
+ * Create template context.
7553
+ *
7554
+ * @param input - Tool input
7555
+ * @param output - Tool output
7556
+ * @returns Template context
7557
+ */
7558
+ createContext(input, output) {
7559
+ return {
7560
+ input,
7561
+ output,
7562
+ helpers: {
7563
+ escapeHtml,
7564
+ formatDate: (date, format) => {
7565
+ const d = typeof date === "string" ? new Date(date) : date;
7566
+ if (isNaN(d.getTime())) return String(date);
7567
+ if (format === "iso") return d.toISOString();
7568
+ if (format === "time") return d.toLocaleTimeString();
7569
+ if (format === "datetime") return d.toLocaleString();
7570
+ return d.toLocaleDateString();
7571
+ },
7572
+ formatCurrency: (amount, currency = "USD") => {
7573
+ return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(amount);
7574
+ },
7575
+ uniqueId: (prefix = "mcp") => {
7576
+ return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
7577
+ },
7578
+ jsonEmbed: (data) => {
7579
+ const json2 = JSON.stringify(data);
7580
+ if (json2 === void 0) return "undefined";
7581
+ return json2.replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/'/g, "\\u0027");
7582
+ }
7583
+ }
7584
+ };
7585
+ }
7586
+ };
7587
+
7588
+ // libs/uipack/src/build/builders/static-builder.ts
7589
+ var StaticBuilder = class extends BaseBuilder {
7590
+ mode = "static";
7591
+ constructor(options = {}) {
7592
+ super(options);
7593
+ }
7594
+ /**
7595
+ * Build a static HTML shell with placeholders.
7596
+ *
7597
+ * @param options - Build options
7598
+ * @returns Static build result
7599
+ */
7600
+ async build(options) {
7601
+ const startTime = Date.now();
7602
+ const { template, toolName, title = `${toolName} Widget` } = options;
7603
+ const detection = this.detectTemplate(template.template);
7604
+ let bodyContent;
7605
+ if (detection.renderer === "html") {
7606
+ const context = this.createContext(
7607
+ options.sampleInput ?? {},
7608
+ options.sampleOutput ?? {}
7609
+ );
7610
+ if (typeof template.template === "function") {
7611
+ bodyContent = template.template(context);
7612
+ } else {
7613
+ bodyContent = template.template;
7614
+ }
7615
+ bodyContent = `
7616
+ <div id="frontmcp-widget-root">
7617
+ ${bodyContent}
7618
+ </div>
7619
+ `;
7620
+ } else {
7621
+ bodyContent = this.buildReactShell(template, toolName);
7622
+ }
7623
+ const head = this.buildHead({
7624
+ title,
7625
+ includeBridge: true,
7626
+ includeCdn: this.cdnMode === "cdn",
7627
+ includeTheme: true
7628
+ });
7629
+ const dataScript = this.buildDataInjectionScript({
7630
+ toolName,
7631
+ usePlaceholders: true
7632
+ });
7633
+ let additionalScripts = "";
7634
+ if (detection.renderer === "react") {
7635
+ additionalScripts = this.cdnMode === "cdn" ? generateCdnScriptTags(false) + generateGlobalsSetupScript() : this.buildInlineReactRuntime();
7636
+ }
7637
+ const body = `
7638
+ ${dataScript}
7639
+ ${additionalScripts}
7640
+ ${bodyContent}
7641
+ `;
7642
+ const html = this.wrapInHtmlDocument({
7643
+ head,
7644
+ body,
7645
+ bodyClass: "antialiased"
7646
+ });
7647
+ const finalHtml = this.minify ? this.minifyHtml(html) : html;
7648
+ const hash = await this.calculateHash(finalHtml);
7649
+ const size = Buffer.byteLength(finalHtml, "utf8");
7650
+ const gzipSize = this.estimateGzipSize(finalHtml);
7651
+ return {
7652
+ mode: "static",
7653
+ html: finalHtml,
7654
+ hash,
7655
+ size,
7656
+ gzipSize,
7657
+ placeholders: {
7658
+ hasOutput: finalHtml.includes(HYBRID_DATA_PLACEHOLDER),
7659
+ hasInput: finalHtml.includes(HYBRID_INPUT_PLACEHOLDER)
7660
+ },
7661
+ rendererType: detection.renderer,
7662
+ buildTime: new Date(startTime).toISOString()
7663
+ };
7664
+ }
7665
+ /**
7666
+ * Inject data into a pre-built shell.
7667
+ *
7668
+ * @param shell - HTML shell with placeholders
7669
+ * @param input - Tool input data
7670
+ * @param output - Tool output data
7671
+ * @returns HTML with data injected
7672
+ */
7673
+ injectData(shell, input, output) {
7674
+ return injectHybridDataFull(shell, input, output);
7675
+ }
7676
+ // ============================================
7677
+ // Private Methods
7678
+ // ============================================
7679
+ /**
7680
+ * Build React rendering shell.
7681
+ *
7682
+ * Creates a client-side React rendering setup that:
7683
+ * 1. Waits for runtime to be ready
7684
+ * 2. Loads component code
7685
+ * 3. Renders into #root with data from window.__mcpToolOutput
7686
+ */
7687
+ buildReactShell(template, _toolName) {
7688
+ const _componentName = this.getComponentName(template.template);
7689
+ return `
7690
+ <div id="frontmcp-widget-root">
7691
+ <div id="root" class="min-h-[200px]">
7692
+ <div class="flex items-center justify-center p-4">
7693
+ <div class="text-center text-gray-500">
7694
+ <svg class="animate-spin mx-auto mb-2" style="width: 1.5rem; height: 1.5rem; color: #9ca3af;" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
7695
+ <circle style="opacity: 0.25;" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
7696
+ <path style="opacity: 0.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>
7697
+ </svg>
7698
+ <p class="text-sm">Loading...</p>
7699
+ </div>
7700
+ </div>
7701
+ </div>
7702
+ </div>
7703
+
7704
+ <script type="module">
7705
+ // Wait for React runtime to be ready
7706
+ function waitForRuntime() {
7707
+ return new Promise((resolve) => {
7708
+ if (window.__frontmcpRuntimeReady) {
7709
+ resolve();
7710
+ } else {
7711
+ window.addEventListener('frontmcp:runtime-ready', resolve, { once: true });
7712
+ }
7713
+ });
7714
+ }
7715
+
7716
+ async function renderWidget() {
7717
+ await waitForRuntime();
7718
+
7719
+ const React = window.React;
7720
+ const ReactDOM = window.ReactDOM;
7721
+
7722
+ // Get data from injected globals
7723
+ const input = window.__mcpToolInput || {};
7724
+ const output = window.__mcpToolOutput || {};
7725
+
7726
+ // Create simple widget component
7727
+ function Widget() {
7728
+ const [data, setData] = React.useState({ input, output });
7729
+
7730
+ React.useEffect(() => {
7731
+ // Subscribe to data updates via bridge
7732
+ const handleUpdate = (event) => {
7733
+ if (event.detail) {
7734
+ setData((prev) => ({ ...prev, output: event.detail }));
7735
+ }
7736
+ };
7737
+ window.addEventListener('frontmcp:toolResult', handleUpdate);
7738
+ return () => window.removeEventListener('frontmcp:toolResult', handleUpdate);
7739
+ }, []);
7740
+
7741
+ return React.createElement('div', {
7742
+ className: 'p-4',
7743
+ dangerouslySetInnerHTML: {
7744
+ __html: '<pre>' + JSON.stringify(data.output, null, 2) + '</pre>'
7745
+ }
7746
+ });
7747
+ }
7748
+
7749
+ // Render
7750
+ const root = ReactDOM.createRoot(document.getElementById('root'));
7751
+ root.render(React.createElement(Widget));
7752
+ }
7753
+
7754
+ renderWidget().catch(console.error);
7755
+ </script>
7756
+ `;
7757
+ }
7758
+ /**
7759
+ * Build inline React runtime (for offline mode).
7760
+ */
7761
+ buildInlineReactRuntime() {
7762
+ return `
7763
+ <script>
7764
+ // Inline React runtime would be bundled here
7765
+ console.warn('[FrontMCP] Inline React runtime not yet implemented');
7766
+ </script>
7767
+ `;
7768
+ }
7769
+ /**
7770
+ * Get component name from template.
7771
+ */
7772
+ getComponentName(template) {
7773
+ if (typeof template === "function") {
7774
+ return template.name || "Widget";
7775
+ }
7776
+ return "Widget";
7777
+ }
7778
+ /**
7779
+ * Simple HTML minification.
7780
+ */
7781
+ minifyHtml(html) {
7782
+ return html.replace(/>\s+</g, "><").replace(/\s{2,}/g, " ").trim();
7783
+ }
7784
+ };
7785
+
7786
+ // libs/uipack/src/build/builders/hybrid-builder.ts
7787
+ var HybridBuilder = class extends BaseBuilder {
7788
+ mode = "hybrid";
7789
+ /**
7790
+ * Cached vendor shell.
7791
+ */
7792
+ vendorShellCache = null;
7793
+ constructor(options = {}) {
7794
+ super(options);
7795
+ }
7796
+ /**
7797
+ * Build a hybrid result with vendor shell and component chunk.
7798
+ *
7799
+ * @param options - Build options
7800
+ * @returns Hybrid build result
7801
+ */
7802
+ async build(options) {
7803
+ const startTime = Date.now();
7804
+ const { template, toolName } = options;
7805
+ const vendorShell = await this.buildVendorShell();
7806
+ const componentChunk = await this.buildComponentChunk(template.template);
7807
+ const shellResourceUri = `resource://widget/${toolName}/shell`;
7808
+ const combinedHash = await this.calculateHash(vendorShell + componentChunk);
7809
+ const shellSize = Buffer.byteLength(vendorShell, "utf8");
7810
+ const componentSize = Buffer.byteLength(componentChunk, "utf8");
7811
+ const detection = this.detectTemplate(template.template);
7812
+ return {
7813
+ mode: "hybrid",
7814
+ vendorShell,
7815
+ componentChunk,
7816
+ shellResourceUri,
7817
+ hash: combinedHash,
7818
+ shellSize,
7819
+ componentSize,
7820
+ rendererType: detection.renderer,
7821
+ buildTime: new Date(startTime).toISOString()
7822
+ };
7823
+ }
7824
+ /**
7825
+ * Build the vendor shell (shared across all tools).
7826
+ *
7827
+ * The vendor shell contains:
7828
+ * - React/ReactDOM from CDN
7829
+ * - FrontMCP Bridge runtime
7830
+ * - Theme CSS and fonts
7831
+ * - Component injection point
7832
+ *
7833
+ * @returns Vendor shell HTML
7834
+ */
7835
+ async buildVendorShell() {
7836
+ if (this.vendorShellCache) {
7837
+ return this.vendorShellCache;
7838
+ }
7839
+ const head = this.buildHead({
7840
+ title: "FrontMCP Widget",
7841
+ includeBridge: true,
7842
+ includeCdn: this.cdnMode === "cdn",
7843
+ includeTheme: true
7844
+ });
7845
+ const cdnScripts = this.cdnMode === "cdn" ? generateCdnScriptTags(false) + generateGlobalsSetupScript() : "";
7846
+ const body = `
7847
+ <script>
7848
+ window.__mcpToolName = '';
7849
+ window.__mcpToolInput = {};
7850
+ window.__mcpToolOutput = {};
7851
+ window.__mcpStructuredContent = {};
7852
+ </script>
7853
+ ${cdnScripts}
7854
+ <div id="frontmcp-widget-root">
7855
+ <div id="root" class="min-h-[200px]">
7856
+ <!-- Component will be injected here -->
7857
+ <div class="flex items-center justify-center p-4">
7858
+ <div class="text-center text-gray-500">
7859
+ <svg class="animate-spin mx-auto mb-2" style="width: 1.5rem; height: 1.5rem; color: #9ca3af;" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
7860
+ <circle style="opacity: 0.25;" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
7861
+ <path style="opacity: 0.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>
7862
+ </svg>
7863
+ <p class="text-sm">Loading component...</p>
7864
+ </div>
7865
+ </div>
7866
+ </div>
7867
+ </div>
7868
+
7869
+ <!-- Component injection script -->
7870
+ <script type="module">
7871
+ // Wait for component code to be injected
7872
+ window.__frontmcpInjectComponent = async function(componentCode) {
7873
+ try {
7874
+ // Wait for runtime
7875
+ if (!window.__frontmcpRuntimeReady) {
7876
+ await new Promise((resolve) => {
7877
+ window.addEventListener('frontmcp:runtime-ready', resolve, { once: true });
7878
+ });
7879
+ }
7880
+
7881
+ // Execute component code
7882
+ const blob = new Blob([componentCode], { type: 'application/javascript' });
7883
+ const url = URL.createObjectURL(blob);
7884
+ const module = await import(url);
7885
+ URL.revokeObjectURL(url);
7886
+
7887
+ // Render component
7888
+ const React = window.React;
7889
+ const ReactDOM = window.ReactDOM;
7890
+ const Component = module.default || module.Widget || module.Component;
7891
+
7892
+ if (Component) {
7893
+ const root = ReactDOM.createRoot(document.getElementById('root'));
7894
+ root.render(React.createElement(Component, {
7895
+ input: window.__mcpToolInput,
7896
+ output: window.__mcpToolOutput,
7897
+ }));
7898
+ }
7899
+ } catch (error) {
7900
+ console.error('[FrontMCP] Component injection failed:', error);
7901
+ document.getElementById('root').innerHTML =
7902
+ '<div class="p-4 text-red-500">Component failed to load</div>';
7903
+ }
7904
+ };
7905
+
7906
+ // Listen for component via bridge
7907
+ if (window.FrontMcpBridge) {
7908
+ const checkForComponent = () => {
7909
+ const meta = window.FrontMcpBridge.getToolResponseMetadata?.() || {};
7910
+ const componentCode = meta['ui/component'] || meta['openai/component'];
7911
+ if (componentCode) {
7912
+ window.__frontmcpInjectComponent(componentCode);
7913
+ }
7914
+ };
7915
+
7916
+ if (window.FrontMcpBridge.onToolResponseMetadata) {
7917
+ window.FrontMcpBridge.onToolResponseMetadata((meta) => {
7918
+ const componentCode = meta['ui/component'] || meta['openai/component'];
7919
+ if (componentCode) {
7920
+ window.__frontmcpInjectComponent(componentCode);
7921
+ }
7922
+ });
7923
+ }
7924
+
7925
+ // Check immediately in case data is already available
7926
+ checkForComponent();
7927
+ }
7928
+ </script>
7929
+ `;
7930
+ const html = this.wrapInHtmlDocument({
7931
+ head,
7932
+ body,
7933
+ bodyClass: "antialiased"
7934
+ });
7935
+ this.vendorShellCache = html;
7936
+ return html;
7937
+ }
7938
+ /**
7939
+ * Build a component chunk for a specific template.
7940
+ *
7941
+ * The component chunk is transpiled with externalized dependencies
7942
+ * (React, etc.) that are provided by the vendor shell.
7943
+ *
7944
+ * @param template - Component template
7945
+ * @returns Transpiled component code
7946
+ */
7947
+ async buildComponentChunk(template) {
7948
+ const detection = this.detectTemplate(template);
7949
+ if (detection.renderer === "html") {
7950
+ return this.wrapHtmlAsComponent(template);
7951
+ }
7952
+ if (typeof template === "function") {
7953
+ return this.transpileReactComponent(template);
7954
+ }
7955
+ return `
7956
+ // Externalized React component
7957
+ const React = window.React;
7958
+
7959
+ export default function Widget({ input, output }) {
7960
+ return React.createElement('div', {
7961
+ className: 'p-4',
7962
+ }, React.createElement('pre', null, JSON.stringify(output, null, 2)));
7963
+ }
7964
+ `;
7965
+ }
7966
+ /**
7967
+ * Combine shell and component for Claude/inline delivery.
7968
+ *
7969
+ * @param shell - Vendor shell HTML
7970
+ * @param component - Component chunk code
7971
+ * @param input - Tool input data
7972
+ * @param output - Tool output data
7973
+ * @returns Complete HTML with embedded component and data
7974
+ */
7975
+ combineForInline(shell, component, input, output) {
7976
+ let result = shell.replace("window.__mcpToolInput = {};", `window.__mcpToolInput = ${JSON.stringify(input)};`).replace("window.__mcpToolOutput = {};", `window.__mcpToolOutput = ${JSON.stringify(output)};`).replace("window.__mcpStructuredContent = {};", `window.__mcpStructuredContent = ${JSON.stringify(output)};`);
7977
+ const componentInjection = `
7978
+ <script type="module">
7979
+ (async function() {
7980
+ // Wait for runtime
7981
+ if (!window.__frontmcpRuntimeReady) {
7982
+ await new Promise((resolve) => {
7983
+ window.addEventListener('frontmcp:runtime-ready', resolve, { once: true });
7984
+ });
7985
+ }
7986
+
7987
+ // Execute component
7988
+ ${component}
7989
+
7990
+ // Render
7991
+ const React = window.React;
7992
+ const ReactDOM = window.ReactDOM;
7993
+ const Component = typeof Widget !== 'undefined' ? Widget : (typeof exports !== 'undefined' ? exports.default : null);
7994
+
7995
+ if (Component) {
7996
+ const root = ReactDOM.createRoot(document.getElementById('root'));
7997
+ root.render(React.createElement(Component, {
7998
+ input: window.__mcpToolInput,
7999
+ output: window.__mcpToolOutput,
8000
+ }));
8001
+ }
8002
+ })();
8003
+ </script>
8004
+ `;
8005
+ result = result.replace("</body>", componentInjection + "\n</body>");
8006
+ return result;
8007
+ }
8008
+ // ============================================
8009
+ // Private Methods
8010
+ // ============================================
8011
+ /**
8012
+ * Wrap HTML template as a React component.
8013
+ */
8014
+ wrapHtmlAsComponent(template) {
8015
+ if (typeof template === "string") {
8016
+ return `
8017
+ // HTML template wrapped as component
8018
+ const React = window.React;
8019
+
8020
+ export default function Widget({ input, output }) {
8021
+ return React.createElement('div', {
8022
+ dangerouslySetInnerHTML: { __html: ${JSON.stringify(template)} }
8023
+ });
8024
+ }
8025
+ `;
8026
+ }
8027
+ return `
8028
+ // HTML function template wrapped as component
8029
+ const React = window.React;
8030
+
8031
+ export default function Widget({ input, output }) {
8032
+ const html = (${template.toString()})({ input, output, helpers: {} });
8033
+ return React.createElement('div', {
8034
+ dangerouslySetInnerHTML: { __html: html }
8035
+ });
8036
+ }
8037
+ `;
8038
+ }
8039
+ /**
8040
+ * Transpile a React component function.
8041
+ */
8042
+ async transpileReactComponent(component) {
8043
+ const funcString = component.toString();
8044
+ const componentName = component.name || "Widget";
8045
+ const source = `
8046
+ // Externalized React component
8047
+ const React = window.React;
8048
+
8049
+ const ${componentName} = ${funcString};
8050
+
8051
+ export default ${componentName};
8052
+ export { ${componentName} as Widget, ${componentName} as Component };
8053
+ `;
8054
+ try {
8055
+ const result = await this.transpile(source, {
8056
+ externals: DEFAULT_EXTERNALS,
8057
+ format: "esm",
8058
+ minify: this.minify
8059
+ });
8060
+ return result.code;
8061
+ } catch (error) {
8062
+ console.warn("[HybridBuilder] Transpilation failed, using source directly:", error);
8063
+ return source;
8064
+ }
8065
+ }
8066
+ };
8067
+
8068
+ // libs/uipack/src/build/builders/inline-builder.ts
8069
+ var InlineBuilder = class extends BaseBuilder {
8070
+ mode = "inline";
8071
+ constructor(options = {}) {
8072
+ super(options);
8073
+ }
8074
+ /**
8075
+ * Build an inline result with loader and full widget generator.
8076
+ *
8077
+ * @param options - Build options
8078
+ * @returns Inline build result
8079
+ */
8080
+ async build(options) {
8081
+ const startTime = Date.now();
8082
+ const { template, toolName } = options;
8083
+ const loaderShell = this.buildLoader(toolName);
8084
+ const buildFullWidget = async (input, output) => {
8085
+ return this.buildFullWidget(template.template, input, output);
8086
+ };
8087
+ const hash = await this.calculateHash(loaderShell);
8088
+ const loaderSize = Buffer.byteLength(loaderShell, "utf8");
8089
+ const detection = this.detectTemplate(template.template);
8090
+ return {
8091
+ mode: "inline",
8092
+ loaderShell,
8093
+ buildFullWidget,
8094
+ hash,
8095
+ loaderSize,
8096
+ rendererType: detection.renderer,
8097
+ buildTime: new Date(startTime).toISOString()
8098
+ };
8099
+ }
8100
+ /**
8101
+ * Build the minimal loader shell.
8102
+ *
8103
+ * The loader contains:
8104
+ * - FrontMCP Bridge runtime
8105
+ * - Loading indicator
8106
+ * - Injector script that replaces document on tool response
8107
+ *
8108
+ * @param toolName - Name of the tool
8109
+ * @returns Loader HTML
8110
+ */
8111
+ buildLoader(toolName) {
8112
+ const head = this.buildHead({
8113
+ title: `${toolName} Widget`,
8114
+ includeBridge: true,
8115
+ includeCdn: this.cdnMode === "cdn",
8116
+ includeTheme: true
8117
+ });
8118
+ const body = `
8119
+ <script>
8120
+ window.__mcpToolName = ${JSON.stringify(toolName)};
8121
+ window.__mcpLeanShell = true;
8122
+ </script>
8123
+
8124
+ <div id="frontmcp-widget-root" class="flex items-center justify-center min-h-[200px] p-4">
8125
+ <div class="text-center text-gray-500">
8126
+ <svg class="animate-spin mx-auto mb-2" style="width: 1.5rem; height: 1.5rem; color: #9ca3af;" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
8127
+ <circle style="opacity: 0.25;" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
8128
+ <path style="opacity: 0.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>
8129
+ </svg>
8130
+ <p class="text-sm">Loading widget...</p>
8131
+ </div>
8132
+ </div>
8133
+
8134
+ <!-- Injector script -->
8135
+ <script>
8136
+ (function() {
8137
+ var injected = false;
8138
+
8139
+ function injectWidget(metadata) {
8140
+ if (injected) return;
8141
+
8142
+ var html = null;
8143
+ if (metadata) {
8144
+ html = metadata['ui/html'] || metadata['openai/html'] || metadata.html;
8145
+ }
8146
+
8147
+ if (html && typeof html === 'string') {
8148
+ injected = true;
8149
+ console.log('[FrontMCP] Inline shell: Injecting widget HTML (' + html.length + ' chars)');
8150
+ document.open();
8151
+ document.write(html);
8152
+ document.close();
8153
+ return true;
8154
+ }
8155
+ return false;
8156
+ }
8157
+
8158
+ function subscribeAndInject() {
8159
+ var bridge = window.FrontMcpBridge;
8160
+ if (!bridge) {
8161
+ console.warn('[FrontMCP] Inline shell: Bridge not found');
8162
+ return;
8163
+ }
8164
+
8165
+ // Check if data already available
8166
+ if (typeof bridge.getToolResponseMetadata === 'function') {
8167
+ var existing = bridge.getToolResponseMetadata();
8168
+ if (existing && injectWidget(existing)) {
8169
+ return;
8170
+ }
8171
+ }
8172
+
8173
+ // Subscribe to metadata changes
8174
+ if (typeof bridge.onToolResponseMetadata === 'function') {
8175
+ console.log('[FrontMCP] Inline shell: Subscribing to tool response metadata');
8176
+ bridge.onToolResponseMetadata(function(metadata) {
8177
+ console.log('[FrontMCP] Inline shell: Received tool response metadata');
8178
+ injectWidget(metadata);
8179
+ });
8180
+ }
8181
+ }
8182
+
8183
+ // Wait for bridge:ready event
8184
+ window.addEventListener('bridge:ready', function() {
8185
+ console.log('[FrontMCP] Inline shell: Bridge ready, setting up injector');
8186
+ subscribeAndInject();
8187
+ });
8188
+
8189
+ // Also try immediately in case bridge is already ready
8190
+ if (window.FrontMcpBridge && window.FrontMcpBridge.initialized) {
8191
+ subscribeAndInject();
8192
+ }
8193
+
8194
+ // Fallback: poll for bridge
8195
+ var attempts = 0;
8196
+ var interval = setInterval(function() {
8197
+ attempts++;
8198
+ if (window.FrontMcpBridge) {
8199
+ clearInterval(interval);
8200
+ if (!injected) {
8201
+ subscribeAndInject();
8202
+ }
8203
+ } else if (attempts >= 100) {
8204
+ clearInterval(interval);
8205
+ console.warn('[FrontMCP] Inline shell: Timeout waiting for bridge');
8206
+ }
8207
+ }, 100);
8208
+ })();
8209
+ </script>
8210
+
8211
+ <style>
8212
+ @keyframes spin {
8213
+ from { transform: rotate(0deg); }
8214
+ to { transform: rotate(360deg); }
8215
+ }
8216
+ .animate-spin {
8217
+ animation: spin 1s linear infinite;
8218
+ }
8219
+ </style>
8220
+ `;
8221
+ return this.wrapInHtmlDocument({
8222
+ head,
8223
+ body,
8224
+ bodyClass: "antialiased"
8225
+ });
8226
+ }
8227
+ /**
8228
+ * Build full widget HTML with embedded data.
8229
+ *
8230
+ * @param template - Component template
8231
+ * @param input - Tool input data
8232
+ * @param output - Tool output data
8233
+ * @returns Complete HTML with all dependencies and data
8234
+ */
8235
+ async buildFullWidget(template, input, output) {
8236
+ const detection = this.detectTemplate(template);
8237
+ const head = this.buildHead({
8238
+ title: "FrontMCP Widget",
8239
+ includeBridge: true,
8240
+ includeCdn: this.cdnMode === "cdn",
8241
+ includeTheme: true
8242
+ });
8243
+ const dataScript = this.buildDataInjectionScript({
8244
+ toolName: "widget",
8245
+ input,
8246
+ output,
8247
+ usePlaceholders: false
8248
+ });
8249
+ let content;
8250
+ if (detection.renderer === "html") {
8251
+ const context = this.createContext(input, output);
8252
+ if (typeof template === "function") {
8253
+ content = template(context);
8254
+ } else {
8255
+ content = template;
8256
+ }
8257
+ content = `
8258
+ <div id="frontmcp-widget-root">
8259
+ ${content}
8260
+ </div>
8261
+ `;
8262
+ } else {
8263
+ content = this.buildReactContent(template, input, output);
8264
+ }
8265
+ const body = `
8266
+ ${dataScript}
8267
+ ${detection.renderer === "react" ? this.buildReactScripts() : ""}
8268
+ ${content}
8269
+ `;
8270
+ const html = this.wrapInHtmlDocument({
8271
+ head,
8272
+ body,
8273
+ bodyClass: "antialiased"
8274
+ });
8275
+ return this.minify ? this.minifyHtml(html) : html;
8276
+ }
8277
+ // ============================================
8278
+ // Private Methods
8279
+ // ============================================
8280
+ /**
8281
+ * Build React scripts for client-side rendering.
8282
+ */
8283
+ buildReactScripts() {
8284
+ if (this.cdnMode === "cdn") {
8285
+ return generateCdnScriptTags(false) + generateGlobalsSetupScript();
8286
+ }
8287
+ return `
8288
+ <script>
8289
+ console.warn('[FrontMCP] Inline React runtime not yet implemented');
8290
+ </script>
8291
+ `;
8292
+ }
8293
+ /**
8294
+ * Build React content with client-side rendering.
8295
+ */
8296
+ buildReactContent(_template, _input, _output) {
8297
+ return `
8298
+ <div id="frontmcp-widget-root">
8299
+ <div id="root" class="min-h-[200px]">
8300
+ <div class="flex items-center justify-center p-4">
8301
+ <div class="text-center text-gray-500">
8302
+ <p class="text-sm">Initializing...</p>
8303
+ </div>
8304
+ </div>
8305
+ </div>
8306
+ </div>
8307
+
8308
+ <script type="module">
8309
+ // Wait for runtime
8310
+ function waitForRuntime() {
8311
+ return new Promise((resolve) => {
8312
+ if (window.__frontmcpRuntimeReady) {
8313
+ resolve();
8314
+ } else {
8315
+ window.addEventListener('frontmcp:runtime-ready', resolve, { once: true });
8316
+ }
8317
+ });
8318
+ }
8319
+
8320
+ async function renderWidget() {
8321
+ await waitForRuntime();
8322
+
8323
+ const React = window.React;
8324
+ const ReactDOM = window.ReactDOM;
8325
+
8326
+ const input = window.__mcpToolInput || {};
8327
+ const output = window.__mcpToolOutput || {};
8328
+
8329
+ function Widget() {
8330
+ return React.createElement('div', {
8331
+ className: 'p-4',
8332
+ }, React.createElement('pre', {
8333
+ className: 'bg-gray-100 p-2 rounded overflow-auto',
8334
+ }, JSON.stringify(output, null, 2)));
8335
+ }
8336
+
8337
+ const root = ReactDOM.createRoot(document.getElementById('root'));
8338
+ root.render(React.createElement(Widget));
8339
+ }
8340
+
8341
+ renderWidget().catch(console.error);
8342
+ </script>
8343
+ `;
8344
+ }
8345
+ /**
8346
+ * Simple HTML minification.
8347
+ */
8348
+ minifyHtml(html) {
8349
+ return html.replace(/>\s+</g, "><").replace(/\s{2,}/g, " ").trim();
8350
+ }
8351
+ };
8352
+
6668
8353
  // libs/uipack/src/build/index.ts
6669
8354
  async function buildToolUI(options) {
6670
8355
  const startTime = Date.now();
@@ -6813,49 +8498,78 @@ async function buildToolUIMulti(options) {
6813
8498
  }
6814
8499
  // Annotate the CommonJS export names for ESM import in node:
6815
8500
  0 && (module.exports = {
8501
+ BaseBuilder,
8502
+ CDN_URLS,
6816
8503
  CLAUDE_PLATFORM,
6817
8504
  CLOUDFLARE_CDN,
8505
+ CLOUDFLARE_CDN_URLS,
6818
8506
  DEFAULT_CSP_BY_TYPE,
8507
+ DEFAULT_EXTERNALS,
6819
8508
  DEFAULT_RENDERER_ASSETS,
6820
8509
  DEFAULT_THEME,
8510
+ EXTERNAL_GLOBALS,
6821
8511
  HANDLEBARS_CDN,
8512
+ HYBRID_DATA_PLACEHOLDER,
8513
+ HYBRID_INPUT_PLACEHOLDER,
8514
+ HybridBuilder,
8515
+ InlineBuilder,
6822
8516
  MARKED_CDN,
6823
8517
  MDX_RUNTIME_CDN,
6824
8518
  OPENAI_PLATFORM,
6825
8519
  REACT_CDN,
6826
8520
  REACT_DOM_CDN,
8521
+ StaticBuilder,
6827
8522
  TAILWIND_CDN,
6828
8523
  batchBuildWidgets,
8524
+ buildAlertComponent,
8525
+ buildBadgeComponent,
8526
+ buildButtonComponent,
6829
8527
  buildCDNInfoForUIType,
6830
8528
  buildCDNScriptTag,
6831
8529
  buildCSPForType,
6832
8530
  buildCSPMetaContent,
8531
+ buildCardComponent,
6833
8532
  buildCloudflareScriptTag,
6834
8533
  buildCloudflareStylesheetTag,
6835
8534
  buildFileComponent,
6836
8535
  buildFileComponents,
8536
+ buildNamespaceExport,
6837
8537
  buildScriptsForUIType,
6838
8538
  buildStaticWidget,
8539
+ buildStyleConstants,
6839
8540
  buildTailwindScriptTag,
6840
8541
  buildToolResponseMeta,
6841
8542
  buildToolUI,
6842
8543
  buildToolUIMulti,
6843
8544
  buildToolWidgetManifest,
8545
+ buildUIComponentsRuntime,
8546
+ createExternalizedConfig,
8547
+ createExternalsBanner,
8548
+ createInlineConfig,
6844
8549
  createTemplateHelpers,
8550
+ createTransformConfig,
6845
8551
  detectUIType,
8552
+ generateCdnScriptTags,
8553
+ generateGlobalsSetupScript,
6846
8554
  getCachedFileComponent,
6847
8555
  getDefaultAssets,
8556
+ getHybridPlaceholders,
6848
8557
  getOutputModeForClient,
6849
8558
  getPlatformFromClientInfo,
6850
8559
  getRendererAssets,
6851
8560
  getTailwindForPlatform,
6852
8561
  getURLsToPreFetch,
6853
8562
  hasInlineScripts,
8563
+ injectHybridData,
8564
+ injectHybridDataFull,
8565
+ injectHybridDataWithTrigger,
6854
8566
  isBundlingMode,
6855
8567
  isDisplayMode,
6856
8568
  isFilePathTemplate,
8569
+ isHybridShell,
6857
8570
  isOutputMode,
6858
8571
  isResourceMode,
6859
8572
  isUIType,
6860
- needsFileComponentRebuild
8573
+ needsFileComponentRebuild,
8574
+ needsInputInjection
6861
8575
  });