@frontmcp/uipack 1.12.0-rc.1 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapters/content-renderers.d.ts.map +1 -1
- package/adapters/index.js +15 -4
- package/adapters/markdown.d.ts.map +1 -1
- package/adapters/template-renderer.d.ts.map +1 -1
- package/bridge-runtime/iife-generator.d.ts.map +1 -1
- package/bridge-runtime/index.js +1 -0
- package/component/index.js +1 -0
- package/esm/adapters/index.mjs +15 -4
- package/esm/bridge-runtime/index.mjs +1 -0
- package/esm/component/index.mjs +1 -0
- package/esm/index.mjs +19 -8
- package/esm/package.json +2 -2
- package/esm/resolver/index.mjs +1 -1
- package/esm/shell/index.mjs +2 -1
- package/esm/typings/index.mjs +2 -2
- package/index.js +19 -8
- package/package.json +2 -2
- package/resolver/import-rewriter.d.ts.map +1 -1
- package/resolver/index.js +1 -1
- package/shell/index.js +2 -1
- package/shell/sanitize-css.d.ts.map +1 -1
- package/typings/dts-parser.d.ts.map +1 -1
- package/typings/index.js +2 -2
- package/typings/type-fetcher.d.ts +2 -1
- package/typings/type-fetcher.d.ts.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-renderers.d.ts","sourceRoot":"","sources":["../../src/adapters/content-renderers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"content-renderers.d.ts","sourceRoot":"","sources":["../../src/adapters/content-renderers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAqBzE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAoB5D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA8CnD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAiBtE"}
|
package/adapters/index.js
CHANGED
|
@@ -394,6 +394,7 @@ var ExtAppsAdapter = {
|
|
|
394
394
|
});
|
|
395
395
|
},
|
|
396
396
|
handleMessage: function(context, event) {
|
|
397
|
+
if (event.source !== window.parent) return;
|
|
397
398
|
if (!this.isOriginTrusted(event.origin)) return;
|
|
398
399
|
var data = event.data;
|
|
399
400
|
if (!data || typeof data !== 'object' || data.jsonrpc !== '2.0') return;
|
|
@@ -1296,7 +1297,7 @@ if (__root) {
|
|
|
1296
1297
|
React.createElement(${componentName})
|
|
1297
1298
|
)
|
|
1298
1299
|
);
|
|
1299
|
-
}`}var import_entities=require("entities");var CSS_ESCAPE=/\\(?:([0-9a-fA-F]{1,6})[ \t\n\r\f]?|([^\n\r\f0-9a-fA-F]))/g;var CSS_COMMENT=/\/\*[\s\S]*?(?:\*\/|$)/g;function unescapeCss(text){return text.replace(CSS_ESCAPE,(_match,hex,character)=>{if(hex===void 0)return character??"";const codePoint=parseInt(hex,16);const valid=codePoint>0&&codePoint<=1114111&&(codePoint<55296||codePoint>57343);return valid?String.fromCodePoint(codePoint):"\uFFFD"})}function sanitizeStyleText(css){return removeImports(css.replace(/</g,"\\3c ").replace(/&(?=[#A-Za-z0-9])/g,"\\26 "))}function removeImports(css){const kept=[];let start=0;let index=css.indexOf("@");while(index!==-1){const nameEnd=identEnd(css,index+1);if(unescapeCss(css.slice(index+1,nameEnd)).toLowerCase()==="import"){kept.push(css.slice(start,index)," ");start=statementEnd(css,nameEnd);index=css.indexOf("@",start)}else{index=css.indexOf("@",index+1)}}kept.push(css.slice(start));return kept.join("")}function commentEnd(css,start){const end=css.indexOf("*/",start+2);return end===-1?css.length:end+2}function stringEnd(css,start){const quote=css[start];let index=start+1;while(index<css.length&&css[index]!==quote&&css[index]!=="\n"){index+=css[index]==="\\"?2:1}return Math.min(index+1,css.length)}function isIdentCharacter(character){return character==="-"||/\w/.test(character)||character.charCodeAt(0)>=128}function identEnd(css,start){let index=start;while(index<css.length){if(css[index]==="\\"&&css[index+1]!==void 0&&css[index+1]!=="\n"){index+=2}else if(isIdentCharacter(css[index])){index++}else{break}}return index}function statementEnd(css,start){let depth=0;let index=start;while(index<css.length){const character=css[index];if(character==="/"&&css[index+1]==="*"){index=commentEnd(css,index);continue}if(character==='"'||character==="'"){index=stringEnd(css,index);continue}if(character==="("||character==="["||character==="{")depth++;if(character===")"||character==="]")depth=Math.max(0,depth-1);if(character==="}"){if(depth===0)return index;depth--;if(depth===0)return index+1}if(character===";"&&depth===0)return index+1;index++}return css.length}function sanitizeStyleAttribute(style){const declarations=splitDeclarations(style);const kept=declarations.filter(declaration=>!isFixedPosition(declaration));return kept.length===declarations.length?style:kept.join(";")}function splitDeclarations(style){const declarations=[];let depth=0;let start=0;let index=0;while(index<style.length){const character=style[index];if(character==="/"&&style[index+1]==="*"){index=commentEnd(style,index);continue}if(character==='"'||character==="'"){index=stringEnd(style,index);continue}if(character==="(")depth++;if(character===")")depth=Math.max(0,depth-1);if(character===";"&&depth===0){declarations.push(style.slice(start,index));start=index+1}index++}declarations.push(style.slice(start));return declarations}function isFixedPosition(declaration){const text=declaration.replace(CSS_COMMENT,"");const colon=text.indexOf(":");if(colon===-1)return false;const property=unescapeCss(text.slice(0,colon)).trim().toLowerCase();const value=unescapeCss(text.slice(colon+1)).toLowerCase();return property==="position"&&/fixed|sticky|var\(/.test(value)}var DEFAULT_MAX_MARKUP_LENGTH=2*1024*1024;var POLICY_FLAGS=["allowUnsafeLinks","allowInlineScripts","allowToolCallAttributes","bypassSanitization"];var WHITESPACE=/[\t\n\f\r ]/;var TAG_NAME=/^[A-Za-z][A-Za-z0-9-]*$/;var ATTRIBUTE_NAME_BREAKERS=/[\s"'<>/=]/;var COMMENT_END=/--!?>/g;var RAW_TEXT_CONTENT={script:content=>content,style:sanitizeStyleText,textarea:content=>content.replace(/</g,"<"),title:content=>content.replace(/</g,"<"),xmp:content=>content.replace(/</g,"<"),iframe:()=>"",noembed:()=>"",noframes:()=>"",noscript:()=>""};var RAW_TEXT_END=Object.fromEntries(Object.keys(RAW_TEXT_CONTENT).map(name=>[name,new RegExp(`</${name}(?=[\\t\\n\\f\\r />])`,"gi")]));var DROPPED_TAGS=new Set(["base","meta","object","embed","applet","animate","animatecolor","animatemotion","animatetransform","set"]);var URL_ATTRIBUTES=new Set(["href","xlink:href","src","action","formaction","poster","background","cite","data","codebase","classid","archive","longdesc","lowsrc","dynsrc","manifest","icon","profile"]);var URL_LIST_ATTRIBUTES=new Set(["srcset","imagesrcset","ping"]);var SCRIPT_SOURCE_ATTRIBUTES=new Set(["src","href","xlink:href"]);var TOOL_CALL_ATTRIBUTES=new Set(["data-tool-call","data-tool-args"]);var NAVIGATION_ATTRIBUTES={a:new Set(["href","xlink:href"]),area:new Set(["href","xlink:href"]),form:new Set(["action"]),button:new Set(["formaction"]),input:new Set(["formaction"])};var SAFE_SCHEMES=new Set(["http","https","mailto"]);var RASTER_IMAGE_DATA_URL=/^data:image\/(png|gif|jpeg|webp|avif)[;,]/i;var URL_SCHEME=/^([A-Za-z][A-Za-z0-9+.-]*):/;function sanitizeHtml(markup,policy={}){const problems=describeContentSecurityProblems(policy);if(problems.length>0)throw new TypeError(problems.join(" "));if(policy.bypassSanitization)return markup;const maxLength=policy.maxMarkupLength??DEFAULT_MAX_MARKUP_LENGTH;if(markup.length>maxLength){throw new RangeError(`The markup is ${markup.length} characters, over the ${maxLength} that \`ui.contentSecurity\` sanitizes (\`maxMarkupLength\`), so it is not rendered.`)}const output=[];let index=0;while(index<markup.length){const open=markup.indexOf("<",index);if(open===-1){output.push(markup.slice(index));break}output.push(markup.slice(index,open));const next=markup[open+1]??"";if(next==="!"||next==="?"){index=skipDeclaration(markup,open)}else if(next==="/"){index=writeEndTag(markup,open,output)}else if(isAsciiLetter(next)){index=writeElement(markup,open,output,policy)}else{output.push("<");index=open+1}}return output.join("")}function describeContentSecurityProblems(policy){if(!isPlainObject(policy)){return[`\`ui.contentSecurity\` must be an object of flags, and it is ${describeValue(policy)}.`]}const problems=[];for(const[key,value]of Object.entries(policy)){if(value===void 0)continue;if(POLICY_FLAGS.includes(key)){if(typeof value!=="boolean"){problems.push(`\`ui.contentSecurity.${key}\` must be true or false, and it is ${describeValue(value)}.`)}}else if(key==="maxMarkupLength"){if(!Number.isSafeInteger(value)||value<=0){problems.push(`\`ui.contentSecurity.maxMarkupLength\` must be a positive integer, and it is ${describeValue(value)}.`)}}else{problems.push(`\`ui.contentSecurity\` has no \`${key}\` option; its options are \`${POLICY_FLAGS.join("`, `")}\` and \`maxMarkupLength\`.`)}}return problems}function isPlainObject(value){if(typeof value!=="object"||value===null)return false;const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}function describeValue(value){if(value===null||Array.isArray(value))return JSON.stringify(value);return typeof value==="object"||typeof value==="function"?`a ${typeof value}`:`${typeof value} ${JSON.stringify(value)}`}function isAsciiLetter(character){return/^[A-Za-z]$/.test(character)}function asciiLowerCase(text){return text.replace(/[A-Z]/g,letter=>letter.toLowerCase())}function skipDeclaration(markup,open){if(markup.startsWith("<!--",open)){COMMENT_END.lastIndex=open+2;const close2=COMMENT_END.exec(markup);return close2?close2.index+close2[0].length:markup.length}const close=markup.indexOf(">",open);return close===-1?markup.length:close+1}function writeEndTag(markup,open,output){if(!isAsciiLetter(markup[open+2]??"")){return markup.startsWith("</>",open)?open+3:skipDeclaration(markup,open)}const tag=parseTag(markup,open+2);if(!tag)return markup.length;if(TAG_NAME.test(tag.name)&&!DROPPED_TAGS.has(asciiLowerCase(tag.name)))output.push(`</${tag.name}>`);return tag.end}function writeElement(markup,open,output,policy){const tag=parseTag(markup,open+1);if(!tag)return markup.length;const name=asciiLowerCase(tag.name);if(name==="plaintext"){output.push(markup.slice(tag.end).replace(/</g,"<"));return markup.length}const keepContent=RAW_TEXT_CONTENT[name];if(keepContent){const{content,end}=readRawText(markup,tag.end,name);if(name==="script"&&!isAllowedScript(tag,policy))return end;output.push(`<${tag.name}${writeAttributes(name,tag.attributes,policy)}>${keepContent(content)}</${tag.name}>`);return end}if(TAG_NAME.test(tag.name)&&!DROPPED_TAGS.has(name)&&!isCrossOriginStylesheet(name,tag.attributes)){output.push(`<${tag.name}${writeAttributes(name,tag.attributes,policy)}${tag.selfClosing?" /":""}>`)}return tag.end}function isAllowedScript(tag,policy){return policy.allowInlineScripts===true&&!tag.attributes.some(({name})=>SCRIPT_SOURCE_ATTRIBUTES.has(asciiLowerCase(name)))}function isCrossOriginStylesheet(tagName,attributes){if(tagName!=="link")return false;const rel=attributeValue(attributes,"rel");const href=attributeValue(attributes,"href");if(rel===void 0||href===void 0||!/(^|[\t\n\f\r ])stylesheet($|[\t\n\f\r ])/i.test(rel))return false;const url=urlAsParsed(href);return URL_SCHEME.test(url)||/^[\\/]{2}/.test(url)}function attributeValue(attributes,name){const attribute=attributes.find(candidate=>asciiLowerCase(candidate.name)===name);return attribute?.value===void 0?void 0:decodeAttributeValue(attribute.value)}function readRawText(markup,start,name){const endTag=RAW_TEXT_END[name];endTag.lastIndex=start;const match=endTag.exec(markup);if(!match)return{content:markup.slice(start),end:markup.length};const tag=parseTag(markup,match.index+2);return{content:markup.slice(start,match.index),end:tag?tag.end:markup.length}}function parseTag(markup,start){let index=start;while(index<markup.length&&!/[\t\n\f\r />]/.test(markup[index]))index++;const tag={name:markup.slice(start,index),attributes:[],selfClosing:false,end:0};while(index<markup.length){const character=markup[index];if(WHITESPACE.test(character)){index++}else if(character===">"){tag.end=index+1;return tag}else if(character==="/"){index++;if(markup[index]===">"){tag.selfClosing=true;tag.end=index+1;return tag}}else{index=readAttribute(markup,index,tag.attributes)}}return void 0}function readAttribute(markup,start,attributes){let index=start+1;while(index<markup.length&&!/[\t\n\f\r />=]/.test(markup[index]))index++;const attribute={name:markup.slice(start,index),value:void 0};attributes.push(attribute);let afterName=index;while(afterName<markup.length&&WHITESPACE.test(markup[afterName]))afterName++;if(markup[afterName]!=="=")return afterName;index=afterName+1;while(index<markup.length&&WHITESPACE.test(markup[index]))index++;const quote=markup[index];if(quote==='"'||quote==="'"){const close=markup.indexOf(quote,index+1);if(close===-1)return markup.length;attribute.value=markup.slice(index+1,close);return close+1}if(quote===">"){attribute.value="";return index}const valueStart=index;while(index<markup.length&&!/[\t\n\f\r >]/.test(markup[index]))index++;attribute.value=markup.slice(valueStart,index);return index}function decodeAttributeValue(raw){return(0,import_entities.decodeHTMLAttribute)(raw).split("\0").join("\uFFFD")}function escapeAttributeValue(value){return value.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function writeAttributes(tagName,attributes,policy){const seen=new Set;let written="";for(const attribute of attributes){const name=asciiLowerCase(attribute.name);if(seen.has(name))continue;seen.add(name);if(!isWritableAttributeName(attribute.name)||name==="srcdoc")continue;if(name.startsWith("on")&&!policy.allowInlineScripts)continue;if(TOOL_CALL_ATTRIBUTES.has(name)&&!policy.allowToolCallAttributes)continue;if(attribute.value===void 0){written+=` ${attribute.name}`;continue}const value=decodeAttributeValue(attribute.value);if(!isAllowedValue(tagName,name,value,policy))continue;written+=` ${attribute.name}="${escapeAttributeValue(name==="style"?sanitizeStyleAttribute(value):value)}"`}return written}function isWritableAttributeName(name){if(name.length===0||ATTRIBUTE_NAME_BREAKERS.test(name))return false;return[...name].every(character=>character.charCodeAt(0)>31&&character.charCodeAt(0)!==127)}function isAllowedValue(tagName,attributeName,value,policy){if(URL_ATTRIBUTES.has(attributeName)){return isAllowedUrl(value,{imageData:tagName==="img"&&attributeName==="src",navigation:policy.allowUnsafeLinks===true&&NAVIGATION_ATTRIBUTES[tagName]?.has(attributeName)===true})}if(URL_LIST_ATTRIBUTES.has(attributeName)){const separator=attributeName==="ping"?/\s+/:/,/;return value.split(separator).every(candidate=>isAllowedUrl(candidate.trim().split(/\s+/)[0]??"",{}))}return true}function urlAsParsed(value){const url=value.replace(/[\t\n\r]/g,"");let start=0;while(start<url.length&&(url.charCodeAt(start)<=32||/\s/.test(url[start])))start++;return url.slice(start)}function isAllowedUrl(value,allowed){const url=urlAsParsed(value);const scheme=URL_SCHEME.exec(url)?.[1].toLowerCase();if(scheme===void 0||SAFE_SCHEMES.has(scheme))return true;if(scheme==="data")return allowed.imageData===true&&RASTER_IMAGE_DATA_URL.test(url);return allowed.navigation===true}function projectRequires(){const{createRequire}=process.getBuiltinModule("node:module");const path=process.getBuiltinModule("node:path");const bases=[process.cwd()];if(process.argv[1])bases.push(path.dirname(process.argv[1]));return bases.map(base=>createRequire(path.join(base,"package.json")))}function packageName(specifier){const parts=specifier.split("/");return specifier.startsWith("@")?parts.slice(0,2).join("/"):parts[0]}function isNotFound(error,specifier){const{code,message}=error??{};return(code==="MODULE_NOT_FOUND"||code==="ERR_MODULE_NOT_FOUND")&&typeof message==="string"&&message.includes(`'${packageName(specifier)}`)}function fromProject(specifier,purpose,use){let notFound;for(const projectRequire of projectRequires()){try{return use(projectRequire)}catch(error){if(!isNotFound(error,specifier))throw error;notFound=error}}const name=packageName(specifier);throw new Error(`${purpose} needs ${name}, which is not installed. Install it where the server runs: \`npm install ${name}\`.`,{cause:notFound})}var preloaded=new Map;function requireFromProject(specifier,purpose){if(preloaded.has(specifier))return preloaded.get(specifier);return fromProject(specifier,purpose,projectRequire=>projectRequire(specifier))}async function preloadFromProject(specifier,purpose){if(preloaded.has(specifier))return;const{pathToFileURL}=process.getBuiltinModule("node:url");const url=pathToFileURL(resolveFromProject(specifier,purpose)).href;let loaded;try{loaded=await import(url)}catch{loaded=requireFromProject(specifier,purpose)}preloaded.set(specifier,loaded)}function resolveFromProject(specifier,purpose){return fromProject(specifier,purpose,projectRequire=>projectRequire.resolve(specifier))}var PURPOSE="`ui.runtimeOptions.markdown.highlightTheme`";var THEME_NAME=/^[a-z0-9-]+(\/[a-z0-9-]+)?$/i;var highlighters=new Map;function loadCodeHighlighter(theme){const loaded=highlighters.get(theme);if(loaded)return loaded;const hljs=requireFromProject("highlight.js",PURPOSE);const highlighter={highlight:(code,language)=>hljs.getLanguage(language)?hljs.highlight(code,{language,ignoreIllegals:true}).value:void 0,css:readTheme(theme)};highlighters.set(theme,highlighter);return highlighter}function readTheme(theme){const fs=require("fs");const path=require("path");const styles=path.join(path.dirname(resolveFromProject("highlight.js/package.json",PURPOSE)),"styles");const file=path.join(styles,`${theme}.min.css`);if(!THEME_NAME.test(theme)||!fs.existsSync(file)){throw new Error(`${PURPOSE} is ${JSON.stringify(theme)}, which is not a highlight.js theme: name a stylesheet in highlight.js/styles without its extension, such as "github", "github-dark" or "base16/dracula".`)}return fs.readFileSync(file,"utf-8")}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=`
|
|
1300
|
+
}`}var import_entities=require("entities");var CSS_ESCAPE=/\\(?:([0-9a-fA-F]{1,6})(?:\r\n|[ \t\n\r\f])?|([^\n\r\f0-9a-fA-F]))/g;var CSS_ESCAPE_AT=new RegExp(CSS_ESCAPE.source,"y");var CSS_COMMENT=/\/\*[\s\S]*?(?:\*\/|$)/g;function unescapeCss(text){return text.replace(CSS_ESCAPE,(_match,hex,character)=>{if(hex===void 0)return character??"";const codePoint=parseInt(hex,16);const valid=codePoint>0&&codePoint<=1114111&&(codePoint<55296||codePoint>57343);return valid?String.fromCodePoint(codePoint):"\uFFFD"})}function sanitizeStyleText(css){return removeImports(css.replace(/</g,"\\3c ").replace(/&(?=[#A-Za-z0-9])/g,"\\26 "))}function removeImports(css){const kept=[];let start=0;let index=css.indexOf("@");while(index!==-1){const nameEnd=identEnd(css,index+1);if(unescapeCss(css.slice(index+1,nameEnd)).toLowerCase()==="import"){kept.push(css.slice(start,index)," ");start=statementEnd(css,nameEnd);index=css.indexOf("@",start)}else{index=css.indexOf("@",index+1)}}kept.push(css.slice(start));return kept.join("")}function commentEnd(css,start){const end=css.indexOf("*/",start+2);return end===-1?css.length:end+2}function stringEnd(css,start){const quote=css[start];let index=start+1;while(index<css.length&&css[index]!==quote&&css[index]!=="\n"){index+=css[index]==="\\"?2:1}return Math.min(index+1,css.length)}function isIdentCharacter(character){return character==="-"||/\w/.test(character)||character.charCodeAt(0)>=128}function identEnd(css,start){let index=start;while(index<css.length){CSS_ESCAPE_AT.lastIndex=index;if(CSS_ESCAPE_AT.test(css)){index=CSS_ESCAPE_AT.lastIndex}else if(isIdentCharacter(css[index])){index++}else{break}}return index}function statementEnd(css,start){let depth=0;let index=start;while(index<css.length){const character=css[index];if(character==="/"&&css[index+1]==="*"){index=commentEnd(css,index);continue}if(character==='"'||character==="'"){index=stringEnd(css,index);continue}if(character==="("||character==="["||character==="{")depth++;if(character===")"||character==="]")depth=Math.max(0,depth-1);if(character==="}"){if(depth===0)return index;depth--;if(depth===0)return index+1}if(character===";"&&depth===0)return index+1;index++}return css.length}function sanitizeStyleAttribute(style){const declarations=splitDeclarations(style);const kept=declarations.filter(declaration=>!isFixedPosition(declaration));return kept.length===declarations.length?style:kept.join(";")}function splitDeclarations(style){const declarations=[];let depth=0;let start=0;let index=0;while(index<style.length){const character=style[index];if(character==="/"&&style[index+1]==="*"){index=commentEnd(style,index);continue}if(character==='"'||character==="'"){index=stringEnd(style,index);continue}if(character==="(")depth++;if(character===")")depth=Math.max(0,depth-1);if(character===";"&&depth===0){declarations.push(style.slice(start,index));start=index+1}index++}declarations.push(style.slice(start));return declarations}function isFixedPosition(declaration){const text=declaration.replace(CSS_COMMENT,"");const colon=text.indexOf(":");if(colon===-1)return false;const property=unescapeCss(text.slice(0,colon)).trim().toLowerCase();const value=unescapeCss(text.slice(colon+1)).toLowerCase();return property==="position"&&/fixed|sticky|var\(/.test(value)}var DEFAULT_MAX_MARKUP_LENGTH=2*1024*1024;var POLICY_FLAGS=["allowUnsafeLinks","allowInlineScripts","allowToolCallAttributes","bypassSanitization"];var WHITESPACE=/[\t\n\f\r ]/;var TAG_NAME=/^[A-Za-z][A-Za-z0-9-]*$/;var ATTRIBUTE_NAME_BREAKERS=/[\s"'<>/=]/;var COMMENT_END=/--!?>/g;var RAW_TEXT_CONTENT={script:content=>content,style:sanitizeStyleText,textarea:content=>content.replace(/</g,"<"),title:content=>content.replace(/</g,"<"),xmp:content=>content.replace(/</g,"<"),iframe:()=>"",noembed:()=>"",noframes:()=>"",noscript:()=>""};var RAW_TEXT_END=Object.fromEntries(Object.keys(RAW_TEXT_CONTENT).map(name=>[name,new RegExp(`</${name}(?=[\\t\\n\\f\\r />])`,"gi")]));var DROPPED_TAGS=new Set(["base","meta","object","embed","applet","animate","animatecolor","animatemotion","animatetransform","set"]);var URL_ATTRIBUTES=new Set(["href","xlink:href","src","action","formaction","poster","background","cite","data","codebase","classid","archive","longdesc","lowsrc","dynsrc","manifest","icon","profile"]);var URL_LIST_ATTRIBUTES=new Set(["srcset","imagesrcset","ping"]);var SCRIPT_SOURCE_ATTRIBUTES=new Set(["src","href","xlink:href"]);var TOOL_CALL_ATTRIBUTES=new Set(["data-tool-call","data-tool-args"]);var NAVIGATION_ATTRIBUTES={a:new Set(["href","xlink:href"]),area:new Set(["href","xlink:href"]),form:new Set(["action"]),button:new Set(["formaction"]),input:new Set(["formaction"])};var SAFE_SCHEMES=new Set(["http","https","mailto"]);var RASTER_IMAGE_DATA_URL=/^data:image\/(png|gif|jpeg|webp|avif)[;,]/i;var URL_SCHEME=/^([A-Za-z][A-Za-z0-9+.-]*):/;function sanitizeHtml(markup,policy={}){const problems=describeContentSecurityProblems(policy);if(problems.length>0)throw new TypeError(problems.join(" "));if(policy.bypassSanitization)return markup;const maxLength=policy.maxMarkupLength??DEFAULT_MAX_MARKUP_LENGTH;if(markup.length>maxLength){throw new RangeError(`The markup is ${markup.length} characters, over the ${maxLength} that \`ui.contentSecurity\` sanitizes (\`maxMarkupLength\`), so it is not rendered.`)}const output=[];let index=0;while(index<markup.length){const open=markup.indexOf("<",index);if(open===-1){output.push(markup.slice(index));break}output.push(markup.slice(index,open));const next=markup[open+1]??"";if(next==="!"||next==="?"){index=skipDeclaration(markup,open)}else if(next==="/"){index=writeEndTag(markup,open,output)}else if(isAsciiLetter(next)){index=writeElement(markup,open,output,policy)}else{output.push("<");index=open+1}}return output.join("")}function describeContentSecurityProblems(policy){if(!isPlainObject(policy)){return[`\`ui.contentSecurity\` must be an object of flags, and it is ${describeValue(policy)}.`]}const problems=[];for(const[key,value]of Object.entries(policy)){if(value===void 0)continue;if(POLICY_FLAGS.includes(key)){if(typeof value!=="boolean"){problems.push(`\`ui.contentSecurity.${key}\` must be true or false, and it is ${describeValue(value)}.`)}}else if(key==="maxMarkupLength"){if(!Number.isSafeInteger(value)||value<=0){problems.push(`\`ui.contentSecurity.maxMarkupLength\` must be a positive integer, and it is ${describeValue(value)}.`)}}else{problems.push(`\`ui.contentSecurity\` has no \`${key}\` option; its options are \`${POLICY_FLAGS.join("`, `")}\` and \`maxMarkupLength\`.`)}}return problems}function isPlainObject(value){if(typeof value!=="object"||value===null)return false;const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}function describeValue(value){if(value===null||Array.isArray(value))return JSON.stringify(value);return typeof value==="object"||typeof value==="function"?`a ${typeof value}`:`${typeof value} ${JSON.stringify(value)}`}function isAsciiLetter(character){return/^[A-Za-z]$/.test(character)}function asciiLowerCase(text){return text.replace(/[A-Z]/g,letter=>letter.toLowerCase())}function skipDeclaration(markup,open){if(markup.startsWith("<!--",open)){COMMENT_END.lastIndex=open+2;const close2=COMMENT_END.exec(markup);return close2?close2.index+close2[0].length:markup.length}const close=markup.indexOf(">",open);return close===-1?markup.length:close+1}function writeEndTag(markup,open,output){if(!isAsciiLetter(markup[open+2]??"")){return markup.startsWith("</>",open)?open+3:skipDeclaration(markup,open)}const tag=parseTag(markup,open+2);if(!tag)return markup.length;if(TAG_NAME.test(tag.name)&&!DROPPED_TAGS.has(asciiLowerCase(tag.name)))output.push(`</${tag.name}>`);return tag.end}function writeElement(markup,open,output,policy){const tag=parseTag(markup,open+1);if(!tag)return markup.length;const name=asciiLowerCase(tag.name);if(name==="plaintext"){output.push(markup.slice(tag.end).replace(/</g,"<"));return markup.length}const keepContent=RAW_TEXT_CONTENT[name];if(keepContent){const{content,end}=readRawText(markup,tag.end,name);if(name==="script"&&!isAllowedScript(tag,policy))return end;output.push(`<${tag.name}${writeAttributes(name,tag.attributes,policy)}>${keepContent(content)}</${tag.name}>`);return end}if(TAG_NAME.test(tag.name)&&!DROPPED_TAGS.has(name)&&!isCrossOriginStylesheet(name,tag.attributes)){output.push(`<${tag.name}${writeAttributes(name,tag.attributes,policy)}${tag.selfClosing?" /":""}>`)}return tag.end}function isAllowedScript(tag,policy){return policy.allowInlineScripts===true&&!tag.attributes.some(({name})=>SCRIPT_SOURCE_ATTRIBUTES.has(asciiLowerCase(name)))}function isCrossOriginStylesheet(tagName,attributes){if(tagName!=="link")return false;const rel=attributeValue(attributes,"rel");const href=attributeValue(attributes,"href");if(rel===void 0||href===void 0||!/(^|[\t\n\f\r ])stylesheet($|[\t\n\f\r ])/i.test(rel))return false;const url=urlAsParsed(href);return URL_SCHEME.test(url)||/^[\\/]{2}/.test(url)}function attributeValue(attributes,name){const attribute=attributes.find(candidate=>asciiLowerCase(candidate.name)===name);return attribute?.value===void 0?void 0:decodeAttributeValue(attribute.value)}function readRawText(markup,start,name){const endTag=RAW_TEXT_END[name];endTag.lastIndex=start;const match=endTag.exec(markup);if(!match)return{content:markup.slice(start),end:markup.length};const tag=parseTag(markup,match.index+2);return{content:markup.slice(start,match.index),end:tag?tag.end:markup.length}}function parseTag(markup,start){let index=start;while(index<markup.length&&!/[\t\n\f\r />]/.test(markup[index]))index++;const tag={name:markup.slice(start,index),attributes:[],selfClosing:false,end:0};while(index<markup.length){const character=markup[index];if(WHITESPACE.test(character)){index++}else if(character===">"){tag.end=index+1;return tag}else if(character==="/"){index++;if(markup[index]===">"){tag.selfClosing=true;tag.end=index+1;return tag}}else{index=readAttribute(markup,index,tag.attributes)}}return void 0}function readAttribute(markup,start,attributes){let index=start+1;while(index<markup.length&&!/[\t\n\f\r />=]/.test(markup[index]))index++;const attribute={name:markup.slice(start,index),value:void 0};attributes.push(attribute);let afterName=index;while(afterName<markup.length&&WHITESPACE.test(markup[afterName]))afterName++;if(markup[afterName]!=="=")return afterName;index=afterName+1;while(index<markup.length&&WHITESPACE.test(markup[index]))index++;const quote=markup[index];if(quote==='"'||quote==="'"){const close=markup.indexOf(quote,index+1);if(close===-1)return markup.length;attribute.value=markup.slice(index+1,close);return close+1}if(quote===">"){attribute.value="";return index}const valueStart=index;while(index<markup.length&&!/[\t\n\f\r >]/.test(markup[index]))index++;attribute.value=markup.slice(valueStart,index);return index}function decodeAttributeValue(raw){return(0,import_entities.decodeHTMLAttribute)(raw).split("\0").join("\uFFFD")}function escapeAttributeValue(value){return value.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function writeAttributes(tagName,attributes,policy){const seen=new Set;let written="";for(const attribute of attributes){const name=asciiLowerCase(attribute.name);if(seen.has(name))continue;seen.add(name);if(!isWritableAttributeName(attribute.name)||name==="srcdoc")continue;if(name.startsWith("on")&&!policy.allowInlineScripts)continue;if(TOOL_CALL_ATTRIBUTES.has(name)&&!policy.allowToolCallAttributes)continue;if(attribute.value===void 0){written+=` ${attribute.name}`;continue}const value=decodeAttributeValue(attribute.value);if(!isAllowedValue(tagName,name,value,policy))continue;written+=` ${attribute.name}="${escapeAttributeValue(name==="style"?sanitizeStyleAttribute(value):value)}"`}return written}function isWritableAttributeName(name){if(name.length===0||ATTRIBUTE_NAME_BREAKERS.test(name))return false;return[...name].every(character=>character.charCodeAt(0)>31&&character.charCodeAt(0)!==127)}function isAllowedValue(tagName,attributeName,value,policy){if(URL_ATTRIBUTES.has(attributeName)){return isAllowedUrl(value,{imageData:tagName==="img"&&attributeName==="src",navigation:policy.allowUnsafeLinks===true&&NAVIGATION_ATTRIBUTES[tagName]?.has(attributeName)===true})}if(URL_LIST_ATTRIBUTES.has(attributeName)){const separator=attributeName==="ping"?/\s+/:/,/;return value.split(separator).every(candidate=>isAllowedUrl(candidate.trim().split(/\s+/)[0]??"",{}))}return true}function urlAsParsed(value){const url=value.replace(/[\t\n\r]/g,"");let start=0;while(start<url.length&&(url.charCodeAt(start)<=32||/\s/.test(url[start])))start++;return url.slice(start)}function isAllowedUrl(value,allowed){const url=urlAsParsed(value);const scheme=URL_SCHEME.exec(url)?.[1].toLowerCase();if(scheme===void 0||SAFE_SCHEMES.has(scheme))return true;if(scheme==="data")return allowed.imageData===true&&RASTER_IMAGE_DATA_URL.test(url);return allowed.navigation===true}function projectRequires(){const{createRequire}=process.getBuiltinModule("node:module");const path=process.getBuiltinModule("node:path");const bases=[process.cwd()];if(process.argv[1])bases.push(path.dirname(process.argv[1]));return bases.map(base=>createRequire(path.join(base,"package.json")))}function packageName(specifier){const parts=specifier.split("/");return specifier.startsWith("@")?parts.slice(0,2).join("/"):parts[0]}function isNotFound(error,specifier){const{code,message}=error??{};return(code==="MODULE_NOT_FOUND"||code==="ERR_MODULE_NOT_FOUND")&&typeof message==="string"&&message.includes(`'${packageName(specifier)}`)}function fromProject(specifier,purpose,use){let notFound;for(const projectRequire of projectRequires()){try{return use(projectRequire)}catch(error){if(!isNotFound(error,specifier))throw error;notFound=error}}const name=packageName(specifier);throw new Error(`${purpose} needs ${name}, which is not installed. Install it where the server runs: \`npm install ${name}\`.`,{cause:notFound})}var preloaded=new Map;function requireFromProject(specifier,purpose){if(preloaded.has(specifier))return preloaded.get(specifier);return fromProject(specifier,purpose,projectRequire=>projectRequire(specifier))}async function preloadFromProject(specifier,purpose){if(preloaded.has(specifier))return;const{pathToFileURL}=process.getBuiltinModule("node:url");const url=pathToFileURL(resolveFromProject(specifier,purpose)).href;let loaded;try{loaded=await import(url)}catch{loaded=requireFromProject(specifier,purpose)}preloaded.set(specifier,loaded)}function resolveFromProject(specifier,purpose){return fromProject(specifier,purpose,projectRequire=>projectRequire.resolve(specifier))}var PURPOSE="`ui.runtimeOptions.markdown.highlightTheme`";var THEME_NAME=/^[a-z0-9-]+(\/[a-z0-9-]+)?$/i;var highlighters=new Map;function loadCodeHighlighter(theme){const loaded=highlighters.get(theme);if(loaded)return loaded;const hljs=requireFromProject("highlight.js",PURPOSE);const highlighter={highlight:(code,language)=>hljs.getLanguage(language)?hljs.highlight(code,{language,ignoreIllegals:true}).value:void 0,css:readTheme(theme)};highlighters.set(theme,highlighter);return highlighter}function readTheme(theme){const fs=require("fs");const path=require("path");const styles=path.join(path.dirname(resolveFromProject("highlight.js/package.json",PURPOSE)),"styles");const file=path.join(styles,`${theme}.min.css`);if(!THEME_NAME.test(theme)||!fs.existsSync(file)){throw new Error(`${PURPOSE} is ${JSON.stringify(theme)}, which is not a highlight.js theme: name a stylesheet in highlight.js/styles without its extension, such as "github", "github-dark" or "base16/dracula".`)}return fs.readFileSync(file,"utf-8")}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";var PDF_MAX_PAGE_PIXELS=2**24;var PDF_MAX_TOTAL_PIXELS=2**27;function buildChartHtml(chartJson){const chartData=safeJsonForScript(chartJson);const content=`
|
|
1300
1301
|
<canvas id="chart" style="max-width:100%;max-height:80vh;"></canvas>
|
|
1301
1302
|
<script type="module">
|
|
1302
1303
|
import Chart from '${CHART_JS_CDN}';
|
|
@@ -1320,9 +1321,19 @@ for (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i);
|
|
|
1320
1321
|
|
|
1321
1322
|
const pdf = await pdfjsLib.getDocument({ data: bytes }).promise;
|
|
1322
1323
|
const container = document.getElementById('pdf-container');
|
|
1324
|
+
let pixelsLeft = ${PDF_MAX_TOTAL_PIXELS};
|
|
1323
1325
|
for (let i = 1; i <= pdf.numPages; i++) {
|
|
1324
1326
|
const page = await pdf.getPage(i);
|
|
1325
|
-
const
|
|
1327
|
+
const unscaled = page.getViewport({ scale: 1 });
|
|
1328
|
+
const scale = Math.min(1.5, Math.sqrt(${PDF_MAX_PAGE_PIXELS} / (unscaled.width * unscaled.height)));
|
|
1329
|
+
const viewport = page.getViewport({ scale });
|
|
1330
|
+
pixelsLeft -= Math.ceil(viewport.width) * Math.ceil(viewport.height);
|
|
1331
|
+
if (pixelsLeft < 0) {
|
|
1332
|
+
const note = document.createElement('p');
|
|
1333
|
+
note.textContent = 'Pages ' + i + ' to ' + pdf.numPages + ' are not shown: the document is too large to draw.';
|
|
1334
|
+
container.appendChild(note);
|
|
1335
|
+
break;
|
|
1336
|
+
}
|
|
1326
1337
|
const canvas = document.createElement('canvas');
|
|
1327
1338
|
canvas.width = viewport.width;
|
|
1328
1339
|
canvas.height = viewport.height;
|
|
@@ -1330,9 +1341,9 @@ for (let i = 1; i <= pdf.numPages; i++) {
|
|
|
1330
1341
|
container.appendChild(canvas);
|
|
1331
1342
|
await page.render({ canvasContext: canvas.getContext('2d'), viewport }).promise;
|
|
1332
1343
|
}
|
|
1333
|
-
</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;var PLACEHOLDER="\uE000";var BARE_URL=/(?<![\w/@.])(?:https?:\/\/|www\.)(?:(?!<)[^\s<])+/gi;var
|
|
1344
|
+
</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;var PLACEHOLDER="\uE000";var BARE_URL=/(?<![\w/@.])(?:https?:\/\/|www\.)(?:(?!<)[^\s<])+/gi;var AUTOLINK_PUNCTUATION="?!.,:*_~";var ENTITY_NAME_CHARACTER=/[a-z0-9#]/i;var HREF_END=/[)\s]/g;var TABLE_DELIMITER=/^\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?$/;var TASK_ITEM=/^\[([ xX])\]\s+(.*)$/;function emphasis(text){return text.replace(/\*\*([^*]+)\*\*/g,"<strong>$1</strong>").replace(/\*([^*]+)\*/g,"<em>$1</em>")}function replaceLinks(text,render){let result="";let copied=0;let labelEnd=-1;let hrefEnd=-1;let start=text.indexOf("[");while(start!==-1){if(labelEnd<start)labelEnd=text.indexOf("]",start+1);if(labelEnd===-1)break;const hrefStart=labelEnd+2;if(labelEnd>start+1&&text[labelEnd+1]==="("){if(hrefEnd<hrefStart){HREF_END.lastIndex=hrefStart;hrefEnd=HREF_END.exec(text)?.index??text.length}if(hrefEnd>hrefStart&&text[hrefEnd]===")"){result+=text.slice(copied,start)+render(text.slice(start+1,labelEnd),text.slice(hrefStart,hrefEnd));copied=hrefEnd+1;start=text.indexOf("[",copied);continue}}start=text.indexOf("[",start+1)}return result+text.slice(copied)}function entityStart(text,end){if(text[end-1]!==";")return-1;let index=end-2;while(index>=0&&ENTITY_NAME_CHARACTER.test(text[index]))index--;return index<end-2&&text[index]==="&"?index:-1}function trimAutolink(url){let end=url.length;let unmatchedCloses=url.split(")").length-url.split("(").length;for(;;){const last=url[end-1]??"";const entity=entityStart(url,end);if(last!==""&&AUTOLINK_PUNCTUATION.includes(last)){end--}else if(entity!==-1){end=entity}else if(last===")"&&unmatchedCloses>0){end--;unmatchedCloses--}else{return url.slice(0,end)}}}function inline(text,gfm=false){const stash=[];const hold=html2=>PLACEHOLDER+(stash.push(html2)-1)+PLACEHOLDER;const restore=value=>value.split(PLACEHOLDER).map((part,i)=>i%2===1?stash[Number(part)]:part).join("");let out=escapeHtml(text.split(PLACEHOLDER).join("")).replace(/`([^`]+)`/g,(_m,code)=>hold(`<code>${code}</code>`));out=replaceLinks(out,(label,href)=>SAFE_HREF.test(href)?hold(`<a href="${href}" rel="noopener noreferrer">${emphasis(label)}</a>`):label);if(gfm){out=out.replace(BARE_URL,match=>{const url=trimAutolink(match.split(PLACEHOLDER,1)[0]);const href=/^www\./i.test(url)?`http://${url}`:url;return hold(`<a href="${href}" rel="noopener noreferrer">${url}</a>`)+match.slice(url.length)});out=out.replace(/~~([^~]+)~~/g,"<del>$1</del>")}out=emphasis(out);return restore(restore(out))}function listItem(item,gfm){const task=gfm?TASK_ITEM.exec(item):null;if(!task)return`<li>${inline(item,gfm)}</li>`;const checked=task[1]===" "?"":" checked";return`<li class="task-list-item"><input type="checkbox" disabled${checked}> ${inline(task[2],gfm)}</li>`}function tableCells(row){const cells=row.trim().replace(/^\|/,"").replace(/(?<!\\)\|$/,"").split(/(?<!\\)\|/);return cells.map(cell=>cell.trim().replace(/\\\|/g,"|"))}function cellAlignment(delimiter){const left=delimiter.startsWith(":");const right=delimiter.endsWith(":");if(left&&right)return' align="center"';if(right)return' align="right"';return left?' align="left"':""}function table(header,delimiter,body){const alignments=tableCells(delimiter).map(cellAlignment);const row=(cells,tag)=>`<tr>${alignments.map((align,i)=>`<${tag}${align}>${inline(cells[i]??"",true)}</${tag}>`).join("")}</tr>`;const rows=body.map(line=>row(tableCells(line),"td")).join("");return`<table><thead>${row(tableCells(header),"th")}</thead>${rows?`<tbody>${rows}</tbody>`:""}</table>`}function isTableStart(line,next){return line.includes("|")&&next!==void 0&&TABLE_DELIMITER.test(next.trim())&&tableCells(line).length===tableCells(next).length}function markdownToHtml(source,options={}){const gfm=options.gfm===true;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(" "),gfm)}</p>`);paragraph=[]};const flushList=()=>{if(list)blocks.push(`<${list.tag}>${list.items.map(item=>listItem(item,gfm)).join("")}</${list.tag}>`);list=void 0};for(let i=0;i<lines.length;i++){const line=lines[i];const fence=/^\s*(`{3,})\s*([\w#+.-]*)/.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(codeBlock(code.join("\n"),fence[2],options.highlight));continue}if(gfm&&isTableStart(line,lines[i+1])){flushParagraph();flushList();const header=line;const delimiter=lines[i+1];const body=[];for(i+=2;i<lines.length&&lines[i].trim()!==""&&lines[i].includes("|");i++)body.push(lines[i]);i--;blocks.push(table(header,delimiter,body));continue}const heading=/^(#{1,6})\s+(.*)$/.exec(line);if(heading){flushParagraph();flushList();blocks.push(`<h${heading[1].length}>${inline(heading[2].trim(),gfm)}</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 codeBlock(code,language,highlight){if(!highlight)return`<pre><code>${escapeHtml(code)}
|
|
1334
1345
|
</code></pre>`;const highlighted=language?highlight(code,language):void 0;const languageClass=language?` language-${language}`:"";return`<pre><code class="hljs${languageClass}">${highlighted??escapeHtml(code)}
|
|
1335
|
-
</code></pre>`}function loadServerReact(purpose){return{react:requireFromProject("react",purpose),jsxRuntime:requireFromProject("react/jsx-runtime",purpose),server:requireFromProject("react-dom/server",purpose)}}function renderComponentOnServer(component,input,output){const{react,server}=loadServerReact("`ui.uiType: 'react'`");return server.renderToStaticMarkup(react.createElement(component,widgetProps(input,output)))}var PURPOSE2="An MDX template";var compiledTemplates=new Map;async function preloadMdxCompiler(gfm=false){await preloadFromProject("@mdx-js/mdx",PURPOSE2);if(gfm)await preloadFromProject("remark-gfm",`${PURPOSE2} with \`gfm\``)}function compileMdxTemplate(source,gfm=false){const key=`${gfm}:${source}`;const cached=compiledTemplates.get(key);if(cached)return cached;const{compileSync}=requireFromProject("@mdx-js/mdx",PURPOSE2);const remarkPlugins=gfm?[requireFromProject("remark-gfm",`${PURPOSE2} with \`gfm\``).default]:[];const body=String(compileSync(source,{outputFormat:"function-body",development:false,remarkPlugins}));const compiled=new Function("__mdxRuntime","input","output","helpers",body);compiledTemplates.set(key,compiled);return compiled}function renderMdxTemplate(source,options){const compiled=compileMdxTemplate(source,options.gfm);const{react,jsxRuntime,server}=loadServerReact(PURPOSE2);const{default:content}=compiled(jsxRuntime,options.input,options.output,options.helpers);const components={...options.highlighter?{code:highlightedCode(react,options.highlighter)}:{},...options.components};return server.renderToStaticMarkup(react.createElement(content,{components}))}function highlightedCode(react,highlighter){return props=>{const language=/\blanguage-([\w#+.-]+)/.exec(props.className??"")?.[1];const highlighted=language&&typeof props.children==="string"?highlighter.highlight(props.children,language):void 0;if(highlighted===void 0)return react.createElement("code",props);return react.createElement("code",{className:`hljs ${props.className}`,dangerouslySetInnerHTML:{__html:highlighted}})}}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 forcedUiType(options){return options.uiType&&options.uiType!=="auto"?options.uiType:void 0}function resolveUiType(template,options){const forced=forcedUiType(options);if(forced)return forced;return typeof template==="string"&&options.mdxComponents?"mdx":detectUIType(template)}function isFileTemplate(template){return typeof template==="object"&&template!==null&&"file"in template}function isJsxFileTemplate(template){return isFileTemplate(template)&&/\.(tsx|jsx)$/i.test(String(template.file))}function isComponentObjectOrClass(template){if(typeof template==="object"&&template!==null)return"$$typeof"in template;const prototype=typeof template==="function"?template.prototype:void 0;return typeof prototype?.render==="function"||Boolean(prototype?.isReactComponent)}function isComponentReference(template,options){if(isComponentObjectOrClass(template))return true;return typeof template==="function"&&resolveUiType(template,options)==="react"}function describeRenderOptionProblems(template,options){const problems=[];const forced=forcedUiType(options);const uiTypeProblem=forced&&describeUiTypeMismatch(forced,template);if(uiTypeProblem)problems.push(`\`ui.uiType: '${forced}'\` ${uiTypeProblem}`);if(options.contentSecurity!==void 0)problems.push(...describeContentSecurityProblems(options.contentSecurity));if(options.contentSecurity!==void 0&&isFileTemplate(template)){problems.push("`ui.contentSecurity` sanitizes the markup FrontMCP builds on the server, and a `{ file }` widget is rendered in the page, so there is nothing for it to sanitize. Remove it, or use an HTML, Markdown or function template.")}if(options.mdxComponents&&typeof template!=="string"){problems.push(`\`ui.mdxComponents\` is for an MDX template, which is a string, and this template is ${describeTemplate(template)}. A template function's result is never compiled as MDX: it carries the call's data, and compiling it would run that data as code. Write the template as a string and read the data in expressions, such as \`{output.title}\`.`)}else if(options.mdxComponents&&forced&&forced!=="mdx"){problems.push(`\`ui.mdxComponents\` is for an MDX template, and \`ui.uiType\` is '${forced}'.`)}const uiType=resolveUiType(template,options);const convertsMarkdown=uiType==="markdown"&&(typeof template==="string"||typeof template==="function")||uiType==="mdx"&&typeof template==="string";if((options.markdown?.gfm||options.markdown?.highlightTheme)&&!convertsMarkdown){problems.push(`\`ui.runtimeOptions.markdown\` applies to a Markdown template (a string without both \`<\` and \`>\`, or any template with \`uiType: 'markdown'\`) or an MDX template, and this template is ${describeTemplate(template)}. Remove it, or write the template in Markdown.`)}if(options.hydrate&&!isJsxFileTemplate(template)){problems.push(isComponentReference(template,options)?"`ui.hydrate` needs the component's code in the page, and a component reference has no source file to bundle. Use `template: { file: './widget.tsx' }`, or remove `hydrate` and set `uiType: 'react'` to render it on the server only.":`\`ui.hydrate\` hydrates a React widget rendered on the server, a \`{ file }\` .tsx or .jsx widget, and this template is ${uiType==="mdx"?"an MDX template, which renders to static HTML":describeTemplate(template)}.`)}return problems}function describeUiTypeMismatch(uiType,template){if(uiType==="react"){if(typeof template==="function"||isComponentObjectOrClass(template)||isJsxFileTemplate(template))return;return`renders a React component (a component reference, or a \`{ file }\` .tsx or .jsx widget), and this template is ${isFileTemplate(template)?"a `{ file }` that is not a .tsx or .jsx file":describeTemplate(template)}.`}if(uiType==="mdx"){return typeof template==="string"?void 0:`renders an MDX template, which is a string, and this template is ${describeTemplate(template)}.`}if(typeof template==="string"||typeof template==="function"&&!isComponentObjectOrClass(template))return;return`renders a string or a template function, and this template is ${describeTemplate(template)}.`}async function prepareRenderOptions(template,options){const uiType=resolveUiType(template,options);if(options.markdown?.highlightTheme&&(uiType==="markdown"||uiType==="mdx")){loadCodeHighlighter(options.markdown.highlightTheme)}if(uiType==="mdx"&&typeof template==="string"){loadServerReact("An MDX template");await preloadMdxCompiler(options.markdown?.gfm);compileMdxTemplate(template,options.markdown?.gfm)}if(forcedUiType(options)==="react"&&!isFileTemplate(template))loadServerReact("`ui.uiType: 'react'`");if(options.hydrate)loadServerReact("`ui.hydrate`")}function describeTemplate(template){if(typeof template==="string")return detectUIType(template)==="html"?"an HTML string":"a Markdown string";if(isComponentObjectOrClass(template))return"a React component";if(typeof template==="function")return"a function";return isFileTemplate(template)?"a `{ file }` widget":"not a string"}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)}function convertMarkdown(source,options,mdx){const{gfm,highlightTheme}=options.markdown??{};const highlighter=highlightTheme?loadCodeHighlighter(highlightTheme):void 0;const converted=mdx?renderMdxTemplate(source,{input:options.input??{},output:options.output??{},helpers:createTemplateHelpers(),components:options.mdxComponents,gfm,highlighter}):markdownToHtml(source,{gfm,highlight:highlighter?.highlight});return highlighter?`<style>${highlighter.css}</style>
|
|
1346
|
+
</code></pre>`}function loadServerReact(purpose){return{react:requireFromProject("react",purpose),jsxRuntime:requireFromProject("react/jsx-runtime",purpose),server:requireFromProject("react-dom/server",purpose)}}function renderComponentOnServer(component,input,output){const{react,server}=loadServerReact("`ui.uiType: 'react'`");return server.renderToStaticMarkup(react.createElement(component,widgetProps(input,output)))}var PURPOSE2="An MDX template";var compiledTemplates=new Map;async function preloadMdxCompiler(gfm=false){await preloadFromProject("@mdx-js/mdx",PURPOSE2);if(gfm)await preloadFromProject("remark-gfm",`${PURPOSE2} with \`gfm\``)}function compileMdxTemplate(source,gfm=false){const key=`${gfm}:${source}`;const cached=compiledTemplates.get(key);if(cached)return cached;const{compileSync}=requireFromProject("@mdx-js/mdx",PURPOSE2);const remarkPlugins=gfm?[requireFromProject("remark-gfm",`${PURPOSE2} with \`gfm\``).default]:[];const body=String(compileSync(source,{outputFormat:"function-body",development:false,remarkPlugins}));const compiled=new Function("__mdxRuntime","input","output","helpers",body);compiledTemplates.set(key,compiled);return compiled}function renderMdxTemplate(source,options){const compiled=compileMdxTemplate(source,options.gfm);const{react,jsxRuntime,server}=loadServerReact(PURPOSE2);const{default:content}=compiled(jsxRuntime,options.input,options.output,options.helpers);const components={...options.highlighter?{code:highlightedCode(react,options.highlighter)}:{},...options.components};return server.renderToStaticMarkup(react.createElement(content,{components}))}function highlightedCode(react,highlighter){return props=>{const language=/\blanguage-([\w#+.-]+)/.exec(props.className??"")?.[1];const highlighted=language&&typeof props.children==="string"?highlighter.highlight(props.children,language):void 0;if(highlighted===void 0)return react.createElement("code",props);return react.createElement("code",{className:`hljs ${props.className}`,dangerouslySetInnerHTML:{__html:highlighted}})}}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 forcedUiType(options){return options.uiType&&options.uiType!=="auto"?options.uiType:void 0}function resolveUiType(template,options){const forced=forcedUiType(options);if(forced)return forced;return typeof template==="string"&&options.mdxComponents?"mdx":detectUIType(template)}function isFileTemplate(template){return typeof template==="object"&&template!==null&&"file"in template}function isJsxFileTemplate(template){return isFileTemplate(template)&&/\.(tsx|jsx)$/i.test(String(template.file))}function isComponentObjectOrClass(template){if(typeof template==="object"&&template!==null)return"$$typeof"in template;const prototype=typeof template==="function"?template.prototype:void 0;return typeof prototype?.render==="function"||Boolean(prototype?.isReactComponent)}function isComponentReference(template,options){if(isComponentObjectOrClass(template))return true;return typeof template==="function"&&resolveUiType(template,options)==="react"}function describeRenderOptionProblems(template,options){const problems=[];const forced=forcedUiType(options);const uiTypeProblem=forced&&describeUiTypeMismatch(forced,template);if(uiTypeProblem)problems.push(`\`ui.uiType: '${forced}'\` ${uiTypeProblem}`);if(options.contentSecurity!==void 0)problems.push(...describeContentSecurityProblems(options.contentSecurity));if(options.contentSecurity!==void 0&&isFileTemplate(template)){problems.push("`ui.contentSecurity` sanitizes the markup FrontMCP builds on the server, and a `{ file }` widget is rendered in the page, so there is nothing for it to sanitize. Remove it, or use an HTML, Markdown or function template.")}if(options.mdxComponents&&typeof template!=="string"){problems.push(`\`ui.mdxComponents\` is for an MDX template, which is a string, and this template is ${describeTemplate(template)}. A template function's result is never compiled as MDX: it carries the call's data, and compiling it would run that data as code. Write the template as a string and read the data in expressions, such as \`{output.title}\`.`)}else if(options.mdxComponents&&forced&&forced!=="mdx"){problems.push(`\`ui.mdxComponents\` is for an MDX template, and \`ui.uiType\` is '${forced}'.`)}const uiType=resolveUiType(template,options);const convertsMarkdown=uiType==="markdown"&&(typeof template==="string"||typeof template==="function")||uiType==="mdx"&&typeof template==="string";if((options.markdown?.gfm||options.markdown?.highlightTheme)&&!convertsMarkdown){problems.push(`\`ui.runtimeOptions.markdown\` applies to a Markdown template (a string without both \`<\` and \`>\`, or any template with \`uiType: 'markdown'\`) or an MDX template, and this template is ${describeTemplate(template)}. Remove it, or write the template in Markdown.`)}if(options.hydrate&&!isJsxFileTemplate(template)){problems.push(isComponentReference(template,options)?"`ui.hydrate` needs the component's code in the page, and a component reference has no source file to bundle. Use `template: { file: './widget.tsx' }`, or remove `hydrate` and set `uiType: 'react'` to render it on the server only.":`\`ui.hydrate\` hydrates a React widget rendered on the server, a \`{ file }\` .tsx or .jsx widget, and this template is ${uiType==="mdx"?"an MDX template, which renders to static HTML":describeTemplate(template)}.`)}return problems}function describeUiTypeMismatch(uiType,template){if(uiType==="react"){if(typeof template==="function"||isComponentObjectOrClass(template)||isJsxFileTemplate(template))return;return`renders a React component (a component reference, or a \`{ file }\` .tsx or .jsx widget), and this template is ${isFileTemplate(template)?"a `{ file }` that is not a .tsx or .jsx file":describeTemplate(template)}.`}if(uiType==="mdx"){return typeof template==="string"?void 0:`renders an MDX template, which is a string, and this template is ${describeTemplate(template)}.`}if(typeof template==="string"||typeof template==="function"&&!isComponentObjectOrClass(template))return;return`renders a string or a template function, and this template is ${describeTemplate(template)}.`}async function prepareRenderOptions(template,options){const uiType=resolveUiType(template,options);if(options.markdown?.highlightTheme&&(uiType==="markdown"||uiType==="mdx")){loadCodeHighlighter(options.markdown.highlightTheme)}if(uiType==="mdx"&&typeof template==="string"){loadServerReact("An MDX template");await preloadMdxCompiler(options.markdown?.gfm);compileMdxTemplate(template,options.markdown?.gfm)}if(forcedUiType(options)==="react"&&!isFileTemplate(template))loadServerReact("`ui.uiType: 'react'`");if(options.hydrate)loadServerReact("`ui.hydrate`")}function describeTemplate(template){if(typeof template==="string")return detectUIType(template)==="html"?"an HTML string":"a Markdown string";if(isComponentObjectOrClass(template))return"a React component";if(typeof template==="function")return"a function";return isFileTemplate(template)?"a `{ file }` widget":"not a string"}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}`)}var MAX_INDENTED_DEPTH=20;function jsonDepth(json){let depth=0;let deepest=0;let inString=false;for(let index=0;index<json.length;index++){const character=json[index];if(inString){if(character==="\\")index++;else if(character==='"')inString=false}else if(character==='"'){inString=true}else if(character==="["||character==="{"){depth++;deepest=Math.max(deepest,depth)}else if(character==="]"||character==="}"){depth--}}return deepest}function resultJson(value){const compact=JSON.stringify(value);if(compact===void 0||jsonDepth(compact)>MAX_INDENTED_DEPTH)return compact;return JSON.stringify(value,null,2)}function renderUnwrappedResult(rawResult,options){if(isTrustedHtml(rawResult)){return String(rawResult)}if(typeof rawResult!=="string"){return`<pre>${escapeHtml(resultJson(rawResult))}</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)}function convertMarkdown(source,options,mdx){const{gfm,highlightTheme}=options.markdown??{};const highlighter=highlightTheme?loadCodeHighlighter(highlightTheme):void 0;const converted=mdx?renderMdxTemplate(source,{input:options.input??{},output:options.output??{},helpers:createTemplateHelpers(),components:options.mdxComponents,gfm,highlighter}):markdownToHtml(source,{gfm,highlight:highlighter?.highlight});return highlighter?`<style>${highlighter.css}</style>
|
|
1336
1347
|
${converted}`:converted}function secureMarkup(markup,options){return options.contentSecurity===void 0?markup:sanitizeHtml(markup,options.contentSecurity)}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, or set \`ui.uiType: 'react'\` to render it on the server.`)}var COMPILED_JSX_PATTERN=/\b(?:React\.createElement|_?jsx(?:s|DEV)?)\)?\s*\(/;function isComponentReference2(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(!isComponentReference2(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 problems=describeRenderOptionProblems(template,options);if(problems.length>0)throw new Error(`Tool "${toolName}": ${problems.join(" ")}`);const uiType=resolveUiType(template,options);const forced=forcedUiType(options);const isClaude=platformType==="claude"||platformType==="claude-code";const resourceMode=options.resourceMode??(isClaude?"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",hydrate:options.hydrate===true},{...shellConfig,csp:buildCspConfig(resolver,options.csp)});html2=result.html;hash=result.hash;size=result.size}else if(typeof template==="function"&&forced==="react"){const shellResult=buildShell(secureMarkup(renderComponentOnServer(template,input,output),options),shellConfig);html2=shellResult.html;hash=shellResult.hash;size=shellResult.size}else if(typeof template==="function"){const helpers=createTemplateHelpers();const ctx={input:input??{},output:output??{},helpers};let rawResult;let isHtmlBuilder=forced!==void 0||uiType!=="react"||!isDefinitelyReactComponent(template);if(isHtmlBuilder){try{rawResult=template(ctx);isHtmlBuilder=forced!==void 0||!isReactTypedObject(rawResult)}catch(error){if(forced!==void 0||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 if(forced==="markdown"){const markup=typeof rawResult==="string"?convertMarkdown(rawResult,options,false):renderUnwrappedResult(rawResult,options);const shellResult=buildShell(secureMarkup(markup,options),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(secureMarkup(renderUnwrappedResult(rawResult,options),options),shellConfig);html2=shellResult.html;hash=shellResult.hash;size=shellResult.size}}}else if(typeof template==="string"){const markup=uiType==="markdown"||uiType==="mdx"?convertMarkdown(template,options,uiType==="mdx"):template;const shellResult=buildShell(secureMarkup(markup,options),shellConfig);html2=shellResult.html;hash=shellResult.hash;size=shellResult.size}else if(forced==="react"){const shellResult=buildShell(secureMarkup(renderComponentOnServer(template,input,output),options),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=`
|
|
1337
1348
|
${bridgeScript}
|
|
1338
1349
|
<div id="root">
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/adapters/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC9B,sGAAsG;IACtG,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,sGAAsG;IACtG,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CACpE;
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/adapters/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC9B,sGAAsG;IACtG,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,sGAAsG;IACtG,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CACpE;AAuJD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,MAAM,CA4EpF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-renderer.d.ts","sourceRoot":"","sources":["../../src/adapters/template-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAKxD,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAYlD;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,gBAAgB;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,qDAAqD;IACrD,QAAQ,EAAE,OAAO,CAAC;IAClB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAChC;;;;OAIG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,8FAA8F;IAC9F,WAAW,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IACzC;;;OAGG;IACH,GAAG,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAChE;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,yEAAyE;IACzE,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IAC7C;;;;OAIG;IACH,eAAe,CAAC,EAAE,iBAAiB,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,oCAAoC;AACpC,MAAM,WAAW,qBAAqB;IACpC,gCAAgC;IAChC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;
|
|
1
|
+
{"version":3,"file":"template-renderer.d.ts","sourceRoot":"","sources":["../../src/adapters/template-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAKxD,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAYlD;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,gBAAgB;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,qDAAqD;IACrD,QAAQ,EAAE,OAAO,CAAC;IAClB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAChC;;;;OAIG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,8FAA8F;IAC9F,WAAW,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IACzC;;;OAGG;IACH,GAAG,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAChE;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,yEAAyE;IACzE,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IAC7C;;;;OAIG;IACH,eAAe,CAAC,EAAE,iBAAiB,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,oCAAoC;AACpC,MAAM,WAAW,qBAAqB;IACpC,gCAAgC;IAChC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAuJD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,EACjB,MAAM,GAAE;IAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAAY,GACpD,OAAO,CAIT;AAeD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,wBAAwB,CAwJ/F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iife-generator.d.ts","sourceRoot":"","sources":["../../src/bridge-runtime/iife-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAE1D,4FAA4F;AAC5F,eAAO,MAAM,sBAAsB,0CAA2C,CAAC;AAE/E;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,QAAQ,CAAC,EAAE,CAAC,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC,EAAE,CAAC;IACvE,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2CAA2C;IAC3C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,wBAAwB;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,oBAAyB,GAAG,MAAM,CAgH7E;
|
|
1
|
+
{"version":3,"file":"iife-generator.d.ts","sourceRoot":"","sources":["../../src/bridge-runtime/iife-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAE1D,4FAA4F;AAC5F,eAAO,MAAM,sBAAsB,0CAA2C,CAAC;AAE/E;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,QAAQ,CAAC,EAAE,CAAC,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC,EAAE,CAAC;IACvE,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2CAA2C;IAC3C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,wBAAwB;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,oBAAyB,GAAG,MAAM,CAgH7E;AAi0CD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,EACvD,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAM,GACnD,MAAM,CAYR;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,QAAuB,CAAC;AAE5D;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;CAK9B,CAAC"}
|
package/bridge-runtime/index.js
CHANGED
|
@@ -388,6 +388,7 @@ var ExtAppsAdapter = {
|
|
|
388
388
|
});
|
|
389
389
|
},
|
|
390
390
|
handleMessage: function(context, event) {
|
|
391
|
+
if (event.source !== window.parent) return;
|
|
391
392
|
if (!this.isOriginTrusted(event.origin)) return;
|
|
392
393
|
var data = event.data;
|
|
393
394
|
if (!data || typeof data !== 'object' || data.jsonrpc !== '2.0') return;
|
package/component/index.js
CHANGED
|
@@ -456,6 +456,7 @@ var ExtAppsAdapter = {
|
|
|
456
456
|
});
|
|
457
457
|
},
|
|
458
458
|
handleMessage: function(context, event) {
|
|
459
|
+
if (event.source !== window.parent) return;
|
|
459
460
|
if (!this.isOriginTrusted(event.origin)) return;
|
|
460
461
|
var data = event.data;
|
|
461
462
|
if (!data || typeof data !== 'object' || data.jsonrpc !== '2.0') return;
|
package/esm/adapters/index.mjs
CHANGED
|
@@ -397,6 +397,7 @@ var ExtAppsAdapter = {
|
|
|
397
397
|
});
|
|
398
398
|
},
|
|
399
399
|
handleMessage: function(context, event) {
|
|
400
|
+
if (event.source !== window.parent) return;
|
|
400
401
|
if (!this.isOriginTrusted(event.origin)) return;
|
|
401
402
|
var data = event.data;
|
|
402
403
|
if (!data || typeof data !== 'object' || data.jsonrpc !== '2.0') return;
|
|
@@ -1299,7 +1300,7 @@ if (__root) {
|
|
|
1299
1300
|
React.createElement(${componentName})
|
|
1300
1301
|
)
|
|
1301
1302
|
);
|
|
1302
|
-
}`}import{decodeHTMLAttribute}from"entities";var CSS_ESCAPE=/\\(?:([0-9a-fA-F]{1,6})[ \t\n\r\f]?|([^\n\r\f0-9a-fA-F]))/g;var CSS_COMMENT=/\/\*[\s\S]*?(?:\*\/|$)/g;function unescapeCss(text){return text.replace(CSS_ESCAPE,(_match,hex,character)=>{if(hex===void 0)return character??"";const codePoint=parseInt(hex,16);const valid=codePoint>0&&codePoint<=1114111&&(codePoint<55296||codePoint>57343);return valid?String.fromCodePoint(codePoint):"\uFFFD"})}function sanitizeStyleText(css){return removeImports(css.replace(/</g,"\\3c ").replace(/&(?=[#A-Za-z0-9])/g,"\\26 "))}function removeImports(css){const kept=[];let start=0;let index=css.indexOf("@");while(index!==-1){const nameEnd=identEnd(css,index+1);if(unescapeCss(css.slice(index+1,nameEnd)).toLowerCase()==="import"){kept.push(css.slice(start,index)," ");start=statementEnd(css,nameEnd);index=css.indexOf("@",start)}else{index=css.indexOf("@",index+1)}}kept.push(css.slice(start));return kept.join("")}function commentEnd(css,start){const end=css.indexOf("*/",start+2);return end===-1?css.length:end+2}function stringEnd(css,start){const quote=css[start];let index=start+1;while(index<css.length&&css[index]!==quote&&css[index]!=="\n"){index+=css[index]==="\\"?2:1}return Math.min(index+1,css.length)}function isIdentCharacter(character){return character==="-"||/\w/.test(character)||character.charCodeAt(0)>=128}function identEnd(css,start){let index=start;while(index<css.length){if(css[index]==="\\"&&css[index+1]!==void 0&&css[index+1]!=="\n"){index+=2}else if(isIdentCharacter(css[index])){index++}else{break}}return index}function statementEnd(css,start){let depth=0;let index=start;while(index<css.length){const character=css[index];if(character==="/"&&css[index+1]==="*"){index=commentEnd(css,index);continue}if(character==='"'||character==="'"){index=stringEnd(css,index);continue}if(character==="("||character==="["||character==="{")depth++;if(character===")"||character==="]")depth=Math.max(0,depth-1);if(character==="}"){if(depth===0)return index;depth--;if(depth===0)return index+1}if(character===";"&&depth===0)return index+1;index++}return css.length}function sanitizeStyleAttribute(style){const declarations=splitDeclarations(style);const kept=declarations.filter(declaration=>!isFixedPosition(declaration));return kept.length===declarations.length?style:kept.join(";")}function splitDeclarations(style){const declarations=[];let depth=0;let start=0;let index=0;while(index<style.length){const character=style[index];if(character==="/"&&style[index+1]==="*"){index=commentEnd(style,index);continue}if(character==='"'||character==="'"){index=stringEnd(style,index);continue}if(character==="(")depth++;if(character===")")depth=Math.max(0,depth-1);if(character===";"&&depth===0){declarations.push(style.slice(start,index));start=index+1}index++}declarations.push(style.slice(start));return declarations}function isFixedPosition(declaration){const text=declaration.replace(CSS_COMMENT,"");const colon=text.indexOf(":");if(colon===-1)return false;const property=unescapeCss(text.slice(0,colon)).trim().toLowerCase();const value=unescapeCss(text.slice(colon+1)).toLowerCase();return property==="position"&&/fixed|sticky|var\(/.test(value)}var DEFAULT_MAX_MARKUP_LENGTH=2*1024*1024;var POLICY_FLAGS=["allowUnsafeLinks","allowInlineScripts","allowToolCallAttributes","bypassSanitization"];var WHITESPACE=/[\t\n\f\r ]/;var TAG_NAME=/^[A-Za-z][A-Za-z0-9-]*$/;var ATTRIBUTE_NAME_BREAKERS=/[\s"'<>/=]/;var COMMENT_END=/--!?>/g;var RAW_TEXT_CONTENT={script:content=>content,style:sanitizeStyleText,textarea:content=>content.replace(/</g,"<"),title:content=>content.replace(/</g,"<"),xmp:content=>content.replace(/</g,"<"),iframe:()=>"",noembed:()=>"",noframes:()=>"",noscript:()=>""};var RAW_TEXT_END=Object.fromEntries(Object.keys(RAW_TEXT_CONTENT).map(name=>[name,new RegExp(`</${name}(?=[\\t\\n\\f\\r />])`,"gi")]));var DROPPED_TAGS=new Set(["base","meta","object","embed","applet","animate","animatecolor","animatemotion","animatetransform","set"]);var URL_ATTRIBUTES=new Set(["href","xlink:href","src","action","formaction","poster","background","cite","data","codebase","classid","archive","longdesc","lowsrc","dynsrc","manifest","icon","profile"]);var URL_LIST_ATTRIBUTES=new Set(["srcset","imagesrcset","ping"]);var SCRIPT_SOURCE_ATTRIBUTES=new Set(["src","href","xlink:href"]);var TOOL_CALL_ATTRIBUTES=new Set(["data-tool-call","data-tool-args"]);var NAVIGATION_ATTRIBUTES={a:new Set(["href","xlink:href"]),area:new Set(["href","xlink:href"]),form:new Set(["action"]),button:new Set(["formaction"]),input:new Set(["formaction"])};var SAFE_SCHEMES=new Set(["http","https","mailto"]);var RASTER_IMAGE_DATA_URL=/^data:image\/(png|gif|jpeg|webp|avif)[;,]/i;var URL_SCHEME=/^([A-Za-z][A-Za-z0-9+.-]*):/;function sanitizeHtml(markup,policy={}){const problems=describeContentSecurityProblems(policy);if(problems.length>0)throw new TypeError(problems.join(" "));if(policy.bypassSanitization)return markup;const maxLength=policy.maxMarkupLength??DEFAULT_MAX_MARKUP_LENGTH;if(markup.length>maxLength){throw new RangeError(`The markup is ${markup.length} characters, over the ${maxLength} that \`ui.contentSecurity\` sanitizes (\`maxMarkupLength\`), so it is not rendered.`)}const output=[];let index=0;while(index<markup.length){const open=markup.indexOf("<",index);if(open===-1){output.push(markup.slice(index));break}output.push(markup.slice(index,open));const next=markup[open+1]??"";if(next==="!"||next==="?"){index=skipDeclaration(markup,open)}else if(next==="/"){index=writeEndTag(markup,open,output)}else if(isAsciiLetter(next)){index=writeElement(markup,open,output,policy)}else{output.push("<");index=open+1}}return output.join("")}function describeContentSecurityProblems(policy){if(!isPlainObject(policy)){return[`\`ui.contentSecurity\` must be an object of flags, and it is ${describeValue(policy)}.`]}const problems=[];for(const[key,value]of Object.entries(policy)){if(value===void 0)continue;if(POLICY_FLAGS.includes(key)){if(typeof value!=="boolean"){problems.push(`\`ui.contentSecurity.${key}\` must be true or false, and it is ${describeValue(value)}.`)}}else if(key==="maxMarkupLength"){if(!Number.isSafeInteger(value)||value<=0){problems.push(`\`ui.contentSecurity.maxMarkupLength\` must be a positive integer, and it is ${describeValue(value)}.`)}}else{problems.push(`\`ui.contentSecurity\` has no \`${key}\` option; its options are \`${POLICY_FLAGS.join("`, `")}\` and \`maxMarkupLength\`.`)}}return problems}function isPlainObject(value){if(typeof value!=="object"||value===null)return false;const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}function describeValue(value){if(value===null||Array.isArray(value))return JSON.stringify(value);return typeof value==="object"||typeof value==="function"?`a ${typeof value}`:`${typeof value} ${JSON.stringify(value)}`}function isAsciiLetter(character){return/^[A-Za-z]$/.test(character)}function asciiLowerCase(text){return text.replace(/[A-Z]/g,letter=>letter.toLowerCase())}function skipDeclaration(markup,open){if(markup.startsWith("<!--",open)){COMMENT_END.lastIndex=open+2;const close2=COMMENT_END.exec(markup);return close2?close2.index+close2[0].length:markup.length}const close=markup.indexOf(">",open);return close===-1?markup.length:close+1}function writeEndTag(markup,open,output){if(!isAsciiLetter(markup[open+2]??"")){return markup.startsWith("</>",open)?open+3:skipDeclaration(markup,open)}const tag=parseTag(markup,open+2);if(!tag)return markup.length;if(TAG_NAME.test(tag.name)&&!DROPPED_TAGS.has(asciiLowerCase(tag.name)))output.push(`</${tag.name}>`);return tag.end}function writeElement(markup,open,output,policy){const tag=parseTag(markup,open+1);if(!tag)return markup.length;const name=asciiLowerCase(tag.name);if(name==="plaintext"){output.push(markup.slice(tag.end).replace(/</g,"<"));return markup.length}const keepContent=RAW_TEXT_CONTENT[name];if(keepContent){const{content,end}=readRawText(markup,tag.end,name);if(name==="script"&&!isAllowedScript(tag,policy))return end;output.push(`<${tag.name}${writeAttributes(name,tag.attributes,policy)}>${keepContent(content)}</${tag.name}>`);return end}if(TAG_NAME.test(tag.name)&&!DROPPED_TAGS.has(name)&&!isCrossOriginStylesheet(name,tag.attributes)){output.push(`<${tag.name}${writeAttributes(name,tag.attributes,policy)}${tag.selfClosing?" /":""}>`)}return tag.end}function isAllowedScript(tag,policy){return policy.allowInlineScripts===true&&!tag.attributes.some(({name})=>SCRIPT_SOURCE_ATTRIBUTES.has(asciiLowerCase(name)))}function isCrossOriginStylesheet(tagName,attributes){if(tagName!=="link")return false;const rel=attributeValue(attributes,"rel");const href=attributeValue(attributes,"href");if(rel===void 0||href===void 0||!/(^|[\t\n\f\r ])stylesheet($|[\t\n\f\r ])/i.test(rel))return false;const url=urlAsParsed(href);return URL_SCHEME.test(url)||/^[\\/]{2}/.test(url)}function attributeValue(attributes,name){const attribute=attributes.find(candidate=>asciiLowerCase(candidate.name)===name);return attribute?.value===void 0?void 0:decodeAttributeValue(attribute.value)}function readRawText(markup,start,name){const endTag=RAW_TEXT_END[name];endTag.lastIndex=start;const match=endTag.exec(markup);if(!match)return{content:markup.slice(start),end:markup.length};const tag=parseTag(markup,match.index+2);return{content:markup.slice(start,match.index),end:tag?tag.end:markup.length}}function parseTag(markup,start){let index=start;while(index<markup.length&&!/[\t\n\f\r />]/.test(markup[index]))index++;const tag={name:markup.slice(start,index),attributes:[],selfClosing:false,end:0};while(index<markup.length){const character=markup[index];if(WHITESPACE.test(character)){index++}else if(character===">"){tag.end=index+1;return tag}else if(character==="/"){index++;if(markup[index]===">"){tag.selfClosing=true;tag.end=index+1;return tag}}else{index=readAttribute(markup,index,tag.attributes)}}return void 0}function readAttribute(markup,start,attributes){let index=start+1;while(index<markup.length&&!/[\t\n\f\r />=]/.test(markup[index]))index++;const attribute={name:markup.slice(start,index),value:void 0};attributes.push(attribute);let afterName=index;while(afterName<markup.length&&WHITESPACE.test(markup[afterName]))afterName++;if(markup[afterName]!=="=")return afterName;index=afterName+1;while(index<markup.length&&WHITESPACE.test(markup[index]))index++;const quote=markup[index];if(quote==='"'||quote==="'"){const close=markup.indexOf(quote,index+1);if(close===-1)return markup.length;attribute.value=markup.slice(index+1,close);return close+1}if(quote===">"){attribute.value="";return index}const valueStart=index;while(index<markup.length&&!/[\t\n\f\r >]/.test(markup[index]))index++;attribute.value=markup.slice(valueStart,index);return index}function decodeAttributeValue(raw){return decodeHTMLAttribute(raw).split("\0").join("\uFFFD")}function escapeAttributeValue(value){return value.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function writeAttributes(tagName,attributes,policy){const seen=new Set;let written="";for(const attribute of attributes){const name=asciiLowerCase(attribute.name);if(seen.has(name))continue;seen.add(name);if(!isWritableAttributeName(attribute.name)||name==="srcdoc")continue;if(name.startsWith("on")&&!policy.allowInlineScripts)continue;if(TOOL_CALL_ATTRIBUTES.has(name)&&!policy.allowToolCallAttributes)continue;if(attribute.value===void 0){written+=` ${attribute.name}`;continue}const value=decodeAttributeValue(attribute.value);if(!isAllowedValue(tagName,name,value,policy))continue;written+=` ${attribute.name}="${escapeAttributeValue(name==="style"?sanitizeStyleAttribute(value):value)}"`}return written}function isWritableAttributeName(name){if(name.length===0||ATTRIBUTE_NAME_BREAKERS.test(name))return false;return[...name].every(character=>character.charCodeAt(0)>31&&character.charCodeAt(0)!==127)}function isAllowedValue(tagName,attributeName,value,policy){if(URL_ATTRIBUTES.has(attributeName)){return isAllowedUrl(value,{imageData:tagName==="img"&&attributeName==="src",navigation:policy.allowUnsafeLinks===true&&NAVIGATION_ATTRIBUTES[tagName]?.has(attributeName)===true})}if(URL_LIST_ATTRIBUTES.has(attributeName)){const separator=attributeName==="ping"?/\s+/:/,/;return value.split(separator).every(candidate=>isAllowedUrl(candidate.trim().split(/\s+/)[0]??"",{}))}return true}function urlAsParsed(value){const url=value.replace(/[\t\n\r]/g,"");let start=0;while(start<url.length&&(url.charCodeAt(start)<=32||/\s/.test(url[start])))start++;return url.slice(start)}function isAllowedUrl(value,allowed){const url=urlAsParsed(value);const scheme=URL_SCHEME.exec(url)?.[1].toLowerCase();if(scheme===void 0||SAFE_SCHEMES.has(scheme))return true;if(scheme==="data")return allowed.imageData===true&&RASTER_IMAGE_DATA_URL.test(url);return allowed.navigation===true}function projectRequires(){const{createRequire}=process.getBuiltinModule("node:module");const path=process.getBuiltinModule("node:path");const bases=[process.cwd()];if(process.argv[1])bases.push(path.dirname(process.argv[1]));return bases.map(base=>createRequire(path.join(base,"package.json")))}function packageName(specifier){const parts=specifier.split("/");return specifier.startsWith("@")?parts.slice(0,2).join("/"):parts[0]}function isNotFound(error,specifier){const{code,message}=error??{};return(code==="MODULE_NOT_FOUND"||code==="ERR_MODULE_NOT_FOUND")&&typeof message==="string"&&message.includes(`'${packageName(specifier)}`)}function fromProject(specifier,purpose,use){let notFound;for(const projectRequire of projectRequires()){try{return use(projectRequire)}catch(error){if(!isNotFound(error,specifier))throw error;notFound=error}}const name=packageName(specifier);throw new Error(`${purpose} needs ${name}, which is not installed. Install it where the server runs: \`npm install ${name}\`.`,{cause:notFound})}var preloaded=new Map;function requireFromProject(specifier,purpose){if(preloaded.has(specifier))return preloaded.get(specifier);return fromProject(specifier,purpose,projectRequire=>projectRequire(specifier))}async function preloadFromProject(specifier,purpose){if(preloaded.has(specifier))return;const{pathToFileURL}=process.getBuiltinModule("node:url");const url=pathToFileURL(resolveFromProject(specifier,purpose)).href;let loaded;try{loaded=await import(url)}catch{loaded=requireFromProject(specifier,purpose)}preloaded.set(specifier,loaded)}function resolveFromProject(specifier,purpose){return fromProject(specifier,purpose,projectRequire=>projectRequire.resolve(specifier))}var PURPOSE="`ui.runtimeOptions.markdown.highlightTheme`";var THEME_NAME=/^[a-z0-9-]+(\/[a-z0-9-]+)?$/i;var highlighters=new Map;function loadCodeHighlighter(theme){const loaded=highlighters.get(theme);if(loaded)return loaded;const hljs=requireFromProject("highlight.js",PURPOSE);const highlighter={highlight:(code,language)=>hljs.getLanguage(language)?hljs.highlight(code,{language,ignoreIllegals:true}).value:void 0,css:readTheme(theme)};highlighters.set(theme,highlighter);return highlighter}function readTheme(theme){const fs=__require("fs");const path=__require("path");const styles=path.join(path.dirname(resolveFromProject("highlight.js/package.json",PURPOSE)),"styles");const file=path.join(styles,`${theme}.min.css`);if(!THEME_NAME.test(theme)||!fs.existsSync(file)){throw new Error(`${PURPOSE} is ${JSON.stringify(theme)}, which is not a highlight.js theme: name a stylesheet in highlight.js/styles without its extension, such as "github", "github-dark" or "base16/dracula".`)}return fs.readFileSync(file,"utf-8")}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=`
|
|
1303
|
+
}`}import{decodeHTMLAttribute}from"entities";var CSS_ESCAPE=/\\(?:([0-9a-fA-F]{1,6})(?:\r\n|[ \t\n\r\f])?|([^\n\r\f0-9a-fA-F]))/g;var CSS_ESCAPE_AT=new RegExp(CSS_ESCAPE.source,"y");var CSS_COMMENT=/\/\*[\s\S]*?(?:\*\/|$)/g;function unescapeCss(text){return text.replace(CSS_ESCAPE,(_match,hex,character)=>{if(hex===void 0)return character??"";const codePoint=parseInt(hex,16);const valid=codePoint>0&&codePoint<=1114111&&(codePoint<55296||codePoint>57343);return valid?String.fromCodePoint(codePoint):"\uFFFD"})}function sanitizeStyleText(css){return removeImports(css.replace(/</g,"\\3c ").replace(/&(?=[#A-Za-z0-9])/g,"\\26 "))}function removeImports(css){const kept=[];let start=0;let index=css.indexOf("@");while(index!==-1){const nameEnd=identEnd(css,index+1);if(unescapeCss(css.slice(index+1,nameEnd)).toLowerCase()==="import"){kept.push(css.slice(start,index)," ");start=statementEnd(css,nameEnd);index=css.indexOf("@",start)}else{index=css.indexOf("@",index+1)}}kept.push(css.slice(start));return kept.join("")}function commentEnd(css,start){const end=css.indexOf("*/",start+2);return end===-1?css.length:end+2}function stringEnd(css,start){const quote=css[start];let index=start+1;while(index<css.length&&css[index]!==quote&&css[index]!=="\n"){index+=css[index]==="\\"?2:1}return Math.min(index+1,css.length)}function isIdentCharacter(character){return character==="-"||/\w/.test(character)||character.charCodeAt(0)>=128}function identEnd(css,start){let index=start;while(index<css.length){CSS_ESCAPE_AT.lastIndex=index;if(CSS_ESCAPE_AT.test(css)){index=CSS_ESCAPE_AT.lastIndex}else if(isIdentCharacter(css[index])){index++}else{break}}return index}function statementEnd(css,start){let depth=0;let index=start;while(index<css.length){const character=css[index];if(character==="/"&&css[index+1]==="*"){index=commentEnd(css,index);continue}if(character==='"'||character==="'"){index=stringEnd(css,index);continue}if(character==="("||character==="["||character==="{")depth++;if(character===")"||character==="]")depth=Math.max(0,depth-1);if(character==="}"){if(depth===0)return index;depth--;if(depth===0)return index+1}if(character===";"&&depth===0)return index+1;index++}return css.length}function sanitizeStyleAttribute(style){const declarations=splitDeclarations(style);const kept=declarations.filter(declaration=>!isFixedPosition(declaration));return kept.length===declarations.length?style:kept.join(";")}function splitDeclarations(style){const declarations=[];let depth=0;let start=0;let index=0;while(index<style.length){const character=style[index];if(character==="/"&&style[index+1]==="*"){index=commentEnd(style,index);continue}if(character==='"'||character==="'"){index=stringEnd(style,index);continue}if(character==="(")depth++;if(character===")")depth=Math.max(0,depth-1);if(character===";"&&depth===0){declarations.push(style.slice(start,index));start=index+1}index++}declarations.push(style.slice(start));return declarations}function isFixedPosition(declaration){const text=declaration.replace(CSS_COMMENT,"");const colon=text.indexOf(":");if(colon===-1)return false;const property=unescapeCss(text.slice(0,colon)).trim().toLowerCase();const value=unescapeCss(text.slice(colon+1)).toLowerCase();return property==="position"&&/fixed|sticky|var\(/.test(value)}var DEFAULT_MAX_MARKUP_LENGTH=2*1024*1024;var POLICY_FLAGS=["allowUnsafeLinks","allowInlineScripts","allowToolCallAttributes","bypassSanitization"];var WHITESPACE=/[\t\n\f\r ]/;var TAG_NAME=/^[A-Za-z][A-Za-z0-9-]*$/;var ATTRIBUTE_NAME_BREAKERS=/[\s"'<>/=]/;var COMMENT_END=/--!?>/g;var RAW_TEXT_CONTENT={script:content=>content,style:sanitizeStyleText,textarea:content=>content.replace(/</g,"<"),title:content=>content.replace(/</g,"<"),xmp:content=>content.replace(/</g,"<"),iframe:()=>"",noembed:()=>"",noframes:()=>"",noscript:()=>""};var RAW_TEXT_END=Object.fromEntries(Object.keys(RAW_TEXT_CONTENT).map(name=>[name,new RegExp(`</${name}(?=[\\t\\n\\f\\r />])`,"gi")]));var DROPPED_TAGS=new Set(["base","meta","object","embed","applet","animate","animatecolor","animatemotion","animatetransform","set"]);var URL_ATTRIBUTES=new Set(["href","xlink:href","src","action","formaction","poster","background","cite","data","codebase","classid","archive","longdesc","lowsrc","dynsrc","manifest","icon","profile"]);var URL_LIST_ATTRIBUTES=new Set(["srcset","imagesrcset","ping"]);var SCRIPT_SOURCE_ATTRIBUTES=new Set(["src","href","xlink:href"]);var TOOL_CALL_ATTRIBUTES=new Set(["data-tool-call","data-tool-args"]);var NAVIGATION_ATTRIBUTES={a:new Set(["href","xlink:href"]),area:new Set(["href","xlink:href"]),form:new Set(["action"]),button:new Set(["formaction"]),input:new Set(["formaction"])};var SAFE_SCHEMES=new Set(["http","https","mailto"]);var RASTER_IMAGE_DATA_URL=/^data:image\/(png|gif|jpeg|webp|avif)[;,]/i;var URL_SCHEME=/^([A-Za-z][A-Za-z0-9+.-]*):/;function sanitizeHtml(markup,policy={}){const problems=describeContentSecurityProblems(policy);if(problems.length>0)throw new TypeError(problems.join(" "));if(policy.bypassSanitization)return markup;const maxLength=policy.maxMarkupLength??DEFAULT_MAX_MARKUP_LENGTH;if(markup.length>maxLength){throw new RangeError(`The markup is ${markup.length} characters, over the ${maxLength} that \`ui.contentSecurity\` sanitizes (\`maxMarkupLength\`), so it is not rendered.`)}const output=[];let index=0;while(index<markup.length){const open=markup.indexOf("<",index);if(open===-1){output.push(markup.slice(index));break}output.push(markup.slice(index,open));const next=markup[open+1]??"";if(next==="!"||next==="?"){index=skipDeclaration(markup,open)}else if(next==="/"){index=writeEndTag(markup,open,output)}else if(isAsciiLetter(next)){index=writeElement(markup,open,output,policy)}else{output.push("<");index=open+1}}return output.join("")}function describeContentSecurityProblems(policy){if(!isPlainObject(policy)){return[`\`ui.contentSecurity\` must be an object of flags, and it is ${describeValue(policy)}.`]}const problems=[];for(const[key,value]of Object.entries(policy)){if(value===void 0)continue;if(POLICY_FLAGS.includes(key)){if(typeof value!=="boolean"){problems.push(`\`ui.contentSecurity.${key}\` must be true or false, and it is ${describeValue(value)}.`)}}else if(key==="maxMarkupLength"){if(!Number.isSafeInteger(value)||value<=0){problems.push(`\`ui.contentSecurity.maxMarkupLength\` must be a positive integer, and it is ${describeValue(value)}.`)}}else{problems.push(`\`ui.contentSecurity\` has no \`${key}\` option; its options are \`${POLICY_FLAGS.join("`, `")}\` and \`maxMarkupLength\`.`)}}return problems}function isPlainObject(value){if(typeof value!=="object"||value===null)return false;const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}function describeValue(value){if(value===null||Array.isArray(value))return JSON.stringify(value);return typeof value==="object"||typeof value==="function"?`a ${typeof value}`:`${typeof value} ${JSON.stringify(value)}`}function isAsciiLetter(character){return/^[A-Za-z]$/.test(character)}function asciiLowerCase(text){return text.replace(/[A-Z]/g,letter=>letter.toLowerCase())}function skipDeclaration(markup,open){if(markup.startsWith("<!--",open)){COMMENT_END.lastIndex=open+2;const close2=COMMENT_END.exec(markup);return close2?close2.index+close2[0].length:markup.length}const close=markup.indexOf(">",open);return close===-1?markup.length:close+1}function writeEndTag(markup,open,output){if(!isAsciiLetter(markup[open+2]??"")){return markup.startsWith("</>",open)?open+3:skipDeclaration(markup,open)}const tag=parseTag(markup,open+2);if(!tag)return markup.length;if(TAG_NAME.test(tag.name)&&!DROPPED_TAGS.has(asciiLowerCase(tag.name)))output.push(`</${tag.name}>`);return tag.end}function writeElement(markup,open,output,policy){const tag=parseTag(markup,open+1);if(!tag)return markup.length;const name=asciiLowerCase(tag.name);if(name==="plaintext"){output.push(markup.slice(tag.end).replace(/</g,"<"));return markup.length}const keepContent=RAW_TEXT_CONTENT[name];if(keepContent){const{content,end}=readRawText(markup,tag.end,name);if(name==="script"&&!isAllowedScript(tag,policy))return end;output.push(`<${tag.name}${writeAttributes(name,tag.attributes,policy)}>${keepContent(content)}</${tag.name}>`);return end}if(TAG_NAME.test(tag.name)&&!DROPPED_TAGS.has(name)&&!isCrossOriginStylesheet(name,tag.attributes)){output.push(`<${tag.name}${writeAttributes(name,tag.attributes,policy)}${tag.selfClosing?" /":""}>`)}return tag.end}function isAllowedScript(tag,policy){return policy.allowInlineScripts===true&&!tag.attributes.some(({name})=>SCRIPT_SOURCE_ATTRIBUTES.has(asciiLowerCase(name)))}function isCrossOriginStylesheet(tagName,attributes){if(tagName!=="link")return false;const rel=attributeValue(attributes,"rel");const href=attributeValue(attributes,"href");if(rel===void 0||href===void 0||!/(^|[\t\n\f\r ])stylesheet($|[\t\n\f\r ])/i.test(rel))return false;const url=urlAsParsed(href);return URL_SCHEME.test(url)||/^[\\/]{2}/.test(url)}function attributeValue(attributes,name){const attribute=attributes.find(candidate=>asciiLowerCase(candidate.name)===name);return attribute?.value===void 0?void 0:decodeAttributeValue(attribute.value)}function readRawText(markup,start,name){const endTag=RAW_TEXT_END[name];endTag.lastIndex=start;const match=endTag.exec(markup);if(!match)return{content:markup.slice(start),end:markup.length};const tag=parseTag(markup,match.index+2);return{content:markup.slice(start,match.index),end:tag?tag.end:markup.length}}function parseTag(markup,start){let index=start;while(index<markup.length&&!/[\t\n\f\r />]/.test(markup[index]))index++;const tag={name:markup.slice(start,index),attributes:[],selfClosing:false,end:0};while(index<markup.length){const character=markup[index];if(WHITESPACE.test(character)){index++}else if(character===">"){tag.end=index+1;return tag}else if(character==="/"){index++;if(markup[index]===">"){tag.selfClosing=true;tag.end=index+1;return tag}}else{index=readAttribute(markup,index,tag.attributes)}}return void 0}function readAttribute(markup,start,attributes){let index=start+1;while(index<markup.length&&!/[\t\n\f\r />=]/.test(markup[index]))index++;const attribute={name:markup.slice(start,index),value:void 0};attributes.push(attribute);let afterName=index;while(afterName<markup.length&&WHITESPACE.test(markup[afterName]))afterName++;if(markup[afterName]!=="=")return afterName;index=afterName+1;while(index<markup.length&&WHITESPACE.test(markup[index]))index++;const quote=markup[index];if(quote==='"'||quote==="'"){const close=markup.indexOf(quote,index+1);if(close===-1)return markup.length;attribute.value=markup.slice(index+1,close);return close+1}if(quote===">"){attribute.value="";return index}const valueStart=index;while(index<markup.length&&!/[\t\n\f\r >]/.test(markup[index]))index++;attribute.value=markup.slice(valueStart,index);return index}function decodeAttributeValue(raw){return decodeHTMLAttribute(raw).split("\0").join("\uFFFD")}function escapeAttributeValue(value){return value.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function writeAttributes(tagName,attributes,policy){const seen=new Set;let written="";for(const attribute of attributes){const name=asciiLowerCase(attribute.name);if(seen.has(name))continue;seen.add(name);if(!isWritableAttributeName(attribute.name)||name==="srcdoc")continue;if(name.startsWith("on")&&!policy.allowInlineScripts)continue;if(TOOL_CALL_ATTRIBUTES.has(name)&&!policy.allowToolCallAttributes)continue;if(attribute.value===void 0){written+=` ${attribute.name}`;continue}const value=decodeAttributeValue(attribute.value);if(!isAllowedValue(tagName,name,value,policy))continue;written+=` ${attribute.name}="${escapeAttributeValue(name==="style"?sanitizeStyleAttribute(value):value)}"`}return written}function isWritableAttributeName(name){if(name.length===0||ATTRIBUTE_NAME_BREAKERS.test(name))return false;return[...name].every(character=>character.charCodeAt(0)>31&&character.charCodeAt(0)!==127)}function isAllowedValue(tagName,attributeName,value,policy){if(URL_ATTRIBUTES.has(attributeName)){return isAllowedUrl(value,{imageData:tagName==="img"&&attributeName==="src",navigation:policy.allowUnsafeLinks===true&&NAVIGATION_ATTRIBUTES[tagName]?.has(attributeName)===true})}if(URL_LIST_ATTRIBUTES.has(attributeName)){const separator=attributeName==="ping"?/\s+/:/,/;return value.split(separator).every(candidate=>isAllowedUrl(candidate.trim().split(/\s+/)[0]??"",{}))}return true}function urlAsParsed(value){const url=value.replace(/[\t\n\r]/g,"");let start=0;while(start<url.length&&(url.charCodeAt(start)<=32||/\s/.test(url[start])))start++;return url.slice(start)}function isAllowedUrl(value,allowed){const url=urlAsParsed(value);const scheme=URL_SCHEME.exec(url)?.[1].toLowerCase();if(scheme===void 0||SAFE_SCHEMES.has(scheme))return true;if(scheme==="data")return allowed.imageData===true&&RASTER_IMAGE_DATA_URL.test(url);return allowed.navigation===true}function projectRequires(){const{createRequire}=process.getBuiltinModule("node:module");const path=process.getBuiltinModule("node:path");const bases=[process.cwd()];if(process.argv[1])bases.push(path.dirname(process.argv[1]));return bases.map(base=>createRequire(path.join(base,"package.json")))}function packageName(specifier){const parts=specifier.split("/");return specifier.startsWith("@")?parts.slice(0,2).join("/"):parts[0]}function isNotFound(error,specifier){const{code,message}=error??{};return(code==="MODULE_NOT_FOUND"||code==="ERR_MODULE_NOT_FOUND")&&typeof message==="string"&&message.includes(`'${packageName(specifier)}`)}function fromProject(specifier,purpose,use){let notFound;for(const projectRequire of projectRequires()){try{return use(projectRequire)}catch(error){if(!isNotFound(error,specifier))throw error;notFound=error}}const name=packageName(specifier);throw new Error(`${purpose} needs ${name}, which is not installed. Install it where the server runs: \`npm install ${name}\`.`,{cause:notFound})}var preloaded=new Map;function requireFromProject(specifier,purpose){if(preloaded.has(specifier))return preloaded.get(specifier);return fromProject(specifier,purpose,projectRequire=>projectRequire(specifier))}async function preloadFromProject(specifier,purpose){if(preloaded.has(specifier))return;const{pathToFileURL}=process.getBuiltinModule("node:url");const url=pathToFileURL(resolveFromProject(specifier,purpose)).href;let loaded;try{loaded=await import(url)}catch{loaded=requireFromProject(specifier,purpose)}preloaded.set(specifier,loaded)}function resolveFromProject(specifier,purpose){return fromProject(specifier,purpose,projectRequire=>projectRequire.resolve(specifier))}var PURPOSE="`ui.runtimeOptions.markdown.highlightTheme`";var THEME_NAME=/^[a-z0-9-]+(\/[a-z0-9-]+)?$/i;var highlighters=new Map;function loadCodeHighlighter(theme){const loaded=highlighters.get(theme);if(loaded)return loaded;const hljs=requireFromProject("highlight.js",PURPOSE);const highlighter={highlight:(code,language)=>hljs.getLanguage(language)?hljs.highlight(code,{language,ignoreIllegals:true}).value:void 0,css:readTheme(theme)};highlighters.set(theme,highlighter);return highlighter}function readTheme(theme){const fs=__require("fs");const path=__require("path");const styles=path.join(path.dirname(resolveFromProject("highlight.js/package.json",PURPOSE)),"styles");const file=path.join(styles,`${theme}.min.css`);if(!THEME_NAME.test(theme)||!fs.existsSync(file)){throw new Error(`${PURPOSE} is ${JSON.stringify(theme)}, which is not a highlight.js theme: name a stylesheet in highlight.js/styles without its extension, such as "github", "github-dark" or "base16/dracula".`)}return fs.readFileSync(file,"utf-8")}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";var PDF_MAX_PAGE_PIXELS=2**24;var PDF_MAX_TOTAL_PIXELS=2**27;function buildChartHtml(chartJson){const chartData=safeJsonForScript(chartJson);const content=`
|
|
1303
1304
|
<canvas id="chart" style="max-width:100%;max-height:80vh;"></canvas>
|
|
1304
1305
|
<script type="module">
|
|
1305
1306
|
import Chart from '${CHART_JS_CDN}';
|
|
@@ -1323,9 +1324,19 @@ for (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i);
|
|
|
1323
1324
|
|
|
1324
1325
|
const pdf = await pdfjsLib.getDocument({ data: bytes }).promise;
|
|
1325
1326
|
const container = document.getElementById('pdf-container');
|
|
1327
|
+
let pixelsLeft = ${PDF_MAX_TOTAL_PIXELS};
|
|
1326
1328
|
for (let i = 1; i <= pdf.numPages; i++) {
|
|
1327
1329
|
const page = await pdf.getPage(i);
|
|
1328
|
-
const
|
|
1330
|
+
const unscaled = page.getViewport({ scale: 1 });
|
|
1331
|
+
const scale = Math.min(1.5, Math.sqrt(${PDF_MAX_PAGE_PIXELS} / (unscaled.width * unscaled.height)));
|
|
1332
|
+
const viewport = page.getViewport({ scale });
|
|
1333
|
+
pixelsLeft -= Math.ceil(viewport.width) * Math.ceil(viewport.height);
|
|
1334
|
+
if (pixelsLeft < 0) {
|
|
1335
|
+
const note = document.createElement('p');
|
|
1336
|
+
note.textContent = 'Pages ' + i + ' to ' + pdf.numPages + ' are not shown: the document is too large to draw.';
|
|
1337
|
+
container.appendChild(note);
|
|
1338
|
+
break;
|
|
1339
|
+
}
|
|
1329
1340
|
const canvas = document.createElement('canvas');
|
|
1330
1341
|
canvas.width = viewport.width;
|
|
1331
1342
|
canvas.height = viewport.height;
|
|
@@ -1333,9 +1344,9 @@ for (let i = 1; i <= pdf.numPages; i++) {
|
|
|
1333
1344
|
container.appendChild(canvas);
|
|
1334
1345
|
await page.render({ canvasContext: canvas.getContext('2d'), viewport }).promise;
|
|
1335
1346
|
}
|
|
1336
|
-
</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;var PLACEHOLDER="\uE000";var BARE_URL=/(?<![\w/@.])(?:https?:\/\/|www\.)(?:(?!<)[^\s<])+/gi;var
|
|
1347
|
+
</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;var PLACEHOLDER="\uE000";var BARE_URL=/(?<![\w/@.])(?:https?:\/\/|www\.)(?:(?!<)[^\s<])+/gi;var AUTOLINK_PUNCTUATION="?!.,:*_~";var ENTITY_NAME_CHARACTER=/[a-z0-9#]/i;var HREF_END=/[)\s]/g;var TABLE_DELIMITER=/^\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?$/;var TASK_ITEM=/^\[([ xX])\]\s+(.*)$/;function emphasis(text){return text.replace(/\*\*([^*]+)\*\*/g,"<strong>$1</strong>").replace(/\*([^*]+)\*/g,"<em>$1</em>")}function replaceLinks(text,render){let result="";let copied=0;let labelEnd=-1;let hrefEnd=-1;let start=text.indexOf("[");while(start!==-1){if(labelEnd<start)labelEnd=text.indexOf("]",start+1);if(labelEnd===-1)break;const hrefStart=labelEnd+2;if(labelEnd>start+1&&text[labelEnd+1]==="("){if(hrefEnd<hrefStart){HREF_END.lastIndex=hrefStart;hrefEnd=HREF_END.exec(text)?.index??text.length}if(hrefEnd>hrefStart&&text[hrefEnd]===")"){result+=text.slice(copied,start)+render(text.slice(start+1,labelEnd),text.slice(hrefStart,hrefEnd));copied=hrefEnd+1;start=text.indexOf("[",copied);continue}}start=text.indexOf("[",start+1)}return result+text.slice(copied)}function entityStart(text,end){if(text[end-1]!==";")return-1;let index=end-2;while(index>=0&&ENTITY_NAME_CHARACTER.test(text[index]))index--;return index<end-2&&text[index]==="&"?index:-1}function trimAutolink(url){let end=url.length;let unmatchedCloses=url.split(")").length-url.split("(").length;for(;;){const last=url[end-1]??"";const entity=entityStart(url,end);if(last!==""&&AUTOLINK_PUNCTUATION.includes(last)){end--}else if(entity!==-1){end=entity}else if(last===")"&&unmatchedCloses>0){end--;unmatchedCloses--}else{return url.slice(0,end)}}}function inline(text,gfm=false){const stash=[];const hold=html2=>PLACEHOLDER+(stash.push(html2)-1)+PLACEHOLDER;const restore=value=>value.split(PLACEHOLDER).map((part,i)=>i%2===1?stash[Number(part)]:part).join("");let out=escapeHtml(text.split(PLACEHOLDER).join("")).replace(/`([^`]+)`/g,(_m,code)=>hold(`<code>${code}</code>`));out=replaceLinks(out,(label,href)=>SAFE_HREF.test(href)?hold(`<a href="${href}" rel="noopener noreferrer">${emphasis(label)}</a>`):label);if(gfm){out=out.replace(BARE_URL,match=>{const url=trimAutolink(match.split(PLACEHOLDER,1)[0]);const href=/^www\./i.test(url)?`http://${url}`:url;return hold(`<a href="${href}" rel="noopener noreferrer">${url}</a>`)+match.slice(url.length)});out=out.replace(/~~([^~]+)~~/g,"<del>$1</del>")}out=emphasis(out);return restore(restore(out))}function listItem(item,gfm){const task=gfm?TASK_ITEM.exec(item):null;if(!task)return`<li>${inline(item,gfm)}</li>`;const checked=task[1]===" "?"":" checked";return`<li class="task-list-item"><input type="checkbox" disabled${checked}> ${inline(task[2],gfm)}</li>`}function tableCells(row){const cells=row.trim().replace(/^\|/,"").replace(/(?<!\\)\|$/,"").split(/(?<!\\)\|/);return cells.map(cell=>cell.trim().replace(/\\\|/g,"|"))}function cellAlignment(delimiter){const left=delimiter.startsWith(":");const right=delimiter.endsWith(":");if(left&&right)return' align="center"';if(right)return' align="right"';return left?' align="left"':""}function table(header,delimiter,body){const alignments=tableCells(delimiter).map(cellAlignment);const row=(cells,tag)=>`<tr>${alignments.map((align,i)=>`<${tag}${align}>${inline(cells[i]??"",true)}</${tag}>`).join("")}</tr>`;const rows=body.map(line=>row(tableCells(line),"td")).join("");return`<table><thead>${row(tableCells(header),"th")}</thead>${rows?`<tbody>${rows}</tbody>`:""}</table>`}function isTableStart(line,next){return line.includes("|")&&next!==void 0&&TABLE_DELIMITER.test(next.trim())&&tableCells(line).length===tableCells(next).length}function markdownToHtml(source,options={}){const gfm=options.gfm===true;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(" "),gfm)}</p>`);paragraph=[]};const flushList=()=>{if(list)blocks.push(`<${list.tag}>${list.items.map(item=>listItem(item,gfm)).join("")}</${list.tag}>`);list=void 0};for(let i=0;i<lines.length;i++){const line=lines[i];const fence=/^\s*(`{3,})\s*([\w#+.-]*)/.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(codeBlock(code.join("\n"),fence[2],options.highlight));continue}if(gfm&&isTableStart(line,lines[i+1])){flushParagraph();flushList();const header=line;const delimiter=lines[i+1];const body=[];for(i+=2;i<lines.length&&lines[i].trim()!==""&&lines[i].includes("|");i++)body.push(lines[i]);i--;blocks.push(table(header,delimiter,body));continue}const heading=/^(#{1,6})\s+(.*)$/.exec(line);if(heading){flushParagraph();flushList();blocks.push(`<h${heading[1].length}>${inline(heading[2].trim(),gfm)}</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 codeBlock(code,language,highlight){if(!highlight)return`<pre><code>${escapeHtml(code)}
|
|
1337
1348
|
</code></pre>`;const highlighted=language?highlight(code,language):void 0;const languageClass=language?` language-${language}`:"";return`<pre><code class="hljs${languageClass}">${highlighted??escapeHtml(code)}
|
|
1338
|
-
</code></pre>`}function loadServerReact(purpose){return{react:requireFromProject("react",purpose),jsxRuntime:requireFromProject("react/jsx-runtime",purpose),server:requireFromProject("react-dom/server",purpose)}}function renderComponentOnServer(component,input,output){const{react,server}=loadServerReact("`ui.uiType: 'react'`");return server.renderToStaticMarkup(react.createElement(component,widgetProps(input,output)))}var PURPOSE2="An MDX template";var compiledTemplates=new Map;async function preloadMdxCompiler(gfm=false){await preloadFromProject("@mdx-js/mdx",PURPOSE2);if(gfm)await preloadFromProject("remark-gfm",`${PURPOSE2} with \`gfm\``)}function compileMdxTemplate(source,gfm=false){const key=`${gfm}:${source}`;const cached=compiledTemplates.get(key);if(cached)return cached;const{compileSync}=requireFromProject("@mdx-js/mdx",PURPOSE2);const remarkPlugins=gfm?[requireFromProject("remark-gfm",`${PURPOSE2} with \`gfm\``).default]:[];const body=String(compileSync(source,{outputFormat:"function-body",development:false,remarkPlugins}));const compiled=new Function("__mdxRuntime","input","output","helpers",body);compiledTemplates.set(key,compiled);return compiled}function renderMdxTemplate(source,options){const compiled=compileMdxTemplate(source,options.gfm);const{react,jsxRuntime,server}=loadServerReact(PURPOSE2);const{default:content}=compiled(jsxRuntime,options.input,options.output,options.helpers);const components={...options.highlighter?{code:highlightedCode(react,options.highlighter)}:{},...options.components};return server.renderToStaticMarkup(react.createElement(content,{components}))}function highlightedCode(react,highlighter){return props=>{const language=/\blanguage-([\w#+.-]+)/.exec(props.className??"")?.[1];const highlighted=language&&typeof props.children==="string"?highlighter.highlight(props.children,language):void 0;if(highlighted===void 0)return react.createElement("code",props);return react.createElement("code",{className:`hljs ${props.className}`,dangerouslySetInnerHTML:{__html:highlighted}})}}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 forcedUiType(options){return options.uiType&&options.uiType!=="auto"?options.uiType:void 0}function resolveUiType(template,options){const forced=forcedUiType(options);if(forced)return forced;return typeof template==="string"&&options.mdxComponents?"mdx":detectUIType(template)}function isFileTemplate(template){return typeof template==="object"&&template!==null&&"file"in template}function isJsxFileTemplate(template){return isFileTemplate(template)&&/\.(tsx|jsx)$/i.test(String(template.file))}function isComponentObjectOrClass(template){if(typeof template==="object"&&template!==null)return"$$typeof"in template;const prototype=typeof template==="function"?template.prototype:void 0;return typeof prototype?.render==="function"||Boolean(prototype?.isReactComponent)}function isComponentReference(template,options){if(isComponentObjectOrClass(template))return true;return typeof template==="function"&&resolveUiType(template,options)==="react"}function describeRenderOptionProblems(template,options){const problems=[];const forced=forcedUiType(options);const uiTypeProblem=forced&&describeUiTypeMismatch(forced,template);if(uiTypeProblem)problems.push(`\`ui.uiType: '${forced}'\` ${uiTypeProblem}`);if(options.contentSecurity!==void 0)problems.push(...describeContentSecurityProblems(options.contentSecurity));if(options.contentSecurity!==void 0&&isFileTemplate(template)){problems.push("`ui.contentSecurity` sanitizes the markup FrontMCP builds on the server, and a `{ file }` widget is rendered in the page, so there is nothing for it to sanitize. Remove it, or use an HTML, Markdown or function template.")}if(options.mdxComponents&&typeof template!=="string"){problems.push(`\`ui.mdxComponents\` is for an MDX template, which is a string, and this template is ${describeTemplate(template)}. A template function's result is never compiled as MDX: it carries the call's data, and compiling it would run that data as code. Write the template as a string and read the data in expressions, such as \`{output.title}\`.`)}else if(options.mdxComponents&&forced&&forced!=="mdx"){problems.push(`\`ui.mdxComponents\` is for an MDX template, and \`ui.uiType\` is '${forced}'.`)}const uiType=resolveUiType(template,options);const convertsMarkdown=uiType==="markdown"&&(typeof template==="string"||typeof template==="function")||uiType==="mdx"&&typeof template==="string";if((options.markdown?.gfm||options.markdown?.highlightTheme)&&!convertsMarkdown){problems.push(`\`ui.runtimeOptions.markdown\` applies to a Markdown template (a string without both \`<\` and \`>\`, or any template with \`uiType: 'markdown'\`) or an MDX template, and this template is ${describeTemplate(template)}. Remove it, or write the template in Markdown.`)}if(options.hydrate&&!isJsxFileTemplate(template)){problems.push(isComponentReference(template,options)?"`ui.hydrate` needs the component's code in the page, and a component reference has no source file to bundle. Use `template: { file: './widget.tsx' }`, or remove `hydrate` and set `uiType: 'react'` to render it on the server only.":`\`ui.hydrate\` hydrates a React widget rendered on the server, a \`{ file }\` .tsx or .jsx widget, and this template is ${uiType==="mdx"?"an MDX template, which renders to static HTML":describeTemplate(template)}.`)}return problems}function describeUiTypeMismatch(uiType,template){if(uiType==="react"){if(typeof template==="function"||isComponentObjectOrClass(template)||isJsxFileTemplate(template))return;return`renders a React component (a component reference, or a \`{ file }\` .tsx or .jsx widget), and this template is ${isFileTemplate(template)?"a `{ file }` that is not a .tsx or .jsx file":describeTemplate(template)}.`}if(uiType==="mdx"){return typeof template==="string"?void 0:`renders an MDX template, which is a string, and this template is ${describeTemplate(template)}.`}if(typeof template==="string"||typeof template==="function"&&!isComponentObjectOrClass(template))return;return`renders a string or a template function, and this template is ${describeTemplate(template)}.`}async function prepareRenderOptions(template,options){const uiType=resolveUiType(template,options);if(options.markdown?.highlightTheme&&(uiType==="markdown"||uiType==="mdx")){loadCodeHighlighter(options.markdown.highlightTheme)}if(uiType==="mdx"&&typeof template==="string"){loadServerReact("An MDX template");await preloadMdxCompiler(options.markdown?.gfm);compileMdxTemplate(template,options.markdown?.gfm)}if(forcedUiType(options)==="react"&&!isFileTemplate(template))loadServerReact("`ui.uiType: 'react'`");if(options.hydrate)loadServerReact("`ui.hydrate`")}function describeTemplate(template){if(typeof template==="string")return detectUIType(template)==="html"?"an HTML string":"a Markdown string";if(isComponentObjectOrClass(template))return"a React component";if(typeof template==="function")return"a function";return isFileTemplate(template)?"a `{ file }` widget":"not a string"}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)}function convertMarkdown(source,options,mdx){const{gfm,highlightTheme}=options.markdown??{};const highlighter=highlightTheme?loadCodeHighlighter(highlightTheme):void 0;const converted=mdx?renderMdxTemplate(source,{input:options.input??{},output:options.output??{},helpers:createTemplateHelpers(),components:options.mdxComponents,gfm,highlighter}):markdownToHtml(source,{gfm,highlight:highlighter?.highlight});return highlighter?`<style>${highlighter.css}</style>
|
|
1349
|
+
</code></pre>`}function loadServerReact(purpose){return{react:requireFromProject("react",purpose),jsxRuntime:requireFromProject("react/jsx-runtime",purpose),server:requireFromProject("react-dom/server",purpose)}}function renderComponentOnServer(component,input,output){const{react,server}=loadServerReact("`ui.uiType: 'react'`");return server.renderToStaticMarkup(react.createElement(component,widgetProps(input,output)))}var PURPOSE2="An MDX template";var compiledTemplates=new Map;async function preloadMdxCompiler(gfm=false){await preloadFromProject("@mdx-js/mdx",PURPOSE2);if(gfm)await preloadFromProject("remark-gfm",`${PURPOSE2} with \`gfm\``)}function compileMdxTemplate(source,gfm=false){const key=`${gfm}:${source}`;const cached=compiledTemplates.get(key);if(cached)return cached;const{compileSync}=requireFromProject("@mdx-js/mdx",PURPOSE2);const remarkPlugins=gfm?[requireFromProject("remark-gfm",`${PURPOSE2} with \`gfm\``).default]:[];const body=String(compileSync(source,{outputFormat:"function-body",development:false,remarkPlugins}));const compiled=new Function("__mdxRuntime","input","output","helpers",body);compiledTemplates.set(key,compiled);return compiled}function renderMdxTemplate(source,options){const compiled=compileMdxTemplate(source,options.gfm);const{react,jsxRuntime,server}=loadServerReact(PURPOSE2);const{default:content}=compiled(jsxRuntime,options.input,options.output,options.helpers);const components={...options.highlighter?{code:highlightedCode(react,options.highlighter)}:{},...options.components};return server.renderToStaticMarkup(react.createElement(content,{components}))}function highlightedCode(react,highlighter){return props=>{const language=/\blanguage-([\w#+.-]+)/.exec(props.className??"")?.[1];const highlighted=language&&typeof props.children==="string"?highlighter.highlight(props.children,language):void 0;if(highlighted===void 0)return react.createElement("code",props);return react.createElement("code",{className:`hljs ${props.className}`,dangerouslySetInnerHTML:{__html:highlighted}})}}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 forcedUiType(options){return options.uiType&&options.uiType!=="auto"?options.uiType:void 0}function resolveUiType(template,options){const forced=forcedUiType(options);if(forced)return forced;return typeof template==="string"&&options.mdxComponents?"mdx":detectUIType(template)}function isFileTemplate(template){return typeof template==="object"&&template!==null&&"file"in template}function isJsxFileTemplate(template){return isFileTemplate(template)&&/\.(tsx|jsx)$/i.test(String(template.file))}function isComponentObjectOrClass(template){if(typeof template==="object"&&template!==null)return"$$typeof"in template;const prototype=typeof template==="function"?template.prototype:void 0;return typeof prototype?.render==="function"||Boolean(prototype?.isReactComponent)}function isComponentReference(template,options){if(isComponentObjectOrClass(template))return true;return typeof template==="function"&&resolveUiType(template,options)==="react"}function describeRenderOptionProblems(template,options){const problems=[];const forced=forcedUiType(options);const uiTypeProblem=forced&&describeUiTypeMismatch(forced,template);if(uiTypeProblem)problems.push(`\`ui.uiType: '${forced}'\` ${uiTypeProblem}`);if(options.contentSecurity!==void 0)problems.push(...describeContentSecurityProblems(options.contentSecurity));if(options.contentSecurity!==void 0&&isFileTemplate(template)){problems.push("`ui.contentSecurity` sanitizes the markup FrontMCP builds on the server, and a `{ file }` widget is rendered in the page, so there is nothing for it to sanitize. Remove it, or use an HTML, Markdown or function template.")}if(options.mdxComponents&&typeof template!=="string"){problems.push(`\`ui.mdxComponents\` is for an MDX template, which is a string, and this template is ${describeTemplate(template)}. A template function's result is never compiled as MDX: it carries the call's data, and compiling it would run that data as code. Write the template as a string and read the data in expressions, such as \`{output.title}\`.`)}else if(options.mdxComponents&&forced&&forced!=="mdx"){problems.push(`\`ui.mdxComponents\` is for an MDX template, and \`ui.uiType\` is '${forced}'.`)}const uiType=resolveUiType(template,options);const convertsMarkdown=uiType==="markdown"&&(typeof template==="string"||typeof template==="function")||uiType==="mdx"&&typeof template==="string";if((options.markdown?.gfm||options.markdown?.highlightTheme)&&!convertsMarkdown){problems.push(`\`ui.runtimeOptions.markdown\` applies to a Markdown template (a string without both \`<\` and \`>\`, or any template with \`uiType: 'markdown'\`) or an MDX template, and this template is ${describeTemplate(template)}. Remove it, or write the template in Markdown.`)}if(options.hydrate&&!isJsxFileTemplate(template)){problems.push(isComponentReference(template,options)?"`ui.hydrate` needs the component's code in the page, and a component reference has no source file to bundle. Use `template: { file: './widget.tsx' }`, or remove `hydrate` and set `uiType: 'react'` to render it on the server only.":`\`ui.hydrate\` hydrates a React widget rendered on the server, a \`{ file }\` .tsx or .jsx widget, and this template is ${uiType==="mdx"?"an MDX template, which renders to static HTML":describeTemplate(template)}.`)}return problems}function describeUiTypeMismatch(uiType,template){if(uiType==="react"){if(typeof template==="function"||isComponentObjectOrClass(template)||isJsxFileTemplate(template))return;return`renders a React component (a component reference, or a \`{ file }\` .tsx or .jsx widget), and this template is ${isFileTemplate(template)?"a `{ file }` that is not a .tsx or .jsx file":describeTemplate(template)}.`}if(uiType==="mdx"){return typeof template==="string"?void 0:`renders an MDX template, which is a string, and this template is ${describeTemplate(template)}.`}if(typeof template==="string"||typeof template==="function"&&!isComponentObjectOrClass(template))return;return`renders a string or a template function, and this template is ${describeTemplate(template)}.`}async function prepareRenderOptions(template,options){const uiType=resolveUiType(template,options);if(options.markdown?.highlightTheme&&(uiType==="markdown"||uiType==="mdx")){loadCodeHighlighter(options.markdown.highlightTheme)}if(uiType==="mdx"&&typeof template==="string"){loadServerReact("An MDX template");await preloadMdxCompiler(options.markdown?.gfm);compileMdxTemplate(template,options.markdown?.gfm)}if(forcedUiType(options)==="react"&&!isFileTemplate(template))loadServerReact("`ui.uiType: 'react'`");if(options.hydrate)loadServerReact("`ui.hydrate`")}function describeTemplate(template){if(typeof template==="string")return detectUIType(template)==="html"?"an HTML string":"a Markdown string";if(isComponentObjectOrClass(template))return"a React component";if(typeof template==="function")return"a function";return isFileTemplate(template)?"a `{ file }` widget":"not a string"}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}`)}var MAX_INDENTED_DEPTH=20;function jsonDepth(json){let depth=0;let deepest=0;let inString=false;for(let index=0;index<json.length;index++){const character=json[index];if(inString){if(character==="\\")index++;else if(character==='"')inString=false}else if(character==='"'){inString=true}else if(character==="["||character==="{"){depth++;deepest=Math.max(deepest,depth)}else if(character==="]"||character==="}"){depth--}}return deepest}function resultJson(value){const compact=JSON.stringify(value);if(compact===void 0||jsonDepth(compact)>MAX_INDENTED_DEPTH)return compact;return JSON.stringify(value,null,2)}function renderUnwrappedResult(rawResult,options){if(isTrustedHtml(rawResult)){return String(rawResult)}if(typeof rawResult!=="string"){return`<pre>${escapeHtml(resultJson(rawResult))}</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)}function convertMarkdown(source,options,mdx){const{gfm,highlightTheme}=options.markdown??{};const highlighter=highlightTheme?loadCodeHighlighter(highlightTheme):void 0;const converted=mdx?renderMdxTemplate(source,{input:options.input??{},output:options.output??{},helpers:createTemplateHelpers(),components:options.mdxComponents,gfm,highlighter}):markdownToHtml(source,{gfm,highlight:highlighter?.highlight});return highlighter?`<style>${highlighter.css}</style>
|
|
1339
1350
|
${converted}`:converted}function secureMarkup(markup,options){return options.contentSecurity===void 0?markup:sanitizeHtml(markup,options.contentSecurity)}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, or set \`ui.uiType: 'react'\` to render it on the server.`)}var COMPILED_JSX_PATTERN=/\b(?:React\.createElement|_?jsx(?:s|DEV)?)\)?\s*\(/;function isComponentReference2(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(!isComponentReference2(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 problems=describeRenderOptionProblems(template,options);if(problems.length>0)throw new Error(`Tool "${toolName}": ${problems.join(" ")}`);const uiType=resolveUiType(template,options);const forced=forcedUiType(options);const isClaude=platformType==="claude"||platformType==="claude-code";const resourceMode=options.resourceMode??(isClaude?"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",hydrate:options.hydrate===true},{...shellConfig,csp:buildCspConfig(resolver,options.csp)});html2=result.html;hash=result.hash;size=result.size}else if(typeof template==="function"&&forced==="react"){const shellResult=buildShell(secureMarkup(renderComponentOnServer(template,input,output),options),shellConfig);html2=shellResult.html;hash=shellResult.hash;size=shellResult.size}else if(typeof template==="function"){const helpers=createTemplateHelpers();const ctx={input:input??{},output:output??{},helpers};let rawResult;let isHtmlBuilder=forced!==void 0||uiType!=="react"||!isDefinitelyReactComponent(template);if(isHtmlBuilder){try{rawResult=template(ctx);isHtmlBuilder=forced!==void 0||!isReactTypedObject(rawResult)}catch(error){if(forced!==void 0||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 if(forced==="markdown"){const markup=typeof rawResult==="string"?convertMarkdown(rawResult,options,false):renderUnwrappedResult(rawResult,options);const shellResult=buildShell(secureMarkup(markup,options),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(secureMarkup(renderUnwrappedResult(rawResult,options),options),shellConfig);html2=shellResult.html;hash=shellResult.hash;size=shellResult.size}}}else if(typeof template==="string"){const markup=uiType==="markdown"||uiType==="mdx"?convertMarkdown(template,options,uiType==="mdx"):template;const shellResult=buildShell(secureMarkup(markup,options),shellConfig);html2=shellResult.html;hash=shellResult.hash;size=shellResult.size}else if(forced==="react"){const shellResult=buildShell(secureMarkup(renderComponentOnServer(template,input,output),options),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=`
|
|
1340
1351
|
${bridgeScript}
|
|
1341
1352
|
<div id="root">
|
|
@@ -388,6 +388,7 @@ var ExtAppsAdapter = {
|
|
|
388
388
|
});
|
|
389
389
|
},
|
|
390
390
|
handleMessage: function(context, event) {
|
|
391
|
+
if (event.source !== window.parent) return;
|
|
391
392
|
if (!this.isOriginTrusted(event.origin)) return;
|
|
392
393
|
var data = event.data;
|
|
393
394
|
if (!data || typeof data !== 'object' || data.jsonrpc !== '2.0') return;
|
package/esm/component/index.mjs
CHANGED
|
@@ -459,6 +459,7 @@ var ExtAppsAdapter = {
|
|
|
459
459
|
});
|
|
460
460
|
},
|
|
461
461
|
handleMessage: function(context, event) {
|
|
462
|
+
if (event.source !== window.parent) return;
|
|
462
463
|
if (!this.isOriginTrusted(event.origin)) return;
|
|
463
464
|
var data = event.data;
|
|
464
465
|
if (!data || typeof data !== 'object' || data.jsonrpc !== '2.0') return;
|