@frontmcp/uipack 1.3.0 → 1.4.1
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/adapters/index.js +1046 -698
- package/adapters/template-renderer.d.ts +14 -0
- package/adapters/template-renderer.d.ts.map +1 -1
- package/bridge-runtime/iife-generator.d.ts.map +1 -1
- package/bridge-runtime/index.js +149 -0
- package/component/index.d.ts +1 -0
- package/component/index.d.ts.map +1 -1
- package/component/index.js +468 -145
- package/component/loader.d.ts +21 -2
- package/component/loader.d.ts.map +1 -1
- package/component/renderer.d.ts +2 -2
- package/component/renderer.d.ts.map +1 -1
- package/component/transpiler.d.ts +16 -1
- package/component/transpiler.d.ts.map +1 -1
- package/component/types.d.ts +19 -0
- package/component/types.d.ts.map +1 -1
- package/component/ui-availability.d.ts +27 -0
- package/component/ui-availability.d.ts.map +1 -0
- package/esm/adapters/index.mjs +1046 -698
- package/esm/bridge-runtime/index.mjs +149 -0
- package/esm/component/index.mjs +468 -145
- package/esm/index.mjs +444 -109
- package/esm/package.json +2 -2
- package/esm/shell/index.mjs +420 -171
- package/index.d.ts +1 -1
- package/index.d.ts.map +1 -1
- package/index.js +445 -109
- package/package.json +2 -2
- package/shell/builder.d.ts.map +1 -1
- package/shell/data-injector.d.ts +27 -1
- package/shell/data-injector.d.ts.map +1 -1
- package/shell/index.d.ts +3 -2
- package/shell/index.d.ts.map +1 -1
- package/shell/index.js +423 -171
- package/shell/sizing-css.d.ts +27 -0
- package/shell/sizing-css.d.ts.map +1 -0
- package/shell/types.d.ts +102 -0
- package/shell/types.d.ts.map +1 -1
- package/types/index.d.ts +1 -1
- package/types/index.d.ts.map +1 -1
- package/types/ui-config.d.ts +105 -11
- package/types/ui-config.d.ts.map +1 -1
- package/types/ui-runtime.d.ts +23 -2
- package/types/ui-runtime.d.ts.map +1 -1
package/esm/index.mjs
CHANGED
|
@@ -181,6 +181,8 @@ function generateBridgeIIFE(options = {}) {
|
|
|
181
181
|
parts.push("});");
|
|
182
182
|
parts.push("");
|
|
183
183
|
parts.push("window.FrontMcpBridge = bridge;");
|
|
184
|
+
parts.push("");
|
|
185
|
+
parts.push(generateAutoResize());
|
|
184
186
|
parts.push("function __showLoading() {");
|
|
185
187
|
parts.push(' var root = document.getElementById("root");');
|
|
186
188
|
parts.push(" if (root && !root.hasChildNodes()) {");
|
|
@@ -201,6 +203,112 @@ function generateBridgeIIFE(options = {}) {
|
|
|
201
203
|
}
|
|
202
204
|
return code;
|
|
203
205
|
}
|
|
206
|
+
function generateAutoResize() {
|
|
207
|
+
return `
|
|
208
|
+
function __applySizingCss(sizing) {
|
|
209
|
+
if (typeof document === 'undefined' || !document.documentElement) return;
|
|
210
|
+
function toLen(v) { return typeof v === 'number' ? v + 'px' : v; }
|
|
211
|
+
var de = document.documentElement;
|
|
212
|
+
var body = document.body;
|
|
213
|
+
var root = document.getElementById('root');
|
|
214
|
+
if (sizing.preferredHeight != null) {
|
|
215
|
+
var ph = toLen(sizing.preferredHeight);
|
|
216
|
+
de.style.height = ph;
|
|
217
|
+
if (body) body.style.height = ph;
|
|
218
|
+
if (root && !root.style.minHeight) root.style.minHeight = ph;
|
|
219
|
+
}
|
|
220
|
+
if (sizing.minHeight != null) {
|
|
221
|
+
var mh = toLen(sizing.minHeight);
|
|
222
|
+
de.style.minHeight = mh;
|
|
223
|
+
if (body) body.style.minHeight = mh;
|
|
224
|
+
if (root) root.style.minHeight = mh;
|
|
225
|
+
}
|
|
226
|
+
if (sizing.maxHeight != null) {
|
|
227
|
+
var mx = toLen(sizing.maxHeight);
|
|
228
|
+
de.style.maxHeight = mx;
|
|
229
|
+
if (body) body.style.maxHeight = mx;
|
|
230
|
+
if (root) root.style.maxHeight = mx;
|
|
231
|
+
}
|
|
232
|
+
if (sizing.aspectRatio != null && root) {
|
|
233
|
+
root.style.aspectRatio = String(sizing.aspectRatio);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function __initAutoResize() {
|
|
238
|
+
if (typeof window === 'undefined') return;
|
|
239
|
+
// Idempotent: a re-injected IIFE must not stack observers.
|
|
240
|
+
if (window.__mcpAutoResizeInit) return;
|
|
241
|
+
window.__mcpAutoResizeInit = true;
|
|
242
|
+
var sizing = window.__mcpWidgetSizing;
|
|
243
|
+
if (!sizing || typeof sizing !== 'object') return;
|
|
244
|
+
|
|
245
|
+
// Apply CSS as a runtime fallback (the static <style> may be absent on some
|
|
246
|
+
// render paths). Wait for the body if it isn't ready yet.
|
|
247
|
+
function apply() { try { __applySizingCss(sizing); } catch (e) {} }
|
|
248
|
+
if (typeof document !== 'undefined' && document.readyState === 'loading') {
|
|
249
|
+
document.addEventListener('DOMContentLoaded', apply);
|
|
250
|
+
} else {
|
|
251
|
+
apply();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Auto-resize defaults ON; opt out with autoResize:false.
|
|
255
|
+
if (sizing.autoResize === false) return;
|
|
256
|
+
if (typeof ResizeObserver === 'undefined') return;
|
|
257
|
+
|
|
258
|
+
function startObserving() {
|
|
259
|
+
var target = document.getElementById('root') || document.body;
|
|
260
|
+
if (!target) return;
|
|
261
|
+
|
|
262
|
+
var rafId = null;
|
|
263
|
+
var lastReported = -1;
|
|
264
|
+
function report() {
|
|
265
|
+
rafId = null;
|
|
266
|
+
try {
|
|
267
|
+
var rect = target.getBoundingClientRect();
|
|
268
|
+
var height = Math.ceil(rect.height);
|
|
269
|
+
var width = Math.ceil(rect.width);
|
|
270
|
+
if (height === lastReported || height <= 0) return;
|
|
271
|
+
lastReported = height;
|
|
272
|
+
var payload = { height: height, width: width };
|
|
273
|
+
if (sizing.aspectRatio != null) payload.aspectRatio = sizing.aspectRatio;
|
|
274
|
+
if (window.FrontMcpBridge && typeof window.FrontMcpBridge.setSize === 'function') {
|
|
275
|
+
window.FrontMcpBridge.setSize(payload).catch(function() {});
|
|
276
|
+
}
|
|
277
|
+
window.dispatchEvent(new CustomEvent('widget:resize', { detail: payload }));
|
|
278
|
+
} catch (e) {}
|
|
279
|
+
}
|
|
280
|
+
function schedule() {
|
|
281
|
+
// Debounce via rAF; fall back to setTimeout if rAF is unavailable.
|
|
282
|
+
if (rafId != null) return;
|
|
283
|
+
if (typeof requestAnimationFrame === 'function') {
|
|
284
|
+
rafId = requestAnimationFrame(report);
|
|
285
|
+
} else {
|
|
286
|
+
rafId = setTimeout(report, 100);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
// Disconnect any prior observer before creating a new one (no leaks/dupes).
|
|
292
|
+
if (window.__mcpResizeObserver && typeof window.__mcpResizeObserver.disconnect === 'function') {
|
|
293
|
+
window.__mcpResizeObserver.disconnect();
|
|
294
|
+
}
|
|
295
|
+
var ro = new ResizeObserver(function() { schedule(); });
|
|
296
|
+
ro.observe(target);
|
|
297
|
+
window.__mcpResizeObserver = ro;
|
|
298
|
+
} catch (e) {}
|
|
299
|
+
// Report once on init so the host gets an initial measurement.
|
|
300
|
+
schedule();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (typeof document !== 'undefined' && document.readyState === 'loading') {
|
|
304
|
+
document.addEventListener('DOMContentLoaded', startObserving);
|
|
305
|
+
} else {
|
|
306
|
+
startObserving();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
__initAutoResize();
|
|
310
|
+
`.trim();
|
|
311
|
+
}
|
|
204
312
|
function generateContextDetection() {
|
|
205
313
|
return `
|
|
206
314
|
function detectTheme() {
|
|
@@ -308,6 +416,19 @@ var OpenAIAdapter = {
|
|
|
308
416
|
requestDisplayMode: function(context, mode) {
|
|
309
417
|
return Promise.resolve();
|
|
310
418
|
},
|
|
419
|
+
setSize: function(context, size) {
|
|
420
|
+
// OpenAI Apps SDK measures DOM height itself; if a sizing API surfaces on
|
|
421
|
+
// window.openai, forward to it, otherwise no-op (CSS drives layout).
|
|
422
|
+
try {
|
|
423
|
+
if (window.openai && typeof window.openai.requestDisplayMode === 'function' && size && size.displayMode) {
|
|
424
|
+
window.openai.requestDisplayMode(size.displayMode);
|
|
425
|
+
}
|
|
426
|
+
if (window.openai && typeof window.openai.setWidgetHeight === 'function' && size && typeof size.height === 'number') {
|
|
427
|
+
window.openai.setWidgetHeight(size.height);
|
|
428
|
+
}
|
|
429
|
+
} catch (e) {}
|
|
430
|
+
return Promise.resolve();
|
|
431
|
+
},
|
|
311
432
|
requestClose: function(context) {
|
|
312
433
|
return Promise.resolve();
|
|
313
434
|
}
|
|
@@ -552,6 +673,15 @@ var ExtAppsAdapter = {
|
|
|
552
673
|
requestDisplayMode: function(context, mode) {
|
|
553
674
|
return this.sendRequest('ui/setDisplayMode', { mode: mode });
|
|
554
675
|
},
|
|
676
|
+
setSize: function(context, size) {
|
|
677
|
+
// FrontMCP sizing channel \u2014 parallels ui/setDisplayMode. Reports the
|
|
678
|
+
// measured/desired widget dimensions to the host.
|
|
679
|
+
return this.sendRequest('ui/setSize', {
|
|
680
|
+
height: size && size.height,
|
|
681
|
+
width: size && size.width,
|
|
682
|
+
aspectRatio: size && size.aspectRatio
|
|
683
|
+
});
|
|
684
|
+
},
|
|
555
685
|
requestClose: function(context) {
|
|
556
686
|
return this.sendRequest('ui/close', {});
|
|
557
687
|
},
|
|
@@ -640,6 +770,10 @@ var ClaudeAdapter = {
|
|
|
640
770
|
requestDisplayMode: function() {
|
|
641
771
|
return Promise.resolve();
|
|
642
772
|
},
|
|
773
|
+
setSize: function() {
|
|
774
|
+
// Claude measures the rendered DOM height itself \u2014 CSS-only, no reporting.
|
|
775
|
+
return Promise.resolve();
|
|
776
|
+
},
|
|
643
777
|
requestClose: function() {
|
|
644
778
|
return Promise.resolve();
|
|
645
779
|
}
|
|
@@ -691,6 +825,9 @@ var GeminiAdapter = {
|
|
|
691
825
|
requestDisplayMode: function() {
|
|
692
826
|
return Promise.resolve();
|
|
693
827
|
},
|
|
828
|
+
setSize: function() {
|
|
829
|
+
return Promise.resolve();
|
|
830
|
+
},
|
|
694
831
|
requestClose: function() {
|
|
695
832
|
return Promise.resolve();
|
|
696
833
|
}
|
|
@@ -726,6 +863,9 @@ var GenericAdapter = {
|
|
|
726
863
|
requestDisplayMode: function() {
|
|
727
864
|
return Promise.resolve();
|
|
728
865
|
},
|
|
866
|
+
setSize: function() {
|
|
867
|
+
return Promise.resolve();
|
|
868
|
+
},
|
|
729
869
|
requestClose: function() {
|
|
730
870
|
return Promise.resolve();
|
|
731
871
|
}
|
|
@@ -960,6 +1100,15 @@ FrontMcpBridge.prototype.requestDisplayMode = function(mode) {
|
|
|
960
1100
|
});
|
|
961
1101
|
};
|
|
962
1102
|
|
|
1103
|
+
// Report a desired widget size to the host. \`size\` is { height?, width?, aspectRatio? }.
|
|
1104
|
+
// Per-adapter behaviour: Claude/generic no-op (host measures the DOM),
|
|
1105
|
+
// ext-apps sends ui/setSize, OpenAI forwards to its SDK when available.
|
|
1106
|
+
FrontMcpBridge.prototype.setSize = function(size) {
|
|
1107
|
+
if (!this._adapter) return Promise.reject(new Error('Not initialized'));
|
|
1108
|
+
if (!this._adapter.setSize) return Promise.resolve();
|
|
1109
|
+
return this._adapter.setSize(this._context, size || {});
|
|
1110
|
+
};
|
|
1111
|
+
|
|
963
1112
|
FrontMcpBridge.prototype.requestClose = function() {
|
|
964
1113
|
if (!this._adapter) return Promise.reject(new Error('Not initialized'));
|
|
965
1114
|
return this._adapter.requestClose(this._context);
|
|
@@ -2714,9 +2863,61 @@ function escapeAttribute(str) {
|
|
|
2714
2863
|
return str.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
2715
2864
|
}
|
|
2716
2865
|
|
|
2866
|
+
// libs/uipack/src/shell/custom-shell-types.ts
|
|
2867
|
+
var SHELL_PLACEHOLDER_NAMES = ["CSP", "DATA", "BRIDGE", "CONTENT", "TITLE"];
|
|
2868
|
+
var SHELL_PLACEHOLDERS = {
|
|
2869
|
+
CSP: "{{CSP}}",
|
|
2870
|
+
DATA: "{{DATA}}",
|
|
2871
|
+
BRIDGE: "{{BRIDGE}}",
|
|
2872
|
+
CONTENT: "{{CONTENT}}",
|
|
2873
|
+
TITLE: "{{TITLE}}"
|
|
2874
|
+
};
|
|
2875
|
+
var REQUIRED_PLACEHOLDERS = ["CONTENT"];
|
|
2876
|
+
var OPTIONAL_PLACEHOLDERS = ["CSP", "DATA", "BRIDGE", "TITLE"];
|
|
2877
|
+
function isInlineShellSource(source) {
|
|
2878
|
+
return typeof source === "object" && source !== null && "inline" in source;
|
|
2879
|
+
}
|
|
2880
|
+
function isUrlShellSource(source) {
|
|
2881
|
+
return typeof source === "object" && source !== null && "url" in source;
|
|
2882
|
+
}
|
|
2883
|
+
function isNpmShellSource(source) {
|
|
2884
|
+
return typeof source === "object" && source !== null && "npm" in source;
|
|
2885
|
+
}
|
|
2886
|
+
|
|
2887
|
+
// libs/uipack/src/shell/custom-shell-applier.ts
|
|
2888
|
+
function applyShellTemplate(template, values) {
|
|
2889
|
+
let result = template;
|
|
2890
|
+
result = result.replaceAll(SHELL_PLACEHOLDERS.CSP, values.csp);
|
|
2891
|
+
result = result.replaceAll(SHELL_PLACEHOLDERS.DATA, values.data);
|
|
2892
|
+
result = result.replaceAll(SHELL_PLACEHOLDERS.BRIDGE, values.bridge);
|
|
2893
|
+
result = result.replaceAll(SHELL_PLACEHOLDERS.CONTENT, values.content);
|
|
2894
|
+
result = result.replaceAll(SHELL_PLACEHOLDERS.TITLE, values.title);
|
|
2895
|
+
return result;
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2898
|
+
// libs/uipack/src/shell/custom-shell-validator.ts
|
|
2899
|
+
function validateShellTemplate(template) {
|
|
2900
|
+
const found = {};
|
|
2901
|
+
for (const name of SHELL_PLACEHOLDER_NAMES) {
|
|
2902
|
+
found[name] = template.includes(SHELL_PLACEHOLDERS[name]);
|
|
2903
|
+
}
|
|
2904
|
+
const missingRequired = REQUIRED_PLACEHOLDERS.filter((name) => !found[name]);
|
|
2905
|
+
const missingOptional = OPTIONAL_PLACEHOLDERS.filter((name) => !found[name]);
|
|
2906
|
+
return {
|
|
2907
|
+
valid: missingRequired.length === 0,
|
|
2908
|
+
found,
|
|
2909
|
+
missingRequired,
|
|
2910
|
+
missingOptional
|
|
2911
|
+
};
|
|
2912
|
+
}
|
|
2913
|
+
|
|
2717
2914
|
// libs/uipack/src/shell/data-injector.ts
|
|
2915
|
+
function hasSizing(sizing) {
|
|
2916
|
+
if (!sizing) return false;
|
|
2917
|
+
return sizing.preferredHeight !== void 0 || sizing.minHeight !== void 0 || sizing.maxHeight !== void 0 || sizing.aspectRatio !== void 0 || sizing.autoResize !== void 0;
|
|
2918
|
+
}
|
|
2718
2919
|
function buildDataInjectionScript(options) {
|
|
2719
|
-
const { toolName, input, output, structuredContent } = options;
|
|
2920
|
+
const { toolName, input, output, structuredContent, sizing } = options;
|
|
2720
2921
|
const lines = [
|
|
2721
2922
|
`window.__mcpAppsEnabled = true;`,
|
|
2722
2923
|
`window.__mcpToolName = ${safeJsonForScript(toolName)};`,
|
|
@@ -2724,10 +2925,24 @@ function buildDataInjectionScript(options) {
|
|
|
2724
2925
|
`window.__mcpToolOutput = ${safeJsonForScript(output ?? null)};`,
|
|
2725
2926
|
`window.__mcpStructuredContent = ${safeJsonForScript(structuredContent ?? null)};`
|
|
2726
2927
|
];
|
|
2928
|
+
if (hasSizing(sizing)) {
|
|
2929
|
+
lines.push(`window.__mcpWidgetSizing = ${safeJsonForScript(sizing)};`);
|
|
2930
|
+
}
|
|
2727
2931
|
return `<script>
|
|
2728
2932
|
${lines.join("\n")}
|
|
2729
2933
|
</script>`;
|
|
2730
2934
|
}
|
|
2935
|
+
function buildCustomDataInjectionScript(descriptor) {
|
|
2936
|
+
if (descriptor.script !== void 0) {
|
|
2937
|
+
return descriptor.script;
|
|
2938
|
+
}
|
|
2939
|
+
if (descriptor.globalKey !== void 0) {
|
|
2940
|
+
return `<script>window[${safeJsonForScript(descriptor.globalKey)}] = ${safeJsonForScript(
|
|
2941
|
+
descriptor.value ?? null
|
|
2942
|
+
)};</script>`;
|
|
2943
|
+
}
|
|
2944
|
+
return "";
|
|
2945
|
+
}
|
|
2731
2946
|
var _uniqueIdCounter = 0;
|
|
2732
2947
|
function createTemplateHelpers() {
|
|
2733
2948
|
return {
|
|
@@ -2755,59 +2970,79 @@ function createTemplateHelpers() {
|
|
|
2755
2970
|
};
|
|
2756
2971
|
}
|
|
2757
2972
|
|
|
2758
|
-
// libs/uipack/src/shell/
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
CSP: "{{CSP}}",
|
|
2762
|
-
DATA: "{{DATA}}",
|
|
2763
|
-
BRIDGE: "{{BRIDGE}}",
|
|
2764
|
-
CONTENT: "{{CONTENT}}",
|
|
2765
|
-
TITLE: "{{TITLE}}"
|
|
2766
|
-
};
|
|
2767
|
-
var REQUIRED_PLACEHOLDERS = ["CONTENT"];
|
|
2768
|
-
var OPTIONAL_PLACEHOLDERS = ["CSP", "DATA", "BRIDGE", "TITLE"];
|
|
2769
|
-
function isInlineShellSource(source) {
|
|
2770
|
-
return typeof source === "object" && source !== null && "inline" in source;
|
|
2973
|
+
// libs/uipack/src/shell/sizing-css.ts
|
|
2974
|
+
function sanitizeCssValue(value) {
|
|
2975
|
+
return value.replace(/[<>{};]/g, "").trim();
|
|
2771
2976
|
}
|
|
2772
|
-
function
|
|
2773
|
-
return typeof
|
|
2977
|
+
function toCssLength(value) {
|
|
2978
|
+
return typeof value === "number" ? `${value}px` : sanitizeCssValue(value);
|
|
2774
2979
|
}
|
|
2775
|
-
function
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
}
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2980
|
+
function buildSizingStyleTag(sizing) {
|
|
2981
|
+
if (!hasSizing(sizing)) return "";
|
|
2982
|
+
const hasCssSizing = sizing.preferredHeight !== void 0 || sizing.minHeight !== void 0 || sizing.maxHeight !== void 0 || sizing.aspectRatio !== void 0;
|
|
2983
|
+
if (!hasCssSizing) return "";
|
|
2984
|
+
const rootRules = [];
|
|
2985
|
+
const docRules = ["margin: 0;"];
|
|
2986
|
+
if (sizing.preferredHeight !== void 0) {
|
|
2987
|
+
const h = toCssLength(sizing.preferredHeight);
|
|
2988
|
+
docRules.push(`height: ${h};`);
|
|
2989
|
+
rootRules.push(`min-height: ${h};`);
|
|
2990
|
+
}
|
|
2991
|
+
if (sizing.minHeight !== void 0) {
|
|
2992
|
+
const mh = toCssLength(sizing.minHeight);
|
|
2993
|
+
docRules.push(`min-height: ${mh};`);
|
|
2994
|
+
rootRules.push(`min-height: ${mh};`);
|
|
2995
|
+
}
|
|
2996
|
+
if (sizing.maxHeight !== void 0) {
|
|
2997
|
+
const mx = toCssLength(sizing.maxHeight);
|
|
2998
|
+
docRules.push(`max-height: ${mx};`);
|
|
2999
|
+
rootRules.push(`max-height: ${mx};`);
|
|
3000
|
+
}
|
|
3001
|
+
if (sizing.aspectRatio !== void 0) {
|
|
3002
|
+
const ar = typeof sizing.aspectRatio === "number" ? String(sizing.aspectRatio) : sanitizeCssValue(sizing.aspectRatio);
|
|
3003
|
+
if (ar) rootRules.push(`aspect-ratio: ${ar};`);
|
|
3004
|
+
}
|
|
3005
|
+
const parts = [`html, body { ${docRules.join(" ")} }`];
|
|
3006
|
+
if (rootRules.length > 0) {
|
|
3007
|
+
parts.push(`#root { ${rootRules.join(" ")} }`);
|
|
3008
|
+
}
|
|
3009
|
+
return `<style>${parts.join("\n")}</style>`;
|
|
2804
3010
|
}
|
|
2805
3011
|
|
|
2806
3012
|
// libs/uipack/src/shell/builder.ts
|
|
3013
|
+
function resolveDataInjectionScript(args) {
|
|
3014
|
+
if (args.dataInjection) {
|
|
3015
|
+
return buildCustomDataInjectionScript(args.dataInjection);
|
|
3016
|
+
}
|
|
3017
|
+
return buildDataInjectionScript({
|
|
3018
|
+
toolName: args.toolName,
|
|
3019
|
+
input: args.input,
|
|
3020
|
+
output: args.output,
|
|
3021
|
+
structuredContent: args.structuredContent,
|
|
3022
|
+
sizing: args.sizing
|
|
3023
|
+
});
|
|
3024
|
+
}
|
|
2807
3025
|
function buildShell(content, config) {
|
|
2808
|
-
const {
|
|
2809
|
-
|
|
2810
|
-
|
|
3026
|
+
const {
|
|
3027
|
+
toolName,
|
|
3028
|
+
csp,
|
|
3029
|
+
withShell = true,
|
|
3030
|
+
input,
|
|
3031
|
+
output,
|
|
3032
|
+
structuredContent,
|
|
3033
|
+
includeBridge = true,
|
|
3034
|
+
title,
|
|
3035
|
+
sizing
|
|
3036
|
+
} = config;
|
|
3037
|
+
const { customShell, dataInjection } = config;
|
|
3038
|
+
const dataScript = resolveDataInjectionScript({
|
|
3039
|
+
dataInjection,
|
|
3040
|
+
toolName,
|
|
3041
|
+
input,
|
|
3042
|
+
output,
|
|
3043
|
+
structuredContent,
|
|
3044
|
+
sizing
|
|
3045
|
+
});
|
|
2811
3046
|
if (!withShell) {
|
|
2812
3047
|
const html2 = `${dataScript}
|
|
2813
3048
|
${content}`;
|
|
@@ -2825,7 +3060,9 @@ ${content}`;
|
|
|
2825
3060
|
output,
|
|
2826
3061
|
structuredContent,
|
|
2827
3062
|
includeBridge,
|
|
2828
|
-
title
|
|
3063
|
+
title,
|
|
3064
|
+
sizing,
|
|
3065
|
+
dataInjection
|
|
2829
3066
|
});
|
|
2830
3067
|
}
|
|
2831
3068
|
const headParts = [
|
|
@@ -2837,6 +3074,10 @@ ${content}`;
|
|
|
2837
3074
|
}
|
|
2838
3075
|
headParts.push(buildCSPMetaTag(csp));
|
|
2839
3076
|
headParts.push(dataScript);
|
|
3077
|
+
const sizingStyle = buildSizingStyleTag(sizing);
|
|
3078
|
+
if (sizingStyle) {
|
|
3079
|
+
headParts.push(sizingStyle);
|
|
3080
|
+
}
|
|
2840
3081
|
if (includeBridge) {
|
|
2841
3082
|
const bridgeScript = generateBridgeIIFE({ minify: true });
|
|
2842
3083
|
headParts.push(`<script>${bridgeScript}</script>`);
|
|
@@ -2870,12 +3111,17 @@ function buildCustomShell(content, customShell, ctx) {
|
|
|
2870
3111
|
template = customShell.template;
|
|
2871
3112
|
}
|
|
2872
3113
|
const cspTag = buildCSPMetaTag(ctx.csp);
|
|
2873
|
-
const dataScript =
|
|
3114
|
+
const dataScript = resolveDataInjectionScript({
|
|
3115
|
+
dataInjection: ctx.dataInjection,
|
|
2874
3116
|
toolName: ctx.toolName,
|
|
2875
3117
|
input: ctx.input,
|
|
2876
3118
|
output: ctx.output,
|
|
2877
|
-
structuredContent: ctx.structuredContent
|
|
3119
|
+
structuredContent: ctx.structuredContent,
|
|
3120
|
+
sizing: ctx.sizing
|
|
2878
3121
|
});
|
|
3122
|
+
const sizingStyle = buildSizingStyleTag(ctx.sizing);
|
|
3123
|
+
const dataWithSizing = sizingStyle ? `${dataScript}
|
|
3124
|
+
${sizingStyle}` : dataScript;
|
|
2879
3125
|
let bridgeHtml = "";
|
|
2880
3126
|
if (ctx.includeBridge) {
|
|
2881
3127
|
const bridgeScript = generateBridgeIIFE({ minify: true });
|
|
@@ -2883,7 +3129,7 @@ function buildCustomShell(content, customShell, ctx) {
|
|
|
2883
3129
|
}
|
|
2884
3130
|
const html = applyShellTemplate(template, {
|
|
2885
3131
|
csp: cspTag,
|
|
2886
|
-
data:
|
|
3132
|
+
data: dataWithSizing,
|
|
2887
3133
|
bridge: bridgeHtml,
|
|
2888
3134
|
content,
|
|
2889
3135
|
title: ctx.title ? escapeHtmlForTag(ctx.title) : ""
|
|
@@ -3030,6 +3276,29 @@ function isFunctionSource(source) {
|
|
|
3030
3276
|
}
|
|
3031
3277
|
var FRONTMCP_META_KEY = "__frontmcp_meta";
|
|
3032
3278
|
|
|
3279
|
+
// libs/uipack/src/component/ui-availability.ts
|
|
3280
|
+
function isFrontmcpUiResolvable(...candidatePaths) {
|
|
3281
|
+
try {
|
|
3282
|
+
const nodeFs = __require("fs");
|
|
3283
|
+
const nodePath = __require("path");
|
|
3284
|
+
const ORG = "@frontmcp";
|
|
3285
|
+
const PKG = "ui";
|
|
3286
|
+
for (const candidate of candidatePaths) {
|
|
3287
|
+
let dir = candidate;
|
|
3288
|
+
while (true) {
|
|
3289
|
+
const pkgJson = nodePath.join(dir, "node_modules", ORG, PKG, "package.json");
|
|
3290
|
+
if (nodeFs.existsSync(pkgJson)) return true;
|
|
3291
|
+
const parent = nodePath.dirname(dir);
|
|
3292
|
+
if (parent === dir) break;
|
|
3293
|
+
dir = parent;
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
return false;
|
|
3297
|
+
} catch {
|
|
3298
|
+
return false;
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
|
|
3033
3302
|
// libs/uipack/src/component/transpiler.ts
|
|
3034
3303
|
function transpileReactSource(source, filename) {
|
|
3035
3304
|
const esbuild = __require("esbuild");
|
|
@@ -3045,7 +3314,12 @@ function transpileReactSource(source, filename) {
|
|
|
3045
3314
|
});
|
|
3046
3315
|
return result.code;
|
|
3047
3316
|
}
|
|
3048
|
-
function bundleFileSource(source, filename, resolveDir, componentName) {
|
|
3317
|
+
function bundleFileSource(source, filename, resolveDir, componentName, options = {}) {
|
|
3318
|
+
if (!isFrontmcpUiResolvable(resolveDir, process.cwd())) {
|
|
3319
|
+
throw new Error(
|
|
3320
|
+
`FileSource widget "${filename}" requires the @frontmcp/ui package, which provides the React bridge mount that's injected at bundle time. Install it (e.g. \`npm install @frontmcp/ui\` or \`yarn add @frontmcp/ui\`) and try again.`
|
|
3321
|
+
);
|
|
3322
|
+
}
|
|
3049
3323
|
const esbuild = __require("esbuild");
|
|
3050
3324
|
const mountCode = `
|
|
3051
3325
|
// --- Auto-generated mount ---
|
|
@@ -3127,7 +3401,11 @@ if (__root) {
|
|
|
3127
3401
|
format: "esm",
|
|
3128
3402
|
target: "es2020",
|
|
3129
3403
|
jsx: "automatic",
|
|
3130
|
-
|
|
3404
|
+
// When `bundleReact` is set (resourceMode: 'inline'), React itself is
|
|
3405
|
+
// bundled — required for hosts that block external script execution
|
|
3406
|
+
// such as Claude (#454). Otherwise React stays external and is loaded
|
|
3407
|
+
// via the import map emitted by the renderer.
|
|
3408
|
+
external: options.bundleReact ? [] : ["react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime"],
|
|
3131
3409
|
alias,
|
|
3132
3410
|
define: { "process.env.NODE_ENV": '"production"' },
|
|
3133
3411
|
platform: "browser",
|
|
@@ -3139,7 +3417,7 @@ if (__root) {
|
|
|
3139
3417
|
} catch (err) {
|
|
3140
3418
|
const message = err instanceof Error ? err.message : String(err);
|
|
3141
3419
|
throw new Error(
|
|
3142
|
-
`Failed to bundle FileSource "${filename}": ${message}.
|
|
3420
|
+
`Failed to bundle FileSource "${filename}": ${message}. If the error mentions @frontmcp/ui or @frontmcp/uipack, ensure both packages are installed in the consuming project.`
|
|
3143
3421
|
);
|
|
3144
3422
|
}
|
|
3145
3423
|
}
|
|
@@ -3157,6 +3435,9 @@ var DEFAULT_META = {
|
|
|
3157
3435
|
renderer: "auto"
|
|
3158
3436
|
};
|
|
3159
3437
|
function resolveUISource(source, options) {
|
|
3438
|
+
if (options?.inlineReact && options?.transformOnly) {
|
|
3439
|
+
throw new Error("resolveUISource: `inlineReact` and `transformOnly` are mutually exclusive \u2014 set at most one.");
|
|
3440
|
+
}
|
|
3160
3441
|
const resolver = options?.resolver ?? createEsmShResolver();
|
|
3161
3442
|
if (isNpmSource(source)) {
|
|
3162
3443
|
return resolveNpmSource(source, resolver);
|
|
@@ -3165,7 +3446,7 @@ function resolveUISource(source, options) {
|
|
|
3165
3446
|
return resolveImportSource(source);
|
|
3166
3447
|
}
|
|
3167
3448
|
if (isFileSource(source)) {
|
|
3168
|
-
return resolveFileSource(source);
|
|
3449
|
+
return resolveFileSource(source, { inlineReact: options?.inlineReact, transformOnly: options?.transformOnly });
|
|
3169
3450
|
}
|
|
3170
3451
|
if (isFunctionSource(source)) {
|
|
3171
3452
|
return resolveFunctionSource(source, options?.input, options?.output);
|
|
@@ -3198,15 +3479,42 @@ function resolveImportSource(source) {
|
|
|
3198
3479
|
peerDependencies: []
|
|
3199
3480
|
};
|
|
3200
3481
|
}
|
|
3201
|
-
function resolveFileSource(source) {
|
|
3482
|
+
function resolveFileSource(source, options = {}) {
|
|
3202
3483
|
const path = __require("path");
|
|
3203
3484
|
const ext = path.extname(source.file).toLowerCase();
|
|
3204
3485
|
if (ext === ".tsx" || ext === ".jsx") {
|
|
3205
3486
|
const fs = __require("fs");
|
|
3206
|
-
const
|
|
3207
|
-
const
|
|
3487
|
+
const wasRelative = !path.isAbsolute(source.file);
|
|
3488
|
+
const filePath = wasRelative ? path.resolve(process.cwd(), source.file) : source.file;
|
|
3489
|
+
let rawSource;
|
|
3490
|
+
try {
|
|
3491
|
+
rawSource = fs.readFileSync(filePath, "utf-8");
|
|
3492
|
+
} catch (err) {
|
|
3493
|
+
const isNotFound = err?.code === "ENOENT";
|
|
3494
|
+
if (isNotFound && wasRelative) {
|
|
3495
|
+
throw new Error(
|
|
3496
|
+
`FileSource widget "${source.file}" not found at "${filePath}". Relative paths are resolved against process.cwd() ("${process.cwd()}"), not the tool file's directory. To anchor the path to the tool file, pass an absolute path \u2014 e.g. \`{ file: fileURLToPath(new URL('./widget.tsx', import.meta.url)) }\` from \`node:url\` (see issue #444).`
|
|
3497
|
+
);
|
|
3498
|
+
}
|
|
3499
|
+
throw err;
|
|
3500
|
+
}
|
|
3208
3501
|
const componentName = source.exportName || extractDefaultExportName(rawSource) || "Component";
|
|
3209
|
-
|
|
3502
|
+
if (options.transformOnly === true) {
|
|
3503
|
+
const code = transpileReactSource(rawSource, path.basename(filePath));
|
|
3504
|
+
const parsed2 = parseImports(code);
|
|
3505
|
+
return {
|
|
3506
|
+
mode: "module",
|
|
3507
|
+
code,
|
|
3508
|
+
imports: [...new Set(parsed2.externalImports.map((i) => i.specifier))],
|
|
3509
|
+
exportName: componentName,
|
|
3510
|
+
meta: { mcpAware: true, renderer: "react" },
|
|
3511
|
+
peerDependencies: source.peerDependencies || ["react", "react-dom"],
|
|
3512
|
+
bundled: false
|
|
3513
|
+
};
|
|
3514
|
+
}
|
|
3515
|
+
const bundled = bundleFileSource(rawSource, source.file, path.dirname(filePath), componentName, {
|
|
3516
|
+
bundleReact: options.inlineReact === true
|
|
3517
|
+
});
|
|
3210
3518
|
const parsed = parseImports(bundled.code);
|
|
3211
3519
|
return {
|
|
3212
3520
|
mode: "module",
|
|
@@ -3275,12 +3583,18 @@ function generateMappedPropsCode(mapping) {
|
|
|
3275
3583
|
}
|
|
3276
3584
|
|
|
3277
3585
|
// libs/uipack/src/component/renderer.ts
|
|
3586
|
+
var DEFAULT_WIDGET_MOUNT = {
|
|
3587
|
+
moduleSpecifier: "@frontmcp/ui/react",
|
|
3588
|
+
wrapperImportName: "McpBridgeProvider"
|
|
3589
|
+
};
|
|
3278
3590
|
function renderComponent(config, shellConfig) {
|
|
3279
3591
|
const resolver = shellConfig.resolver ?? createEsmShResolver();
|
|
3280
3592
|
const resolved = resolveUISource(config.source, {
|
|
3281
3593
|
resolver,
|
|
3282
3594
|
input: shellConfig.input,
|
|
3283
|
-
output: shellConfig.output
|
|
3595
|
+
output: shellConfig.output,
|
|
3596
|
+
inlineReact: config.inlineReact === true,
|
|
3597
|
+
transformOnly: config.transformOnly === true
|
|
3284
3598
|
});
|
|
3285
3599
|
const mergedShellConfig = {
|
|
3286
3600
|
...shellConfig,
|
|
@@ -3291,10 +3605,10 @@ function renderComponent(config, shellConfig) {
|
|
|
3291
3605
|
if (resolved.mode === "inline") {
|
|
3292
3606
|
return buildShell(resolved.html ?? "", mergedShellConfig);
|
|
3293
3607
|
}
|
|
3294
|
-
const content = buildModuleContent(resolved, resolver, config.props);
|
|
3608
|
+
const content = buildModuleContent(resolved, resolver, config.props, shellConfig.mount);
|
|
3295
3609
|
return buildShell(content, mergedShellConfig);
|
|
3296
3610
|
}
|
|
3297
|
-
function buildModuleContent(resolved, resolver, propsMapping) {
|
|
3611
|
+
function buildModuleContent(resolved, resolver, propsMapping, mount = DEFAULT_WIDGET_MOUNT) {
|
|
3298
3612
|
const parts = [];
|
|
3299
3613
|
if (resolved.code && resolved.bundled) {
|
|
3300
3614
|
const importEntries = {};
|
|
@@ -3318,14 +3632,16 @@ ${resolved.code}
|
|
|
3318
3632
|
...resolved.imports || [],
|
|
3319
3633
|
"react-dom/client",
|
|
3320
3634
|
// needed by mount script
|
|
3321
|
-
|
|
3322
|
-
//
|
|
3635
|
+
mount.moduleSpecifier,
|
|
3636
|
+
// mounter/provider package (e.g. @frontmcp/ui/react)
|
|
3323
3637
|
// React subpath entries needed by esm.sh externalized modules:
|
|
3324
3638
|
"react/jsx-runtime",
|
|
3325
|
-
"react/jsx-dev-runtime"
|
|
3326
|
-
"react-dom/server",
|
|
3327
|
-
"react-dom/static"
|
|
3639
|
+
"react/jsx-dev-runtime"
|
|
3328
3640
|
]);
|
|
3641
|
+
if (mount === DEFAULT_WIDGET_MOUNT) {
|
|
3642
|
+
allSpecifiers.add("react-dom/server");
|
|
3643
|
+
allSpecifiers.add("react-dom/static");
|
|
3644
|
+
}
|
|
3329
3645
|
const coreDeps = /* @__PURE__ */ new Set([
|
|
3330
3646
|
"react",
|
|
3331
3647
|
"react-dom",
|
|
@@ -3356,8 +3672,9 @@ ${resolved.code}
|
|
|
3356
3672
|
const importMap = createImportMapFromResolved(importEntries);
|
|
3357
3673
|
parts.push(generateImportMapScriptTag(importMap));
|
|
3358
3674
|
}
|
|
3359
|
-
|
|
3360
|
-
|
|
3675
|
+
const mountNodeId = mount.mountNodeId ?? "root";
|
|
3676
|
+
parts.push(`<div id="${mountNodeId}">${mount.mountNodeInnerHtml ?? ""}</div>`);
|
|
3677
|
+
const mountCode = generateInlineMountCode(resolved.exportName, mount);
|
|
3361
3678
|
parts.push(`<script type="module">
|
|
3362
3679
|
${resolved.code}
|
|
3363
3680
|
${mountCode}
|
|
@@ -3394,15 +3711,21 @@ function addExternalParam(url, externals) {
|
|
|
3394
3711
|
const sep = url.includes("?") ? "&" : "?";
|
|
3395
3712
|
return `${url}${sep}external=${externals.join(",")}`;
|
|
3396
3713
|
}
|
|
3397
|
-
function generateInlineMountCode(componentName) {
|
|
3714
|
+
function generateInlineMountCode(componentName, mount) {
|
|
3715
|
+
if (mount.generate) {
|
|
3716
|
+
return mount.generate(componentName);
|
|
3717
|
+
}
|
|
3718
|
+
const wrapperName = mount.wrapperImportName ?? "McpBridgeProvider";
|
|
3719
|
+
const wrapperAlias = `__${wrapperName}`;
|
|
3720
|
+
const mountNodeId = mount.mountNodeId ?? "root";
|
|
3398
3721
|
return `
|
|
3399
3722
|
// --- Mount ---
|
|
3400
3723
|
import { createRoot as __createRoot } from 'react-dom/client';
|
|
3401
|
-
import {
|
|
3402
|
-
const __root = document.getElementById('
|
|
3724
|
+
import { ${wrapperName} as ${wrapperAlias} } from '${mount.moduleSpecifier}';
|
|
3725
|
+
const __root = document.getElementById('${mountNodeId}');
|
|
3403
3726
|
if (__root) {
|
|
3404
3727
|
__createRoot(__root).render(
|
|
3405
|
-
React.createElement(
|
|
3728
|
+
React.createElement(${wrapperAlias}, null,
|
|
3406
3729
|
React.createElement(${componentName})
|
|
3407
3730
|
)
|
|
3408
3731
|
);
|
|
@@ -3478,38 +3801,6 @@ function isUIRenderFailure(result) {
|
|
|
3478
3801
|
return typeof rec["reason"] === "string" && !("meta" in rec);
|
|
3479
3802
|
}
|
|
3480
3803
|
|
|
3481
|
-
// libs/uipack/src/adapters/type-detector.ts
|
|
3482
|
-
function detectUIType(template) {
|
|
3483
|
-
if (template === null || template === void 0) {
|
|
3484
|
-
return "auto";
|
|
3485
|
-
}
|
|
3486
|
-
if (typeof template === "object" && template !== null && "file" in template) {
|
|
3487
|
-
const file = template.file;
|
|
3488
|
-
if (/\.(tsx|jsx)$/i.test(file)) return "react";
|
|
3489
|
-
}
|
|
3490
|
-
if (typeof template === "function") {
|
|
3491
|
-
const proto = template.prototype;
|
|
3492
|
-
if (proto && typeof proto.render === "function") {
|
|
3493
|
-
return "react";
|
|
3494
|
-
}
|
|
3495
|
-
const asRecord = template;
|
|
3496
|
-
if (asRecord["$$typeof"] !== void 0) {
|
|
3497
|
-
return "react";
|
|
3498
|
-
}
|
|
3499
|
-
if (template.name && /^[A-Z]/.test(template.name)) {
|
|
3500
|
-
return "react";
|
|
3501
|
-
}
|
|
3502
|
-
return "html";
|
|
3503
|
-
}
|
|
3504
|
-
if (typeof template === "string") {
|
|
3505
|
-
if (template.includes("<") && template.includes(">")) {
|
|
3506
|
-
return "html";
|
|
3507
|
-
}
|
|
3508
|
-
return "markdown";
|
|
3509
|
-
}
|
|
3510
|
-
return "auto";
|
|
3511
|
-
}
|
|
3512
|
-
|
|
3513
3804
|
// libs/uipack/src/adapters/content-detector.ts
|
|
3514
3805
|
var CHART_TYPES = /* @__PURE__ */ new Set(["bar", "line", "pie", "area", "scatter", "doughnut", "radar", "polarArea", "bubble"]);
|
|
3515
3806
|
var MERMAID_PREFIXES = [
|
|
@@ -3650,6 +3941,38 @@ function wrapDetectedContent(value) {
|
|
|
3650
3941
|
}
|
|
3651
3942
|
}
|
|
3652
3943
|
|
|
3944
|
+
// libs/uipack/src/adapters/type-detector.ts
|
|
3945
|
+
function detectUIType(template) {
|
|
3946
|
+
if (template === null || template === void 0) {
|
|
3947
|
+
return "auto";
|
|
3948
|
+
}
|
|
3949
|
+
if (typeof template === "object" && template !== null && "file" in template) {
|
|
3950
|
+
const file = template.file;
|
|
3951
|
+
if (/\.(tsx|jsx)$/i.test(file)) return "react";
|
|
3952
|
+
}
|
|
3953
|
+
if (typeof template === "function") {
|
|
3954
|
+
const proto = template.prototype;
|
|
3955
|
+
if (proto && typeof proto.render === "function") {
|
|
3956
|
+
return "react";
|
|
3957
|
+
}
|
|
3958
|
+
const asRecord = template;
|
|
3959
|
+
if (asRecord["$$typeof"] !== void 0) {
|
|
3960
|
+
return "react";
|
|
3961
|
+
}
|
|
3962
|
+
if (template.name && /^[A-Z]/.test(template.name)) {
|
|
3963
|
+
return "react";
|
|
3964
|
+
}
|
|
3965
|
+
return "html";
|
|
3966
|
+
}
|
|
3967
|
+
if (typeof template === "string") {
|
|
3968
|
+
if (template.includes("<") && template.includes(">")) {
|
|
3969
|
+
return "html";
|
|
3970
|
+
}
|
|
3971
|
+
return "markdown";
|
|
3972
|
+
}
|
|
3973
|
+
return "auto";
|
|
3974
|
+
}
|
|
3975
|
+
|
|
3653
3976
|
// libs/uipack/src/adapters/template-renderer.ts
|
|
3654
3977
|
function buildCspConfig(resolver) {
|
|
3655
3978
|
const cspResourceDomains = ["https://esm.sh"];
|
|
@@ -3670,21 +3993,26 @@ function buildCspConfig(resolver) {
|
|
|
3670
3993
|
return { resourceDomains: cspResourceDomains, connectDomains: cspConnectDomains };
|
|
3671
3994
|
}
|
|
3672
3995
|
function renderToolTemplate(options) {
|
|
3673
|
-
const { toolName, input, output, template, resolver } = options;
|
|
3996
|
+
const { toolName, input, output, template, resolver, platformType, sizing } = options;
|
|
3674
3997
|
const uiType = detectUIType(template);
|
|
3998
|
+
const resourceMode = options.resourceMode ?? (platformType === "claude" ? "inline" : "cdn");
|
|
3675
3999
|
const shellConfig = {
|
|
3676
4000
|
toolName,
|
|
3677
4001
|
input,
|
|
3678
4002
|
output,
|
|
3679
4003
|
includeBridge: true,
|
|
3680
|
-
resolver
|
|
4004
|
+
resolver,
|
|
4005
|
+
sizing
|
|
3681
4006
|
};
|
|
3682
4007
|
let html;
|
|
3683
4008
|
let hash = "";
|
|
3684
4009
|
let size = 0;
|
|
3685
4010
|
if (typeof template === "object" && template !== null && "file" in template) {
|
|
3686
4011
|
const cspConfig = buildCspConfig(resolver);
|
|
3687
|
-
const result = renderComponent(
|
|
4012
|
+
const result = renderComponent(
|
|
4013
|
+
{ source: template, inlineReact: resourceMode === "inline" },
|
|
4014
|
+
{ ...shellConfig, csp: cspConfig }
|
|
4015
|
+
);
|
|
3688
4016
|
html = result.html;
|
|
3689
4017
|
hash = result.hash;
|
|
3690
4018
|
size = result.size;
|
|
@@ -3726,6 +4054,12 @@ function renderToolTemplate(options) {
|
|
|
3726
4054
|
"ui/type": uiType,
|
|
3727
4055
|
"ui/mimeType": MCP_APPS_MIME_TYPE
|
|
3728
4056
|
};
|
|
4057
|
+
if (hasSizing(sizing)) {
|
|
4058
|
+
if (sizing.preferredHeight !== void 0) meta["ui/preferredHeight"] = sizing.preferredHeight;
|
|
4059
|
+
if (sizing.minHeight !== void 0) meta["ui/minHeight"] = sizing.minHeight;
|
|
4060
|
+
if (sizing.maxHeight !== void 0) meta["ui/maxHeight"] = sizing.maxHeight;
|
|
4061
|
+
if (sizing.aspectRatio !== void 0) meta["ui/aspectRatio"] = sizing.aspectRatio;
|
|
4062
|
+
}
|
|
3729
4063
|
return {
|
|
3730
4064
|
html,
|
|
3731
4065
|
uiType,
|
|
@@ -3830,6 +4164,7 @@ export {
|
|
|
3830
4164
|
buildCSPDirectives,
|
|
3831
4165
|
buildCSPMetaTag,
|
|
3832
4166
|
buildChartHtml,
|
|
4167
|
+
buildCustomDataInjectionScript,
|
|
3833
4168
|
buildDataInjectionScript,
|
|
3834
4169
|
buildMermaidHtml,
|
|
3835
4170
|
buildPdfHtml,
|