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