@frontmcp/uipack 1.10.9-rc.1 → 1.10.9-rc.3

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 CHANGED
@@ -1,649 +1,6 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // libs/uipack/src/adapters/index.ts
21
- var adapters_exports = {};
22
- __export(adapters_exports, {
23
- MCP_APPS_EXTENSION_ID: () => MCP_APPS_EXTENSION_ID,
24
- MCP_APPS_MIME_TYPE: () => MCP_APPS_MIME_TYPE,
25
- buildCDNInfoForUIType: () => buildCDNInfoForUIType,
26
- buildChartHtml: () => buildChartHtml,
27
- buildMermaidHtml: () => buildMermaidHtml,
28
- buildPdfHtml: () => buildPdfHtml,
29
- buildToolResponseContent: () => buildToolResponseContent,
30
- createDefaultBaseTemplate: () => createDefaultBaseTemplate,
31
- detectContentType: () => detectContentType,
32
- detectUIType: () => detectUIType,
33
- isUIRenderFailure: () => isUIRenderFailure,
34
- renderToolTemplate: () => renderToolTemplate,
35
- resolveServingMode: () => resolveServingMode,
36
- warnIfComponentReference: () => warnIfComponentReference,
37
- wrapDetectedContent: () => wrapDetectedContent
38
- });
39
- module.exports = __toCommonJS(adapters_exports);
40
-
41
- // libs/uipack/src/adapters/constants.ts
42
- var MCP_APPS_MIME_TYPE = "text/html;profile=mcp-app";
43
- var MCP_APPS_EXTENSION_ID = "io.modelcontextprotocol/ui";
44
-
45
- // libs/uipack/src/adapters/serving-mode.ts
46
- function resolveServingMode(options) {
47
- const { configuredMode, platformType } = options;
48
- if (platformType === "gemini") {
49
- return {
50
- mode: configuredMode,
51
- supportsUI: false,
52
- effectiveMode: null,
53
- useStructuredContent: false,
54
- reason: "Gemini does not support MCP Apps UI"
55
- };
56
- }
57
- const effectiveMode = configuredMode === "auto" ? "inline" : configuredMode;
58
- if (effectiveMode === "hybrid") {
59
- const hybridCapable = platformType === "openai" || platformType === "ext-apps" || platformType === "cursor";
60
- if (!hybridCapable) {
61
- return {
62
- mode: configuredMode,
63
- supportsUI: false,
64
- effectiveMode: null,
65
- useStructuredContent: false,
66
- reason: `Platform ${platformType} does not support hybrid serving mode`
67
- };
68
- }
69
- }
70
- const useStructuredContent = platformType === "openai" || platformType === "ext-apps" || platformType === "generic-mcp" || platformType === "unknown";
71
- return {
72
- mode: configuredMode,
73
- supportsUI: true,
74
- effectiveMode,
75
- useStructuredContent,
76
- reason: `Platform ${platformType} supports UI, mode: ${effectiveMode}`
77
- };
78
- }
79
-
80
- // libs/uipack/src/adapters/response-builder.ts
81
- function buildToolResponseContent(options) {
82
- const { rawOutput, htmlContent, servingMode, useStructuredContent, platformType } = options;
83
- const textSummary = typeof rawOutput === "string" ? rawOutput : rawOutput !== null && rawOutput !== void 0 ? JSON.stringify(rawOutput) : "";
84
- const result = {
85
- content: [{ type: "text", text: textSummary }]
86
- };
87
- if (useStructuredContent && rawOutput !== null && rawOutput !== void 0) {
88
- const structured = typeof rawOutput === "object" && !Array.isArray(rawOutput) ? rawOutput : { value: rawOutput };
89
- result.structuredContent = structured;
90
- }
91
- if (htmlContent && servingMode === "inline") {
92
- const htmlKey = "ui/html";
93
- result._meta = {
94
- [htmlKey]: htmlContent
95
- };
96
- result.format = "html";
97
- }
98
- return result;
99
- }
100
-
101
- // libs/uipack/src/adapters/render-failure.ts
102
- function isUIRenderFailure(result) {
103
- if (typeof result !== "object" || result === null) {
104
- return false;
105
- }
106
- const rec = result;
107
- return typeof rec["reason"] === "string" && !("meta" in rec);
108
- }
109
-
110
- // libs/uipack/src/resolver/cdn-registry.ts
111
- var DEFAULT_CDN_REGISTRY = {
112
- react: {
113
- packageName: "react",
114
- defaultVersion: "19.2.4",
115
- providers: {
116
- cloudflare: {
117
- url: "https://cdnjs.cloudflare.com/ajax/libs/react/19.2.4/umd/react.production.min.js",
118
- global: "React",
119
- crossorigin: "anonymous"
120
- },
121
- jsdelivr: {
122
- url: "https://cdn.jsdelivr.net/npm/react@19.2.4/umd/react.production.min.js",
123
- global: "React",
124
- crossorigin: "anonymous"
125
- },
126
- unpkg: {
127
- url: "https://unpkg.com/react@19.2.4/umd/react.production.min.js",
128
- global: "React",
129
- crossorigin: "anonymous"
130
- },
131
- "esm.sh": {
132
- url: "https://esm.sh/react@19.2.4",
133
- esm: true,
134
- crossorigin: "anonymous"
135
- }
136
- },
137
- preferredProviders: ["esm.sh", "cloudflare", "jsdelivr", "unpkg"],
138
- metadata: {
139
- description: "A JavaScript library for building user interfaces",
140
- homepage: "https://react.dev",
141
- license: "MIT"
142
- }
143
- },
144
- "react-dom": {
145
- packageName: "react-dom",
146
- defaultVersion: "19.2.4",
147
- providers: {
148
- cloudflare: {
149
- url: "https://cdnjs.cloudflare.com/ajax/libs/react-dom/19.2.4/umd/react-dom.production.min.js",
150
- global: "ReactDOM",
151
- crossorigin: "anonymous",
152
- peerDependencies: ["react"]
153
- },
154
- jsdelivr: {
155
- url: "https://cdn.jsdelivr.net/npm/react-dom@19.2.4/umd/react-dom.production.min.js",
156
- global: "ReactDOM",
157
- crossorigin: "anonymous",
158
- peerDependencies: ["react"]
159
- },
160
- unpkg: {
161
- url: "https://unpkg.com/react-dom@19.2.4/umd/react-dom.production.min.js",
162
- global: "ReactDOM",
163
- crossorigin: "anonymous",
164
- peerDependencies: ["react"]
165
- },
166
- "esm.sh": {
167
- url: "https://esm.sh/react-dom@19.2.4",
168
- esm: true,
169
- crossorigin: "anonymous",
170
- peerDependencies: ["react"]
171
- }
172
- },
173
- preferredProviders: ["esm.sh", "cloudflare", "jsdelivr", "unpkg"],
174
- metadata: {
175
- description: "React package for working with the DOM",
176
- homepage: "https://react.dev",
177
- license: "MIT"
178
- }
179
- },
180
- "chart.js": {
181
- packageName: "chart.js",
182
- defaultVersion: "4.5.1",
183
- providers: {
184
- cloudflare: {
185
- url: "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.5.1/chart.umd.min.js",
186
- global: "Chart",
187
- crossorigin: "anonymous"
188
- },
189
- jsdelivr: {
190
- url: "https://cdn.jsdelivr.net/npm/chart.js@4.5.1/dist/chart.umd.min.js",
191
- global: "Chart",
192
- crossorigin: "anonymous"
193
- },
194
- unpkg: {
195
- url: "https://unpkg.com/chart.js@4.5.1/dist/chart.umd.min.js",
196
- global: "Chart",
197
- crossorigin: "anonymous"
198
- }
199
- },
200
- preferredProviders: ["esm.sh", "cloudflare", "jsdelivr", "unpkg"],
201
- metadata: {
202
- description: "Simple yet flexible JavaScript charting library",
203
- homepage: "https://www.chartjs.org",
204
- license: "MIT"
205
- }
206
- },
207
- d3: {
208
- packageName: "d3",
209
- defaultVersion: "7.9.0",
210
- providers: {
211
- cloudflare: {
212
- url: "https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js",
213
- integrity: "sha512-vc58qvvBdrDR4etbxMdlTt4GBQk1qjvyORR2nrsPsFPyrs+/u5c3+1Ct6upOgdZoIl7eq6k3a1UPDSNAQi/32A==",
214
- global: "d3",
215
- crossorigin: "anonymous"
216
- },
217
- jsdelivr: {
218
- url: "https://cdn.jsdelivr.net/npm/d3@7.9.0/dist/d3.min.js",
219
- global: "d3",
220
- crossorigin: "anonymous"
221
- },
222
- unpkg: {
223
- url: "https://unpkg.com/d3@7.9.0/dist/d3.min.js",
224
- global: "d3",
225
- crossorigin: "anonymous"
226
- }
227
- },
228
- preferredProviders: ["esm.sh", "cloudflare", "jsdelivr", "unpkg"],
229
- metadata: {
230
- description: "Data-Driven Documents",
231
- homepage: "https://d3js.org",
232
- license: "ISC"
233
- }
234
- },
235
- lodash: {
236
- packageName: "lodash",
237
- defaultVersion: "4.17.21",
238
- providers: {
239
- cloudflare: {
240
- url: "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js",
241
- integrity: "sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==",
242
- global: "_",
243
- crossorigin: "anonymous"
244
- },
245
- jsdelivr: {
246
- url: "https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js",
247
- global: "_",
248
- crossorigin: "anonymous"
249
- },
250
- unpkg: {
251
- url: "https://unpkg.com/lodash@4.17.21/lodash.min.js",
252
- global: "_",
253
- crossorigin: "anonymous"
254
- }
255
- },
256
- preferredProviders: ["esm.sh", "cloudflare", "jsdelivr", "unpkg"],
257
- metadata: {
258
- description: "A modern JavaScript utility library",
259
- homepage: "https://lodash.com",
260
- license: "MIT"
261
- }
262
- }
263
- };
264
- function lookupPackage(packageName, registry = DEFAULT_CDN_REGISTRY) {
265
- return registry[packageName];
266
- }
267
-
268
- // libs/uipack/src/resolver/import-parser.ts
269
- var IMPORT_PATTERNS = {
270
- named: /import\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g,
271
- default: /import\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,
272
- namespace: /import\s*\*\s*as\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,
273
- sideEffect: /import\s*['"]([^'"]+)['"]/g,
274
- dynamic: /(?:await\s+)?import\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
275
- defaultAndNamed: /import\s+(\w+)\s*,\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g,
276
- defaultAndNamespace: /import\s+(\w+)\s*,\s*\*\s*as\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,
277
- reExport: /export\s*\{[^}]+\}\s*from\s*['"]([^'"]+)['"]/g,
278
- reExportAll: /export\s*\*\s*from\s*['"]([^'"]+)['"]/g
279
- };
280
- function parseNamedImports(namedString) {
281
- return namedString.split(",").map((s) => s.trim()).filter((s) => s.length > 0).map((s) => {
282
- const asMatch = s.match(/^(\w+)\s+as\s+\w+$/);
283
- return asMatch ? asMatch[1] : s;
284
- });
285
- }
286
- function isRelativeImport(specifier) {
287
- return specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/");
288
- }
289
- function isExternalImport(specifier) {
290
- return !isRelativeImport(specifier) && !specifier.startsWith("#");
291
- }
292
- function getPackageName(specifier) {
293
- if (specifier.startsWith("@")) {
294
- const parts = specifier.split("/");
295
- if (parts.length >= 2) {
296
- return `${parts[0]}/${parts[1]}`;
297
- }
298
- return specifier;
299
- }
300
- const firstSlash = specifier.indexOf("/");
301
- return firstSlash === -1 ? specifier : specifier.slice(0, firstSlash);
302
- }
303
- function getLineNumber(source, index) {
304
- let line = 1;
305
- for (let i = 0; i < index && i < source.length; i++) {
306
- if (source[i] === "\n") {
307
- line++;
308
- }
309
- }
310
- return line;
311
- }
312
- function getColumnNumber(source, index) {
313
- let column = 0;
314
- for (let i = index - 1; i >= 0 && source[i] !== "\n"; i--) {
315
- column++;
316
- }
317
- return column;
318
- }
319
- function parseImports(source) {
320
- const imports = [];
321
- const seenStatements = /* @__PURE__ */ new Set();
322
- const addImport = (imp) => {
323
- const key = `${imp.type}:${imp.specifier}:${imp.statement}`;
324
- if (!seenStatements.has(key)) {
325
- seenStatements.add(key);
326
- imports.push(imp);
327
- }
328
- };
329
- let match;
330
- const defaultAndNamedRegex = new RegExp(IMPORT_PATTERNS.defaultAndNamed.source, "g");
331
- while ((match = defaultAndNamedRegex.exec(source)) !== null) {
332
- const [statement, defaultName, namedString, specifier] = match;
333
- addImport({
334
- statement,
335
- specifier,
336
- type: "default",
337
- defaultImport: defaultName,
338
- namedImports: parseNamedImports(namedString),
339
- line: getLineNumber(source, match.index),
340
- column: getColumnNumber(source, match.index)
341
- });
342
- }
343
- const defaultAndNamespaceRegex = new RegExp(IMPORT_PATTERNS.defaultAndNamespace.source, "g");
344
- while ((match = defaultAndNamespaceRegex.exec(source)) !== null) {
345
- const [statement, defaultName, namespaceName, specifier] = match;
346
- addImport({
347
- statement,
348
- specifier,
349
- type: "default",
350
- defaultImport: defaultName,
351
- namespaceImport: namespaceName,
352
- line: getLineNumber(source, match.index),
353
- column: getColumnNumber(source, match.index)
354
- });
355
- }
356
- const namedRegex = new RegExp(IMPORT_PATTERNS.named.source, "g");
357
- while ((match = namedRegex.exec(source)) !== null) {
358
- const [statement, namedString, specifier] = match;
359
- addImport({
360
- statement,
361
- specifier,
362
- type: "named",
363
- namedImports: parseNamedImports(namedString),
364
- line: getLineNumber(source, match.index),
365
- column: getColumnNumber(source, match.index)
366
- });
367
- }
368
- const defaultRegex = new RegExp(IMPORT_PATTERNS.default.source, "g");
369
- while ((match = defaultRegex.exec(source)) !== null) {
370
- const [statement, defaultName, specifier] = match;
371
- const afterMatch = source.slice(match.index + match[0].length - specifier.length - 2);
372
- if (afterMatch.startsWith(",")) continue;
373
- addImport({
374
- statement,
375
- specifier,
376
- type: "default",
377
- defaultImport: defaultName,
378
- line: getLineNumber(source, match.index),
379
- column: getColumnNumber(source, match.index)
380
- });
381
- }
382
- const namespaceRegex = new RegExp(IMPORT_PATTERNS.namespace.source, "g");
383
- while ((match = namespaceRegex.exec(source)) !== null) {
384
- const [statement, namespaceName, specifier] = match;
385
- addImport({
386
- statement,
387
- specifier,
388
- type: "namespace",
389
- namespaceImport: namespaceName,
390
- line: getLineNumber(source, match.index),
391
- column: getColumnNumber(source, match.index)
392
- });
393
- }
394
- const sideEffectRegex = new RegExp(IMPORT_PATTERNS.sideEffect.source, "g");
395
- while ((match = sideEffectRegex.exec(source)) !== null) {
396
- const [statement, specifier] = match;
397
- const beforeMatch = source.slice(Math.max(0, match.index - 50), match.index);
398
- if (beforeMatch.includes("from")) continue;
399
- addImport({
400
- statement,
401
- specifier,
402
- type: "side-effect",
403
- line: getLineNumber(source, match.index),
404
- column: getColumnNumber(source, match.index)
405
- });
406
- }
407
- const dynamicRegex = new RegExp(IMPORT_PATTERNS.dynamic.source, "g");
408
- while ((match = dynamicRegex.exec(source)) !== null) {
409
- const [statement, specifier] = match;
410
- addImport({
411
- statement,
412
- specifier,
413
- type: "dynamic",
414
- line: getLineNumber(source, match.index),
415
- column: getColumnNumber(source, match.index)
416
- });
417
- }
418
- const reExportRegex = new RegExp(IMPORT_PATTERNS.reExport.source, "g");
419
- while ((match = reExportRegex.exec(source)) !== null) {
420
- const [statement, specifier] = match;
421
- addImport({
422
- statement,
423
- specifier,
424
- type: "named",
425
- line: getLineNumber(source, match.index),
426
- column: getColumnNumber(source, match.index)
427
- });
428
- }
429
- const reExportAllRegex = new RegExp(IMPORT_PATTERNS.reExportAll.source, "g");
430
- while ((match = reExportAllRegex.exec(source)) !== null) {
431
- const [statement, specifier] = match;
432
- addImport({
433
- statement,
434
- specifier,
435
- type: "namespace",
436
- line: getLineNumber(source, match.index),
437
- column: getColumnNumber(source, match.index)
438
- });
439
- }
440
- const externalImports = imports.filter((imp) => isExternalImport(imp.specifier));
441
- const relativeImports = imports.filter((imp) => isRelativeImport(imp.specifier));
442
- const externalPackages = [...new Set(externalImports.map((imp) => getPackageName(imp.specifier)))];
443
- return {
444
- imports,
445
- externalImports,
446
- relativeImports,
447
- externalPackages
448
- };
449
- }
450
-
451
- // libs/uipack/src/resolver/esm-sh.resolver.ts
452
- var DEFAULT_FALLBACK_CDN = "https://esm.sh";
453
- function createEsmShResolver(options = {}) {
454
- const {
455
- fallbackCdnBase = DEFAULT_FALLBACK_CDN,
456
- registry = DEFAULT_CDN_REGISTRY,
457
- providerOrder = ["esm.sh", "cloudflare", "jsdelivr", "unpkg"]
458
- } = options;
459
- return {
460
- resolve(specifier, _context) {
461
- if (specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/")) {
462
- return null;
463
- }
464
- if (specifier.startsWith("node:") || specifier.startsWith("#")) {
465
- return null;
466
- }
467
- const pkgName = getPackageName(specifier);
468
- const entry = lookupPackage(pkgName, registry);
469
- if (entry) {
470
- for (const provider of providerOrder) {
471
- const config = entry.providers[provider];
472
- if (config?.url) {
473
- const subpath = specifier.slice(pkgName.length);
474
- if (subpath && config.url.includes("esm.sh/")) {
475
- return {
476
- value: config.url + subpath,
477
- type: "url",
478
- integrity: config.integrity
479
- };
480
- }
481
- if (subpath) {
482
- return {
483
- value: `${fallbackCdnBase}/${specifier}`,
484
- type: "url"
485
- };
486
- }
487
- if (config.global && !config.esm) {
488
- return {
489
- value: config.url,
490
- type: "url",
491
- integrity: config.integrity
492
- };
493
- }
494
- return {
495
- value: config.url,
496
- type: "url",
497
- integrity: config.integrity
498
- };
499
- }
500
- }
501
- }
502
- return {
503
- value: `${fallbackCdnBase}/${specifier}`,
504
- type: "url"
505
- };
506
- }
507
- };
508
- }
509
-
510
- // libs/uipack/src/utils/index.ts
511
- function escapeHtml(str) {
512
- if (str === null || str === void 0) {
513
- return "";
514
- }
515
- const s = String(str);
516
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
517
- }
518
- var SCRIPT_UNSAFE_CHARACTERS = /[<>&\u2028\u2029]/g;
519
- function toUnicodeEscape(character) {
520
- return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
521
- }
522
- function safeJsonForScript(value) {
523
- if (value === void 0) {
524
- return "null";
525
- }
526
- try {
527
- const jsonString = JSON.stringify(value, (_key, val) => {
528
- if (typeof val === "bigint") {
529
- return val.toString();
530
- }
531
- return val;
532
- });
533
- if (jsonString === void 0) {
534
- return "null";
535
- }
536
- return jsonString.replace(SCRIPT_UNSAFE_CHARACTERS, toUnicodeEscape);
537
- } catch {
538
- return '{"error":"Value could not be serialized"}';
539
- }
540
- }
541
-
542
- // libs/uipack/src/resolver/import-map.ts
543
- function createImportMapFromResolved(resolved) {
544
- const imports = {};
545
- const integrity = {};
546
- for (const [specifier, res] of Object.entries(resolved)) {
547
- if (res.type === "url") {
548
- imports[specifier] = res.value;
549
- if (res.integrity) {
550
- integrity[res.value] = res.integrity;
551
- }
552
- }
553
- }
554
- return {
555
- imports,
556
- integrity: Object.keys(integrity).length > 0 ? integrity : void 0
557
- };
558
- }
559
- function generateImportMapScriptTag(map) {
560
- const json = JSON.stringify(map, null, 2).replace(/<\//g, "<\\/");
561
- return `<script type="importmap">
1
+ "use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var adapters_exports={};__export(adapters_exports,{MCP_APPS_EXTENSION_ID:()=>MCP_APPS_EXTENSION_ID,MCP_APPS_MIME_TYPE:()=>MCP_APPS_MIME_TYPE,buildCDNInfoForUIType:()=>buildCDNInfoForUIType,buildChartHtml:()=>buildChartHtml,buildMermaidHtml:()=>buildMermaidHtml,buildPdfHtml:()=>buildPdfHtml,buildToolResponseContent:()=>buildToolResponseContent,createDefaultBaseTemplate:()=>createDefaultBaseTemplate,detectContentType:()=>detectContentType,detectUIType:()=>detectUIType,isUIRenderFailure:()=>isUIRenderFailure,renderToolTemplate:()=>renderToolTemplate,resolveServingMode:()=>resolveServingMode,warnIfComponentReference:()=>warnIfComponentReference,wrapDetectedContent:()=>wrapDetectedContent});module.exports=__toCommonJS(adapters_exports);var MCP_APPS_MIME_TYPE="text/html;profile=mcp-app";var MCP_APPS_EXTENSION_ID="io.modelcontextprotocol/ui";function resolveServingMode(options){const{configuredMode,platformType}=options;if(platformType==="gemini"){return{mode:configuredMode,supportsUI:false,effectiveMode:null,useStructuredContent:false,reason:"Gemini does not support MCP Apps UI"}}const effectiveMode=configuredMode==="auto"?"inline":configuredMode;if(effectiveMode==="hybrid"){const hybridCapable=platformType==="openai"||platformType==="ext-apps"||platformType==="cursor";if(!hybridCapable){return{mode:configuredMode,supportsUI:false,effectiveMode:null,useStructuredContent:false,reason:`Platform ${platformType} does not support hybrid serving mode`}}}const useStructuredContent=platformType==="openai"||platformType==="ext-apps"||platformType==="generic-mcp"||platformType==="unknown";return{mode:configuredMode,supportsUI:true,effectiveMode,useStructuredContent,reason:`Platform ${platformType} supports UI, mode: ${effectiveMode}`}}function buildToolResponseContent(options){const{rawOutput,htmlContent,servingMode,useStructuredContent,platformType}=options;const textSummary=typeof rawOutput==="string"?rawOutput:rawOutput!==null&&rawOutput!==void 0?JSON.stringify(rawOutput):"";const result={content:[{type:"text",text:textSummary}]};if(useStructuredContent&&rawOutput!==null&&rawOutput!==void 0){const structured=typeof rawOutput==="object"&&!Array.isArray(rawOutput)?rawOutput:{value:rawOutput};result.structuredContent=structured}if(htmlContent&&servingMode==="inline"){const htmlKey="ui/html";result._meta={[htmlKey]:htmlContent};result.format="html"}return result}function isUIRenderFailure(result){if(typeof result!=="object"||result===null){return false}const rec=result;return typeof rec["reason"]==="string"&&!("meta"in rec)}var DEFAULT_CDN_REGISTRY={react:{packageName:"react",defaultVersion:"19.2.4",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/react/19.2.4/umd/react.production.min.js",global:"React",crossorigin:"anonymous"},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/react@19.2.4/umd/react.production.min.js",global:"React",crossorigin:"anonymous"},unpkg:{url:"https://unpkg.com/react@19.2.4/umd/react.production.min.js",global:"React",crossorigin:"anonymous"},"esm.sh":{url:"https://esm.sh/react@19.2.4",esm:true,crossorigin:"anonymous"}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"A JavaScript library for building user interfaces",homepage:"https://react.dev",license:"MIT"}},"react-dom":{packageName:"react-dom",defaultVersion:"19.2.4",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/react-dom/19.2.4/umd/react-dom.production.min.js",global:"ReactDOM",crossorigin:"anonymous",peerDependencies:["react"]},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/react-dom@19.2.4/umd/react-dom.production.min.js",global:"ReactDOM",crossorigin:"anonymous",peerDependencies:["react"]},unpkg:{url:"https://unpkg.com/react-dom@19.2.4/umd/react-dom.production.min.js",global:"ReactDOM",crossorigin:"anonymous",peerDependencies:["react"]},"esm.sh":{url:"https://esm.sh/react-dom@19.2.4",esm:true,crossorigin:"anonymous",peerDependencies:["react"]}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"React package for working with the DOM",homepage:"https://react.dev",license:"MIT"}},"chart.js":{packageName:"chart.js",defaultVersion:"4.5.1",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.5.1/chart.umd.min.js",global:"Chart",crossorigin:"anonymous"},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/chart.js@4.5.1/dist/chart.umd.min.js",global:"Chart",crossorigin:"anonymous"},unpkg:{url:"https://unpkg.com/chart.js@4.5.1/dist/chart.umd.min.js",global:"Chart",crossorigin:"anonymous"}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"Simple yet flexible JavaScript charting library",homepage:"https://www.chartjs.org",license:"MIT"}},d3:{packageName:"d3",defaultVersion:"7.9.0",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js",integrity:"sha512-vc58qvvBdrDR4etbxMdlTt4GBQk1qjvyORR2nrsPsFPyrs+/u5c3+1Ct6upOgdZoIl7eq6k3a1UPDSNAQi/32A==",global:"d3",crossorigin:"anonymous"},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/d3@7.9.0/dist/d3.min.js",global:"d3",crossorigin:"anonymous"},unpkg:{url:"https://unpkg.com/d3@7.9.0/dist/d3.min.js",global:"d3",crossorigin:"anonymous"}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"Data-Driven Documents",homepage:"https://d3js.org",license:"ISC"}},lodash:{packageName:"lodash",defaultVersion:"4.17.21",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js",integrity:"sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==",global:"_",crossorigin:"anonymous"},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js",global:"_",crossorigin:"anonymous"},unpkg:{url:"https://unpkg.com/lodash@4.17.21/lodash.min.js",global:"_",crossorigin:"anonymous"}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"A modern JavaScript utility library",homepage:"https://lodash.com",license:"MIT"}}};function lookupPackage(packageName,registry=DEFAULT_CDN_REGISTRY){return registry[packageName]}var IMPORT_PATTERNS={named:/import\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g,default:/import\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,namespace:/import\s*\*\s*as\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,sideEffect:/import\s*['"]([^'"]+)['"]/g,dynamic:/(?:await\s+)?import\s*\(\s*['"]([^'"]+)['"]\s*\)/g,defaultAndNamed:/import\s+(\w+)\s*,\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g,defaultAndNamespace:/import\s+(\w+)\s*,\s*\*\s*as\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,reExport:/export\s*\{[^}]+\}\s*from\s*['"]([^'"]+)['"]/g,reExportAll:/export\s*\*\s*from\s*['"]([^'"]+)['"]/g};function parseNamedImports(namedString){return namedString.split(",").map(s=>s.trim()).filter(s=>s.length>0).map(s=>{const asMatch=s.match(/^(\w+)\s+as\s+\w+$/);return asMatch?asMatch[1]:s})}function isRelativeImport(specifier){return specifier.startsWith("./")||specifier.startsWith("../")||specifier.startsWith("/")}function isExternalImport(specifier){return!isRelativeImport(specifier)&&!specifier.startsWith("#")}function getPackageName(specifier){if(specifier.startsWith("@")){const parts=specifier.split("/");if(parts.length>=2){return`${parts[0]}/${parts[1]}`}return specifier}const firstSlash=specifier.indexOf("/");return firstSlash===-1?specifier:specifier.slice(0,firstSlash)}function getLineNumber(source,index){let line=1;for(let i=0;i<index&&i<source.length;i++){if(source[i]==="\n"){line++}}return line}function getColumnNumber(source,index){let column=0;for(let i=index-1;i>=0&&source[i]!=="\n";i--){column++}return column}function parseImports(source){const imports=[];const seenStatements=new Set;const addImport=imp=>{const key=`${imp.type}:${imp.specifier}:${imp.statement}`;if(!seenStatements.has(key)){seenStatements.add(key);imports.push(imp)}};let match;const defaultAndNamedRegex=new RegExp(IMPORT_PATTERNS.defaultAndNamed.source,"g");while((match=defaultAndNamedRegex.exec(source))!==null){const[statement,defaultName,namedString,specifier]=match;addImport({statement,specifier,type:"default",defaultImport:defaultName,namedImports:parseNamedImports(namedString),line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const defaultAndNamespaceRegex=new RegExp(IMPORT_PATTERNS.defaultAndNamespace.source,"g");while((match=defaultAndNamespaceRegex.exec(source))!==null){const[statement,defaultName,namespaceName,specifier]=match;addImport({statement,specifier,type:"default",defaultImport:defaultName,namespaceImport:namespaceName,line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const namedRegex=new RegExp(IMPORT_PATTERNS.named.source,"g");while((match=namedRegex.exec(source))!==null){const[statement,namedString,specifier]=match;addImport({statement,specifier,type:"named",namedImports:parseNamedImports(namedString),line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const defaultRegex=new RegExp(IMPORT_PATTERNS.default.source,"g");while((match=defaultRegex.exec(source))!==null){const[statement,defaultName,specifier]=match;const afterMatch=source.slice(match.index+match[0].length-specifier.length-2);if(afterMatch.startsWith(","))continue;addImport({statement,specifier,type:"default",defaultImport:defaultName,line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const namespaceRegex=new RegExp(IMPORT_PATTERNS.namespace.source,"g");while((match=namespaceRegex.exec(source))!==null){const[statement,namespaceName,specifier]=match;addImport({statement,specifier,type:"namespace",namespaceImport:namespaceName,line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const sideEffectRegex=new RegExp(IMPORT_PATTERNS.sideEffect.source,"g");while((match=sideEffectRegex.exec(source))!==null){const[statement,specifier]=match;const beforeMatch=source.slice(Math.max(0,match.index-50),match.index);if(beforeMatch.includes("from"))continue;addImport({statement,specifier,type:"side-effect",line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const dynamicRegex=new RegExp(IMPORT_PATTERNS.dynamic.source,"g");while((match=dynamicRegex.exec(source))!==null){const[statement,specifier]=match;addImport({statement,specifier,type:"dynamic",line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const reExportRegex=new RegExp(IMPORT_PATTERNS.reExport.source,"g");while((match=reExportRegex.exec(source))!==null){const[statement,specifier]=match;addImport({statement,specifier,type:"named",line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const reExportAllRegex=new RegExp(IMPORT_PATTERNS.reExportAll.source,"g");while((match=reExportAllRegex.exec(source))!==null){const[statement,specifier]=match;addImport({statement,specifier,type:"namespace",line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const externalImports=imports.filter(imp=>isExternalImport(imp.specifier));const relativeImports=imports.filter(imp=>isRelativeImport(imp.specifier));const externalPackages=[...new Set(externalImports.map(imp=>getPackageName(imp.specifier)))];return{imports,externalImports,relativeImports,externalPackages}}var DEFAULT_FALLBACK_CDN="https://esm.sh";function createEsmShResolver(options={}){const{fallbackCdnBase=DEFAULT_FALLBACK_CDN,registry=DEFAULT_CDN_REGISTRY,providerOrder=["esm.sh","cloudflare","jsdelivr","unpkg"]}=options;return{resolve(specifier,_context){if(specifier.startsWith("./")||specifier.startsWith("../")||specifier.startsWith("/")){return null}if(specifier.startsWith("node:")||specifier.startsWith("#")){return null}const pkgName=getPackageName(specifier);const entry=lookupPackage(pkgName,registry);if(entry){for(const provider of providerOrder){const config=entry.providers[provider];if(config?.url){const subpath=specifier.slice(pkgName.length);if(subpath&&config.url.includes("esm.sh/")){return{value:config.url+subpath,type:"url",integrity:config.integrity}}if(subpath){return{value:`${fallbackCdnBase}/${specifier}`,type:"url"}}if(config.global&&!config.esm){return{value:config.url,type:"url",integrity:config.integrity}}return{value:config.url,type:"url",integrity:config.integrity}}}}return{value:`${fallbackCdnBase}/${specifier}`,type:"url"}}}}function escapeHtml(str){if(str===null||str===void 0){return""}const s=String(str);return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}var SCRIPT_UNSAFE_CHARACTERS=/[<>&\u2028\u2029]/g;function toUnicodeEscape(character){return`\\u${character.charCodeAt(0).toString(16).padStart(4,"0")}`}function safeJsonForScript(value){if(value===void 0){return"null"}try{const jsonString=JSON.stringify(value,(_key,val)=>{if(typeof val==="bigint"){return val.toString()}return val});if(jsonString===void 0){return"null"}return jsonString.replace(SCRIPT_UNSAFE_CHARACTERS,toUnicodeEscape)}catch{return'{"error":"Value could not be serialized"}'}}function createImportMapFromResolved(resolved){const imports={};const integrity={};for(const[specifier,res]of Object.entries(resolved)){if(res.type==="url"){imports[specifier]=res.value;if(res.integrity){integrity[res.value]=res.integrity}}}return{imports,integrity:Object.keys(integrity).length>0?integrity:void 0}}function generateImportMapScriptTag(map){const json=JSON.stringify(map,null,2).replace(/<\//g,"<\\/");return`<script type="importmap">
562
2
  ${json}
563
- </script>`;
564
- }
565
-
566
- // libs/uipack/src/bridge-runtime/iife-generator.ts
567
- var WIDGET_CALL_META_KEY = "frontmcp/widgetCall";
568
- var MCP_APPS_DISPLAY_MODES = ["inline", "fullscreen", "pip"];
569
- function generateBridgeIIFE(options = {}) {
570
- const { debug = false, trustedOrigins = [], minify = false } = options;
571
- const adapters = options.adapters || ["openai", "ext-apps", "claude", "gemini", "generic"];
572
- const parts = [];
573
- parts.push("(function() {");
574
- parts.push('"use strict";');
575
- parts.push("");
576
- if (debug) {
577
- parts.push('function log(msg) { console.log("[FrontMcpBridge] " + msg); }');
578
- } else {
579
- parts.push("function log() {}");
580
- }
581
- parts.push("");
582
- parts.push("var DEFAULT_SAFE_AREA = { top: 0, bottom: 0, left: 0, right: 0 };");
583
- parts.push("");
584
- parts.push(generateContextDetection());
585
- parts.push("");
586
- parts.push(generateBaseCapabilities());
587
- parts.push("");
588
- if (adapters.includes("openai")) {
589
- parts.push(generateOpenAIAdapter());
590
- parts.push("");
591
- }
592
- if (adapters.includes("ext-apps")) {
593
- parts.push(generateExtAppsAdapter(trustedOrigins));
594
- parts.push("");
595
- }
596
- if (adapters.includes("claude")) {
597
- parts.push(generateClaudeAdapter());
598
- parts.push("");
599
- }
600
- if (adapters.includes("gemini")) {
601
- parts.push(generateGeminiAdapter());
602
- parts.push("");
603
- }
604
- if (adapters.includes("generic")) {
605
- parts.push(generateGenericAdapter());
606
- parts.push("");
607
- }
608
- parts.push(generatePlatformDetection(adapters));
609
- parts.push("");
610
- parts.push(generateBridgeClass());
611
- parts.push("");
612
- parts.push("var bridge = new FrontMcpBridge();");
613
- parts.push("bridge.initialize().then(function() {");
614
- parts.push(' log("Bridge initialized with adapter: " + bridge.adapterId);');
615
- parts.push(' window.dispatchEvent(new CustomEvent("bridge:ready", { detail: { adapter: bridge.adapterId } }));');
616
- parts.push(" if (window.__mcpDisplayMode) bridge.requestDisplayMode(window.__mcpDisplayMode).catch(function() {});");
617
- parts.push("}).catch(function(err) {");
618
- parts.push(' console.error("[FrontMcpBridge] Init failed:", err);');
619
- parts.push(' window.dispatchEvent(new CustomEvent("bridge:error", { detail: { error: err } }));');
620
- parts.push("});");
621
- parts.push("");
622
- parts.push("window.FrontMcpBridge = bridge;");
623
- parts.push("");
624
- parts.push(generateAutoResize());
625
- parts.push("function __showLoading() {");
626
- parts.push(' var root = document.getElementById("root");');
627
- parts.push(" if (root && !root.hasChildNodes()) {");
628
- parts.push(
629
- ` root.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;padding:2rem;color:#6b7280;font-family:system-ui,sans-serif"><div style="text-align:center"><div style="width:24px;height:24px;border:2px solid #e5e7eb;border-top-color:#3b82f6;border-radius:50%;animation:__spin 0.6s linear infinite;margin:0 auto 12px"></div><div style="font-size:0.875rem">Loading widget...</div></div></div><style>@keyframes __spin{to{transform:rotate(360deg)}}</style>';`
630
- );
631
- parts.push(" }");
632
- parts.push("}");
633
- parts.push('if (document.readyState === "loading") {');
634
- parts.push(' document.addEventListener("DOMContentLoaded", __showLoading);');
635
- parts.push("} else {");
636
- parts.push(" __showLoading();");
637
- parts.push("}");
638
- parts.push("})();");
639
- const code = parts.join("\n");
640
- if (minify) {
641
- return minifyJS(code);
642
- }
643
- return code;
644
- }
645
- function generateAutoResize() {
646
- return `
3
+ </script>`}var WIDGET_CALL_META_KEY="frontmcp/widgetCall";var MCP_APPS_DISPLAY_MODES=["inline","fullscreen","pip"];function generateBridgeIIFE(options={}){const{debug=false,trustedOrigins=[],minify=false}=options;const adapters=options.adapters||["openai","ext-apps","claude","gemini","generic"];const parts=[];parts.push("(function() {");parts.push('"use strict";');parts.push("");if(debug){parts.push('function log(msg) { console.log("[FrontMcpBridge] " + msg); }')}else{parts.push("function log() {}")}parts.push("");parts.push("var DEFAULT_SAFE_AREA = { top: 0, bottom: 0, left: 0, right: 0 };");parts.push("");parts.push(generateContextDetection());parts.push("");parts.push(generateBaseCapabilities());parts.push("");if(adapters.includes("openai")){parts.push(generateOpenAIAdapter());parts.push("")}if(adapters.includes("ext-apps")){parts.push(generateExtAppsAdapter(trustedOrigins));parts.push("")}if(adapters.includes("claude")){parts.push(generateClaudeAdapter());parts.push("")}if(adapters.includes("gemini")){parts.push(generateGeminiAdapter());parts.push("")}if(adapters.includes("generic")){parts.push(generateGenericAdapter());parts.push("")}parts.push(generatePlatformDetection(adapters));parts.push("");parts.push(generateBridgeClass());parts.push("");parts.push("var bridge = new FrontMcpBridge();");parts.push("bridge.initialize().then(function() {");parts.push(' log("Bridge initialized with adapter: " + bridge.adapterId);');parts.push(' window.dispatchEvent(new CustomEvent("bridge:ready", { detail: { adapter: bridge.adapterId } }));');parts.push(" if (window.__mcpDisplayMode) bridge.requestDisplayMode(window.__mcpDisplayMode).catch(function() {});");parts.push("}).catch(function(err) {");parts.push(' console.error("[FrontMcpBridge] Init failed:", err);');parts.push(' window.dispatchEvent(new CustomEvent("bridge:error", { detail: { error: err } }));');parts.push("});");parts.push("");parts.push("window.FrontMcpBridge = bridge;");parts.push("");parts.push(generateAutoResize());parts.push("function __showLoading() {");parts.push(' var root = document.getElementById("root");');parts.push(" if (root && !root.hasChildNodes()) {");parts.push(` root.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;padding:2rem;color:#6b7280;font-family:system-ui,sans-serif"><div style="text-align:center"><div style="width:24px;height:24px;border:2px solid #e5e7eb;border-top-color:#3b82f6;border-radius:50%;animation:__spin 0.6s linear infinite;margin:0 auto 12px"></div><div style="font-size:0.875rem">Loading widget...</div></div></div><style>@keyframes __spin{to{transform:rotate(360deg)}}</style>';`);parts.push(" }");parts.push("}");parts.push('if (document.readyState === "loading") {');parts.push(' document.addEventListener("DOMContentLoaded", __showLoading);');parts.push("} else {");parts.push(" __showLoading();");parts.push("}");parts.push("})();");const code=parts.join("\n");if(minify){return minifyJS(code)}return code}function generateAutoResize(){return`
647
4
  function __applySizingCss(sizing) {
648
5
  if (typeof document === 'undefined' || !document.documentElement) return;
649
6
  function toLen(v) { return typeof v === 'number' ? v + 'px' : v; }
@@ -778,10 +135,7 @@ function __initAutoResize() {
778
135
  }
779
136
  }
780
137
  __initAutoResize();
781
- `.trim();
782
- }
783
- function generateContextDetection() {
784
- return `
138
+ `.trim()}function generateContextDetection(){return`
785
139
  function detectTheme() {
786
140
  if (typeof window !== 'undefined' && window.matchMedia) {
787
141
  return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
@@ -868,10 +222,7 @@ function readInjectedData() {
868
222
  }
869
223
  return data;
870
224
  }
871
- `.trim();
872
- }
873
- function generateBaseCapabilities() {
874
- return `
225
+ `.trim()}function generateBaseCapabilities(){return`
875
226
  var DEFAULT_CAPABILITIES = {
876
227
  canCallTools: false,
877
228
  canSendMessages: false,
@@ -881,10 +232,7 @@ var DEFAULT_CAPABILITIES = {
881
232
  supportsDisplayModes: false,
882
233
  supportsTheme: true
883
234
  };
884
- `.trim();
885
- }
886
- function generateOpenAIAdapter() {
887
- return `
235
+ `.trim()}function generateOpenAIAdapter(){return`
888
236
  var OpenAIAdapter = {
889
237
  id: 'openai',
890
238
  name: 'OpenAI ChatGPT',
@@ -969,11 +317,7 @@ var OpenAIAdapter = {
969
317
  return Promise.resolve();
970
318
  }
971
319
  };
972
- `.trim();
973
- }
974
- function generateExtAppsAdapter(trustedOrigins) {
975
- const originsArray = trustedOrigins.length > 0 ? JSON.stringify(trustedOrigins) : "[]";
976
- return `
320
+ `.trim()}function generateExtAppsAdapter(trustedOrigins){const originsArray=trustedOrigins.length>0?JSON.stringify(trustedOrigins):"[]";return`
977
321
  var ExtAppsAdapter = {
978
322
  id: 'ext-apps',
979
323
  name: 'ext-apps (SEP-1865)',
@@ -1316,10 +660,7 @@ var ExtAppsAdapter = {
1316
660
  return this.sendRequest('ui/unregisterTool', { name: name });
1317
661
  }
1318
662
  };
1319
- `.trim();
1320
- }
1321
- function generateClaudeAdapter() {
1322
- return `
663
+ `.trim()}function generateClaudeAdapter(){return`
1323
664
  var ClaudeAdapter = {
1324
665
  id: 'claude',
1325
666
  name: 'Claude (Anthropic)',
@@ -1380,10 +721,7 @@ var ClaudeAdapter = {
1380
721
  return Promise.resolve();
1381
722
  }
1382
723
  };
1383
- `.trim();
1384
- }
1385
- function generateGeminiAdapter() {
1386
- return `
724
+ `.trim()}function generateGeminiAdapter(){return`
1387
725
  var GeminiAdapter = {
1388
726
  id: 'gemini',
1389
727
  name: 'Google Gemini',
@@ -1434,10 +772,7 @@ var GeminiAdapter = {
1434
772
  return Promise.resolve();
1435
773
  }
1436
774
  };
1437
- `.trim();
1438
- }
1439
- function generateGenericAdapter() {
1440
- return `
775
+ `.trim()}function generateGenericAdapter(){return`
1441
776
  var GenericAdapter = {
1442
777
  id: 'generic',
1443
778
  name: 'Generic Web',
@@ -1472,26 +807,7 @@ var GenericAdapter = {
1472
807
  return Promise.resolve();
1473
808
  }
1474
809
  };
1475
- `.trim();
1476
- }
1477
- function generatePlatformDetection(adapters) {
1478
- const adapterVars = adapters.map((a) => {
1479
- switch (a) {
1480
- case "openai":
1481
- return "OpenAIAdapter";
1482
- case "ext-apps":
1483
- return "ExtAppsAdapter";
1484
- case "claude":
1485
- return "ClaudeAdapter";
1486
- case "gemini":
1487
- return "GeminiAdapter";
1488
- case "generic":
1489
- return "GenericAdapter";
1490
- default:
1491
- return "";
1492
- }
1493
- }).filter(Boolean);
1494
- return `
810
+ `.trim()}function generatePlatformDetection(adapters){const adapterVars=adapters.map(a=>{switch(a){case"openai":return"OpenAIAdapter";case"ext-apps":return"ExtAppsAdapter";case"claude":return"ClaudeAdapter";case"gemini":return"GeminiAdapter";case"generic":return"GenericAdapter";default:return""}}).filter(Boolean);return`
1495
811
  var ADAPTERS = [${adapterVars.join(", ")}].sort(function(a, b) { return b.priority - a.priority; });
1496
812
 
1497
813
  function detectPlatform() {
@@ -1504,10 +820,7 @@ function detectPlatform() {
1504
820
  log('No platform detected, using generic');
1505
821
  return GenericAdapter;
1506
822
  }
1507
- `.trim();
1508
- }
1509
- function generateBridgeClass() {
1510
- return `
823
+ `.trim()}function generateBridgeClass(){return`
1511
824
  function FrontMcpBridge() {
1512
825
  this._adapter = null;
1513
826
  this._initialized = false;
@@ -1883,504 +1196,19 @@ FrontMcpBridge.prototype._setupDataToolCallHandler = function() {
1883
1196
  }
1884
1197
  }, true); // Use capture phase to handle before React handlers
1885
1198
  };
1886
- `.trim();
1887
- }
1888
- var MAX_MINIFY_CODE_LENGTH = 5e5;
1889
- function minifyJS(code) {
1890
- if (code.length > MAX_MINIFY_CODE_LENGTH) {
1891
- return code;
1892
- }
1893
- const out = [];
1894
- let inBlockComment = false;
1895
- for (const raw of code.split("\n")) {
1896
- const line = raw.trim();
1897
- if (inBlockComment) {
1898
- if (line.includes("*/")) inBlockComment = false;
1899
- continue;
1900
- }
1901
- if (line === "" || line.startsWith("//")) continue;
1902
- if (line.startsWith("/*")) {
1903
- if (!line.includes("*/")) inBlockComment = true;
1904
- continue;
1905
- }
1906
- out.push(line);
1907
- }
1908
- return out.join("\n");
1909
- }
1910
- function generatePlatformBundle(platform, options = {}) {
1911
- const platformAdapters = {
1912
- chatgpt: ["openai", "generic"],
1913
- claude: ["claude", "generic"],
1914
- gemini: ["gemini", "generic"],
1915
- universal: ["openai", "ext-apps", "claude", "gemini", "generic"]
1916
- };
1917
- return generateBridgeIIFE({
1918
- ...options,
1919
- adapters: platformAdapters[platform]
1920
- });
1921
- }
1922
- var UNIVERSAL_BRIDGE_SCRIPT = generateBridgeIIFE();
1923
- var BRIDGE_SCRIPT_TAGS = {
1924
- universal: `<script>${UNIVERSAL_BRIDGE_SCRIPT}</script>`,
1925
- chatgpt: `<script>${generatePlatformBundle("chatgpt")}</script>`,
1926
- claude: `<script>${generatePlatformBundle("claude")}</script>`,
1927
- gemini: `<script>${generatePlatformBundle("gemini")}</script>`
1928
- };
1929
-
1930
- // libs/uipack/src/shell/csp.ts
1931
- var DEFAULT_CDN_DOMAINS = [
1932
- "https://cdn.jsdelivr.net",
1933
- "https://cdnjs.cloudflare.com",
1934
- "https://fonts.googleapis.com",
1935
- "https://fonts.gstatic.com",
1936
- "https://esm.sh"
1937
- ];
1938
- var DEFAULT_CSP_DIRECTIVES = [
1939
- "default-src 'none'",
1940
- `script-src 'self' 'unsafe-inline' ${DEFAULT_CDN_DOMAINS.join(" ")}`,
1941
- `style-src 'self' 'unsafe-inline' ${DEFAULT_CDN_DOMAINS.join(" ")}`,
1942
- `img-src 'self' data: ${DEFAULT_CDN_DOMAINS.join(" ")}`,
1943
- `font-src 'self' data: ${DEFAULT_CDN_DOMAINS.join(" ")}`,
1944
- `connect-src ${DEFAULT_CDN_DOMAINS.join(" ")}`,
1945
- "object-src 'self' data:"
1946
- ];
1947
- function buildCSPDirectives(csp) {
1948
- if (!csp) {
1949
- return [...DEFAULT_CSP_DIRECTIVES];
1950
- }
1951
- const validResourceDomains = sanitizeCSPDomains(csp.resourceDomains);
1952
- const validConnectDomains = sanitizeCSPDomains(csp.connectDomains);
1953
- const allResourceDomains = [.../* @__PURE__ */ new Set([...DEFAULT_CDN_DOMAINS, ...validResourceDomains])];
1954
- const directives = [
1955
- "default-src 'none'",
1956
- `script-src 'self' 'unsafe-inline' ${allResourceDomains.join(" ")}`,
1957
- `style-src 'self' 'unsafe-inline' ${allResourceDomains.join(" ")}`
1958
- ];
1959
- const imgSources = ["'self'", "data:", ...allResourceDomains];
1960
- directives.push(`img-src ${imgSources.join(" ")}`);
1961
- const fontSources = ["'self'", "data:", ...allResourceDomains];
1962
- directives.push(`font-src ${fontSources.join(" ")}`);
1963
- const connectSources = [.../* @__PURE__ */ new Set([...allResourceDomains, ...validConnectDomains])];
1964
- directives.push(`connect-src ${connectSources.join(" ")}`);
1965
- directives.push("object-src 'self' data:");
1966
- return directives;
1967
- }
1968
- function buildCSPMetaTag(csp) {
1969
- const directives = buildCSPDirectives(csp);
1970
- const content = directives.join("; ");
1971
- return `<meta http-equiv="Content-Security-Policy" content="${escapeAttribute(content)}">`;
1972
- }
1973
- var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
1974
- function validateCSPDomain(domain) {
1975
- if (typeof domain !== "string" || /[\s;,'"]/.test(domain)) return false;
1976
- if (/[?#]/.test(domain)) return false;
1977
- if (domain.includes("*")) {
1978
- const wildcard = /^(?:https|wss):\/\/\*\.(.*)$/.exec(domain);
1979
- return wildcard !== null && /^([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(wildcard[1]);
1980
- }
1981
- try {
1982
- const url = new URL(domain);
1983
- if (url.protocol === "https:" || url.protocol === "wss:") return true;
1984
- return (url.protocol === "http:" || url.protocol === "ws:") && LOOPBACK_HOSTS.has(url.hostname);
1985
- } catch {
1986
- return false;
1987
- }
1988
- }
1989
- var reportedInvalidDomains = /* @__PURE__ */ new Set();
1990
- function sanitizeCSPDomains(domains) {
1991
- if (!domains) return [];
1992
- const valid = [];
1993
- for (const domain of domains) {
1994
- if (validateCSPDomain(domain)) {
1995
- valid.push(domain);
1996
- } else if (!reportedInvalidDomains.has(domain)) {
1997
- reportedInvalidDomains.add(domain);
1998
- console.warn(
1999
- `Invalid CSP domain ignored: ${domain} (expected an https:// or wss:// origin, or http:// / ws:// on localhost)`
2000
- );
2001
- }
2002
- }
2003
- return valid;
2004
- }
2005
- function escapeAttribute(str) {
2006
- return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
2007
- }
2008
-
2009
- // libs/uipack/src/shell/custom-shell-types.ts
2010
- var SHELL_PLACEHOLDER_NAMES = ["CSP", "DATA", "BRIDGE", "CONTENT", "TITLE"];
2011
- var SHELL_PLACEHOLDERS = {
2012
- CSP: "{{CSP}}",
2013
- DATA: "{{DATA}}",
2014
- BRIDGE: "{{BRIDGE}}",
2015
- CONTENT: "{{CONTENT}}",
2016
- TITLE: "{{TITLE}}"
2017
- };
2018
- var REQUIRED_PLACEHOLDERS = ["CONTENT"];
2019
- var OPTIONAL_PLACEHOLDERS = ["CSP", "DATA", "BRIDGE", "TITLE"];
2020
-
2021
- // libs/uipack/src/shell/custom-shell-applier.ts
2022
- var PLACEHOLDER_PATTERN = new RegExp(`\\{\\{(${SHELL_PLACEHOLDER_NAMES.join("|")})\\}\\}`, "g");
2023
- var VALUE_KEYS = {
2024
- CSP: "csp",
2025
- DATA: "data",
2026
- BRIDGE: "bridge",
2027
- CONTENT: "content",
2028
- TITLE: "title"
2029
- };
2030
- function applyShellTemplate(template, values) {
2031
- return template.replace(PLACEHOLDER_PATTERN, (_token, name) => values[VALUE_KEYS[name]]);
2032
- }
2033
-
2034
- // libs/uipack/src/shell/custom-shell-validator.ts
2035
- function validateShellTemplate(template) {
2036
- const found = {};
2037
- for (const name of SHELL_PLACEHOLDER_NAMES) {
2038
- found[name] = template.includes(SHELL_PLACEHOLDERS[name]);
2039
- }
2040
- const missingRequired = REQUIRED_PLACEHOLDERS.filter((name) => !found[name]);
2041
- const missingOptional = OPTIONAL_PLACEHOLDERS.filter((name) => !found[name]);
2042
- return {
2043
- valid: missingRequired.length === 0,
2044
- found,
2045
- missingRequired,
2046
- missingOptional
2047
- };
2048
- }
2049
-
2050
- // libs/uipack/src/shell/trusted-html.ts
2051
- var TRUSTED_HTML = /* @__PURE__ */ Symbol.for("@frontmcp/uipack/trusted-html");
2052
- function trustedHtml(markup) {
2053
- const value = String(markup);
2054
- return Object.freeze({ [TRUSTED_HTML]: value, toString: () => value });
2055
- }
2056
- function isTrustedHtml(value) {
2057
- return typeof value === "object" && value !== null && typeof value[TRUSTED_HTML] === "string";
2058
- }
2059
- function interpolate(value) {
2060
- if (isTrustedHtml(value)) return value[TRUSTED_HTML];
2061
- if (Array.isArray(value)) return value.map(interpolate).join("");
2062
- if (value === false) return "";
2063
- return escapeHtml(value);
2064
- }
2065
- function html(strings, ...values) {
2066
- let markup = strings[0];
2067
- for (let index = 0; index < values.length; index++) {
2068
- markup += interpolate(values[index]) + strings[index + 1];
2069
- }
2070
- return trustedHtml(markup);
2071
- }
2072
-
2073
- // libs/uipack/src/shell/data-injector.ts
2074
- function hasSizing(sizing) {
2075
- if (!sizing) return false;
2076
- return sizing.preferredHeight !== void 0 || sizing.minHeight !== void 0 || sizing.maxHeight !== void 0 || sizing.aspectRatio !== void 0 || sizing.autoResize !== void 0;
2077
- }
2078
- function buildDataInjectionScript(options) {
2079
- const { toolName, input, output, structuredContent, sizing, displayMode } = options;
2080
- const lines = [
2081
- `window.__mcpAppsEnabled = true;`,
2082
- `window.__mcpToolName = ${safeJsonForScript(toolName)};`,
2083
- `window.__mcpToolInput = ${safeJsonForScript(input ?? null)};`,
2084
- `window.__mcpToolOutput = ${safeJsonForScript(output ?? null)};`,
2085
- `window.__mcpStructuredContent = ${safeJsonForScript(structuredContent ?? null)};`
2086
- ];
2087
- if (hasSizing(sizing)) {
2088
- lines.push(`window.__mcpWidgetSizing = ${safeJsonForScript(sizing)};`);
2089
- }
2090
- if (displayMode && displayMode !== "inline") {
2091
- lines.push(`window.__mcpDisplayMode = ${safeJsonForScript(displayMode)};`);
2092
- }
2093
- return `<script>
1199
+ `.trim()}var MAX_MINIFY_CODE_LENGTH=5e5;function minifyJS(code){if(code.length>MAX_MINIFY_CODE_LENGTH){return code}const out=[];let inBlockComment=false;for(const raw of code.split("\n")){const line=raw.trim();if(inBlockComment){if(line.includes("*/"))inBlockComment=false;continue}if(line===""||line.startsWith("//"))continue;if(line.startsWith("/*")){if(!line.includes("*/"))inBlockComment=true;continue}out.push(line)}return out.join("\n")}function generatePlatformBundle(platform,options={}){const platformAdapters={chatgpt:["openai","generic"],claude:["claude","generic"],gemini:["gemini","generic"],universal:["openai","ext-apps","claude","gemini","generic"]};return generateBridgeIIFE({...options,adapters:platformAdapters[platform]})}var UNIVERSAL_BRIDGE_SCRIPT=generateBridgeIIFE();var BRIDGE_SCRIPT_TAGS={universal:`<script>${UNIVERSAL_BRIDGE_SCRIPT}</script>`,chatgpt:`<script>${generatePlatformBundle("chatgpt")}</script>`,claude:`<script>${generatePlatformBundle("claude")}</script>`,gemini:`<script>${generatePlatformBundle("gemini")}</script>`};var DEFAULT_CDN_DOMAINS=["https://cdn.jsdelivr.net","https://cdnjs.cloudflare.com","https://fonts.googleapis.com","https://fonts.gstatic.com","https://esm.sh"];var DEFAULT_CSP_DIRECTIVES=["default-src 'none'",`script-src 'self' 'unsafe-inline' ${DEFAULT_CDN_DOMAINS.join(" ")}`,`style-src 'self' 'unsafe-inline' ${DEFAULT_CDN_DOMAINS.join(" ")}`,`img-src 'self' data: ${DEFAULT_CDN_DOMAINS.join(" ")}`,`font-src 'self' data: ${DEFAULT_CDN_DOMAINS.join(" ")}`,`connect-src ${DEFAULT_CDN_DOMAINS.join(" ")}`,"object-src 'self' data:"];function buildCSPDirectives(csp){if(!csp){return[...DEFAULT_CSP_DIRECTIVES]}const validResourceDomains=sanitizeCSPDomains(csp.resourceDomains);const validConnectDomains=sanitizeCSPDomains(csp.connectDomains);const allResourceDomains=[...new Set([...DEFAULT_CDN_DOMAINS,...validResourceDomains])];const directives=["default-src 'none'",`script-src 'self' 'unsafe-inline' ${allResourceDomains.join(" ")}`,`style-src 'self' 'unsafe-inline' ${allResourceDomains.join(" ")}`];const imgSources=["'self'","data:",...allResourceDomains];directives.push(`img-src ${imgSources.join(" ")}`);const fontSources=["'self'","data:",...allResourceDomains];directives.push(`font-src ${fontSources.join(" ")}`);const connectSources=[...new Set([...allResourceDomains,...validConnectDomains])];directives.push(`connect-src ${connectSources.join(" ")}`);directives.push("object-src 'self' data:");return directives}function buildCSPMetaTag(csp){const directives=buildCSPDirectives(csp);const content=directives.join("; ");return`<meta http-equiv="Content-Security-Policy" content="${escapeAttribute(content)}">`}var LOOPBACK_HOSTS=new Set(["localhost","127.0.0.1","[::1]"]);function validateCSPDomain(domain){if(typeof domain!=="string"||/[\s;,'"]/.test(domain))return false;if(/[?#]/.test(domain))return false;if(domain.includes("*")){const wildcard=/^(?:https|wss):\/\/\*\.(.*)$/.exec(domain);return wildcard!==null&&/^([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(wildcard[1])}try{const url=new URL(domain);if(url.protocol==="https:"||url.protocol==="wss:")return true;return(url.protocol==="http:"||url.protocol==="ws:")&&LOOPBACK_HOSTS.has(url.hostname)}catch{return false}}var reportedInvalidDomains=new Set;function sanitizeCSPDomains(domains){if(!domains)return[];const valid=[];for(const domain of domains){if(validateCSPDomain(domain)){valid.push(domain)}else if(!reportedInvalidDomains.has(domain)){reportedInvalidDomains.add(domain);console.warn(`Invalid CSP domain ignored: ${domain} (expected an https:// or wss:// origin, or http:// / ws:// on localhost)`)}}return valid}function escapeAttribute(str){return str.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&#39;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}var SHELL_PLACEHOLDER_NAMES=["CSP","DATA","BRIDGE","CONTENT","TITLE"];var SHELL_PLACEHOLDERS={CSP:"{{CSP}}",DATA:"{{DATA}}",BRIDGE:"{{BRIDGE}}",CONTENT:"{{CONTENT}}",TITLE:"{{TITLE}}"};var REQUIRED_PLACEHOLDERS=["CONTENT"];var OPTIONAL_PLACEHOLDERS=["CSP","DATA","BRIDGE","TITLE"];var PLACEHOLDER_PATTERN=new RegExp(`\\{\\{(${SHELL_PLACEHOLDER_NAMES.join("|")})\\}\\}`,"g");var VALUE_KEYS={CSP:"csp",DATA:"data",BRIDGE:"bridge",CONTENT:"content",TITLE:"title"};function applyShellTemplate(template,values){return template.replace(PLACEHOLDER_PATTERN,(_token,name)=>values[VALUE_KEYS[name]])}function validateShellTemplate(template){const found={};for(const name of SHELL_PLACEHOLDER_NAMES){found[name]=template.includes(SHELL_PLACEHOLDERS[name])}const missingRequired=REQUIRED_PLACEHOLDERS.filter(name=>!found[name]);const missingOptional=OPTIONAL_PLACEHOLDERS.filter(name=>!found[name]);return{valid:missingRequired.length===0,found,missingRequired,missingOptional}}var TRUSTED_HTML=Symbol.for("@frontmcp/uipack/trusted-html");function trustedHtml(markup){const value=String(markup);return Object.freeze({[TRUSTED_HTML]:value,toString:()=>value})}function isTrustedHtml(value){return typeof value==="object"&&value!==null&&typeof value[TRUSTED_HTML]==="string"}function interpolate(value){if(isTrustedHtml(value))return value[TRUSTED_HTML];if(Array.isArray(value))return value.map(interpolate).join("");if(value===false)return"";return escapeHtml(value)}function html(strings,...values){let markup=strings[0];for(let index=0;index<values.length;index++){markup+=interpolate(values[index])+strings[index+1]}return trustedHtml(markup)}function hasSizing(sizing){if(!sizing)return false;return sizing.preferredHeight!==void 0||sizing.minHeight!==void 0||sizing.maxHeight!==void 0||sizing.aspectRatio!==void 0||sizing.autoResize!==void 0}function buildDataInjectionScript(options){const{toolName,input,output,structuredContent,sizing,displayMode}=options;const lines=[`window.__mcpAppsEnabled = true;`,`window.__mcpToolName = ${safeJsonForScript(toolName)};`,`window.__mcpToolInput = ${safeJsonForScript(input??null)};`,`window.__mcpToolOutput = ${safeJsonForScript(output??null)};`,`window.__mcpStructuredContent = ${safeJsonForScript(structuredContent??null)};`];if(hasSizing(sizing)){lines.push(`window.__mcpWidgetSizing = ${safeJsonForScript(sizing)};`)}if(displayMode&&displayMode!=="inline"){lines.push(`window.__mcpDisplayMode = ${safeJsonForScript(displayMode)};`)}return`<script>
2094
1200
  ${lines.join("\n")}
2095
- </script>`;
2096
- }
2097
- function buildCustomDataInjectionScript(descriptor) {
2098
- if (descriptor.script !== void 0) {
2099
- return descriptor.script;
2100
- }
2101
- if (descriptor.globalKey !== void 0) {
2102
- return `<script>window[${safeJsonForScript(descriptor.globalKey)}] = ${safeJsonForScript(
2103
- descriptor.value ?? null
2104
- )};</script>`;
2105
- }
2106
- return "";
2107
- }
2108
- var _uniqueIdCounter = 0;
2109
- function createTemplateHelpers() {
2110
- return {
2111
- escapeHtml: (str) => escapeHtml(str),
2112
- formatDate: (date, format) => {
2113
- const d = date instanceof Date ? date : new Date(date);
2114
- if (isNaN(d.getTime())) return String(date);
2115
- if (format === "iso") return d.toISOString();
2116
- if (format === "date") return d.toLocaleDateString();
2117
- if (format === "time") return d.toLocaleTimeString();
2118
- return d.toLocaleString();
2119
- },
2120
- formatCurrency: (amount, currency = "USD") => {
2121
- return new Intl.NumberFormat("en-US", {
2122
- style: "currency",
2123
- currency
2124
- }).format(amount);
2125
- },
2126
- uniqueId: (prefix = "mcp") => {
2127
- return `${prefix}-${++_uniqueIdCounter}`;
2128
- },
2129
- jsonEmbed: (data) => safeJsonForScript(data),
2130
- html,
2131
- trustedHtml
2132
- };
2133
- }
2134
-
2135
- // libs/uipack/src/shell/sizing-css.ts
2136
- function sanitizeCssValue(value) {
2137
- return value.replace(/[<>{};]/g, "").trim();
2138
- }
2139
- function toCssLength(value) {
2140
- return typeof value === "number" ? `${value}px` : sanitizeCssValue(value);
2141
- }
2142
- function buildSizingStyleTag(sizing) {
2143
- if (!hasSizing(sizing)) return "";
2144
- const hasCssSizing = sizing.preferredHeight !== void 0 || sizing.minHeight !== void 0 || sizing.maxHeight !== void 0 || sizing.aspectRatio !== void 0;
2145
- if (!hasCssSizing) return "";
2146
- const rootRules = [];
2147
- const docRules = ["margin: 0;"];
2148
- if (sizing.preferredHeight !== void 0) {
2149
- const h = toCssLength(sizing.preferredHeight);
2150
- docRules.push(`height: ${h};`);
2151
- rootRules.push(`min-height: ${h};`);
2152
- }
2153
- if (sizing.minHeight !== void 0) {
2154
- const mh = toCssLength(sizing.minHeight);
2155
- docRules.push(`min-height: ${mh};`);
2156
- rootRules.push(`min-height: ${mh};`);
2157
- }
2158
- if (sizing.maxHeight !== void 0) {
2159
- const mx = toCssLength(sizing.maxHeight);
2160
- docRules.push(`max-height: ${mx};`);
2161
- rootRules.push(`max-height: ${mx};`);
2162
- }
2163
- if (sizing.aspectRatio !== void 0) {
2164
- const ar = typeof sizing.aspectRatio === "number" ? String(sizing.aspectRatio) : sanitizeCssValue(sizing.aspectRatio);
2165
- if (ar) rootRules.push(`aspect-ratio: ${ar};`);
2166
- }
2167
- const parts = [`html, body { ${docRules.join(" ")} }`];
2168
- if (rootRules.length > 0) {
2169
- parts.push(`#root { ${rootRules.join(" ")} }`);
2170
- }
2171
- return `<style>${parts.join("\n")}</style>`;
2172
- }
2173
-
2174
- // libs/uipack/src/shell/builder.ts
2175
- function resolveDataInjectionScript(args) {
2176
- if (args.dataInjection) {
2177
- return buildCustomDataInjectionScript(args.dataInjection);
2178
- }
2179
- return buildDataInjectionScript({
2180
- toolName: args.toolName,
2181
- input: args.input,
2182
- output: args.output,
2183
- structuredContent: args.structuredContent,
2184
- sizing: args.sizing,
2185
- displayMode: args.displayMode
2186
- });
2187
- }
2188
- function buildShell(content, config) {
2189
- const {
2190
- toolName,
2191
- csp,
2192
- withShell = true,
2193
- input,
2194
- output,
2195
- structuredContent,
2196
- includeBridge = true,
2197
- title,
2198
- sizing,
2199
- displayMode
2200
- } = config;
2201
- const { customShell, dataInjection } = config;
2202
- const dataScript = resolveDataInjectionScript({
2203
- dataInjection,
2204
- toolName,
2205
- input,
2206
- output,
2207
- structuredContent,
2208
- sizing,
2209
- displayMode
2210
- });
2211
- if (!withShell) {
2212
- const html3 = `${dataScript}
2213
- ${content}`;
2214
- return {
2215
- html: html3,
2216
- hash: simpleHash(html3),
2217
- size: Buffer.byteLength(html3, "utf-8")
2218
- };
2219
- }
2220
- if (customShell) {
2221
- return buildCustomShell(content, customShell, {
2222
- csp,
2223
- toolName,
2224
- input,
2225
- output,
2226
- structuredContent,
2227
- includeBridge,
2228
- title,
2229
- sizing,
2230
- displayMode,
2231
- dataInjection
2232
- });
2233
- }
2234
- const headParts = [
2235
- '<meta charset="UTF-8">',
2236
- '<meta name="viewport" content="width=device-width, initial-scale=1.0">'
2237
- ];
2238
- if (title) {
2239
- headParts.push(`<title>${escapeHtmlForTag(title)}</title>`);
2240
- }
2241
- headParts.push(buildCSPMetaTag(csp));
2242
- headParts.push(dataScript);
2243
- const sizingStyle = buildSizingStyleTag(sizing);
2244
- if (sizingStyle) {
2245
- headParts.push(sizingStyle);
2246
- }
2247
- if (includeBridge) {
2248
- const bridgeScript = generateBridgeIIFE({ minify: true });
2249
- headParts.push(`<script>${bridgeScript}</script>`);
2250
- }
2251
- const html2 = `<!DOCTYPE html>
1201
+ </script>`}function buildCustomDataInjectionScript(descriptor){if(descriptor.script!==void 0){return descriptor.script}if(descriptor.globalKey!==void 0){return`<script>window[${safeJsonForScript(descriptor.globalKey)}] = ${safeJsonForScript(descriptor.value??null)};</script>`}return""}var _uniqueIdCounter=0;function createTemplateHelpers(){return{escapeHtml:str=>escapeHtml(str),formatDate:(date,format)=>{const d=date instanceof Date?date:new Date(date);if(isNaN(d.getTime()))return String(date);if(format==="iso")return d.toISOString();if(format==="date")return d.toLocaleDateString();if(format==="time")return d.toLocaleTimeString();return d.toLocaleString()},formatCurrency:(amount,currency="USD")=>{return new Intl.NumberFormat("en-US",{style:"currency",currency}).format(amount)},uniqueId:(prefix="mcp")=>{return`${prefix}-${++_uniqueIdCounter}`},jsonEmbed:data=>safeJsonForScript(data),html,trustedHtml}}function sanitizeCssValue(value){return value.replace(/[<>{};]/g,"").trim()}function toCssLength(value){return typeof value==="number"?`${value}px`:sanitizeCssValue(value)}function buildSizingStyleTag(sizing){if(!hasSizing(sizing))return"";const hasCssSizing=sizing.preferredHeight!==void 0||sizing.minHeight!==void 0||sizing.maxHeight!==void 0||sizing.aspectRatio!==void 0;if(!hasCssSizing)return"";const rootRules=[];const docRules=["margin: 0;"];if(sizing.preferredHeight!==void 0){const h=toCssLength(sizing.preferredHeight);docRules.push(`height: ${h};`);rootRules.push(`min-height: ${h};`)}if(sizing.minHeight!==void 0){const mh=toCssLength(sizing.minHeight);docRules.push(`min-height: ${mh};`);rootRules.push(`min-height: ${mh};`)}if(sizing.maxHeight!==void 0){const mx=toCssLength(sizing.maxHeight);docRules.push(`max-height: ${mx};`);rootRules.push(`max-height: ${mx};`)}if(sizing.aspectRatio!==void 0){const ar=typeof sizing.aspectRatio==="number"?String(sizing.aspectRatio):sanitizeCssValue(sizing.aspectRatio);if(ar)rootRules.push(`aspect-ratio: ${ar};`)}const parts=[`html, body { ${docRules.join(" ")} }`];if(rootRules.length>0){parts.push(`#root { ${rootRules.join(" ")} }`)}return`<style>${parts.join("\n")}</style>`}function resolveDataInjectionScript(args){if(args.dataInjection){return buildCustomDataInjectionScript(args.dataInjection)}return buildDataInjectionScript({toolName:args.toolName,input:args.input,output:args.output,structuredContent:args.structuredContent,sizing:args.sizing,displayMode:args.displayMode})}function buildShell(content,config){const{toolName,csp,withShell=true,input,output,structuredContent,includeBridge=true,title,sizing,displayMode}=config;const{customShell,dataInjection}=config;const dataScript=resolveDataInjectionScript({dataInjection,toolName,input,output,structuredContent,sizing,displayMode});if(!withShell){const html3=`${dataScript}
1202
+ ${content}`;return{html:html3,hash:simpleHash(html3),size:Buffer.byteLength(html3,"utf-8")}}if(customShell){return buildCustomShell(content,customShell,{csp,toolName,input,output,structuredContent,includeBridge,title,sizing,displayMode,dataInjection})}const headParts=['<meta charset="UTF-8">','<meta name="viewport" content="width=device-width, initial-scale=1.0">'];if(title){headParts.push(`<title>${escapeHtmlForTag(title)}</title>`)}headParts.push(buildCSPMetaTag(csp));headParts.push(dataScript);const sizingStyle=buildSizingStyleTag(sizing);if(sizingStyle){headParts.push(sizingStyle)}if(includeBridge){const bridgeScript=generateBridgeIIFE({minify:true});headParts.push(`<script>${bridgeScript}</script>`)}const html2=`<!DOCTYPE html>
2252
1203
  <html lang="en">
2253
1204
  <head>
2254
- ${headParts.map((p) => ` ${p}`).join("\n")}
1205
+ ${headParts.map(p=>` ${p}`).join("\n")}
2255
1206
  </head>
2256
1207
  <body>
2257
1208
  ${content}
2258
1209
  </body>
2259
- </html>`;
2260
- return {
2261
- html: html2,
2262
- hash: simpleHash(html2),
2263
- size: Buffer.byteLength(html2, "utf-8")
2264
- };
2265
- }
2266
- function buildCustomShell(content, customShell, ctx) {
2267
- let template;
2268
- if (typeof customShell === "string") {
2269
- const validation = validateShellTemplate(customShell);
2270
- if (!validation.valid) {
2271
- throw new Error(
2272
- `Custom shell template is missing required placeholder(s): ${validation.missingRequired.map((n) => `{{${n}}}`).join(", ")}`
2273
- );
2274
- }
2275
- template = customShell;
2276
- } else {
2277
- template = customShell.template;
2278
- }
2279
- const cspTag = buildCSPMetaTag(ctx.csp);
2280
- const dataScript = resolveDataInjectionScript({
2281
- dataInjection: ctx.dataInjection,
2282
- toolName: ctx.toolName,
2283
- input: ctx.input,
2284
- output: ctx.output,
2285
- structuredContent: ctx.structuredContent,
2286
- sizing: ctx.sizing,
2287
- displayMode: ctx.displayMode
2288
- });
2289
- const sizingStyle = buildSizingStyleTag(ctx.sizing);
2290
- const dataWithSizing = sizingStyle ? `${dataScript}
2291
- ${sizingStyle}` : dataScript;
2292
- let bridgeHtml = "";
2293
- if (ctx.includeBridge) {
2294
- const bridgeScript = generateBridgeIIFE({ minify: true });
2295
- bridgeHtml = `<script>${bridgeScript}</script>`;
2296
- }
2297
- const html2 = applyShellTemplate(template, {
2298
- csp: cspTag,
2299
- data: dataWithSizing,
2300
- bridge: bridgeHtml,
2301
- content,
2302
- title: ctx.title ? escapeHtmlForTag(ctx.title) : ""
2303
- });
2304
- return {
2305
- html: html2,
2306
- hash: simpleHash(html2),
2307
- size: Buffer.byteLength(html2, "utf-8")
2308
- };
2309
- }
2310
- function simpleHash(str) {
2311
- let hash = 0;
2312
- for (let i = 0; i < str.length; i++) {
2313
- const char = str.charCodeAt(i);
2314
- hash = (hash << 5) - hash + char | 0;
2315
- }
2316
- return Math.abs(hash).toString(16).padStart(8, "0");
2317
- }
2318
- function escapeHtmlForTag(str) {
2319
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
2320
- }
2321
-
2322
- // libs/uipack/src/component/ui-availability.ts
2323
- function isFrontmcpUiResolvable(...candidatePaths) {
2324
- try {
2325
- const nodeFs = require("fs");
2326
- const nodePath = require("path");
2327
- const ORG = "@frontmcp";
2328
- const PKG = "ui";
2329
- for (const candidate of candidatePaths) {
2330
- let dir = candidate;
2331
- while (true) {
2332
- const pkgJson = nodePath.join(dir, "node_modules", ORG, PKG, "package.json");
2333
- if (nodeFs.existsSync(pkgJson)) return true;
2334
- const parent = nodePath.dirname(dir);
2335
- if (parent === dir) break;
2336
- dir = parent;
2337
- }
2338
- }
2339
- return false;
2340
- } catch {
2341
- return false;
2342
- }
2343
- }
2344
-
2345
- // libs/uipack/src/component/transpiler.ts
2346
- function loadEsbuild(filename) {
2347
- try {
2348
- return require("esbuild");
2349
- } catch (err) {
2350
- if (!isMissingEsbuild(err)) throw err;
2351
- const subject = filename ? `FileSource widget "${filename}"` : "A FileSource widget";
2352
- throw new Error(
2353
- `${subject} needs esbuild, which is not installed. @frontmcp/uipack loads esbuild on demand to bundle FileSource widgets (.tsx/.jsx) when the tool is called, so it must be installed where the server runs: \`npm install esbuild\` (in "dependencies", not "devDependencies"). Projects created with \`frontmcp create\` already get it through the \`frontmcp\` package.`,
2354
- { cause: err }
2355
- );
2356
- }
2357
- }
2358
- function isMissingEsbuild(err) {
2359
- if (!(err instanceof Error)) return false;
2360
- return err.code === "MODULE_NOT_FOUND" && /Cannot find module ['"]esbuild['"]/.test(err.message);
2361
- }
2362
- function transpileReactSource(source, filename) {
2363
- const esbuild = loadEsbuild(filename);
2364
- const loader = filename?.endsWith(".tsx") ? "tsx" : "jsx";
2365
- const result = esbuild.transformSync(source, {
2366
- loader,
2367
- jsx: "transform",
2368
- jsxFactory: "React.createElement",
2369
- jsxFragment: "React.Fragment",
2370
- format: "esm",
2371
- target: "es2020",
2372
- define: { "process.env.NODE_ENV": '"production"' }
2373
- });
2374
- return result.code;
2375
- }
2376
- function bundleFileSource(source, filename, resolveDir, componentName, options = {}) {
2377
- if (!isFrontmcpUiResolvable(resolveDir, process.cwd())) {
2378
- throw new Error(
2379
- `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.`
2380
- );
2381
- }
2382
- const esbuild = loadEsbuild(filename);
2383
- const mountCode = `
1210
+ </html>`;return{html:html2,hash:simpleHash(html2),size:Buffer.byteLength(html2,"utf-8")}}function buildCustomShell(content,customShell,ctx){let template;if(typeof customShell==="string"){const validation=validateShellTemplate(customShell);if(!validation.valid){throw new Error(`Custom shell template is missing required placeholder(s): ${validation.missingRequired.map(n=>`{{${n}}}`).join(", ")}`)}template=customShell}else{template=customShell.template}const cspTag=buildCSPMetaTag(ctx.csp);const dataScript=resolveDataInjectionScript({dataInjection:ctx.dataInjection,toolName:ctx.toolName,input:ctx.input,output:ctx.output,structuredContent:ctx.structuredContent,sizing:ctx.sizing,displayMode:ctx.displayMode});const sizingStyle=buildSizingStyleTag(ctx.sizing);const dataWithSizing=sizingStyle?`${dataScript}
1211
+ ${sizingStyle}`:dataScript;let bridgeHtml="";if(ctx.includeBridge){const bridgeScript=generateBridgeIIFE({minify:true});bridgeHtml=`<script>${bridgeScript}</script>`}const html2=applyShellTemplate(template,{csp:cspTag,data:dataWithSizing,bridge:bridgeHtml,content,title:ctx.title?escapeHtmlForTag(ctx.title):""});return{html:html2,hash:simpleHash(html2),size:Buffer.byteLength(html2,"utf-8")}}function simpleHash(str){let hash=0;for(let i=0;i<str.length;i++){const char=str.charCodeAt(i);hash=(hash<<5)-hash+char|0}return Math.abs(hash).toString(16).padStart(8,"0")}function escapeHtmlForTag(str){return str.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function isFrontmcpUiResolvable(...candidatePaths){try{const nodeFs=require("fs");const nodePath=require("path");const ORG="@frontmcp";const PKG="ui";for(const candidate of candidatePaths){let dir=candidate;while(true){const pkgJson=nodePath.join(dir,"node_modules",ORG,PKG,"package.json");if(nodeFs.existsSync(pkgJson))return true;const parent=nodePath.dirname(dir);if(parent===dir)break;dir=parent}}return false}catch{return false}}function loadEsbuild(filename){try{return require("esbuild")}catch(err){if(!isMissingEsbuild(err))throw err;const subject=filename?`FileSource widget "${filename}"`:"A FileSource widget";throw new Error(`${subject} needs esbuild, which is not installed. @frontmcp/uipack loads esbuild on demand to bundle FileSource widgets (.tsx/.jsx) when the tool is called, so it must be installed where the server runs: \`npm install esbuild\` (in "dependencies", not "devDependencies"). Projects created with \`frontmcp create\` already get it through the \`frontmcp\` package.`,{cause:err})}}function isMissingEsbuild(err){if(!(err instanceof Error))return false;return err.code==="MODULE_NOT_FOUND"&&/Cannot find module ['"]esbuild['"]/.test(err.message)}function transpileReactSource(source,filename){const esbuild=loadEsbuild(filename);const loader=filename?.endsWith(".tsx")?"tsx":"jsx";const result=esbuild.transformSync(source,{loader,jsx:"transform",jsxFactory:"React.createElement",jsxFragment:"React.Fragment",format:"esm",target:"es2020",define:{"process.env.NODE_ENV":'"production"'}});return result.code}function bundleFileSource(source,filename,resolveDir,componentName,options={}){if(!isFrontmcpUiResolvable(resolveDir,process.cwd())){throw new Error(`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.`)}const esbuild=loadEsbuild(filename);const mountCode=`
2384
1212
  // --- Auto-generated mount ---
2385
1213
  import { createElement as __h } from 'react';
2386
1214
  import { createRoot } from 'react-dom/client';
@@ -2422,410 +1250,24 @@ if (__root) {
2422
1250
  if (d) __render(d.structuredContent !== undefined ? d.structuredContent : d.content !== undefined ? d.content : d);
2423
1251
  });
2424
1252
  }
2425
- }`;
2426
- const loader = {
2427
- ".tsx": "tsx",
2428
- ".jsx": "jsx"
2429
- };
2430
- const stdinLoader = filename.endsWith(".tsx") ? "tsx" : "jsx";
2431
- const alias = {};
2432
- try {
2433
- const nodePath = require("path");
2434
- const nodeFs = require("fs");
2435
- const candidates = [
2436
- nodePath.join(process.cwd(), "node_modules", "@frontmcp", "ui", "dist", "esm"),
2437
- nodePath.join(resolveDir, "node_modules", "@frontmcp", "ui", "dist", "esm")
2438
- ];
2439
- for (const uiEsmBase of candidates) {
2440
- if (!nodeFs.existsSync(uiEsmBase)) continue;
2441
- const subpaths = ["components", "react", "theme", "bridge", "runtime"];
2442
- for (const sub of subpaths) {
2443
- const mjs = nodePath.join(uiEsmBase, sub, "index.mjs");
2444
- if (nodeFs.existsSync(mjs)) alias[`@frontmcp/ui/${sub}`] = mjs;
2445
- }
2446
- if (Object.keys(alias).length > 0) break;
2447
- }
2448
- } catch {
2449
- }
2450
- try {
2451
- const result = esbuild.buildSync({
2452
- stdin: {
2453
- contents: source + "\n" + mountCode,
2454
- loader: stdinLoader,
2455
- resolveDir,
2456
- sourcefile: filename
2457
- },
2458
- bundle: true,
2459
- write: false,
2460
- format: "esm",
2461
- target: "es2020",
2462
- jsx: "automatic",
2463
- // When `bundleReact` is set (resourceMode: 'inline'), React itself is
2464
- // bundled — required for hosts that block external script execution
2465
- // such as Claude (#454). Otherwise React stays external and is loaded
2466
- // via the import map emitted by the renderer.
2467
- external: options.bundleReact ? [] : ["react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime"],
2468
- alias,
2469
- define: { "process.env.NODE_ENV": '"production"' },
2470
- platform: "browser",
2471
- treeShaking: true,
2472
- logLevel: "warning",
2473
- loader
2474
- });
2475
- return { code: result.outputFiles[0].text };
2476
- } catch (err) {
2477
- const message = err instanceof Error ? err.message : String(err);
2478
- throw new Error(
2479
- `Failed to bundle FileSource "${filename}": ${message}. If the error mentions @frontmcp/ui or @frontmcp/uipack, ensure both packages are installed in the consuming project.`,
2480
- { cause: err }
2481
- );
2482
- }
2483
- }
2484
- function extractDefaultExportName(code) {
2485
- let match = code.match(/export\s+default\s+(?:function|class)\s+(\w+)/);
2486
- if (match) return match[1];
2487
- match = code.match(/export\s+default\s+(\w+)\s*;/);
2488
- if (match) return match[1];
2489
- return null;
2490
- }
2491
-
2492
- // libs/uipack/src/component/types.ts
2493
- function isNpmSource(source) {
2494
- return typeof source === "object" && source !== null && "npm" in source;
2495
- }
2496
- function isFileSource(source) {
2497
- return typeof source === "object" && source !== null && "file" in source;
2498
- }
2499
- function isImportSource(source) {
2500
- return typeof source === "object" && source !== null && "import" in source;
2501
- }
2502
- function isFunctionSource(source) {
2503
- return typeof source === "function";
2504
- }
2505
-
2506
- // libs/uipack/src/component/loader.ts
2507
- var DEFAULT_META = {
2508
- mcpAware: false,
2509
- renderer: "auto"
2510
- };
2511
- function resolveUISource(source, options) {
2512
- if (options?.inlineReact && options?.transformOnly) {
2513
- throw new Error("resolveUISource: `inlineReact` and `transformOnly` are mutually exclusive \u2014 set at most one.");
2514
- }
2515
- const resolver = options?.resolver ?? createEsmShResolver();
2516
- if (isNpmSource(source)) {
2517
- return resolveNpmSource(source, resolver);
2518
- }
2519
- if (isImportSource(source)) {
2520
- return resolveImportSource(source);
2521
- }
2522
- if (isFileSource(source)) {
2523
- return resolveFileSource(source, { inlineReact: options?.inlineReact, transformOnly: options?.transformOnly });
2524
- }
2525
- if (isFunctionSource(source)) {
2526
- return resolveFunctionSource(source, options?.input, options?.output);
2527
- }
2528
- throw new Error("Unknown UISource type");
2529
- }
2530
- function resolveNpmSource(source, resolver) {
2531
- const specifier = source.version ? `${source.npm}@${source.version}` : source.npm;
2532
- const pkgName = getPackageName(source.npm);
2533
- const resolved = resolver.resolve(specifier);
2534
- const url = resolved?.value ?? `https://esm.sh/${specifier}`;
2535
- const peerDeps = [];
2536
- if (pkgName !== "react" && pkgName !== "react-dom") {
2537
- peerDeps.push("react", "react-dom");
2538
- }
2539
- return {
2540
- mode: "module",
2541
- url,
2542
- exportName: source.exportName ?? "default",
2543
- meta: { ...DEFAULT_META, renderer: "react" },
2544
- peerDependencies: peerDeps
2545
- };
2546
- }
2547
- function resolveImportSource(source) {
2548
- return {
2549
- mode: "module",
2550
- url: source.import,
2551
- exportName: source.exportName ?? "default",
2552
- meta: { ...DEFAULT_META },
2553
- peerDependencies: []
2554
- };
2555
- }
2556
- var BUILD_DIR_SEGMENTS = /* @__PURE__ */ new Set(["dist", "build", "out"]);
2557
- function missingWidgetError(filePath, cause) {
2558
- const sourceWidget = findSourceWidget(filePath);
2559
- const error = new Error(
2560
- `FileSource widget not found (ENOENT): no file at "${filePath}". The widget source is read from this path when the tool is called, so it has to exist where the compiled tool runs \u2014 a path built from \`__dirname\` or \`import.meta.url\` points into the build output once the tool is compiled. tsc does not copy \`*.widget.tsx\` / \`*.widget.jsx\` files into its output; \`frontmcp build\` does, and any other build needs a step that copies them next to the compiled tool.` + (sourceWidget ? ` The source widget exists at "${sourceWidget}" \u2014 copy it to "${filePath}", or build with \`frontmcp build\`.` : ""),
2561
- { cause }
2562
- );
2563
- error.code = "ENOENT";
2564
- error.path = filePath;
2565
- return error;
2566
- }
2567
- function findSourceWidget(filePath) {
2568
- const path = require("path");
2569
- const fs = require("fs");
2570
- const parts = filePath.split(path.sep);
2571
- for (let i = parts.length - 2; i >= 0; i--) {
2572
- if (!BUILD_DIR_SEGMENTS.has(parts[i])) continue;
2573
- const candidates = [[...parts.slice(0, i), "src", ...parts.slice(i + 1)]];
2574
- if (parts.length - i > 2) candidates.push([...parts.slice(0, i), "src", ...parts.slice(i + 2)]);
2575
- candidates.push([...parts.slice(0, i), ...parts.slice(i + 1)]);
2576
- for (const candidate of candidates) {
2577
- const candidatePath = candidate.join(path.sep);
2578
- try {
2579
- if (fs.existsSync(candidatePath)) return candidatePath;
2580
- } catch {
2581
- }
2582
- }
2583
- return void 0;
2584
- }
2585
- return void 0;
2586
- }
2587
- function resolveFileSource(source, options = {}) {
2588
- const path = require("path");
2589
- const ext = path.extname(source.file).toLowerCase();
2590
- if (ext === ".tsx" || ext === ".jsx") {
2591
- const fs = require("fs");
2592
- const wasRelative = !path.isAbsolute(source.file);
2593
- const filePath = wasRelative ? path.resolve(process.cwd(), source.file) : source.file;
2594
- let rawSource;
2595
- try {
2596
- rawSource = fs.readFileSync(filePath, "utf-8");
2597
- } catch (err) {
2598
- const isNotFound = err?.code === "ENOENT";
2599
- if (isNotFound && wasRelative) {
2600
- throw new Error(
2601
- `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).`,
2602
- { cause: err }
2603
- );
2604
- }
2605
- if (isNotFound) throw missingWidgetError(filePath, err);
2606
- throw err;
2607
- }
2608
- const componentName = source.exportName || extractDefaultExportName(rawSource) || "Component";
2609
- if (options.transformOnly === true) {
2610
- const code = transpileReactSource(rawSource, path.basename(filePath));
2611
- const parsed2 = parseImports(code);
2612
- return {
2613
- mode: "module",
2614
- code,
2615
- imports: [...new Set(parsed2.externalImports.map((i) => i.specifier))],
2616
- exportName: componentName,
2617
- meta: { mcpAware: true, renderer: "react" },
2618
- peerDependencies: source.peerDependencies || ["react", "react-dom"],
2619
- bundled: false
2620
- };
2621
- }
2622
- const bundled = bundleFileSource(rawSource, source.file, path.dirname(filePath), componentName, {
2623
- bundleReact: options.inlineReact === true
2624
- });
2625
- const parsed = parseImports(bundled.code);
2626
- return {
2627
- mode: "module",
2628
- code: bundled.code,
2629
- imports: [...new Set(parsed.externalImports.map((i) => i.specifier))],
2630
- exportName: componentName,
2631
- meta: { mcpAware: true, renderer: "react" },
2632
- peerDependencies: source.peerDependencies || ["react", "react-dom"],
2633
- bundled: true
2634
- };
2635
- }
2636
- if (source.inline) {
2637
- return {
2638
- mode: "inline",
2639
- html: `<!-- File source: ${source.file} (inline mode - content to be resolved at build time) -->`,
2640
- exportName: "default",
2641
- meta: { ...DEFAULT_META, renderer: "html" },
2642
- peerDependencies: []
2643
- };
2644
- }
2645
- return {
2646
- mode: "module",
2647
- url: source.file,
2648
- exportName: "default",
2649
- meta: { ...DEFAULT_META },
2650
- peerDependencies: []
2651
- };
2652
- }
2653
- function resolveFunctionSource(source, input, output) {
2654
- const html2 = source(input, output);
2655
- return {
2656
- mode: "inline",
2657
- html: html2,
2658
- exportName: "default",
2659
- meta: { mcpAware: false, renderer: "html" },
2660
- peerDependencies: []
2661
- };
2662
- }
2663
- function generateMountScript(resolved, propsMapping) {
2664
- if (resolved.mode !== "module" || !resolved.url) {
2665
- return "";
2666
- }
2667
- const componentImport = resolved.exportName === "default" ? `import Component from '${resolved.url}';` : `import { ${resolved.exportName} as Component } from '${resolved.url}';`;
2668
- if (resolved.meta.mcpAware) {
2669
- return `${componentImport}
1253
+ }`;const loader={".tsx":"tsx",".jsx":"jsx"};const stdinLoader=filename.endsWith(".tsx")?"tsx":"jsx";const alias={};try{const nodePath=require("path");const nodeFs=require("fs");const candidates=[nodePath.join(process.cwd(),"node_modules","@frontmcp","ui","dist","esm"),nodePath.join(resolveDir,"node_modules","@frontmcp","ui","dist","esm")];for(const uiEsmBase of candidates){if(!nodeFs.existsSync(uiEsmBase))continue;const subpaths=["components","react","theme","bridge","runtime"];for(const sub of subpaths){const mjs=nodePath.join(uiEsmBase,sub,"index.mjs");if(nodeFs.existsSync(mjs))alias[`@frontmcp/ui/${sub}`]=mjs}if(Object.keys(alias).length>0)break}}catch{}try{const result=esbuild.buildSync({stdin:{contents:source+"\n"+mountCode,loader:stdinLoader,resolveDir,sourcefile:filename},bundle:true,write:false,format:"esm",target:"es2020",jsx:"automatic",external:options.bundleReact?[]:["react","react-dom","react/jsx-runtime","react/jsx-dev-runtime"],alias,define:{"process.env.NODE_ENV":'"production"'},platform:"browser",treeShaking:true,logLevel:"warning",loader});return{code:result.outputFiles[0].text}}catch(err){const message=err instanceof Error?err.message:String(err);throw new Error(`Failed to bundle FileSource "${filename}": ${message}. If the error mentions @frontmcp/ui or @frontmcp/uipack, ensure both packages are installed in the consuming project.`,{cause:err})}}function extractDefaultExportName(code){let match=code.match(/export\s+default\s+(?:function|class)\s+(\w+)/);if(match)return match[1];match=code.match(/export\s+default\s+(\w+)\s*;/);if(match)return match[1];return null}function isNpmSource(source){return typeof source==="object"&&source!==null&&"npm"in source}function isFileSource(source){return typeof source==="object"&&source!==null&&"file"in source}function isImportSource(source){return typeof source==="object"&&source!==null&&"import"in source}function isFunctionSource(source){return typeof source==="function"}var DEFAULT_META={mcpAware:false,renderer:"auto"};function resolveUISource(source,options){if(options?.inlineReact&&options?.transformOnly){throw new Error("resolveUISource: `inlineReact` and `transformOnly` are mutually exclusive \u2014 set at most one.")}const resolver=options?.resolver??createEsmShResolver();if(isNpmSource(source)){return resolveNpmSource(source,resolver)}if(isImportSource(source)){return resolveImportSource(source)}if(isFileSource(source)){return resolveFileSource(source,{inlineReact:options?.inlineReact,transformOnly:options?.transformOnly})}if(isFunctionSource(source)){return resolveFunctionSource(source,options?.input,options?.output)}throw new Error("Unknown UISource type")}function resolveNpmSource(source,resolver){const specifier=source.version?`${source.npm}@${source.version}`:source.npm;const pkgName=getPackageName(source.npm);const resolved=resolver.resolve(specifier);const url=resolved?.value??`https://esm.sh/${specifier}`;const peerDeps=[];if(pkgName!=="react"&&pkgName!=="react-dom"){peerDeps.push("react","react-dom")}return{mode:"module",url,exportName:source.exportName??"default",meta:{...DEFAULT_META,renderer:"react"},peerDependencies:peerDeps}}function resolveImportSource(source){return{mode:"module",url:source.import,exportName:source.exportName??"default",meta:{...DEFAULT_META},peerDependencies:[]}}var BUILD_DIR_SEGMENTS=new Set(["dist","build","out"]);function missingWidgetError(filePath,cause){const sourceWidget=findSourceWidget(filePath);const error=new Error(`FileSource widget not found (ENOENT): no file at "${filePath}". The widget source is read from this path when the tool is called, so it has to exist where the compiled tool runs \u2014 a path built from \`__dirname\` or \`import.meta.url\` points into the build output once the tool is compiled. tsc does not copy \`*.widget.tsx\` / \`*.widget.jsx\` files into its output; \`frontmcp build\` does, and any other build needs a step that copies them next to the compiled tool.`+(sourceWidget?` The source widget exists at "${sourceWidget}" \u2014 copy it to "${filePath}", or build with \`frontmcp build\`.`:""),{cause});error.code="ENOENT";error.path=filePath;return error}function findSourceWidget(filePath){const path=require("path");const fs=require("fs");const parts=filePath.split(path.sep);for(let i=parts.length-2;i>=0;i--){if(!BUILD_DIR_SEGMENTS.has(parts[i]))continue;const candidates=[[...parts.slice(0,i),"src",...parts.slice(i+1)]];if(parts.length-i>2)candidates.push([...parts.slice(0,i),"src",...parts.slice(i+2)]);candidates.push([...parts.slice(0,i),...parts.slice(i+1)]);for(const candidate of candidates){const candidatePath=candidate.join(path.sep);try{if(fs.existsSync(candidatePath))return candidatePath}catch{}}return void 0}return void 0}function resolveFileSource(source,options={}){const path=require("path");const ext=path.extname(source.file).toLowerCase();if(ext===".tsx"||ext===".jsx"){const fs=require("fs");const wasRelative=!path.isAbsolute(source.file);const filePath=wasRelative?path.resolve(process.cwd(),source.file):source.file;let rawSource;try{rawSource=fs.readFileSync(filePath,"utf-8")}catch(err){const isNotFound=err?.code==="ENOENT";if(isNotFound&&wasRelative){throw new Error(`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).`,{cause:err})}if(isNotFound)throw missingWidgetError(filePath,err);throw err}const componentName=source.exportName||extractDefaultExportName(rawSource)||"Component";if(options.transformOnly===true){const code=transpileReactSource(rawSource,path.basename(filePath));const parsed2=parseImports(code);return{mode:"module",code,imports:[...new Set(parsed2.externalImports.map(i=>i.specifier))],exportName:componentName,meta:{mcpAware:true,renderer:"react"},peerDependencies:source.peerDependencies||["react","react-dom"],bundled:false}}const bundled=bundleFileSource(rawSource,source.file,path.dirname(filePath),componentName,{bundleReact:options.inlineReact===true});const parsed=parseImports(bundled.code);return{mode:"module",code:bundled.code,imports:[...new Set(parsed.externalImports.map(i=>i.specifier))],exportName:componentName,meta:{mcpAware:true,renderer:"react"},peerDependencies:source.peerDependencies||["react","react-dom"],bundled:true}}if(source.inline){return{mode:"inline",html:`<!-- File source: ${source.file} (inline mode - content to be resolved at build time) -->`,exportName:"default",meta:{...DEFAULT_META,renderer:"html"},peerDependencies:[]}}return{mode:"module",url:source.file,exportName:"default",meta:{...DEFAULT_META},peerDependencies:[]}}function resolveFunctionSource(source,input,output){const html2=source(input,output);return{mode:"inline",html:html2,exportName:"default",meta:{mcpAware:false,renderer:"html"},peerDependencies:[]}}function generateMountScript(resolved,propsMapping){if(resolved.mode!=="module"||!resolved.url){return""}const componentImport=resolved.exportName==="default"?`import Component from '${resolved.url}';`:`import { ${resolved.exportName} as Component } from '${resolved.url}';`;if(resolved.meta.mcpAware){return`${componentImport}
2670
1254
  import React from 'react';
2671
1255
  import { createRoot } from 'react-dom/client';
2672
1256
  createRoot(document.getElementById('root'))
2673
- .render(React.createElement(Component));`;
2674
- }
2675
- const propsCode = propsMapping ? generateMappedPropsCode(propsMapping) : "window.__mcpToolOutput";
2676
- return `${componentImport}
1257
+ .render(React.createElement(Component));`}const propsCode=propsMapping?generateMappedPropsCode(propsMapping):"window.__mcpToolOutput";return`${componentImport}
2677
1258
  import React from 'react';
2678
1259
  import { createRoot } from 'react-dom/client';
2679
1260
  const output = window.__mcpToolOutput || {};
2680
1261
  const props = ${propsCode};
2681
1262
  createRoot(document.getElementById('root'))
2682
- .render(React.createElement(Component, props));`;
2683
- }
2684
- function generateMappedPropsCode(mapping) {
2685
- const entries = Object.entries(mapping).map(([prop, path]) => {
2686
- const accessPath = path.split(".").map((part) => `[${safeJsonForScript(part)}]`).join("");
2687
- return `${safeJsonForScript(prop)}: output${accessPath}`;
2688
- }).join(", ");
2689
- return `({ ${entries} })`;
2690
- }
2691
-
2692
- // libs/uipack/src/component/renderer.ts
2693
- var DEFAULT_WIDGET_MOUNT = {
2694
- moduleSpecifier: "@frontmcp/ui/react",
2695
- wrapperImportName: "McpBridgeProvider"
2696
- };
2697
- function renderComponent(config, shellConfig) {
2698
- const resolver = shellConfig.resolver ?? createEsmShResolver();
2699
- const resolved = resolveUISource(config.source, {
2700
- resolver,
2701
- input: shellConfig.input,
2702
- output: shellConfig.output,
2703
- inlineReact: config.inlineReact === true,
2704
- transformOnly: config.transformOnly === true
2705
- });
2706
- const mergedShellConfig = {
2707
- ...shellConfig,
2708
- withShell: config.withShell ?? shellConfig.withShell,
2709
- includeBridge: config.includeBridge ?? shellConfig.includeBridge,
2710
- customShell: config.customShell ?? shellConfig.customShell
2711
- };
2712
- if (resolved.mode === "inline") {
2713
- return buildShell(resolved.html ?? "", mergedShellConfig);
2714
- }
2715
- const content = buildModuleContent(resolved, resolver, config.props, shellConfig.mount);
2716
- return buildShell(content, mergedShellConfig);
2717
- }
2718
- function buildModuleContent(resolved, resolver, propsMapping, mount = DEFAULT_WIDGET_MOUNT) {
2719
- const parts = [];
2720
- if (resolved.code && resolved.bundled) {
2721
- const importEntries = {};
2722
- for (const spec of resolved.imports || []) {
2723
- const depResolved = resolver.resolve(spec);
2724
- if (depResolved) {
2725
- importEntries[spec] = depResolved;
2726
- }
2727
- }
2728
- if (Object.keys(importEntries).length > 0) {
2729
- const importMap = createImportMapFromResolved(importEntries);
2730
- parts.push(generateImportMapScriptTag(importMap));
2731
- }
2732
- parts.push('<div id="root"></div>');
2733
- parts.push(`<script type="module">
1263
+ .render(React.createElement(Component, props));`}function generateMappedPropsCode(mapping){const entries=Object.entries(mapping).map(([prop,path])=>{const accessPath=path.split(".").map(part=>`[${safeJsonForScript(part)}]`).join("");return`${safeJsonForScript(prop)}: output${accessPath}`}).join(", ");return`({ ${entries} })`}var DEFAULT_WIDGET_MOUNT={moduleSpecifier:"@frontmcp/ui/react",wrapperImportName:"McpBridgeProvider"};function renderComponent(config,shellConfig){const resolver=shellConfig.resolver??createEsmShResolver();const resolved=resolveUISource(config.source,{resolver,input:shellConfig.input,output:shellConfig.output,inlineReact:config.inlineReact===true,transformOnly:config.transformOnly===true});const mergedShellConfig={...shellConfig,withShell:config.withShell??shellConfig.withShell,includeBridge:config.includeBridge??shellConfig.includeBridge,customShell:config.customShell??shellConfig.customShell};if(resolved.mode==="inline"){return buildShell(resolved.html??"",mergedShellConfig)}const content=buildModuleContent(resolved,resolver,config.props,shellConfig.mount);return buildShell(content,mergedShellConfig)}function buildModuleContent(resolved,resolver,propsMapping,mount=DEFAULT_WIDGET_MOUNT){const parts=[];if(resolved.code&&resolved.bundled){const importEntries={};for(const spec of resolved.imports||[]){const depResolved=resolver.resolve(spec);if(depResolved){importEntries[spec]=depResolved}}if(Object.keys(importEntries).length>0){const importMap=createImportMapFromResolved(importEntries);parts.push(generateImportMapScriptTag(importMap))}parts.push('<div id="root"></div>');parts.push(`<script type="module">
2734
1264
  ${resolved.code}
2735
- </script>`);
2736
- } else if (resolved.code) {
2737
- const importEntries = {};
2738
- const allSpecifiers = /* @__PURE__ */ new Set([
2739
- ...resolved.imports || [],
2740
- "react-dom/client",
2741
- // needed by mount script
2742
- mount.moduleSpecifier,
2743
- // mounter/provider package (e.g. @frontmcp/ui/react)
2744
- // React subpath entries needed by esm.sh externalized modules:
2745
- "react/jsx-runtime",
2746
- "react/jsx-dev-runtime"
2747
- ]);
2748
- if (mount === DEFAULT_WIDGET_MOUNT) {
2749
- allSpecifiers.add("react-dom/server");
2750
- allSpecifiers.add("react-dom/static");
2751
- }
2752
- const coreDeps = /* @__PURE__ */ new Set([
2753
- "react",
2754
- "react-dom",
2755
- "react-dom/client",
2756
- "react/jsx-runtime",
2757
- "react/jsx-dev-runtime",
2758
- "react-dom/server",
2759
- "react-dom/static"
2760
- ]);
2761
- for (const spec of allSpecifiers) {
2762
- const depResolved = resolver.resolve(spec);
2763
- if (depResolved) {
2764
- if (!coreDeps.has(spec) && depResolved.value?.includes("esm.sh")) {
2765
- importEntries[spec] = {
2766
- ...depResolved,
2767
- value: addExternalParam(depResolved.value, ["react", "react-dom"])
2768
- };
2769
- } else {
2770
- importEntries[spec] = depResolved;
2771
- }
2772
- }
2773
- }
2774
- if (importEntries["react-dom"] && !importEntries["react-dom/client"]) {
2775
- const rdc = resolver.resolve("react-dom/client");
2776
- if (rdc) importEntries["react-dom/client"] = rdc;
2777
- }
2778
- if (Object.keys(importEntries).length > 0) {
2779
- const importMap = createImportMapFromResolved(importEntries);
2780
- parts.push(generateImportMapScriptTag(importMap));
2781
- }
2782
- const mountNodeId = mount.mountNodeId ?? "root";
2783
- parts.push(`<div id="${mountNodeId}">${mount.mountNodeInnerHtml ?? ""}</div>`);
2784
- const mountCode = generateInlineMountCode(resolved.exportName, mount);
2785
- parts.push(`<script type="module">
1265
+ </script>`)}else if(resolved.code){const importEntries={};const allSpecifiers=new Set([...resolved.imports||[],"react-dom/client",mount.moduleSpecifier,"react/jsx-runtime","react/jsx-dev-runtime"]);if(mount===DEFAULT_WIDGET_MOUNT){allSpecifiers.add("react-dom/server");allSpecifiers.add("react-dom/static")}const coreDeps=new Set(["react","react-dom","react-dom/client","react/jsx-runtime","react/jsx-dev-runtime","react-dom/server","react-dom/static"]);for(const spec of allSpecifiers){const depResolved=resolver.resolve(spec);if(depResolved){if(!coreDeps.has(spec)&&depResolved.value?.includes("esm.sh")){importEntries[spec]={...depResolved,value:addExternalParam(depResolved.value,["react","react-dom"])}}else{importEntries[spec]=depResolved}}}if(importEntries["react-dom"]&&!importEntries["react-dom/client"]){const rdc=resolver.resolve("react-dom/client");if(rdc)importEntries["react-dom/client"]=rdc}if(Object.keys(importEntries).length>0){const importMap=createImportMapFromResolved(importEntries);parts.push(generateImportMapScriptTag(importMap))}const mountNodeId=mount.mountNodeId??"root";parts.push(`<div id="${mountNodeId}">${mount.mountNodeInnerHtml??""}</div>`);const mountCode=generateInlineMountCode(resolved.exportName,mount);parts.push(`<script type="module">
2786
1266
  ${resolved.code}
2787
1267
  ${mountCode}
2788
- </script>`);
2789
- } else {
2790
- const importEntries = {};
2791
- for (const dep of resolved.peerDependencies) {
2792
- const depResolved = resolver.resolve(dep);
2793
- if (depResolved) {
2794
- importEntries[dep] = depResolved;
2795
- }
2796
- }
2797
- if (importEntries["react-dom"]) {
2798
- const reactDomClient = resolver.resolve("react-dom/client");
2799
- if (reactDomClient) {
2800
- importEntries["react-dom/client"] = reactDomClient;
2801
- }
2802
- }
2803
- if (Object.keys(importEntries).length > 0) {
2804
- const importMap = createImportMapFromResolved(importEntries);
2805
- parts.push(generateImportMapScriptTag(importMap));
2806
- }
2807
- parts.push('<div id="root"></div>');
2808
- const mountScript = generateMountScript(resolved, propsMapping);
2809
- if (mountScript) {
2810
- parts.push(`<script type="module">
1268
+ </script>`)}else{const importEntries={};for(const dep of resolved.peerDependencies){const depResolved=resolver.resolve(dep);if(depResolved){importEntries[dep]=depResolved}}if(importEntries["react-dom"]){const reactDomClient=resolver.resolve("react-dom/client");if(reactDomClient){importEntries["react-dom/client"]=reactDomClient}}if(Object.keys(importEntries).length>0){const importMap=createImportMapFromResolved(importEntries);parts.push(generateImportMapScriptTag(importMap))}parts.push('<div id="root"></div>');const mountScript=generateMountScript(resolved,propsMapping);if(mountScript){parts.push(`<script type="module">
2811
1269
  ${mountScript}
2812
- </script>`);
2813
- }
2814
- }
2815
- return parts.join("\n");
2816
- }
2817
- function addExternalParam(url, externals) {
2818
- const sep = url.includes("?") ? "&" : "?";
2819
- return `${url}${sep}external=${externals.join(",")}`;
2820
- }
2821
- function generateInlineMountCode(componentName, mount) {
2822
- if (mount.generate) {
2823
- return mount.generate(componentName);
2824
- }
2825
- const wrapperName = mount.wrapperImportName ?? "McpBridgeProvider";
2826
- const wrapperAlias = `__${wrapperName}`;
2827
- const mountNodeId = mount.mountNodeId ?? "root";
2828
- return `
1270
+ </script>`)}}return parts.join("\n")}function addExternalParam(url,externals){const sep=url.includes("?")?"&":"?";return`${url}${sep}external=${externals.join(",")}`}function generateInlineMountCode(componentName,mount){if(mount.generate){return mount.generate(componentName)}const wrapperName=mount.wrapperImportName??"McpBridgeProvider";const wrapperAlias=`__${wrapperName}`;const mountNodeId=mount.mountNodeId??"root";return`
2829
1271
  // --- Mount ---
2830
1272
  import { createRoot as __createRoot } from 'react-dom/client';
2831
1273
  import { ${wrapperName} as ${wrapperAlias} } from '${mount.moduleSpecifier}';
@@ -2836,101 +1278,18 @@ if (__root) {
2836
1278
  React.createElement(${componentName})
2837
1279
  )
2838
1280
  );
2839
- }`;
2840
- }
2841
-
2842
- // libs/uipack/src/adapters/content-detector.ts
2843
- var CHART_TYPES = /* @__PURE__ */ new Set(["bar", "line", "pie", "area", "scatter", "doughnut", "radar", "polarArea", "bubble"]);
2844
- var MERMAID_PREFIXES = [
2845
- "flowchart",
2846
- "graph",
2847
- "sequenceDiagram",
2848
- "classDiagram",
2849
- "stateDiagram",
2850
- "erDiagram",
2851
- "gantt",
2852
- "pie",
2853
- "gitGraph",
2854
- "journey",
2855
- "mindmap",
2856
- "timeline",
2857
- "quadrantChart",
2858
- "sankey",
2859
- "xychart"
2860
- ];
2861
- var PDF_MAGIC = "JVBERi";
2862
- var BASE64_PATTERN = /^[A-Za-z0-9+/=\r\n]+$/;
2863
- function detectContentType(value) {
2864
- if (value === null || value === void 0) {
2865
- return "text";
2866
- }
2867
- if (typeof value === "object" && !Array.isArray(value)) {
2868
- const obj = value;
2869
- if (typeof obj["type"] === "string" && CHART_TYPES.has(obj["type"])) {
2870
- return "chart";
2871
- }
2872
- return "json";
2873
- }
2874
- if (typeof value === "string") {
2875
- const trimmed = value.trimStart();
2876
- if (trimmed.startsWith(PDF_MAGIC)) {
2877
- return BASE64_PATTERN.test(trimmed.trimEnd()) ? "pdf" : "text";
2878
- }
2879
- for (const prefix of MERMAID_PREFIXES) {
2880
- if (trimmed.startsWith(prefix)) {
2881
- return "mermaid";
2882
- }
2883
- }
2884
- if (trimmed.includes("<") && trimmed.includes(">")) {
2885
- return "html";
2886
- }
2887
- return "text";
2888
- }
2889
- return "text";
2890
- }
2891
-
2892
- // libs/uipack/src/adapters/content-renderers.ts
2893
- var CHART_JS_CDN = "https://esm.sh/chart.js@4/auto";
2894
- var MERMAID_CDN = "https://esm.sh/mermaid@11/dist/mermaid.esm.min.mjs";
2895
- function buildChartHtml(chartJson) {
2896
- const chartData = safeJsonForScript(chartJson);
2897
- const content = `
1281
+ }`}var CHART_TYPES=new Set(["bar","line","pie","area","scatter","doughnut","radar","polarArea","bubble"]);var MERMAID_PREFIXES=["flowchart","graph","sequenceDiagram","classDiagram","stateDiagram","erDiagram","gantt","pie","gitGraph","journey","mindmap","timeline","quadrantChart","sankey","xychart"];var PDF_MAGIC="JVBERi";var BASE64_PATTERN=/^[A-Za-z0-9+/=\r\n]+$/;function detectContentType(value){if(value===null||value===void 0){return"text"}if(typeof value==="object"&&!Array.isArray(value)){const obj=value;if(typeof obj["type"]==="string"&&CHART_TYPES.has(obj["type"])){return"chart"}return"json"}if(typeof value==="string"){const trimmed=value.trimStart();if(trimmed.startsWith(PDF_MAGIC)){return BASE64_PATTERN.test(trimmed.trimEnd())?"pdf":"text"}for(const prefix of MERMAID_PREFIXES){if(trimmed.startsWith(prefix)){return"mermaid"}}if(trimmed.includes("<")&&trimmed.includes(">")){return"html"}return"text"}return"text"}var CHART_JS_CDN="https://esm.sh/chart.js@4/auto";var MERMAID_CDN="https://esm.sh/mermaid@11/dist/mermaid.esm.min.mjs";function buildChartHtml(chartJson){const chartData=safeJsonForScript(chartJson);const content=`
2898
1282
  <canvas id="chart" style="max-width:100%;max-height:80vh;"></canvas>
2899
1283
  <script type="module">
2900
1284
  import Chart from '${CHART_JS_CDN}';
2901
1285
  const ctx = document.getElementById('chart').getContext('2d');
2902
1286
  new Chart(ctx, ${chartData});
2903
- </script>`;
2904
- const result = buildShell(content, {
2905
- toolName: "chart",
2906
- csp: {
2907
- resourceDomains: ["https://esm.sh"],
2908
- connectDomains: ["https://esm.sh"]
2909
- },
2910
- includeBridge: false
2911
- });
2912
- return result.html;
2913
- }
2914
- function buildMermaidHtml(mermaidCode) {
2915
- const escaped = escapeHtml(mermaidCode);
2916
- const content = `
1287
+ </script>`;const result=buildShell(content,{toolName:"chart",csp:{resourceDomains:["https://esm.sh"],connectDomains:["https://esm.sh"]},includeBridge:false});return result.html}function buildMermaidHtml(mermaidCode){const escaped=escapeHtml(mermaidCode);const content=`
2917
1288
  <pre class="mermaid">${escaped}</pre>
2918
1289
  <script type="module">
2919
1290
  import mermaid from '${MERMAID_CDN}';
2920
1291
  mermaid.initialize({ startOnLoad: true, theme: 'default' });
2921
- </script>`;
2922
- const result = buildShell(content, {
2923
- toolName: "mermaid",
2924
- csp: {
2925
- resourceDomains: ["https://esm.sh"],
2926
- connectDomains: ["https://esm.sh"]
2927
- },
2928
- includeBridge: false
2929
- });
2930
- return result.html;
2931
- }
2932
- function buildPdfHtml(base64) {
2933
- const content = `
1292
+ </script>`;const result=buildShell(content,{toolName:"mermaid",csp:{resourceDomains:["https://esm.sh"],connectDomains:["https://esm.sh"]},includeBridge:false});return result.html}function buildPdfHtml(base64){const content=`
2934
1293
  <div id="pdf-container" style="width:100%;overflow:auto;text-align:center;"></div>
2935
1294
  <script type="module">
2936
1295
  import * as pdfjsLib from 'https://esm.sh/pdfjs-dist@4/build/pdf.min.mjs';
@@ -2953,319 +1312,8 @@ for (let i = 1; i <= pdf.numPages; i++) {
2953
1312
  container.appendChild(canvas);
2954
1313
  await page.render({ canvasContext: canvas.getContext('2d'), viewport }).promise;
2955
1314
  }
2956
- </script>`;
2957
- const result = buildShell(content, {
2958
- toolName: "pdf",
2959
- csp: {
2960
- resourceDomains: ["https://esm.sh"],
2961
- connectDomains: ["https://esm.sh"]
2962
- },
2963
- includeBridge: false
2964
- });
2965
- return result.html;
2966
- }
2967
- function wrapDetectedContent(value) {
2968
- const contentType = detectContentType(value);
2969
- switch (contentType) {
2970
- case "chart":
2971
- return buildChartHtml(value);
2972
- case "mermaid":
2973
- return buildMermaidHtml(value);
2974
- case "pdf":
2975
- return buildPdfHtml(value);
2976
- case "html":
2977
- return void 0;
2978
- default:
2979
- return void 0;
2980
- }
2981
- }
2982
-
2983
- // libs/uipack/src/adapters/markdown.ts
2984
- var SAFE_HREF = /^(https?:|mailto:|\/|#)/i;
2985
- function emphasis(text) {
2986
- return text.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>").replace(/\*([^*]+)\*/g, "<em>$1</em>");
2987
- }
2988
- function inline(text) {
2989
- const stash = [];
2990
- const hold = (html2) => `\uE000${stash.push(html2) - 1}\uE000`;
2991
- let out = escapeHtml(text.replace(/\uE000/g, "")).replace(
2992
- /`([^`]+)`/g,
2993
- (_m, code) => hold(`<code>${code}</code>`)
2994
- );
2995
- out = out.replace(
2996
- /\[([^\]]+)\]\(([^)\s]+)\)/g,
2997
- (_m, label, href) => SAFE_HREF.test(href) ? hold(`<a href="${href}" rel="noopener noreferrer">${emphasis(label)}</a>`) : label
2998
- );
2999
- out = emphasis(out);
3000
- for (let i = 0; i < 2; i++) out = out.replace(/\uE000(\d+)\uE000/g, (_m, n) => stash[Number(n)]);
3001
- return out;
3002
- }
3003
- function markdownToHtml(source) {
3004
- const lines = source.replace(/\r\n?/g, "\n").split("\n");
3005
- const blocks = [];
3006
- let paragraph = [];
3007
- let list;
3008
- const flushParagraph = () => {
3009
- if (paragraph.length > 0) blocks.push(`<p>${inline(paragraph.join(" "))}</p>`);
3010
- paragraph = [];
3011
- };
3012
- const flushList = () => {
3013
- if (list)
3014
- blocks.push(`<${list.tag}>${list.items.map((item) => `<li>${inline(item)}</li>`).join("")}</${list.tag}>`);
3015
- list = void 0;
3016
- };
3017
- for (let i = 0; i < lines.length; i++) {
3018
- const line = lines[i];
3019
- const fence = /^\s*(`{3,})/.exec(line);
3020
- if (fence) {
3021
- flushParagraph();
3022
- flushList();
3023
- const fenceLength = fence[1].length;
3024
- const isClosing = (l) => {
3025
- const m = /^\s*(`{3,})\s*$/.exec(l);
3026
- return m !== null && m[1].length >= fenceLength;
3027
- };
3028
- const code = [];
3029
- for (i++; i < lines.length && !isClosing(lines[i]); i++) code.push(lines[i]);
3030
- blocks.push(`<pre><code>${escapeHtml(code.join("\n"))}
3031
- </code></pre>`);
3032
- continue;
3033
- }
3034
- const heading = /^(#{1,6})\s+(.*)$/.exec(line);
3035
- if (heading) {
3036
- flushParagraph();
3037
- flushList();
3038
- blocks.push(`<h${heading[1].length}>${inline(heading[2].trim())}</h${heading[1].length}>`);
3039
- continue;
3040
- }
3041
- const item = /^\s*([-*+]|\d+\.)\s+(.*)$/.exec(line);
3042
- if (item) {
3043
- flushParagraph();
3044
- const tag = /\d/.test(item[1]) ? "ol" : "ul";
3045
- if (list && list.tag !== tag) flushList();
3046
- list ??= { tag, items: [] };
3047
- list.items.push(item[2]);
3048
- continue;
3049
- }
3050
- if (line.trim() === "") {
3051
- flushParagraph();
3052
- flushList();
3053
- continue;
3054
- }
3055
- flushList();
3056
- paragraph.push(line.trim());
3057
- }
3058
- flushParagraph();
3059
- flushList();
3060
- return blocks.join("\n");
3061
- }
3062
-
3063
- // libs/uipack/src/adapters/type-detector.ts
3064
- function detectUIType(template) {
3065
- if (template === null || template === void 0) {
3066
- return "auto";
3067
- }
3068
- if (typeof template === "object" && template !== null && "file" in template) {
3069
- const file = template.file;
3070
- if (/\.(tsx|jsx)$/i.test(file)) return "react";
3071
- }
3072
- if (typeof template === "function") {
3073
- const proto = template.prototype;
3074
- if (proto && typeof proto.render === "function") {
3075
- return "react";
3076
- }
3077
- const asRecord = template;
3078
- if (asRecord["$$typeof"] !== void 0) {
3079
- return "react";
3080
- }
3081
- if (template.name && /^[A-Z]/.test(template.name)) {
3082
- return "react";
3083
- }
3084
- return "html";
3085
- }
3086
- if (typeof template === "string") {
3087
- if (template.includes("<") && template.includes(">")) {
3088
- return "html";
3089
- }
3090
- return "markdown";
3091
- }
3092
- return "auto";
3093
- }
3094
-
3095
- // libs/uipack/src/adapters/template-renderer.ts
3096
- function buildCspConfig(resolver, extra) {
3097
- const cspResourceDomains = ["https://esm.sh"];
3098
- const cspConnectDomains = ["https://esm.sh"];
3099
- for (const domain of extra?.resourceDomains ?? []) {
3100
- if (!cspResourceDomains.includes(domain)) cspResourceDomains.push(domain);
3101
- }
3102
- for (const domain of extra?.connectDomains ?? []) {
3103
- if (!cspConnectDomains.includes(domain)) cspConnectDomains.push(domain);
3104
- }
3105
- if (resolver && "overrides" in resolver) {
3106
- const overrides = resolver.overrides;
3107
- if (overrides) {
3108
- for (const url of Object.values(overrides)) {
3109
- try {
3110
- const origin = new URL(url).origin;
3111
- if (!cspResourceDomains.includes(origin)) cspResourceDomains.push(origin);
3112
- if (!cspConnectDomains.includes(origin)) cspConnectDomains.push(origin);
3113
- } catch {
3114
- }
3115
- }
3116
- }
3117
- }
3118
- return { resourceDomains: cspResourceDomains, connectDomains: cspConnectDomains };
3119
- }
3120
- var STRING_RESULT_DOCS = "https://frontmcp.dev/learn/your-first-widget";
3121
- var noticedStringResultTools = /* @__PURE__ */ new Set();
3122
- function noticeStringResult(toolName, logger) {
3123
- if (noticedStringResultTools.has(toolName)) return;
3124
- noticedStringResultTools.add(toolName);
3125
- logger.warn(
3126
- `[frontmcp] The UI template of tool "${toolName}" returned a plain string containing markup. Since 1.9.2, FrontMCP HTML-escapes plain string results by default, so it is shown as text. Build the markup with ctx.helpers.html\`\u2026\` (interpolated values are escaped) or wrap safe markup with ctx.helpers.trustedHtml(). Set ui.escapeStringResults: false to render plain strings as markup, or true to silence this notice. See ${STRING_RESULT_DOCS}`
3127
- );
3128
- }
3129
- function renderUnwrappedResult(rawResult, options) {
3130
- if (isTrustedHtml(rawResult)) {
3131
- return String(rawResult);
3132
- }
3133
- if (typeof rawResult !== "string") {
3134
- return `<pre>${escapeHtml(JSON.stringify(rawResult, null, 2))}</pre>`;
3135
- }
3136
- const looksLikeMarkup = detectContentType(rawResult) === "html";
3137
- if (looksLikeMarkup && options.escapeStringResults === false) {
3138
- return rawResult;
3139
- }
3140
- if (looksLikeMarkup && options.escapeStringResults === void 0) {
3141
- noticeStringResult(options.toolName, options.logger ?? console);
3142
- }
3143
- return escapeHtml(rawResult);
3144
- }
3145
- var warnedComponentReferences = /* @__PURE__ */ new WeakMap();
3146
- function warnComponentReference(template, toolName, logger) {
3147
- const warned = warnedComponentReferences.get(template) ?? /* @__PURE__ */ new Set();
3148
- if (warned.has(toolName)) return;
3149
- warned.add(toolName);
3150
- warnedComponentReferences.set(template, warned);
3151
- logger.warn(
3152
- `[FrontMCP] Tool "${toolName}": \`ui.template\` is a React component reference, which cannot be bundled (there is no source file to compile), so the widget would render an empty page. Use \`template: { file: './widget.tsx' }\` instead.`
3153
- );
3154
- }
3155
- var COMPILED_JSX_PATTERN = /\b(?:React\.createElement|_?jsx(?:s|DEV)?)\)?\s*\(/;
3156
- function isComponentReference(template) {
3157
- if (isReactTypedObject(template)) return true;
3158
- if (typeof template !== "function" || detectUIType(template) !== "react") return false;
3159
- return isDefinitelyReactComponent(template) || COMPILED_JSX_PATTERN.test(Function.prototype.toString.call(template));
3160
- }
3161
- function warnIfComponentReference(toolName, template, logger = console) {
3162
- if (!isComponentReference(template)) return false;
3163
- warnComponentReference(template, toolName, logger);
3164
- return true;
3165
- }
3166
- function isReactTypedObject(value) {
3167
- return typeof value === "object" && value !== null && "$$typeof" in value;
3168
- }
3169
- function isDefinitelyReactComponent(template) {
3170
- if (typeof template !== "function") return false;
3171
- const proto = template.prototype;
3172
- return typeof proto?.render === "function" || template["$$typeof"] !== void 0;
3173
- }
3174
- function renderToolTemplate(options) {
3175
- const { toolName, input, output, template, resolver, platformType, sizing } = options;
3176
- const uiType = detectUIType(template);
3177
- const resourceMode = options.resourceMode ?? (platformType === "claude" ? "inline" : "cdn");
3178
- const shellConfig = {
3179
- toolName,
3180
- input,
3181
- output,
3182
- includeBridge: true,
3183
- resolver,
3184
- sizing,
3185
- displayMode: options.displayMode,
3186
- csp: options.csp ? buildCspConfig(resolver, options.csp) : void 0
3187
- };
3188
- let html2;
3189
- let hash = "";
3190
- let size = 0;
3191
- if (typeof template === "object" && template !== null && "file" in template) {
3192
- const result = renderComponent(
3193
- { source: template, inlineReact: resourceMode === "inline" },
3194
- { ...shellConfig, csp: buildCspConfig(resolver, options.csp) }
3195
- );
3196
- html2 = result.html;
3197
- hash = result.hash;
3198
- size = result.size;
3199
- } else if (typeof template === "function") {
3200
- const helpers = createTemplateHelpers();
3201
- const ctx = { input: input ?? {}, output: output ?? {}, helpers };
3202
- let rawResult;
3203
- let isHtmlBuilder = uiType !== "react" || !isDefinitelyReactComponent(template);
3204
- if (isHtmlBuilder) {
3205
- try {
3206
- rawResult = template(ctx);
3207
- isHtmlBuilder = !isReactTypedObject(rawResult);
3208
- } catch (error) {
3209
- if (uiType !== "react") throw error;
3210
- isHtmlBuilder = false;
3211
- }
3212
- }
3213
- if (!isHtmlBuilder) {
3214
- warnComponentReference(template, toolName, options.logger ?? console);
3215
- const shellResult = buildShell('<div id="root"></div>', shellConfig);
3216
- html2 = shellResult.html;
3217
- hash = shellResult.hash;
3218
- size = shellResult.size;
3219
- } else {
3220
- const wrapped = isTrustedHtml(rawResult) ? void 0 : wrapDetectedContent(rawResult);
3221
- if (wrapped) {
3222
- html2 = wrapped;
3223
- } else {
3224
- const shellResult = buildShell(renderUnwrappedResult(rawResult, options), shellConfig);
3225
- html2 = shellResult.html;
3226
- hash = shellResult.hash;
3227
- size = shellResult.size;
3228
- }
3229
- }
3230
- } else if (typeof template === "string") {
3231
- const shellResult = buildShell(uiType === "markdown" ? markdownToHtml(template) : template, shellConfig);
3232
- html2 = shellResult.html;
3233
- hash = shellResult.hash;
3234
- size = shellResult.size;
3235
- } else {
3236
- if (isReactTypedObject(template)) warnComponentReference(template, toolName, options.logger ?? console);
3237
- const shellResult = buildShell('<div id="root"></div>', shellConfig);
3238
- html2 = shellResult.html;
3239
- hash = shellResult.hash;
3240
- size = shellResult.size;
3241
- }
3242
- const htmlKey = "ui/html";
3243
- const meta = {
3244
- [htmlKey]: html2,
3245
- "ui/type": uiType,
3246
- "ui/mimeType": MCP_APPS_MIME_TYPE
3247
- };
3248
- if (hasSizing(sizing)) {
3249
- if (sizing.preferredHeight !== void 0) meta["ui/preferredHeight"] = sizing.preferredHeight;
3250
- if (sizing.minHeight !== void 0) meta["ui/minHeight"] = sizing.minHeight;
3251
- if (sizing.maxHeight !== void 0) meta["ui/maxHeight"] = sizing.maxHeight;
3252
- if (sizing.aspectRatio !== void 0) meta["ui/aspectRatio"] = sizing.aspectRatio;
3253
- }
3254
- return {
3255
- html: html2,
3256
- uiType,
3257
- hash,
3258
- size: size || Buffer.byteLength(html2, "utf8"),
3259
- meta
3260
- };
3261
- }
3262
-
3263
- // libs/uipack/src/adapters/base-template.ts
3264
- function createDefaultBaseTemplate(options) {
3265
- const { toolName } = options;
3266
- const safeToolName = escapeHtml(toolName);
3267
- const bridgeScript = `<script>${generateBridgeIIFE({ minify: true })}</script>`;
3268
- const content = `
1315
+ </script>`;const result=buildShell(content,{toolName:"pdf",csp:{resourceDomains:["https://esm.sh"],connectDomains:["https://esm.sh"]},includeBridge:false});return result.html}function wrapDetectedContent(value){const contentType=detectContentType(value);switch(contentType){case"chart":return buildChartHtml(value);case"mermaid":return buildMermaidHtml(value);case"pdf":return buildPdfHtml(value);case"html":return void 0;default:return void 0}}var SAFE_HREF=/^(https?:|mailto:|\/|#)/i;function emphasis(text){return text.replace(/\*\*([^*]+)\*\*/g,"<strong>$1</strong>").replace(/\*([^*]+)\*/g,"<em>$1</em>")}function inline(text){const stash=[];const hold=html2=>`\uE000${stash.push(html2)-1}\uE000`;let out=escapeHtml(text.replace(/\uE000/g,"")).replace(/`([^`]+)`/g,(_m,code)=>hold(`<code>${code}</code>`));out=out.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g,(_m,label,href)=>SAFE_HREF.test(href)?hold(`<a href="${href}" rel="noopener noreferrer">${emphasis(label)}</a>`):label);out=emphasis(out);for(let i=0;i<2;i++)out=out.replace(/\uE000(\d+)\uE000/g,(_m,n)=>stash[Number(n)]);return out}function markdownToHtml(source){const lines=source.replace(/\r\n?/g,"\n").split("\n");const blocks=[];let paragraph=[];let list;const flushParagraph=()=>{if(paragraph.length>0)blocks.push(`<p>${inline(paragraph.join(" "))}</p>`);paragraph=[]};const flushList=()=>{if(list)blocks.push(`<${list.tag}>${list.items.map(item=>`<li>${inline(item)}</li>`).join("")}</${list.tag}>`);list=void 0};for(let i=0;i<lines.length;i++){const line=lines[i];const fence=/^\s*(`{3,})/.exec(line);if(fence){flushParagraph();flushList();const fenceLength=fence[1].length;const isClosing=l=>{const m=/^\s*(`{3,})\s*$/.exec(l);return m!==null&&m[1].length>=fenceLength};const code=[];for(i++;i<lines.length&&!isClosing(lines[i]);i++)code.push(lines[i]);blocks.push(`<pre><code>${escapeHtml(code.join("\n"))}
1316
+ </code></pre>`);continue}const heading=/^(#{1,6})\s+(.*)$/.exec(line);if(heading){flushParagraph();flushList();blocks.push(`<h${heading[1].length}>${inline(heading[2].trim())}</h${heading[1].length}>`);continue}const item=/^\s*([-*+]|\d+\.)\s+(.*)$/.exec(line);if(item){flushParagraph();const tag=/\d/.test(item[1])?"ol":"ul";if(list&&list.tag!==tag)flushList();list??={tag,items:[]};list.items.push(item[2]);continue}if(line.trim()===""){flushParagraph();flushList();continue}flushList();paragraph.push(line.trim())}flushParagraph();flushList();return blocks.join("\n")}function detectUIType(template){if(template===null||template===void 0){return"auto"}if(typeof template==="object"&&template!==null&&"file"in template){const file=template.file;if(/\.(tsx|jsx)$/i.test(file))return"react"}if(typeof template==="function"){const proto=template.prototype;if(proto&&typeof proto.render==="function"){return"react"}const asRecord=template;if(asRecord["$$typeof"]!==void 0){return"react"}if(template.name&&/^[A-Z]/.test(template.name)){return"react"}return"html"}if(typeof template==="string"){if(template.includes("<")&&template.includes(">")){return"html"}return"markdown"}return"auto"}function buildCspConfig(resolver,extra){const cspResourceDomains=["https://esm.sh"];const cspConnectDomains=["https://esm.sh"];for(const domain of extra?.resourceDomains??[]){if(!cspResourceDomains.includes(domain))cspResourceDomains.push(domain)}for(const domain of extra?.connectDomains??[]){if(!cspConnectDomains.includes(domain))cspConnectDomains.push(domain)}if(resolver&&"overrides"in resolver){const overrides=resolver.overrides;if(overrides){for(const url of Object.values(overrides)){try{const origin=new URL(url).origin;if(!cspResourceDomains.includes(origin))cspResourceDomains.push(origin);if(!cspConnectDomains.includes(origin))cspConnectDomains.push(origin)}catch{}}}}return{resourceDomains:cspResourceDomains,connectDomains:cspConnectDomains}}var STRING_RESULT_DOCS="https://frontmcp.dev/learn/your-first-widget";var noticedStringResultTools=new Set;function noticeStringResult(toolName,logger){if(noticedStringResultTools.has(toolName))return;noticedStringResultTools.add(toolName);logger.warn(`[frontmcp] The UI template of tool "${toolName}" returned a plain string containing markup. Since 1.9.2, FrontMCP HTML-escapes plain string results by default, so it is shown as text. Build the markup with ctx.helpers.html\`\u2026\` (interpolated values are escaped) or wrap safe markup with ctx.helpers.trustedHtml(). Set ui.escapeStringResults: false to render plain strings as markup, or true to silence this notice. See ${STRING_RESULT_DOCS}`)}function renderUnwrappedResult(rawResult,options){if(isTrustedHtml(rawResult)){return String(rawResult)}if(typeof rawResult!=="string"){return`<pre>${escapeHtml(JSON.stringify(rawResult,null,2))}</pre>`}const looksLikeMarkup=detectContentType(rawResult)==="html";if(looksLikeMarkup&&options.escapeStringResults===false){return rawResult}if(looksLikeMarkup&&options.escapeStringResults===void 0){noticeStringResult(options.toolName,options.logger??console)}return escapeHtml(rawResult)}var warnedComponentReferences=new WeakMap;function warnComponentReference(template,toolName,logger){const warned=warnedComponentReferences.get(template)??new Set;if(warned.has(toolName))return;warned.add(toolName);warnedComponentReferences.set(template,warned);logger.warn(`[FrontMCP] Tool "${toolName}": \`ui.template\` is a React component reference, which cannot be bundled (there is no source file to compile), so the widget would render an empty page. Use \`template: { file: './widget.tsx' }\` instead.`)}var COMPILED_JSX_PATTERN=/\b(?:React\.createElement|_?jsx(?:s|DEV)?)\)?\s*\(/;function isComponentReference(template){if(isReactTypedObject(template))return true;if(typeof template!=="function"||detectUIType(template)!=="react")return false;return isDefinitelyReactComponent(template)||COMPILED_JSX_PATTERN.test(Function.prototype.toString.call(template))}function warnIfComponentReference(toolName,template,logger=console){if(!isComponentReference(template))return false;warnComponentReference(template,toolName,logger);return true}function isReactTypedObject(value){return typeof value==="object"&&value!==null&&"$$typeof"in value}function isDefinitelyReactComponent(template){if(typeof template!=="function")return false;const proto=template.prototype;return typeof proto?.render==="function"||template["$$typeof"]!==void 0}function renderToolTemplate(options){const{toolName,input,output,template,resolver,platformType,sizing}=options;const uiType=detectUIType(template);const resourceMode=options.resourceMode??(platformType==="claude"?"inline":"cdn");const shellConfig={toolName,input,output,includeBridge:true,resolver,sizing,displayMode:options.displayMode,csp:options.csp?buildCspConfig(resolver,options.csp):void 0};let html2;let hash="";let size=0;if(typeof template==="object"&&template!==null&&"file"in template){const result=renderComponent({source:template,inlineReact:resourceMode==="inline"},{...shellConfig,csp:buildCspConfig(resolver,options.csp)});html2=result.html;hash=result.hash;size=result.size}else if(typeof template==="function"){const helpers=createTemplateHelpers();const ctx={input:input??{},output:output??{},helpers};let rawResult;let isHtmlBuilder=uiType!=="react"||!isDefinitelyReactComponent(template);if(isHtmlBuilder){try{rawResult=template(ctx);isHtmlBuilder=!isReactTypedObject(rawResult)}catch(error){if(uiType!=="react")throw error;isHtmlBuilder=false}}if(!isHtmlBuilder){warnComponentReference(template,toolName,options.logger??console);const shellResult=buildShell('<div id="root"></div>',shellConfig);html2=shellResult.html;hash=shellResult.hash;size=shellResult.size}else{const wrapped=isTrustedHtml(rawResult)?void 0:wrapDetectedContent(rawResult);if(wrapped){html2=wrapped}else{const shellResult=buildShell(renderUnwrappedResult(rawResult,options),shellConfig);html2=shellResult.html;hash=shellResult.hash;size=shellResult.size}}}else if(typeof template==="string"){const shellResult=buildShell(uiType==="markdown"?markdownToHtml(template):template,shellConfig);html2=shellResult.html;hash=shellResult.hash;size=shellResult.size}else{if(isReactTypedObject(template))warnComponentReference(template,toolName,options.logger??console);const shellResult=buildShell('<div id="root"></div>',shellConfig);html2=shellResult.html;hash=shellResult.hash;size=shellResult.size}const htmlKey="ui/html";const meta={[htmlKey]:html2,"ui/type":uiType,"ui/mimeType":MCP_APPS_MIME_TYPE};if(hasSizing(sizing)){if(sizing.preferredHeight!==void 0)meta["ui/preferredHeight"]=sizing.preferredHeight;if(sizing.minHeight!==void 0)meta["ui/minHeight"]=sizing.minHeight;if(sizing.maxHeight!==void 0)meta["ui/maxHeight"]=sizing.maxHeight;if(sizing.aspectRatio!==void 0)meta["ui/aspectRatio"]=sizing.aspectRatio}return{html:html2,uiType,hash,size:size||Buffer.byteLength(html2,"utf8"),meta}}function createDefaultBaseTemplate(options){const{toolName}=options;const safeToolName=escapeHtml(toolName);const bridgeScript=`<script>${generateBridgeIIFE({minify:true})}</script>`;const content=`
3269
1317
  ${bridgeScript}
3270
1318
  <div id="root">
3271
1319
  <div style="font-family:system-ui,sans-serif;padding:1rem;color:#374151;">
@@ -3291,63 +1339,4 @@ ${bridgeScript}
3291
1339
  });
3292
1340
  }
3293
1341
  })();
3294
- </script>`;
3295
- const result = buildShell(content, {
3296
- toolName,
3297
- includeBridge: false,
3298
- // Bridge already included via inline script above
3299
- title: `Widget: ${toolName}`
3300
- });
3301
- return result.html;
3302
- }
3303
-
3304
- // libs/uipack/src/adapters/cdn-info.ts
3305
- var ESM_SH_BASE = "https://esm.sh";
3306
- var REACT_DEPS = [
3307
- { name: "react", url: `${ESM_SH_BASE}/react@18` },
3308
- { name: "react-dom", url: `${ESM_SH_BASE}/react-dom@18` }
3309
- ];
3310
- function buildCDNInfoForUIType(uiType) {
3311
- const deps = [];
3312
- switch (uiType) {
3313
- case "react":
3314
- deps.push(...REACT_DEPS);
3315
- break;
3316
- case "mdx":
3317
- deps.push(...REACT_DEPS);
3318
- deps.push({ name: "marked", url: `${ESM_SH_BASE}/marked@latest` });
3319
- break;
3320
- case "markdown":
3321
- deps.push({ name: "marked", url: `${ESM_SH_BASE}/marked@latest` });
3322
- break;
3323
- case "auto":
3324
- deps.push(...REACT_DEPS);
3325
- deps.push({ name: "marked", url: `${ESM_SH_BASE}/marked@latest` });
3326
- break;
3327
- case "html":
3328
- default:
3329
- break;
3330
- }
3331
- return {
3332
- base: ESM_SH_BASE,
3333
- dependencies: deps
3334
- };
3335
- }
3336
- // Annotate the CommonJS export names for ESM import in node:
3337
- 0 && (module.exports = {
3338
- MCP_APPS_EXTENSION_ID,
3339
- MCP_APPS_MIME_TYPE,
3340
- buildCDNInfoForUIType,
3341
- buildChartHtml,
3342
- buildMermaidHtml,
3343
- buildPdfHtml,
3344
- buildToolResponseContent,
3345
- createDefaultBaseTemplate,
3346
- detectContentType,
3347
- detectUIType,
3348
- isUIRenderFailure,
3349
- renderToolTemplate,
3350
- resolveServingMode,
3351
- warnIfComponentReference,
3352
- wrapDetectedContent
3353
- });
1342
+ </script>`;const result=buildShell(content,{toolName,includeBridge:false,title:`Widget: ${toolName}`});return result.html}var ESM_SH_BASE="https://esm.sh";var REACT_DEPS=[{name:"react",url:`${ESM_SH_BASE}/react@18`},{name:"react-dom",url:`${ESM_SH_BASE}/react-dom@18`}];function buildCDNInfoForUIType(uiType){const deps=[];switch(uiType){case"react":deps.push(...REACT_DEPS);break;case"mdx":deps.push(...REACT_DEPS);deps.push({name:"marked",url:`${ESM_SH_BASE}/marked@latest`});break;case"markdown":deps.push({name:"marked",url:`${ESM_SH_BASE}/marked@latest`});break;case"auto":deps.push(...REACT_DEPS);deps.push({name:"marked",url:`${ESM_SH_BASE}/marked@latest`});break;case"html":default:break}return{base:ESM_SH_BASE,dependencies:deps}}0&&(module.exports={MCP_APPS_EXTENSION_ID,MCP_APPS_MIME_TYPE,buildCDNInfoForUIType,buildChartHtml,buildMermaidHtml,buildPdfHtml,buildToolResponseContent,createDefaultBaseTemplate,detectContentType,detectUIType,isUIRenderFailure,renderToolTemplate,resolveServingMode,warnIfComponentReference,wrapDetectedContent});