@frontmcp/ui 0.12.2 → 1.0.0-beta.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 (310) hide show
  1. package/README.md +279 -72
  2. package/bridge/adapters/claude.adapter.d.ts.map +1 -1
  3. package/bridge/adapters/gemini.adapter.d.ts.map +1 -1
  4. package/bridge/index.js +2 -36
  5. package/components/Alert/Alert.d.ts +11 -0
  6. package/components/Alert/Alert.d.ts.map +1 -0
  7. package/components/Alert/index.d.ts +4 -0
  8. package/components/Alert/index.d.ts.map +1 -0
  9. package/components/Alert/index.js +61 -0
  10. package/components/Avatar/Avatar.d.ts +10 -0
  11. package/components/Avatar/Avatar.d.ts.map +1 -0
  12. package/components/Avatar/index.d.ts +4 -0
  13. package/components/Avatar/index.d.ts.map +1 -0
  14. package/components/Avatar/index.js +43 -0
  15. package/components/Badge/Badge.d.ts +13 -0
  16. package/components/Badge/Badge.d.ts.map +1 -0
  17. package/components/Badge/index.d.ts +4 -0
  18. package/components/Badge/index.d.ts.map +1 -0
  19. package/{render → components/Badge}/index.js +54 -42
  20. package/components/Button/Button.d.ts +16 -0
  21. package/components/Button/Button.d.ts.map +1 -0
  22. package/components/Button/index.d.ts +4 -0
  23. package/components/Button/index.d.ts.map +1 -0
  24. package/components/Button/index.js +91 -0
  25. package/components/Card/Card.d.ts +25 -0
  26. package/components/Card/Card.d.ts.map +1 -0
  27. package/components/Card/index.d.ts +4 -0
  28. package/components/Card/index.d.ts.map +1 -0
  29. package/components/Card/index.js +110 -0
  30. package/components/List/List.d.ts +15 -0
  31. package/components/List/List.d.ts.map +1 -0
  32. package/components/List/index.d.ts +4 -0
  33. package/components/List/index.d.ts.map +1 -0
  34. package/components/List/index.js +58 -0
  35. package/components/Loader/Loader.d.ts +28 -0
  36. package/components/Loader/Loader.d.ts.map +1 -0
  37. package/components/Loader/LoaderContext.d.ts +20 -0
  38. package/components/Loader/LoaderContext.d.ts.map +1 -0
  39. package/components/Loader/index.d.ts +6 -0
  40. package/components/Loader/index.d.ts.map +1 -0
  41. package/components/Loader/index.js +174 -0
  42. package/components/Modal/Modal.d.ts +22 -0
  43. package/components/Modal/Modal.d.ts.map +1 -0
  44. package/components/Modal/index.d.ts +4 -0
  45. package/components/Modal/index.d.ts.map +1 -0
  46. package/components/Modal/index.js +80 -0
  47. package/components/Select/Select.d.ts +21 -0
  48. package/components/Select/Select.d.ts.map +1 -0
  49. package/components/Select/index.d.ts +4 -0
  50. package/components/Select/index.d.ts.map +1 -0
  51. package/components/Select/index.js +78 -0
  52. package/components/Table/Table.d.ts +15 -0
  53. package/components/Table/Table.d.ts.map +1 -0
  54. package/components/Table/index.d.ts +4 -0
  55. package/components/Table/index.d.ts.map +1 -0
  56. package/components/Table/index.js +70 -0
  57. package/components/TextField/TextField.d.ts +19 -0
  58. package/components/TextField/TextField.d.ts.map +1 -0
  59. package/components/TextField/index.d.ts +4 -0
  60. package/components/TextField/index.d.ts.map +1 -0
  61. package/components/TextField/index.js +77 -0
  62. package/components/index.d.ts +22 -28
  63. package/components/index.d.ts.map +1 -1
  64. package/components/index.js +523 -2521
  65. package/esm/bridge/index.mjs +2 -6
  66. package/esm/components/Alert/index.mjs +28 -0
  67. package/esm/components/Avatar/index.mjs +10 -0
  68. package/esm/components/Badge/index.mjs +56 -0
  69. package/esm/components/Button/index.mjs +58 -0
  70. package/esm/components/Card/index.mjs +77 -0
  71. package/esm/components/List/index.mjs +25 -0
  72. package/esm/components/Loader/index.mjs +141 -0
  73. package/esm/components/Modal/index.mjs +47 -0
  74. package/esm/components/Select/index.mjs +45 -0
  75. package/esm/components/Table/index.mjs +37 -0
  76. package/esm/components/TextField/index.mjs +44 -0
  77. package/esm/components/index.mjs +513 -2415
  78. package/esm/index.mjs +62 -4652
  79. package/esm/package.json +372 -16
  80. package/esm/react/index.mjs +2 -285
  81. package/esm/renderer/charts/index.mjs +336 -0
  82. package/esm/renderer/common/index.mjs +135 -0
  83. package/esm/renderer/csv/index.mjs +193 -0
  84. package/esm/renderer/flow/index.mjs +259 -0
  85. package/esm/renderer/html/index.mjs +99 -0
  86. package/esm/renderer/image/index.mjs +125 -0
  87. package/esm/renderer/index.mjs +2173 -0
  88. package/esm/renderer/maps/index.mjs +217 -0
  89. package/esm/renderer/math/index.mjs +229 -0
  90. package/esm/renderer/mdx/index.mjs +261 -0
  91. package/esm/renderer/media/index.mjs +235 -0
  92. package/esm/renderer/mermaid/index.mjs +220 -0
  93. package/esm/renderer/pdf/index.mjs +229 -0
  94. package/esm/renderer/react/index.mjs +230 -0
  95. package/esm/runtime/index.mjs +194 -0
  96. package/esm/theme/index.mjs +93 -0
  97. package/index.d.ts +10 -18
  98. package/index.d.ts.map +1 -1
  99. package/index.js +63 -4806
  100. package/package.json +372 -16
  101. package/react/index.d.ts +8 -54
  102. package/react/index.d.ts.map +1 -1
  103. package/react/index.js +2 -295
  104. package/renderer/auto-detect.d.ts +39 -0
  105. package/renderer/auto-detect.d.ts.map +1 -0
  106. package/renderer/charts/index.d.ts +22 -0
  107. package/renderer/charts/index.d.ts.map +1 -0
  108. package/renderer/charts/index.js +367 -0
  109. package/renderer/common/index.d.ts +5 -0
  110. package/renderer/common/index.d.ts.map +1 -0
  111. package/renderer/common/index.js +158 -0
  112. package/renderer/common/inject-stylesheet.d.ts +9 -0
  113. package/renderer/common/inject-stylesheet.d.ts.map +1 -0
  114. package/renderer/common/lazy-import.d.ts +85 -0
  115. package/renderer/common/lazy-import.d.ts.map +1 -0
  116. package/renderer/common/use-lazy-module.d.ts +13 -0
  117. package/renderer/common/use-lazy-module.d.ts.map +1 -0
  118. package/renderer/common/use-renderer-theme.d.ts +35 -0
  119. package/renderer/common/use-renderer-theme.d.ts.map +1 -0
  120. package/renderer/csv/index.d.ts +12 -0
  121. package/renderer/csv/index.d.ts.map +1 -0
  122. package/renderer/csv/index.js +224 -0
  123. package/renderer/flow/index.d.ts +40 -0
  124. package/renderer/flow/index.d.ts.map +1 -0
  125. package/renderer/flow/index.js +290 -0
  126. package/renderer/html/index.d.ts +12 -0
  127. package/renderer/html/index.d.ts.map +1 -0
  128. package/renderer/html/index.js +130 -0
  129. package/renderer/image/index.d.ts +11 -0
  130. package/renderer/image/index.d.ts.map +1 -0
  131. package/renderer/image/index.js +156 -0
  132. package/renderer/index.d.ts +32 -0
  133. package/renderer/index.d.ts.map +1 -0
  134. package/renderer/index.js +2206 -0
  135. package/renderer/maps/index.d.ts +27 -0
  136. package/renderer/maps/index.d.ts.map +1 -0
  137. package/renderer/maps/index.js +248 -0
  138. package/renderer/math/index.d.ts +11 -0
  139. package/renderer/math/index.d.ts.map +1 -0
  140. package/renderer/math/index.js +260 -0
  141. package/renderer/mdx/index.d.ts +10 -0
  142. package/renderer/mdx/index.d.ts.map +1 -0
  143. package/renderer/mdx/index.js +292 -0
  144. package/renderer/media/index.d.ts +20 -0
  145. package/renderer/media/index.d.ts.map +1 -0
  146. package/renderer/media/index.js +266 -0
  147. package/renderer/mermaid/index.d.ts +11 -0
  148. package/renderer/mermaid/index.d.ts.map +1 -0
  149. package/renderer/mermaid/index.js +251 -0
  150. package/renderer/pdf/index.d.ts +10 -0
  151. package/renderer/pdf/index.d.ts.map +1 -0
  152. package/renderer/pdf/index.js +260 -0
  153. package/renderer/react/index.d.ts +45 -0
  154. package/renderer/react/index.d.ts.map +1 -0
  155. package/renderer/react/index.js +261 -0
  156. package/renderer/types.d.ts +24 -0
  157. package/renderer/types.d.ts.map +1 -0
  158. package/runtime/babel-runtime.d.ts +70 -0
  159. package/runtime/babel-runtime.d.ts.map +1 -0
  160. package/runtime/content-detector.d.ts +43 -0
  161. package/runtime/content-detector.d.ts.map +1 -0
  162. package/runtime/index.d.ts +10 -0
  163. package/runtime/index.d.ts.map +1 -0
  164. package/runtime/index.js +217 -0
  165. package/theme/FrontMcpThemeProvider.d.ts +4 -0
  166. package/theme/FrontMcpThemeProvider.d.ts.map +1 -0
  167. package/theme/create-theme.d.ts +9 -0
  168. package/theme/create-theme.d.ts.map +1 -0
  169. package/theme/index.d.ts +5 -0
  170. package/theme/index.d.ts.map +1 -0
  171. package/theme/index.js +126 -0
  172. package/theme/types.d.ts +28 -0
  173. package/theme/types.d.ts.map +1 -0
  174. package/theme/use-theme.d.ts +3 -0
  175. package/theme/use-theme.d.ts.map +1 -0
  176. package/bundler/browser-components.d.ts +0 -42
  177. package/bundler/browser-components.d.ts.map +0 -1
  178. package/bundler/bundler.d.ts +0 -282
  179. package/bundler/bundler.d.ts.map +0 -1
  180. package/bundler/index.d.ts +0 -43
  181. package/bundler/index.d.ts.map +0 -1
  182. package/bundler/index.js +0 -3168
  183. package/bundler/types.d.ts +0 -883
  184. package/bundler/types.d.ts.map +0 -1
  185. package/components/alert.d.ts +0 -83
  186. package/components/alert.d.ts.map +0 -1
  187. package/components/alert.schema.d.ts +0 -98
  188. package/components/alert.schema.d.ts.map +0 -1
  189. package/components/avatar.d.ts +0 -77
  190. package/components/avatar.d.ts.map +0 -1
  191. package/components/avatar.schema.d.ts +0 -170
  192. package/components/avatar.schema.d.ts.map +0 -1
  193. package/components/badge.d.ts +0 -78
  194. package/components/badge.d.ts.map +0 -1
  195. package/components/badge.schema.d.ts +0 -91
  196. package/components/badge.schema.d.ts.map +0 -1
  197. package/components/button.d.ts +0 -100
  198. package/components/button.d.ts.map +0 -1
  199. package/components/button.schema.d.ts +0 -120
  200. package/components/button.schema.d.ts.map +0 -1
  201. package/components/card.d.ts +0 -76
  202. package/components/card.d.ts.map +0 -1
  203. package/components/card.schema.d.ts +0 -93
  204. package/components/card.schema.d.ts.map +0 -1
  205. package/components/form.d.ts +0 -227
  206. package/components/form.d.ts.map +0 -1
  207. package/components/form.schema.d.ts +0 -365
  208. package/components/form.schema.d.ts.map +0 -1
  209. package/components/list.d.ts +0 -121
  210. package/components/list.d.ts.map +0 -1
  211. package/components/list.schema.d.ts +0 -129
  212. package/components/list.schema.d.ts.map +0 -1
  213. package/components/modal.d.ts +0 -100
  214. package/components/modal.d.ts.map +0 -1
  215. package/components/modal.schema.d.ts +0 -151
  216. package/components/modal.schema.d.ts.map +0 -1
  217. package/components/table.d.ts +0 -91
  218. package/components/table.d.ts.map +0 -1
  219. package/components/table.schema.d.ts +0 -123
  220. package/components/table.schema.d.ts.map +0 -1
  221. package/esm/bundler/index.mjs +0 -3136
  222. package/esm/layouts/index.mjs +0 -409
  223. package/esm/render/index.mjs +0 -45
  224. package/esm/renderers/index.mjs +0 -621
  225. package/esm/universal/index.mjs +0 -1946
  226. package/esm/web-components/index.mjs +0 -2023
  227. package/layouts/base.d.ts +0 -86
  228. package/layouts/base.d.ts.map +0 -1
  229. package/layouts/index.d.ts +0 -8
  230. package/layouts/index.d.ts.map +0 -1
  231. package/layouts/index.js +0 -437
  232. package/layouts/presets.d.ts +0 -134
  233. package/layouts/presets.d.ts.map +0 -1
  234. package/react/Alert.d.ts +0 -101
  235. package/react/Alert.d.ts.map +0 -1
  236. package/react/Badge.d.ts +0 -100
  237. package/react/Badge.d.ts.map +0 -1
  238. package/react/Button.d.ts +0 -108
  239. package/react/Button.d.ts.map +0 -1
  240. package/react/Card.d.ts +0 -103
  241. package/react/Card.d.ts.map +0 -1
  242. package/react/types.d.ts +0 -105
  243. package/react/types.d.ts.map +0 -1
  244. package/render/index.d.ts +0 -8
  245. package/render/index.d.ts.map +0 -1
  246. package/render/prerender.d.ts +0 -57
  247. package/render/prerender.d.ts.map +0 -1
  248. package/renderers/index.d.ts +0 -26
  249. package/renderers/index.d.ts.map +0 -1
  250. package/renderers/index.js +0 -666
  251. package/renderers/mdx.renderer.d.ts +0 -99
  252. package/renderers/mdx.renderer.d.ts.map +0 -1
  253. package/renderers/react.adapter.d.ts +0 -70
  254. package/renderers/react.adapter.d.ts.map +0 -1
  255. package/renderers/react.renderer.d.ts +0 -105
  256. package/renderers/react.renderer.d.ts.map +0 -1
  257. package/renderers/transpiler.d.ts +0 -49
  258. package/renderers/transpiler.d.ts.map +0 -1
  259. package/universal/UniversalApp.d.ts +0 -108
  260. package/universal/UniversalApp.d.ts.map +0 -1
  261. package/universal/cached-runtime.d.ts +0 -139
  262. package/universal/cached-runtime.d.ts.map +0 -1
  263. package/universal/context.d.ts +0 -122
  264. package/universal/context.d.ts.map +0 -1
  265. package/universal/index.d.ts +0 -57
  266. package/universal/index.d.ts.map +0 -1
  267. package/universal/index.js +0 -2032
  268. package/universal/renderers/html.renderer.d.ts +0 -36
  269. package/universal/renderers/html.renderer.d.ts.map +0 -1
  270. package/universal/renderers/index.d.ts +0 -112
  271. package/universal/renderers/index.d.ts.map +0 -1
  272. package/universal/renderers/markdown.renderer.d.ts +0 -33
  273. package/universal/renderers/markdown.renderer.d.ts.map +0 -1
  274. package/universal/renderers/mdx.renderer.d.ts +0 -38
  275. package/universal/renderers/mdx.renderer.d.ts.map +0 -1
  276. package/universal/renderers/react.renderer.d.ts +0 -46
  277. package/universal/renderers/react.renderer.d.ts.map +0 -1
  278. package/universal/runtime-builder.d.ts +0 -33
  279. package/universal/runtime-builder.d.ts.map +0 -1
  280. package/universal/store.d.ts +0 -135
  281. package/universal/store.d.ts.map +0 -1
  282. package/universal/types.d.ts +0 -199
  283. package/universal/types.d.ts.map +0 -1
  284. package/web-components/core/attribute-parser.d.ts +0 -82
  285. package/web-components/core/attribute-parser.d.ts.map +0 -1
  286. package/web-components/core/base-element.d.ts +0 -197
  287. package/web-components/core/base-element.d.ts.map +0 -1
  288. package/web-components/core/index.d.ts +0 -9
  289. package/web-components/core/index.d.ts.map +0 -1
  290. package/web-components/elements/fmcp-alert.d.ts +0 -46
  291. package/web-components/elements/fmcp-alert.d.ts.map +0 -1
  292. package/web-components/elements/fmcp-badge.d.ts +0 -47
  293. package/web-components/elements/fmcp-badge.d.ts.map +0 -1
  294. package/web-components/elements/fmcp-button.d.ts +0 -117
  295. package/web-components/elements/fmcp-button.d.ts.map +0 -1
  296. package/web-components/elements/fmcp-card.d.ts +0 -53
  297. package/web-components/elements/fmcp-card.d.ts.map +0 -1
  298. package/web-components/elements/fmcp-input.d.ts +0 -96
  299. package/web-components/elements/fmcp-input.d.ts.map +0 -1
  300. package/web-components/elements/fmcp-select.d.ts +0 -100
  301. package/web-components/elements/fmcp-select.d.ts.map +0 -1
  302. package/web-components/elements/index.d.ts +0 -13
  303. package/web-components/elements/index.d.ts.map +0 -1
  304. package/web-components/index.d.ts +0 -49
  305. package/web-components/index.d.ts.map +0 -1
  306. package/web-components/index.js +0 -2058
  307. package/web-components/register.d.ts +0 -57
  308. package/web-components/register.d.ts.map +0 -1
  309. package/web-components/types.d.ts +0 -122
  310. package/web-components/types.d.ts.map +0 -1
package/bundler/index.js DELETED
@@ -1,3168 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // libs/ui/src/bundler/index.ts
31
- var bundler_exports = {};
32
- __export(bundler_exports, {
33
- ALL_PLATFORMS: () => ALL_PLATFORMS,
34
- BundlerCache: () => import_bundler4.BundlerCache,
35
- ComponentBuilder: () => import_bundler7.ComponentBuilder,
36
- DEFAULT_BUNDLER_OPTIONS: () => DEFAULT_BUNDLER_OPTIONS,
37
- DEFAULT_BUNDLE_OPTIONS: () => DEFAULT_BUNDLE_OPTIONS,
38
- DEFAULT_SECURITY_POLICY: () => DEFAULT_SECURITY_POLICY,
39
- DEFAULT_STATIC_HTML_OPTIONS: () => DEFAULT_STATIC_HTML_OPTIONS,
40
- DEFAULT_STORAGE_OPTIONS: () => import_bundler7.DEFAULT_STORAGE_OPTIONS,
41
- ExecutionError: () => import_bundler2.ExecutionError,
42
- FilesystemStorage: () => import_bundler7.FilesystemStorage,
43
- HYBRID_DATA_PLACEHOLDER: () => HYBRID_DATA_PLACEHOLDER,
44
- HYBRID_INPUT_PLACEHOLDER: () => HYBRID_INPUT_PLACEHOLDER,
45
- InMemoryBundler: () => InMemoryBundler,
46
- RedisStorage: () => import_bundler7.RedisStorage,
47
- STATIC_HTML_CDN: () => STATIC_HTML_CDN,
48
- SecurityError: () => import_bundler2.SecurityError,
49
- buildIdFromHash: () => import_bundler7.buildIdFromHash,
50
- calculateComponentHash: () => import_bundler7.calculateComponentHash,
51
- calculateManifestSize: () => import_bundler7.calculateManifestSize,
52
- calculateQuickHash: () => import_bundler7.calculateQuickHash,
53
- createBundler: () => createBundler,
54
- createCacheKey: () => import_bundler4.createCacheKey,
55
- createFilesystemBuilder: () => import_bundler7.createFilesystemBuilder,
56
- createFilesystemStorage: () => import_bundler7.createFilesystemStorage,
57
- createRedisBuilder: () => import_bundler7.createRedisBuilder,
58
- createRedisStorage: () => import_bundler7.createRedisStorage,
59
- executeCode: () => import_bundler6.executeCode,
60
- executeDefault: () => import_bundler6.executeDefault,
61
- generateBuildId: () => import_bundler7.generateBuildId,
62
- getCdnTypeForPlatform: () => getCdnTypeForPlatform,
63
- hashContent: () => import_bundler4.hashContent,
64
- hashFile: () => import_bundler7.hashFile,
65
- hashFiles: () => import_bundler7.hashFiles,
66
- isExecutionError: () => import_bundler6.isExecutionError,
67
- mergePolicy: () => import_bundler5.mergePolicy,
68
- sha256: () => import_bundler7.sha256,
69
- sha256Buffer: () => import_bundler7.sha256Buffer,
70
- throwOnViolations: () => import_bundler5.throwOnViolations,
71
- validateImports: () => import_bundler5.validateImports,
72
- validateSize: () => import_bundler5.validateSize,
73
- validateSource: () => import_bundler5.validateSource
74
- });
75
- module.exports = __toCommonJS(bundler_exports);
76
-
77
- // libs/ui/src/bundler/types.ts
78
- var HYBRID_DATA_PLACEHOLDER = "__FRONTMCP_OUTPUT_PLACEHOLDER__";
79
- var HYBRID_INPUT_PLACEHOLDER = "__FRONTMCP_INPUT_PLACEHOLDER__";
80
- var DEFAULT_SECURITY_POLICY = {
81
- allowedImports: [/^react$/, /^react-dom$/, /^react\/jsx-runtime$/, /^react\/jsx-dev-runtime$/, /^@frontmcp\/ui/],
82
- blockedImports: [
83
- /^fs$/,
84
- /^fs\//,
85
- /^net$/,
86
- /^child_process$/,
87
- /^os$/,
88
- /^path$/,
89
- /^crypto$/,
90
- /^http$/,
91
- /^https$/,
92
- /^dgram$/,
93
- /^dns$/,
94
- /^cluster$/,
95
- /^readline$/,
96
- /^repl$/,
97
- /^tls$/,
98
- /^vm$/,
99
- /^worker_threads$/
100
- ],
101
- maxBundleSize: 512e3,
102
- // 500KB
103
- maxTransformTime: 5e3,
104
- // 5s
105
- noEval: true,
106
- noDynamicImports: true,
107
- noRequire: true,
108
- allowedGlobals: [
109
- "console",
110
- "Math",
111
- "JSON",
112
- "Date",
113
- "Array",
114
- "Object",
115
- "String",
116
- "Number",
117
- "Boolean",
118
- "Promise",
119
- "Map",
120
- "Set",
121
- "WeakMap",
122
- "WeakSet",
123
- "Symbol",
124
- "Reflect",
125
- "Proxy",
126
- "Error",
127
- "TypeError",
128
- "RangeError",
129
- "SyntaxError",
130
- "ReferenceError",
131
- "parseInt",
132
- "parseFloat",
133
- "isNaN",
134
- "isFinite",
135
- "encodeURI",
136
- "encodeURIComponent",
137
- "decodeURI",
138
- "decodeURIComponent",
139
- "setTimeout",
140
- "clearTimeout",
141
- "setInterval",
142
- "clearInterval",
143
- "atob",
144
- "btoa",
145
- "Intl",
146
- "TextEncoder",
147
- "TextDecoder",
148
- "URL",
149
- "URLSearchParams",
150
- "Uint8Array",
151
- "Int8Array",
152
- "Uint16Array",
153
- "Int16Array",
154
- "Uint32Array",
155
- "Int32Array",
156
- "Float32Array",
157
- "Float64Array",
158
- "BigInt",
159
- "BigInt64Array",
160
- "BigUint64Array",
161
- "ArrayBuffer",
162
- "SharedArrayBuffer",
163
- "DataView",
164
- "queueMicrotask"
165
- ]
166
- };
167
- var DEFAULT_BUNDLE_OPTIONS = {
168
- sourceType: "auto",
169
- format: "iife",
170
- minify: false,
171
- sourceMaps: false,
172
- externals: ["react", "react-dom"],
173
- jsx: {
174
- runtime: "automatic",
175
- importSource: "react"
176
- },
177
- target: "es2020",
178
- globalName: "Widget",
179
- skipCache: false
180
- };
181
- var DEFAULT_BUNDLER_OPTIONS = {
182
- defaultSecurity: DEFAULT_SECURITY_POLICY,
183
- cache: {
184
- maxSize: 100,
185
- ttl: 3e5,
186
- // 5 minutes
187
- disabled: false
188
- },
189
- verbose: false,
190
- esbuildOptions: {}
191
- };
192
- var ALL_PLATFORMS = [
193
- "openai",
194
- "claude",
195
- "cursor",
196
- "ext-apps",
197
- "generic"
198
- ];
199
- var STATIC_HTML_CDN = {
200
- /**
201
- * ES modules from esm.sh (React 19, modern platforms)
202
- */
203
- esm: {
204
- react: "https://esm.sh/react@19",
205
- reactDom: "https://esm.sh/react-dom@19/client"
206
- },
207
- /**
208
- * UMD builds from cdnjs (React 18.2, Claude only trusts cloudflare)
209
- */
210
- umd: {
211
- react: "https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js",
212
- reactDom: "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"
213
- },
214
- /**
215
- * Font CDN URLs
216
- */
217
- fonts: {
218
- preconnect: ["https://fonts.googleapis.com", "https://fonts.gstatic.com"],
219
- inter: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
220
- }
221
- };
222
- function getCdnTypeForPlatform(platform) {
223
- if (platform === "claude") return "umd";
224
- return "esm";
225
- }
226
- var DEFAULT_STATIC_HTML_OPTIONS = {
227
- sourceType: "auto",
228
- targetPlatform: "auto",
229
- minify: true,
230
- skipCache: false,
231
- rootId: "frontmcp-widget-root",
232
- widgetAccessible: false,
233
- externals: {
234
- react: "cdn",
235
- reactDom: "cdn",
236
- tailwind: "cdn",
237
- frontmcpUi: "inline"
238
- },
239
- // Universal mode defaults
240
- universal: false,
241
- contentType: "auto",
242
- includeMarkdown: false,
243
- includeMdx: false,
244
- // Build mode defaults
245
- buildMode: "static"
246
- };
247
-
248
- // libs/ui/src/bundler/bundler.ts
249
- var import_adapters = require("@frontmcp/uipack/adapters");
250
- var import_theme = require("@frontmcp/uipack/theme");
251
- var import_bundler = require("@frontmcp/uipack/bundler");
252
- var import_utils = require("@frontmcp/uipack/utils");
253
-
254
- // libs/ui/src/universal/types.ts
255
- var UNIVERSAL_CDN = {
256
- esm: {
257
- reactMarkdown: "https://esm.sh/react-markdown@9",
258
- mdxReact: "https://esm.sh/@mdx-js/react@3",
259
- remarkGfm: "https://esm.sh/remark-gfm@4"
260
- }
261
- // Note: These libraries are not available on cdnjs
262
- // For Claude, we use inline implementations
263
- };
264
- function detectContentType(source) {
265
- if (typeof source === "function") {
266
- return "react";
267
- }
268
- if (typeof source !== "string") {
269
- return "html";
270
- }
271
- const hasModuleSyntax = /^import\s+/m.test(source) || /^export\s+(default\s+)?/m.test(source) || /^const\s+\w+\s*=\s*\([^)]*\)\s*=>/m.test(source) || // Arrow function components
272
- /^function\s+\w+\s*\(/m.test(source);
273
- const hasJsxTags = /<[A-Z][a-zA-Z]*/.test(source);
274
- const hasMarkdown = /^#{1,6}\s/m.test(source) || /^\*\s/m.test(source) || /^-\s/m.test(source) || /^\d+\.\s/m.test(source);
275
- if (hasModuleSyntax && hasJsxTags) {
276
- return "react";
277
- }
278
- if (hasJsxTags && hasMarkdown && !hasModuleSyntax) {
279
- return "mdx";
280
- }
281
- if (hasMarkdown || /\*\*[^*]+\*\*/.test(source) || /\[[^\]]+\]\([^)]+\)/.test(source)) {
282
- return "markdown";
283
- }
284
- if (hasJsxTags && !hasModuleSyntax) {
285
- return "mdx";
286
- }
287
- return "html";
288
- }
289
-
290
- // libs/ui/src/universal/cached-runtime.ts
291
- var import_runtime = require("@frontmcp/uipack/runtime");
292
- var import_build = require("@frontmcp/uipack/build");
293
- var RUNTIME_PLACEHOLDERS = {
294
- /** Placeholder for transpiled component code */
295
- COMPONENT_CODE: "/*__FRONTMCP_COMPONENT_CODE__*/",
296
- /** Placeholder for data injection */
297
- DATA_INJECTION: "/*__FRONTMCP_DATA_INJECTION__*/",
298
- /** Placeholder for custom components */
299
- CUSTOM_COMPONENTS: "/*__FRONTMCP_CUSTOM_COMPONENTS__*/"
300
- };
301
- var runtimeCache = /* @__PURE__ */ new Map();
302
- var DEFAULT_CACHE_CONFIG = {
303
- maxEntries: 10,
304
- ttl: 0
305
- // Forever by default
306
- };
307
- function generateCacheKey(options) {
308
- const securityKey = options.contentSecurity ? [
309
- options.contentSecurity.allowUnsafeLinks ? "unsafeLinks" : "",
310
- options.contentSecurity.allowInlineScripts ? "unsafeScripts" : "",
311
- options.contentSecurity.bypassSanitization ? "bypass" : ""
312
- ].filter(Boolean).join("+") || "secure" : "secure";
313
- return [
314
- options.cdnType,
315
- options.includeMarkdown ? "md" : "",
316
- options.includeMdx ? "mdx" : "",
317
- options.minify ? "min" : "",
318
- options.includeBridge ? "bridge" : "",
319
- securityKey
320
- ].filter(Boolean).join(":");
321
- }
322
- function buildStoreRuntime() {
323
- return `
324
- // FrontMCP Store (Vendor)
325
- (function() {
326
- var state = {
327
- toolName: null,
328
- input: null,
329
- output: null,
330
- content: null,
331
- structuredContent: null,
332
- loading: false,
333
- error: null
334
- };
335
-
336
- var listeners = new Set();
337
-
338
- window.__frontmcp = {
339
- getState: function() { return state; },
340
- setState: function(partial) {
341
- state = Object.assign({}, state, partial);
342
- listeners.forEach(function(fn) { fn(); });
343
- },
344
- subscribe: function(fn) {
345
- listeners.add(fn);
346
- return function() { listeners.delete(fn); };
347
- },
348
- reset: function() {
349
- state = {
350
- toolName: null,
351
- input: null,
352
- output: null,
353
- content: null,
354
- structuredContent: null,
355
- loading: false,
356
- error: null
357
- };
358
- },
359
- context: state,
360
- setContext: function(ctx) {
361
- this.setState(ctx);
362
- },
363
- // Dynamic mode: update output and re-render
364
- updateOutput: function(output) {
365
- this.setState({ output: output, loading: false });
366
- // Also update the global window variable for compatibility
367
- window.__mcpToolOutput = output;
368
- },
369
- // Dynamic mode: update input and re-render
370
- updateInput: function(input) {
371
- this.setState({ input: input });
372
- window.__mcpToolInput = input;
373
- }
374
- };
375
-
376
- // React hooks
377
- window.useFrontMCPStore = function() {
378
- var store = window.__frontmcp;
379
- return React.useSyncExternalStore(
380
- store.subscribe,
381
- store.getState,
382
- store.getState
383
- );
384
- };
385
-
386
- window.useToolOutput = function() {
387
- return window.useFrontMCPStore().output;
388
- };
389
-
390
- window.useToolInput = function() {
391
- return window.useFrontMCPStore().input;
392
- };
393
-
394
- window.useContent = function() {
395
- return window.useFrontMCPStore().content;
396
- };
397
-
398
- // Connect to MCP Bridge for platform data detection
399
- function initFromBridge() {
400
- // Check for data from mcpBridge (handles OpenAI, ext-apps, etc.)
401
- if (window.mcpBridge && window.mcpBridge.toolOutput != null) {
402
- window.__frontmcp.setState({
403
- output: window.mcpBridge.toolOutput,
404
- loading: false
405
- });
406
- }
407
-
408
- // Subscribe to bridge updates via onToolResult
409
- if (window.mcpBridge && window.mcpBridge.onToolResult) {
410
- window.mcpBridge.onToolResult(function(result) {
411
- window.__frontmcp.updateOutput(result);
412
- });
413
- }
414
- }
415
-
416
- // Initialize from bridge when ready
417
- if (window.mcpBridge) {
418
- initFromBridge();
419
- } else {
420
- // Wait for bridge to be ready
421
- window.addEventListener('mcp:bridge-ready', initFromBridge);
422
- }
423
- })();
424
- `;
425
- }
426
- function buildRequireShim() {
427
- return `
428
- // Module Require Shim (Vendor)
429
- (function() {
430
- window.__moduleCache = {};
431
- window.require = function(moduleName) {
432
- if (window.__moduleCache[moduleName]) {
433
- return window.__moduleCache[moduleName];
434
- }
435
-
436
- var moduleMap = {
437
- 'react': function() { return window.React; },
438
- 'react-dom': function() { return window.ReactDOM; },
439
- 'react-dom/client': function() { return window.ReactDOM; },
440
- 'react/jsx-runtime': function() { return window.jsx_runtime_namespaceObject; },
441
- 'react/jsx-dev-runtime': function() { return window.jsx_runtime_namespaceObject; },
442
- '@frontmcp/ui': function() { return window.frontmcp_ui_namespaceObject; },
443
- '@frontmcp/ui/react': function() { return window.frontmcp_ui_namespaceObject; }
444
- };
445
-
446
- var resolver = moduleMap[moduleName];
447
- if (resolver) {
448
- var mod = resolver();
449
- window.__moduleCache[moduleName] = mod;
450
- return mod;
451
- }
452
-
453
- console.warn('[FrontMCP] Unknown module:', moduleName);
454
- return {};
455
- };
456
- })();
457
- `;
458
- }
459
- function buildInlineMarkdownParser(options) {
460
- const allowUnsafeLinks = options?.contentSecurity?.bypassSanitization || options?.contentSecurity?.allowUnsafeLinks;
461
- return `
462
- // Inline Markdown Parser (Vendor)
463
- (function() {
464
- // XSS protection settings (configured at build time)
465
- // Set to true if contentSecurity.allowUnsafeLinks or bypassSanitization is enabled
466
- var __allowUnsafeLinks = ${allowUnsafeLinks ? "true" : "false"};
467
-
468
- // URL scheme validation to prevent XSS via javascript: URLs
469
- function isSafeUrl(url) {
470
- // If unsafe links are explicitly allowed, skip validation
471
- if (__allowUnsafeLinks) return true;
472
- if (!url) return false;
473
- var lower = url.toLowerCase().trim();
474
- return lower.startsWith('http://') ||
475
- lower.startsWith('https://') ||
476
- lower.startsWith('/') ||
477
- lower.startsWith('#') ||
478
- lower.startsWith('mailto:');
479
- }
480
-
481
- function parseMarkdown(md) {
482
- var html = md;
483
- html = html.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
484
- html = html.replace(/^######\\s+(.*)$/gm, '<h6>$1</h6>');
485
- html = html.replace(/^#####\\s+(.*)$/gm, '<h5>$1</h5>');
486
- html = html.replace(/^####\\s+(.*)$/gm, '<h4>$1</h4>');
487
- html = html.replace(/^###\\s+(.*)$/gm, '<h3>$1</h3>');
488
- html = html.replace(/^##\\s+(.*)$/gm, '<h2>$1</h2>');
489
- html = html.replace(/^#\\s+(.*)$/gm, '<h1>$1</h1>');
490
- html = html.replace(/\\*\\*\\*(.+?)\\*\\*\\*/g, '<strong><em>$1</em></strong>');
491
- html = html.replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>');
492
- html = html.replace(/\\*(.+?)\\*/g, '<em>$1</em>');
493
- html = html.replace(/\`([^\`]+)\`/g, '<code>$1</code>');
494
- // Links - validate URL scheme to prevent XSS (unless bypassed)
495
- html = html.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, function(match, text, url) {
496
- return isSafeUrl(url) ? '<a href="' + url + '">' + text + '</a>' : text;
497
- });
498
- html = html.replace(/^[-*]\\s+(.*)$/gm, '<li>$1</li>');
499
- html = html.replace(/\\n\\n+/g, '</p><p>');
500
- html = '<p>' + html + '</p>';
501
- return html;
502
- }
503
-
504
- window.__frontmcp.parseMarkdown = parseMarkdown;
505
-
506
- window.ReactMarkdown = function(props) {
507
- var html = parseMarkdown(props.children || '');
508
- return React.createElement('div', {
509
- className: 'frontmcp-markdown prose',
510
- dangerouslySetInnerHTML: { __html: html }
511
- });
512
- };
513
- })();
514
- `;
515
- }
516
- function buildRenderersRuntime(options) {
517
- const bypassSanitization = options?.contentSecurity?.bypassSanitization;
518
- const allowInlineScripts = bypassSanitization || options?.contentSecurity?.allowInlineScripts;
519
- return `
520
- // Universal Renderers (Vendor)
521
- (function() {
522
- var renderers = {};
523
-
524
- // XSS protection settings (configured at build time)
525
- // Set to true if contentSecurity.allowInlineScripts or bypassSanitization is enabled
526
- var __allowInlineScripts = ${allowInlineScripts ? "true" : "false"};
527
-
528
- renderers.html = {
529
- type: 'html',
530
- priority: 0,
531
- canHandle: function(c) { return c.type === 'html'; },
532
- render: function(c, ctx) {
533
- var html = c.source;
534
- // Apply XSS protection unless bypassed
535
- if (!__allowInlineScripts) {
536
- // Remove script tags and event handlers to prevent XSS
537
- html = html.replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, '');
538
- html = html.replace(/\\s+on\\w+\\s*=/gi, ' data-removed-handler=');
539
- }
540
- return React.createElement('div', {
541
- className: 'frontmcp-html-content',
542
- dangerouslySetInnerHTML: { __html: html }
543
- });
544
- }
545
- };
546
-
547
- renderers.markdown = {
548
- type: 'markdown',
549
- priority: 10,
550
- canHandle: function(c) {
551
- if (c.type === 'markdown') return true;
552
- if (typeof c.source !== 'string') return false;
553
- var s = c.source;
554
- return /^#{1,6}\\s/m.test(s) || /^[-*]\\s/m.test(s) || /\\*\\*[^*]+\\*\\*/.test(s);
555
- },
556
- render: function(c, ctx) {
557
- if (window.ReactMarkdown) {
558
- return React.createElement(window.ReactMarkdown, {
559
- children: c.source,
560
- components: Object.assign({}, ctx.components, c.components)
561
- });
562
- }
563
- var html = window.__frontmcp.parseMarkdown ? window.__frontmcp.parseMarkdown(c.source) : c.source;
564
- return React.createElement('div', {
565
- className: 'frontmcp-markdown prose',
566
- dangerouslySetInnerHTML: { __html: html }
567
- });
568
- }
569
- };
570
-
571
- renderers.react = {
572
- type: 'react',
573
- priority: 30,
574
- canHandle: function(c) { return c.type === 'react' || typeof c.source === 'function'; },
575
- render: function(c, ctx) {
576
- var Component = c.source;
577
- var props = Object.assign({
578
- output: ctx.output,
579
- input: ctx.input,
580
- state: ctx.state,
581
- data: ctx.output // Alias for convenience
582
- }, c.props);
583
- return React.createElement(Component, props);
584
- }
585
- };
586
-
587
- renderers.mdx = {
588
- type: 'mdx',
589
- priority: 20,
590
- canHandle: function(c) {
591
- if (c.type === 'mdx') return true;
592
- if (typeof c.source !== 'string') return false;
593
- var s = c.source;
594
- return /<[A-Z][a-zA-Z]*/.test(s) && /^#{1,6}\\s/m.test(s);
595
- },
596
- render: function(c, ctx) {
597
- if (typeof c.compiledContent === 'function') {
598
- var MDXContent = c.compiledContent;
599
- return React.createElement(MDXContent, {
600
- output: ctx.output,
601
- input: ctx.input,
602
- components: Object.assign({}, ctx.components, c.components)
603
- });
604
- }
605
- return React.createElement('div', { className: 'frontmcp-mdx-fallback' }, [
606
- React.createElement('div', {
607
- key: 'warn',
608
- className: 'bg-yellow-50 border border-yellow-200 rounded p-2 mb-2 text-sm text-yellow-800'
609
- }, 'MDX requires pre-compilation. Showing raw content.'),
610
- React.createElement('pre', {
611
- key: 'pre',
612
- className: 'bg-gray-100 p-4 rounded text-sm overflow-auto'
613
- }, c.source)
614
- ]);
615
- }
616
- };
617
-
618
- var sortedRenderers = [renderers.react, renderers.mdx, renderers.markdown, renderers.html];
619
-
620
- window.__frontmcp.detectRenderer = function(content) {
621
- if (content.type && renderers[content.type]) {
622
- return renderers[content.type];
623
- }
624
- for (var i = 0; i < sortedRenderers.length; i++) {
625
- if (sortedRenderers[i].canHandle(content)) {
626
- return sortedRenderers[i];
627
- }
628
- }
629
- return renderers.html;
630
- };
631
-
632
- window.__frontmcp.renderContent = function(content, context) {
633
- var renderer = window.__frontmcp.detectRenderer(content);
634
- return renderer.render(content, context);
635
- };
636
-
637
- window.__frontmcp.renderers = renderers;
638
- })();
639
- `;
640
- }
641
- function buildUIComponentsRuntime() {
642
- return (0, import_build.buildUIComponentsRuntime)();
643
- }
644
- function buildUniversalAppRuntime() {
645
- return `
646
- // Universal App (Vendor)
647
- (function() {
648
- var LoadingSpinner = function() {
649
- return React.createElement('div', {
650
- className: 'frontmcp-loading flex items-center justify-center min-h-[200px]'
651
- }, React.createElement('div', {
652
- className: 'frontmcp-spinner w-6 h-6 border-2 border-gray-200 border-t-blue-500 rounded-full animate-spin'
653
- }));
654
- };
655
-
656
- var ErrorDisplay = function(props) {
657
- return React.createElement('div', {
658
- className: 'frontmcp-error bg-red-50 border border-red-200 rounded-lg p-4 text-red-800'
659
- }, [
660
- React.createElement('div', { key: 'title', className: 'font-medium' }, 'Error'),
661
- React.createElement('div', { key: 'msg', className: 'text-sm mt-1' }, props.error)
662
- ]);
663
- };
664
-
665
- var EmptyState = function() {
666
- return React.createElement('div', {
667
- className: 'frontmcp-empty text-gray-500 text-center py-8'
668
- }, 'No content to display');
669
- };
670
-
671
- window.__frontmcp.UniversalApp = function(props) {
672
- var state = window.useFrontMCPStore();
673
-
674
- if (state.loading) {
675
- return props.fallback || React.createElement(LoadingSpinner);
676
- }
677
-
678
- if (state.error) {
679
- var ErrorComp = props.errorFallback || ErrorDisplay;
680
- return React.createElement(ErrorComp, { error: state.error });
681
- }
682
-
683
- var content = props.content || state.content;
684
-
685
- if (!content) {
686
- return React.createElement(EmptyState);
687
- }
688
-
689
- var context = {
690
- output: state.output,
691
- input: state.input,
692
- state: state,
693
- components: props.components || {}
694
- };
695
-
696
- var rendered = window.__frontmcp.renderContent(content, context);
697
- return React.createElement('div', { className: 'frontmcp-content' }, rendered);
698
- };
699
-
700
- window.__frontmcp.LoadingSpinner = LoadingSpinner;
701
- window.__frontmcp.ErrorDisplay = ErrorDisplay;
702
- window.__frontmcp.EmptyState = EmptyState;
703
- })();
704
- `;
705
- }
706
- function buildComponentWrapper() {
707
- return `
708
- // Component Execution (App Chunk)
709
- (function() {
710
- ${RUNTIME_PLACEHOLDERS.COMPONENT_CODE}
711
- })();
712
- `;
713
- }
714
- function buildDataInjectionWrapper() {
715
- return `
716
- // Data Injection (App Chunk)
717
- (function() {
718
- ${RUNTIME_PLACEHOLDERS.DATA_INJECTION}
719
- })();
720
- `;
721
- }
722
- function buildCustomComponentsWrapper() {
723
- return `
724
- // Custom Components (App Chunk)
725
- (function() {
726
- ${RUNTIME_PLACEHOLDERS.CUSTOM_COMPONENTS}
727
- })();
728
- `;
729
- }
730
- function buildCdnImports(options) {
731
- const parts = [];
732
- if (options.cdnType === "esm") {
733
- if (options.includeMarkdown) {
734
- parts.push(`
735
- <script type="module">
736
- import ReactMarkdown from '${UNIVERSAL_CDN.esm.reactMarkdown}';
737
- window.ReactMarkdown = ReactMarkdown;
738
- </script>`);
739
- }
740
- if (options.includeMdx) {
741
- parts.push(`
742
- <script type="module">
743
- import { MDXProvider } from '${UNIVERSAL_CDN.esm.mdxReact}';
744
- window.MDXProvider = MDXProvider;
745
- </script>`);
746
- }
747
- }
748
- return parts.join("\n");
749
- }
750
- function getCachedRuntime(options, config = {}) {
751
- const cacheKey = generateCacheKey(options);
752
- const cacheConfig = { ...DEFAULT_CACHE_CONFIG, ...config };
753
- const cached = runtimeCache.get(cacheKey);
754
- if (cached) {
755
- if (cacheConfig.ttl === 0 || Date.now() - cached.cachedAt < cacheConfig.ttl) {
756
- return {
757
- vendorScript: cached.script,
758
- appTemplate: buildAppTemplate(),
759
- cdnImports: cached.cdnImports,
760
- vendorSize: cached.size,
761
- cached: true,
762
- cacheKey
763
- };
764
- }
765
- runtimeCache.delete(cacheKey);
766
- }
767
- const vendorParts = [];
768
- if (options.includeBridge) {
769
- vendorParts.push((0, import_runtime.getMCPBridgeScript)());
770
- }
771
- vendorParts.push(buildStoreRuntime(), buildRequireShim());
772
- if (options.cdnType === "umd" || options.includeMarkdown) {
773
- vendorParts.push(buildInlineMarkdownParser(options));
774
- }
775
- vendorParts.push(buildRenderersRuntime(options));
776
- vendorParts.push(buildUIComponentsRuntime());
777
- vendorParts.push(buildUniversalAppRuntime());
778
- let vendorScript = vendorParts.join("\n");
779
- if (options.minify) {
780
- vendorScript = minifyScript(vendorScript);
781
- }
782
- const cdnImports = buildCdnImports(options);
783
- const entry = {
784
- script: vendorScript,
785
- cdnImports,
786
- size: vendorScript.length,
787
- cacheKey,
788
- cachedAt: Date.now()
789
- };
790
- if (runtimeCache.size >= cacheConfig.maxEntries) {
791
- const oldestKey = runtimeCache.keys().next().value;
792
- if (oldestKey) {
793
- runtimeCache.delete(oldestKey);
794
- }
795
- }
796
- runtimeCache.set(cacheKey, entry);
797
- return {
798
- vendorScript,
799
- appTemplate: buildAppTemplate(),
800
- cdnImports,
801
- vendorSize: vendorScript.length,
802
- cached: false,
803
- cacheKey
804
- };
805
- }
806
- function buildAppTemplate() {
807
- return [buildCustomComponentsWrapper(), buildComponentWrapper(), buildDataInjectionWrapper()].join("\n");
808
- }
809
- function minifyScript(script) {
810
- return script.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/[^\n]*$/gm, "").replace(/\n\s*\n/g, "\n").replace(/^\s+/gm, "").trim();
811
- }
812
- function buildAppScript(appTemplate, componentCode, dataInjection, customComponents = "") {
813
- return appTemplate.replace(RUNTIME_PLACEHOLDERS.CUSTOM_COMPONENTS, customComponents || "// No custom components").replace(RUNTIME_PLACEHOLDERS.COMPONENT_CODE, componentCode || "// No component code").replace(RUNTIME_PLACEHOLDERS.DATA_INJECTION, dataInjection);
814
- }
815
- var DEFAULT_OUTPUT_PLACEHOLDER = "__FRONTMCP_OUTPUT_PLACEHOLDER__";
816
- var DEFAULT_INPUT_PLACEHOLDER = "__FRONTMCP_INPUT_PLACEHOLDER__";
817
- function buildDataInjectionCode(toolName, input, output, structuredContent, contentType, source, hasComponent, options) {
818
- const buildMode = options?.buildMode ?? "static";
819
- const cdnType = options?.cdnType ?? "esm";
820
- switch (buildMode) {
821
- case "dynamic":
822
- return buildDynamicDataInjectionCode(
823
- toolName,
824
- input,
825
- output,
826
- structuredContent,
827
- contentType,
828
- source,
829
- hasComponent,
830
- cdnType,
831
- options?.dynamicOptions
832
- );
833
- case "hybrid":
834
- return buildHybridDataInjectionCode(
835
- toolName,
836
- structuredContent,
837
- contentType,
838
- source,
839
- hasComponent,
840
- options?.hybridOptions
841
- );
842
- default:
843
- return buildStaticDataInjectionCode(
844
- toolName,
845
- input,
846
- output,
847
- structuredContent,
848
- contentType,
849
- source,
850
- hasComponent
851
- );
852
- }
853
- }
854
- function buildStaticDataInjectionCode(toolName, input, output, structuredContent, contentType, source, hasComponent) {
855
- const safeJson = (value) => {
856
- try {
857
- return JSON.stringify(value);
858
- } catch {
859
- return "null";
860
- }
861
- };
862
- if (hasComponent) {
863
- return `
864
- // Static Mode - Data baked at build time
865
- window.__frontmcp.setState({
866
- toolName: ${safeJson(toolName)},
867
- input: ${safeJson(input ?? null)},
868
- output: ${safeJson(output ?? null)},
869
- structuredContent: ${safeJson(structuredContent ?? null)},
870
- content: {
871
- type: 'react',
872
- source: window.__frontmcp_component
873
- },
874
- loading: false,
875
- error: null
876
- });`;
877
- }
878
- return `
879
- // Static Mode - Data baked at build time
880
- window.__frontmcp.setState({
881
- toolName: ${safeJson(toolName)},
882
- input: ${safeJson(input ?? null)},
883
- output: ${safeJson(output ?? null)},
884
- structuredContent: ${safeJson(structuredContent ?? null)},
885
- content: {
886
- type: ${safeJson(contentType)},
887
- source: ${safeJson(source)}
888
- },
889
- loading: false,
890
- error: null
891
- });`;
892
- }
893
- function buildDynamicDataInjectionCode(toolName, input, output, structuredContent, contentType, source, hasComponent, cdnType, dynamicOptions) {
894
- if (cdnType === "umd") {
895
- return buildDynamicWithPlaceholdersCode(
896
- toolName,
897
- structuredContent,
898
- contentType,
899
- source,
900
- hasComponent,
901
- dynamicOptions
902
- );
903
- }
904
- return buildDynamicWithSubscriptionCode(
905
- toolName,
906
- input,
907
- output,
908
- structuredContent,
909
- contentType,
910
- source,
911
- hasComponent,
912
- dynamicOptions
913
- );
914
- }
915
- function buildDynamicWithPlaceholdersCode(toolName, structuredContent, contentType, source, hasComponent, dynamicOptions) {
916
- const safeJson = (value) => {
917
- try {
918
- return JSON.stringify(value);
919
- } catch {
920
- return "null";
921
- }
922
- };
923
- const outputPlaceholder = DEFAULT_OUTPUT_PLACEHOLDER;
924
- const inputPlaceholder = DEFAULT_INPUT_PLACEHOLDER;
925
- const includeInitialData = dynamicOptions?.includeInitialData ?? true;
926
- const contentBlock = hasComponent ? `content: { type: 'react', source: window.__frontmcp_component }` : `content: { type: ${safeJson(contentType)}, source: ${safeJson(source)} }`;
927
- return `
928
- // Dynamic Mode - Placeholder-based for non-OpenAI platforms
929
- var __outputRaw = "${outputPlaceholder}";
930
- var __inputRaw = "${inputPlaceholder}";
931
- var __output = null;
932
- var __input = null;
933
- var __error = null;
934
- var __outputNotReplaced = false;
935
- var __includeInitialData = ${includeInitialData};
936
-
937
- // Parse output placeholder
938
- if (typeof __outputRaw === 'string' && __outputRaw !== "${outputPlaceholder}") {
939
- try { __output = JSON.parse(__outputRaw); } catch (e) {
940
- console.warn('[FrontMCP] Failed to parse output:', e);
941
- __error = 'Failed to parse output data';
942
- }
943
- } else if (__outputRaw === "${outputPlaceholder}") {
944
- __outputNotReplaced = true;
945
- }
946
-
947
- // Parse input placeholder
948
- if (typeof __inputRaw === 'string' && __inputRaw !== "${inputPlaceholder}") {
949
- try { __input = JSON.parse(__inputRaw); } catch (e) { console.warn('[FrontMCP] Failed to parse input:', e); }
950
- }
951
-
952
- // Handle placeholder not replaced - show error if expecting initial data
953
- if (__outputNotReplaced && __includeInitialData) {
954
- __error = 'No data provided. The output placeholder was not replaced.';
955
- }
956
-
957
- window.__frontmcp.setState({
958
- toolName: ${safeJson(toolName)},
959
- input: __input,
960
- output: __output,
961
- structuredContent: ${safeJson(structuredContent ?? null)},
962
- ${contentBlock},
963
- loading: !__includeInitialData && __output === null && !__error,
964
- error: __error
965
- });`;
966
- }
967
- function buildDynamicWithSubscriptionCode(toolName, input, output, structuredContent, contentType, source, hasComponent, dynamicOptions) {
968
- const safeJson = (value) => {
969
- try {
970
- return JSON.stringify(value);
971
- } catch {
972
- return "null";
973
- }
974
- };
975
- const includeInitialData = dynamicOptions?.includeInitialData ?? true;
976
- const subscribeToUpdates = dynamicOptions?.subscribeToUpdates ?? true;
977
- const contentBlock = hasComponent ? `content: { type: 'react', source: window.__frontmcp_component }` : `content: { type: ${safeJson(contentType)}, source: ${safeJson(source)} }`;
978
- const initialState = includeInitialData ? `{
979
- toolName: ${safeJson(toolName)},
980
- input: ${safeJson(input ?? null)},
981
- output: ${safeJson(output ?? null)},
982
- structuredContent: ${safeJson(structuredContent ?? null)},
983
- ${contentBlock},
984
- loading: false,
985
- error: null
986
- }` : `{
987
- toolName: ${safeJson(toolName)},
988
- input: ${safeJson(input ?? null)},
989
- output: null,
990
- structuredContent: ${safeJson(structuredContent ?? null)},
991
- ${contentBlock},
992
- loading: true,
993
- error: null
994
- }`;
995
- const subscriptionBlock = subscribeToUpdates ? `
996
- // Subscribe to platform tool result events
997
- (function() {
998
- function subscribeToUpdates() {
999
- if (window.openai && window.openai.canvas && window.openai.canvas.onToolResult) {
1000
- window.openai.canvas.onToolResult(function(result) {
1001
- window.__frontmcp.updateOutput(result);
1002
- window.dispatchEvent(new CustomEvent('frontmcp:toolResult', { detail: result }));
1003
- });
1004
- }
1005
- }
1006
- if (document.readyState === 'loading') {
1007
- document.addEventListener('DOMContentLoaded', subscribeToUpdates);
1008
- } else {
1009
- subscribeToUpdates();
1010
- }
1011
- })();` : "";
1012
- return `
1013
- // Dynamic Mode - OpenAI Subscription
1014
- window.__frontmcp.setState(${initialState});
1015
- ${subscriptionBlock}`;
1016
- }
1017
- function buildHybridDataInjectionCode(toolName, structuredContent, contentType, source, hasComponent, hybridOptions) {
1018
- const safeJson = (value) => {
1019
- try {
1020
- return JSON.stringify(value);
1021
- } catch {
1022
- return "null";
1023
- }
1024
- };
1025
- const outputPlaceholder = hybridOptions?.placeholder ?? DEFAULT_OUTPUT_PLACEHOLDER;
1026
- const inputPlaceholder = hybridOptions?.inputPlaceholder ?? DEFAULT_INPUT_PLACEHOLDER;
1027
- const contentBlock = hasComponent ? `content: { type: 'react', source: window.__frontmcp_component }` : `content: { type: ${safeJson(contentType)}, source: ${safeJson(source)} }`;
1028
- return `
1029
- // Hybrid Mode - Placeholders replaced at runtime
1030
- var __outputRaw = "${outputPlaceholder}";
1031
- var __inputRaw = "${inputPlaceholder}";
1032
- var __output = null;
1033
- var __input = null;
1034
- var __error = null;
1035
- var __outputNotReplaced = false;
1036
-
1037
- // Parse output placeholder
1038
- if (typeof __outputRaw === 'string' && __outputRaw !== "${outputPlaceholder}") {
1039
- try { __output = JSON.parse(__outputRaw); } catch (e) {
1040
- console.warn('[FrontMCP] Failed to parse output:', e);
1041
- __error = 'Failed to parse output data';
1042
- }
1043
- } else if (__outputRaw === "${outputPlaceholder}") {
1044
- // Placeholder not replaced - no data was injected
1045
- __outputNotReplaced = true;
1046
- }
1047
-
1048
- // Parse input placeholder
1049
- if (typeof __inputRaw === 'string' && __inputRaw !== "${inputPlaceholder}") {
1050
- try { __input = JSON.parse(__inputRaw); } catch (e) { console.warn('[FrontMCP] Failed to parse input:', e); }
1051
- }
1052
-
1053
- // Set error if output placeholder was not replaced (no data provided)
1054
- if (__outputNotReplaced) {
1055
- __error = 'No data provided. The output placeholder was not replaced.';
1056
- }
1057
-
1058
- window.__frontmcp.setState({
1059
- toolName: ${safeJson(toolName)},
1060
- input: __input,
1061
- output: __output,
1062
- structuredContent: ${safeJson(structuredContent ?? null)},
1063
- ${contentBlock},
1064
- loading: false,
1065
- error: __error
1066
- });`;
1067
- }
1068
- function buildComponentCode(transpiledCode) {
1069
- return `
1070
- // CommonJS module shim
1071
- var module = { exports: {} };
1072
- var exports = module.exports;
1073
-
1074
- // Execute transpiled component
1075
- ${transpiledCode}
1076
-
1077
- // Capture component
1078
- window.__frontmcp_component = module.exports.default || module.exports;`;
1079
- }
1080
-
1081
- // libs/ui/src/bundler/bundler.ts
1082
- var import_build2 = require("@frontmcp/uipack/build");
1083
-
1084
- // libs/ui/src/bundler/browser-components.ts
1085
- var path = __toESM(require("path"));
1086
- var cachedBrowserComponents = null;
1087
- var buildingPromise = null;
1088
- function getComponentsEntrySource() {
1089
- return `
1090
- // Browser Components Entry Point
1091
- // This gets transpiled by esbuild to create browser-compatible code
1092
-
1093
- import {
1094
- // Card styles
1095
- CARD_VARIANTS,
1096
- CARD_SIZES,
1097
- // Button styles
1098
- BUTTON_VARIANTS,
1099
- BUTTON_SIZES,
1100
- BUTTON_ICON_SIZES,
1101
- BUTTON_BASE_CLASSES,
1102
- LOADING_SPINNER,
1103
- // Badge styles
1104
- BADGE_VARIANTS,
1105
- BADGE_SIZES,
1106
- BADGE_DOT_SIZES,
1107
- BADGE_DOT_VARIANTS,
1108
- // Alert styles
1109
- ALERT_VARIANTS,
1110
- ALERT_BASE_CLASSES,
1111
- ALERT_ICONS,
1112
- CLOSE_ICON,
1113
- // Utility
1114
- cn,
1115
- } from '@frontmcp/uipack/styles';
1116
-
1117
- // Re-export for the IIFE
1118
- export {
1119
- CARD_VARIANTS,
1120
- CARD_SIZES,
1121
- BUTTON_VARIANTS,
1122
- BUTTON_SIZES,
1123
- BUTTON_ICON_SIZES,
1124
- BUTTON_BASE_CLASSES,
1125
- LOADING_SPINNER,
1126
- BADGE_VARIANTS,
1127
- BADGE_SIZES,
1128
- BADGE_DOT_SIZES,
1129
- BADGE_DOT_VARIANTS,
1130
- ALERT_VARIANTS,
1131
- ALERT_BASE_CLASSES,
1132
- ALERT_ICONS,
1133
- CLOSE_ICON,
1134
- cn,
1135
- };
1136
-
1137
- // Card Component
1138
- export function Card(props: any) {
1139
- const {
1140
- title,
1141
- subtitle,
1142
- headerActions,
1143
- footer,
1144
- variant = 'default',
1145
- size = 'md',
1146
- className,
1147
- id,
1148
- clickable,
1149
- href,
1150
- children,
1151
- } = props;
1152
-
1153
- const variantClasses = CARD_VARIANTS[variant] || CARD_VARIANTS.default;
1154
- const sizeClasses = CARD_SIZES[size] || CARD_SIZES.md;
1155
- const clickableClasses = clickable ? 'cursor-pointer hover:shadow-md transition-shadow' : '';
1156
- const allClasses = cn(variantClasses, sizeClasses, clickableClasses, className);
1157
-
1158
- const hasHeader = title || subtitle || headerActions;
1159
-
1160
- const headerElement = hasHeader ? React.createElement('div', {
1161
- className: 'flex items-start justify-between mb-4'
1162
- }, [
1163
- React.createElement('div', { key: 'titles' }, [
1164
- title && React.createElement('h3', {
1165
- key: 'title',
1166
- className: 'text-lg font-semibold text-text-primary'
1167
- }, title),
1168
- subtitle && React.createElement('p', {
1169
- key: 'subtitle',
1170
- className: 'text-sm text-text-secondary mt-1'
1171
- }, subtitle)
1172
- ]),
1173
- headerActions && React.createElement('div', {
1174
- key: 'actions',
1175
- className: 'flex items-center gap-2'
1176
- }, headerActions)
1177
- ]) : null;
1178
-
1179
- const footerElement = footer ? React.createElement('div', {
1180
- className: 'mt-4 pt-4 border-t border-divider'
1181
- }, footer) : null;
1182
-
1183
- const content = React.createElement(React.Fragment, null, headerElement, children, footerElement);
1184
-
1185
- if (href) {
1186
- return React.createElement('a', { href, className: allClasses, id }, content);
1187
- }
1188
-
1189
- return React.createElement('div', { className: allClasses, id }, content);
1190
- }
1191
-
1192
- // Button Component
1193
- export function Button(props: any) {
1194
- const {
1195
- variant = 'primary',
1196
- size = 'md',
1197
- disabled = false,
1198
- loading = false,
1199
- fullWidth = false,
1200
- iconPosition = 'left',
1201
- icon,
1202
- iconOnly = false,
1203
- type = 'button',
1204
- className,
1205
- onClick,
1206
- children,
1207
- } = props;
1208
-
1209
- const variantClasses = BUTTON_VARIANTS[variant] || BUTTON_VARIANTS.primary;
1210
- const sizeClasses = iconOnly
1211
- ? (BUTTON_ICON_SIZES[size] || BUTTON_ICON_SIZES.md)
1212
- : (BUTTON_SIZES[size] || BUTTON_SIZES.md);
1213
-
1214
- const disabledClasses = (disabled || loading) ? 'opacity-50 cursor-not-allowed' : '';
1215
- const widthClasses = fullWidth ? 'w-full' : '';
1216
-
1217
- const allClasses = cn(BUTTON_BASE_CLASSES, variantClasses, sizeClasses, disabledClasses, widthClasses, className);
1218
-
1219
- const iconElement = icon ? React.createElement('span', {
1220
- className: iconPosition === 'left' ? 'mr-2' : 'ml-2'
1221
- }, icon) : null;
1222
-
1223
- const loadingSpinner = loading ? React.createElement('span', {
1224
- className: 'mr-2',
1225
- dangerouslySetInnerHTML: { __html: LOADING_SPINNER }
1226
- }) : null;
1227
-
1228
- return React.createElement('button', {
1229
- type,
1230
- className: allClasses,
1231
- disabled: disabled || loading,
1232
- onClick
1233
- },
1234
- loadingSpinner,
1235
- !loading && icon && iconPosition === 'left' ? iconElement : null,
1236
- !iconOnly ? children : null,
1237
- !loading && icon && iconPosition === 'right' ? iconElement : null
1238
- );
1239
- }
1240
-
1241
- // Badge Component
1242
- export function Badge(props: any) {
1243
- const {
1244
- variant = 'default',
1245
- size = 'md',
1246
- pill = false,
1247
- icon,
1248
- dot = false,
1249
- className,
1250
- removable = false,
1251
- onRemove,
1252
- children,
1253
- } = props;
1254
-
1255
- // Handle dot badge
1256
- if (dot) {
1257
- const dotSizeClasses = BADGE_DOT_SIZES[size] || BADGE_DOT_SIZES.md;
1258
- const dotVariantClasses = BADGE_DOT_VARIANTS[variant] || BADGE_DOT_VARIANTS.default;
1259
- const dotClasses = cn('inline-block rounded-full', dotSizeClasses, dotVariantClasses, className);
1260
- const label = typeof children === 'string' ? children : undefined;
1261
- return React.createElement('span', {
1262
- className: dotClasses,
1263
- 'aria-label': label,
1264
- title: label
1265
- });
1266
- }
1267
-
1268
- const variantClasses = BADGE_VARIANTS[variant] || BADGE_VARIANTS.default;
1269
- const sizeClasses = BADGE_SIZES[size] || BADGE_SIZES.md;
1270
-
1271
- const baseClasses = cn(
1272
- 'inline-flex items-center font-medium',
1273
- pill ? 'rounded-full' : 'rounded-md',
1274
- variantClasses,
1275
- sizeClasses,
1276
- className
1277
- );
1278
-
1279
- const closeButton = removable ? React.createElement('button', {
1280
- type: 'button',
1281
- className: 'ml-1.5 -mr-1 hover:opacity-70 transition-opacity',
1282
- 'aria-label': 'Remove',
1283
- onClick: onRemove
1284
- }, React.createElement('svg', {
1285
- className: 'w-3 h-3',
1286
- fill: 'none',
1287
- stroke: 'currentColor',
1288
- viewBox: '0 0 24 24'
1289
- }, React.createElement('path', {
1290
- strokeLinecap: 'round',
1291
- strokeLinejoin: 'round',
1292
- strokeWidth: '2',
1293
- d: 'M6 18L18 6M6 6l12 12'
1294
- }))) : null;
1295
-
1296
- return React.createElement('span', { className: baseClasses },
1297
- icon ? React.createElement('span', { className: 'mr-1' }, icon) : null,
1298
- children,
1299
- closeButton
1300
- );
1301
- }
1302
-
1303
- // Alert Component
1304
- export function Alert(props: any) {
1305
- const {
1306
- variant = 'info',
1307
- title,
1308
- icon,
1309
- showIcon = true,
1310
- dismissible = false,
1311
- onDismiss,
1312
- className,
1313
- children,
1314
- } = props;
1315
-
1316
- const variantStyles = ALERT_VARIANTS[variant] || ALERT_VARIANTS.info;
1317
- const allClasses = cn(ALERT_BASE_CLASSES, variantStyles.container, className);
1318
-
1319
- const iconContent = icon || (showIcon ? React.createElement('span', {
1320
- className: cn('flex-shrink-0', variantStyles.icon),
1321
- dangerouslySetInnerHTML: { __html: ALERT_ICONS[variant] || ALERT_ICONS.info }
1322
- }) : null);
1323
-
1324
- const dismissButton = dismissible ? React.createElement('button', {
1325
- type: 'button',
1326
- className: 'flex-shrink-0 ml-3 hover:opacity-70 transition-opacity',
1327
- 'aria-label': 'Dismiss',
1328
- onClick: onDismiss
1329
- }, React.createElement('span', {
1330
- dangerouslySetInnerHTML: { __html: CLOSE_ICON }
1331
- })) : null;
1332
-
1333
- return React.createElement('div', { className: allClasses, role: 'alert' },
1334
- React.createElement('div', { className: 'flex' },
1335
- iconContent ? React.createElement('div', { className: 'flex-shrink-0 mr-3' }, iconContent) : null,
1336
- React.createElement('div', { className: 'flex-1' },
1337
- title ? React.createElement('h4', { className: 'font-semibold mb-1' }, title) : null,
1338
- React.createElement('div', { className: 'text-sm' }, children)
1339
- ),
1340
- dismissButton
1341
- )
1342
- );
1343
- }
1344
- `;
1345
- }
1346
- function getBrowserRuntimeWrapper() {
1347
- return `
1348
- // Assign components to window for require() shim
1349
- window.Card = Card;
1350
- window.Button = Button;
1351
- window.Badge = Badge;
1352
- window.Alert = Alert;
1353
-
1354
- // Build the namespace object for @frontmcp/ui/react imports
1355
- window.frontmcp_ui_namespaceObject = Object.assign({}, window.React || {}, {
1356
- // Hooks
1357
- useToolOutput: window.useToolOutput,
1358
- useToolInput: window.useToolInput,
1359
- useMcpBridgeContext: function() { return window.__frontmcp.context; },
1360
- useMcpBridge: function() { return window.__frontmcp.context; },
1361
- useCallTool: function() {
1362
- return function(name, args) {
1363
- if (window.__frontmcp.context && window.__frontmcp.context.callTool) {
1364
- return window.__frontmcp.context.callTool(name, args);
1365
- }
1366
- console.warn('[FrontMCP] callTool not available');
1367
- return Promise.resolve(null);
1368
- };
1369
- },
1370
- useTheme: function() { return window.__frontmcp.theme || 'light'; },
1371
- useDisplayMode: function() { return window.__frontmcp.displayMode || 'embedded'; },
1372
- useHostContext: function() { return window.__frontmcp.hostContext || {}; },
1373
- useCapability: function(cap) { return window.__frontmcp.capabilities && window.__frontmcp.capabilities[cap] || false; },
1374
- useStructuredContent: function() { return window.__frontmcp.getState().structuredContent; },
1375
- useToolCalls: function() { return []; },
1376
- useSendMessage: function() { return function() { return Promise.resolve(); }; },
1377
- useOpenLink: function() { return function() {}; },
1378
-
1379
- // Components
1380
- Card: window.Card,
1381
- Badge: window.Badge,
1382
- Button: window.Button,
1383
- Alert: window.Alert,
1384
-
1385
- // Re-export React for convenience
1386
- createElement: React.createElement,
1387
- Fragment: React.Fragment,
1388
- useState: React.useState,
1389
- useEffect: React.useEffect,
1390
- useCallback: React.useCallback,
1391
- useMemo: React.useMemo,
1392
- useRef: React.useRef,
1393
- useContext: React.useContext
1394
- });
1395
- `;
1396
- }
1397
- async function buildWithEsbuild() {
1398
- try {
1399
- const esbuild = await import("esbuild");
1400
- const stylesPath = require.resolve("@frontmcp/uipack/styles");
1401
- const entrySource = getComponentsEntrySource();
1402
- const result = await esbuild.build({
1403
- stdin: {
1404
- contents: entrySource,
1405
- loader: "tsx",
1406
- resolveDir: path.dirname(stylesPath)
1407
- },
1408
- bundle: true,
1409
- format: "iife",
1410
- globalName: "__frontmcp_components",
1411
- target: "es2020",
1412
- minify: false,
1413
- write: false,
1414
- external: ["react", "react-dom"],
1415
- define: {
1416
- React: "window.React"
1417
- },
1418
- platform: "browser"
1419
- });
1420
- if (result.outputFiles && result.outputFiles.length > 0) {
1421
- let code = result.outputFiles[0].text;
1422
- code += "\n" + getBrowserRuntimeWrapper();
1423
- return code;
1424
- }
1425
- throw new Error("No output from esbuild");
1426
- } catch (error) {
1427
- console.warn(
1428
- `[FrontMCP] esbuild bundle failed, falling back to manual components: ${error instanceof Error ? error.message : String(error)}`
1429
- );
1430
- throw error;
1431
- }
1432
- }
1433
- async function getBrowserComponents() {
1434
- if (cachedBrowserComponents !== null) {
1435
- return cachedBrowserComponents;
1436
- }
1437
- if (buildingPromise !== null) {
1438
- return buildingPromise;
1439
- }
1440
- buildingPromise = buildWithEsbuild().then((code) => {
1441
- cachedBrowserComponents = code;
1442
- buildingPromise = null;
1443
- return code;
1444
- }).catch((error) => {
1445
- buildingPromise = null;
1446
- throw error;
1447
- });
1448
- return buildingPromise;
1449
- }
1450
-
1451
- // libs/ui/src/bundler/bundler.ts
1452
- var import_bundler2 = require("@frontmcp/uipack/bundler");
1453
- var esbuildTransform = null;
1454
- async function loadEsbuild() {
1455
- if (esbuildTransform !== null) {
1456
- return esbuildTransform;
1457
- }
1458
- try {
1459
- const esbuild = await import("esbuild");
1460
- esbuildTransform = esbuild.transform;
1461
- return esbuildTransform;
1462
- } catch {
1463
- try {
1464
- const swc = await import("@swc/core");
1465
- esbuildTransform = async (source, options) => {
1466
- const opts = options;
1467
- const result = await swc.transform(source, {
1468
- jsc: {
1469
- parser: {
1470
- syntax: "typescript",
1471
- tsx: opts.loader === "tsx" || opts.loader === "jsx"
1472
- },
1473
- transform: {
1474
- react: {
1475
- runtime: "automatic",
1476
- development: false
1477
- }
1478
- },
1479
- target: "es2020",
1480
- minify: opts.minify ? { compress: true, mangle: true } : void 0
1481
- },
1482
- module: {
1483
- type: "commonjs"
1484
- },
1485
- sourceMaps: opts.sourcemap ? true : false
1486
- });
1487
- return { code: result.code, map: result.map };
1488
- };
1489
- return esbuildTransform;
1490
- } catch {
1491
- console.warn(
1492
- "[@frontmcp/ui/bundler] Neither esbuild nor @swc/core available. Install esbuild for best performance: npm install esbuild"
1493
- );
1494
- return null;
1495
- }
1496
- }
1497
- }
1498
- function sanitizeRootId(rootId) {
1499
- const safeId = rootId.replace(/[^a-zA-Z0-9_-]/g, "");
1500
- if (safeId !== rootId) {
1501
- console.warn("[FrontMCP] rootId sanitized:", { original: rootId, sanitized: safeId });
1502
- }
1503
- return safeId || "frontmcp-root";
1504
- }
1505
- function sanitizeCss(css) {
1506
- return css.replace(/<\/style>/gi, "\\3c/style\\3e");
1507
- }
1508
- var InMemoryBundler = class {
1509
- cache;
1510
- options;
1511
- defaultSecurity;
1512
- constructor(options = {}) {
1513
- this.options = {
1514
- ...DEFAULT_BUNDLER_OPTIONS,
1515
- ...options,
1516
- cache: {
1517
- ...DEFAULT_BUNDLER_OPTIONS.cache,
1518
- ...options.cache
1519
- }
1520
- };
1521
- this.cache = new import_bundler.BundlerCache({
1522
- maxSize: this.options.cache.maxSize,
1523
- ttl: this.options.cache.ttl
1524
- });
1525
- this.defaultSecurity = (0, import_bundler.mergePolicy)(options.defaultSecurity);
1526
- }
1527
- /**
1528
- * Bundle source code.
1529
- *
1530
- * @param options - Bundle options
1531
- * @returns Bundle result
1532
- */
1533
- async bundle(options) {
1534
- const startTime = performance.now();
1535
- const opts = this.mergeOptions(options);
1536
- if (!opts.skipCache && !this.options.cache.disabled) {
1537
- const cacheKey = options.cacheKey ?? (0, import_bundler.createCacheKey)(options.source, opts);
1538
- const cached = this.cache.get(cacheKey);
1539
- if (cached) {
1540
- return {
1541
- ...cached,
1542
- cached: true,
1543
- metrics: {
1544
- ...cached.metrics,
1545
- cacheTime: performance.now() - startTime
1546
- }
1547
- };
1548
- }
1549
- }
1550
- const security = (0, import_bundler.mergePolicy)(options.security ?? this.defaultSecurity);
1551
- const violations = (0, import_bundler.validateSource)(options.source, security);
1552
- (0, import_bundler.throwOnViolations)(violations);
1553
- const sourceType = opts.sourceType === "auto" ? this.detectSourceType(options.source) : opts.sourceType;
1554
- const transformStart = performance.now();
1555
- const transformed = await this.transform(options.source, sourceType, opts);
1556
- const transformTime = performance.now() - transformStart;
1557
- const sizeViolation = (0, import_bundler.validateSize)(transformed.code.length, security);
1558
- if (sizeViolation) {
1559
- (0, import_bundler.throwOnViolations)([sizeViolation]);
1560
- }
1561
- const hash = (0, import_bundler.hashContent)(transformed.code);
1562
- const result = {
1563
- code: transformed.code,
1564
- hash,
1565
- cached: false,
1566
- size: transformed.code.length,
1567
- map: transformed.map,
1568
- metrics: {
1569
- transformTime,
1570
- bundleTime: 0,
1571
- // No separate bundle step for transform-only
1572
- totalTime: performance.now() - startTime
1573
- },
1574
- sourceType,
1575
- format: opts.format
1576
- };
1577
- if (!this.options.cache.disabled) {
1578
- const cacheKey = options.cacheKey ?? (0, import_bundler.createCacheKey)(options.source, opts);
1579
- this.cache.set(cacheKey, result);
1580
- }
1581
- return result;
1582
- }
1583
- /**
1584
- * Bundle and execute for SSR.
1585
- *
1586
- * @param options - SSR bundle options
1587
- * @returns SSR result with rendered HTML
1588
- */
1589
- async bundleSSR(options) {
1590
- const startTime = performance.now();
1591
- const bundleResult = await this.bundle({
1592
- ...options,
1593
- format: "cjs"
1594
- // CommonJS for execution
1595
- });
1596
- let React;
1597
- let ReactDOMServer;
1598
- try {
1599
- React = await import("react");
1600
- ReactDOMServer = await import("react-dom/server");
1601
- } catch {
1602
- throw new Error("React and react-dom/server are required for SSR. Install them: npm install react react-dom");
1603
- }
1604
- const renderStart = performance.now();
1605
- const Component = await (0, import_bundler.executeDefault)(bundleResult.code, {
1606
- React,
1607
- security: (0, import_bundler.mergePolicy)(options.security ?? this.defaultSecurity)
1608
- });
1609
- let html;
1610
- try {
1611
- const element = React.createElement(Component, options.context ?? {});
1612
- html = ReactDOMServer.renderToString(element);
1613
- } catch (error) {
1614
- throw new import_bundler.ExecutionError(
1615
- `SSR rendering failed: ${error instanceof Error ? error.message : String(error)}`,
1616
- error
1617
- );
1618
- }
1619
- const renderTime = performance.now() - renderStart;
1620
- let hydrationScript;
1621
- if (options.includeHydration) {
1622
- hydrationScript = this.buildHydrationScript(bundleResult.code, options.context);
1623
- }
1624
- return {
1625
- ...bundleResult,
1626
- html,
1627
- hydrationScript,
1628
- metrics: {
1629
- ...bundleResult.metrics,
1630
- totalTime: performance.now() - startTime
1631
- },
1632
- ssrMetrics: {
1633
- renderTime
1634
- }
1635
- };
1636
- }
1637
- /**
1638
- * Bundle and execute code, returning the exports.
1639
- *
1640
- * @param options - Bundle options
1641
- * @param context - Execution context
1642
- * @returns Exported value
1643
- */
1644
- async bundleAndExecute(options, context) {
1645
- const result = await this.bundle({
1646
- ...options,
1647
- format: "cjs"
1648
- // CommonJS for execution
1649
- });
1650
- let React;
1651
- try {
1652
- React = await import("react");
1653
- } catch {
1654
- }
1655
- return (0, import_bundler.executeDefault)(result.code, {
1656
- React,
1657
- globals: context,
1658
- security: (0, import_bundler.mergePolicy)(options.security ?? this.defaultSecurity)
1659
- });
1660
- }
1661
- /**
1662
- * Bundle a component to a self-contained static HTML document.
1663
- *
1664
- * Creates a complete HTML page with:
1665
- * - React runtime (CDN or inline based on platform)
1666
- * - FrontMCP UI hooks and components (always inline)
1667
- * - Tool data injection (input/output)
1668
- * - Transpiled component code
1669
- * - Client-side rendering via createRoot
1670
- *
1671
- * @param options - Static HTML options
1672
- * @returns Static HTML result with complete document
1673
- *
1674
- * @example
1675
- * ```typescript
1676
- * const result = await bundler.bundleToStaticHTML({
1677
- * source: `
1678
- * import { Card, useToolOutput } from '@frontmcp/ui/react';
1679
- * export default function Weather() {
1680
- * const output = useToolOutput();
1681
- * return <Card title="Weather">{output?.temperature}°F</Card>;
1682
- * }
1683
- * `,
1684
- * toolName: 'get_weather',
1685
- * output: { temperature: 72 },
1686
- * });
1687
- *
1688
- * // result.html contains the complete HTML document
1689
- * ```
1690
- */
1691
- async bundleToStaticHTML(options) {
1692
- const startTime = performance.now();
1693
- const opts = this.mergeStaticHTMLOptions(options);
1694
- const platform = opts.targetPlatform === "auto" ? "generic" : opts.targetPlatform;
1695
- const cdnType = getCdnTypeForPlatform(platform);
1696
- if (opts.universal) {
1697
- return this.bundleToStaticHTMLUniversal(options, opts, platform, cdnType, startTime);
1698
- }
1699
- const bundleResult = await this.bundle({
1700
- source: options.source,
1701
- sourceType: opts.sourceType,
1702
- format: "cjs",
1703
- minify: opts.minify,
1704
- sourceMaps: false,
1705
- externals: ["react", "react-dom", "react/jsx-runtime", "@frontmcp/ui", "@frontmcp/ui/react"],
1706
- security: opts.security,
1707
- skipCache: opts.skipCache
1708
- });
1709
- const head = this.buildStaticHTMLHead({ externals: opts.externals, customCss: opts.customCss, theme: opts.theme });
1710
- const reactRuntime = this.buildReactRuntimeScripts(opts.externals, platform, cdnType);
1711
- const frontmcpRuntime = await this.buildFrontMCPRuntime();
1712
- const dataScript = this.buildDataInjectionScript(
1713
- opts.toolName,
1714
- opts.input,
1715
- opts.output,
1716
- opts.structuredContent,
1717
- opts.buildMode,
1718
- cdnType,
1719
- opts.dynamicOptions,
1720
- opts.hybridOptions
1721
- );
1722
- const componentScript = this.buildComponentRenderScript(bundleResult.code, opts.rootId, cdnType);
1723
- const html = this.assembleStaticHTML({
1724
- title: opts.title || `${opts.toolName} - Widget`,
1725
- head,
1726
- reactRuntime,
1727
- frontmcpRuntime,
1728
- dataScript,
1729
- componentScript,
1730
- rootId: opts.rootId,
1731
- cdnType
1732
- });
1733
- const hash = (0, import_bundler.hashContent)(html);
1734
- const dataPlaceholder = opts.buildMode === "hybrid" ? opts.hybridOptions?.placeholder ?? HYBRID_DATA_PLACEHOLDER : void 0;
1735
- const inputPlaceholder = opts.buildMode === "hybrid" ? opts.hybridOptions?.inputPlaceholder ?? HYBRID_INPUT_PLACEHOLDER : void 0;
1736
- return {
1737
- html,
1738
- componentCode: bundleResult.code,
1739
- metrics: {
1740
- ...bundleResult.metrics,
1741
- totalTime: performance.now() - startTime
1742
- },
1743
- hash,
1744
- size: html.length,
1745
- cached: bundleResult.cached,
1746
- sourceType: bundleResult.sourceType,
1747
- targetPlatform: platform,
1748
- buildMode: opts.buildMode,
1749
- dataPlaceholder,
1750
- inputPlaceholder
1751
- };
1752
- }
1753
- /**
1754
- * Bundle a component to static HTML for all target platforms at once.
1755
- *
1756
- * This method is optimized for efficiency:
1757
- * - Transpiles the component source code only once
1758
- * - Generates platform-specific HTML variations from the shared transpiled code
1759
- * - Returns complete platform metadata ready for MCP responses
1760
- *
1761
- * @param options - Multi-platform build options
1762
- * @returns Multi-platform build result with all platforms
1763
- *
1764
- * @example
1765
- * ```typescript
1766
- * const result = await bundler.bundleToStaticHTMLAll({
1767
- * source: `
1768
- * import { Card, useToolOutput } from '@frontmcp/ui/react';
1769
- * export default function Weather() {
1770
- * const output = useToolOutput();
1771
- * return <Card title="Weather">{output?.temperature}°F</Card>;
1772
- * }
1773
- * `,
1774
- * toolName: 'get_weather',
1775
- * output: { temperature: 72 },
1776
- * });
1777
- *
1778
- * // Access platform-specific results
1779
- * const openaiHtml = result.platforms.openai.html;
1780
- * const claudeHtml = result.platforms.claude.html;
1781
- *
1782
- * // Get metadata for MCP response
1783
- * const openaiMeta = result.platforms.openai.meta;
1784
- * ```
1785
- */
1786
- async bundleToStaticHTMLAll(options) {
1787
- const startTime = performance.now();
1788
- const opts = this.mergeStaticHTMLOptions(options);
1789
- const platforms = options.platforms ?? [...ALL_PLATFORMS];
1790
- const transpileStart = performance.now();
1791
- let transpiledCode = null;
1792
- let bundleResult = null;
1793
- const isUniversal = opts.universal;
1794
- const rawContentType = options.contentType ?? "auto";
1795
- const contentType = isUniversal ? rawContentType === "auto" ? detectContentType(options.source) : rawContentType : "react";
1796
- if (contentType === "react" || !isUniversal) {
1797
- bundleResult = await this.bundle({
1798
- source: options.source,
1799
- sourceType: opts.sourceType,
1800
- format: "cjs",
1801
- minify: opts.minify,
1802
- sourceMaps: false,
1803
- externals: ["react", "react-dom", "react/jsx-runtime", "@frontmcp/ui", "@frontmcp/ui/react"],
1804
- security: opts.security,
1805
- skipCache: opts.skipCache
1806
- });
1807
- transpiledCode = bundleResult.code;
1808
- }
1809
- const transpileTime = performance.now() - transpileStart;
1810
- const generationStart = performance.now();
1811
- const platformResults = {};
1812
- for (const platform of platforms) {
1813
- const platformResult = await this.buildForPlatform({
1814
- options,
1815
- opts,
1816
- platform,
1817
- transpiledCode,
1818
- bundleResult,
1819
- contentType,
1820
- isUniversal
1821
- });
1822
- platformResults[platform] = platformResult;
1823
- }
1824
- const generationTime = performance.now() - generationStart;
1825
- return {
1826
- platforms: platformResults,
1827
- sharedComponentCode: transpiledCode ?? "",
1828
- metrics: {
1829
- transpileTime,
1830
- generationTime,
1831
- totalTime: performance.now() - startTime
1832
- },
1833
- cached: bundleResult?.cached ?? false
1834
- };
1835
- }
1836
- /**
1837
- * Build for a specific platform with pre-transpiled code.
1838
- * Internal helper for bundleToStaticHTMLAll.
1839
- */
1840
- async buildForPlatform(params) {
1841
- const { options, opts, platform, transpiledCode, bundleResult, contentType, isUniversal } = params;
1842
- const cdnType = getCdnTypeForPlatform(platform);
1843
- const buildStart = performance.now();
1844
- let html;
1845
- let componentCode;
1846
- if (isUniversal) {
1847
- const shouldIncludeBridge = opts.buildMode === "dynamic" || opts.buildMode === "hybrid";
1848
- const cachedRuntime = getCachedRuntime({
1849
- cdnType,
1850
- includeMarkdown: opts.includeMarkdown || contentType === "markdown",
1851
- includeMdx: opts.includeMdx || contentType === "mdx",
1852
- minify: opts.minify,
1853
- includeBridge: shouldIncludeBridge
1854
- });
1855
- const componentCodeStr = transpiledCode ? buildComponentCode(transpiledCode) : "";
1856
- const dataInjectionStr = buildDataInjectionCode(
1857
- opts.toolName,
1858
- opts.input,
1859
- opts.output,
1860
- opts.structuredContent,
1861
- contentType,
1862
- transpiledCode ? null : options.source,
1863
- transpiledCode !== null,
1864
- {
1865
- buildMode: opts.buildMode,
1866
- cdnType,
1867
- dynamicOptions: opts.dynamicOptions,
1868
- hybridOptions: opts.hybridOptions
1869
- }
1870
- );
1871
- const appScript = buildAppScript(
1872
- cachedRuntime.appTemplate,
1873
- componentCodeStr,
1874
- dataInjectionStr,
1875
- opts.customComponents ?? ""
1876
- );
1877
- const head = this.buildStaticHTMLHead({
1878
- externals: opts.externals,
1879
- customCss: opts.customCss,
1880
- theme: opts.theme
1881
- });
1882
- const reactRuntime = this.buildReactRuntimeScripts(opts.externals, platform, cdnType);
1883
- const renderScript = this.buildUniversalRenderScript(opts.rootId, cdnType);
1884
- html = this.assembleUniversalStaticHTMLCached({
1885
- title: opts.title || `${opts.toolName} - Widget`,
1886
- head,
1887
- reactRuntime,
1888
- cdnImports: cachedRuntime.cdnImports,
1889
- vendorScript: cachedRuntime.vendorScript,
1890
- appScript,
1891
- renderScript,
1892
- rootId: opts.rootId,
1893
- cdnType
1894
- });
1895
- componentCode = transpiledCode ?? appScript;
1896
- } else {
1897
- if (!transpiledCode) {
1898
- throw new Error("Failed to transpile component source");
1899
- }
1900
- const head = this.buildStaticHTMLHead({
1901
- externals: opts.externals,
1902
- customCss: opts.customCss,
1903
- theme: opts.theme
1904
- });
1905
- const reactRuntime = this.buildReactRuntimeScripts(opts.externals, platform, cdnType);
1906
- const frontmcpRuntime = await this.buildFrontMCPRuntime();
1907
- const dataScript = this.buildDataInjectionScript(
1908
- opts.toolName,
1909
- opts.input,
1910
- opts.output,
1911
- opts.structuredContent,
1912
- opts.buildMode,
1913
- cdnType,
1914
- opts.dynamicOptions,
1915
- opts.hybridOptions
1916
- );
1917
- const componentScript = this.buildComponentRenderScript(transpiledCode, opts.rootId, cdnType);
1918
- html = this.assembleStaticHTML({
1919
- title: opts.title || `${opts.toolName} - Widget`,
1920
- head,
1921
- reactRuntime,
1922
- frontmcpRuntime,
1923
- dataScript,
1924
- componentScript,
1925
- rootId: opts.rootId,
1926
- cdnType
1927
- });
1928
- componentCode = transpiledCode;
1929
- }
1930
- const hash = (0, import_bundler.hashContent)(html);
1931
- const meta = (0, import_adapters.buildUIMeta)({
1932
- uiConfig: {
1933
- template: () => html,
1934
- widgetAccessible: opts.widgetAccessible
1935
- },
1936
- platformType: this.mapTargetPlatformToAIPlatform(platform),
1937
- html
1938
- });
1939
- const dataPlaceholder = opts.buildMode === "hybrid" ? opts.hybridOptions?.placeholder ?? HYBRID_DATA_PLACEHOLDER : void 0;
1940
- const inputPlaceholder = opts.buildMode === "hybrid" ? opts.hybridOptions?.inputPlaceholder ?? HYBRID_INPUT_PLACEHOLDER : void 0;
1941
- return {
1942
- html,
1943
- componentCode,
1944
- metrics: bundleResult?.metrics ?? {
1945
- transformTime: 0,
1946
- bundleTime: 0,
1947
- totalTime: performance.now() - buildStart
1948
- },
1949
- hash,
1950
- size: html.length,
1951
- cached: bundleResult?.cached ?? false,
1952
- sourceType: bundleResult?.sourceType ?? opts.sourceType,
1953
- targetPlatform: platform,
1954
- universal: isUniversal,
1955
- contentType: isUniversal ? contentType : void 0,
1956
- buildMode: opts.buildMode,
1957
- dataPlaceholder,
1958
- inputPlaceholder,
1959
- meta
1960
- };
1961
- }
1962
- /**
1963
- * Map TargetPlatform to AIPlatformType for metadata generation.
1964
- */
1965
- mapTargetPlatformToAIPlatform(platform) {
1966
- switch (platform) {
1967
- case "openai":
1968
- return "openai";
1969
- case "claude":
1970
- return "claude";
1971
- case "cursor":
1972
- return "cursor";
1973
- case "ext-apps":
1974
- return "ext-apps";
1975
- case "generic":
1976
- return "generic-mcp";
1977
- default:
1978
- return "generic-mcp";
1979
- }
1980
- }
1981
- /**
1982
- * Bundle to static HTML with universal rendering mode.
1983
- * Uses the universal renderer that can handle multiple content types.
1984
- *
1985
- * Optimization: Uses cached runtime (vendor chunk) to avoid rebuilding
1986
- * static code on every request. Only the user's component is transpiled.
1987
- */
1988
- async bundleToStaticHTMLUniversal(options, opts, platform, cdnType, startTime) {
1989
- let contentType;
1990
- const rawContentType = options.contentType ?? "auto";
1991
- if (rawContentType === "auto") {
1992
- contentType = detectContentType(options.source);
1993
- } else {
1994
- contentType = rawContentType;
1995
- }
1996
- let transpiledCode = null;
1997
- let transformTime = 0;
1998
- if (contentType === "react") {
1999
- const bundleResult = await this.bundle({
2000
- source: options.source,
2001
- sourceType: opts.sourceType,
2002
- format: "cjs",
2003
- minify: opts.minify,
2004
- sourceMaps: false,
2005
- externals: ["react", "react-dom", "react/jsx-runtime", "@frontmcp/ui", "@frontmcp/ui/react"],
2006
- security: opts.security,
2007
- skipCache: opts.skipCache
2008
- });
2009
- transpiledCode = bundleResult.code;
2010
- transformTime = bundleResult.metrics.transformTime;
2011
- }
2012
- const shouldIncludeBridge = opts.buildMode === "dynamic" || opts.buildMode === "hybrid";
2013
- const cachedRuntime = getCachedRuntime({
2014
- cdnType,
2015
- includeMarkdown: opts.includeMarkdown || contentType === "markdown",
2016
- includeMdx: opts.includeMdx || contentType === "mdx",
2017
- minify: opts.minify,
2018
- includeBridge: shouldIncludeBridge
2019
- });
2020
- const componentCodeStr = transpiledCode ? buildComponentCode(transpiledCode) : "";
2021
- const dataInjectionStr = buildDataInjectionCode(
2022
- opts.toolName,
2023
- opts.input,
2024
- opts.output,
2025
- opts.structuredContent,
2026
- contentType,
2027
- transpiledCode ? null : options.source,
2028
- // Pass source only if not a component
2029
- transpiledCode !== null,
2030
- {
2031
- buildMode: opts.buildMode,
2032
- cdnType,
2033
- dynamicOptions: opts.dynamicOptions,
2034
- hybridOptions: opts.hybridOptions
2035
- }
2036
- );
2037
- const appScript = buildAppScript(
2038
- cachedRuntime.appTemplate,
2039
- componentCodeStr,
2040
- dataInjectionStr,
2041
- opts.customComponents ?? ""
2042
- );
2043
- const head = this.buildStaticHTMLHead({ externals: opts.externals, customCss: opts.customCss, theme: opts.theme });
2044
- const reactRuntime = this.buildReactRuntimeScripts(opts.externals, platform, cdnType);
2045
- const renderScript = this.buildUniversalRenderScript(opts.rootId, cdnType);
2046
- const html = this.assembleUniversalStaticHTMLCached({
2047
- title: opts.title || `${opts.toolName} - Widget`,
2048
- head,
2049
- reactRuntime,
2050
- cdnImports: cachedRuntime.cdnImports,
2051
- vendorScript: cachedRuntime.vendorScript,
2052
- appScript,
2053
- renderScript,
2054
- rootId: opts.rootId,
2055
- cdnType
2056
- });
2057
- const hash = (0, import_bundler.hashContent)(html);
2058
- return {
2059
- html,
2060
- componentCode: transpiledCode ?? appScript,
2061
- metrics: {
2062
- transformTime,
2063
- bundleTime: 0,
2064
- totalTime: performance.now() - startTime,
2065
- cacheTime: cachedRuntime.cached ? 0 : void 0
2066
- },
2067
- hash,
2068
- size: html.length,
2069
- cached: cachedRuntime.cached,
2070
- sourceType: opts.sourceType === "auto" ? this.detectSourceType(options.source) : opts.sourceType,
2071
- targetPlatform: platform,
2072
- universal: true,
2073
- contentType
2074
- };
2075
- }
2076
- /**
2077
- * Assemble the complete universal static HTML document using cached runtime.
2078
- *
2079
- * For ESM mode (OpenAI), scripts must wait for React to load asynchronously.
2080
- * For UMD mode (Claude), scripts can execute synchronously.
2081
- */
2082
- assembleUniversalStaticHTMLCached(parts) {
2083
- if (parts.cdnType === "umd") {
2084
- return `<!DOCTYPE html>
2085
- <html lang="en">
2086
- <head>
2087
- <title>${(0, import_utils.escapeHtml)(parts.title)}</title>
2088
- ${parts.head}
2089
- ${parts.reactRuntime}
2090
- ${parts.cdnImports}
2091
- <!-- Vendor Runtime (Cached) -->
2092
- <script>
2093
- ${parts.vendorScript}
2094
- </script>
2095
- <!-- App Script (User Component) -->
2096
- <script>
2097
- ${parts.appScript}
2098
- </script>
2099
- </head>
2100
- <body>
2101
- <div id="${parts.rootId}" class="frontmcp-loading">
2102
- <div class="frontmcp-spinner"></div>
2103
- </div>
2104
- ${parts.renderScript}
2105
- </body>
2106
- </html>`;
2107
- } else {
2108
- return `<!DOCTYPE html>
2109
- <html lang="en">
2110
- <head>
2111
- <title>${(0, import_utils.escapeHtml)(parts.title)}</title>
2112
- ${parts.head}
2113
- ${parts.reactRuntime}
2114
- ${parts.cdnImports}
2115
- </head>
2116
- <body>
2117
- <div id="${parts.rootId}" class="frontmcp-loading">
2118
- <div class="frontmcp-spinner"></div>
2119
- </div>
2120
- <!-- Scripts wait for React to load (ESM is async) -->
2121
- <script type="module">
2122
- // Wait for React to be ready
2123
- function initFrontMCP() {
2124
- // Vendor Runtime (Cached)
2125
- ${parts.vendorScript}
2126
-
2127
- // App Script (User Component)
2128
- ${parts.appScript}
2129
-
2130
- // Render the app
2131
- var container = document.getElementById('${parts.rootId}');
2132
- if (container && window.ReactDOM && window.ReactDOM.createRoot && window.__frontmcp.UniversalApp) {
2133
- var root = window.ReactDOM.createRoot(container);
2134
- root.render(React.createElement(window.__frontmcp.UniversalApp));
2135
- }
2136
- }
2137
-
2138
- if (window.__reactReady) {
2139
- initFrontMCP();
2140
- } else {
2141
- window.addEventListener('react:ready', initFrontMCP);
2142
- }
2143
- </script>
2144
- </body>
2145
- </html>`;
2146
- }
2147
- }
2148
- /**
2149
- * Build the component script for transpiled React/MDX content.
2150
- * Wraps CommonJS code with module/exports shim to capture the component.
2151
- */
2152
- buildUniversalComponentScript(transpiledCode, cdnType) {
2153
- const wrappedCode = `
2154
- // CommonJS module shim
2155
- var module = { exports: {} };
2156
- var exports = module.exports;
2157
-
2158
- // Execute transpiled component code (CommonJS format)
2159
- ${transpiledCode}
2160
-
2161
- // Capture the component export
2162
- window.__frontmcp_component = module.exports.default || module.exports;
2163
- `;
2164
- if (cdnType === "umd") {
2165
- return `
2166
- <!-- Universal Component Script (transpiled) -->
2167
- <script>
2168
- (function() {
2169
- ${wrappedCode}
2170
- })();
2171
- </script>`;
2172
- } else {
2173
- return `
2174
- <!-- Universal Component Script (transpiled, ESM) -->
2175
- <script type="module">
2176
- function loadComponent() {
2177
- ${wrappedCode}
2178
- }
2179
-
2180
- if (window.__reactReady) {
2181
- loadComponent();
2182
- } else {
2183
- window.addEventListener('react:ready', loadComponent);
2184
- }
2185
- </script>`;
2186
- }
2187
- }
2188
- /**
2189
- * Build the universal runtime script section.
2190
- */
2191
- buildUniversalRuntimeScript(runtimeScript) {
2192
- return `
2193
- <!-- Universal Runtime -->
2194
- <script>
2195
- ${runtimeScript}
2196
- </script>`;
2197
- }
2198
- /**
2199
- * Build data injection script for universal mode.
2200
- */
2201
- buildUniversalDataScript(toolName, input, output, structuredContent, contentType, source, hasTranspiledComponent = false) {
2202
- const safeJson = (value) => {
2203
- try {
2204
- return JSON.stringify(value);
2205
- } catch {
2206
- return "null";
2207
- }
2208
- };
2209
- if (hasTranspiledComponent) {
2210
- return `
2211
- <!-- Universal Data Injection (React Component) -->
2212
- <script>
2213
- window.__frontmcp.setState({
2214
- toolName: ${safeJson(toolName)},
2215
- input: ${safeJson(input ?? null)},
2216
- output: ${safeJson(output ?? null)},
2217
- structuredContent: ${safeJson(structuredContent ?? null)},
2218
- content: {
2219
- type: 'react',
2220
- source: window.__frontmcp_component
2221
- },
2222
- loading: false,
2223
- error: null
2224
- });
2225
- </script>`;
2226
- }
2227
- const escapedSource = JSON.stringify(source);
2228
- return `
2229
- <!-- Universal Data Injection -->
2230
- <script>
2231
- window.__frontmcp.setState({
2232
- toolName: ${safeJson(toolName)},
2233
- input: ${safeJson(input ?? null)},
2234
- output: ${safeJson(output ?? null)},
2235
- structuredContent: ${safeJson(structuredContent ?? null)},
2236
- content: {
2237
- type: ${safeJson(contentType)},
2238
- source: ${escapedSource}
2239
- },
2240
- loading: false,
2241
- error: null
2242
- });
2243
- </script>`;
2244
- }
2245
- /**
2246
- * Build the universal render script.
2247
- */
2248
- buildUniversalRenderScript(rootId, cdnType) {
2249
- if (cdnType === "umd") {
2250
- return `
2251
- <!-- Universal Render Script (UMD - synchronous) -->
2252
- <script>
2253
- (function() {
2254
- var container = document.getElementById('${rootId}');
2255
- if (container && window.ReactDOM && window.ReactDOM.createRoot && window.__frontmcp.UniversalApp) {
2256
- var root = window.ReactDOM.createRoot(container);
2257
- root.render(React.createElement(window.__frontmcp.UniversalApp));
2258
- } else if (container && window.ReactDOM && window.ReactDOM.render && window.__frontmcp.UniversalApp) {
2259
- window.ReactDOM.render(
2260
- React.createElement(window.__frontmcp.UniversalApp),
2261
- container
2262
- );
2263
- }
2264
- })();
2265
- </script>`;
2266
- } else {
2267
- return `
2268
- <!-- Universal Render Script (ESM - waits for React) -->
2269
- <script type="module">
2270
- function renderUniversalApp() {
2271
- var container = document.getElementById('${rootId}');
2272
- if (container && window.ReactDOM && window.ReactDOM.createRoot && window.__frontmcp.UniversalApp) {
2273
- var root = window.ReactDOM.createRoot(container);
2274
- root.render(React.createElement(window.__frontmcp.UniversalApp));
2275
- }
2276
- }
2277
-
2278
- if (window.__reactReady) {
2279
- renderUniversalApp();
2280
- } else {
2281
- window.addEventListener('react:ready', renderUniversalApp);
2282
- }
2283
- </script>`;
2284
- }
2285
- }
2286
- /**
2287
- * Assemble the complete universal static HTML document.
2288
- */
2289
- assembleUniversalStaticHTML(parts) {
2290
- return `<!DOCTYPE html>
2291
- <html lang="en">
2292
- <head>
2293
- <title>${(0, import_utils.escapeHtml)(parts.title)}</title>
2294
- ${parts.head}
2295
- ${parts.reactRuntime}
2296
- ${parts.frontmcpRuntime ?? ""}
2297
- ${parts.cdnImports}
2298
- ${parts.universalRuntimeScript}
2299
- ${parts.componentScript ?? ""}
2300
- ${parts.dataScript}
2301
- </head>
2302
- <body>
2303
- <div id="${parts.rootId}" class="frontmcp-loading">
2304
- <div class="frontmcp-spinner"></div>
2305
- </div>
2306
- ${parts.renderScript}
2307
- </body>
2308
- </html>`;
2309
- }
2310
- /**
2311
- * Get cache statistics.
2312
- */
2313
- getCacheStats() {
2314
- return this.cache.getStats();
2315
- }
2316
- /**
2317
- * Clear the cache.
2318
- */
2319
- clearCache() {
2320
- this.cache.clear();
2321
- }
2322
- /**
2323
- * Clean up expired cache entries.
2324
- */
2325
- cleanupCache() {
2326
- return this.cache.cleanup();
2327
- }
2328
- /**
2329
- * Transform source code using esbuild/SWC.
2330
- */
2331
- async transform(source, sourceType, options) {
2332
- const transform = await loadEsbuild();
2333
- if (!transform) {
2334
- throw new Error("No bundler available. Install esbuild or @swc/core: npm install esbuild");
2335
- }
2336
- const loader = this.getLoader(sourceType);
2337
- const esbuildOptions = {
2338
- loader,
2339
- minify: options.minify,
2340
- sourcemap: options.sourceMaps,
2341
- target: options.target,
2342
- format: options.format === "cjs" ? "cjs" : options.format === "esm" ? "esm" : "iife",
2343
- jsx: "automatic",
2344
- jsxImportSource: options.jsx.importSource
2345
- };
2346
- try {
2347
- const result = await transform(source, esbuildOptions);
2348
- return {
2349
- code: result.code,
2350
- map: result.map
2351
- };
2352
- } catch (error) {
2353
- throw new Error(`Transform failed: ${error instanceof Error ? error.message : String(error)}`);
2354
- }
2355
- }
2356
- /**
2357
- * Get esbuild loader for source type.
2358
- */
2359
- getLoader(sourceType) {
2360
- switch (sourceType) {
2361
- case "jsx":
2362
- return "jsx";
2363
- case "tsx":
2364
- return "tsx";
2365
- case "mdx":
2366
- return "tsx";
2367
- // MDX compiles to JSX/TSX
2368
- case "html":
2369
- return "text";
2370
- default:
2371
- return "tsx";
2372
- }
2373
- }
2374
- /**
2375
- * Detect source type from content.
2376
- */
2377
- detectSourceType(source) {
2378
- const hasTypeScript = /:\s*(string|number|boolean|any|unknown|void|never|object)\b/.test(source) || /interface\s+\w+/.test(source) || /type\s+\w+\s*=/.test(source) || /<\w+>/.test(source);
2379
- const hasJSX = /<[A-Z][a-zA-Z]*/.test(source) || // Component tags
2380
- /<[a-z]+\s/.test(source) || // HTML tags with attributes
2381
- /<[a-z]+>/.test(source) || // Self-closing HTML tags
2382
- /<\/[a-z]+>/.test(source);
2383
- const hasMDX = /^#\s+/.test(source) || // Markdown heading
2384
- /^-\s+/.test(source) || // Markdown list
2385
- /\*\*\w+\*\*/.test(source) || // Bold
2386
- /```\w*\n/.test(source);
2387
- if (hasMDX && hasJSX) {
2388
- return "mdx";
2389
- }
2390
- if (hasTypeScript && hasJSX) {
2391
- return "tsx";
2392
- }
2393
- if (hasJSX) {
2394
- return "jsx";
2395
- }
2396
- if (hasTypeScript) {
2397
- return "tsx";
2398
- }
2399
- return "jsx";
2400
- }
2401
- /**
2402
- * Merge bundle options with defaults.
2403
- */
2404
- mergeOptions(options) {
2405
- return {
2406
- sourceType: options.sourceType ?? DEFAULT_BUNDLE_OPTIONS.sourceType,
2407
- format: options.format ?? DEFAULT_BUNDLE_OPTIONS.format,
2408
- minify: options.minify ?? DEFAULT_BUNDLE_OPTIONS.minify,
2409
- sourceMaps: options.sourceMaps ?? DEFAULT_BUNDLE_OPTIONS.sourceMaps,
2410
- externals: options.externals ?? DEFAULT_BUNDLE_OPTIONS.externals,
2411
- jsx: {
2412
- ...DEFAULT_BUNDLE_OPTIONS.jsx,
2413
- ...options.jsx
2414
- },
2415
- target: options.target ?? DEFAULT_BUNDLE_OPTIONS.target,
2416
- globalName: options.globalName ?? DEFAULT_BUNDLE_OPTIONS.globalName,
2417
- skipCache: options.skipCache ?? DEFAULT_BUNDLE_OPTIONS.skipCache
2418
- };
2419
- }
2420
- /**
2421
- * Build hydration script for client-side React.
2422
- */
2423
- buildHydrationScript(bundledCode, context) {
2424
- const contextJson = context ? JSON.stringify(context) : "{}";
2425
- return `
2426
- (function() {
2427
- var context = ${contextJson};
2428
- var exports = {};
2429
- var module = { exports: exports };
2430
-
2431
- // Execute bundled code
2432
- (function(exports, module) {
2433
- ${bundledCode}
2434
- })(exports, module);
2435
-
2436
- // Get component
2437
- var Component = module.exports.default || module.exports;
2438
-
2439
- // Hydrate
2440
- if (typeof ReactDOM !== 'undefined' && ReactDOM.hydrateRoot) {
2441
- var container = document.getElementById('root') || document.body.firstElementChild;
2442
- if (container) {
2443
- ReactDOM.hydrateRoot(container, React.createElement(Component, context));
2444
- }
2445
- }
2446
- })();
2447
- `.trim();
2448
- }
2449
- // ============================================
2450
- // Static HTML Helper Methods
2451
- // ============================================
2452
- /**
2453
- * Merge static HTML options with defaults.
2454
- */
2455
- mergeStaticHTMLOptions(options) {
2456
- return {
2457
- sourceType: options.sourceType ?? DEFAULT_STATIC_HTML_OPTIONS.sourceType,
2458
- targetPlatform: options.targetPlatform ?? DEFAULT_STATIC_HTML_OPTIONS.targetPlatform,
2459
- minify: options.minify ?? DEFAULT_STATIC_HTML_OPTIONS.minify,
2460
- skipCache: options.skipCache ?? DEFAULT_STATIC_HTML_OPTIONS.skipCache,
2461
- rootId: sanitizeRootId(options.rootId ?? DEFAULT_STATIC_HTML_OPTIONS.rootId),
2462
- widgetAccessible: options.widgetAccessible ?? DEFAULT_STATIC_HTML_OPTIONS.widgetAccessible,
2463
- externals: {
2464
- ...DEFAULT_STATIC_HTML_OPTIONS.externals,
2465
- ...options.externals
2466
- },
2467
- // Universal mode options
2468
- universal: options.universal ?? DEFAULT_STATIC_HTML_OPTIONS.universal,
2469
- contentType: options.contentType ?? DEFAULT_STATIC_HTML_OPTIONS.contentType,
2470
- includeMarkdown: options.includeMarkdown ?? DEFAULT_STATIC_HTML_OPTIONS.includeMarkdown,
2471
- includeMdx: options.includeMdx ?? DEFAULT_STATIC_HTML_OPTIONS.includeMdx,
2472
- // Build mode options
2473
- buildMode: options.buildMode ?? DEFAULT_STATIC_HTML_OPTIONS.buildMode,
2474
- dynamicOptions: options.dynamicOptions,
2475
- hybridOptions: options.hybridOptions,
2476
- // Pass-through options
2477
- toolName: options.toolName,
2478
- input: options.input,
2479
- output: options.output,
2480
- structuredContent: options.structuredContent,
2481
- title: options.title,
2482
- security: options.security,
2483
- customCss: options.customCss,
2484
- customComponents: options.customComponents,
2485
- theme: options.theme
2486
- };
2487
- }
2488
- /**
2489
- * Build the <head> section for static HTML.
2490
- */
2491
- buildStaticHTMLHead(opts) {
2492
- const parts = [];
2493
- parts.push(`<meta charset="UTF-8">`);
2494
- parts.push(`<meta name="viewport" content="width=device-width, initial-scale=1.0">`);
2495
- for (const url of STATIC_HTML_CDN.fonts.preconnect) {
2496
- parts.push(`<link rel="preconnect" href="${url}" crossorigin>`);
2497
- }
2498
- parts.push(`<link rel="stylesheet" href="${STATIC_HTML_CDN.fonts.inter}">`);
2499
- parts.push((0, import_build2.buildCDNScriptTag)(import_build2.CLOUDFLARE_CDN.tailwindCss));
2500
- parts.push(this.buildThemeStyleBlock(opts.theme));
2501
- parts.push(`<style>
2502
- body { margin: 0; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
2503
- .frontmcp-loading { display: flex; align-items: center; justify-content: center; min-height: 200px; }
2504
- .frontmcp-spinner { width: 24px; height: 24px; border: 2px solid #e5e7eb; border-top-color: #3b82f6; border-radius: 50%; animation: spin 1s linear infinite; }
2505
- @keyframes spin { to { transform: rotate(360deg); } }
2506
- </style>`);
2507
- if (opts.customCss) {
2508
- parts.push(`<style>
2509
- ${sanitizeCss(opts.customCss)}
2510
- </style>`);
2511
- }
2512
- return parts.join("\n ");
2513
- }
2514
- /**
2515
- * Build theme CSS variables as a :root style block.
2516
- * Uses DEFAULT_THEME if no theme is provided.
2517
- */
2518
- buildThemeStyleBlock(theme = import_theme.DEFAULT_THEME) {
2519
- const cssVars = (0, import_theme.buildThemeCss)(theme);
2520
- return `<style>
2521
- :root {
2522
- ${cssVars}
2523
- }
2524
- </style>`;
2525
- }
2526
- /**
2527
- * Build React runtime scripts for static HTML.
2528
- */
2529
- buildReactRuntimeScripts(externals, platform, cdnType) {
2530
- const reactConfig = externals.react ?? "cdn";
2531
- const reactDomConfig = externals.reactDom ?? "cdn";
2532
- if (cdnType === "umd") {
2533
- const reactUrl = reactConfig === "cdn" ? STATIC_HTML_CDN.umd.react : reactConfig;
2534
- const reactDomUrl = reactDomConfig === "cdn" ? STATIC_HTML_CDN.umd.reactDom : reactDomConfig;
2535
- return `
2536
- <!-- React Runtime (UMD from cdnjs - Claude compatible) -->
2537
- <script src="${reactUrl}"></script>
2538
- <script src="${reactDomUrl}"></script>
2539
- <script>
2540
- // Webpack/esbuild polyfills for transpiled code (UMD globals)
2541
- window.external_react_namespaceObject = window.React;
2542
- window.jsx_runtime_namespaceObject = {
2543
- jsx: function(type, props, key) {
2544
- if (key !== undefined) props = Object.assign({}, props, { key: key });
2545
- return React.createElement(type, props);
2546
- },
2547
- jsxs: function(type, props, key) {
2548
- if (key !== undefined) props = Object.assign({}, props, { key: key });
2549
- return React.createElement(type, props);
2550
- },
2551
- Fragment: React.Fragment
2552
- };
2553
- window.__reactReady = true;
2554
- </script>`;
2555
- } else {
2556
- const reactUrl = reactConfig === "cdn" ? STATIC_HTML_CDN.esm.react : reactConfig;
2557
- const reactDomUrl = reactDomConfig === "cdn" ? STATIC_HTML_CDN.esm.reactDom : reactDomConfig;
2558
- return `
2559
- <!-- React Runtime (ES modules from esm.sh) -->
2560
- <script type="module">
2561
- import React from '${reactUrl}';
2562
- import { createRoot } from '${reactDomUrl}';
2563
-
2564
- // Make React available globally
2565
- window.React = React;
2566
- window.ReactDOM = { createRoot };
2567
-
2568
- // Webpack/esbuild polyfills for transpiled code
2569
- window.external_react_namespaceObject = React;
2570
- window.jsx_runtime_namespaceObject = {
2571
- jsx: function(type, props, key) {
2572
- if (key !== undefined) props = Object.assign({}, props, { key: key });
2573
- return React.createElement(type, props);
2574
- },
2575
- jsxs: function(type, props, key) {
2576
- if (key !== undefined) props = Object.assign({}, props, { key: key });
2577
- return React.createElement(type, props);
2578
- },
2579
- Fragment: React.Fragment
2580
- };
2581
-
2582
- // Signal React is ready
2583
- window.__reactReady = true;
2584
- window.dispatchEvent(new CustomEvent('react:ready'));
2585
- </script>`;
2586
- }
2587
- }
2588
- /**
2589
- * Build FrontMCP runtime (hooks and UI components).
2590
- * Uses esbuild to transpile real React components at first use, then caches.
2591
- * Falls back to manual implementation if esbuild fails.
2592
- * Always inlined for reliability across platforms.
2593
- */
2594
- async buildFrontMCPRuntime() {
2595
- let uiComponents;
2596
- try {
2597
- uiComponents = await getBrowserComponents();
2598
- } catch {
2599
- uiComponents = (0, import_build2.buildUIComponentsRuntime)();
2600
- }
2601
- return `
2602
- <!-- FrontMCP Runtime (always inline) -->
2603
- <script>
2604
- // Custom require() shim for browser - maps module names to globals
2605
- // This allows esbuild-transpiled code to work in browsers
2606
- window.__moduleCache = {};
2607
- window.require = function(moduleName) {
2608
- // Check cache first
2609
- if (window.__moduleCache[moduleName]) {
2610
- return window.__moduleCache[moduleName];
2611
- }
2612
-
2613
- // Map module names to browser globals
2614
- var moduleMap = {
2615
- 'react': function() { return window.React; },
2616
- 'react-dom': function() { return window.ReactDOM; },
2617
- 'react-dom/client': function() { return window.ReactDOM; },
2618
- 'react/jsx-runtime': function() { return window.jsx_runtime_namespaceObject; },
2619
- 'react/jsx-dev-runtime': function() { return window.jsx_runtime_namespaceObject; },
2620
- '@frontmcp/ui': function() { return window.frontmcp_ui_namespaceObject; },
2621
- '@frontmcp/ui/react': function() { return window.frontmcp_ui_namespaceObject; },
2622
- };
2623
-
2624
- var resolver = moduleMap[moduleName];
2625
- if (resolver) {
2626
- var mod = resolver();
2627
- window.__moduleCache[moduleName] = mod;
2628
- return mod;
2629
- }
2630
-
2631
- console.warn('[FrontMCP] Unknown module requested:', moduleName);
2632
- return {};
2633
- };
2634
-
2635
- // Async require for dynamic imports (returns Promise)
2636
- window.requireAsync = function(moduleName) {
2637
- return new Promise(function(resolve, reject) {
2638
- // If module is already loaded, resolve immediately
2639
- var mod = window.require(moduleName);
2640
- if (mod && Object.keys(mod).length > 0) {
2641
- resolve(mod);
2642
- return;
2643
- }
2644
-
2645
- // For now, we don't support dynamic CDN loading
2646
- // All required modules should be pre-loaded
2647
- console.warn('[FrontMCP] Async module not available:', moduleName);
2648
- resolve({});
2649
- });
2650
- };
2651
-
2652
- // FrontMCP Hook implementations and state
2653
- window.__frontmcp = {
2654
- // Context for MCP bridge
2655
- context: {
2656
- toolName: null,
2657
- toolInput: null,
2658
- toolOutput: null,
2659
- structuredContent: null,
2660
- callTool: null,
2661
- },
2662
-
2663
- // Theme and display settings
2664
- theme: 'light',
2665
- displayMode: 'embedded',
2666
- hostContext: {},
2667
- capabilities: {},
2668
-
2669
- // Set context from data injection
2670
- setContext: function(ctx) {
2671
- Object.assign(this.context, ctx);
2672
- },
2673
-
2674
- // State management (for universal mode compatibility)
2675
- getState: function() {
2676
- return {
2677
- toolName: this.context.toolName,
2678
- input: this.context.toolInput,
2679
- output: this.context.toolOutput,
2680
- structuredContent: this.context.structuredContent,
2681
- loading: false,
2682
- error: null
2683
- };
2684
- },
2685
-
2686
- setState: function(partial) {
2687
- if (partial.toolName !== undefined) this.context.toolName = partial.toolName;
2688
- if (partial.input !== undefined) this.context.toolInput = partial.input;
2689
- if (partial.output !== undefined) this.context.toolOutput = partial.output;
2690
- if (partial.structuredContent !== undefined) this.context.structuredContent = partial.structuredContent;
2691
- }
2692
- };
2693
-
2694
- // Hook: useToolOutput - returns the tool output data
2695
- window.useToolOutput = function() {
2696
- return window.__frontmcp.context.toolOutput;
2697
- };
2698
-
2699
- // Hook: useToolInput - returns the tool input arguments
2700
- window.useToolInput = function() {
2701
- return window.__frontmcp.context.toolInput;
2702
- };
2703
-
2704
- // Hook: useMcpBridgeContext - returns full bridge context
2705
- window.useMcpBridgeContext = function() {
2706
- return window.__frontmcp.context;
2707
- };
2708
-
2709
- // Hook: useCallTool - returns function to call other tools
2710
- window.useCallTool = function() {
2711
- return function(name, args) {
2712
- if (window.__frontmcp.context.callTool) {
2713
- return window.__frontmcp.context.callTool(name, args);
2714
- }
2715
- console.warn('[FrontMCP] callTool not available - widget may not have tool access');
2716
- return Promise.resolve(null);
2717
- };
2718
- };
2719
- </script>
2720
- <!-- UI Components (Full-Featured, Browser-Compatible) -->
2721
- <script>
2722
- ${uiComponents}
2723
- </script>`;
2724
- }
2725
- /**
2726
- * Build data injection script for tool input/output.
2727
- * Dispatches to mode-specific builders based on buildMode.
2728
- */
2729
- buildDataInjectionScript(toolName, input, output, structuredContent, buildMode = "static", cdnType = "esm", dynamicOptions, hybridOptions) {
2730
- switch (buildMode) {
2731
- case "dynamic":
2732
- return this.buildDynamicDataScript(toolName, input, output, structuredContent, cdnType, dynamicOptions);
2733
- case "hybrid":
2734
- return this.buildHybridDataScript(toolName, input, structuredContent, hybridOptions);
2735
- case "static":
2736
- default:
2737
- return this.buildStaticDataScript(toolName, input, output, structuredContent);
2738
- }
2739
- }
2740
- /**
2741
- * Build static data injection - data baked in at build time (current default).
2742
- */
2743
- buildStaticDataScript(toolName, input, output, structuredContent) {
2744
- const safeJson = (value) => {
2745
- try {
2746
- return JSON.stringify(value);
2747
- } catch {
2748
- return "null";
2749
- }
2750
- };
2751
- return `
2752
- <!-- Tool Data Injection (Static Mode) -->
2753
- <script>
2754
- window.__mcpToolName = ${safeJson(toolName)};
2755
- window.__mcpToolInput = ${safeJson(input ?? null)};
2756
- window.__mcpToolOutput = ${safeJson(output ?? null)};
2757
- window.__mcpStructuredContent = ${safeJson(structuredContent ?? null)};
2758
-
2759
- // Initialize FrontMCP context
2760
- window.__frontmcp.setContext({
2761
- toolName: window.__mcpToolName,
2762
- toolInput: window.__mcpToolInput,
2763
- toolOutput: window.__mcpToolOutput,
2764
- structuredContent: window.__mcpStructuredContent,
2765
- });
2766
- </script>`;
2767
- }
2768
- /**
2769
- * Build dynamic data injection - platform-aware.
2770
- * For OpenAI (ESM): subscribes to platform events for updates.
2771
- * For non-OpenAI (UMD/Claude): uses placeholders for data injection.
2772
- */
2773
- buildDynamicDataScript(toolName, input, output, structuredContent, cdnType = "esm", options) {
2774
- if (cdnType === "umd") {
2775
- return this.buildDynamicWithPlaceholdersScript(toolName, structuredContent, options);
2776
- }
2777
- return this.buildDynamicWithSubscriptionScript(toolName, input, output, structuredContent, options);
2778
- }
2779
- /**
2780
- * Build dynamic data injection for non-OpenAI platforms using placeholders.
2781
- * Similar to hybrid mode but with platform-appropriate loading/error states.
2782
- */
2783
- buildDynamicWithPlaceholdersScript(toolName, structuredContent, options) {
2784
- const safeJson = (value) => {
2785
- try {
2786
- return JSON.stringify(value);
2787
- } catch {
2788
- return "null";
2789
- }
2790
- };
2791
- const outputPlaceholder = HYBRID_DATA_PLACEHOLDER;
2792
- const inputPlaceholder = HYBRID_INPUT_PLACEHOLDER;
2793
- const includeInitialData = options?.includeInitialData !== false;
2794
- return `
2795
- <!-- Tool Data Injection (Dynamic Mode - Placeholder-based for non-OpenAI) -->
2796
- <script>
2797
- window.__mcpToolName = ${safeJson(toolName)};
2798
- window.__mcpToolInput = "${inputPlaceholder}";
2799
- window.__mcpToolOutput = "${outputPlaceholder}";
2800
- window.__mcpStructuredContent = ${safeJson(structuredContent ?? null)};
2801
- window.__mcpHybridError = null;
2802
-
2803
- (function() {
2804
- var outputNotReplaced = false;
2805
- var includeInitialData = ${includeInitialData};
2806
-
2807
- // Parse output placeholder
2808
- var rawOutput = window.__mcpToolOutput;
2809
- if (typeof rawOutput === 'string' && rawOutput !== "${outputPlaceholder}") {
2810
- try {
2811
- window.__mcpToolOutput = JSON.parse(rawOutput);
2812
- } catch (e) {
2813
- console.warn('[FrontMCP] Failed to parse injected output data:', e);
2814
- window.__mcpToolOutput = null;
2815
- window.__mcpHybridError = 'Failed to parse output data';
2816
- }
2817
- } else if (rawOutput === "${outputPlaceholder}") {
2818
- window.__mcpToolOutput = null;
2819
- outputNotReplaced = true;
2820
- }
2821
-
2822
- // Parse input placeholder
2823
- var rawInput = window.__mcpToolInput;
2824
- if (typeof rawInput === 'string' && rawInput !== "${inputPlaceholder}") {
2825
- try {
2826
- window.__mcpToolInput = JSON.parse(rawInput);
2827
- } catch (e) {
2828
- console.warn('[FrontMCP] Failed to parse injected input data:', e);
2829
- window.__mcpToolInput = null;
2830
- }
2831
- } else if (rawInput === "${inputPlaceholder}") {
2832
- window.__mcpToolInput = null;
2833
- }
2834
-
2835
- // Handle placeholder not replaced - show error if expecting initial data
2836
- if (outputNotReplaced && includeInitialData) {
2837
- window.__mcpHybridError = 'No data provided. The output placeholder was not replaced.';
2838
- }
2839
- })();
2840
-
2841
- // Initialize FrontMCP context with appropriate loading/error state
2842
- if (window.__frontmcp && window.__frontmcp.setContext) {
2843
- window.__frontmcp.setContext({
2844
- toolName: window.__mcpToolName,
2845
- toolInput: window.__mcpToolInput,
2846
- toolOutput: window.__mcpToolOutput,
2847
- structuredContent: window.__mcpStructuredContent,
2848
- loading: ${!includeInitialData} && window.__mcpToolOutput === null && !window.__mcpHybridError,
2849
- error: window.__mcpHybridError,
2850
- });
2851
- }
2852
- </script>`;
2853
- }
2854
- /**
2855
- * Build dynamic data injection for OpenAI using subscription pattern.
2856
- */
2857
- buildDynamicWithSubscriptionScript(toolName, input, output, structuredContent, options) {
2858
- const safeJson = (value) => {
2859
- try {
2860
- return JSON.stringify(value);
2861
- } catch {
2862
- return "null";
2863
- }
2864
- };
2865
- const includeInitial = options?.includeInitialData !== false;
2866
- const subscribeToUpdates = options?.subscribeToUpdates !== false;
2867
- const initialDataBlock = includeInitial ? `
2868
- window.__mcpToolOutput = ${safeJson(output ?? null)};
2869
- if (window.__frontmcp && window.__frontmcp.setState) {
2870
- window.__frontmcp.setState({
2871
- output: window.__mcpToolOutput,
2872
- loading: false,
2873
- });
2874
- }` : `
2875
- window.__mcpToolOutput = null;
2876
- if (window.__frontmcp && window.__frontmcp.setState) {
2877
- window.__frontmcp.setState({
2878
- output: null,
2879
- loading: true,
2880
- });
2881
- }`;
2882
- const subscriptionBlock = subscribeToUpdates ? `
2883
- // Subscribe to platform tool result updates
2884
- (function() {
2885
- function subscribeToUpdates() {
2886
- // OpenAI Apps SDK
2887
- if (window.openai && window.openai.canvas && window.openai.canvas.onToolResult) {
2888
- window.openai.canvas.onToolResult(function(result) {
2889
- window.__mcpToolOutput = result;
2890
- if (window.__frontmcp && window.__frontmcp.setState) {
2891
- window.__frontmcp.setState({
2892
- output: result,
2893
- loading: false,
2894
- });
2895
- }
2896
- // Dispatch custom event for React hooks
2897
- window.dispatchEvent(new CustomEvent('frontmcp:toolResult', { detail: result }));
2898
- });
2899
- return;
2900
- }
2901
-
2902
- // Fallback: listen for custom events (for testing/other platforms)
2903
- window.addEventListener('frontmcp:injectData', function(e) {
2904
- if (e.detail && e.detail.output !== undefined) {
2905
- window.__mcpToolOutput = e.detail.output;
2906
- if (window.__frontmcp && window.__frontmcp.setState) {
2907
- window.__frontmcp.setState({
2908
- output: e.detail.output,
2909
- loading: false,
2910
- });
2911
- }
2912
- }
2913
- });
2914
- }
2915
-
2916
- // Subscribe when DOM is ready
2917
- if (document.readyState === 'loading') {
2918
- document.addEventListener('DOMContentLoaded', subscribeToUpdates);
2919
- } else {
2920
- subscribeToUpdates();
2921
- }
2922
- })();` : "";
2923
- return `
2924
- <!-- Tool Data Injection (Dynamic Mode - OpenAI Subscription) -->
2925
- <script>
2926
- window.__mcpToolName = ${safeJson(toolName)};
2927
- window.__mcpToolInput = ${safeJson(input ?? null)};
2928
- window.__mcpStructuredContent = ${safeJson(structuredContent ?? null)};
2929
- ${initialDataBlock}
2930
-
2931
- // Initialize FrontMCP context
2932
- if (window.__frontmcp && window.__frontmcp.setContext) {
2933
- window.__frontmcp.setContext({
2934
- toolName: window.__mcpToolName,
2935
- toolInput: window.__mcpToolInput,
2936
- toolOutput: window.__mcpToolOutput,
2937
- structuredContent: window.__mcpStructuredContent,
2938
- });
2939
- }
2940
- ${subscriptionBlock}
2941
- </script>`;
2942
- }
2943
- /**
2944
- * Build hybrid data injection - shell with placeholders for runtime injection.
2945
- * Use injectHybridData() or injectHybridDataFull() from @frontmcp/uipack to replace the placeholders.
2946
- */
2947
- buildHybridDataScript(toolName, _input, structuredContent, options) {
2948
- const safeJson = (value) => {
2949
- try {
2950
- return JSON.stringify(value);
2951
- } catch {
2952
- return "null";
2953
- }
2954
- };
2955
- const outputPlaceholder = options?.placeholder ?? HYBRID_DATA_PLACEHOLDER;
2956
- const inputPlaceholder = options?.inputPlaceholder ?? HYBRID_INPUT_PLACEHOLDER;
2957
- return `
2958
- <!-- Tool Data Injection (Hybrid Mode - Replace placeholders with JSON) -->
2959
- <script>
2960
- window.__mcpToolName = ${safeJson(toolName)};
2961
- window.__mcpToolInput = "${inputPlaceholder}";
2962
- window.__mcpToolOutput = "${outputPlaceholder}";
2963
- window.__mcpStructuredContent = ${safeJson(structuredContent ?? null)};
2964
- window.__mcpHybridError = null;
2965
-
2966
- // Parse placeholders if they've been replaced with actual JSON
2967
- (function() {
2968
- var outputNotReplaced = false;
2969
-
2970
- // Parse output placeholder
2971
- var rawOutput = window.__mcpToolOutput;
2972
- if (typeof rawOutput === 'string' && rawOutput !== "${outputPlaceholder}") {
2973
- try {
2974
- window.__mcpToolOutput = JSON.parse(rawOutput);
2975
- } catch (e) {
2976
- console.warn('[FrontMCP] Failed to parse injected output data:', e);
2977
- window.__mcpToolOutput = null;
2978
- window.__mcpHybridError = 'Failed to parse output data';
2979
- }
2980
- } else if (rawOutput === "${outputPlaceholder}") {
2981
- // Placeholder not replaced - no data was injected
2982
- window.__mcpToolOutput = null;
2983
- outputNotReplaced = true;
2984
- }
2985
-
2986
- // Parse input placeholder
2987
- var rawInput = window.__mcpToolInput;
2988
- if (typeof rawInput === 'string' && rawInput !== "${inputPlaceholder}") {
2989
- try {
2990
- window.__mcpToolInput = JSON.parse(rawInput);
2991
- } catch (e) {
2992
- console.warn('[FrontMCP] Failed to parse injected input data:', e);
2993
- window.__mcpToolInput = null;
2994
- }
2995
- } else if (rawInput === "${inputPlaceholder}") {
2996
- window.__mcpToolInput = null;
2997
- }
2998
-
2999
- // Set error if output placeholder was not replaced (no data provided)
3000
- if (outputNotReplaced) {
3001
- window.__mcpHybridError = 'No data provided. The output placeholder was not replaced.';
3002
- }
3003
- })();
3004
-
3005
- // Initialize FrontMCP context with appropriate loading/error state
3006
- if (window.__frontmcp && window.__frontmcp.setContext) {
3007
- window.__frontmcp.setContext({
3008
- toolName: window.__mcpToolName,
3009
- toolInput: window.__mcpToolInput,
3010
- toolOutput: window.__mcpToolOutput,
3011
- structuredContent: window.__mcpStructuredContent,
3012
- loading: false,
3013
- error: window.__mcpHybridError,
3014
- });
3015
- }
3016
- </script>`;
3017
- }
3018
- /**
3019
- * Build component render script.
3020
- * Wraps CommonJS code with module/exports shim to capture the component.
3021
- */
3022
- buildComponentRenderScript(componentCode, rootId, cdnType) {
3023
- const wrappedCode = `
3024
- // CommonJS module shim
3025
- var module = { exports: {} };
3026
- var exports = module.exports;
3027
-
3028
- // Execute transpiled component code (CommonJS format)
3029
- ${componentCode}
3030
-
3031
- // Capture the component export
3032
- window.__frontmcp_component = module.exports;
3033
- `;
3034
- if (cdnType === "umd") {
3035
- return `
3036
- <!-- Component Render Script (UMD - synchronous) -->
3037
- <script>
3038
- (function() {
3039
- ${wrappedCode}
3040
-
3041
- // Get the component
3042
- var Component = window.__frontmcp_component.default || window.__frontmcp_component;
3043
-
3044
- // Render the component
3045
- var container = document.getElementById('${rootId}');
3046
- if (container && window.ReactDOM && window.ReactDOM.createRoot) {
3047
- var root = window.ReactDOM.createRoot(container);
3048
- root.render(React.createElement(Component, {
3049
- output: window.__mcpToolOutput,
3050
- input: window.__mcpToolInput,
3051
- }));
3052
- } else if (container && window.ReactDOM && window.ReactDOM.render) {
3053
- // Fallback for React 17
3054
- window.ReactDOM.render(
3055
- React.createElement(Component, {
3056
- output: window.__mcpToolOutput,
3057
- input: window.__mcpToolInput,
3058
- }),
3059
- container
3060
- );
3061
- }
3062
- })();
3063
- </script>`;
3064
- } else {
3065
- return `
3066
- <!-- Component Render Script (ESM - waits for React) -->
3067
- <script type="module">
3068
- function renderComponent() {
3069
- ${wrappedCode}
3070
-
3071
- // Get the component
3072
- var Component = window.__frontmcp_component.default || window.__frontmcp_component;
3073
-
3074
- // Render the component
3075
- var container = document.getElementById('${rootId}');
3076
- if (container && window.ReactDOM && window.ReactDOM.createRoot) {
3077
- var root = window.ReactDOM.createRoot(container);
3078
- root.render(React.createElement(Component, {
3079
- output: window.__mcpToolOutput,
3080
- input: window.__mcpToolInput,
3081
- }));
3082
- }
3083
- }
3084
-
3085
- // Wait for React to be ready
3086
- if (window.__reactReady) {
3087
- renderComponent();
3088
- } else {
3089
- window.addEventListener('react:ready', renderComponent);
3090
- }
3091
- </script>`;
3092
- }
3093
- }
3094
- /**
3095
- * Assemble the complete static HTML document.
3096
- */
3097
- assembleStaticHTML(parts) {
3098
- return `<!DOCTYPE html>
3099
- <html lang="en">
3100
- <head>
3101
- <title>${(0, import_utils.escapeHtml)(parts.title)}</title>
3102
- ${parts.head}
3103
- ${parts.reactRuntime}
3104
- ${parts.frontmcpRuntime}
3105
- ${parts.dataScript}
3106
- </head>
3107
- <body>
3108
- <div id="${parts.rootId}" class="frontmcp-loading">
3109
- <div class="frontmcp-spinner"></div>
3110
- </div>
3111
- ${parts.componentScript}
3112
- </body>
3113
- </html>`;
3114
- }
3115
- };
3116
- function createBundler(options) {
3117
- return new InMemoryBundler(options);
3118
- }
3119
-
3120
- // libs/ui/src/bundler/index.ts
3121
- var import_bundler4 = require("@frontmcp/uipack/bundler");
3122
- var import_bundler5 = require("@frontmcp/uipack/bundler");
3123
- var import_bundler6 = require("@frontmcp/uipack/bundler");
3124
- var import_bundler7 = require("@frontmcp/uipack/bundler");
3125
- // Annotate the CommonJS export names for ESM import in node:
3126
- 0 && (module.exports = {
3127
- ALL_PLATFORMS,
3128
- BundlerCache,
3129
- ComponentBuilder,
3130
- DEFAULT_BUNDLER_OPTIONS,
3131
- DEFAULT_BUNDLE_OPTIONS,
3132
- DEFAULT_SECURITY_POLICY,
3133
- DEFAULT_STATIC_HTML_OPTIONS,
3134
- DEFAULT_STORAGE_OPTIONS,
3135
- ExecutionError,
3136
- FilesystemStorage,
3137
- HYBRID_DATA_PLACEHOLDER,
3138
- HYBRID_INPUT_PLACEHOLDER,
3139
- InMemoryBundler,
3140
- RedisStorage,
3141
- STATIC_HTML_CDN,
3142
- SecurityError,
3143
- buildIdFromHash,
3144
- calculateComponentHash,
3145
- calculateManifestSize,
3146
- calculateQuickHash,
3147
- createBundler,
3148
- createCacheKey,
3149
- createFilesystemBuilder,
3150
- createFilesystemStorage,
3151
- createRedisBuilder,
3152
- createRedisStorage,
3153
- executeCode,
3154
- executeDefault,
3155
- generateBuildId,
3156
- getCdnTypeForPlatform,
3157
- hashContent,
3158
- hashFile,
3159
- hashFiles,
3160
- isExecutionError,
3161
- mergePolicy,
3162
- sha256,
3163
- sha256Buffer,
3164
- throwOnViolations,
3165
- validateImports,
3166
- validateSize,
3167
- validateSource
3168
- });