@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
package/esm/index.mjs
CHANGED
|
@@ -391,6 +391,7 @@ var ExtAppsAdapter = {
|
|
|
391
391
|
});
|
|
392
392
|
},
|
|
393
393
|
handleMessage: function(context, event) {
|
|
394
|
+
if (event.source !== window.parent) return;
|
|
394
395
|
if (!this.isOriginTrusted(event.origin)) return;
|
|
395
396
|
var data = event.data;
|
|
396
397
|
if (!data || typeof data !== 'object' || data.jsonrpc !== '2.0') return;
|
|
@@ -1197,12 +1198,12 @@ FrontMcpBridge.prototype._setupDataToolCallHandler = function() {
|
|
|
1197
1198
|
}
|
|
1198
1199
|
}, true); // Use capture phase to handle before React handlers
|
|
1199
1200
|
};
|
|
1200
|
-
`.trim()}var MAX_MINIFY_CODE_LENGTH=5e5;function minifyJS(code){if(code.length>MAX_MINIFY_CODE_LENGTH){return code}const out=[];let inBlockComment=false;for(const raw of code.split("\n")){const line=raw.trim();if(inBlockComment){if(line.includes("*/"))inBlockComment=false;continue}if(line===""||line.startsWith("//"))continue;if(line.startsWith("/*")){if(!line.includes("*/"))inBlockComment=true;continue}out.push(line)}return out.join("\n")}function generatePlatformBundle(platform,options={}){const platformAdapters={chatgpt:["openai","generic"],claude:["claude","generic"],gemini:["gemini","generic"],universal:["openai","ext-apps","claude","gemini","generic"]};return generateBridgeIIFE({...options,adapters:platformAdapters[platform]})}var UNIVERSAL_BRIDGE_SCRIPT=generateBridgeIIFE();var BRIDGE_SCRIPT_TAGS={universal:`<script>${UNIVERSAL_BRIDGE_SCRIPT}</script>`,chatgpt:`<script>${generatePlatformBundle("chatgpt")}</script>`,claude:`<script>${generatePlatformBundle("claude")}</script>`,gemini:`<script>${generatePlatformBundle("gemini")}</script>`};var DEFAULT_ALLOWED_PACKAGES=["react","react-dom","react/jsx-runtime","zod","@frontmcp/*"];var DEFAULT_TYPE_FETCHER_OPTIONS={allowedPackages:[...DEFAULT_ALLOWED_PACKAGES],maxDepth:4,timeout:1e4,maxConcurrency:5,cdnBaseUrl:"https://esm.sh"};var TYPE_CACHE_PREFIX="types:";var DEFAULT_TYPE_CACHE_TTL=60*60*1e3;var DEFAULT_CACHE_OPTIONS={maxSize:500,defaultTtl:60*60*1e3,trackStats:true};var MemoryTypeCache=class{cache=new Map;maxSize;defaultTtl;trackStats;stats={hits:0,misses:0,evictions:0};constructor(options={}){const opts={...DEFAULT_CACHE_OPTIONS,...options};this.maxSize=opts.maxSize;this.defaultTtl=opts.defaultTtl;this.trackStats=opts.trackStats}async get(key){const internal=this.cache.get(key);if(!internal){if(this.trackStats)this.stats.misses++;return void 0}if(internal.expiresAt>0&&Date.now()>internal.expiresAt){this.cache.delete(key);if(this.trackStats)this.stats.misses++;return void 0}this.cache.delete(key);internal.entry.accessCount++;this.cache.set(key,internal);if(this.trackStats)this.stats.hits++;return internal.entry}async set(key,entry,ttl){if(this.cache.size>=this.maxSize&&!this.cache.has(key)){const oldestKey=this.cache.keys().next().value;if(oldestKey){this.cache.delete(oldestKey);if(this.trackStats)this.stats.evictions++}}const effectiveTtl=ttl??this.defaultTtl;const expiresAt=effectiveTtl>0?Date.now()+effectiveTtl:0;this.cache.set(key,{entry,expiresAt})}async has(key){const internal=this.cache.get(key);if(!internal)return false;if(internal.expiresAt>0&&Date.now()>internal.expiresAt){this.cache.delete(key);return false}return true}async delete(key){return this.cache.delete(key)}async clear(){this.cache.clear();this.stats={hits:0,misses:0,evictions:0}}async getStats(){let totalSize=0;for(const{entry}of this.cache.values()){totalSize+=entry.size}const total=this.stats.hits+this.stats.misses;return{entries:this.cache.size,totalSize,hits:this.stats.hits,misses:this.stats.misses,hitRate:total>0?this.stats.hits/total:0}}get size(){return this.cache.size}get evictions(){return this.stats.evictions}cleanup(){const now=Date.now();let cleaned=0;for(const[key,internal]of this.cache.entries()){if(internal.expiresAt>0&&now>internal.expiresAt){this.cache.delete(key);cleaned++}}return cleaned}};var globalTypeCache=new MemoryTypeCache({maxSize:500,defaultTtl:60*60*1e3});var IMPORT_PATTERN=/^import\s+(?:type\s+)?(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+)?['"]([^'"]+)['"]/gm;var EXPORT_FROM_PATTERN=/^export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/gm;var REFERENCE_TYPES_PATTERN=/^\/\/\/\s*<reference\s+types\s*=\s*['"]([^'"]+)['"]\s*\/>/gm;var REFERENCE_PATH_PATTERN=/^\/\/\/\s*<reference\s+path\s*=\s*['"]([^'"]+)['"]\s*\/>/gm;var DECLARE_MODULE_PATTERN=/^declare\s+module\s+['"]([^'"]+)['"]/gm;function parseDtsImports(content){const imports=[];const externalPackages=new Set;const relativeImports=new Set;const lines=content.split("\n");for(let i=0;i<lines.length;i++){const line=lines[i];const lineNum=i+1;IMPORT_PATTERN.lastIndex=0;let match=IMPORT_PATTERN.exec(line);if(match){const specifier=match[1];imports.push({type:"import",specifier,statement:line.trim(),line:lineNum});categorizeSpecifier(specifier,externalPackages,relativeImports)}EXPORT_FROM_PATTERN.lastIndex=0;match=EXPORT_FROM_PATTERN.exec(line);if(match){const specifier=match[1];imports.push({type:"export",specifier,statement:line.trim(),line:lineNum});categorizeSpecifier(specifier,externalPackages,relativeImports)}REFERENCE_TYPES_PATTERN.lastIndex=0;match=REFERENCE_TYPES_PATTERN.exec(line);if(match){const specifier=match[1];imports.push({type:"reference",specifier,statement:line.trim(),line:lineNum});externalPackages.add(getPackageFromSpecifier(specifier))}REFERENCE_PATH_PATTERN.lastIndex=0;match=REFERENCE_PATH_PATTERN.exec(line);if(match){const specifier=match[1];imports.push({type:"reference",specifier,statement:line.trim(),line:lineNum});relativeImports.add(specifier)}DECLARE_MODULE_PATTERN.lastIndex=0;match=DECLARE_MODULE_PATTERN.exec(line);if(match){const specifier=match[1];imports.push({type:"declare-module",specifier,statement:line.trim(),line:lineNum})}}return{imports,externalPackages:Array.from(externalPackages),relativeImports:Array.from(relativeImports)}}function categorizeSpecifier(specifier,externalPackages,relativeImports){if(isRelativeImport(specifier)){relativeImports.add(specifier)}else{externalPackages.add(getPackageFromSpecifier(specifier))}}function isRelativeImport(specifier){return specifier.startsWith("./")||specifier.startsWith("../")||specifier.startsWith("/")||/^[A-Za-z]:/.test(specifier)}function getPackageFromSpecifier(specifier){if(specifier.startsWith("@")){const parts=specifier.split("/");if(parts.length>=2){return`${parts[0]}/${parts[1]}`}return specifier}const slashIndex=specifier.indexOf("/");if(slashIndex>0){return specifier.substring(0,slashIndex)}return specifier}function getSubpathFromSpecifier(specifier){const packageName2=getPackageFromSpecifier(specifier);if(specifier.length>packageName2.length+1){return specifier.substring(packageName2.length+1)}return void 0}var MAX_IMPORT_STATEMENT_LENGTH=2e3;function parseImportStatement(statement){if(statement.length>MAX_IMPORT_STATEMENT_LENGTH){return null}const namedMatch=/import\s+(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+['"]([^'"]+)['"]/.exec(statement);if(namedMatch){return namedMatch[1]}const sideEffectMatch=/import\s+['"]([^'"]+)['"]/.exec(statement);if(sideEffectMatch){return sideEffectMatch[1]}return null}function combineDtsContents(contents){const seenReferences=new Set;const references=[];const declarations=[];for(const[url,content]of contents.entries()){const lines=content.split("\n");let inReferences=true;for(const line of lines){const trimmed=line.trim();if(trimmed.startsWith("///")){if(!seenReferences.has(trimmed)){seenReferences.add(trimmed);references.push(trimmed)}continue}if(inReferences&&trimmed===""){continue}inReferences=false;if(declarations.length===0||declarations[declarations.length-1]!==""){if(trimmed!==""){
|
|
1201
|
-
// Source: ${url}`)}}}declarations.push(line)}}const parts=[];if(references.length>0){parts.push(references.join("\n"));parts.push("")}parts.push(declarations.join("\n").trim());return parts.join("\n")}var Semaphore=class{permits;waiting=[];constructor(permits){this.permits=permits}async acquire(){if(this.permits>0){this.permits--;return}return new Promise(resolve=>{this.waiting.push(resolve)})}release(){if(this.waiting.length>0){const next=this.waiting.shift();next?.()}else{this.permits++}}};var TypeFetcher=class{maxDepth;timeout;maxConcurrency;cdnBaseUrl;fetchFn;cache;allowedPatterns;allowlistEnabled;_initialized=false;constructor(options={},cache){this.maxDepth=options.maxDepth??2;this.timeout=options.timeout??1e4;this.maxConcurrency=options.maxConcurrency??5;this.cdnBaseUrl=options.cdnBaseUrl??"https://esm.sh";this.fetchFn=options.fetch??globalThis.fetch.bind(globalThis);this.cache=cache??globalTypeCache;if(options.allowedPackages===false){this.allowlistEnabled=false;this.allowedPatterns=[]}else{this.allowlistEnabled=true;this.allowedPatterns=[...DEFAULT_ALLOWED_PACKAGES,...options.allowedPackages??[]]}}isPackageAllowed(packageName2){if(!this.allowlistEnabled){return true}return this.allowedPatterns.some(pattern=>{if(pattern.includes("*")){const escaped=pattern.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");const regex=new RegExp(`^${escaped}$`);return regex.test(packageName2)}return packageName2===pattern||packageName2.startsWith(pattern+"/")})}async initialize(options){if(this._initialized){const stats2=await this.cache.getStats();return{loaded:[],failed:[],cached:stats2.entries}}const loaded=[];const failed=[];const packagesToLoad=this.allowedPatterns.filter(p=>!p.includes("*"));for(const pkg of packagesToLoad){const result=await this.fetchBatch({imports:[`import * from "${pkg}"`],timeout:options?.timeout??this.timeout});if(result.results.length>0){loaded.push(pkg)}else if(result.errors.length>0){failed.push(pkg)}}this._initialized=true;const stats=await this.cache.getStats();return{loaded,failed,cached:stats.entries}}get initialized(){return this._initialized}get allowedPackagePatterns(){return this.allowedPatterns}async fetchBatch(request){const startTime=Date.now();const results=[];const errors=[];let cacheHits=0;let networkRequests=0;const maxDepth=request.maxDepth??this.maxDepth;const timeout=request.timeout??this.timeout;const maxConcurrency=request.maxConcurrency??this.maxConcurrency;const skipCache=request.skipCache??false;const versionOverrides=request.versionOverrides??{};const semaphore=new Semaphore(maxConcurrency);const promises=request.imports.map(async importStatement=>{await semaphore.acquire();try{const specifier=parseImportStatement(importStatement);if(!specifier){errors.push({specifier:importStatement,code:"INVALID_SPECIFIER",message:`Could not parse import statement: ${importStatement}`});return}const packageName2=getPackageFromSpecifier(specifier);if(!this.isPackageAllowed(packageName2)){errors.push({specifier,code:"PACKAGE_NOT_ALLOWED",message:`Package "${packageName2}" is not in the allowlist`});return}const version=versionOverrides[packageName2]??"latest";const cacheKey=`${TYPE_CACHE_PREFIX}${packageName2}@${version}`;if(!skipCache){const cached=await this.cache.get(cacheKey);if(cached){cacheHits++;results.push(cached.result);return}}const result=await this.fetchTypesForSpecifier(specifier,{maxDepth,timeout,version});if(result.success){results.push(result.data);networkRequests+=result.fetchCount;const entry={result:result.data,cachedAt:Date.now(),size:result.data.content.length,accessCount:1};await this.cache.set(cacheKey,entry)}else{errors.push(result.error);networkRequests+=result.fetchCount}}finally{semaphore.release()}});await Promise.all(promises);return{results,errors,totalTimeMs:Date.now()-startTime,cacheHits,networkRequests}}async fetchTypesForSpecifier(specifier,options){let fetchCount=0;const fetchedUrls=[];const visitedUrls=new Set;const contents=new Map;try{const resolution=await this.resolvePackage(specifier,options.version,options.timeout);if(!resolution){return{success:false,error:{specifier,code:"PACKAGE_NOT_FOUND",message:`Could not resolve package: ${specifier}`},fetchCount}}fetchCount++;const fetchResult=await this.fetchRecursive(resolution.typesUrl,options.maxDepth,options.timeout,visitedUrls,contents);fetchCount+=fetchResult.fetchCount;fetchedUrls.push(...fetchResult.fetchedUrls);if(!fetchResult.success){return{success:false,error:{specifier,code:fetchResult.errorCode,message:fetchResult.errorMessage??"Unknown error",url:fetchResult.errorUrl},fetchCount}}const files=buildTypeFiles(contents,resolution.packageName,resolution.version,resolution.subpath);const combinedContent=combineDtsContents(contents);const result={specifier,resolvedPackage:resolution.packageName,subpath:resolution.subpath,version:resolution.version,content:combinedContent,files,fetchedUrls,fetchedAt:new Date().toISOString()};return{success:true,data:result,fetchCount}}catch(error){return{success:false,error:{specifier,code:"NETWORK_ERROR",message:error instanceof Error?error.message:String(error)},fetchCount}}}async resolvePackage(specifier,version,timeout){const packageName2=getPackageFromSpecifier(specifier);const subpath=getSubpathFromSpecifier(specifier);const versionSuffix=version==="latest"?"":`@${version}`;const baseUrl=`${this.cdnBaseUrl}/${packageName2}${versionSuffix}`;const urlsToTry=subpath?[`${baseUrl}/${subpath}`,baseUrl]:[baseUrl];for(const url of urlsToTry){try{const response=await this.fetchWithTimeout(url,timeout,"HEAD");if(response.ok){const typesHeader=response.headers.get("X-TypeScript-Types");if(typesHeader){const typesUrl=typesHeader.startsWith("/")?`${this.cdnBaseUrl}${typesHeader}`:typesHeader;const versionMatch=/@(\d+\.\d+\.\d+[^/]*)/.exec(typesUrl);const resolvedVersion=versionMatch?versionMatch[1]:version;return{packageName:packageName2,subpath,version:resolvedVersion,typesUrl}}}}catch{continue}}return null}async fetchRecursive(url,depth,timeout,visited,contents){if(visited.has(url)){return{success:true,fetchCount:0,fetchedUrls:[]}}visited.add(url);let fetchCount=1;const fetchedUrls=[url];try{const response=await this.fetchWithTimeout(url,timeout,"GET");if(!response.ok){return{success:false,fetchCount,fetchedUrls,errorCode:"NETWORK_ERROR",errorMessage:`HTTP ${response.status}: ${response.statusText}`,errorUrl:url}}const content=await response.text();contents.set(url,content);if(depth<=0){return{success:true,fetchCount,fetchedUrls}}const parsed=parseDtsImports(content);for(const pkg of parsed.externalPackages){if(pkg.startsWith("@types/")||isBuiltinModule(pkg)){continue}const resolution=await this.resolvePackage(pkg,"latest",timeout);fetchCount++;if(resolution&&!visited.has(resolution.typesUrl)){const result=await this.fetchRecursive(resolution.typesUrl,depth-1,timeout,visited,contents);fetchCount+=result.fetchCount;fetchedUrls.push(...result.fetchedUrls)}}for(const relativePath of parsed.relativeImports){const resolvedUrl=resolveRelativeUrl(url,relativePath);if(resolvedUrl&&!visited.has(resolvedUrl)){const result=await this.fetchRecursive(resolvedUrl,depth-1,timeout,visited,contents);fetchCount+=result.fetchCount;fetchedUrls.push(...result.fetchedUrls)}}return{success:true,fetchCount,fetchedUrls}}catch(error){const isTimeout=error instanceof Error&&error.message.includes("timeout");return{success:false,fetchCount,fetchedUrls,errorCode:isTimeout?"TIMEOUT":"NETWORK_ERROR",errorMessage:error instanceof Error?error.message:String(error),errorUrl:url}}}async fetchWithTimeout(url,timeout,method){const controller=new AbortController;const timeoutId=setTimeout(()=>controller.abort(),timeout);try{const response=await this.fetchFn(url,{method,signal:controller.signal,headers:{Accept:"application/typescript, text/plain, */*"}});return response}finally{clearTimeout(timeoutId)}}};function isBuiltinModule(name){const builtins=new Set(["assert","buffer","child_process","cluster","console","constants","crypto","dgram","dns","domain","events","fs","http","https","module","net","os","path","punycode","querystring","readline","repl","stream","string_decoder","sys","timers","tls","tty","url","util","v8","vm","zlib","node:assert","node:buffer","node:child_process","node:cluster","node:console","node:constants","node:crypto","node:dgram","node:dns","node:domain","node:events","node:fs","node:http","node:https","node:module","node:net","node:os","node:path","node:punycode","node:querystring","node:readline","node:repl","node:stream","node:string_decoder","node:sys","node:timers","node:tls","node:tty","node:url","node:util","node:v8","node:vm","node:zlib"]);return builtins.has(name)}function resolveRelativeUrl(base,relative){try{let path=relative;if(!path.endsWith(".d.ts")&&!path.endsWith(".ts")){path=`${path}.d.ts`}const resolved=new URL(path,base);return resolved.toString()}catch{return null}}function buildTypeFiles(contents,packageName2,version,subpath){const files=[];for(const[url,content]of contents.entries()){const virtualPath=urlToVirtualPath(url,packageName2,version);files.push({path:virtualPath,url,content})}if(subpath){const aliasPath=`node_modules/${packageName2}/${subpath}/index.d.ts`;const aliasExists=files.some(f=>f.path===aliasPath);if(!aliasExists){const aliasContent=`// Auto-generated alias for ${packageName2}/${subpath}
|
|
1201
|
+
`.trim()}var MAX_MINIFY_CODE_LENGTH=5e5;function minifyJS(code){if(code.length>MAX_MINIFY_CODE_LENGTH){return code}const out=[];let inBlockComment=false;for(const raw of code.split("\n")){const line=raw.trim();if(inBlockComment){if(line.includes("*/"))inBlockComment=false;continue}if(line===""||line.startsWith("//"))continue;if(line.startsWith("/*")){if(!line.includes("*/"))inBlockComment=true;continue}out.push(line)}return out.join("\n")}function generatePlatformBundle(platform,options={}){const platformAdapters={chatgpt:["openai","generic"],claude:["claude","generic"],gemini:["gemini","generic"],universal:["openai","ext-apps","claude","gemini","generic"]};return generateBridgeIIFE({...options,adapters:platformAdapters[platform]})}var UNIVERSAL_BRIDGE_SCRIPT=generateBridgeIIFE();var BRIDGE_SCRIPT_TAGS={universal:`<script>${UNIVERSAL_BRIDGE_SCRIPT}</script>`,chatgpt:`<script>${generatePlatformBundle("chatgpt")}</script>`,claude:`<script>${generatePlatformBundle("claude")}</script>`,gemini:`<script>${generatePlatformBundle("gemini")}</script>`};var DEFAULT_ALLOWED_PACKAGES=["react","react-dom","react/jsx-runtime","zod","@frontmcp/*"];var DEFAULT_TYPE_FETCHER_OPTIONS={allowedPackages:[...DEFAULT_ALLOWED_PACKAGES],maxDepth:4,timeout:1e4,maxConcurrency:5,cdnBaseUrl:"https://esm.sh"};var TYPE_CACHE_PREFIX="types:";var DEFAULT_TYPE_CACHE_TTL=60*60*1e3;var DEFAULT_CACHE_OPTIONS={maxSize:500,defaultTtl:60*60*1e3,trackStats:true};var MemoryTypeCache=class{cache=new Map;maxSize;defaultTtl;trackStats;stats={hits:0,misses:0,evictions:0};constructor(options={}){const opts={...DEFAULT_CACHE_OPTIONS,...options};this.maxSize=opts.maxSize;this.defaultTtl=opts.defaultTtl;this.trackStats=opts.trackStats}async get(key){const internal=this.cache.get(key);if(!internal){if(this.trackStats)this.stats.misses++;return void 0}if(internal.expiresAt>0&&Date.now()>internal.expiresAt){this.cache.delete(key);if(this.trackStats)this.stats.misses++;return void 0}this.cache.delete(key);internal.entry.accessCount++;this.cache.set(key,internal);if(this.trackStats)this.stats.hits++;return internal.entry}async set(key,entry,ttl){if(this.cache.size>=this.maxSize&&!this.cache.has(key)){const oldestKey=this.cache.keys().next().value;if(oldestKey){this.cache.delete(oldestKey);if(this.trackStats)this.stats.evictions++}}const effectiveTtl=ttl??this.defaultTtl;const expiresAt=effectiveTtl>0?Date.now()+effectiveTtl:0;this.cache.set(key,{entry,expiresAt})}async has(key){const internal=this.cache.get(key);if(!internal)return false;if(internal.expiresAt>0&&Date.now()>internal.expiresAt){this.cache.delete(key);return false}return true}async delete(key){return this.cache.delete(key)}async clear(){this.cache.clear();this.stats={hits:0,misses:0,evictions:0}}async getStats(){let totalSize=0;for(const{entry}of this.cache.values()){totalSize+=entry.size}const total=this.stats.hits+this.stats.misses;return{entries:this.cache.size,totalSize,hits:this.stats.hits,misses:this.stats.misses,hitRate:total>0?this.stats.hits/total:0}}get size(){return this.cache.size}get evictions(){return this.stats.evictions}cleanup(){const now=Date.now();let cleaned=0;for(const[key,internal]of this.cache.entries()){if(internal.expiresAt>0&&now>internal.expiresAt){this.cache.delete(key);cleaned++}}return cleaned}};var globalTypeCache=new MemoryTypeCache({maxSize:500,defaultTtl:60*60*1e3});var IMPORT_PATTERN=/^import\s+(?:type\s+)?(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+)?['"]([^'"]+)['"]/gm;var EXPORT_FROM_PATTERN=/^export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/gm;var REFERENCE_TYPES_PATTERN=/^\/\/\/\s*<reference\s+types\s*=\s*['"]([^'"]+)['"]\s*\/>/gm;var REFERENCE_PATH_PATTERN=/^\/\/\/\s*<reference\s+path\s*=\s*['"]([^'"]+)['"]\s*\/>/gm;var DECLARE_MODULE_PATTERN=/^declare\s+module\s+['"]([^'"]+)['"]/gm;function parseDtsImports(content){const imports=[];const externalPackages=new Set;const relativeImports=new Set;const lines=content.split("\n");for(let i=0;i<lines.length;i++){const line=lines[i];const lineNum=i+1;IMPORT_PATTERN.lastIndex=0;let match=IMPORT_PATTERN.exec(line);if(match){const specifier=match[1];imports.push({type:"import",specifier,statement:line.trim(),line:lineNum});categorizeSpecifier(specifier,externalPackages,relativeImports)}EXPORT_FROM_PATTERN.lastIndex=0;match=EXPORT_FROM_PATTERN.exec(line);if(match){const specifier=match[1];imports.push({type:"export",specifier,statement:line.trim(),line:lineNum});categorizeSpecifier(specifier,externalPackages,relativeImports)}REFERENCE_TYPES_PATTERN.lastIndex=0;match=REFERENCE_TYPES_PATTERN.exec(line);if(match){const specifier=match[1];imports.push({type:"reference",specifier,statement:line.trim(),line:lineNum});externalPackages.add(getPackageFromSpecifier(specifier))}REFERENCE_PATH_PATTERN.lastIndex=0;match=REFERENCE_PATH_PATTERN.exec(line);if(match){const specifier=match[1];imports.push({type:"reference",specifier,statement:line.trim(),line:lineNum});relativeImports.add(specifier)}DECLARE_MODULE_PATTERN.lastIndex=0;match=DECLARE_MODULE_PATTERN.exec(line);if(match){const specifier=match[1];imports.push({type:"declare-module",specifier,statement:line.trim(),line:lineNum})}}return{imports,externalPackages:Array.from(externalPackages),relativeImports:Array.from(relativeImports)}}function categorizeSpecifier(specifier,externalPackages,relativeImports){if(isRelativeImport(specifier)){relativeImports.add(specifier)}else{externalPackages.add(getPackageFromSpecifier(specifier))}}function isRelativeImport(specifier){return specifier.startsWith("./")||specifier.startsWith("../")||specifier.startsWith("/")||/^[A-Za-z]:/.test(specifier)}function getPackageFromSpecifier(specifier){if(specifier.startsWith("@")){const parts=specifier.split("/");if(parts.length>=2){return`${parts[0]}/${parts[1]}`}return specifier}const slashIndex=specifier.indexOf("/");if(slashIndex>0){return specifier.substring(0,slashIndex)}return specifier}function getSubpathFromSpecifier(specifier){const packageName2=getPackageFromSpecifier(specifier);if(specifier.length>packageName2.length+1){return specifier.substring(packageName2.length+1)}return void 0}var MAX_IMPORT_STATEMENT_LENGTH=2e3;function parseImportStatement(statement){if(statement.length>MAX_IMPORT_STATEMENT_LENGTH){return null}const namedMatch=/import\s+(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+['"]([^'"]+)['"]/.exec(statement);if(namedMatch){return namedMatch[1]}const sideEffectMatch=/import\s+['"]([^'"]+)['"]/.exec(statement);if(sideEffectMatch){return sideEffectMatch[1]}return null}function combineDtsContents(contents){const seenReferences=new Set;const references=[];const declarations=[];for(const[url,content]of contents.entries()){const lines=content.split("\n");let inReferences=true;let markerAdded=false;for(const line of lines){const trimmed=line.trim();if(trimmed.startsWith("///")){if(!seenReferences.has(trimmed)){seenReferences.add(trimmed);references.push(trimmed)}continue}if(inReferences&&trimmed===""){continue}inReferences=false;if(declarations.length===0||declarations[declarations.length-1]!==""){if(trimmed!==""&&!markerAdded){declarations.push(`
|
|
1202
|
+
// Source: ${url}`);markerAdded=true}}declarations.push(line)}}const parts=[];if(references.length>0){parts.push(references.join("\n"));parts.push("")}parts.push(declarations.join("\n").trim());return parts.join("\n")}var Semaphore=class{permits;waiting=[];constructor(permits){this.permits=permits}async acquire(){if(this.permits>0){this.permits--;return}return new Promise(resolve=>{this.waiting.push(resolve)})}release(){if(this.waiting.length>0){const next=this.waiting.shift();next?.()}else{this.permits++}}};var TypeFetcher=class{maxDepth;timeout;maxConcurrency;cdnBaseUrl;fetchFn;cache;allowedPatterns;allowlistEnabled;_initialized=false;constructor(options={},cache){this.maxDepth=options.maxDepth??2;this.timeout=options.timeout??1e4;this.maxConcurrency=options.maxConcurrency??5;this.cdnBaseUrl=options.cdnBaseUrl??"https://esm.sh";this.fetchFn=options.fetch??globalThis.fetch.bind(globalThis);this.cache=cache??globalTypeCache;if(options.allowedPackages===false){this.allowlistEnabled=false;this.allowedPatterns=[]}else{this.allowlistEnabled=true;this.allowedPatterns=[...DEFAULT_ALLOWED_PACKAGES,...options.allowedPackages??[]]}}isPackageAllowed(packageName2){if(!this.allowlistEnabled){return true}return this.allowedPatterns.some(pattern=>{if(pattern.includes("*")){const escaped=pattern.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");const regex=new RegExp(`^${escaped}$`);return regex.test(packageName2)}return packageName2===pattern||packageName2.startsWith(pattern+"/")})}async initialize(options){if(this._initialized){const stats2=await this.cache.getStats();return{loaded:[],failed:[],cached:stats2.entries}}const loaded=[];const failed=[];const packagesToLoad=this.allowedPatterns.filter(p=>!p.includes("*"));for(const pkg of packagesToLoad){const result=await this.fetchBatch({imports:[`import * from "${pkg}"`],timeout:options?.timeout??this.timeout});if(result.results.length>0){loaded.push(pkg)}else if(result.errors.length>0){failed.push(pkg)}}this._initialized=true;const stats=await this.cache.getStats();return{loaded,failed,cached:stats.entries}}get initialized(){return this._initialized}get allowedPackagePatterns(){return this.allowedPatterns}async fetchBatch(request){const startTime=Date.now();const results=[];const errors=[];let cacheHits=0;let networkRequests=0;const maxDepth=request.maxDepth??this.maxDepth;const timeout=request.timeout??this.timeout;const maxConcurrency=request.maxConcurrency??this.maxConcurrency;const skipCache=request.skipCache??false;const versionOverrides=request.versionOverrides??{};const semaphore=new Semaphore(maxConcurrency);const promises=request.imports.map(async importStatement=>{await semaphore.acquire();try{const specifier=parseImportStatement(importStatement);if(!specifier){errors.push({specifier:importStatement,code:"INVALID_SPECIFIER",message:`Could not parse import statement: ${importStatement}`});return}const packageName2=getPackageFromSpecifier(specifier);if(!this.isPackageAllowed(packageName2)){errors.push({specifier,code:"PACKAGE_NOT_ALLOWED",message:`Package "${packageName2}" is not in the allowlist`});return}const version=versionOverrides[packageName2]??"latest";if(!isRequestablePackage(packageName2,getSubpathFromSpecifier(specifier),version)){errors.push({specifier,code:"INVALID_SPECIFIER",message:`"${specifier}" at version "${version}" is not an npm package name, subpath and version that name the same package in a CDN URL. Use a subpath without "." or ".." segments and a version, range or tag.`});return}const cacheKey=`${TYPE_CACHE_PREFIX}${packageName2}@${version}`;if(!skipCache){const cached=await this.cache.get(cacheKey);if(cached){cacheHits++;results.push(cached.result);return}}const result=await this.fetchTypesForSpecifier(specifier,{maxDepth,timeout,version});if(result.success){results.push(result.data);networkRequests+=result.fetchCount;const entry={result:result.data,cachedAt:Date.now(),size:result.data.content.length,accessCount:1};await this.cache.set(cacheKey,entry)}else{errors.push(result.error);networkRequests+=result.fetchCount}}finally{semaphore.release()}});await Promise.all(promises);return{results,errors,totalTimeMs:Date.now()-startTime,cacheHits,networkRequests}}async fetchTypesForSpecifier(specifier,options){let fetchCount=0;const fetchedUrls=[];const visitedUrls=new Set;const contents=new Map;try{const resolution=await this.resolvePackage(specifier,options.version,options.timeout);if(!resolution){return{success:false,error:{specifier,code:"PACKAGE_NOT_FOUND",message:`Could not resolve package: ${specifier}`},fetchCount}}fetchCount++;const fetchResult=await this.fetchRecursive(resolution.typesUrl,options.maxDepth,options.timeout,visitedUrls,contents);fetchCount+=fetchResult.fetchCount;fetchedUrls.push(...fetchResult.fetchedUrls);if(!fetchResult.success){return{success:false,error:{specifier,code:fetchResult.errorCode,message:fetchResult.errorMessage??"Unknown error",url:fetchResult.errorUrl},fetchCount}}const files=buildTypeFiles(contents,resolution.packageName,resolution.version,resolution.subpath);const combinedContent=combineDtsContents(contents);const result={specifier,resolvedPackage:resolution.packageName,subpath:resolution.subpath,version:resolution.version,content:combinedContent,files,fetchedUrls,fetchedAt:new Date().toISOString()};return{success:true,data:result,fetchCount}}catch(error){return{success:false,error:{specifier,code:"NETWORK_ERROR",message:error instanceof Error?error.message:String(error)},fetchCount}}}async resolvePackage(specifier,version,timeout){const packageName2=getPackageFromSpecifier(specifier);const subpath=getSubpathFromSpecifier(specifier);if(!isRequestablePackage(packageName2,subpath,version))return null;const versionSuffix=version==="latest"?"":`@${version}`;const baseUrl=`${this.cdnBaseUrl}/${packageName2}${versionSuffix}`;const urlsToTry=subpath?[`${baseUrl}/${subpath}`,baseUrl]:[baseUrl];for(const url of urlsToTry){try{const response=await this.fetchWithTimeout(url,timeout,"HEAD");if(response.ok){const typesHeader=response.headers.get("X-TypeScript-Types");if(typesHeader){const typesUrl=typesHeader.startsWith("/")?`${this.cdnBaseUrl}${typesHeader}`:typesHeader;const versionMatch=/@(\d+\.\d+\.\d+[^/]*)/.exec(typesUrl);const resolvedVersion=versionMatch?versionMatch[1]:version;return{packageName:packageName2,subpath,version:resolvedVersion,typesUrl}}}}catch{continue}}return null}async fetchRecursive(url,depth,timeout,visited,contents){if(visited.has(url)){return{success:true,fetchCount:0,fetchedUrls:[]}}visited.add(url);let fetchCount=1;const fetchedUrls=[url];try{const response=await this.fetchWithTimeout(url,timeout,"GET");if(!response.ok){return{success:false,fetchCount,fetchedUrls,errorCode:"NETWORK_ERROR",errorMessage:`HTTP ${response.status}: ${response.statusText}`,errorUrl:url}}const content=await response.text();contents.set(url,content);if(depth<=0){return{success:true,fetchCount,fetchedUrls}}const parsed=parseDtsImports(content);for(const pkg of parsed.externalPackages){if(pkg.startsWith("@types/")||isBuiltinModule(pkg)){continue}const resolution=await this.resolvePackage(pkg,"latest",timeout);fetchCount++;if(resolution&&!visited.has(resolution.typesUrl)){const result=await this.fetchRecursive(resolution.typesUrl,depth-1,timeout,visited,contents);fetchCount+=result.fetchCount;fetchedUrls.push(...result.fetchedUrls)}}for(const relativePath of parsed.relativeImports){const resolvedUrl=resolveRelativeUrl(url,relativePath);if(resolvedUrl&&!visited.has(resolvedUrl)){const result=await this.fetchRecursive(resolvedUrl,depth-1,timeout,visited,contents);fetchCount+=result.fetchCount;fetchedUrls.push(...result.fetchedUrls)}}return{success:true,fetchCount,fetchedUrls}}catch(error){const isTimeout=error instanceof Error&&error.message.includes("timeout");return{success:false,fetchCount,fetchedUrls,errorCode:isTimeout?"TIMEOUT":"NETWORK_ERROR",errorMessage:error instanceof Error?error.message:String(error),errorUrl:url}}}async fetchWithTimeout(url,timeout,method){const cdnOrigin=new URL(this.cdnBaseUrl).origin;assertSameOrigin(url,cdnOrigin);const controller=new AbortController;const timeoutId=setTimeout(()=>controller.abort(),timeout);try{const response=await this.fetchFn(url,{method,signal:controller.signal,headers:{Accept:"application/typescript, text/plain, */*"}});if(response.url)assertSameOrigin(response.url,cdnOrigin);return response}finally{clearTimeout(timeoutId)}}};function isBuiltinModule(name){const builtins=new Set(["assert","buffer","child_process","cluster","console","constants","crypto","dgram","dns","domain","events","fs","http","https","module","net","os","path","punycode","querystring","readline","repl","stream","string_decoder","sys","timers","tls","tty","url","util","v8","vm","zlib","node:assert","node:buffer","node:child_process","node:cluster","node:console","node:constants","node:crypto","node:dgram","node:dns","node:domain","node:events","node:fs","node:http","node:https","node:module","node:net","node:os","node:path","node:punycode","node:querystring","node:readline","node:repl","node:stream","node:string_decoder","node:sys","node:timers","node:tls","node:tty","node:url","node:util","node:v8","node:vm","node:zlib"]);return builtins.has(name)}var PACKAGE_NAME=/^(?:@[a-z0-9-][\w.-]*\/)?[a-z0-9-][\w.-]*$/i;var SUBPATH_SEGMENT=/^[\w-][\w.-]*$/;var VERSION=/^[\w.^~*<>=+-]+$/;function isRequestablePackage(packageName2,subpath,version){return PACKAGE_NAME.test(packageName2)&&(subpath===void 0||subpath.split("/").every(segment=>SUBPATH_SEGMENT.test(segment)))&&VERSION.test(version)}function assertSameOrigin(url,origin){if(new URL(url).origin!==origin){throw new Error(`${url} is outside ${origin}, the origin of cdnBaseUrl, so it is not fetched.`)}}function resolveRelativeUrl(base,relative){try{let path=relative;if(!path.endsWith(".d.ts")&&!path.endsWith(".ts")){path=`${path}.d.ts`}const resolved=new URL(path,base);return resolved.toString()}catch{return null}}function buildTypeFiles(contents,packageName2,version,subpath){const files=[];for(const[url,content]of contents.entries()){const virtualPath=urlToVirtualPath(url,packageName2,version);files.push({path:virtualPath,url,content})}if(subpath){const aliasPath=`node_modules/${packageName2}/${subpath}/index.d.ts`;const aliasExists=files.some(f=>f.path===aliasPath);if(!aliasExists){const aliasContent=`// Auto-generated alias for ${packageName2}/${subpath}
|
|
1202
1203
|
export * from '${getRelativeImportPath(subpath)}';
|
|
1203
1204
|
`;files.push({path:aliasPath,url:"",content:aliasContent})}}return files}function getRelativeImportPath(subpath){const depth=subpath.split("/").length;const prefix="../".repeat(depth);return`${prefix}index`}function urlToVirtualPath(url,packageName2,version){try{const urlObj=new URL(url);const pathname=urlObj.pathname;const cleanPath=pathname.replace(/^\/v\d+\//,"/");const versionedPackage=`${packageName2}@${version}`;const packageIndex=cleanPath.indexOf(versionedPackage);if(packageIndex!==-1){const afterPackageVersion=cleanPath.substring(packageIndex+versionedPackage.length);const relativePath=afterPackageVersion.startsWith("/")?afterPackageVersion.substring(1):afterPackageVersion;return`node_modules/${packageName2}/${relativePath||"index.d.ts"}`}const packagePattern=new RegExp(`/${escapeRegExp(packageName2)}@[^/]+(/.*)?$`);const match=pathname.match(packagePattern);if(match){const filePath=match[1]?match[1].substring(1):"index.d.ts";return`node_modules/${packageName2}/${filePath}`}return`node_modules/${packageName2}/${pathname.split("/").pop()||"index.d.ts"}`}catch{return`node_modules/${packageName2}/index.d.ts`}}function escapeRegExp(string){return string.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function createTypeFetcher(options,cache){return new TypeFetcher(options,cache)}var DEFAULT_CDN_REGISTRY={react:{packageName:"react",defaultVersion:"19.2.4",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/react/19.2.4/umd/react.production.min.js",global:"React",crossorigin:"anonymous"},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/react@19.2.4/umd/react.production.min.js",global:"React",crossorigin:"anonymous"},unpkg:{url:"https://unpkg.com/react@19.2.4/umd/react.production.min.js",global:"React",crossorigin:"anonymous"},"esm.sh":{url:"https://esm.sh/react@19.2.4",esm:true,crossorigin:"anonymous"}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"A JavaScript library for building user interfaces",homepage:"https://react.dev",license:"MIT"}},"react-dom":{packageName:"react-dom",defaultVersion:"19.2.4",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/react-dom/19.2.4/umd/react-dom.production.min.js",global:"ReactDOM",crossorigin:"anonymous",peerDependencies:["react"]},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/react-dom@19.2.4/umd/react-dom.production.min.js",global:"ReactDOM",crossorigin:"anonymous",peerDependencies:["react"]},unpkg:{url:"https://unpkg.com/react-dom@19.2.4/umd/react-dom.production.min.js",global:"ReactDOM",crossorigin:"anonymous",peerDependencies:["react"]},"esm.sh":{url:"https://esm.sh/react-dom@19.2.4",esm:true,crossorigin:"anonymous",peerDependencies:["react"]}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"React package for working with the DOM",homepage:"https://react.dev",license:"MIT"}},"chart.js":{packageName:"chart.js",defaultVersion:"4.5.1",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.5.1/chart.umd.min.js",global:"Chart",crossorigin:"anonymous"},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/chart.js@4.5.1/dist/chart.umd.min.js",global:"Chart",crossorigin:"anonymous"},unpkg:{url:"https://unpkg.com/chart.js@4.5.1/dist/chart.umd.min.js",global:"Chart",crossorigin:"anonymous"}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"Simple yet flexible JavaScript charting library",homepage:"https://www.chartjs.org",license:"MIT"}},d3:{packageName:"d3",defaultVersion:"7.9.0",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js",integrity:"sha512-vc58qvvBdrDR4etbxMdlTt4GBQk1qjvyORR2nrsPsFPyrs+/u5c3+1Ct6upOgdZoIl7eq6k3a1UPDSNAQi/32A==",global:"d3",crossorigin:"anonymous"},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/d3@7.9.0/dist/d3.min.js",global:"d3",crossorigin:"anonymous"},unpkg:{url:"https://unpkg.com/d3@7.9.0/dist/d3.min.js",global:"d3",crossorigin:"anonymous"}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"Data-Driven Documents",homepage:"https://d3js.org",license:"ISC"}},lodash:{packageName:"lodash",defaultVersion:"4.17.21",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js",integrity:"sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==",global:"_",crossorigin:"anonymous"},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js",global:"_",crossorigin:"anonymous"},unpkg:{url:"https://unpkg.com/lodash@4.17.21/lodash.min.js",global:"_",crossorigin:"anonymous"}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"A modern JavaScript utility library",homepage:"https://lodash.com",license:"MIT"}}};function lookupPackage(packageName2,registry=DEFAULT_CDN_REGISTRY){return registry[packageName2]}function getPackageCDNUrl(packageName2,providerOrder=["esm.sh","cloudflare","jsdelivr","unpkg"],registry=DEFAULT_CDN_REGISTRY){const entry=lookupPackage(packageName2,registry);if(!entry)return void 0;for(const provider of providerOrder){const config=entry.providers[provider];if(config?.url){return config.url}}for(const provider of Object.keys(entry.providers)){const config=entry.providers[provider];if(config?.url){return config.url}}return void 0}function getRegisteredPackages(registry=DEFAULT_CDN_REGISTRY){return Object.keys(registry)}function isPackageRegistered(packageName2,registry=DEFAULT_CDN_REGISTRY){return packageName2 in registry}function mergeRegistries(customRegistry){return{...DEFAULT_CDN_REGISTRY,...customRegistry}}function getPackagePeerDependencies(packageName2,registry=DEFAULT_CDN_REGISTRY){const entry=lookupPackage(packageName2,registry);if(!entry)return[];for(const provider of Object.keys(entry.providers)){const config=entry.providers[provider];if(config?.peerDependencies){return config.peerDependencies}}return[]}var IMPORT_PATTERNS={named:/import\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g,default:/import\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,namespace:/import\s*\*\s*as\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,sideEffect:/import\s*['"]([^'"]+)['"]/g,dynamic:/(?:await\s+)?import\s*\(\s*['"]([^'"]+)['"]\s*\)/g,defaultAndNamed:/import\s+(\w+)\s*,\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g,defaultAndNamespace:/import\s+(\w+)\s*,\s*\*\s*as\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,reExport:/export\s*\{[^}]+\}\s*from\s*['"]([^'"]+)['"]/g,reExportAll:/export\s*\*\s*from\s*['"]([^'"]+)['"]/g};function parseNamedImports(namedString){return namedString.split(",").map(s=>s.trim()).filter(s=>s.length>0).map(s=>{const asMatch=s.match(/^(\w+)\s+as\s+\w+$/);return asMatch?asMatch[1]:s})}function isRelativeImport2(specifier){return specifier.startsWith("./")||specifier.startsWith("../")||specifier.startsWith("/")}function isExternalImport(specifier){return!isRelativeImport2(specifier)&&!specifier.startsWith("#")}function getPackageName(specifier){if(specifier.startsWith("@")){const parts=specifier.split("/");if(parts.length>=2){return`${parts[0]}/${parts[1]}`}return specifier}const firstSlash=specifier.indexOf("/");return firstSlash===-1?specifier:specifier.slice(0,firstSlash)}function getLineNumber(source,index){let line=1;for(let i=0;i<index&&i<source.length;i++){if(source[i]==="\n"){line++}}return line}function getColumnNumber(source,index){let column=0;for(let i=index-1;i>=0&&source[i]!=="\n";i--){column++}return column}function parseImports(source){const imports=[];const seenStatements=new Set;const addImport=imp=>{const key=`${imp.type}:${imp.specifier}:${imp.statement}`;if(!seenStatements.has(key)){seenStatements.add(key);imports.push(imp)}};let match;const defaultAndNamedRegex=new RegExp(IMPORT_PATTERNS.defaultAndNamed.source,"g");while((match=defaultAndNamedRegex.exec(source))!==null){const[statement,defaultName,namedString,specifier]=match;addImport({statement,specifier,type:"default",defaultImport:defaultName,namedImports:parseNamedImports(namedString),line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const defaultAndNamespaceRegex=new RegExp(IMPORT_PATTERNS.defaultAndNamespace.source,"g");while((match=defaultAndNamespaceRegex.exec(source))!==null){const[statement,defaultName,namespaceName,specifier]=match;addImport({statement,specifier,type:"default",defaultImport:defaultName,namespaceImport:namespaceName,line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const namedRegex=new RegExp(IMPORT_PATTERNS.named.source,"g");while((match=namedRegex.exec(source))!==null){const[statement,namedString,specifier]=match;addImport({statement,specifier,type:"named",namedImports:parseNamedImports(namedString),line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const defaultRegex=new RegExp(IMPORT_PATTERNS.default.source,"g");while((match=defaultRegex.exec(source))!==null){const[statement,defaultName,specifier]=match;const afterMatch=source.slice(match.index+match[0].length-specifier.length-2);if(afterMatch.startsWith(","))continue;addImport({statement,specifier,type:"default",defaultImport:defaultName,line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const namespaceRegex=new RegExp(IMPORT_PATTERNS.namespace.source,"g");while((match=namespaceRegex.exec(source))!==null){const[statement,namespaceName,specifier]=match;addImport({statement,specifier,type:"namespace",namespaceImport:namespaceName,line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const sideEffectRegex=new RegExp(IMPORT_PATTERNS.sideEffect.source,"g");while((match=sideEffectRegex.exec(source))!==null){const[statement,specifier]=match;const beforeMatch=source.slice(Math.max(0,match.index-50),match.index);if(beforeMatch.includes("from"))continue;addImport({statement,specifier,type:"side-effect",line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const dynamicRegex=new RegExp(IMPORT_PATTERNS.dynamic.source,"g");while((match=dynamicRegex.exec(source))!==null){const[statement,specifier]=match;addImport({statement,specifier,type:"dynamic",line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const reExportRegex=new RegExp(IMPORT_PATTERNS.reExport.source,"g");while((match=reExportRegex.exec(source))!==null){const[statement,specifier]=match;addImport({statement,specifier,type:"named",line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const reExportAllRegex=new RegExp(IMPORT_PATTERNS.reExportAll.source,"g");while((match=reExportAllRegex.exec(source))!==null){const[statement,specifier]=match;addImport({statement,specifier,type:"namespace",line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const externalImports=imports.filter(imp=>isExternalImport(imp.specifier));const relativeImports=imports.filter(imp=>isRelativeImport2(imp.specifier));const externalPackages=[...new Set(externalImports.map(imp=>getPackageName(imp.specifier)))];return{imports,externalImports,relativeImports,externalPackages}}function extractExternalPackages(source){return parseImports(source).externalPackages}var DEFAULT_FALLBACK_CDN="https://esm.sh";function createResolverWithOverrides(overrides,baseOptions){const base=createEsmShResolver(baseOptions);return{overrides,resolve(specifier,context){if(overrides[specifier]){return{value:overrides[specifier],type:"url"}}for(const[prefix,url]of Object.entries(overrides)){if(specifier.startsWith(prefix+"/")){const subpath=specifier.slice(prefix.length);return{value:url+subpath,type:"url"}}}return base.resolve(specifier,context)}}}function createEsmShResolver(options={}){const{fallbackCdnBase=DEFAULT_FALLBACK_CDN,registry=DEFAULT_CDN_REGISTRY,providerOrder=["esm.sh","cloudflare","jsdelivr","unpkg"]}=options;return{resolve(specifier,_context){if(specifier.startsWith("./")||specifier.startsWith("../")||specifier.startsWith("/")){return null}if(specifier.startsWith("node:")||specifier.startsWith("#")){return null}const pkgName=getPackageName(specifier);const entry=lookupPackage(pkgName,registry);if(entry){for(const provider of providerOrder){const config=entry.providers[provider];if(config?.url){const subpath=specifier.slice(pkgName.length);if(subpath&&config.url.includes("esm.sh/")){return{value:config.url+subpath,type:"url",integrity:config.integrity}}if(subpath){return{value:`${fallbackCdnBase}/${specifier}`,type:"url"}}if(config.global&&!config.esm){return{value:config.url,type:"url",integrity:config.integrity}}return{value:config.url,type:"url",integrity:config.integrity}}}}return{value:`${fallbackCdnBase}/${specifier}`,type:"url"}}}}function createImportMapFromResolved(resolved){const imports={};const integrity={};for(const[specifier,res]of Object.entries(resolved)){if(res.type==="url"){imports[specifier]=res.value;if(res.integrity){integrity[res.value]=res.integrity}}}return{imports,integrity:Object.keys(integrity).length>0?integrity:void 0}}function createImportMap(dependencies){const imports={};const integrity={};for(const dep of dependencies){imports[dep.packageName]=dep.cdnUrl;if(dep.integrity){integrity[dep.cdnUrl]=dep.integrity}}return{imports,integrity:Object.keys(integrity).length>0?integrity:void 0}}function mergeImportMaps(...maps){const imports={};const integrity={};const scopes={};for(const map of maps){Object.assign(imports,map.imports);if(map.integrity){Object.assign(integrity,map.integrity)}if(map.scopes){for(const[scope,mappings]of Object.entries(map.scopes)){scopes[scope]={...scopes[scope],...mappings}}}}return{imports,integrity:Object.keys(integrity).length>0?integrity:void 0,scopes:Object.keys(scopes).length>0?scopes:void 0}}function generateImportMapScriptTag(map){const json=JSON.stringify(map,null,2).replace(/<\//g,"<\\/");return`<script type="importmap">
|
|
1204
1205
|
${json}
|
|
1205
|
-
</script>`}function generateImportMapScriptTagMinified(map){const json=JSON.stringify(map).replace(/<\//g,"<\\/");return`<script type="importmap">${json}</script>`}function generateCDNScriptTags(dependencies){return dependencies.filter(dep=>!dep.esm).map(dep=>{const attrs=[`src="${escapeHtmlAttr(dep.cdnUrl)}"`];if(dep.integrity){attrs.push(`integrity="${escapeHtmlAttr(dep.integrity)}"`)}attrs.push('crossorigin="anonymous"');return`<script ${attrs.join(" ")}></script>`})}function generateDependencyHTML(dependencies,options={}){const{minify=false}=options;const parts=[];const importMap=createImportMap(dependencies);const importMapTag=minify?generateImportMapScriptTagMinified(importMap):generateImportMapScriptTag(importMap);parts.push(importMapTag);const umdTags=generateCDNScriptTags(dependencies);parts.push(...umdTags);return parts.join(minify?"":"\n")}function validateImportMap(map){const errors=[];if(typeof map!=="object"||map===null){return{valid:false,errors:["Import map must be an object"]}}const obj=map;if(!obj["imports"]){errors.push('Import map must have an "imports" field')}else if(typeof obj["imports"]!=="object"||obj["imports"]===null){errors.push('"imports" must be an object')}else{const imports=obj["imports"];for(const[key,value]of Object.entries(imports)){if(typeof value!=="string"){errors.push(`Import "${key}" must map to a string URL`)}else if(!value.startsWith("https://")){errors.push(`Import "${key}" URL must use HTTPS: ${value}`)}}}if(obj["integrity"]!==void 0){if(typeof obj["integrity"]!=="object"||obj["integrity"]===null){errors.push('"integrity" must be an object')}else{const integrity=obj["integrity"];for(const[url,hash]of Object.entries(integrity)){if(typeof hash!=="string"){errors.push(`Integrity for "${url}" must be a string`)}else if(!hash.match(/^sha(256|384|512)-/)){errors.push(`Invalid integrity hash format for "${url}": ${hash}`)}}}}return{valid:errors.length===0,errors}}function rewriteImports(source,options={}){const{resolver=createEsmShResolver(),skipPackages=[],overrides={}}=options;const skipSet=new Set(skipPackages);const rewrites=new Map;const fallbackPackages=[];const parsed=parseImports(source);const specifierMap=new Map;for(const imp of parsed.externalImports){const specifier=imp.specifier;if(specifierMap.has(specifier))continue;if(specifier.startsWith("node:"))continue;const pkgName=getPackageName(specifier);if(skipSet.has(pkgName))continue;if(overrides[specifier]){specifierMap.set(specifier,overrides[specifier]);continue}if(overrides[pkgName]){const subpath=specifier.slice(pkgName.length);specifierMap.set(specifier,overrides[pkgName]+subpath);continue}const resolved=resolver.resolve(specifier);if(resolved&&resolved.type==="url"){specifierMap.set(specifier,resolved.value)}}let code=source;for(const[specifier,cdnUrl]of specifierMap){const escaped=escapeRegExp2(specifier);const singleQuotePattern=new RegExp(`((?:import|export)\\s
|
|
1206
|
+
</script>`}function generateImportMapScriptTagMinified(map){const json=JSON.stringify(map).replace(/<\//g,"<\\/");return`<script type="importmap">${json}</script>`}function generateCDNScriptTags(dependencies){return dependencies.filter(dep=>!dep.esm).map(dep=>{const attrs=[`src="${escapeHtmlAttr(dep.cdnUrl)}"`];if(dep.integrity){attrs.push(`integrity="${escapeHtmlAttr(dep.integrity)}"`)}attrs.push('crossorigin="anonymous"');return`<script ${attrs.join(" ")}></script>`})}function generateDependencyHTML(dependencies,options={}){const{minify=false}=options;const parts=[];const importMap=createImportMap(dependencies);const importMapTag=minify?generateImportMapScriptTagMinified(importMap):generateImportMapScriptTag(importMap);parts.push(importMapTag);const umdTags=generateCDNScriptTags(dependencies);parts.push(...umdTags);return parts.join(minify?"":"\n")}function validateImportMap(map){const errors=[];if(typeof map!=="object"||map===null){return{valid:false,errors:["Import map must be an object"]}}const obj=map;if(!obj["imports"]){errors.push('Import map must have an "imports" field')}else if(typeof obj["imports"]!=="object"||obj["imports"]===null){errors.push('"imports" must be an object')}else{const imports=obj["imports"];for(const[key,value]of Object.entries(imports)){if(typeof value!=="string"){errors.push(`Import "${key}" must map to a string URL`)}else if(!value.startsWith("https://")){errors.push(`Import "${key}" URL must use HTTPS: ${value}`)}}}if(obj["integrity"]!==void 0){if(typeof obj["integrity"]!=="object"||obj["integrity"]===null){errors.push('"integrity" must be an object')}else{const integrity=obj["integrity"];for(const[url,hash]of Object.entries(integrity)){if(typeof hash!=="string"){errors.push(`Integrity for "${url}" must be a string`)}else if(!hash.match(/^sha(256|384|512)-/)){errors.push(`Invalid integrity hash format for "${url}": ${hash}`)}}}}return{valid:errors.length===0,errors}}function rewriteImports(source,options={}){const{resolver=createEsmShResolver(),skipPackages=[],overrides={}}=options;const skipSet=new Set(skipPackages);const rewrites=new Map;const fallbackPackages=[];const parsed=parseImports(source);const specifierMap=new Map;for(const imp of parsed.externalImports){const specifier=imp.specifier;if(specifierMap.has(specifier))continue;if(specifier.startsWith("node:"))continue;const pkgName=getPackageName(specifier);if(skipSet.has(pkgName))continue;if(overrides[specifier]){specifierMap.set(specifier,overrides[specifier]);continue}if(overrides[pkgName]){const subpath=specifier.slice(pkgName.length);specifierMap.set(specifier,overrides[pkgName]+subpath);continue}const resolved=resolver.resolve(specifier);if(resolved&&resolved.type==="url"){specifierMap.set(specifier,resolved.value)}}let code=source;for(const[specifier,cdnUrl]of specifierMap){const escaped=escapeRegExp2(specifier);const singleQuotePattern=new RegExp(`((?:import|export)\\s(?:[^'"]*\\s)?from\\s+)'${escaped}'`,"g");const doubleQuotePattern=new RegExp(`((?:import|export)\\s(?:[^'"]*\\s)?from\\s+)"${escaped}"`,"g");const dynamicSinglePattern=new RegExp(`(import\\s*\\(\\s*)'${escaped}'`,"g");const dynamicDoublePattern=new RegExp(`(import\\s*\\(\\s*)"${escaped}"`,"g");const sideEffectSinglePattern=new RegExp(`(import\\s+)'${escaped}'`,"g");const sideEffectDoublePattern=new RegExp(`(import\\s+)"${escaped}"`,"g");const beforeLength=code.length;code=code.replace(singleQuotePattern,`$1'${cdnUrl}'`).replace(doubleQuotePattern,`$1"${cdnUrl}"`).replace(dynamicSinglePattern,`$1'${cdnUrl}'`).replace(dynamicDoublePattern,`$1"${cdnUrl}"`).replace(sideEffectSinglePattern,`$1'${cdnUrl}'`).replace(sideEffectDoublePattern,`$1"${cdnUrl}"`);if(code.length!==beforeLength||code!==source){rewrites.set(specifier,cdnUrl)}}return{code,rewrittenCount:rewrites.size,rewrites,fallbackPackages}}function escapeRegExp2(str){return str.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var DEFAULT_CDN_DOMAINS=["https://cdn.jsdelivr.net","https://cdnjs.cloudflare.com","https://fonts.googleapis.com","https://fonts.gstatic.com","https://esm.sh"];var DEFAULT_CSP_DIRECTIVES=["default-src 'none'",`script-src 'self' 'unsafe-inline' ${DEFAULT_CDN_DOMAINS.join(" ")}`,`style-src 'self' 'unsafe-inline' ${DEFAULT_CDN_DOMAINS.join(" ")}`,`img-src 'self' data: ${DEFAULT_CDN_DOMAINS.join(" ")}`,`font-src 'self' data: ${DEFAULT_CDN_DOMAINS.join(" ")}`,`connect-src ${DEFAULT_CDN_DOMAINS.join(" ")}`,"object-src 'self' data:"];var RESTRICTIVE_CSP_DIRECTIVES=["default-src 'none'","script-src 'self' 'unsafe-inline'","style-src 'self' 'unsafe-inline'","img-src 'self' data:","font-src 'self' data:","connect-src 'none'","object-src 'self' data:"];function buildCSPDirectives(csp){if(!csp){return[...DEFAULT_CSP_DIRECTIVES]}const validResourceDomains=sanitizeCSPDomains(csp.resourceDomains);const validConnectDomains=sanitizeCSPDomains(csp.connectDomains);const allResourceDomains=[...new Set([...DEFAULT_CDN_DOMAINS,...validResourceDomains])];const directives=["default-src 'none'",`script-src 'self' 'unsafe-inline' ${allResourceDomains.join(" ")}`,`style-src 'self' 'unsafe-inline' ${allResourceDomains.join(" ")}`];const imgSources=["'self'","data:",...allResourceDomains];directives.push(`img-src ${imgSources.join(" ")}`);const fontSources=["'self'","data:",...allResourceDomains];directives.push(`font-src ${fontSources.join(" ")}`);const connectSources=[...new Set([...allResourceDomains,...validConnectDomains])];directives.push(`connect-src ${connectSources.join(" ")}`);directives.push("object-src 'self' data:");return directives}function buildCSPMetaTag(csp){const directives=buildCSPDirectives(csp);const content=directives.join("; ");return`<meta http-equiv="Content-Security-Policy" content="${escapeAttribute(content)}">`}var LOOPBACK_HOSTS=new Set(["localhost","127.0.0.1","[::1]"]);function validateCSPDomain(domain){if(typeof domain!=="string"||/[\s;,'"]/.test(domain))return false;if(/[?#]/.test(domain))return false;if(domain.includes("*")){const wildcard=/^(?:https|wss):\/\/\*\.(.*)$/.exec(domain);return wildcard!==null&&/^([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(wildcard[1])}try{const url=new URL(domain);if(url.protocol==="https:"||url.protocol==="wss:")return true;return(url.protocol==="http:"||url.protocol==="ws:")&&LOOPBACK_HOSTS.has(url.hostname)}catch{return false}}var reportedInvalidDomains=new Set;function sanitizeCSPDomains(domains){if(!domains)return[];const valid=[];for(const domain of domains){if(validateCSPDomain(domain)){valid.push(domain)}else if(!reportedInvalidDomains.has(domain)){reportedInvalidDomains.add(domain);console.warn(`Invalid CSP domain ignored: ${domain} (expected an https:// or wss:// origin, or http:// / ws:// on localhost)`)}}return valid}function escapeAttribute(str){return str.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">")}var SHELL_PLACEHOLDER_NAMES=["CSP","DATA","BRIDGE","CONTENT","TITLE"];var SHELL_PLACEHOLDERS={CSP:"{{CSP}}",DATA:"{{DATA}}",BRIDGE:"{{BRIDGE}}",CONTENT:"{{CONTENT}}",TITLE:"{{TITLE}}"};var REQUIRED_PLACEHOLDERS=["CONTENT"];var OPTIONAL_PLACEHOLDERS=["CSP","DATA","BRIDGE","TITLE"];function isInlineShellSource(source){return typeof source==="object"&&source!==null&&"inline"in source}function isUrlShellSource(source){return typeof source==="object"&&source!==null&&"url"in source}function isNpmShellSource(source){return typeof source==="object"&&source!==null&&"npm"in source}var PLACEHOLDER_PATTERN=new RegExp(`\\{\\{(${SHELL_PLACEHOLDER_NAMES.join("|")})\\}\\}`,"g");var VALUE_KEYS={CSP:"csp",DATA:"data",BRIDGE:"bridge",CONTENT:"content",TITLE:"title"};function applyShellTemplate(template,values){return template.replace(PLACEHOLDER_PATTERN,(_token,name)=>values[VALUE_KEYS[name]])}function validateShellTemplate(template){const found={};for(const name of SHELL_PLACEHOLDER_NAMES){found[name]=template.includes(SHELL_PLACEHOLDERS[name])}const missingRequired=REQUIRED_PLACEHOLDERS.filter(name=>!found[name]);const missingOptional=OPTIONAL_PLACEHOLDERS.filter(name=>!found[name]);return{valid:missingRequired.length===0,found,missingRequired,missingOptional}}var TRUSTED_HTML=Symbol.for("@frontmcp/uipack/trusted-html");function trustedHtml(markup){const value=String(markup);return Object.freeze({[TRUSTED_HTML]:value,toString:()=>value})}function isTrustedHtml(value){return typeof value==="object"&&value!==null&&typeof value[TRUSTED_HTML]==="string"}function interpolate(value){if(isTrustedHtml(value))return value[TRUSTED_HTML];if(Array.isArray(value))return value.map(interpolate).join("");if(value===false)return"";return escapeHtml(value)}function html(strings,...values){let markup=strings[0];for(let index=0;index<values.length;index++){markup+=interpolate(values[index])+strings[index+1]}return trustedHtml(markup)}function hasSizing(sizing){if(!sizing)return false;return sizing.preferredHeight!==void 0||sizing.minHeight!==void 0||sizing.maxHeight!==void 0||sizing.aspectRatio!==void 0||sizing.autoResize!==void 0}function buildDataInjectionScript(options){const{toolName,input,output,structuredContent,sizing,displayMode}=options;const lines=[`window.__mcpAppsEnabled = true;`,`window.__mcpToolName = ${safeJsonForScript(toolName)};`,`window.__mcpToolInput = ${safeJsonForScript(input??null)};`,`window.__mcpToolOutput = ${safeJsonForScript(output??null)};`,`window.__mcpStructuredContent = ${safeJsonForScript(structuredContent??null)};`];if(hasSizing(sizing)){lines.push(`window.__mcpWidgetSizing = ${safeJsonForScript(sizing)};`)}if(displayMode&&displayMode!=="inline"){lines.push(`window.__mcpDisplayMode = ${safeJsonForScript(displayMode)};`)}return`<script>
|
|
1206
1207
|
${lines.join("\n")}
|
|
1207
1208
|
</script>`}function buildCustomDataInjectionScript(descriptor){if(descriptor.script!==void 0){return descriptor.script}if(descriptor.globalKey!==void 0){return`<script>window[${safeJsonForScript(descriptor.globalKey)}] = ${safeJsonForScript(descriptor.value??null)};</script>`}return""}var _uniqueIdCounter=0;function createTemplateHelpers(){return{escapeHtml:str=>escapeHtml(str),formatDate:(date,format)=>{const d=date instanceof Date?date:new Date(date);if(isNaN(d.getTime()))return String(date);if(format==="iso")return d.toISOString();if(format==="date")return d.toLocaleDateString();if(format==="time")return d.toLocaleTimeString();return d.toLocaleString()},formatCurrency:(amount,currency="USD")=>{return new Intl.NumberFormat("en-US",{style:"currency",currency}).format(amount)},uniqueId:(prefix="mcp")=>{return`${prefix}-${++_uniqueIdCounter}`},jsonEmbed:data=>safeJsonForScript(data),html,trustedHtml}}function sanitizeCssValue(value){return value.replace(/[<>{};]/g,"").trim()}function toCssLength(value){return typeof value==="number"?`${value}px`:sanitizeCssValue(value)}function buildSizingStyleTag(sizing){if(!hasSizing(sizing))return"";const hasCssSizing=sizing.preferredHeight!==void 0||sizing.minHeight!==void 0||sizing.maxHeight!==void 0||sizing.aspectRatio!==void 0;if(!hasCssSizing)return"";const rootRules=[];const docRules=["margin: 0;"];if(sizing.preferredHeight!==void 0){const h=toCssLength(sizing.preferredHeight);docRules.push(`height: ${h};`);rootRules.push(`min-height: ${h};`)}if(sizing.minHeight!==void 0){const mh=toCssLength(sizing.minHeight);docRules.push(`min-height: ${mh};`);rootRules.push(`min-height: ${mh};`)}if(sizing.maxHeight!==void 0){const mx=toCssLength(sizing.maxHeight);docRules.push(`max-height: ${mx};`);rootRules.push(`max-height: ${mx};`)}if(sizing.aspectRatio!==void 0){const ar=typeof sizing.aspectRatio==="number"?String(sizing.aspectRatio):sanitizeCssValue(sizing.aspectRatio);if(ar)rootRules.push(`aspect-ratio: ${ar};`)}const parts=[`html, body { ${docRules.join(" ")} }`];if(rootRules.length>0){parts.push(`#root { ${rootRules.join(" ")} }`)}return`<style>${parts.join("\n")}</style>`}function resolveDataInjectionScript(args){if(args.dataInjection){return buildCustomDataInjectionScript(args.dataInjection)}return buildDataInjectionScript({toolName:args.toolName,input:args.input,output:args.output,structuredContent:args.structuredContent,sizing:args.sizing,displayMode:args.displayMode})}function buildShell(content,config){const{toolName,csp,withShell=true,input,output,structuredContent,includeBridge=true,title,sizing,displayMode}=config;const{customShell,dataInjection}=config;const dataScript=resolveDataInjectionScript({dataInjection,toolName,input,output,structuredContent,sizing,displayMode});if(!withShell){const html3=`${dataScript}
|
|
1208
1209
|
${content}`;return{html:html3,hash:simpleHash(html3),size:Buffer.byteLength(html3,"utf-8")}}if(customShell){return buildCustomShell(content,customShell,{csp,toolName,input,output,structuredContent,includeBridge,title,sizing,displayMode,dataInjection})}const headParts=['<meta charset="UTF-8">','<meta name="viewport" content="width=device-width, initial-scale=1.0">'];if(title){headParts.push(`<title>${escapeHtmlForTag(title)}</title>`)}headParts.push(buildCSPMetaTag(csp));headParts.push(dataScript);const sizingStyle=buildSizingStyleTag(sizing);if(sizingStyle){headParts.push(sizingStyle)}if(includeBridge){const bridgeScript=generateBridgeIIFE({minify:true});headParts.push(`<script>${bridgeScript}</script>`)}const html2=`<!DOCTYPE html>
|
|
@@ -1247,7 +1248,7 @@ ${sizingStyle}`:dataScript;let bridgeHtml="";if(ctx.includeBridge){const bridgeS
|
|
|
1247
1248
|
note.textContent = 'This widget loads from ' + widgetOrigin + ', which this host does not allow.';
|
|
1248
1249
|
frame.replaceWith(note);
|
|
1249
1250
|
});
|
|
1250
|
-
})();`}function escapeAttribute2(value){return value.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">")}function escapeText(value){return value.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}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}var DEFAULT_TIMEOUT_MS=1e4;var templateCache=new Map;async function resolveShellTemplate(source,options){if(isInlineShellSource(source)){return resolveInline(source.inline)}if(isUrlShellSource(source)){const cacheKey=`url:${source.url}`;if(!options?.noCache){const cached=templateCache.get(cacheKey);if(cached)return cached}const template=await fetchWithTimeout(source.url,source.timeout??DEFAULT_TIMEOUT_MS);const resolved=buildResolved(template,"url");if(!options?.noCache){templateCache.set(cacheKey,resolved)}return resolved}if(isNpmShellSource(source)){const specifier=source.version?`${source.npm}@${source.version}`:source.npm;const cacheKey=`npm:${specifier}`;if(!options?.noCache){const cached=templateCache.get(cacheKey);if(cached)return cached}const template=await resolveNpmTemplate(source,specifier,options?.resolver);const resolved=buildResolved(template,"npm");if(!options?.noCache){templateCache.set(cacheKey,resolved)}return resolved}throw new Error('Invalid custom shell source: must have "inline", "url", or "npm" property')}function clearShellTemplateCache(){templateCache.clear()}function resolveInline(template){return buildResolved(template,"inline")}function buildResolved(template,sourceType){const validation=validateShellTemplate(template);if(!validation.valid){throw new Error(`Custom shell template is missing required placeholder(s): ${validation.missingRequired.map(n=>`{{${n}}}`).join(", ")}`)}return{template,sourceType,validation}}async function fetchWithTimeout(url,timeoutMs){const controller=new AbortController;const timer=setTimeout(()=>controller.abort(),timeoutMs);try{const response=await fetch(url,{signal:controller.signal});if(!response.ok){throw new Error(`Failed to fetch shell template from ${url}: HTTP ${response.status}`)}return await response.text()}catch(err){if(err instanceof Error&&err.name==="AbortError"){throw new Error(`Shell template fetch timed out after ${timeoutMs}ms: ${url}`)}throw err}finally{clearTimeout(timer)}}async function resolveNpmTemplate(source,specifier,resolver){const cdnUrl=resolveNpmToCdnUrl(specifier,resolver);const moduleText=await fetchWithTimeout(cdnUrl,DEFAULT_TIMEOUT_MS);return extractTemplateFromModule(moduleText,source.exportName)}function resolveNpmToCdnUrl(specifier,resolver){if(resolver){const resolved=resolver.resolve(specifier);if(resolved){return resolved.value}}return`https://esm.sh/${specifier}`}function extractTemplateFromModule(moduleText,exportName){if(exportName&&exportName!=="default"){const namedPattern=new RegExp(`export\\s+(?:const|let|var)\\s+${escapeRegExp3(exportName)}\\s*=\\s*\`([\\s\\S]*?)\``);const namedMatch=moduleText.match(namedPattern);if(namedMatch){return namedMatch[1]}throw new Error(`Could not extract named export "${exportName}" from npm shell package. The package must export a template literal string.`)}const defaultPattern=/export\s+default\s+`([\s\S]*?)`/;const defaultMatch=moduleText.match(defaultPattern);if(defaultMatch){return defaultMatch[1]}throw new Error("Could not extract default export from npm shell package. The package must export a template literal string (e.g., export default `<html>...</html>`).")}function escapeRegExp3(str){return str.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function isNpmSource(source){return typeof source==="object"&&source!==null&&"npm"in source}function isFileSource(source){return typeof source==="object"&&source!==null&&"file"in source}function isImportSource(source){return typeof source==="object"&&source!==null&&"import"in source}function isFunctionSource(source){return typeof source==="function"}var FRONTMCP_META_KEY="__frontmcp_meta";function isFrontmcpUiResolvable(...candidatePaths){try{const nodeFs=__require("fs");const nodePath=__require("path");const ORG="@frontmcp";const PKG="ui";for(const candidate of candidatePaths){let dir=candidate;while(true){const pkgJson=nodePath.join(dir,"node_modules",ORG,PKG,"package.json");if(nodeFs.existsSync(pkgJson))return true;const parent=nodePath.dirname(dir);if(parent===dir)break;dir=parent}}return false}catch{return false}}function loadEsbuild(filename){try{return __require("esbuild")}catch(err){if(!isMissingEsbuild(err))throw err;const subject=filename?`FileSource widget "${filename}"`:"A FileSource widget";throw new Error(`${subject} needs esbuild, which is not installed. @frontmcp/uipack loads esbuild on demand to bundle FileSource widgets (.tsx/.jsx) when the tool is called, so it must be installed where the server runs: \`npm install esbuild\` (in "dependencies", not "devDependencies"). Projects created with \`frontmcp create\` already get it through the \`frontmcp\` package.`,{cause:err})}}function isMissingEsbuild(err){if(!(err instanceof Error))return false;return err.code==="MODULE_NOT_FOUND"&&/Cannot find module ['"]esbuild['"]/.test(err.message)}function transpileReactSource(source,filename){const esbuild=loadEsbuild(filename);const loader=filename?.endsWith(".tsx")?"tsx":"jsx";const result=esbuild.transformSync(source,{loader,jsx:"transform",jsxFactory:"React.createElement",jsxFragment:"React.Fragment",format:"esm",target:"es2020",define:{"process.env.NODE_ENV":'"production"'}});return result.code}var FIRST_RENDER=` // Render immediately (component shows loading state until data arrives)
|
|
1251
|
+
})();`}function escapeAttribute2(value){return value.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">")}function escapeText(value){return value.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}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}var DEFAULT_TIMEOUT_MS=1e4;var templateCache=new Map;async function resolveShellTemplate(source,options){if(isInlineShellSource(source)){return resolveInline(source.inline)}if(isUrlShellSource(source)){const cacheKey=`url:${source.url}`;if(!options?.noCache){const cached=templateCache.get(cacheKey);if(cached)return cached}const template=await fetchWithTimeout(source.url,source.timeout??DEFAULT_TIMEOUT_MS);const resolved=buildResolved(template,"url");if(!options?.noCache){templateCache.set(cacheKey,resolved)}return resolved}if(isNpmShellSource(source)){const specifier=source.version?`${source.npm}@${source.version}`:source.npm;const cacheKey=`npm:${specifier}`;if(!options?.noCache){const cached=templateCache.get(cacheKey);if(cached)return cached}const template=await resolveNpmTemplate(source,specifier,options?.resolver);const resolved=buildResolved(template,"npm");if(!options?.noCache){templateCache.set(cacheKey,resolved)}return resolved}throw new Error('Invalid custom shell source: must have "inline", "url", or "npm" property')}function clearShellTemplateCache(){templateCache.clear()}function resolveInline(template){return buildResolved(template,"inline")}function buildResolved(template,sourceType){const validation=validateShellTemplate(template);if(!validation.valid){throw new Error(`Custom shell template is missing required placeholder(s): ${validation.missingRequired.map(n=>`{{${n}}}`).join(", ")}`)}return{template,sourceType,validation}}async function fetchWithTimeout(url,timeoutMs){const controller=new AbortController;const timer=setTimeout(()=>controller.abort(),timeoutMs);try{const response=await fetch(url,{signal:controller.signal});if(!response.ok){throw new Error(`Failed to fetch shell template from ${url}: HTTP ${response.status}`)}return await response.text()}catch(err){if(err instanceof Error&&err.name==="AbortError"){throw new Error(`Shell template fetch timed out after ${timeoutMs}ms: ${url}`)}throw err}finally{clearTimeout(timer)}}async function resolveNpmTemplate(source,specifier,resolver){const cdnUrl=resolveNpmToCdnUrl(specifier,resolver);const moduleText=await fetchWithTimeout(cdnUrl,DEFAULT_TIMEOUT_MS);return extractTemplateFromModule(moduleText,source.exportName)}function resolveNpmToCdnUrl(specifier,resolver){if(resolver){const resolved=resolver.resolve(specifier);if(resolved){return resolved.value}}return`https://esm.sh/${specifier}`}function extractTemplateFromModule(moduleText,exportName){if(exportName&&exportName!=="default"){const namedPattern=new RegExp(`export\\s+(?:const|let|var)\\s+${escapeRegExp3(exportName)}\\s*=\\s*\`([\\s\\S]*?)\``);const namedMatch=moduleText.match(namedPattern);if(namedMatch){return namedMatch[1]}throw new Error(`Could not extract named export "${exportName}" from npm shell package. The package must export a template literal string.`)}const defaultPattern=/export\s+default\s+`([\s\S]*?)`/;const defaultMatch=moduleText.match(defaultPattern);if(defaultMatch){return defaultMatch[1]}throw new Error("Could not extract default export from npm shell package. The package must export a template literal string (e.g., export default `<html>...</html>`).")}function escapeRegExp3(str){return str.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function isNpmSource(source){return typeof source==="object"&&source!==null&&"npm"in source}function isFileSource(source){return typeof source==="object"&&source!==null&&"file"in source}function isImportSource(source){return typeof source==="object"&&source!==null&&"import"in source}function isFunctionSource(source){return typeof source==="function"}var FRONTMCP_META_KEY="__frontmcp_meta";function isFrontmcpUiResolvable(...candidatePaths){try{const nodeFs=__require("fs");const nodePath=__require("path");const ORG="@frontmcp";const PKG="ui";for(const candidate of candidatePaths){let dir=candidate;while(true){const pkgJson=nodePath.join(dir,"node_modules",ORG,PKG,"package.json");if(nodeFs.existsSync(pkgJson))return true;const parent=nodePath.dirname(dir);if(parent===dir)break;dir=parent}}return false}catch{return false}}function loadEsbuild(filename){try{return __require("esbuild")}catch(err){if(!isMissingEsbuild(err))throw err;const subject=filename?`FileSource widget "${filename}"`:"A FileSource widget";throw new Error(`${subject} needs esbuild, which is not installed. @frontmcp/uipack loads esbuild on demand to bundle FileSource widgets (.tsx/.jsx) when the tool is called, so it must be installed where the server runs: \`npm install esbuild\` (in "dependencies", not "devDependencies"). Projects created with \`frontmcp create\` already get it through the \`frontmcp\` package.`,{cause:err})}}function isMissingEsbuild(err){if(!(err instanceof Error))return false;return err.code==="MODULE_NOT_FOUND"&&/Cannot find module ['"]esbuild['"]/.test(err.message)}function transpileReactSource(source,filename){const esbuild=loadEsbuild(filename);const loader=filename?.endsWith(".tsx")?"tsx":"jsx";const result=esbuild.transformSync(source,{loader,jsx:"transform",jsxFactory:"React.createElement",jsxFragment:"React.Fragment",format:"esm",target:"es2020",define:{"process.env.NODE_ENV":'"production"'}});return result.code}var FIRST_RENDER=` // Render immediately (component shows loading state until data arrives)
|
|
1251
1252
|
__render(undefined);
|
|
1252
1253
|
`;var INJECTED_DATA_RENDER=` // 2. Try injected data globals (null: the page carries no call's data, e.g. compiled at startup)
|
|
1253
1254
|
if (__hasData(window.__mcpToolOutput) && window.__mcpToolOutput !== null) { __render(window.__mcpToolOutput); }
|
|
@@ -1335,7 +1336,7 @@ if (__root) {
|
|
|
1335
1336
|
|
|
1336
1337
|
${fence}html
|
|
1337
1338
|
${html2}
|
|
1338
|
-
${fence}`}function isUIRenderFailure(result){if(typeof result!=="object"||result===null){return false}const rec=result;return typeof rec["reason"]==="string"&&!("meta"in rec)}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=`
|
|
1339
|
+
${fence}`}function isUIRenderFailure(result){if(typeof result!=="object"||result===null){return false}const rec=result;return typeof rec["reason"]==="string"&&!("meta"in rec)}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=`
|
|
1339
1340
|
<canvas id="chart" style="max-width:100%;max-height:80vh;"></canvas>
|
|
1340
1341
|
<script type="module">
|
|
1341
1342
|
import Chart from '${CHART_JS_CDN}';
|
|
@@ -1359,9 +1360,19 @@ for (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i);
|
|
|
1359
1360
|
|
|
1360
1361
|
const pdf = await pdfjsLib.getDocument({ data: bytes }).promise;
|
|
1361
1362
|
const container = document.getElementById('pdf-container');
|
|
1363
|
+
let pixelsLeft = ${PDF_MAX_TOTAL_PIXELS};
|
|
1362
1364
|
for (let i = 1; i <= pdf.numPages; i++) {
|
|
1363
1365
|
const page = await pdf.getPage(i);
|
|
1364
|
-
const
|
|
1366
|
+
const unscaled = page.getViewport({ scale: 1 });
|
|
1367
|
+
const scale = Math.min(1.5, Math.sqrt(${PDF_MAX_PAGE_PIXELS} / (unscaled.width * unscaled.height)));
|
|
1368
|
+
const viewport = page.getViewport({ scale });
|
|
1369
|
+
pixelsLeft -= Math.ceil(viewport.width) * Math.ceil(viewport.height);
|
|
1370
|
+
if (pixelsLeft < 0) {
|
|
1371
|
+
const note = document.createElement('p');
|
|
1372
|
+
note.textContent = 'Pages ' + i + ' to ' + pdf.numPages + ' are not shown: the document is too large to draw.';
|
|
1373
|
+
container.appendChild(note);
|
|
1374
|
+
break;
|
|
1375
|
+
}
|
|
1365
1376
|
const canvas = document.createElement('canvas');
|
|
1366
1377
|
canvas.width = viewport.width;
|
|
1367
1378
|
canvas.height = viewport.height;
|
|
@@ -1369,9 +1380,9 @@ for (let i = 1; i <= pdf.numPages; i++) {
|
|
|
1369
1380
|
container.appendChild(canvas);
|
|
1370
1381
|
await page.render({ canvasContext: canvas.getContext('2d'), viewport }).promise;
|
|
1371
1382
|
}
|
|
1372
|
-
</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
|
|
1383
|
+
</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)}
|
|
1373
1384
|
</code></pre>`;const highlighted=language?highlight(code,language):void 0;const languageClass=language?` language-${language}`:"";return`<pre><code class="hljs${languageClass}">${highlighted??escapeHtml(code)}
|
|
1374
|
-
</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>
|
|
1385
|
+
</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>
|
|
1375
1386
|
${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=`
|
|
1376
1387
|
${bridgeScript}
|
|
1377
1388
|
<div id="root">
|
package/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/uipack",
|
|
3
|
-
"version": "1.12.
|
|
3
|
+
"version": "1.12.1",
|
|
4
4
|
"description": "React-free core that builds FrontMCP widget pages: HTML shell with CSP and bridge, template rendering, CDN import resolution",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://frontmcp.dev/reference/ui/components#frontmcpuipack",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"typescript": "^5.9.3"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
68
|
-
"@frontmcp/lazy-zod": "1.12.
|
|
68
|
+
"@frontmcp/lazy-zod": "1.12.1",
|
|
69
69
|
"@mdx-js/mdx": "^3.0.0",
|
|
70
70
|
"esbuild": ">=0.27.0 <1",
|
|
71
71
|
"highlight.js": "^11.0.0",
|
package/esm/resolver/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
var DEFAULT_CDN_REGISTRY={react:{packageName:"react",defaultVersion:"19.2.4",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/react/19.2.4/umd/react.production.min.js",global:"React",crossorigin:"anonymous"},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/react@19.2.4/umd/react.production.min.js",global:"React",crossorigin:"anonymous"},unpkg:{url:"https://unpkg.com/react@19.2.4/umd/react.production.min.js",global:"React",crossorigin:"anonymous"},"esm.sh":{url:"https://esm.sh/react@19.2.4",esm:true,crossorigin:"anonymous"}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"A JavaScript library for building user interfaces",homepage:"https://react.dev",license:"MIT"}},"react-dom":{packageName:"react-dom",defaultVersion:"19.2.4",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/react-dom/19.2.4/umd/react-dom.production.min.js",global:"ReactDOM",crossorigin:"anonymous",peerDependencies:["react"]},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/react-dom@19.2.4/umd/react-dom.production.min.js",global:"ReactDOM",crossorigin:"anonymous",peerDependencies:["react"]},unpkg:{url:"https://unpkg.com/react-dom@19.2.4/umd/react-dom.production.min.js",global:"ReactDOM",crossorigin:"anonymous",peerDependencies:["react"]},"esm.sh":{url:"https://esm.sh/react-dom@19.2.4",esm:true,crossorigin:"anonymous",peerDependencies:["react"]}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"React package for working with the DOM",homepage:"https://react.dev",license:"MIT"}},"chart.js":{packageName:"chart.js",defaultVersion:"4.5.1",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.5.1/chart.umd.min.js",global:"Chart",crossorigin:"anonymous"},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/chart.js@4.5.1/dist/chart.umd.min.js",global:"Chart",crossorigin:"anonymous"},unpkg:{url:"https://unpkg.com/chart.js@4.5.1/dist/chart.umd.min.js",global:"Chart",crossorigin:"anonymous"}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"Simple yet flexible JavaScript charting library",homepage:"https://www.chartjs.org",license:"MIT"}},d3:{packageName:"d3",defaultVersion:"7.9.0",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js",integrity:"sha512-vc58qvvBdrDR4etbxMdlTt4GBQk1qjvyORR2nrsPsFPyrs+/u5c3+1Ct6upOgdZoIl7eq6k3a1UPDSNAQi/32A==",global:"d3",crossorigin:"anonymous"},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/d3@7.9.0/dist/d3.min.js",global:"d3",crossorigin:"anonymous"},unpkg:{url:"https://unpkg.com/d3@7.9.0/dist/d3.min.js",global:"d3",crossorigin:"anonymous"}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"Data-Driven Documents",homepage:"https://d3js.org",license:"ISC"}},lodash:{packageName:"lodash",defaultVersion:"4.17.21",providers:{cloudflare:{url:"https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js",integrity:"sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==",global:"_",crossorigin:"anonymous"},jsdelivr:{url:"https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js",global:"_",crossorigin:"anonymous"},unpkg:{url:"https://unpkg.com/lodash@4.17.21/lodash.min.js",global:"_",crossorigin:"anonymous"}},preferredProviders:["esm.sh","cloudflare","jsdelivr","unpkg"],metadata:{description:"A modern JavaScript utility library",homepage:"https://lodash.com",license:"MIT"}}};function lookupPackage(packageName,registry=DEFAULT_CDN_REGISTRY){return registry[packageName]}function getPackageCDNUrl(packageName,providerOrder=["esm.sh","cloudflare","jsdelivr","unpkg"],registry=DEFAULT_CDN_REGISTRY){const entry=lookupPackage(packageName,registry);if(!entry)return void 0;for(const provider of providerOrder){const config=entry.providers[provider];if(config?.url){return config.url}}for(const provider of Object.keys(entry.providers)){const config=entry.providers[provider];if(config?.url){return config.url}}return void 0}function getRegisteredPackages(registry=DEFAULT_CDN_REGISTRY){return Object.keys(registry)}function isPackageRegistered(packageName,registry=DEFAULT_CDN_REGISTRY){return packageName in registry}function mergeRegistries(customRegistry){return{...DEFAULT_CDN_REGISTRY,...customRegistry}}function getPackagePeerDependencies(packageName,registry=DEFAULT_CDN_REGISTRY){const entry=lookupPackage(packageName,registry);if(!entry)return[];for(const provider of Object.keys(entry.providers)){const config=entry.providers[provider];if(config?.peerDependencies){return config.peerDependencies}}return[]}var IMPORT_PATTERNS={named:/import\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g,default:/import\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,namespace:/import\s*\*\s*as\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,sideEffect:/import\s*['"]([^'"]+)['"]/g,dynamic:/(?:await\s+)?import\s*\(\s*['"]([^'"]+)['"]\s*\)/g,defaultAndNamed:/import\s+(\w+)\s*,\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g,defaultAndNamespace:/import\s+(\w+)\s*,\s*\*\s*as\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,reExport:/export\s*\{[^}]+\}\s*from\s*['"]([^'"]+)['"]/g,reExportAll:/export\s*\*\s*from\s*['"]([^'"]+)['"]/g};function parseNamedImports(namedString){return namedString.split(",").map(s=>s.trim()).filter(s=>s.length>0).map(s=>{const asMatch=s.match(/^(\w+)\s+as\s+\w+$/);return asMatch?asMatch[1]:s})}function isRelativeImport(specifier){return specifier.startsWith("./")||specifier.startsWith("../")||specifier.startsWith("/")}function isExternalImport(specifier){return!isRelativeImport(specifier)&&!specifier.startsWith("#")}function getPackageName(specifier){if(specifier.startsWith("@")){const parts=specifier.split("/");if(parts.length>=2){return`${parts[0]}/${parts[1]}`}return specifier}const firstSlash=specifier.indexOf("/");return firstSlash===-1?specifier:specifier.slice(0,firstSlash)}function getLineNumber(source,index){let line=1;for(let i=0;i<index&&i<source.length;i++){if(source[i]==="\n"){line++}}return line}function getColumnNumber(source,index){let column=0;for(let i=index-1;i>=0&&source[i]!=="\n";i--){column++}return column}function parseImports(source){const imports=[];const seenStatements=new Set;const addImport=imp=>{const key=`${imp.type}:${imp.specifier}:${imp.statement}`;if(!seenStatements.has(key)){seenStatements.add(key);imports.push(imp)}};let match;const defaultAndNamedRegex=new RegExp(IMPORT_PATTERNS.defaultAndNamed.source,"g");while((match=defaultAndNamedRegex.exec(source))!==null){const[statement,defaultName,namedString,specifier]=match;addImport({statement,specifier,type:"default",defaultImport:defaultName,namedImports:parseNamedImports(namedString),line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const defaultAndNamespaceRegex=new RegExp(IMPORT_PATTERNS.defaultAndNamespace.source,"g");while((match=defaultAndNamespaceRegex.exec(source))!==null){const[statement,defaultName,namespaceName,specifier]=match;addImport({statement,specifier,type:"default",defaultImport:defaultName,namespaceImport:namespaceName,line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const namedRegex=new RegExp(IMPORT_PATTERNS.named.source,"g");while((match=namedRegex.exec(source))!==null){const[statement,namedString,specifier]=match;addImport({statement,specifier,type:"named",namedImports:parseNamedImports(namedString),line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const defaultRegex=new RegExp(IMPORT_PATTERNS.default.source,"g");while((match=defaultRegex.exec(source))!==null){const[statement,defaultName,specifier]=match;const afterMatch=source.slice(match.index+match[0].length-specifier.length-2);if(afterMatch.startsWith(","))continue;addImport({statement,specifier,type:"default",defaultImport:defaultName,line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const namespaceRegex=new RegExp(IMPORT_PATTERNS.namespace.source,"g");while((match=namespaceRegex.exec(source))!==null){const[statement,namespaceName,specifier]=match;addImport({statement,specifier,type:"namespace",namespaceImport:namespaceName,line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const sideEffectRegex=new RegExp(IMPORT_PATTERNS.sideEffect.source,"g");while((match=sideEffectRegex.exec(source))!==null){const[statement,specifier]=match;const beforeMatch=source.slice(Math.max(0,match.index-50),match.index);if(beforeMatch.includes("from"))continue;addImport({statement,specifier,type:"side-effect",line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const dynamicRegex=new RegExp(IMPORT_PATTERNS.dynamic.source,"g");while((match=dynamicRegex.exec(source))!==null){const[statement,specifier]=match;addImport({statement,specifier,type:"dynamic",line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const reExportRegex=new RegExp(IMPORT_PATTERNS.reExport.source,"g");while((match=reExportRegex.exec(source))!==null){const[statement,specifier]=match;addImport({statement,specifier,type:"named",line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const reExportAllRegex=new RegExp(IMPORT_PATTERNS.reExportAll.source,"g");while((match=reExportAllRegex.exec(source))!==null){const[statement,specifier]=match;addImport({statement,specifier,type:"namespace",line:getLineNumber(source,match.index),column:getColumnNumber(source,match.index)})}const externalImports=imports.filter(imp=>isExternalImport(imp.specifier));const relativeImports=imports.filter(imp=>isRelativeImport(imp.specifier));const externalPackages=[...new Set(externalImports.map(imp=>getPackageName(imp.specifier)))];return{imports,externalImports,relativeImports,externalPackages}}function extractExternalPackages(source){return parseImports(source).externalPackages}var DEFAULT_FALLBACK_CDN="https://esm.sh";function createResolverWithOverrides(overrides,baseOptions){const base=createEsmShResolver(baseOptions);return{overrides,resolve(specifier,context){if(overrides[specifier]){return{value:overrides[specifier],type:"url"}}for(const[prefix,url]of Object.entries(overrides)){if(specifier.startsWith(prefix+"/")){const subpath=specifier.slice(prefix.length);return{value:url+subpath,type:"url"}}}return base.resolve(specifier,context)}}}function createEsmShResolver(options={}){const{fallbackCdnBase=DEFAULT_FALLBACK_CDN,registry=DEFAULT_CDN_REGISTRY,providerOrder=["esm.sh","cloudflare","jsdelivr","unpkg"]}=options;return{resolve(specifier,_context){if(specifier.startsWith("./")||specifier.startsWith("../")||specifier.startsWith("/")){return null}if(specifier.startsWith("node:")||specifier.startsWith("#")){return null}const pkgName=getPackageName(specifier);const entry=lookupPackage(pkgName,registry);if(entry){for(const provider of providerOrder){const config=entry.providers[provider];if(config?.url){const subpath=specifier.slice(pkgName.length);if(subpath&&config.url.includes("esm.sh/")){return{value:config.url+subpath,type:"url",integrity:config.integrity}}if(subpath){return{value:`${fallbackCdnBase}/${specifier}`,type:"url"}}if(config.global&&!config.esm){return{value:config.url,type:"url",integrity:config.integrity}}return{value:config.url,type:"url",integrity:config.integrity}}}}return{value:`${fallbackCdnBase}/${specifier}`,type:"url"}}}}function escapeHtmlAttr(str){return str.replace(/&/g,"&").replace(/"/g,""")}function createImportMapFromResolved(resolved){const imports={};const integrity={};for(const[specifier,res]of Object.entries(resolved)){if(res.type==="url"){imports[specifier]=res.value;if(res.integrity){integrity[res.value]=res.integrity}}}return{imports,integrity:Object.keys(integrity).length>0?integrity:void 0}}function createImportMap(dependencies){const imports={};const integrity={};for(const dep of dependencies){imports[dep.packageName]=dep.cdnUrl;if(dep.integrity){integrity[dep.cdnUrl]=dep.integrity}}return{imports,integrity:Object.keys(integrity).length>0?integrity:void 0}}function mergeImportMaps(...maps){const imports={};const integrity={};const scopes={};for(const map of maps){Object.assign(imports,map.imports);if(map.integrity){Object.assign(integrity,map.integrity)}if(map.scopes){for(const[scope,mappings]of Object.entries(map.scopes)){scopes[scope]={...scopes[scope],...mappings}}}}return{imports,integrity:Object.keys(integrity).length>0?integrity:void 0,scopes:Object.keys(scopes).length>0?scopes:void 0}}function generateImportMapScriptTag(map){const json=JSON.stringify(map,null,2).replace(/<\//g,"<\\/");return`<script type="importmap">
|
|
2
2
|
${json}
|
|
3
|
-
</script>`}function generateImportMapScriptTagMinified(map){const json=JSON.stringify(map).replace(/<\//g,"<\\/");return`<script type="importmap">${json}</script>`}function generateCDNScriptTags(dependencies){return dependencies.filter(dep=>!dep.esm).map(dep=>{const attrs=[`src="${escapeHtmlAttr(dep.cdnUrl)}"`];if(dep.integrity){attrs.push(`integrity="${escapeHtmlAttr(dep.integrity)}"`)}attrs.push('crossorigin="anonymous"');return`<script ${attrs.join(" ")}></script>`})}function generateDependencyHTML(dependencies,options={}){const{minify=false}=options;const parts=[];const importMap=createImportMap(dependencies);const importMapTag=minify?generateImportMapScriptTagMinified(importMap):generateImportMapScriptTag(importMap);parts.push(importMapTag);const umdTags=generateCDNScriptTags(dependencies);parts.push(...umdTags);return parts.join(minify?"":"\n")}function validateImportMap(map){const errors=[];if(typeof map!=="object"||map===null){return{valid:false,errors:["Import map must be an object"]}}const obj=map;if(!obj["imports"]){errors.push('Import map must have an "imports" field')}else if(typeof obj["imports"]!=="object"||obj["imports"]===null){errors.push('"imports" must be an object')}else{const imports=obj["imports"];for(const[key,value]of Object.entries(imports)){if(typeof value!=="string"){errors.push(`Import "${key}" must map to a string URL`)}else if(!value.startsWith("https://")){errors.push(`Import "${key}" URL must use HTTPS: ${value}`)}}}if(obj["integrity"]!==void 0){if(typeof obj["integrity"]!=="object"||obj["integrity"]===null){errors.push('"integrity" must be an object')}else{const integrity=obj["integrity"];for(const[url,hash]of Object.entries(integrity)){if(typeof hash!=="string"){errors.push(`Integrity for "${url}" must be a string`)}else if(!hash.match(/^sha(256|384|512)-/)){errors.push(`Invalid integrity hash format for "${url}": ${hash}`)}}}}return{valid:errors.length===0,errors}}function rewriteImports(source,options={}){const{resolver=createEsmShResolver(),skipPackages=[],overrides={}}=options;const skipSet=new Set(skipPackages);const rewrites=new Map;const fallbackPackages=[];const parsed=parseImports(source);const specifierMap=new Map;for(const imp of parsed.externalImports){const specifier=imp.specifier;if(specifierMap.has(specifier))continue;if(specifier.startsWith("node:"))continue;const pkgName=getPackageName(specifier);if(skipSet.has(pkgName))continue;if(overrides[specifier]){specifierMap.set(specifier,overrides[specifier]);continue}if(overrides[pkgName]){const subpath=specifier.slice(pkgName.length);specifierMap.set(specifier,overrides[pkgName]+subpath);continue}const resolved=resolver.resolve(specifier);if(resolved&&resolved.type==="url"){specifierMap.set(specifier,resolved.value)}}let code=source;for(const[specifier,cdnUrl]of specifierMap){const escaped=escapeRegExp(specifier);const singleQuotePattern=new RegExp(`((?:import|export)\\s
|
|
3
|
+
</script>`}function generateImportMapScriptTagMinified(map){const json=JSON.stringify(map).replace(/<\//g,"<\\/");return`<script type="importmap">${json}</script>`}function generateCDNScriptTags(dependencies){return dependencies.filter(dep=>!dep.esm).map(dep=>{const attrs=[`src="${escapeHtmlAttr(dep.cdnUrl)}"`];if(dep.integrity){attrs.push(`integrity="${escapeHtmlAttr(dep.integrity)}"`)}attrs.push('crossorigin="anonymous"');return`<script ${attrs.join(" ")}></script>`})}function generateDependencyHTML(dependencies,options={}){const{minify=false}=options;const parts=[];const importMap=createImportMap(dependencies);const importMapTag=minify?generateImportMapScriptTagMinified(importMap):generateImportMapScriptTag(importMap);parts.push(importMapTag);const umdTags=generateCDNScriptTags(dependencies);parts.push(...umdTags);return parts.join(minify?"":"\n")}function validateImportMap(map){const errors=[];if(typeof map!=="object"||map===null){return{valid:false,errors:["Import map must be an object"]}}const obj=map;if(!obj["imports"]){errors.push('Import map must have an "imports" field')}else if(typeof obj["imports"]!=="object"||obj["imports"]===null){errors.push('"imports" must be an object')}else{const imports=obj["imports"];for(const[key,value]of Object.entries(imports)){if(typeof value!=="string"){errors.push(`Import "${key}" must map to a string URL`)}else if(!value.startsWith("https://")){errors.push(`Import "${key}" URL must use HTTPS: ${value}`)}}}if(obj["integrity"]!==void 0){if(typeof obj["integrity"]!=="object"||obj["integrity"]===null){errors.push('"integrity" must be an object')}else{const integrity=obj["integrity"];for(const[url,hash]of Object.entries(integrity)){if(typeof hash!=="string"){errors.push(`Integrity for "${url}" must be a string`)}else if(!hash.match(/^sha(256|384|512)-/)){errors.push(`Invalid integrity hash format for "${url}": ${hash}`)}}}}return{valid:errors.length===0,errors}}function rewriteImports(source,options={}){const{resolver=createEsmShResolver(),skipPackages=[],overrides={}}=options;const skipSet=new Set(skipPackages);const rewrites=new Map;const fallbackPackages=[];const parsed=parseImports(source);const specifierMap=new Map;for(const imp of parsed.externalImports){const specifier=imp.specifier;if(specifierMap.has(specifier))continue;if(specifier.startsWith("node:"))continue;const pkgName=getPackageName(specifier);if(skipSet.has(pkgName))continue;if(overrides[specifier]){specifierMap.set(specifier,overrides[specifier]);continue}if(overrides[pkgName]){const subpath=specifier.slice(pkgName.length);specifierMap.set(specifier,overrides[pkgName]+subpath);continue}const resolved=resolver.resolve(specifier);if(resolved&&resolved.type==="url"){specifierMap.set(specifier,resolved.value)}}let code=source;for(const[specifier,cdnUrl]of specifierMap){const escaped=escapeRegExp(specifier);const singleQuotePattern=new RegExp(`((?:import|export)\\s(?:[^'"]*\\s)?from\\s+)'${escaped}'`,"g");const doubleQuotePattern=new RegExp(`((?:import|export)\\s(?:[^'"]*\\s)?from\\s+)"${escaped}"`,"g");const dynamicSinglePattern=new RegExp(`(import\\s*\\(\\s*)'${escaped}'`,"g");const dynamicDoublePattern=new RegExp(`(import\\s*\\(\\s*)"${escaped}"`,"g");const sideEffectSinglePattern=new RegExp(`(import\\s+)'${escaped}'`,"g");const sideEffectDoublePattern=new RegExp(`(import\\s+)"${escaped}"`,"g");const beforeLength=code.length;code=code.replace(singleQuotePattern,`$1'${cdnUrl}'`).replace(doubleQuotePattern,`$1"${cdnUrl}"`).replace(dynamicSinglePattern,`$1'${cdnUrl}'`).replace(dynamicDoublePattern,`$1"${cdnUrl}"`).replace(sideEffectSinglePattern,`$1'${cdnUrl}'`).replace(sideEffectDoublePattern,`$1"${cdnUrl}"`);if(code.length!==beforeLength||code!==source){rewrites.set(specifier,cdnUrl)}}return{code,rewrittenCount:rewrites.size,rewrites,fallbackPackages}}function escapeRegExp(str){return str.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}export{DEFAULT_CDN_REGISTRY,createEsmShResolver,createImportMap,createImportMapFromResolved,createResolverWithOverrides,extractExternalPackages,generateCDNScriptTags,generateDependencyHTML,generateImportMapScriptTag,generateImportMapScriptTagMinified,getPackageCDNUrl,getPackageName,getPackagePeerDependencies,getRegisteredPackages,isPackageRegistered,lookupPackage,mergeImportMaps,mergeRegistries,parseImports,rewriteImports,validateImportMap};
|