@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
@@ -8,13 +8,6 @@ var __export = (target, all) => {
8
8
  __defProp(target, name, { get: all[name], enumerable: true });
9
9
  };
10
10
 
11
- // libs/uipack/src/utils/safe-stringify.ts
12
- var init_safe_stringify = __esm({
13
- "libs/uipack/src/utils/safe-stringify.ts"() {
14
- "use strict";
15
- }
16
- });
17
-
18
11
  // libs/uipack/src/utils/escape-html.ts
19
12
  function escapeHtml(str) {
20
13
  if (str === null || str === void 0) {
@@ -26,6 +19,12 @@ function escapeHtml(str) {
26
19
  function escapeHtmlAttr(str) {
27
20
  return str.replace(/&/g, "&").replace(/"/g, """);
28
21
  }
22
+ function escapeJsString(str) {
23
+ 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");
24
+ }
25
+ function escapeScriptClose(jsonString) {
26
+ return jsonString.replace(/<\//g, "<\\/");
27
+ }
29
28
  var init_escape_html = __esm({
30
29
  "libs/uipack/src/utils/escape-html.ts"() {
31
30
  "use strict";
@@ -36,7 +35,6 @@ var init_escape_html = __esm({
36
35
  var init_utils = __esm({
37
36
  "libs/uipack/src/utils/index.ts"() {
38
37
  "use strict";
39
- init_safe_stringify();
40
38
  init_escape_html();
41
39
  }
42
40
  });
@@ -267,7 +265,6 @@ var init_helpers = __esm({
267
265
  // libs/uipack/src/handlebars/expression-extractor.ts
268
266
  function extractExpressions(template) {
269
267
  const expressions = [];
270
- const lines = template.split("\n");
271
268
  const positionMap = buildPositionMap(template);
272
269
  let match;
273
270
  EXPRESSION_REGEX.lastIndex = 0;
@@ -666,7 +663,7 @@ async function calculateComponentHash(options) {
666
663
  const {
667
664
  entryPath,
668
665
  baseDir = dirname(entryPath),
669
- externals = [],
666
+ externals: _externals = [],
670
667
  dependencies = {},
671
668
  bundleOptions = {},
672
669
  maxDepth = 10
@@ -793,7 +790,7 @@ function getPackagePeerDependencies(packageName, registry = DEFAULT_CDN_REGISTRY
793
790
  }
794
791
  return [];
795
792
  }
796
- function resolveAllDependencies(packageNames, platform = "unknown", registry = DEFAULT_CDN_REGISTRY) {
793
+ function resolveAllDependencies(packageNames, _platform = "unknown", registry = DEFAULT_CDN_REGISTRY) {
797
794
  const resolved = /* @__PURE__ */ new Set();
798
795
  const queue = [...packageNames];
799
796
  while (queue.length > 0) {
@@ -2708,8 +2705,10 @@ var init_component_builder = __esm({
2708
2705
  return void 0;
2709
2706
  }
2710
2707
  try {
2711
- const React = await import("react");
2712
- const ReactDOMServer = await import("react-dom/server");
2708
+ const reactPkg = "react";
2709
+ const reactDomServerPkg = "react-dom/server";
2710
+ const React = await import(reactPkg);
2711
+ const ReactDOMServer = await import(reactDomServerPkg);
2713
2712
  const exports = {};
2714
2713
  const module = { exports };
2715
2714
  if (executeCode) {
@@ -3582,9 +3581,6 @@ var BRIDGE_SCRIPT_TAGS = {
3582
3581
  gemini: `<script>${generatePlatformBundle("gemini")}</script>`
3583
3582
  };
3584
3583
 
3585
- // libs/uipack/src/runtime/mcp-bridge.ts
3586
- var FRONTMCP_BRIDGE_RUNTIME = BRIDGE_SCRIPT_TAGS.universal;
3587
-
3588
3584
  // libs/uipack/src/runtime/csp.ts
3589
3585
  var DEFAULT_CDN_DOMAINS = [
3590
3586
  "https://cdn.jsdelivr.net",
@@ -3707,9 +3703,6 @@ var scriptCache = /* @__PURE__ */ new Map();
3707
3703
  function getCachedScript(url) {
3708
3704
  return scriptCache.get(url);
3709
3705
  }
3710
- function isScriptCached(url) {
3711
- return scriptCache.has(url);
3712
- }
3713
3706
  function buildFontPreconnect() {
3714
3707
  return CDN.fonts.preconnect.map((url, i) => `<link rel="preconnect" href="${url}"${i > 0 ? " crossorigin" : ""}>`).join("\n ");
3715
3708
  }
@@ -3742,8 +3735,9 @@ function buildCdnScripts(options = {}) {
3742
3735
  const scripts = [];
3743
3736
  if (inline) {
3744
3737
  if (tailwind) {
3745
- if (isScriptCached(CDN.tailwind)) {
3746
- scripts.push(buildInlineScriptTag(getCachedScript(CDN.tailwind)));
3738
+ const cached = getCachedScript(CDN.tailwind);
3739
+ if (cached) {
3740
+ scripts.push(buildInlineScriptTag(cached));
3747
3741
  } else {
3748
3742
  console.warn(
3749
3743
  "[frontmcp/ui] Inline mode requested but Tailwind script not cached. Call fetchAndCacheScripts() first."
@@ -3751,8 +3745,9 @@ function buildCdnScripts(options = {}) {
3751
3745
  }
3752
3746
  }
3753
3747
  if (htmx) {
3754
- if (isScriptCached(CDN.htmx.url)) {
3755
- scripts.push(buildInlineScriptTag(getCachedScript(CDN.htmx.url)));
3748
+ const cached = getCachedScript(CDN.htmx.url);
3749
+ if (cached) {
3750
+ scripts.push(buildInlineScriptTag(cached));
3756
3751
  } else {
3757
3752
  console.warn(
3758
3753
  "[frontmcp/ui] Inline mode requested but HTMX script not cached. Call fetchAndCacheScripts() first."
@@ -3760,8 +3755,9 @@ function buildCdnScripts(options = {}) {
3760
3755
  }
3761
3756
  }
3762
3757
  if (alpine) {
3763
- if (isScriptCached(CDN.alpine.url)) {
3764
- scripts.push(buildInlineScriptTag(getCachedScript(CDN.alpine.url)));
3758
+ const cached = getCachedScript(CDN.alpine.url);
3759
+ if (cached) {
3760
+ scripts.push(buildInlineScriptTag(cached));
3765
3761
  } else {
3766
3762
  console.warn(
3767
3763
  "[frontmcp/ui] Inline mode requested but Alpine.js script not cached. Call fetchAndCacheScripts() first."
@@ -3769,8 +3765,9 @@ function buildCdnScripts(options = {}) {
3769
3765
  }
3770
3766
  }
3771
3767
  if (icons) {
3772
- if (isScriptCached(CDN.icons.url)) {
3773
- scripts.push(buildInlineScriptTag(getCachedScript(CDN.icons.url)));
3768
+ const cached = getCachedScript(CDN.icons.url);
3769
+ if (cached) {
3770
+ scripts.push(buildInlineScriptTag(cached));
3774
3771
  } else {
3775
3772
  console.warn(
3776
3773
  "[frontmcp/ui] Inline mode requested but Lucide icons script not cached. Call fetchAndCacheScripts() first."
@@ -3812,11 +3809,12 @@ var CLAUDE_PLATFORM = {
3812
3809
  id: "claude",
3813
3810
  name: "Claude (Artifacts)",
3814
3811
  supportsWidgets: true,
3812
+ // Claude Artifacts support interactive widgets
3815
3813
  supportsTailwind: true,
3816
3814
  supportsHtmx: false,
3817
3815
  // Network blocked, HTMX won't work for API calls
3818
- networkMode: "blocked",
3819
- scriptStrategy: "inline",
3816
+ networkMode: "limited",
3817
+ scriptStrategy: "cdn",
3820
3818
  maxInlineSize: 100 * 1024,
3821
3819
  // 100KB limit for artifacts
3822
3820
  cspRestrictions: ["script-src 'unsafe-inline'", "connect-src 'none'"],
@@ -4066,17 +4064,31 @@ function emitColorScale(lines, name, scale) {
4066
4064
  if (value) lines.push(`--color-${name}-${shade}: ${value};`);
4067
4065
  }
4068
4066
  }
4067
+ var OPACITY_VARIANTS = [10, 20, 30, 50, 70, 90];
4068
+ function emitColorWithOpacityVariants(lines, name, value) {
4069
+ lines.push(`--color-${name}: ${value};`);
4070
+ for (const opacity of OPACITY_VARIANTS) {
4071
+ lines.push(`--color-${name}-${opacity}: color-mix(in oklch, ${value} ${opacity}%, transparent);`);
4072
+ }
4073
+ }
4074
+ function emitBrandColorWithVariants(lines, name, value) {
4075
+ lines.push(`--color-${name}: ${value};`);
4076
+ lines.push(`--color-${name}-hover: color-mix(in oklch, ${value} 85%, black);`);
4077
+ for (const opacity of OPACITY_VARIANTS) {
4078
+ lines.push(`--color-${name}-${opacity}: color-mix(in oklch, ${value} ${opacity}%, transparent);`);
4079
+ }
4080
+ }
4069
4081
  function buildThemeCss(theme) {
4070
4082
  const lines = [];
4071
4083
  const semantic = theme.colors.semantic;
4072
4084
  if (typeof semantic.primary === "string") {
4073
- lines.push(`--color-primary: ${semantic.primary};`);
4085
+ emitBrandColorWithVariants(lines, "primary", semantic.primary);
4074
4086
  } else if (semantic.primary) {
4075
4087
  emitColorScale(lines, "primary", semantic.primary);
4076
4088
  }
4077
4089
  if (semantic.secondary) {
4078
4090
  if (typeof semantic.secondary === "string") {
4079
- lines.push(`--color-secondary: ${semantic.secondary};`);
4091
+ emitBrandColorWithVariants(lines, "secondary", semantic.secondary);
4080
4092
  } else {
4081
4093
  emitColorScale(lines, "secondary", semantic.secondary);
4082
4094
  }
@@ -4095,10 +4107,10 @@ function buildThemeCss(theme) {
4095
4107
  emitColorScale(lines, "neutral", semantic.neutral);
4096
4108
  }
4097
4109
  }
4098
- if (semantic.success) lines.push(`--color-success: ${semantic.success};`);
4099
- if (semantic.warning) lines.push(`--color-warning: ${semantic.warning};`);
4100
- if (semantic.danger) lines.push(`--color-danger: ${semantic.danger};`);
4101
- if (semantic.info) lines.push(`--color-info: ${semantic.info};`);
4110
+ if (semantic.success) emitColorWithOpacityVariants(lines, "success", semantic.success);
4111
+ if (semantic.warning) emitColorWithOpacityVariants(lines, "warning", semantic.warning);
4112
+ if (semantic.danger) emitColorWithOpacityVariants(lines, "danger", semantic.danger);
4113
+ if (semantic.info) emitColorWithOpacityVariants(lines, "info", semantic.info);
4102
4114
  const surface = theme.colors.surface;
4103
4115
  if (surface?.background) lines.push(`--color-background: ${surface.background};`);
4104
4116
  if (surface?.surface) lines.push(`--color-surface: ${surface.surface};`);
@@ -4981,35 +4993,25 @@ var ComponentCache = class {
4981
4993
  };
4982
4994
  var componentCache = new ComponentCache();
4983
4995
 
4984
- // libs/uipack/src/renderers/mdx.renderer.ts
4985
- var REACT_CDN = {
4986
- react: "https://unpkg.com/react@18/umd/react.production.min.js",
4987
- reactDom: "https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"
4996
+ // libs/uipack/src/renderers/mdx-client.renderer.ts
4997
+ init_utils();
4998
+ function buildReactCdnUrls(version = "19") {
4999
+ return {
5000
+ react: `https://esm.sh/react@${version}`,
5001
+ reactDom: `https://esm.sh/react-dom@${version}/client`,
5002
+ jsxRuntime: `https://esm.sh/react@${version}/jsx-runtime`
5003
+ };
5004
+ }
5005
+ var DEFAULT_CDN = {
5006
+ mdx: "https://esm.sh/@mdx-js/mdx@3",
5007
+ ...buildReactCdnUrls("19")
4988
5008
  };
4989
- var INLINE_MDX_PLACEHOLDER = `
4990
- // MDX runtime not available inline yet.
4991
- // For blocked-network platforms, use pre-rendered HTML templates.
4992
- console.warn('[FrontMCP] MDX hydration not available on this platform.');
4993
- `;
4994
- var MdxRenderer = class {
4995
- type = "mdx";
4996
- priority = 10;
4997
- // Between HTML (0) and React (20)
4998
- /**
4999
- * Lazy-loaded modules.
5000
- */
5001
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5002
- React = null;
5003
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5004
- ReactDOMServer = null;
5005
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5006
- jsxRuntime = null;
5007
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5008
- mdxEvaluate = null;
5009
+ var MdxClientRenderer = class {
5010
+ type = "mdx-client";
5011
+ priority = 8;
5012
+ // Lower than server-side MDX (10)
5009
5013
  /**
5010
5014
  * Check if this renderer can handle the given template.
5011
- *
5012
- * Accepts strings containing MDX syntax (Markdown + JSX).
5013
5015
  */
5014
5016
  canHandle(template) {
5015
5017
  if (typeof template !== "string") {
@@ -5018,11 +5020,9 @@ var MdxRenderer = class {
5018
5020
  return containsMdxSyntax(template);
5019
5021
  }
5020
5022
  /**
5021
- * Transpile MDX to executable JavaScript.
5022
- *
5023
- * Uses @mdx-js/mdx to compile MDX source to a module.
5024
- * Note: For MDX, we use evaluate() which combines compile + run,
5025
- * so this method just returns the source hash for caching purposes.
5023
+ * Prepare MDX template for rendering.
5024
+ * Caches the template hash for deduplication. Actual MDX compilation
5025
+ * happens client-side via CDN-loaded @mdx-js/mdx in the browser.
5026
5026
  */
5027
5027
  async transpile(template, _options) {
5028
5028
  const hash = hashString(template);
@@ -5032,7 +5032,6 @@ var MdxRenderer = class {
5032
5032
  }
5033
5033
  const transpileResult = {
5034
5034
  code: template,
5035
- // Store original MDX for evaluate()
5036
5035
  hash,
5037
5036
  cached: false
5038
5037
  };
@@ -5040,37 +5039,20 @@ var MdxRenderer = class {
5040
5039
  return transpileResult;
5041
5040
  }
5042
5041
  /**
5043
- * Render MDX template to HTML string.
5042
+ * Render MDX template to HTML with CDN scripts.
5044
5043
  *
5045
- * Uses @mdx-js/mdx's evaluate() for clean compilation + execution,
5046
- * then renders the resulting React component to HTML via SSR.
5044
+ * The returned HTML includes:
5045
+ * - A container div for the rendered content
5046
+ * - Script tags that load React and MDX from CDN
5047
+ * - Inline script that compiles and renders the MDX
5047
5048
  */
5048
5049
  async render(template, context, options) {
5049
- await this.loadReact();
5050
- await this.loadMdx();
5051
- if (!this.mdxEvaluate) {
5052
- throw new Error("MDX compilation requires @mdx-js/mdx. Install it: npm install @mdx-js/mdx");
5053
- }
5054
- const templateHash = hashString(template);
5055
- const cacheKey = `mdx-component:${templateHash}`;
5056
- let Content = componentCache.get(cacheKey);
5057
- if (!Content) {
5058
- const result = await this.mdxEvaluate(template, {
5059
- ...this.jsxRuntime,
5060
- Fragment: this.React.Fragment,
5061
- development: false
5062
- });
5063
- Content = result.default;
5064
- componentCache.set(cacheKey, Content);
5065
- }
5066
- const mdxComponents = {
5067
- // User-provided components from tool config
5068
- ...options?.mdxComponents,
5069
- // Wrapper that provides context to the content
5070
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5071
- wrapper: ({ children }) => {
5072
- return this.React.createElement("div", { className: "mdx-content" }, children);
5073
- }
5050
+ const containerId = options?.containerId || "mdx-content";
5051
+ const showLoading = options?.showLoading !== false;
5052
+ const loadingMessage = options?.loadingMessage || "Loading...";
5053
+ const cdn = {
5054
+ ...DEFAULT_CDN,
5055
+ ...options?.cdn
5074
5056
  };
5075
5057
  const props = {
5076
5058
  input: context.input,
@@ -5078,82 +5060,80 @@ var MdxRenderer = class {
5078
5060
  structuredContent: context.structuredContent,
5079
5061
  helpers: context.helpers
5080
5062
  };
5063
+ const reservedProps = /* @__PURE__ */ new Set(["input", "output", "structuredContent", "helpers", "components"]);
5064
+ const outputProps = typeof context.output === "object" && context.output !== null ? Object.fromEntries(Object.entries(context.output).filter(([key]) => !reservedProps.has(key))) : {};
5081
5065
  const spreadProps = {
5082
- ...props,
5083
- ...typeof context.output === "object" && context.output !== null ? context.output : {}
5066
+ ...outputProps,
5067
+ ...props
5084
5068
  };
5085
- const element = this.React.createElement(Content, {
5086
- components: mdxComponents,
5087
- ...spreadProps
5069
+ const escapedMdx = escapeScriptClose(JSON.stringify(template));
5070
+ const escapedProps = escapeScriptClose(JSON.stringify(spreadProps));
5071
+ const safeContainerId = escapeJsString(containerId);
5072
+ const loadingHtml = showLoading ? `<div class="mdx-loading">${escapeHtml(loadingMessage)}</div>` : "";
5073
+ return `
5074
+ <div id="${escapeHtml(containerId)}">${loadingHtml}</div>
5075
+ <script type="module">
5076
+ (async function() {
5077
+ try {
5078
+ // Load dependencies from CDN
5079
+ const [
5080
+ { evaluate },
5081
+ runtime,
5082
+ React,
5083
+ { createRoot }
5084
+ ] = await Promise.all([
5085
+ import('${cdn.mdx}'),
5086
+ import('${cdn.jsxRuntime}'),
5087
+ import('${cdn.react}'),
5088
+ import('${cdn.reactDom}')
5089
+ ]);
5090
+
5091
+ // MDX content and props
5092
+ const mdxSource = ${escapedMdx};
5093
+ const props = ${escapedProps};
5094
+
5095
+ // Compile and evaluate MDX
5096
+ const { default: Content } = await evaluate(mdxSource, {
5097
+ ...runtime,
5098
+ Fragment: React.Fragment,
5099
+ development: false
5088
5100
  });
5089
- const html = this.ReactDOMServer.renderToString(element);
5090
- if (options?.hydrate) {
5091
- const escapedProps = JSON.stringify(props).replace(/&/g, "&amp;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5092
- return `<div data-mdx-hydrate="true" data-props='${escapedProps}'>${html}</div>`;
5101
+
5102
+ // Render to DOM
5103
+ const container = document.getElementById('${safeContainerId}');
5104
+ if (container) {
5105
+ const root = createRoot(container);
5106
+ root.render(React.createElement(Content, props));
5093
5107
  }
5094
- return html;
5108
+ } catch (error) {
5109
+ console.error('[FrontMCP] MDX client rendering failed:', error);
5110
+ const container = document.getElementById('${safeContainerId}');
5111
+ if (container) {
5112
+ container.innerHTML = '<div class="mdx-error">Failed to render MDX content</div>';
5113
+ }
5114
+ }
5115
+ })();
5116
+ </script>
5117
+ `;
5095
5118
  }
5096
5119
  /**
5097
- * Get runtime scripts for client-side functionality.
5120
+ * Get runtime scripts - not needed for client renderer since scripts are inline.
5098
5121
  */
5099
5122
  getRuntimeScripts(platform) {
5100
5123
  if (platform.networkMode === "blocked") {
5101
5124
  return {
5102
5125
  headScripts: "",
5103
- inlineScripts: INLINE_MDX_PLACEHOLDER,
5126
+ inlineScripts: `console.warn('[FrontMCP] Client-side MDX rendering requires network access. Use @frontmcp/ui for SSR.');`,
5104
5127
  isInline: true
5105
5128
  };
5106
5129
  }
5107
5130
  return {
5108
- headScripts: `
5109
- <script crossorigin src="${REACT_CDN.react}"></script>
5110
- <script crossorigin src="${REACT_CDN.reactDom}"></script>
5111
- `,
5131
+ headScripts: "",
5112
5132
  isInline: false
5113
5133
  };
5114
5134
  }
5115
- /**
5116
- * Load React and ReactDOMServer modules.
5117
- */
5118
- async loadReact() {
5119
- if (this.React && this.ReactDOMServer && this.jsxRuntime) {
5120
- return;
5121
- }
5122
- try {
5123
- const [react, reactDomServer, jsxRuntime] = await Promise.all([
5124
- import("react"),
5125
- import("react-dom/server"),
5126
- import("react/jsx-runtime")
5127
- ]);
5128
- this.React = react;
5129
- this.ReactDOMServer = reactDomServer;
5130
- this.jsxRuntime = jsxRuntime;
5131
- } catch {
5132
- throw new Error("React is required for MdxRenderer. Install react and react-dom: npm install react react-dom");
5133
- }
5134
- }
5135
- /**
5136
- * Load @mdx-js/mdx evaluate function.
5137
- *
5138
- * evaluate() is the cleanest way to run MDX - it combines
5139
- * compile and run in a single step, handling all the runtime
5140
- * injection automatically.
5141
- */
5142
- async loadMdx() {
5143
- if (this.mdxEvaluate) {
5144
- return;
5145
- }
5146
- try {
5147
- const mdx = await import("@mdx-js/mdx");
5148
- this.mdxEvaluate = mdx.evaluate;
5149
- } catch {
5150
- console.warn(
5151
- "[@frontmcp/ui] @mdx-js/mdx not available. MDX rendering disabled. Install @mdx-js/mdx to enable: npm install @mdx-js/mdx"
5152
- );
5153
- }
5154
- }
5155
5135
  };
5156
- var mdxRenderer = new MdxRenderer();
5136
+ var mdxClientRenderer = new MdxClientRenderer();
5157
5137
 
5158
5138
  // libs/uipack/src/types/ui-runtime.ts
5159
5139
  function isUIType(value) {
@@ -5223,7 +5203,7 @@ var DEFAULT_RENDERER_ASSETS = {
5223
5203
  };
5224
5204
 
5225
5205
  // libs/uipack/src/build/cdn-resources.ts
5226
- var REACT_CDN2 = {
5206
+ var REACT_CDN = {
5227
5207
  url: "https://esm.sh/react@19",
5228
5208
  crossorigin: "anonymous"
5229
5209
  };
@@ -5253,8 +5233,9 @@ var CLOUDFLARE_CDN = {
5253
5233
  * Use this instead of TAILWIND_CDN for Claude Artifacts.
5254
5234
  */
5255
5235
  tailwindCss: {
5256
- url: "https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css",
5257
- type: "stylesheet"
5236
+ url: "https://cdnjs.cloudflare.com/ajax/libs/tailwindcss-browser/4.1.13/index.global.min.js",
5237
+ integrity: "sha512-TscjjxDy2iXx5s55Ar78c01JDHUug0K5aw4YKId9Yuocjx3ueX/X9PFyH5XNRVWqagx3TtcQWQVBaHAIPFjiFA==",
5238
+ crossorigin: "anonymous"
5258
5239
  },
5259
5240
  /**
5260
5241
  * HTMX for dynamic interactions.
@@ -5294,7 +5275,7 @@ function getTailwindForPlatform(platform) {
5294
5275
  if (platform === "openai") {
5295
5276
  return buildCDNScriptTag(TAILWIND_CDN);
5296
5277
  }
5297
- return `<link href="${CLOUDFLARE_CDN.tailwindCss.url}" rel="stylesheet">`;
5278
+ return buildCDNScriptTag(CLOUDFLARE_CDN.tailwindCss);
5298
5279
  }
5299
5280
  function buildCloudflareStylesheetTag(url) {
5300
5281
  return `<link href="${url}" rel="stylesheet">`;
@@ -5321,13 +5302,13 @@ function getDefaultAssets(uiType, mode = "cdn") {
5321
5302
  case "react":
5322
5303
  return {
5323
5304
  ...baseAssets,
5324
- react: REACT_CDN2,
5305
+ react: REACT_CDN,
5325
5306
  reactDom: REACT_DOM_CDN
5326
5307
  };
5327
5308
  case "mdx":
5328
5309
  return {
5329
5310
  ...baseAssets,
5330
- react: REACT_CDN2,
5311
+ react: REACT_CDN,
5331
5312
  reactDom: REACT_DOM_CDN,
5332
5313
  mdxRuntime: MDX_RUNTIME_CDN,
5333
5314
  markdown: MARKED_CDN
@@ -5345,7 +5326,7 @@ function getDefaultAssets(uiType, mode = "cdn") {
5345
5326
  case "auto":
5346
5327
  return {
5347
5328
  ...baseAssets,
5348
- react: REACT_CDN2,
5329
+ react: REACT_CDN,
5349
5330
  reactDom: REACT_DOM_CDN,
5350
5331
  markdown: MARKED_CDN,
5351
5332
  handlebars: HANDLEBARS_CDN
@@ -5423,13 +5404,13 @@ function buildCDNInfoForUIType(uiType) {
5423
5404
  switch (uiType) {
5424
5405
  case "react":
5425
5406
  return {
5426
- react: REACT_CDN2.url,
5407
+ react: REACT_CDN.url,
5427
5408
  reactDom: REACT_DOM_CDN.url,
5428
5409
  tailwind: TAILWIND_CDN.url
5429
5410
  };
5430
5411
  case "mdx":
5431
5412
  return {
5432
- react: REACT_CDN2.url,
5413
+ react: REACT_CDN.url,
5433
5414
  reactDom: REACT_DOM_CDN.url,
5434
5415
  mdxRuntime: MDX_RUNTIME_CDN.url,
5435
5416
  marked: MARKED_CDN.url,
@@ -5448,7 +5429,7 @@ function buildCDNInfoForUIType(uiType) {
5448
5429
  case "auto":
5449
5430
  default:
5450
5431
  return {
5451
- react: REACT_CDN2.url,
5432
+ react: REACT_CDN.url,
5452
5433
  reactDom: REACT_DOM_CDN.url,
5453
5434
  handlebars: HANDLEBARS_CDN.url,
5454
5435
  marked: MARKED_CDN.url,
@@ -5493,9 +5474,6 @@ function detectFormatFromPath(pathOrUrl) {
5493
5474
  return "html";
5494
5475
  }
5495
5476
 
5496
- // libs/uipack/src/validation/error-box.ts
5497
- init_utils();
5498
-
5499
5477
  // libs/uipack/src/validation/schema-paths.ts
5500
5478
  import { z } from "zod";
5501
5479
  function extractSchemaPaths(schema, prefix = "output", options = {}) {
@@ -6039,7 +6017,7 @@ async function processTemplate(resolved, options) {
6039
6017
  structuredContent: context.structuredContent,
6040
6018
  helpers: defaultHelpers
6041
6019
  };
6042
- const html = await mdxRenderer.render(processedContent, templateContext);
6020
+ const html = await mdxClientRenderer.render(processedContent, templateContext);
6043
6021
  return {
6044
6022
  html,
6045
6023
  format: "mdx"
@@ -6165,7 +6143,7 @@ async function generateHash(content) {
6165
6143
  return Math.abs(hash).toString(16).padStart(8, "0");
6166
6144
  }
6167
6145
  async function buildToolWidgetManifest(options) {
6168
- const { toolName, uiConfig, schema, theme, sampleInput, sampleOutput, outputSchema, inputSchema } = options;
6146
+ const { toolName, uiConfig, schema, theme: _theme, sampleInput, sampleOutput, outputSchema, inputSchema } = options;
6169
6147
  const uiType = isUIType(uiConfig.uiType) ? uiConfig.uiType : detectUIType(uiConfig.template);
6170
6148
  const displayMode = uiConfig.displayMode ?? "inline";
6171
6149
  const bundlingMode = uiConfig.bundlingMode ?? "static";
@@ -6303,7 +6281,7 @@ function ensureRenderersRegistered() {
6303
6281
  return;
6304
6282
  }
6305
6283
  if (!rendererRegistry.has("mdx")) {
6306
- rendererRegistry.register(mdxRenderer);
6284
+ rendererRegistry.register(mdxClientRenderer);
6307
6285
  }
6308
6286
  renderersInitialized = true;
6309
6287
  }
@@ -6591,6 +6569,1684 @@ function getPlatformFromClientInfo(clientInfo) {
6591
6569
  return "unknown";
6592
6570
  }
6593
6571
 
6572
+ // libs/uipack/src/build/hybrid-data.ts
6573
+ var HYBRID_DATA_PLACEHOLDER = "__FRONTMCP_OUTPUT_PLACEHOLDER__";
6574
+ var HYBRID_INPUT_PLACEHOLDER = "__FRONTMCP_INPUT_PLACEHOLDER__";
6575
+ function injectHybridData(shell, data, placeholder = HYBRID_DATA_PLACEHOLDER) {
6576
+ let jsonData;
6577
+ try {
6578
+ jsonData = JSON.stringify(JSON.stringify(data));
6579
+ jsonData = jsonData.slice(1, -1);
6580
+ } catch {
6581
+ jsonData = "null";
6582
+ }
6583
+ return shell.replace(placeholder, jsonData);
6584
+ }
6585
+ function injectHybridDataFull(shell, input, output) {
6586
+ let result = shell;
6587
+ result = injectHybridData(result, output, HYBRID_DATA_PLACEHOLDER);
6588
+ result = injectHybridData(result, input, HYBRID_INPUT_PLACEHOLDER);
6589
+ return result;
6590
+ }
6591
+ function isHybridShell(html, placeholder = HYBRID_DATA_PLACEHOLDER) {
6592
+ return html.includes(placeholder);
6593
+ }
6594
+ function needsInputInjection(html) {
6595
+ return html.includes(HYBRID_INPUT_PLACEHOLDER);
6596
+ }
6597
+ function getHybridPlaceholders(html) {
6598
+ return {
6599
+ hasOutput: html.includes(HYBRID_DATA_PLACEHOLDER),
6600
+ hasInput: html.includes(HYBRID_INPUT_PLACEHOLDER)
6601
+ };
6602
+ }
6603
+ function injectHybridDataWithTrigger(shell, input, output) {
6604
+ let result = injectHybridDataFull(shell, input, output);
6605
+ let outputJson;
6606
+ try {
6607
+ outputJson = JSON.stringify(output);
6608
+ } catch {
6609
+ outputJson = "null";
6610
+ }
6611
+ const triggerScript = `
6612
+ <script>
6613
+ (function() {
6614
+ var data = ${outputJson};
6615
+
6616
+ function triggerUpdate() {
6617
+ if (window.__frontmcp && window.__frontmcp.updateOutput) {
6618
+ window.__frontmcp.updateOutput(data);
6619
+ } else if (window.mcpBridge) {
6620
+ // Trigger via bridge listeners
6621
+ window.dispatchEvent(new CustomEvent('frontmcp:toolResult', { detail: data }));
6622
+ }
6623
+ }
6624
+
6625
+ if (document.readyState === 'loading') {
6626
+ document.addEventListener('DOMContentLoaded', triggerUpdate);
6627
+ } else {
6628
+ // Small delay to ensure store is initialized
6629
+ setTimeout(triggerUpdate, 0);
6630
+ }
6631
+ })();
6632
+ </script>`;
6633
+ result = result.replace("</body>", triggerScript + "\n</body>");
6634
+ return result;
6635
+ }
6636
+
6637
+ // libs/uipack/src/styles/variants.ts
6638
+ var CARD_VARIANTS = {
6639
+ default: "bg-white border border-border rounded-xl shadow-sm",
6640
+ outlined: "bg-transparent border-2 border-border rounded-xl",
6641
+ elevated: "bg-white rounded-xl shadow-lg",
6642
+ filled: "bg-gray-50 rounded-xl",
6643
+ ghost: "bg-transparent"
6644
+ };
6645
+ var CARD_SIZES = {
6646
+ sm: "p-4",
6647
+ md: "p-6",
6648
+ lg: "p-8"
6649
+ };
6650
+ var BADGE_VARIANTS = {
6651
+ default: "bg-gray-100 text-gray-800",
6652
+ primary: "bg-primary/10 text-primary",
6653
+ secondary: "bg-secondary/10 text-secondary",
6654
+ success: "bg-success/10 text-success",
6655
+ warning: "bg-warning/10 text-warning",
6656
+ danger: "bg-danger/10 text-danger",
6657
+ info: "bg-info/10 text-info",
6658
+ outline: "border border-border text-text-primary bg-transparent"
6659
+ };
6660
+ var BADGE_SIZES = {
6661
+ sm: "px-2 py-0.5 text-xs",
6662
+ md: "px-2.5 py-1 text-xs",
6663
+ lg: "px-3 py-1.5 text-sm"
6664
+ };
6665
+ var BADGE_DOT_SIZES = {
6666
+ sm: "w-2 h-2",
6667
+ md: "w-2.5 h-2.5",
6668
+ lg: "w-3 h-3"
6669
+ };
6670
+ var BADGE_DOT_VARIANTS = {
6671
+ default: "bg-gray-400",
6672
+ primary: "bg-primary",
6673
+ secondary: "bg-secondary",
6674
+ success: "bg-success",
6675
+ warning: "bg-warning",
6676
+ danger: "bg-danger",
6677
+ info: "bg-info",
6678
+ outline: "border border-current"
6679
+ };
6680
+ var BUTTON_VARIANTS = {
6681
+ primary: "bg-primary hover:bg-primary/90 text-white shadow-sm",
6682
+ secondary: "bg-secondary hover:bg-secondary/90 text-white shadow-sm",
6683
+ outline: "border-2 border-primary text-primary bg-transparent hover:bg-primary/10",
6684
+ ghost: "text-text-primary hover:bg-gray-100",
6685
+ danger: "bg-danger hover:bg-danger/90 text-white shadow-sm",
6686
+ success: "bg-success hover:bg-success/90 text-white shadow-sm",
6687
+ link: "text-primary hover:text-primary/80 hover:underline"
6688
+ };
6689
+ var BUTTON_SIZES = {
6690
+ xs: "px-2.5 py-1.5 text-xs",
6691
+ sm: "px-3 py-2 text-sm",
6692
+ md: "px-4 py-2.5 text-sm",
6693
+ lg: "px-5 py-3 text-base",
6694
+ xl: "px-6 py-3.5 text-lg"
6695
+ };
6696
+ var BUTTON_ICON_SIZES = {
6697
+ xs: "p-1.5",
6698
+ sm: "p-2",
6699
+ md: "p-2.5",
6700
+ lg: "p-3",
6701
+ xl: "p-4"
6702
+ };
6703
+ 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";
6704
+ var ALERT_VARIANTS = {
6705
+ info: {
6706
+ container: "bg-info/10 border-info/30 text-info",
6707
+ icon: "text-info"
6708
+ },
6709
+ success: {
6710
+ container: "bg-success/10 border-success/30 text-success",
6711
+ icon: "text-success"
6712
+ },
6713
+ warning: {
6714
+ container: "bg-warning/10 border-warning/30 text-warning",
6715
+ icon: "text-warning"
6716
+ },
6717
+ danger: {
6718
+ container: "bg-danger/10 border-danger/30 text-danger",
6719
+ icon: "text-danger"
6720
+ },
6721
+ neutral: {
6722
+ container: "bg-gray-50 border-gray-200 text-gray-800",
6723
+ icon: "text-gray-500"
6724
+ }
6725
+ };
6726
+ var ALERT_BASE_CLASSES = "rounded-lg border p-4";
6727
+ var ALERT_ICONS = {
6728
+ info: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6729
+ <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"/>
6730
+ </svg>`,
6731
+ success: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6732
+ <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"/>
6733
+ </svg>`,
6734
+ warning: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6735
+ <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"/>
6736
+ </svg>`,
6737
+ danger: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6738
+ <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"/>
6739
+ </svg>`,
6740
+ neutral: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6741
+ <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"/>
6742
+ </svg>`
6743
+ };
6744
+ var CLOSE_ICON = `<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6745
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
6746
+ </svg>`;
6747
+ var LOADING_SPINNER = `<svg class="animate-spin -ml-1 mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24">
6748
+ <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
6749
+ <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>
6750
+ </svg>`;
6751
+
6752
+ // libs/uipack/src/build/ui-components-browser.ts
6753
+ function buildStyleConstants() {
6754
+ return `
6755
+ // Style Constants (from @frontmcp/uipack/styles)
6756
+ var CARD_VARIANTS = ${JSON.stringify(CARD_VARIANTS)};
6757
+ var CARD_SIZES = ${JSON.stringify(CARD_SIZES)};
6758
+
6759
+ var BUTTON_VARIANTS = ${JSON.stringify(BUTTON_VARIANTS)};
6760
+ var BUTTON_SIZES = ${JSON.stringify(BUTTON_SIZES)};
6761
+ var BUTTON_ICON_SIZES = ${JSON.stringify(BUTTON_ICON_SIZES)};
6762
+ var BUTTON_BASE_CLASSES = ${JSON.stringify(BUTTON_BASE_CLASSES)};
6763
+ var LOADING_SPINNER = ${JSON.stringify(LOADING_SPINNER)};
6764
+
6765
+ var BADGE_VARIANTS = ${JSON.stringify(BADGE_VARIANTS)};
6766
+ var BADGE_SIZES = ${JSON.stringify(BADGE_SIZES)};
6767
+ var BADGE_DOT_SIZES = ${JSON.stringify(BADGE_DOT_SIZES)};
6768
+ var BADGE_DOT_VARIANTS = ${JSON.stringify(BADGE_DOT_VARIANTS)};
6769
+
6770
+ var ALERT_VARIANTS = ${JSON.stringify(ALERT_VARIANTS)};
6771
+ var ALERT_BASE_CLASSES = ${JSON.stringify(ALERT_BASE_CLASSES)};
6772
+ var ALERT_ICONS = ${JSON.stringify(ALERT_ICONS)};
6773
+ var CLOSE_ICON = ${JSON.stringify(CLOSE_ICON)};
6774
+
6775
+ // Utility: Join CSS classes, filtering out falsy values
6776
+ function cn() {
6777
+ var result = [];
6778
+ for (var i = 0; i < arguments.length; i++) {
6779
+ if (arguments[i]) result.push(arguments[i]);
6780
+ }
6781
+ return result.join(' ');
6782
+ }
6783
+ `;
6784
+ }
6785
+ function buildCardComponent() {
6786
+ return `
6787
+ // Card Component (matches @frontmcp/ui/react/Card)
6788
+ window.Card = function Card(props) {
6789
+ var title = props.title;
6790
+ var subtitle = props.subtitle;
6791
+ var headerActions = props.headerActions;
6792
+ var footer = props.footer;
6793
+ var variant = props.variant || 'default';
6794
+ var size = props.size || 'md';
6795
+ var className = props.className;
6796
+ var id = props.id;
6797
+ var clickable = props.clickable;
6798
+ var href = props.href;
6799
+ var children = props.children;
6800
+
6801
+ var variantClasses = CARD_VARIANTS[variant] || CARD_VARIANTS.default;
6802
+ var sizeClasses = CARD_SIZES[size] || CARD_SIZES.md;
6803
+ var clickableClasses = clickable ? 'cursor-pointer hover:shadow-md transition-shadow' : '';
6804
+ var allClasses = cn(variantClasses, sizeClasses, clickableClasses, className);
6805
+
6806
+ var hasHeader = title || subtitle || headerActions;
6807
+
6808
+ var headerElement = hasHeader ? React.createElement('div', {
6809
+ className: 'flex items-start justify-between mb-4'
6810
+ }, [
6811
+ React.createElement('div', { key: 'titles' }, [
6812
+ title && React.createElement('h3', {
6813
+ key: 'title',
6814
+ className: 'text-lg font-semibold text-text-primary'
6815
+ }, title),
6816
+ subtitle && React.createElement('p', {
6817
+ key: 'subtitle',
6818
+ className: 'text-sm text-text-secondary mt-1'
6819
+ }, subtitle)
6820
+ ]),
6821
+ headerActions && React.createElement('div', {
6822
+ key: 'actions',
6823
+ className: 'flex items-center gap-2'
6824
+ }, headerActions)
6825
+ ]) : null;
6826
+
6827
+ var footerElement = footer ? React.createElement('div', {
6828
+ className: 'mt-4 pt-4 border-t border-divider'
6829
+ }, footer) : null;
6830
+
6831
+ var content = React.createElement(React.Fragment, null, [
6832
+ headerElement,
6833
+ children,
6834
+ footerElement
6835
+ ]);
6836
+
6837
+ if (href) {
6838
+ return React.createElement('a', {
6839
+ href: href,
6840
+ className: allClasses,
6841
+ id: id
6842
+ }, content);
6843
+ }
6844
+
6845
+ return React.createElement('div', {
6846
+ className: allClasses,
6847
+ id: id
6848
+ }, content);
6849
+ };
6850
+ `;
6851
+ }
6852
+ function buildButtonComponent() {
6853
+ return `
6854
+ // Button Component (matches @frontmcp/ui/react/Button)
6855
+ window.Button = function Button(props) {
6856
+ var variant = props.variant || 'primary';
6857
+ var size = props.size || 'md';
6858
+ var disabled = props.disabled || false;
6859
+ var loading = props.loading || false;
6860
+ var fullWidth = props.fullWidth || false;
6861
+ var iconPosition = props.iconPosition || 'left';
6862
+ var icon = props.icon;
6863
+ var iconOnly = props.iconOnly || false;
6864
+ var type = props.type || 'button';
6865
+ var className = props.className;
6866
+ var onClick = props.onClick;
6867
+ var children = props.children;
6868
+
6869
+ var variantClasses = BUTTON_VARIANTS[variant] || BUTTON_VARIANTS.primary;
6870
+ var sizeClasses = iconOnly
6871
+ ? (BUTTON_ICON_SIZES[size] || BUTTON_ICON_SIZES.md)
6872
+ : (BUTTON_SIZES[size] || BUTTON_SIZES.md);
6873
+
6874
+ var disabledClasses = (disabled || loading) ? 'opacity-50 cursor-not-allowed' : '';
6875
+ var widthClasses = fullWidth ? 'w-full' : '';
6876
+
6877
+ var allClasses = cn(BUTTON_BASE_CLASSES, variantClasses, sizeClasses, disabledClasses, widthClasses, className);
6878
+
6879
+ var iconElement = icon ? React.createElement('span', {
6880
+ className: iconPosition === 'left' ? 'mr-2' : 'ml-2'
6881
+ }, icon) : null;
6882
+
6883
+ var loadingSpinner = loading ? React.createElement('span', {
6884
+ className: 'mr-2',
6885
+ dangerouslySetInnerHTML: { __html: LOADING_SPINNER }
6886
+ }) : null;
6887
+
6888
+ return React.createElement('button', {
6889
+ type: type,
6890
+ className: allClasses,
6891
+ disabled: disabled || loading,
6892
+ onClick: onClick
6893
+ }, [
6894
+ loadingSpinner,
6895
+ !loading && icon && iconPosition === 'left' ? iconElement : null,
6896
+ !iconOnly ? children : null,
6897
+ !loading && icon && iconPosition === 'right' ? iconElement : null
6898
+ ]);
6899
+ };
6900
+ `;
6901
+ }
6902
+ function buildBadgeComponent() {
6903
+ return `
6904
+ // Badge Component (matches @frontmcp/ui/react/Badge)
6905
+ window.Badge = function Badge(props) {
6906
+ var variant = props.variant || 'default';
6907
+ var size = props.size || 'md';
6908
+ var pill = props.pill || false;
6909
+ var icon = props.icon;
6910
+ var dot = props.dot || false;
6911
+ var className = props.className;
6912
+ var removable = props.removable || false;
6913
+ var onRemove = props.onRemove;
6914
+ var children = props.children;
6915
+
6916
+ // Handle dot badge (status indicator)
6917
+ if (dot) {
6918
+ var dotSizeClasses = BADGE_DOT_SIZES[size] || BADGE_DOT_SIZES.md;
6919
+ var dotVariantClasses = BADGE_DOT_VARIANTS[variant] || BADGE_DOT_VARIANTS.default;
6920
+ var dotClasses = cn('inline-block rounded-full', dotSizeClasses, dotVariantClasses, className);
6921
+
6922
+ var label = typeof children === 'string' ? children : undefined;
6923
+
6924
+ return React.createElement('span', {
6925
+ className: dotClasses,
6926
+ 'aria-label': label,
6927
+ title: label
6928
+ });
6929
+ }
6930
+
6931
+ var variantClasses = BADGE_VARIANTS[variant] || BADGE_VARIANTS.default;
6932
+ var sizeClasses = BADGE_SIZES[size] || BADGE_SIZES.md;
6933
+
6934
+ var baseClasses = cn(
6935
+ 'inline-flex items-center font-medium',
6936
+ pill ? 'rounded-full' : 'rounded-md',
6937
+ variantClasses,
6938
+ sizeClasses,
6939
+ className
6940
+ );
6941
+
6942
+ var closeButton = removable ? React.createElement('button', {
6943
+ type: 'button',
6944
+ className: 'ml-1.5 -mr-1 hover:opacity-70 transition-opacity',
6945
+ 'aria-label': 'Remove',
6946
+ onClick: onRemove
6947
+ }, React.createElement('svg', {
6948
+ className: 'w-3 h-3',
6949
+ fill: 'none',
6950
+ stroke: 'currentColor',
6951
+ viewBox: '0 0 24 24'
6952
+ }, React.createElement('path', {
6953
+ strokeLinecap: 'round',
6954
+ strokeLinejoin: 'round',
6955
+ strokeWidth: '2',
6956
+ d: 'M6 18L18 6M6 6l12 12'
6957
+ }))) : null;
6958
+
6959
+ return React.createElement('span', {
6960
+ className: baseClasses
6961
+ }, [
6962
+ icon ? React.createElement('span', { key: 'icon', className: 'mr-1' }, icon) : null,
6963
+ children,
6964
+ closeButton
6965
+ ]);
6966
+ };
6967
+ `;
6968
+ }
6969
+ function buildAlertComponent() {
6970
+ return `
6971
+ // Alert Component (matches @frontmcp/ui/react/Alert)
6972
+ window.Alert = function Alert(props) {
6973
+ var variant = props.variant || 'info';
6974
+ var title = props.title;
6975
+ var icon = props.icon;
6976
+ var showIcon = props.showIcon !== false;
6977
+ var dismissible = props.dismissible || false;
6978
+ var onDismiss = props.onDismiss;
6979
+ var className = props.className;
6980
+ var children = props.children;
6981
+
6982
+ var variantStyles = ALERT_VARIANTS[variant] || ALERT_VARIANTS.info;
6983
+ var allClasses = cn(ALERT_BASE_CLASSES, variantStyles.container, className);
6984
+
6985
+ // Use custom icon or default variant icon
6986
+ var iconContent = icon || (showIcon ? React.createElement('span', {
6987
+ className: cn('flex-shrink-0', variantStyles.icon),
6988
+ dangerouslySetInnerHTML: { __html: ALERT_ICONS[variant] || ALERT_ICONS.info }
6989
+ }) : null);
6990
+
6991
+ var dismissButton = dismissible ? React.createElement('button', {
6992
+ type: 'button',
6993
+ className: 'flex-shrink-0 ml-3 hover:opacity-70 transition-opacity',
6994
+ 'aria-label': 'Dismiss',
6995
+ onClick: onDismiss
6996
+ }, React.createElement('span', {
6997
+ dangerouslySetInnerHTML: { __html: CLOSE_ICON }
6998
+ })) : null;
6999
+
7000
+ return React.createElement('div', {
7001
+ className: allClasses,
7002
+ role: 'alert'
7003
+ }, React.createElement('div', {
7004
+ className: 'flex'
7005
+ }, [
7006
+ iconContent ? React.createElement('div', {
7007
+ key: 'icon',
7008
+ className: 'flex-shrink-0 mr-3'
7009
+ }, iconContent) : null,
7010
+ React.createElement('div', {
7011
+ key: 'content',
7012
+ className: 'flex-1'
7013
+ }, [
7014
+ title ? React.createElement('h4', {
7015
+ key: 'title',
7016
+ className: 'font-semibold mb-1'
7017
+ }, title) : null,
7018
+ React.createElement('div', {
7019
+ key: 'body',
7020
+ className: 'text-sm'
7021
+ }, children)
7022
+ ]),
7023
+ dismissButton
7024
+ ]));
7025
+ };
7026
+ `;
7027
+ }
7028
+ function buildNamespaceExport() {
7029
+ return `
7030
+ // Export to namespace (for require('@frontmcp/ui/react') shim)
7031
+ window.frontmcp_ui_namespaceObject = Object.assign({}, window.React || {}, {
7032
+ // Hooks
7033
+ useToolOutput: window.useToolOutput,
7034
+ useToolInput: window.useToolInput,
7035
+ useMcpBridgeContext: function() { return window.__frontmcp.context; },
7036
+ useMcpBridge: function() { return window.__frontmcp.context; },
7037
+ useCallTool: function() {
7038
+ return function(name, args) {
7039
+ if (window.__frontmcp.context.callTool) {
7040
+ return window.__frontmcp.context.callTool(name, args);
7041
+ }
7042
+ console.warn('[FrontMCP] callTool not available');
7043
+ return Promise.resolve(null);
7044
+ };
7045
+ },
7046
+ useTheme: function() { return window.__frontmcp.theme || 'light'; },
7047
+ useDisplayMode: function() { return window.__frontmcp.displayMode || 'embedded'; },
7048
+ useHostContext: function() { return window.__frontmcp.hostContext || {}; },
7049
+ useCapability: function(cap) { return window.__frontmcp.capabilities?.[cap] || false; },
7050
+ useStructuredContent: function() { return window.__frontmcp.getState().structuredContent; },
7051
+ useToolCalls: function() { return []; },
7052
+ useSendMessage: function() { return function() { return Promise.resolve(); }; },
7053
+ useOpenLink: function() { return function() {}; },
7054
+
7055
+ // Components
7056
+ Card: window.Card,
7057
+ Badge: window.Badge,
7058
+ Button: window.Button,
7059
+ Alert: window.Alert,
7060
+
7061
+ // Re-export React stuff for convenience
7062
+ createElement: React.createElement,
7063
+ Fragment: React.Fragment,
7064
+ useState: React.useState,
7065
+ useEffect: React.useEffect,
7066
+ useCallback: React.useCallback,
7067
+ useMemo: React.useMemo,
7068
+ useRef: React.useRef,
7069
+ useContext: React.useContext
7070
+ });
7071
+ `;
7072
+ }
7073
+ function buildUIComponentsRuntime(options = {}) {
7074
+ const parts = [
7075
+ "// UI Components (Browser-Compatible)",
7076
+ "// Generated from @frontmcp/ui/react components",
7077
+ "(function() {",
7078
+ buildStyleConstants(),
7079
+ buildCardComponent(),
7080
+ buildButtonComponent(),
7081
+ buildBadgeComponent(),
7082
+ buildAlertComponent(),
7083
+ buildNamespaceExport(),
7084
+ "})();"
7085
+ ];
7086
+ let script = parts.join("\n");
7087
+ if (options.minify) {
7088
+ script = minifyScript(script);
7089
+ }
7090
+ return script;
7091
+ }
7092
+ function minifyScript(script) {
7093
+ return script.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/[^\n]*$/gm, "").replace(/\n\s*\n/g, "\n").replace(/^\s+/gm, "").trim();
7094
+ }
7095
+
7096
+ // libs/uipack/src/build/builders/base-builder.ts
7097
+ import { transform } from "esbuild";
7098
+
7099
+ // libs/uipack/src/build/builders/esbuild-config.ts
7100
+ var DEFAULT_EXTERNALS = [
7101
+ "react",
7102
+ "react-dom",
7103
+ "react/jsx-runtime",
7104
+ "react/jsx-dev-runtime",
7105
+ "@frontmcp/ui",
7106
+ "@frontmcp/ui/*"
7107
+ ];
7108
+ var EXTERNAL_GLOBALS = {
7109
+ "react": "React",
7110
+ "react-dom": "ReactDOM",
7111
+ "react/jsx-runtime": "jsxRuntime",
7112
+ "react/jsx-dev-runtime": "jsxRuntime",
7113
+ "@frontmcp/ui": "FrontMcpUI"
7114
+ };
7115
+ function createTransformConfig(options = {}) {
7116
+ const {
7117
+ format = "esm",
7118
+ target = "es2020",
7119
+ minify = false,
7120
+ jsxImportSource = "react"
7121
+ } = options;
7122
+ return {
7123
+ loader: "tsx",
7124
+ format,
7125
+ target,
7126
+ minify,
7127
+ treeShaking: true,
7128
+ jsx: "automatic",
7129
+ jsxImportSource,
7130
+ sourcemap: options.minify ? false : "inline"
7131
+ };
7132
+ }
7133
+ function createExternalizedConfig(options = {}) {
7134
+ const baseConfig = createTransformConfig({
7135
+ ...options,
7136
+ format: "esm"
7137
+ });
7138
+ return {
7139
+ ...baseConfig,
7140
+ // Add banner to define external namespace objects
7141
+ banner: createExternalsBanner(options.externals || DEFAULT_EXTERNALS)
7142
+ };
7143
+ }
7144
+ function createExternalsBanner(externals) {
7145
+ const lines = [
7146
+ "// Externalized dependencies - loaded from shell globals"
7147
+ ];
7148
+ for (const pkg of externals) {
7149
+ const globalName = EXTERNAL_GLOBALS[pkg];
7150
+ if (globalName) {
7151
+ const safeName = pkg.replace(/[^a-zA-Z0-9]/g, "_");
7152
+ lines.push(`const __external_${safeName} = window.${globalName};`);
7153
+ }
7154
+ }
7155
+ return lines.join("\n");
7156
+ }
7157
+ function createInlineConfig(options = {}) {
7158
+ return createTransformConfig({
7159
+ ...options,
7160
+ format: "iife",
7161
+ minify: options.minify ?? true
7162
+ });
7163
+ }
7164
+ var CDN_URLS = {
7165
+ react: "https://esm.sh/react@19",
7166
+ reactDom: "https://esm.sh/react-dom@19",
7167
+ reactJsxRuntime: "https://esm.sh/react@19/jsx-runtime",
7168
+ frontmcpUI: "https://esm.sh/@frontmcp/ui",
7169
+ tailwind: "https://cdn.tailwindcss.com"
7170
+ };
7171
+ var CLOUDFLARE_CDN_URLS = {
7172
+ react: "https://cdnjs.cloudflare.com/ajax/libs/react/19.0.0/umd/react.production.min.js",
7173
+ reactDom: "https://cdnjs.cloudflare.com/ajax/libs/react-dom/19.0.0/umd/react-dom.production.min.js",
7174
+ tailwind: "https://cdn.tailwindcss.com"
7175
+ };
7176
+ function generateCdnScriptTags(useCloudflare = false) {
7177
+ const urls = useCloudflare ? CLOUDFLARE_CDN_URLS : CDN_URLS;
7178
+ if (useCloudflare) {
7179
+ return `
7180
+ <script src="${urls.react}"></script>
7181
+ <script src="${urls.reactDom}"></script>
7182
+ <script src="${urls.tailwind}"></script>
7183
+ `;
7184
+ }
7185
+ return `
7186
+ <script type="importmap">
7187
+ {
7188
+ "imports": {
7189
+ "react": "${CDN_URLS.react}",
7190
+ "react-dom": "${CDN_URLS.reactDom}",
7191
+ "react/jsx-runtime": "${CDN_URLS.reactJsxRuntime}",
7192
+ "@frontmcp/ui": "${CDN_URLS.frontmcpUI}"
7193
+ }
7194
+ }
7195
+ </script>
7196
+ <script src="${CDN_URLS.tailwind}"></script>
7197
+ `;
7198
+ }
7199
+ function generateGlobalsSetupScript() {
7200
+ return `
7201
+ <script type="module">
7202
+ import React from 'react';
7203
+ import ReactDOM from 'react-dom/client';
7204
+ import * as jsxRuntime from 'react/jsx-runtime';
7205
+
7206
+ // Expose as globals for externalized components
7207
+ window.React = React;
7208
+ window.ReactDOM = ReactDOM;
7209
+ window.jsxRuntime = jsxRuntime;
7210
+
7211
+ // Signal that runtime is ready
7212
+ window.__frontmcpRuntimeReady = true;
7213
+ window.dispatchEvent(new CustomEvent('frontmcp:runtime-ready'));
7214
+ </script>
7215
+ `;
7216
+ }
7217
+
7218
+ // libs/uipack/src/build/builders/base-builder.ts
7219
+ init_utils();
7220
+ var BaseBuilder = class {
7221
+ /**
7222
+ * CDN loading mode.
7223
+ */
7224
+ cdnMode;
7225
+ /**
7226
+ * Whether to minify output.
7227
+ */
7228
+ minify;
7229
+ /**
7230
+ * Theme configuration.
7231
+ */
7232
+ theme;
7233
+ /**
7234
+ * Whether to include source maps.
7235
+ */
7236
+ sourceMaps;
7237
+ constructor(options = {}) {
7238
+ this.cdnMode = options.cdnMode ?? "cdn";
7239
+ this.minify = options.minify ?? false;
7240
+ this.theme = options.theme ? mergeThemes(DEFAULT_THEME, options.theme) : DEFAULT_THEME;
7241
+ this.sourceMaps = options.sourceMaps ?? false;
7242
+ }
7243
+ // ============================================
7244
+ // Template Detection
7245
+ // ============================================
7246
+ /**
7247
+ * Detect the type of a template.
7248
+ *
7249
+ * @param template - Template to detect
7250
+ * @returns Detection result with type and renderer info
7251
+ */
7252
+ detectTemplate(template) {
7253
+ if (typeof template === "string") {
7254
+ return {
7255
+ type: "html-string",
7256
+ renderer: "html",
7257
+ needsTranspilation: false
7258
+ };
7259
+ }
7260
+ if (typeof template === "function") {
7261
+ const funcStr = template.toString();
7262
+ if (funcStr.includes("jsx") || funcStr.includes("createElement") || funcStr.includes("React") || template.$$typeof) {
7263
+ return {
7264
+ type: "react-component",
7265
+ renderer: "react",
7266
+ needsTranspilation: true
7267
+ };
7268
+ }
7269
+ return {
7270
+ type: "html-function",
7271
+ renderer: "html",
7272
+ needsTranspilation: false
7273
+ };
7274
+ }
7275
+ if (template && typeof template === "object" && template.$$typeof) {
7276
+ return {
7277
+ type: "react-element",
7278
+ renderer: "react",
7279
+ needsTranspilation: true
7280
+ };
7281
+ }
7282
+ return {
7283
+ type: "html-string",
7284
+ renderer: "html",
7285
+ needsTranspilation: false
7286
+ };
7287
+ }
7288
+ // ============================================
7289
+ // Transpilation
7290
+ // ============================================
7291
+ /**
7292
+ * Transpile a component using esbuild.
7293
+ *
7294
+ * @param source - Source code to transpile
7295
+ * @param options - Transpile options
7296
+ * @returns Transpile result
7297
+ */
7298
+ async transpile(source, options = {}) {
7299
+ const externals = options.externals || DEFAULT_EXTERNALS;
7300
+ const config = options.externals ? createExternalizedConfig(options) : createTransformConfig(options);
7301
+ const result = await transform(source, config);
7302
+ return {
7303
+ code: result.code,
7304
+ map: result.map,
7305
+ size: Buffer.byteLength(result.code, "utf8"),
7306
+ externalizedImports: externals
7307
+ };
7308
+ }
7309
+ /**
7310
+ * Render an HTML template.
7311
+ *
7312
+ * @param template - HTML template (string or function)
7313
+ * @param context - Template context with input/output
7314
+ * @returns Rendered HTML string
7315
+ */
7316
+ renderHtmlTemplate(template, context) {
7317
+ if (typeof template === "string") {
7318
+ return template;
7319
+ }
7320
+ return template(context);
7321
+ }
7322
+ // ============================================
7323
+ // HTML Generation
7324
+ // ============================================
7325
+ /**
7326
+ * Build the <head> section of the HTML document.
7327
+ *
7328
+ * @param options - Head options
7329
+ * @returns HTML head content
7330
+ */
7331
+ buildHead(options) {
7332
+ const {
7333
+ title,
7334
+ includeBridge = true,
7335
+ includeCdn = this.cdnMode === "cdn",
7336
+ includeTheme = true,
7337
+ customStyles = ""
7338
+ } = options;
7339
+ const parts = [
7340
+ "<head>",
7341
+ '<meta charset="UTF-8">',
7342
+ '<meta name="viewport" content="width=device-width, initial-scale=1.0">',
7343
+ `<title>${escapeHtml(title)}</title>`
7344
+ ];
7345
+ parts.push(buildFontPreconnect());
7346
+ parts.push(buildFontStylesheets({ inter: true }));
7347
+ if (includeTheme) {
7348
+ const themeCss = buildThemeCss(this.theme);
7349
+ const customCss = this.theme.customCss || "";
7350
+ parts.push(`
7351
+ <style type="text/tailwindcss">
7352
+ @theme {
7353
+ ${themeCss}
7354
+ }
7355
+ ${customCss}
7356
+ </style>
7357
+ `);
7358
+ }
7359
+ if (customStyles) {
7360
+ parts.push(`<style>${customStyles}</style>`);
7361
+ }
7362
+ if (includeCdn) {
7363
+ parts.push('<script src="https://cdn.tailwindcss.com"></script>');
7364
+ }
7365
+ if (includeBridge) {
7366
+ parts.push(BRIDGE_SCRIPT_TAGS.universal);
7367
+ }
7368
+ parts.push("</head>");
7369
+ return parts.join("\n");
7370
+ }
7371
+ /**
7372
+ * Build data injection script.
7373
+ *
7374
+ * @param options - Injection options
7375
+ * @returns Script tag with data injection
7376
+ */
7377
+ buildDataInjectionScript(options) {
7378
+ const { toolName, input, output, usePlaceholders = false } = options;
7379
+ if (usePlaceholders) {
7380
+ return `
7381
+ <script>
7382
+ window.__mcpToolName = ${JSON.stringify(toolName)};
7383
+ window.__mcpToolInput = JSON.parse("${HYBRID_INPUT_PLACEHOLDER}");
7384
+ window.__mcpToolOutput = JSON.parse("${HYBRID_DATA_PLACEHOLDER}");
7385
+ window.__mcpStructuredContent = window.__mcpToolOutput;
7386
+ </script>
7387
+ `;
7388
+ }
7389
+ return `
7390
+ <script>
7391
+ window.__mcpToolName = ${JSON.stringify(toolName)};
7392
+ window.__mcpToolInput = ${JSON.stringify(input ?? {})};
7393
+ window.__mcpToolOutput = ${JSON.stringify(output ?? {})};
7394
+ window.__mcpStructuredContent = window.__mcpToolOutput;
7395
+ </script>
7396
+ `;
7397
+ }
7398
+ /**
7399
+ * Wrap content in a complete HTML document.
7400
+ *
7401
+ * @param options - Wrap options
7402
+ * @returns Complete HTML document
7403
+ */
7404
+ wrapInHtmlDocument(options) {
7405
+ const { head, body, bodyClass = "" } = options;
7406
+ return `<!DOCTYPE html>
7407
+ <html lang="en">
7408
+ ${head}
7409
+ <body${bodyClass ? ` class="${bodyClass}"` : ""}>
7410
+ ${body}
7411
+ </body>
7412
+ </html>`;
7413
+ }
7414
+ // ============================================
7415
+ // Utility Methods
7416
+ // ============================================
7417
+ /**
7418
+ * Calculate content hash.
7419
+ *
7420
+ * @param content - Content to hash
7421
+ * @returns Hash string
7422
+ */
7423
+ async calculateHash(content) {
7424
+ if (typeof crypto !== "undefined" && crypto.subtle) {
7425
+ const encoder = new TextEncoder();
7426
+ const data = encoder.encode(content);
7427
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
7428
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
7429
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 16);
7430
+ }
7431
+ let hash = 0;
7432
+ for (let i = 0; i < content.length; i++) {
7433
+ const char = content.charCodeAt(i);
7434
+ hash = (hash << 5) - hash + char;
7435
+ hash = hash & hash;
7436
+ }
7437
+ return Math.abs(hash).toString(16).padStart(8, "0");
7438
+ }
7439
+ /**
7440
+ * Estimate gzipped size.
7441
+ *
7442
+ * @param content - Content to estimate
7443
+ * @returns Estimated gzipped size in bytes
7444
+ */
7445
+ estimateGzipSize(content) {
7446
+ return Math.round(Buffer.byteLength(content, "utf8") * 0.25);
7447
+ }
7448
+ /**
7449
+ * Create template context.
7450
+ *
7451
+ * @param input - Tool input
7452
+ * @param output - Tool output
7453
+ * @returns Template context
7454
+ */
7455
+ createContext(input, output) {
7456
+ return {
7457
+ input,
7458
+ output,
7459
+ helpers: {
7460
+ escapeHtml,
7461
+ formatDate: (date, format) => {
7462
+ const d = typeof date === "string" ? new Date(date) : date;
7463
+ if (isNaN(d.getTime())) return String(date);
7464
+ if (format === "iso") return d.toISOString();
7465
+ if (format === "time") return d.toLocaleTimeString();
7466
+ if (format === "datetime") return d.toLocaleString();
7467
+ return d.toLocaleDateString();
7468
+ },
7469
+ formatCurrency: (amount, currency = "USD") => {
7470
+ return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(amount);
7471
+ },
7472
+ uniqueId: (prefix = "mcp") => {
7473
+ return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
7474
+ },
7475
+ jsonEmbed: (data) => {
7476
+ const json2 = JSON.stringify(data);
7477
+ if (json2 === void 0) return "undefined";
7478
+ return json2.replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/'/g, "\\u0027");
7479
+ }
7480
+ }
7481
+ };
7482
+ }
7483
+ };
7484
+
7485
+ // libs/uipack/src/build/builders/static-builder.ts
7486
+ var StaticBuilder = class extends BaseBuilder {
7487
+ mode = "static";
7488
+ constructor(options = {}) {
7489
+ super(options);
7490
+ }
7491
+ /**
7492
+ * Build a static HTML shell with placeholders.
7493
+ *
7494
+ * @param options - Build options
7495
+ * @returns Static build result
7496
+ */
7497
+ async build(options) {
7498
+ const startTime = Date.now();
7499
+ const { template, toolName, title = `${toolName} Widget` } = options;
7500
+ const detection = this.detectTemplate(template.template);
7501
+ let bodyContent;
7502
+ if (detection.renderer === "html") {
7503
+ const context = this.createContext(
7504
+ options.sampleInput ?? {},
7505
+ options.sampleOutput ?? {}
7506
+ );
7507
+ if (typeof template.template === "function") {
7508
+ bodyContent = template.template(context);
7509
+ } else {
7510
+ bodyContent = template.template;
7511
+ }
7512
+ bodyContent = `
7513
+ <div id="frontmcp-widget-root">
7514
+ ${bodyContent}
7515
+ </div>
7516
+ `;
7517
+ } else {
7518
+ bodyContent = this.buildReactShell(template, toolName);
7519
+ }
7520
+ const head = this.buildHead({
7521
+ title,
7522
+ includeBridge: true,
7523
+ includeCdn: this.cdnMode === "cdn",
7524
+ includeTheme: true
7525
+ });
7526
+ const dataScript = this.buildDataInjectionScript({
7527
+ toolName,
7528
+ usePlaceholders: true
7529
+ });
7530
+ let additionalScripts = "";
7531
+ if (detection.renderer === "react") {
7532
+ additionalScripts = this.cdnMode === "cdn" ? generateCdnScriptTags(false) + generateGlobalsSetupScript() : this.buildInlineReactRuntime();
7533
+ }
7534
+ const body = `
7535
+ ${dataScript}
7536
+ ${additionalScripts}
7537
+ ${bodyContent}
7538
+ `;
7539
+ const html = this.wrapInHtmlDocument({
7540
+ head,
7541
+ body,
7542
+ bodyClass: "antialiased"
7543
+ });
7544
+ const finalHtml = this.minify ? this.minifyHtml(html) : html;
7545
+ const hash = await this.calculateHash(finalHtml);
7546
+ const size = Buffer.byteLength(finalHtml, "utf8");
7547
+ const gzipSize = this.estimateGzipSize(finalHtml);
7548
+ return {
7549
+ mode: "static",
7550
+ html: finalHtml,
7551
+ hash,
7552
+ size,
7553
+ gzipSize,
7554
+ placeholders: {
7555
+ hasOutput: finalHtml.includes(HYBRID_DATA_PLACEHOLDER),
7556
+ hasInput: finalHtml.includes(HYBRID_INPUT_PLACEHOLDER)
7557
+ },
7558
+ rendererType: detection.renderer,
7559
+ buildTime: new Date(startTime).toISOString()
7560
+ };
7561
+ }
7562
+ /**
7563
+ * Inject data into a pre-built shell.
7564
+ *
7565
+ * @param shell - HTML shell with placeholders
7566
+ * @param input - Tool input data
7567
+ * @param output - Tool output data
7568
+ * @returns HTML with data injected
7569
+ */
7570
+ injectData(shell, input, output) {
7571
+ return injectHybridDataFull(shell, input, output);
7572
+ }
7573
+ // ============================================
7574
+ // Private Methods
7575
+ // ============================================
7576
+ /**
7577
+ * Build React rendering shell.
7578
+ *
7579
+ * Creates a client-side React rendering setup that:
7580
+ * 1. Waits for runtime to be ready
7581
+ * 2. Loads component code
7582
+ * 3. Renders into #root with data from window.__mcpToolOutput
7583
+ */
7584
+ buildReactShell(template, _toolName) {
7585
+ const _componentName = this.getComponentName(template.template);
7586
+ return `
7587
+ <div id="frontmcp-widget-root">
7588
+ <div id="root" class="min-h-[200px]">
7589
+ <div class="flex items-center justify-center p-4">
7590
+ <div class="text-center text-gray-500">
7591
+ <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">
7592
+ <circle style="opacity: 0.25;" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
7593
+ <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>
7594
+ </svg>
7595
+ <p class="text-sm">Loading...</p>
7596
+ </div>
7597
+ </div>
7598
+ </div>
7599
+ </div>
7600
+
7601
+ <script type="module">
7602
+ // Wait for React runtime to be ready
7603
+ function waitForRuntime() {
7604
+ return new Promise((resolve) => {
7605
+ if (window.__frontmcpRuntimeReady) {
7606
+ resolve();
7607
+ } else {
7608
+ window.addEventListener('frontmcp:runtime-ready', resolve, { once: true });
7609
+ }
7610
+ });
7611
+ }
7612
+
7613
+ async function renderWidget() {
7614
+ await waitForRuntime();
7615
+
7616
+ const React = window.React;
7617
+ const ReactDOM = window.ReactDOM;
7618
+
7619
+ // Get data from injected globals
7620
+ const input = window.__mcpToolInput || {};
7621
+ const output = window.__mcpToolOutput || {};
7622
+
7623
+ // Create simple widget component
7624
+ function Widget() {
7625
+ const [data, setData] = React.useState({ input, output });
7626
+
7627
+ React.useEffect(() => {
7628
+ // Subscribe to data updates via bridge
7629
+ const handleUpdate = (event) => {
7630
+ if (event.detail) {
7631
+ setData((prev) => ({ ...prev, output: event.detail }));
7632
+ }
7633
+ };
7634
+ window.addEventListener('frontmcp:toolResult', handleUpdate);
7635
+ return () => window.removeEventListener('frontmcp:toolResult', handleUpdate);
7636
+ }, []);
7637
+
7638
+ return React.createElement('div', {
7639
+ className: 'p-4',
7640
+ dangerouslySetInnerHTML: {
7641
+ __html: '<pre>' + JSON.stringify(data.output, null, 2) + '</pre>'
7642
+ }
7643
+ });
7644
+ }
7645
+
7646
+ // Render
7647
+ const root = ReactDOM.createRoot(document.getElementById('root'));
7648
+ root.render(React.createElement(Widget));
7649
+ }
7650
+
7651
+ renderWidget().catch(console.error);
7652
+ </script>
7653
+ `;
7654
+ }
7655
+ /**
7656
+ * Build inline React runtime (for offline mode).
7657
+ */
7658
+ buildInlineReactRuntime() {
7659
+ return `
7660
+ <script>
7661
+ // Inline React runtime would be bundled here
7662
+ console.warn('[FrontMCP] Inline React runtime not yet implemented');
7663
+ </script>
7664
+ `;
7665
+ }
7666
+ /**
7667
+ * Get component name from template.
7668
+ */
7669
+ getComponentName(template) {
7670
+ if (typeof template === "function") {
7671
+ return template.name || "Widget";
7672
+ }
7673
+ return "Widget";
7674
+ }
7675
+ /**
7676
+ * Simple HTML minification.
7677
+ */
7678
+ minifyHtml(html) {
7679
+ return html.replace(/>\s+</g, "><").replace(/\s{2,}/g, " ").trim();
7680
+ }
7681
+ };
7682
+
7683
+ // libs/uipack/src/build/builders/hybrid-builder.ts
7684
+ var HybridBuilder = class extends BaseBuilder {
7685
+ mode = "hybrid";
7686
+ /**
7687
+ * Cached vendor shell.
7688
+ */
7689
+ vendorShellCache = null;
7690
+ constructor(options = {}) {
7691
+ super(options);
7692
+ }
7693
+ /**
7694
+ * Build a hybrid result with vendor shell and component chunk.
7695
+ *
7696
+ * @param options - Build options
7697
+ * @returns Hybrid build result
7698
+ */
7699
+ async build(options) {
7700
+ const startTime = Date.now();
7701
+ const { template, toolName } = options;
7702
+ const vendorShell = await this.buildVendorShell();
7703
+ const componentChunk = await this.buildComponentChunk(template.template);
7704
+ const shellResourceUri = `resource://widget/${toolName}/shell`;
7705
+ const combinedHash = await this.calculateHash(vendorShell + componentChunk);
7706
+ const shellSize = Buffer.byteLength(vendorShell, "utf8");
7707
+ const componentSize = Buffer.byteLength(componentChunk, "utf8");
7708
+ const detection = this.detectTemplate(template.template);
7709
+ return {
7710
+ mode: "hybrid",
7711
+ vendorShell,
7712
+ componentChunk,
7713
+ shellResourceUri,
7714
+ hash: combinedHash,
7715
+ shellSize,
7716
+ componentSize,
7717
+ rendererType: detection.renderer,
7718
+ buildTime: new Date(startTime).toISOString()
7719
+ };
7720
+ }
7721
+ /**
7722
+ * Build the vendor shell (shared across all tools).
7723
+ *
7724
+ * The vendor shell contains:
7725
+ * - React/ReactDOM from CDN
7726
+ * - FrontMCP Bridge runtime
7727
+ * - Theme CSS and fonts
7728
+ * - Component injection point
7729
+ *
7730
+ * @returns Vendor shell HTML
7731
+ */
7732
+ async buildVendorShell() {
7733
+ if (this.vendorShellCache) {
7734
+ return this.vendorShellCache;
7735
+ }
7736
+ const head = this.buildHead({
7737
+ title: "FrontMCP Widget",
7738
+ includeBridge: true,
7739
+ includeCdn: this.cdnMode === "cdn",
7740
+ includeTheme: true
7741
+ });
7742
+ const cdnScripts = this.cdnMode === "cdn" ? generateCdnScriptTags(false) + generateGlobalsSetupScript() : "";
7743
+ const body = `
7744
+ <script>
7745
+ window.__mcpToolName = '';
7746
+ window.__mcpToolInput = {};
7747
+ window.__mcpToolOutput = {};
7748
+ window.__mcpStructuredContent = {};
7749
+ </script>
7750
+ ${cdnScripts}
7751
+ <div id="frontmcp-widget-root">
7752
+ <div id="root" class="min-h-[200px]">
7753
+ <!-- Component will be injected here -->
7754
+ <div class="flex items-center justify-center p-4">
7755
+ <div class="text-center text-gray-500">
7756
+ <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">
7757
+ <circle style="opacity: 0.25;" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
7758
+ <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>
7759
+ </svg>
7760
+ <p class="text-sm">Loading component...</p>
7761
+ </div>
7762
+ </div>
7763
+ </div>
7764
+ </div>
7765
+
7766
+ <!-- Component injection script -->
7767
+ <script type="module">
7768
+ // Wait for component code to be injected
7769
+ window.__frontmcpInjectComponent = async function(componentCode) {
7770
+ try {
7771
+ // Wait for runtime
7772
+ if (!window.__frontmcpRuntimeReady) {
7773
+ await new Promise((resolve) => {
7774
+ window.addEventListener('frontmcp:runtime-ready', resolve, { once: true });
7775
+ });
7776
+ }
7777
+
7778
+ // Execute component code
7779
+ const blob = new Blob([componentCode], { type: 'application/javascript' });
7780
+ const url = URL.createObjectURL(blob);
7781
+ const module = await import(url);
7782
+ URL.revokeObjectURL(url);
7783
+
7784
+ // Render component
7785
+ const React = window.React;
7786
+ const ReactDOM = window.ReactDOM;
7787
+ const Component = module.default || module.Widget || module.Component;
7788
+
7789
+ if (Component) {
7790
+ const root = ReactDOM.createRoot(document.getElementById('root'));
7791
+ root.render(React.createElement(Component, {
7792
+ input: window.__mcpToolInput,
7793
+ output: window.__mcpToolOutput,
7794
+ }));
7795
+ }
7796
+ } catch (error) {
7797
+ console.error('[FrontMCP] Component injection failed:', error);
7798
+ document.getElementById('root').innerHTML =
7799
+ '<div class="p-4 text-red-500">Component failed to load</div>';
7800
+ }
7801
+ };
7802
+
7803
+ // Listen for component via bridge
7804
+ if (window.FrontMcpBridge) {
7805
+ const checkForComponent = () => {
7806
+ const meta = window.FrontMcpBridge.getToolResponseMetadata?.() || {};
7807
+ const componentCode = meta['ui/component'] || meta['openai/component'];
7808
+ if (componentCode) {
7809
+ window.__frontmcpInjectComponent(componentCode);
7810
+ }
7811
+ };
7812
+
7813
+ if (window.FrontMcpBridge.onToolResponseMetadata) {
7814
+ window.FrontMcpBridge.onToolResponseMetadata((meta) => {
7815
+ const componentCode = meta['ui/component'] || meta['openai/component'];
7816
+ if (componentCode) {
7817
+ window.__frontmcpInjectComponent(componentCode);
7818
+ }
7819
+ });
7820
+ }
7821
+
7822
+ // Check immediately in case data is already available
7823
+ checkForComponent();
7824
+ }
7825
+ </script>
7826
+ `;
7827
+ const html = this.wrapInHtmlDocument({
7828
+ head,
7829
+ body,
7830
+ bodyClass: "antialiased"
7831
+ });
7832
+ this.vendorShellCache = html;
7833
+ return html;
7834
+ }
7835
+ /**
7836
+ * Build a component chunk for a specific template.
7837
+ *
7838
+ * The component chunk is transpiled with externalized dependencies
7839
+ * (React, etc.) that are provided by the vendor shell.
7840
+ *
7841
+ * @param template - Component template
7842
+ * @returns Transpiled component code
7843
+ */
7844
+ async buildComponentChunk(template) {
7845
+ const detection = this.detectTemplate(template);
7846
+ if (detection.renderer === "html") {
7847
+ return this.wrapHtmlAsComponent(template);
7848
+ }
7849
+ if (typeof template === "function") {
7850
+ return this.transpileReactComponent(template);
7851
+ }
7852
+ return `
7853
+ // Externalized React component
7854
+ const React = window.React;
7855
+
7856
+ export default function Widget({ input, output }) {
7857
+ return React.createElement('div', {
7858
+ className: 'p-4',
7859
+ }, React.createElement('pre', null, JSON.stringify(output, null, 2)));
7860
+ }
7861
+ `;
7862
+ }
7863
+ /**
7864
+ * Combine shell and component for Claude/inline delivery.
7865
+ *
7866
+ * @param shell - Vendor shell HTML
7867
+ * @param component - Component chunk code
7868
+ * @param input - Tool input data
7869
+ * @param output - Tool output data
7870
+ * @returns Complete HTML with embedded component and data
7871
+ */
7872
+ combineForInline(shell, component, input, output) {
7873
+ 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)};`);
7874
+ const componentInjection = `
7875
+ <script type="module">
7876
+ (async function() {
7877
+ // Wait for runtime
7878
+ if (!window.__frontmcpRuntimeReady) {
7879
+ await new Promise((resolve) => {
7880
+ window.addEventListener('frontmcp:runtime-ready', resolve, { once: true });
7881
+ });
7882
+ }
7883
+
7884
+ // Execute component
7885
+ ${component}
7886
+
7887
+ // Render
7888
+ const React = window.React;
7889
+ const ReactDOM = window.ReactDOM;
7890
+ const Component = typeof Widget !== 'undefined' ? Widget : (typeof exports !== 'undefined' ? exports.default : null);
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
+ })();
7900
+ </script>
7901
+ `;
7902
+ result = result.replace("</body>", componentInjection + "\n</body>");
7903
+ return result;
7904
+ }
7905
+ // ============================================
7906
+ // Private Methods
7907
+ // ============================================
7908
+ /**
7909
+ * Wrap HTML template as a React component.
7910
+ */
7911
+ wrapHtmlAsComponent(template) {
7912
+ if (typeof template === "string") {
7913
+ return `
7914
+ // HTML template wrapped as component
7915
+ const React = window.React;
7916
+
7917
+ export default function Widget({ input, output }) {
7918
+ return React.createElement('div', {
7919
+ dangerouslySetInnerHTML: { __html: ${JSON.stringify(template)} }
7920
+ });
7921
+ }
7922
+ `;
7923
+ }
7924
+ return `
7925
+ // HTML function template wrapped as component
7926
+ const React = window.React;
7927
+
7928
+ export default function Widget({ input, output }) {
7929
+ const html = (${template.toString()})({ input, output, helpers: {} });
7930
+ return React.createElement('div', {
7931
+ dangerouslySetInnerHTML: { __html: html }
7932
+ });
7933
+ }
7934
+ `;
7935
+ }
7936
+ /**
7937
+ * Transpile a React component function.
7938
+ */
7939
+ async transpileReactComponent(component) {
7940
+ const funcString = component.toString();
7941
+ const componentName = component.name || "Widget";
7942
+ const source = `
7943
+ // Externalized React component
7944
+ const React = window.React;
7945
+
7946
+ const ${componentName} = ${funcString};
7947
+
7948
+ export default ${componentName};
7949
+ export { ${componentName} as Widget, ${componentName} as Component };
7950
+ `;
7951
+ try {
7952
+ const result = await this.transpile(source, {
7953
+ externals: DEFAULT_EXTERNALS,
7954
+ format: "esm",
7955
+ minify: this.minify
7956
+ });
7957
+ return result.code;
7958
+ } catch (error) {
7959
+ console.warn("[HybridBuilder] Transpilation failed, using source directly:", error);
7960
+ return source;
7961
+ }
7962
+ }
7963
+ };
7964
+
7965
+ // libs/uipack/src/build/builders/inline-builder.ts
7966
+ var InlineBuilder = class extends BaseBuilder {
7967
+ mode = "inline";
7968
+ constructor(options = {}) {
7969
+ super(options);
7970
+ }
7971
+ /**
7972
+ * Build an inline result with loader and full widget generator.
7973
+ *
7974
+ * @param options - Build options
7975
+ * @returns Inline build result
7976
+ */
7977
+ async build(options) {
7978
+ const startTime = Date.now();
7979
+ const { template, toolName } = options;
7980
+ const loaderShell = this.buildLoader(toolName);
7981
+ const buildFullWidget = async (input, output) => {
7982
+ return this.buildFullWidget(template.template, input, output);
7983
+ };
7984
+ const hash = await this.calculateHash(loaderShell);
7985
+ const loaderSize = Buffer.byteLength(loaderShell, "utf8");
7986
+ const detection = this.detectTemplate(template.template);
7987
+ return {
7988
+ mode: "inline",
7989
+ loaderShell,
7990
+ buildFullWidget,
7991
+ hash,
7992
+ loaderSize,
7993
+ rendererType: detection.renderer,
7994
+ buildTime: new Date(startTime).toISOString()
7995
+ };
7996
+ }
7997
+ /**
7998
+ * Build the minimal loader shell.
7999
+ *
8000
+ * The loader contains:
8001
+ * - FrontMCP Bridge runtime
8002
+ * - Loading indicator
8003
+ * - Injector script that replaces document on tool response
8004
+ *
8005
+ * @param toolName - Name of the tool
8006
+ * @returns Loader HTML
8007
+ */
8008
+ buildLoader(toolName) {
8009
+ const head = this.buildHead({
8010
+ title: `${toolName} Widget`,
8011
+ includeBridge: true,
8012
+ includeCdn: this.cdnMode === "cdn",
8013
+ includeTheme: true
8014
+ });
8015
+ const body = `
8016
+ <script>
8017
+ window.__mcpToolName = ${JSON.stringify(toolName)};
8018
+ window.__mcpLeanShell = true;
8019
+ </script>
8020
+
8021
+ <div id="frontmcp-widget-root" class="flex items-center justify-center min-h-[200px] p-4">
8022
+ <div class="text-center text-gray-500">
8023
+ <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">
8024
+ <circle style="opacity: 0.25;" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
8025
+ <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>
8026
+ </svg>
8027
+ <p class="text-sm">Loading widget...</p>
8028
+ </div>
8029
+ </div>
8030
+
8031
+ <!-- Injector script -->
8032
+ <script>
8033
+ (function() {
8034
+ var injected = false;
8035
+
8036
+ function injectWidget(metadata) {
8037
+ if (injected) return;
8038
+
8039
+ var html = null;
8040
+ if (metadata) {
8041
+ html = metadata['ui/html'] || metadata['openai/html'] || metadata.html;
8042
+ }
8043
+
8044
+ if (html && typeof html === 'string') {
8045
+ injected = true;
8046
+ console.log('[FrontMCP] Inline shell: Injecting widget HTML (' + html.length + ' chars)');
8047
+ document.open();
8048
+ document.write(html);
8049
+ document.close();
8050
+ return true;
8051
+ }
8052
+ return false;
8053
+ }
8054
+
8055
+ function subscribeAndInject() {
8056
+ var bridge = window.FrontMcpBridge;
8057
+ if (!bridge) {
8058
+ console.warn('[FrontMCP] Inline shell: Bridge not found');
8059
+ return;
8060
+ }
8061
+
8062
+ // Check if data already available
8063
+ if (typeof bridge.getToolResponseMetadata === 'function') {
8064
+ var existing = bridge.getToolResponseMetadata();
8065
+ if (existing && injectWidget(existing)) {
8066
+ return;
8067
+ }
8068
+ }
8069
+
8070
+ // Subscribe to metadata changes
8071
+ if (typeof bridge.onToolResponseMetadata === 'function') {
8072
+ console.log('[FrontMCP] Inline shell: Subscribing to tool response metadata');
8073
+ bridge.onToolResponseMetadata(function(metadata) {
8074
+ console.log('[FrontMCP] Inline shell: Received tool response metadata');
8075
+ injectWidget(metadata);
8076
+ });
8077
+ }
8078
+ }
8079
+
8080
+ // Wait for bridge:ready event
8081
+ window.addEventListener('bridge:ready', function() {
8082
+ console.log('[FrontMCP] Inline shell: Bridge ready, setting up injector');
8083
+ subscribeAndInject();
8084
+ });
8085
+
8086
+ // Also try immediately in case bridge is already ready
8087
+ if (window.FrontMcpBridge && window.FrontMcpBridge.initialized) {
8088
+ subscribeAndInject();
8089
+ }
8090
+
8091
+ // Fallback: poll for bridge
8092
+ var attempts = 0;
8093
+ var interval = setInterval(function() {
8094
+ attempts++;
8095
+ if (window.FrontMcpBridge) {
8096
+ clearInterval(interval);
8097
+ if (!injected) {
8098
+ subscribeAndInject();
8099
+ }
8100
+ } else if (attempts >= 100) {
8101
+ clearInterval(interval);
8102
+ console.warn('[FrontMCP] Inline shell: Timeout waiting for bridge');
8103
+ }
8104
+ }, 100);
8105
+ })();
8106
+ </script>
8107
+
8108
+ <style>
8109
+ @keyframes spin {
8110
+ from { transform: rotate(0deg); }
8111
+ to { transform: rotate(360deg); }
8112
+ }
8113
+ .animate-spin {
8114
+ animation: spin 1s linear infinite;
8115
+ }
8116
+ </style>
8117
+ `;
8118
+ return this.wrapInHtmlDocument({
8119
+ head,
8120
+ body,
8121
+ bodyClass: "antialiased"
8122
+ });
8123
+ }
8124
+ /**
8125
+ * Build full widget HTML with embedded data.
8126
+ *
8127
+ * @param template - Component template
8128
+ * @param input - Tool input data
8129
+ * @param output - Tool output data
8130
+ * @returns Complete HTML with all dependencies and data
8131
+ */
8132
+ async buildFullWidget(template, input, output) {
8133
+ const detection = this.detectTemplate(template);
8134
+ const head = this.buildHead({
8135
+ title: "FrontMCP Widget",
8136
+ includeBridge: true,
8137
+ includeCdn: this.cdnMode === "cdn",
8138
+ includeTheme: true
8139
+ });
8140
+ const dataScript = this.buildDataInjectionScript({
8141
+ toolName: "widget",
8142
+ input,
8143
+ output,
8144
+ usePlaceholders: false
8145
+ });
8146
+ let content;
8147
+ if (detection.renderer === "html") {
8148
+ const context = this.createContext(input, output);
8149
+ if (typeof template === "function") {
8150
+ content = template(context);
8151
+ } else {
8152
+ content = template;
8153
+ }
8154
+ content = `
8155
+ <div id="frontmcp-widget-root">
8156
+ ${content}
8157
+ </div>
8158
+ `;
8159
+ } else {
8160
+ content = this.buildReactContent(template, input, output);
8161
+ }
8162
+ const body = `
8163
+ ${dataScript}
8164
+ ${detection.renderer === "react" ? this.buildReactScripts() : ""}
8165
+ ${content}
8166
+ `;
8167
+ const html = this.wrapInHtmlDocument({
8168
+ head,
8169
+ body,
8170
+ bodyClass: "antialiased"
8171
+ });
8172
+ return this.minify ? this.minifyHtml(html) : html;
8173
+ }
8174
+ // ============================================
8175
+ // Private Methods
8176
+ // ============================================
8177
+ /**
8178
+ * Build React scripts for client-side rendering.
8179
+ */
8180
+ buildReactScripts() {
8181
+ if (this.cdnMode === "cdn") {
8182
+ return generateCdnScriptTags(false) + generateGlobalsSetupScript();
8183
+ }
8184
+ return `
8185
+ <script>
8186
+ console.warn('[FrontMCP] Inline React runtime not yet implemented');
8187
+ </script>
8188
+ `;
8189
+ }
8190
+ /**
8191
+ * Build React content with client-side rendering.
8192
+ */
8193
+ buildReactContent(_template, _input, _output) {
8194
+ return `
8195
+ <div id="frontmcp-widget-root">
8196
+ <div id="root" class="min-h-[200px]">
8197
+ <div class="flex items-center justify-center p-4">
8198
+ <div class="text-center text-gray-500">
8199
+ <p class="text-sm">Initializing...</p>
8200
+ </div>
8201
+ </div>
8202
+ </div>
8203
+ </div>
8204
+
8205
+ <script type="module">
8206
+ // Wait for runtime
8207
+ function waitForRuntime() {
8208
+ return new Promise((resolve) => {
8209
+ if (window.__frontmcpRuntimeReady) {
8210
+ resolve();
8211
+ } else {
8212
+ window.addEventListener('frontmcp:runtime-ready', resolve, { once: true });
8213
+ }
8214
+ });
8215
+ }
8216
+
8217
+ async function renderWidget() {
8218
+ await waitForRuntime();
8219
+
8220
+ const React = window.React;
8221
+ const ReactDOM = window.ReactDOM;
8222
+
8223
+ const input = window.__mcpToolInput || {};
8224
+ const output = window.__mcpToolOutput || {};
8225
+
8226
+ function Widget() {
8227
+ return React.createElement('div', {
8228
+ className: 'p-4',
8229
+ }, React.createElement('pre', {
8230
+ className: 'bg-gray-100 p-2 rounded overflow-auto',
8231
+ }, JSON.stringify(output, null, 2)));
8232
+ }
8233
+
8234
+ const root = ReactDOM.createRoot(document.getElementById('root'));
8235
+ root.render(React.createElement(Widget));
8236
+ }
8237
+
8238
+ renderWidget().catch(console.error);
8239
+ </script>
8240
+ `;
8241
+ }
8242
+ /**
8243
+ * Simple HTML minification.
8244
+ */
8245
+ minifyHtml(html) {
8246
+ return html.replace(/>\s+</g, "><").replace(/\s{2,}/g, " ").trim();
8247
+ }
8248
+ };
8249
+
6594
8250
  // libs/uipack/src/build/index.ts
6595
8251
  async function buildToolUI(options) {
6596
8252
  const startTime = Date.now();
@@ -6738,49 +8394,78 @@ async function buildToolUIMulti(options) {
6738
8394
  };
6739
8395
  }
6740
8396
  export {
8397
+ BaseBuilder,
8398
+ CDN_URLS,
6741
8399
  CLAUDE_PLATFORM,
6742
8400
  CLOUDFLARE_CDN,
8401
+ CLOUDFLARE_CDN_URLS,
6743
8402
  DEFAULT_CSP_BY_TYPE,
8403
+ DEFAULT_EXTERNALS,
6744
8404
  DEFAULT_RENDERER_ASSETS,
6745
8405
  DEFAULT_THEME,
8406
+ EXTERNAL_GLOBALS,
6746
8407
  HANDLEBARS_CDN,
8408
+ HYBRID_DATA_PLACEHOLDER,
8409
+ HYBRID_INPUT_PLACEHOLDER,
8410
+ HybridBuilder,
8411
+ InlineBuilder,
6747
8412
  MARKED_CDN,
6748
8413
  MDX_RUNTIME_CDN,
6749
8414
  OPENAI_PLATFORM,
6750
- REACT_CDN2 as REACT_CDN,
8415
+ REACT_CDN,
6751
8416
  REACT_DOM_CDN,
8417
+ StaticBuilder,
6752
8418
  TAILWIND_CDN,
6753
8419
  batchBuildWidgets,
8420
+ buildAlertComponent,
8421
+ buildBadgeComponent,
8422
+ buildButtonComponent,
6754
8423
  buildCDNInfoForUIType,
6755
8424
  buildCDNScriptTag,
6756
8425
  buildCSPForType,
6757
8426
  buildCSPMetaContent,
8427
+ buildCardComponent,
6758
8428
  buildCloudflareScriptTag,
6759
8429
  buildCloudflareStylesheetTag,
6760
8430
  buildFileComponent,
6761
8431
  buildFileComponents,
8432
+ buildNamespaceExport,
6762
8433
  buildScriptsForUIType,
6763
8434
  buildStaticWidget,
8435
+ buildStyleConstants,
6764
8436
  buildTailwindScriptTag,
6765
8437
  buildToolResponseMeta,
6766
8438
  buildToolUI,
6767
8439
  buildToolUIMulti,
6768
8440
  buildToolWidgetManifest,
8441
+ buildUIComponentsRuntime,
8442
+ createExternalizedConfig,
8443
+ createExternalsBanner,
8444
+ createInlineConfig,
6769
8445
  createTemplateHelpers,
8446
+ createTransformConfig,
6770
8447
  detectUIType,
8448
+ generateCdnScriptTags,
8449
+ generateGlobalsSetupScript,
6771
8450
  getCachedFileComponent,
6772
8451
  getDefaultAssets,
8452
+ getHybridPlaceholders,
6773
8453
  getOutputModeForClient,
6774
8454
  getPlatformFromClientInfo,
6775
8455
  getRendererAssets,
6776
8456
  getTailwindForPlatform,
6777
8457
  getURLsToPreFetch,
6778
8458
  hasInlineScripts,
8459
+ injectHybridData,
8460
+ injectHybridDataFull,
8461
+ injectHybridDataWithTrigger,
6779
8462
  isBundlingMode,
6780
8463
  isDisplayMode,
6781
8464
  isFilePathTemplate,
8465
+ isHybridShell,
6782
8466
  isOutputMode,
6783
8467
  isResourceMode,
6784
8468
  isUIType,
6785
- needsFileComponentRebuild
8469
+ needsFileComponentRebuild,
8470
+ needsInputInjection
6786
8471
  };