@frontmcp/uipack 1.10.8 → 1.10.9-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapters/index.js +29 -2040
- package/bridge-runtime/index.js +11 -217
- package/component/index.js +24 -1469
- package/esm/adapters/index.mjs +29 -2006
- package/esm/bridge-runtime/index.mjs +11 -185
- package/esm/component/index.mjs +24 -1439
- package/esm/index.mjs +150 -3483
- package/esm/package.json +2 -2
- package/esm/resolver/index.mjs +2 -660
- package/esm/shell/index.mjs +16 -750
- package/esm/types/index.mjs +1 -75
- package/esm/typings/index.mjs +3 -971
- package/esm/utils/index.mjs +1 -66
- package/index.js +150 -3605
- package/package.json +2 -2
- package/resolver/index.js +2 -707
- package/shell/index.js +16 -803
- package/types/index.js +1 -108
- package/typings/index.js +3 -1032
- package/utils/index.js +1 -96
package/shell/index.js
CHANGED
|
@@ -1,136 +1,4 @@
|
|
|
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/shell/index.ts
|
|
21
|
-
var shell_exports = {};
|
|
22
|
-
__export(shell_exports, {
|
|
23
|
-
DEFAULT_CDN_DOMAINS: () => DEFAULT_CDN_DOMAINS,
|
|
24
|
-
DEFAULT_CSP_DIRECTIVES: () => DEFAULT_CSP_DIRECTIVES,
|
|
25
|
-
OPTIONAL_PLACEHOLDERS: () => OPTIONAL_PLACEHOLDERS,
|
|
26
|
-
REQUIRED_PLACEHOLDERS: () => REQUIRED_PLACEHOLDERS,
|
|
27
|
-
RESTRICTIVE_CSP_DIRECTIVES: () => RESTRICTIVE_CSP_DIRECTIVES,
|
|
28
|
-
SHELL_PLACEHOLDERS: () => SHELL_PLACEHOLDERS,
|
|
29
|
-
SHELL_PLACEHOLDER_NAMES: () => SHELL_PLACEHOLDER_NAMES,
|
|
30
|
-
applyShellTemplate: () => applyShellTemplate,
|
|
31
|
-
buildCSPDirectives: () => buildCSPDirectives,
|
|
32
|
-
buildCSPMetaTag: () => buildCSPMetaTag,
|
|
33
|
-
buildCustomDataInjectionScript: () => buildCustomDataInjectionScript,
|
|
34
|
-
buildDataInjectionScript: () => buildDataInjectionScript,
|
|
35
|
-
buildShell: () => buildShell,
|
|
36
|
-
buildSizingStyleTag: () => buildSizingStyleTag,
|
|
37
|
-
clearShellTemplateCache: () => clearShellTemplateCache,
|
|
38
|
-
createTemplateHelpers: () => createTemplateHelpers,
|
|
39
|
-
hasSizing: () => hasSizing,
|
|
40
|
-
html: () => html,
|
|
41
|
-
isInlineShellSource: () => isInlineShellSource,
|
|
42
|
-
isNpmShellSource: () => isNpmShellSource,
|
|
43
|
-
isTrustedHtml: () => isTrustedHtml,
|
|
44
|
-
isUrlShellSource: () => isUrlShellSource,
|
|
45
|
-
resolveShellTemplate: () => resolveShellTemplate,
|
|
46
|
-
sanitizeCSPDomains: () => sanitizeCSPDomains,
|
|
47
|
-
trustedHtml: () => trustedHtml,
|
|
48
|
-
validateCSPDomain: () => validateCSPDomain,
|
|
49
|
-
validateShellTemplate: () => validateShellTemplate
|
|
50
|
-
});
|
|
51
|
-
module.exports = __toCommonJS(shell_exports);
|
|
52
|
-
|
|
53
|
-
// libs/uipack/src/bridge-runtime/iife-generator.ts
|
|
54
|
-
var WIDGET_CALL_META_KEY = "frontmcp/widgetCall";
|
|
55
|
-
var MCP_APPS_DISPLAY_MODES = ["inline", "fullscreen", "pip"];
|
|
56
|
-
function generateBridgeIIFE(options = {}) {
|
|
57
|
-
const { debug = false, trustedOrigins = [], minify = false } = options;
|
|
58
|
-
const adapters = options.adapters || ["openai", "ext-apps", "claude", "gemini", "generic"];
|
|
59
|
-
const parts = [];
|
|
60
|
-
parts.push("(function() {");
|
|
61
|
-
parts.push('"use strict";');
|
|
62
|
-
parts.push("");
|
|
63
|
-
if (debug) {
|
|
64
|
-
parts.push('function log(msg) { console.log("[FrontMcpBridge] " + msg); }');
|
|
65
|
-
} else {
|
|
66
|
-
parts.push("function log() {}");
|
|
67
|
-
}
|
|
68
|
-
parts.push("");
|
|
69
|
-
parts.push("var DEFAULT_SAFE_AREA = { top: 0, bottom: 0, left: 0, right: 0 };");
|
|
70
|
-
parts.push("");
|
|
71
|
-
parts.push(generateContextDetection());
|
|
72
|
-
parts.push("");
|
|
73
|
-
parts.push(generateBaseCapabilities());
|
|
74
|
-
parts.push("");
|
|
75
|
-
if (adapters.includes("openai")) {
|
|
76
|
-
parts.push(generateOpenAIAdapter());
|
|
77
|
-
parts.push("");
|
|
78
|
-
}
|
|
79
|
-
if (adapters.includes("ext-apps")) {
|
|
80
|
-
parts.push(generateExtAppsAdapter(trustedOrigins));
|
|
81
|
-
parts.push("");
|
|
82
|
-
}
|
|
83
|
-
if (adapters.includes("claude")) {
|
|
84
|
-
parts.push(generateClaudeAdapter());
|
|
85
|
-
parts.push("");
|
|
86
|
-
}
|
|
87
|
-
if (adapters.includes("gemini")) {
|
|
88
|
-
parts.push(generateGeminiAdapter());
|
|
89
|
-
parts.push("");
|
|
90
|
-
}
|
|
91
|
-
if (adapters.includes("generic")) {
|
|
92
|
-
parts.push(generateGenericAdapter());
|
|
93
|
-
parts.push("");
|
|
94
|
-
}
|
|
95
|
-
parts.push(generatePlatformDetection(adapters));
|
|
96
|
-
parts.push("");
|
|
97
|
-
parts.push(generateBridgeClass());
|
|
98
|
-
parts.push("");
|
|
99
|
-
parts.push("var bridge = new FrontMcpBridge();");
|
|
100
|
-
parts.push("bridge.initialize().then(function() {");
|
|
101
|
-
parts.push(' log("Bridge initialized with adapter: " + bridge.adapterId);');
|
|
102
|
-
parts.push(' window.dispatchEvent(new CustomEvent("bridge:ready", { detail: { adapter: bridge.adapterId } }));');
|
|
103
|
-
parts.push(" if (window.__mcpDisplayMode) bridge.requestDisplayMode(window.__mcpDisplayMode).catch(function() {});");
|
|
104
|
-
parts.push("}).catch(function(err) {");
|
|
105
|
-
parts.push(' console.error("[FrontMcpBridge] Init failed:", err);');
|
|
106
|
-
parts.push(' window.dispatchEvent(new CustomEvent("bridge:error", { detail: { error: err } }));');
|
|
107
|
-
parts.push("});");
|
|
108
|
-
parts.push("");
|
|
109
|
-
parts.push("window.FrontMcpBridge = bridge;");
|
|
110
|
-
parts.push("");
|
|
111
|
-
parts.push(generateAutoResize());
|
|
112
|
-
parts.push("function __showLoading() {");
|
|
113
|
-
parts.push(' var root = document.getElementById("root");');
|
|
114
|
-
parts.push(" if (root && !root.hasChildNodes()) {");
|
|
115
|
-
parts.push(
|
|
116
|
-
` 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>';`
|
|
117
|
-
);
|
|
118
|
-
parts.push(" }");
|
|
119
|
-
parts.push("}");
|
|
120
|
-
parts.push('if (document.readyState === "loading") {');
|
|
121
|
-
parts.push(' document.addEventListener("DOMContentLoaded", __showLoading);');
|
|
122
|
-
parts.push("} else {");
|
|
123
|
-
parts.push(" __showLoading();");
|
|
124
|
-
parts.push("}");
|
|
125
|
-
parts.push("})();");
|
|
126
|
-
const code = parts.join("\n");
|
|
127
|
-
if (minify) {
|
|
128
|
-
return minifyJS(code);
|
|
129
|
-
}
|
|
130
|
-
return code;
|
|
131
|
-
}
|
|
132
|
-
function generateAutoResize() {
|
|
133
|
-
return `
|
|
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 shell_exports={};__export(shell_exports,{DEFAULT_CDN_DOMAINS:()=>DEFAULT_CDN_DOMAINS,DEFAULT_CSP_DIRECTIVES:()=>DEFAULT_CSP_DIRECTIVES,OPTIONAL_PLACEHOLDERS:()=>OPTIONAL_PLACEHOLDERS,REQUIRED_PLACEHOLDERS:()=>REQUIRED_PLACEHOLDERS,RESTRICTIVE_CSP_DIRECTIVES:()=>RESTRICTIVE_CSP_DIRECTIVES,SHELL_PLACEHOLDERS:()=>SHELL_PLACEHOLDERS,SHELL_PLACEHOLDER_NAMES:()=>SHELL_PLACEHOLDER_NAMES,applyShellTemplate:()=>applyShellTemplate,buildCSPDirectives:()=>buildCSPDirectives,buildCSPMetaTag:()=>buildCSPMetaTag,buildCustomDataInjectionScript:()=>buildCustomDataInjectionScript,buildDataInjectionScript:()=>buildDataInjectionScript,buildShell:()=>buildShell,buildSizingStyleTag:()=>buildSizingStyleTag,clearShellTemplateCache:()=>clearShellTemplateCache,createTemplateHelpers:()=>createTemplateHelpers,hasSizing:()=>hasSizing,html:()=>html,isInlineShellSource:()=>isInlineShellSource,isNpmShellSource:()=>isNpmShellSource,isTrustedHtml:()=>isTrustedHtml,isUrlShellSource:()=>isUrlShellSource,resolveShellTemplate:()=>resolveShellTemplate,sanitizeCSPDomains:()=>sanitizeCSPDomains,trustedHtml:()=>trustedHtml,validateCSPDomain:()=>validateCSPDomain,validateShellTemplate:()=>validateShellTemplate});module.exports=__toCommonJS(shell_exports);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`
|
|
134
2
|
function __applySizingCss(sizing) {
|
|
135
3
|
if (typeof document === 'undefined' || !document.documentElement) return;
|
|
136
4
|
function toLen(v) { return typeof v === 'number' ? v + 'px' : v; }
|
|
@@ -265,10 +133,7 @@ function __initAutoResize() {
|
|
|
265
133
|
}
|
|
266
134
|
}
|
|
267
135
|
__initAutoResize();
|
|
268
|
-
`.trim()
|
|
269
|
-
}
|
|
270
|
-
function generateContextDetection() {
|
|
271
|
-
return `
|
|
136
|
+
`.trim()}function generateContextDetection(){return`
|
|
272
137
|
function detectTheme() {
|
|
273
138
|
if (typeof window !== 'undefined' && window.matchMedia) {
|
|
274
139
|
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
@@ -355,10 +220,7 @@ function readInjectedData() {
|
|
|
355
220
|
}
|
|
356
221
|
return data;
|
|
357
222
|
}
|
|
358
|
-
`.trim()
|
|
359
|
-
}
|
|
360
|
-
function generateBaseCapabilities() {
|
|
361
|
-
return `
|
|
223
|
+
`.trim()}function generateBaseCapabilities(){return`
|
|
362
224
|
var DEFAULT_CAPABILITIES = {
|
|
363
225
|
canCallTools: false,
|
|
364
226
|
canSendMessages: false,
|
|
@@ -368,10 +230,7 @@ var DEFAULT_CAPABILITIES = {
|
|
|
368
230
|
supportsDisplayModes: false,
|
|
369
231
|
supportsTheme: true
|
|
370
232
|
};
|
|
371
|
-
`.trim()
|
|
372
|
-
}
|
|
373
|
-
function generateOpenAIAdapter() {
|
|
374
|
-
return `
|
|
233
|
+
`.trim()}function generateOpenAIAdapter(){return`
|
|
375
234
|
var OpenAIAdapter = {
|
|
376
235
|
id: 'openai',
|
|
377
236
|
name: 'OpenAI ChatGPT',
|
|
@@ -456,11 +315,7 @@ var OpenAIAdapter = {
|
|
|
456
315
|
return Promise.resolve();
|
|
457
316
|
}
|
|
458
317
|
};
|
|
459
|
-
`.trim();
|
|
460
|
-
}
|
|
461
|
-
function generateExtAppsAdapter(trustedOrigins) {
|
|
462
|
-
const originsArray = trustedOrigins.length > 0 ? JSON.stringify(trustedOrigins) : "[]";
|
|
463
|
-
return `
|
|
318
|
+
`.trim()}function generateExtAppsAdapter(trustedOrigins){const originsArray=trustedOrigins.length>0?JSON.stringify(trustedOrigins):"[]";return`
|
|
464
319
|
var ExtAppsAdapter = {
|
|
465
320
|
id: 'ext-apps',
|
|
466
321
|
name: 'ext-apps (SEP-1865)',
|
|
@@ -803,10 +658,7 @@ var ExtAppsAdapter = {
|
|
|
803
658
|
return this.sendRequest('ui/unregisterTool', { name: name });
|
|
804
659
|
}
|
|
805
660
|
};
|
|
806
|
-
`.trim()
|
|
807
|
-
}
|
|
808
|
-
function generateClaudeAdapter() {
|
|
809
|
-
return `
|
|
661
|
+
`.trim()}function generateClaudeAdapter(){return`
|
|
810
662
|
var ClaudeAdapter = {
|
|
811
663
|
id: 'claude',
|
|
812
664
|
name: 'Claude (Anthropic)',
|
|
@@ -867,10 +719,7 @@ var ClaudeAdapter = {
|
|
|
867
719
|
return Promise.resolve();
|
|
868
720
|
}
|
|
869
721
|
};
|
|
870
|
-
`.trim()
|
|
871
|
-
}
|
|
872
|
-
function generateGeminiAdapter() {
|
|
873
|
-
return `
|
|
722
|
+
`.trim()}function generateGeminiAdapter(){return`
|
|
874
723
|
var GeminiAdapter = {
|
|
875
724
|
id: 'gemini',
|
|
876
725
|
name: 'Google Gemini',
|
|
@@ -921,10 +770,7 @@ var GeminiAdapter = {
|
|
|
921
770
|
return Promise.resolve();
|
|
922
771
|
}
|
|
923
772
|
};
|
|
924
|
-
`.trim()
|
|
925
|
-
}
|
|
926
|
-
function generateGenericAdapter() {
|
|
927
|
-
return `
|
|
773
|
+
`.trim()}function generateGenericAdapter(){return`
|
|
928
774
|
var GenericAdapter = {
|
|
929
775
|
id: 'generic',
|
|
930
776
|
name: 'Generic Web',
|
|
@@ -959,26 +805,7 @@ var GenericAdapter = {
|
|
|
959
805
|
return Promise.resolve();
|
|
960
806
|
}
|
|
961
807
|
};
|
|
962
|
-
`.trim();
|
|
963
|
-
}
|
|
964
|
-
function generatePlatformDetection(adapters) {
|
|
965
|
-
const adapterVars = adapters.map((a) => {
|
|
966
|
-
switch (a) {
|
|
967
|
-
case "openai":
|
|
968
|
-
return "OpenAIAdapter";
|
|
969
|
-
case "ext-apps":
|
|
970
|
-
return "ExtAppsAdapter";
|
|
971
|
-
case "claude":
|
|
972
|
-
return "ClaudeAdapter";
|
|
973
|
-
case "gemini":
|
|
974
|
-
return "GeminiAdapter";
|
|
975
|
-
case "generic":
|
|
976
|
-
return "GenericAdapter";
|
|
977
|
-
default:
|
|
978
|
-
return "";
|
|
979
|
-
}
|
|
980
|
-
}).filter(Boolean);
|
|
981
|
-
return `
|
|
808
|
+
`.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`
|
|
982
809
|
var ADAPTERS = [${adapterVars.join(", ")}].sort(function(a, b) { return b.priority - a.priority; });
|
|
983
810
|
|
|
984
811
|
function detectPlatform() {
|
|
@@ -991,10 +818,7 @@ function detectPlatform() {
|
|
|
991
818
|
log('No platform detected, using generic');
|
|
992
819
|
return GenericAdapter;
|
|
993
820
|
}
|
|
994
|
-
`.trim()
|
|
995
|
-
}
|
|
996
|
-
function generateBridgeClass() {
|
|
997
|
-
return `
|
|
821
|
+
`.trim()}function generateBridgeClass(){return`
|
|
998
822
|
function FrontMcpBridge() {
|
|
999
823
|
this._adapter = null;
|
|
1000
824
|
this._initialized = false;
|
|
@@ -1370,627 +1194,16 @@ FrontMcpBridge.prototype._setupDataToolCallHandler = function() {
|
|
|
1370
1194
|
}
|
|
1371
1195
|
}, true); // Use capture phase to handle before React handlers
|
|
1372
1196
|
};
|
|
1373
|
-
`.trim();
|
|
1374
|
-
}
|
|
1375
|
-
var MAX_MINIFY_CODE_LENGTH = 5e5;
|
|
1376
|
-
function minifyJS(code) {
|
|
1377
|
-
if (code.length > MAX_MINIFY_CODE_LENGTH) {
|
|
1378
|
-
return code;
|
|
1379
|
-
}
|
|
1380
|
-
const out = [];
|
|
1381
|
-
let inBlockComment = false;
|
|
1382
|
-
for (const raw of code.split("\n")) {
|
|
1383
|
-
const line = raw.trim();
|
|
1384
|
-
if (inBlockComment) {
|
|
1385
|
-
if (line.includes("*/")) inBlockComment = false;
|
|
1386
|
-
continue;
|
|
1387
|
-
}
|
|
1388
|
-
if (line === "" || line.startsWith("//")) continue;
|
|
1389
|
-
if (line.startsWith("/*")) {
|
|
1390
|
-
if (!line.includes("*/")) inBlockComment = true;
|
|
1391
|
-
continue;
|
|
1392
|
-
}
|
|
1393
|
-
out.push(line);
|
|
1394
|
-
}
|
|
1395
|
-
return out.join("\n");
|
|
1396
|
-
}
|
|
1397
|
-
function generatePlatformBundle(platform, options = {}) {
|
|
1398
|
-
const platformAdapters = {
|
|
1399
|
-
chatgpt: ["openai", "generic"],
|
|
1400
|
-
claude: ["claude", "generic"],
|
|
1401
|
-
gemini: ["gemini", "generic"],
|
|
1402
|
-
universal: ["openai", "ext-apps", "claude", "gemini", "generic"]
|
|
1403
|
-
};
|
|
1404
|
-
return generateBridgeIIFE({
|
|
1405
|
-
...options,
|
|
1406
|
-
adapters: platformAdapters[platform]
|
|
1407
|
-
});
|
|
1408
|
-
}
|
|
1409
|
-
var UNIVERSAL_BRIDGE_SCRIPT = generateBridgeIIFE();
|
|
1410
|
-
var BRIDGE_SCRIPT_TAGS = {
|
|
1411
|
-
universal: `<script>${UNIVERSAL_BRIDGE_SCRIPT}</script>`,
|
|
1412
|
-
chatgpt: `<script>${generatePlatformBundle("chatgpt")}</script>`,
|
|
1413
|
-
claude: `<script>${generatePlatformBundle("claude")}</script>`,
|
|
1414
|
-
gemini: `<script>${generatePlatformBundle("gemini")}</script>`
|
|
1415
|
-
};
|
|
1416
|
-
|
|
1417
|
-
// libs/uipack/src/shell/csp.ts
|
|
1418
|
-
var DEFAULT_CDN_DOMAINS = [
|
|
1419
|
-
"https://cdn.jsdelivr.net",
|
|
1420
|
-
"https://cdnjs.cloudflare.com",
|
|
1421
|
-
"https://fonts.googleapis.com",
|
|
1422
|
-
"https://fonts.gstatic.com",
|
|
1423
|
-
"https://esm.sh"
|
|
1424
|
-
];
|
|
1425
|
-
var DEFAULT_CSP_DIRECTIVES = [
|
|
1426
|
-
"default-src 'none'",
|
|
1427
|
-
`script-src 'self' 'unsafe-inline' ${DEFAULT_CDN_DOMAINS.join(" ")}`,
|
|
1428
|
-
`style-src 'self' 'unsafe-inline' ${DEFAULT_CDN_DOMAINS.join(" ")}`,
|
|
1429
|
-
`img-src 'self' data: ${DEFAULT_CDN_DOMAINS.join(" ")}`,
|
|
1430
|
-
`font-src 'self' data: ${DEFAULT_CDN_DOMAINS.join(" ")}`,
|
|
1431
|
-
`connect-src ${DEFAULT_CDN_DOMAINS.join(" ")}`,
|
|
1432
|
-
"object-src 'self' data:"
|
|
1433
|
-
];
|
|
1434
|
-
var RESTRICTIVE_CSP_DIRECTIVES = [
|
|
1435
|
-
"default-src 'none'",
|
|
1436
|
-
"script-src 'self' 'unsafe-inline'",
|
|
1437
|
-
"style-src 'self' 'unsafe-inline'",
|
|
1438
|
-
"img-src 'self' data:",
|
|
1439
|
-
"font-src 'self' data:",
|
|
1440
|
-
"connect-src 'none'",
|
|
1441
|
-
"object-src 'self' data:"
|
|
1442
|
-
];
|
|
1443
|
-
function buildCSPDirectives(csp) {
|
|
1444
|
-
if (!csp) {
|
|
1445
|
-
return [...DEFAULT_CSP_DIRECTIVES];
|
|
1446
|
-
}
|
|
1447
|
-
const validResourceDomains = sanitizeCSPDomains(csp.resourceDomains);
|
|
1448
|
-
const validConnectDomains = sanitizeCSPDomains(csp.connectDomains);
|
|
1449
|
-
const allResourceDomains = [.../* @__PURE__ */ new Set([...DEFAULT_CDN_DOMAINS, ...validResourceDomains])];
|
|
1450
|
-
const directives = [
|
|
1451
|
-
"default-src 'none'",
|
|
1452
|
-
`script-src 'self' 'unsafe-inline' ${allResourceDomains.join(" ")}`,
|
|
1453
|
-
`style-src 'self' 'unsafe-inline' ${allResourceDomains.join(" ")}`
|
|
1454
|
-
];
|
|
1455
|
-
const imgSources = ["'self'", "data:", ...allResourceDomains];
|
|
1456
|
-
directives.push(`img-src ${imgSources.join(" ")}`);
|
|
1457
|
-
const fontSources = ["'self'", "data:", ...allResourceDomains];
|
|
1458
|
-
directives.push(`font-src ${fontSources.join(" ")}`);
|
|
1459
|
-
const connectSources = [.../* @__PURE__ */ new Set([...allResourceDomains, ...validConnectDomains])];
|
|
1460
|
-
directives.push(`connect-src ${connectSources.join(" ")}`);
|
|
1461
|
-
directives.push("object-src 'self' data:");
|
|
1462
|
-
return directives;
|
|
1463
|
-
}
|
|
1464
|
-
function buildCSPMetaTag(csp) {
|
|
1465
|
-
const directives = buildCSPDirectives(csp);
|
|
1466
|
-
const content = directives.join("; ");
|
|
1467
|
-
return `<meta http-equiv="Content-Security-Policy" content="${escapeAttribute(content)}">`;
|
|
1468
|
-
}
|
|
1469
|
-
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
1470
|
-
function validateCSPDomain(domain) {
|
|
1471
|
-
if (typeof domain !== "string" || /[\s;,'"]/.test(domain)) return false;
|
|
1472
|
-
if (/[?#]/.test(domain)) return false;
|
|
1473
|
-
if (domain.includes("*")) {
|
|
1474
|
-
const wildcard = /^(?:https|wss):\/\/\*\.(.*)$/.exec(domain);
|
|
1475
|
-
return wildcard !== null && /^([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(wildcard[1]);
|
|
1476
|
-
}
|
|
1477
|
-
try {
|
|
1478
|
-
const url = new URL(domain);
|
|
1479
|
-
if (url.protocol === "https:" || url.protocol === "wss:") return true;
|
|
1480
|
-
return (url.protocol === "http:" || url.protocol === "ws:") && LOOPBACK_HOSTS.has(url.hostname);
|
|
1481
|
-
} catch {
|
|
1482
|
-
return false;
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
var reportedInvalidDomains = /* @__PURE__ */ new Set();
|
|
1486
|
-
function sanitizeCSPDomains(domains) {
|
|
1487
|
-
if (!domains) return [];
|
|
1488
|
-
const valid = [];
|
|
1489
|
-
for (const domain of domains) {
|
|
1490
|
-
if (validateCSPDomain(domain)) {
|
|
1491
|
-
valid.push(domain);
|
|
1492
|
-
} else if (!reportedInvalidDomains.has(domain)) {
|
|
1493
|
-
reportedInvalidDomains.add(domain);
|
|
1494
|
-
console.warn(
|
|
1495
|
-
`Invalid CSP domain ignored: ${domain} (expected an https:// or wss:// origin, or http:// / ws:// on localhost)`
|
|
1496
|
-
);
|
|
1497
|
-
}
|
|
1498
|
-
}
|
|
1499
|
-
return valid;
|
|
1500
|
-
}
|
|
1501
|
-
function escapeAttribute(str) {
|
|
1502
|
-
return str.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
// libs/uipack/src/shell/custom-shell-types.ts
|
|
1506
|
-
var SHELL_PLACEHOLDER_NAMES = ["CSP", "DATA", "BRIDGE", "CONTENT", "TITLE"];
|
|
1507
|
-
var SHELL_PLACEHOLDERS = {
|
|
1508
|
-
CSP: "{{CSP}}",
|
|
1509
|
-
DATA: "{{DATA}}",
|
|
1510
|
-
BRIDGE: "{{BRIDGE}}",
|
|
1511
|
-
CONTENT: "{{CONTENT}}",
|
|
1512
|
-
TITLE: "{{TITLE}}"
|
|
1513
|
-
};
|
|
1514
|
-
var REQUIRED_PLACEHOLDERS = ["CONTENT"];
|
|
1515
|
-
var OPTIONAL_PLACEHOLDERS = ["CSP", "DATA", "BRIDGE", "TITLE"];
|
|
1516
|
-
function isInlineShellSource(source) {
|
|
1517
|
-
return typeof source === "object" && source !== null && "inline" in source;
|
|
1518
|
-
}
|
|
1519
|
-
function isUrlShellSource(source) {
|
|
1520
|
-
return typeof source === "object" && source !== null && "url" in source;
|
|
1521
|
-
}
|
|
1522
|
-
function isNpmShellSource(source) {
|
|
1523
|
-
return typeof source === "object" && source !== null && "npm" in source;
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
|
-
// libs/uipack/src/shell/custom-shell-applier.ts
|
|
1527
|
-
var PLACEHOLDER_PATTERN = new RegExp(`\\{\\{(${SHELL_PLACEHOLDER_NAMES.join("|")})\\}\\}`, "g");
|
|
1528
|
-
var VALUE_KEYS = {
|
|
1529
|
-
CSP: "csp",
|
|
1530
|
-
DATA: "data",
|
|
1531
|
-
BRIDGE: "bridge",
|
|
1532
|
-
CONTENT: "content",
|
|
1533
|
-
TITLE: "title"
|
|
1534
|
-
};
|
|
1535
|
-
function applyShellTemplate(template, values) {
|
|
1536
|
-
return template.replace(PLACEHOLDER_PATTERN, (_token, name) => values[VALUE_KEYS[name]]);
|
|
1537
|
-
}
|
|
1538
|
-
|
|
1539
|
-
// libs/uipack/src/shell/custom-shell-validator.ts
|
|
1540
|
-
function validateShellTemplate(template) {
|
|
1541
|
-
const found = {};
|
|
1542
|
-
for (const name of SHELL_PLACEHOLDER_NAMES) {
|
|
1543
|
-
found[name] = template.includes(SHELL_PLACEHOLDERS[name]);
|
|
1544
|
-
}
|
|
1545
|
-
const missingRequired = REQUIRED_PLACEHOLDERS.filter((name) => !found[name]);
|
|
1546
|
-
const missingOptional = OPTIONAL_PLACEHOLDERS.filter((name) => !found[name]);
|
|
1547
|
-
return {
|
|
1548
|
-
valid: missingRequired.length === 0,
|
|
1549
|
-
found,
|
|
1550
|
-
missingRequired,
|
|
1551
|
-
missingOptional
|
|
1552
|
-
};
|
|
1553
|
-
}
|
|
1554
|
-
|
|
1555
|
-
// libs/uipack/src/utils/index.ts
|
|
1556
|
-
function escapeHtml(str) {
|
|
1557
|
-
if (str === null || str === void 0) {
|
|
1558
|
-
return "";
|
|
1559
|
-
}
|
|
1560
|
-
const s = String(str);
|
|
1561
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
1562
|
-
}
|
|
1563
|
-
var SCRIPT_UNSAFE_CHARACTERS = /[<>&\u2028\u2029]/g;
|
|
1564
|
-
function toUnicodeEscape(character) {
|
|
1565
|
-
return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
1566
|
-
}
|
|
1567
|
-
function safeJsonForScript(value) {
|
|
1568
|
-
if (value === void 0) {
|
|
1569
|
-
return "null";
|
|
1570
|
-
}
|
|
1571
|
-
try {
|
|
1572
|
-
const jsonString = JSON.stringify(value, (_key, val) => {
|
|
1573
|
-
if (typeof val === "bigint") {
|
|
1574
|
-
return val.toString();
|
|
1575
|
-
}
|
|
1576
|
-
return val;
|
|
1577
|
-
});
|
|
1578
|
-
if (jsonString === void 0) {
|
|
1579
|
-
return "null";
|
|
1580
|
-
}
|
|
1581
|
-
return jsonString.replace(SCRIPT_UNSAFE_CHARACTERS, toUnicodeEscape);
|
|
1582
|
-
} catch {
|
|
1583
|
-
return '{"error":"Value could not be serialized"}';
|
|
1584
|
-
}
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
// libs/uipack/src/shell/trusted-html.ts
|
|
1588
|
-
var TRUSTED_HTML = /* @__PURE__ */ Symbol.for("@frontmcp/uipack/trusted-html");
|
|
1589
|
-
function trustedHtml(markup) {
|
|
1590
|
-
const value = String(markup);
|
|
1591
|
-
return Object.freeze({ [TRUSTED_HTML]: value, toString: () => value });
|
|
1592
|
-
}
|
|
1593
|
-
function isTrustedHtml(value) {
|
|
1594
|
-
return typeof value === "object" && value !== null && typeof value[TRUSTED_HTML] === "string";
|
|
1595
|
-
}
|
|
1596
|
-
function interpolate(value) {
|
|
1597
|
-
if (isTrustedHtml(value)) return value[TRUSTED_HTML];
|
|
1598
|
-
if (Array.isArray(value)) return value.map(interpolate).join("");
|
|
1599
|
-
if (value === false) return "";
|
|
1600
|
-
return escapeHtml(value);
|
|
1601
|
-
}
|
|
1602
|
-
function html(strings, ...values) {
|
|
1603
|
-
let markup = strings[0];
|
|
1604
|
-
for (let index = 0; index < values.length; index++) {
|
|
1605
|
-
markup += interpolate(values[index]) + strings[index + 1];
|
|
1606
|
-
}
|
|
1607
|
-
return trustedHtml(markup);
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
|
-
// libs/uipack/src/shell/data-injector.ts
|
|
1611
|
-
function hasSizing(sizing) {
|
|
1612
|
-
if (!sizing) return false;
|
|
1613
|
-
return sizing.preferredHeight !== void 0 || sizing.minHeight !== void 0 || sizing.maxHeight !== void 0 || sizing.aspectRatio !== void 0 || sizing.autoResize !== void 0;
|
|
1614
|
-
}
|
|
1615
|
-
function buildDataInjectionScript(options) {
|
|
1616
|
-
const { toolName, input, output, structuredContent, sizing, displayMode } = options;
|
|
1617
|
-
const lines = [
|
|
1618
|
-
`window.__mcpAppsEnabled = true;`,
|
|
1619
|
-
`window.__mcpToolName = ${safeJsonForScript(toolName)};`,
|
|
1620
|
-
`window.__mcpToolInput = ${safeJsonForScript(input ?? null)};`,
|
|
1621
|
-
`window.__mcpToolOutput = ${safeJsonForScript(output ?? null)};`,
|
|
1622
|
-
`window.__mcpStructuredContent = ${safeJsonForScript(structuredContent ?? null)};`
|
|
1623
|
-
];
|
|
1624
|
-
if (hasSizing(sizing)) {
|
|
1625
|
-
lines.push(`window.__mcpWidgetSizing = ${safeJsonForScript(sizing)};`);
|
|
1626
|
-
}
|
|
1627
|
-
if (displayMode && displayMode !== "inline") {
|
|
1628
|
-
lines.push(`window.__mcpDisplayMode = ${safeJsonForScript(displayMode)};`);
|
|
1629
|
-
}
|
|
1630
|
-
return `<script>
|
|
1197
|
+
`.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:"];var RESTRICTIVE_CSP_DIRECTIVES=["default-src 'none'","script-src 'self' 'unsafe-inline'","style-src 'self' 'unsafe-inline'","img-src 'self' data:","font-src 'self' data:","connect-src 'none'","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,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">")}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"];function isInlineShellSource(source){return typeof source==="object"&&source!==null&&"inline"in source}function isUrlShellSource(source){return typeof source==="object"&&source!==null&&"url"in source}function isNpmShellSource(source){return typeof source==="object"&&source!==null&&"npm"in source}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}}function escapeHtml(str){if(str===null||str===void 0){return""}const s=String(str);return s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").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"}'}}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>
|
|
1631
1198
|
${lines.join("\n")}
|
|
1632
|
-
</script
|
|
1633
|
-
}
|
|
1634
|
-
function buildCustomDataInjectionScript(descriptor) {
|
|
1635
|
-
if (descriptor.script !== void 0) {
|
|
1636
|
-
return descriptor.script;
|
|
1637
|
-
}
|
|
1638
|
-
if (descriptor.globalKey !== void 0) {
|
|
1639
|
-
return `<script>window[${safeJsonForScript(descriptor.globalKey)}] = ${safeJsonForScript(
|
|
1640
|
-
descriptor.value ?? null
|
|
1641
|
-
)};</script>`;
|
|
1642
|
-
}
|
|
1643
|
-
return "";
|
|
1644
|
-
}
|
|
1645
|
-
var _uniqueIdCounter = 0;
|
|
1646
|
-
function createTemplateHelpers() {
|
|
1647
|
-
return {
|
|
1648
|
-
escapeHtml: (str) => escapeHtml(str),
|
|
1649
|
-
formatDate: (date, format) => {
|
|
1650
|
-
const d = date instanceof Date ? date : new Date(date);
|
|
1651
|
-
if (isNaN(d.getTime())) return String(date);
|
|
1652
|
-
if (format === "iso") return d.toISOString();
|
|
1653
|
-
if (format === "date") return d.toLocaleDateString();
|
|
1654
|
-
if (format === "time") return d.toLocaleTimeString();
|
|
1655
|
-
return d.toLocaleString();
|
|
1656
|
-
},
|
|
1657
|
-
formatCurrency: (amount, currency = "USD") => {
|
|
1658
|
-
return new Intl.NumberFormat("en-US", {
|
|
1659
|
-
style: "currency",
|
|
1660
|
-
currency
|
|
1661
|
-
}).format(amount);
|
|
1662
|
-
},
|
|
1663
|
-
uniqueId: (prefix = "mcp") => {
|
|
1664
|
-
return `${prefix}-${++_uniqueIdCounter}`;
|
|
1665
|
-
},
|
|
1666
|
-
jsonEmbed: (data) => safeJsonForScript(data),
|
|
1667
|
-
html,
|
|
1668
|
-
trustedHtml
|
|
1669
|
-
};
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
|
-
// libs/uipack/src/shell/sizing-css.ts
|
|
1673
|
-
function sanitizeCssValue(value) {
|
|
1674
|
-
return value.replace(/[<>{};]/g, "").trim();
|
|
1675
|
-
}
|
|
1676
|
-
function toCssLength(value) {
|
|
1677
|
-
return typeof value === "number" ? `${value}px` : sanitizeCssValue(value);
|
|
1678
|
-
}
|
|
1679
|
-
function buildSizingStyleTag(sizing) {
|
|
1680
|
-
if (!hasSizing(sizing)) return "";
|
|
1681
|
-
const hasCssSizing = sizing.preferredHeight !== void 0 || sizing.minHeight !== void 0 || sizing.maxHeight !== void 0 || sizing.aspectRatio !== void 0;
|
|
1682
|
-
if (!hasCssSizing) return "";
|
|
1683
|
-
const rootRules = [];
|
|
1684
|
-
const docRules = ["margin: 0;"];
|
|
1685
|
-
if (sizing.preferredHeight !== void 0) {
|
|
1686
|
-
const h = toCssLength(sizing.preferredHeight);
|
|
1687
|
-
docRules.push(`height: ${h};`);
|
|
1688
|
-
rootRules.push(`min-height: ${h};`);
|
|
1689
|
-
}
|
|
1690
|
-
if (sizing.minHeight !== void 0) {
|
|
1691
|
-
const mh = toCssLength(sizing.minHeight);
|
|
1692
|
-
docRules.push(`min-height: ${mh};`);
|
|
1693
|
-
rootRules.push(`min-height: ${mh};`);
|
|
1694
|
-
}
|
|
1695
|
-
if (sizing.maxHeight !== void 0) {
|
|
1696
|
-
const mx = toCssLength(sizing.maxHeight);
|
|
1697
|
-
docRules.push(`max-height: ${mx};`);
|
|
1698
|
-
rootRules.push(`max-height: ${mx};`);
|
|
1699
|
-
}
|
|
1700
|
-
if (sizing.aspectRatio !== void 0) {
|
|
1701
|
-
const ar = typeof sizing.aspectRatio === "number" ? String(sizing.aspectRatio) : sanitizeCssValue(sizing.aspectRatio);
|
|
1702
|
-
if (ar) rootRules.push(`aspect-ratio: ${ar};`);
|
|
1703
|
-
}
|
|
1704
|
-
const parts = [`html, body { ${docRules.join(" ")} }`];
|
|
1705
|
-
if (rootRules.length > 0) {
|
|
1706
|
-
parts.push(`#root { ${rootRules.join(" ")} }`);
|
|
1707
|
-
}
|
|
1708
|
-
return `<style>${parts.join("\n")}</style>`;
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
// libs/uipack/src/shell/builder.ts
|
|
1712
|
-
function resolveDataInjectionScript(args) {
|
|
1713
|
-
if (args.dataInjection) {
|
|
1714
|
-
return buildCustomDataInjectionScript(args.dataInjection);
|
|
1715
|
-
}
|
|
1716
|
-
return buildDataInjectionScript({
|
|
1717
|
-
toolName: args.toolName,
|
|
1718
|
-
input: args.input,
|
|
1719
|
-
output: args.output,
|
|
1720
|
-
structuredContent: args.structuredContent,
|
|
1721
|
-
sizing: args.sizing,
|
|
1722
|
-
displayMode: args.displayMode
|
|
1723
|
-
});
|
|
1724
|
-
}
|
|
1725
|
-
function buildShell(content, config) {
|
|
1726
|
-
const {
|
|
1727
|
-
toolName,
|
|
1728
|
-
csp,
|
|
1729
|
-
withShell = true,
|
|
1730
|
-
input,
|
|
1731
|
-
output,
|
|
1732
|
-
structuredContent,
|
|
1733
|
-
includeBridge = true,
|
|
1734
|
-
title,
|
|
1735
|
-
sizing,
|
|
1736
|
-
displayMode
|
|
1737
|
-
} = config;
|
|
1738
|
-
const { customShell, dataInjection } = config;
|
|
1739
|
-
const dataScript = resolveDataInjectionScript({
|
|
1740
|
-
dataInjection,
|
|
1741
|
-
toolName,
|
|
1742
|
-
input,
|
|
1743
|
-
output,
|
|
1744
|
-
structuredContent,
|
|
1745
|
-
sizing,
|
|
1746
|
-
displayMode
|
|
1747
|
-
});
|
|
1748
|
-
if (!withShell) {
|
|
1749
|
-
const html3 = `${dataScript}
|
|
1750
|
-
${content}`;
|
|
1751
|
-
return {
|
|
1752
|
-
html: html3,
|
|
1753
|
-
hash: simpleHash(html3),
|
|
1754
|
-
size: Buffer.byteLength(html3, "utf-8")
|
|
1755
|
-
};
|
|
1756
|
-
}
|
|
1757
|
-
if (customShell) {
|
|
1758
|
-
return buildCustomShell(content, customShell, {
|
|
1759
|
-
csp,
|
|
1760
|
-
toolName,
|
|
1761
|
-
input,
|
|
1762
|
-
output,
|
|
1763
|
-
structuredContent,
|
|
1764
|
-
includeBridge,
|
|
1765
|
-
title,
|
|
1766
|
-
sizing,
|
|
1767
|
-
displayMode,
|
|
1768
|
-
dataInjection
|
|
1769
|
-
});
|
|
1770
|
-
}
|
|
1771
|
-
const headParts = [
|
|
1772
|
-
'<meta charset="UTF-8">',
|
|
1773
|
-
'<meta name="viewport" content="width=device-width, initial-scale=1.0">'
|
|
1774
|
-
];
|
|
1775
|
-
if (title) {
|
|
1776
|
-
headParts.push(`<title>${escapeHtmlForTag(title)}</title>`);
|
|
1777
|
-
}
|
|
1778
|
-
headParts.push(buildCSPMetaTag(csp));
|
|
1779
|
-
headParts.push(dataScript);
|
|
1780
|
-
const sizingStyle = buildSizingStyleTag(sizing);
|
|
1781
|
-
if (sizingStyle) {
|
|
1782
|
-
headParts.push(sizingStyle);
|
|
1783
|
-
}
|
|
1784
|
-
if (includeBridge) {
|
|
1785
|
-
const bridgeScript = generateBridgeIIFE({ minify: true });
|
|
1786
|
-
headParts.push(`<script>${bridgeScript}</script>`);
|
|
1787
|
-
}
|
|
1788
|
-
const html2 = `<!DOCTYPE html>
|
|
1199
|
+
</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}
|
|
1200
|
+
${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>
|
|
1789
1201
|
<html lang="en">
|
|
1790
1202
|
<head>
|
|
1791
|
-
${headParts.map(
|
|
1203
|
+
${headParts.map(p=>` ${p}`).join("\n")}
|
|
1792
1204
|
</head>
|
|
1793
1205
|
<body>
|
|
1794
1206
|
${content}
|
|
1795
1207
|
</body>
|
|
1796
|
-
</html>`;
|
|
1797
|
-
|
|
1798
|
-
html: html2,
|
|
1799
|
-
hash: simpleHash(html2),
|
|
1800
|
-
size: Buffer.byteLength(html2, "utf-8")
|
|
1801
|
-
};
|
|
1802
|
-
}
|
|
1803
|
-
function buildCustomShell(content, customShell, ctx) {
|
|
1804
|
-
let template;
|
|
1805
|
-
if (typeof customShell === "string") {
|
|
1806
|
-
const validation = validateShellTemplate(customShell);
|
|
1807
|
-
if (!validation.valid) {
|
|
1808
|
-
throw new Error(
|
|
1809
|
-
`Custom shell template is missing required placeholder(s): ${validation.missingRequired.map((n) => `{{${n}}}`).join(", ")}`
|
|
1810
|
-
);
|
|
1811
|
-
}
|
|
1812
|
-
template = customShell;
|
|
1813
|
-
} else {
|
|
1814
|
-
template = customShell.template;
|
|
1815
|
-
}
|
|
1816
|
-
const cspTag = buildCSPMetaTag(ctx.csp);
|
|
1817
|
-
const dataScript = resolveDataInjectionScript({
|
|
1818
|
-
dataInjection: ctx.dataInjection,
|
|
1819
|
-
toolName: ctx.toolName,
|
|
1820
|
-
input: ctx.input,
|
|
1821
|
-
output: ctx.output,
|
|
1822
|
-
structuredContent: ctx.structuredContent,
|
|
1823
|
-
sizing: ctx.sizing,
|
|
1824
|
-
displayMode: ctx.displayMode
|
|
1825
|
-
});
|
|
1826
|
-
const sizingStyle = buildSizingStyleTag(ctx.sizing);
|
|
1827
|
-
const dataWithSizing = sizingStyle ? `${dataScript}
|
|
1828
|
-
${sizingStyle}` : dataScript;
|
|
1829
|
-
let bridgeHtml = "";
|
|
1830
|
-
if (ctx.includeBridge) {
|
|
1831
|
-
const bridgeScript = generateBridgeIIFE({ minify: true });
|
|
1832
|
-
bridgeHtml = `<script>${bridgeScript}</script>`;
|
|
1833
|
-
}
|
|
1834
|
-
const html2 = applyShellTemplate(template, {
|
|
1835
|
-
csp: cspTag,
|
|
1836
|
-
data: dataWithSizing,
|
|
1837
|
-
bridge: bridgeHtml,
|
|
1838
|
-
content,
|
|
1839
|
-
title: ctx.title ? escapeHtmlForTag(ctx.title) : ""
|
|
1840
|
-
});
|
|
1841
|
-
return {
|
|
1842
|
-
html: html2,
|
|
1843
|
-
hash: simpleHash(html2),
|
|
1844
|
-
size: Buffer.byteLength(html2, "utf-8")
|
|
1845
|
-
};
|
|
1846
|
-
}
|
|
1847
|
-
function simpleHash(str) {
|
|
1848
|
-
let hash = 0;
|
|
1849
|
-
for (let i = 0; i < str.length; i++) {
|
|
1850
|
-
const char = str.charCodeAt(i);
|
|
1851
|
-
hash = (hash << 5) - hash + char | 0;
|
|
1852
|
-
}
|
|
1853
|
-
return Math.abs(hash).toString(16).padStart(8, "0");
|
|
1854
|
-
}
|
|
1855
|
-
function escapeHtmlForTag(str) {
|
|
1856
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1857
|
-
}
|
|
1858
|
-
|
|
1859
|
-
// libs/uipack/src/shell/custom-shell-resolver.ts
|
|
1860
|
-
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
1861
|
-
var templateCache = /* @__PURE__ */ new Map();
|
|
1862
|
-
async function resolveShellTemplate(source, options) {
|
|
1863
|
-
if (isInlineShellSource(source)) {
|
|
1864
|
-
return resolveInline(source.inline);
|
|
1865
|
-
}
|
|
1866
|
-
if (isUrlShellSource(source)) {
|
|
1867
|
-
const cacheKey = `url:${source.url}`;
|
|
1868
|
-
if (!options?.noCache) {
|
|
1869
|
-
const cached = templateCache.get(cacheKey);
|
|
1870
|
-
if (cached) return cached;
|
|
1871
|
-
}
|
|
1872
|
-
const template = await fetchWithTimeout(source.url, source.timeout ?? DEFAULT_TIMEOUT_MS);
|
|
1873
|
-
const resolved = buildResolved(template, "url");
|
|
1874
|
-
if (!options?.noCache) {
|
|
1875
|
-
templateCache.set(cacheKey, resolved);
|
|
1876
|
-
}
|
|
1877
|
-
return resolved;
|
|
1878
|
-
}
|
|
1879
|
-
if (isNpmShellSource(source)) {
|
|
1880
|
-
const specifier = source.version ? `${source.npm}@${source.version}` : source.npm;
|
|
1881
|
-
const cacheKey = `npm:${specifier}`;
|
|
1882
|
-
if (!options?.noCache) {
|
|
1883
|
-
const cached = templateCache.get(cacheKey);
|
|
1884
|
-
if (cached) return cached;
|
|
1885
|
-
}
|
|
1886
|
-
const template = await resolveNpmTemplate(source, specifier, options?.resolver);
|
|
1887
|
-
const resolved = buildResolved(template, "npm");
|
|
1888
|
-
if (!options?.noCache) {
|
|
1889
|
-
templateCache.set(cacheKey, resolved);
|
|
1890
|
-
}
|
|
1891
|
-
return resolved;
|
|
1892
|
-
}
|
|
1893
|
-
throw new Error('Invalid custom shell source: must have "inline", "url", or "npm" property');
|
|
1894
|
-
}
|
|
1895
|
-
function clearShellTemplateCache() {
|
|
1896
|
-
templateCache.clear();
|
|
1897
|
-
}
|
|
1898
|
-
function resolveInline(template) {
|
|
1899
|
-
return buildResolved(template, "inline");
|
|
1900
|
-
}
|
|
1901
|
-
function buildResolved(template, sourceType) {
|
|
1902
|
-
const validation = validateShellTemplate(template);
|
|
1903
|
-
if (!validation.valid) {
|
|
1904
|
-
throw new Error(
|
|
1905
|
-
`Custom shell template is missing required placeholder(s): ${validation.missingRequired.map((n) => `{{${n}}}`).join(", ")}`
|
|
1906
|
-
);
|
|
1907
|
-
}
|
|
1908
|
-
return { template, sourceType, validation };
|
|
1909
|
-
}
|
|
1910
|
-
async function fetchWithTimeout(url, timeoutMs) {
|
|
1911
|
-
const controller = new AbortController();
|
|
1912
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
1913
|
-
try {
|
|
1914
|
-
const response = await fetch(url, { signal: controller.signal });
|
|
1915
|
-
if (!response.ok) {
|
|
1916
|
-
throw new Error(`Failed to fetch shell template from ${url}: HTTP ${response.status}`);
|
|
1917
|
-
}
|
|
1918
|
-
return await response.text();
|
|
1919
|
-
} catch (err) {
|
|
1920
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
1921
|
-
throw new Error(`Shell template fetch timed out after ${timeoutMs}ms: ${url}`);
|
|
1922
|
-
}
|
|
1923
|
-
throw err;
|
|
1924
|
-
} finally {
|
|
1925
|
-
clearTimeout(timer);
|
|
1926
|
-
}
|
|
1927
|
-
}
|
|
1928
|
-
async function resolveNpmTemplate(source, specifier, resolver) {
|
|
1929
|
-
const cdnUrl = resolveNpmToCdnUrl(specifier, resolver);
|
|
1930
|
-
const moduleText = await fetchWithTimeout(cdnUrl, DEFAULT_TIMEOUT_MS);
|
|
1931
|
-
return extractTemplateFromModule(moduleText, source.exportName);
|
|
1932
|
-
}
|
|
1933
|
-
function resolveNpmToCdnUrl(specifier, resolver) {
|
|
1934
|
-
if (resolver) {
|
|
1935
|
-
const resolved = resolver.resolve(specifier);
|
|
1936
|
-
if (resolved) {
|
|
1937
|
-
return resolved.value;
|
|
1938
|
-
}
|
|
1939
|
-
}
|
|
1940
|
-
return `https://esm.sh/${specifier}`;
|
|
1941
|
-
}
|
|
1942
|
-
function extractTemplateFromModule(moduleText, exportName) {
|
|
1943
|
-
if (exportName && exportName !== "default") {
|
|
1944
|
-
const namedPattern = new RegExp(
|
|
1945
|
-
`export\\s+(?:const|let|var)\\s+${escapeRegExp(exportName)}\\s*=\\s*\`([\\s\\S]*?)\``
|
|
1946
|
-
);
|
|
1947
|
-
const namedMatch = moduleText.match(namedPattern);
|
|
1948
|
-
if (namedMatch) {
|
|
1949
|
-
return namedMatch[1];
|
|
1950
|
-
}
|
|
1951
|
-
throw new Error(
|
|
1952
|
-
`Could not extract named export "${exportName}" from npm shell package. The package must export a template literal string.`
|
|
1953
|
-
);
|
|
1954
|
-
}
|
|
1955
|
-
const defaultPattern = /export\s+default\s+`([\s\S]*?)`/;
|
|
1956
|
-
const defaultMatch = moduleText.match(defaultPattern);
|
|
1957
|
-
if (defaultMatch) {
|
|
1958
|
-
return defaultMatch[1];
|
|
1959
|
-
}
|
|
1960
|
-
throw new Error(
|
|
1961
|
-
"Could not extract default export from npm shell package. The package must export a template literal string (e.g., export default `<html>...</html>`)."
|
|
1962
|
-
);
|
|
1963
|
-
}
|
|
1964
|
-
function escapeRegExp(str) {
|
|
1965
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1966
|
-
}
|
|
1967
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
1968
|
-
0 && (module.exports = {
|
|
1969
|
-
DEFAULT_CDN_DOMAINS,
|
|
1970
|
-
DEFAULT_CSP_DIRECTIVES,
|
|
1971
|
-
OPTIONAL_PLACEHOLDERS,
|
|
1972
|
-
REQUIRED_PLACEHOLDERS,
|
|
1973
|
-
RESTRICTIVE_CSP_DIRECTIVES,
|
|
1974
|
-
SHELL_PLACEHOLDERS,
|
|
1975
|
-
SHELL_PLACEHOLDER_NAMES,
|
|
1976
|
-
applyShellTemplate,
|
|
1977
|
-
buildCSPDirectives,
|
|
1978
|
-
buildCSPMetaTag,
|
|
1979
|
-
buildCustomDataInjectionScript,
|
|
1980
|
-
buildDataInjectionScript,
|
|
1981
|
-
buildShell,
|
|
1982
|
-
buildSizingStyleTag,
|
|
1983
|
-
clearShellTemplateCache,
|
|
1984
|
-
createTemplateHelpers,
|
|
1985
|
-
hasSizing,
|
|
1986
|
-
html,
|
|
1987
|
-
isInlineShellSource,
|
|
1988
|
-
isNpmShellSource,
|
|
1989
|
-
isTrustedHtml,
|
|
1990
|
-
isUrlShellSource,
|
|
1991
|
-
resolveShellTemplate,
|
|
1992
|
-
sanitizeCSPDomains,
|
|
1993
|
-
trustedHtml,
|
|
1994
|
-
validateCSPDomain,
|
|
1995
|
-
validateShellTemplate
|
|
1996
|
-
});
|
|
1208
|
+
</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}
|
|
1209
|
+
${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,"&").replace(/</g,"<").replace(/>/g,">")}var DEFAULT_TIMEOUT_MS=1e4;var templateCache=new Map;async function resolveShellTemplate(source,options){if(isInlineShellSource(source)){return resolveInline(source.inline)}if(isUrlShellSource(source)){const cacheKey=`url:${source.url}`;if(!options?.noCache){const cached=templateCache.get(cacheKey);if(cached)return cached}const template=await fetchWithTimeout(source.url,source.timeout??DEFAULT_TIMEOUT_MS);const resolved=buildResolved(template,"url");if(!options?.noCache){templateCache.set(cacheKey,resolved)}return resolved}if(isNpmShellSource(source)){const specifier=source.version?`${source.npm}@${source.version}`:source.npm;const cacheKey=`npm:${specifier}`;if(!options?.noCache){const cached=templateCache.get(cacheKey);if(cached)return cached}const template=await resolveNpmTemplate(source,specifier,options?.resolver);const resolved=buildResolved(template,"npm");if(!options?.noCache){templateCache.set(cacheKey,resolved)}return resolved}throw new Error('Invalid custom shell source: must have "inline", "url", or "npm" property')}function clearShellTemplateCache(){templateCache.clear()}function resolveInline(template){return buildResolved(template,"inline")}function buildResolved(template,sourceType){const validation=validateShellTemplate(template);if(!validation.valid){throw new Error(`Custom shell template is missing required placeholder(s): ${validation.missingRequired.map(n=>`{{${n}}}`).join(", ")}`)}return{template,sourceType,validation}}async function fetchWithTimeout(url,timeoutMs){const controller=new AbortController;const timer=setTimeout(()=>controller.abort(),timeoutMs);try{const response=await fetch(url,{signal:controller.signal});if(!response.ok){throw new Error(`Failed to fetch shell template from ${url}: HTTP ${response.status}`)}return await response.text()}catch(err){if(err instanceof Error&&err.name==="AbortError"){throw new Error(`Shell template fetch timed out after ${timeoutMs}ms: ${url}`)}throw err}finally{clearTimeout(timer)}}async function resolveNpmTemplate(source,specifier,resolver){const cdnUrl=resolveNpmToCdnUrl(specifier,resolver);const moduleText=await fetchWithTimeout(cdnUrl,DEFAULT_TIMEOUT_MS);return extractTemplateFromModule(moduleText,source.exportName)}function resolveNpmToCdnUrl(specifier,resolver){if(resolver){const resolved=resolver.resolve(specifier);if(resolved){return resolved.value}}return`https://esm.sh/${specifier}`}function extractTemplateFromModule(moduleText,exportName){if(exportName&&exportName!=="default"){const namedPattern=new RegExp(`export\\s+(?:const|let|var)\\s+${escapeRegExp(exportName)}\\s*=\\s*\`([\\s\\S]*?)\``);const namedMatch=moduleText.match(namedPattern);if(namedMatch){return namedMatch[1]}throw new Error(`Could not extract named export "${exportName}" from npm shell package. The package must export a template literal string.`)}const defaultPattern=/export\s+default\s+`([\s\S]*?)`/;const defaultMatch=moduleText.match(defaultPattern);if(defaultMatch){return defaultMatch[1]}throw new Error("Could not extract default export from npm shell package. The package must export a template literal string (e.g., export default `<html>...</html>`).")}function escapeRegExp(str){return str.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}0&&(module.exports={DEFAULT_CDN_DOMAINS,DEFAULT_CSP_DIRECTIVES,OPTIONAL_PLACEHOLDERS,REQUIRED_PLACEHOLDERS,RESTRICTIVE_CSP_DIRECTIVES,SHELL_PLACEHOLDERS,SHELL_PLACEHOLDER_NAMES,applyShellTemplate,buildCSPDirectives,buildCSPMetaTag,buildCustomDataInjectionScript,buildDataInjectionScript,buildShell,buildSizingStyleTag,clearShellTemplateCache,createTemplateHelpers,hasSizing,html,isInlineShellSource,isNpmShellSource,isTrustedHtml,isUrlShellSource,resolveShellTemplate,sanitizeCSPDomains,trustedHtml,validateCSPDomain,validateShellTemplate});
|