@frontmcp/uipack 0.6.3 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CLAUDE.md +0 -14
  2. package/adapters/index.js +50 -47
  3. package/adapters/platform-meta.d.ts.map +1 -1
  4. package/adapters/response-builder.d.ts +16 -3
  5. package/adapters/response-builder.d.ts.map +1 -1
  6. package/bridge-runtime/iife-generator.d.ts.map +1 -1
  7. package/bridge-runtime/index.js +4 -0
  8. package/build/index.d.ts +1 -1
  9. package/build/index.d.ts.map +1 -1
  10. package/build/index.js +61 -69
  11. package/bundler/index.js +35 -34
  12. package/dependency/import-map.d.ts.map +1 -1
  13. package/dependency/index.js +22 -29
  14. package/esm/adapters/index.mjs +52 -42
  15. package/esm/bridge-runtime/index.mjs +4 -0
  16. package/esm/build/index.mjs +30 -32
  17. package/esm/bundler/index.mjs +19 -11
  18. package/esm/dependency/index.mjs +18 -18
  19. package/esm/handlebars/index.mjs +9 -8
  20. package/esm/index.mjs +107 -126
  21. package/esm/package.json +3 -2
  22. package/esm/registry/index.mjs +53 -49
  23. package/esm/renderers/index.mjs +15 -21
  24. package/esm/runtime/index.mjs +16 -15
  25. package/esm/theme/index.mjs +8 -0
  26. package/esm/tool-template/index.mjs +23 -15
  27. package/esm/typings/index.mjs +4 -0
  28. package/esm/utils/index.mjs +9 -56
  29. package/esm/validation/index.mjs +9 -8
  30. package/handlebars/index.js +4 -10
  31. package/index.js +186 -211
  32. package/package.json +3 -2
  33. package/preview/generic-preview.d.ts +4 -5
  34. package/preview/generic-preview.d.ts.map +1 -1
  35. package/preview/types.d.ts +15 -1
  36. package/preview/types.d.ts.map +1 -1
  37. package/registry/index.js +61 -63
  38. package/registry/render-template.d.ts.map +1 -1
  39. package/renderers/index.js +16 -28
  40. package/renderers/utils/detect.d.ts.map +1 -1
  41. package/runtime/index.js +20 -25
  42. package/runtime/sanitizer.d.ts.map +1 -1
  43. package/theme/css-to-theme.d.ts +0 -27
  44. package/theme/css-to-theme.d.ts.map +1 -1
  45. package/theme/index.js +8 -0
  46. package/tool-template/index.js +30 -28
  47. package/typings/dts-parser.d.ts.map +1 -1
  48. package/typings/index.js +4 -0
  49. package/utils/index.d.ts +2 -3
  50. package/utils/index.d.ts.map +1 -1
  51. package/utils/index.js +7 -63
  52. package/validation/index.js +6 -12
  53. package/utils/escape-html.d.ts +0 -102
  54. package/utils/escape-html.d.ts.map +0 -1
  55. package/utils/safe-stringify.d.ts +0 -30
  56. package/utils/safe-stringify.d.ts.map +0 -1
package/esm/index.mjs CHANGED
@@ -8,79 +8,18 @@ var __export = (target, all) => {
8
8
  __defProp(target, name, { get: all[name], enumerable: true });
9
9
  };
10
10
 
11
- // libs/uipack/src/utils/safe-stringify.ts
12
- function safeStringify(value, space) {
13
- const seen = /* @__PURE__ */ new WeakSet();
14
- try {
15
- return JSON.stringify(
16
- value,
17
- (_key, val) => {
18
- if (typeof val === "object" && val !== null) {
19
- if (seen.has(val)) return "[Circular]";
20
- seen.add(val);
21
- }
22
- return val;
23
- },
24
- space
25
- );
26
- } catch {
27
- return JSON.stringify({ error: "Output could not be serialized" });
28
- }
29
- }
30
- var init_safe_stringify = __esm({
31
- "libs/uipack/src/utils/safe-stringify.ts"() {
32
- "use strict";
33
- }
34
- });
35
-
36
- // libs/uipack/src/utils/escape-html.ts
37
- function escapeHtml(str) {
38
- if (str === null || str === void 0) {
39
- return "";
40
- }
41
- const s = String(str);
42
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
43
- }
44
- function escapeHtmlAttr(str) {
45
- return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
46
- }
47
- function escapeJsString(str) {
48
- return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
49
- }
50
- function escapeScriptClose(jsonString) {
51
- return jsonString.replace(/<\//g, "<\\/");
52
- }
53
- function safeJsonForScript(value) {
54
- if (value === void 0) {
55
- return "null";
56
- }
57
- try {
58
- const jsonString = JSON.stringify(value, (_key, val) => {
59
- if (typeof val === "bigint") {
60
- return val.toString();
61
- }
62
- return val;
63
- });
64
- if (jsonString === void 0) {
65
- return "null";
66
- }
67
- return escapeScriptClose(jsonString);
68
- } catch {
69
- return '{"error":"Value could not be serialized"}';
70
- }
71
- }
72
- var init_escape_html = __esm({
73
- "libs/uipack/src/utils/escape-html.ts"() {
74
- "use strict";
75
- }
76
- });
77
-
78
11
  // libs/uipack/src/utils/index.ts
12
+ import {
13
+ safeStringify,
14
+ escapeHtml,
15
+ escapeHtmlAttr,
16
+ escapeJsString,
17
+ escapeScriptClose,
18
+ safeJsonForScript
19
+ } from "@frontmcp/utils";
79
20
  var init_utils = __esm({
80
21
  "libs/uipack/src/utils/index.ts"() {
81
22
  "use strict";
82
- init_safe_stringify();
83
- init_escape_html();
84
23
  }
85
24
  });
86
25
 
@@ -798,6 +737,13 @@ var init_theme = __esm({
798
737
 
799
738
  // libs/uipack/src/theme/css-to-theme.ts
800
739
  function cssToTailwindTheme(userCss) {
740
+ if (userCss.length > MAX_CSS_INPUT_LENGTH) {
741
+ return {
742
+ themeBlock: "",
743
+ remainingCss: userCss,
744
+ colorVars: /* @__PURE__ */ new Map()
745
+ };
746
+ }
801
747
  const colorVars = /* @__PURE__ */ new Map();
802
748
  const regex = new RegExp(COLOR_VAR_REGEX.source, "g");
803
749
  let match;
@@ -830,11 +776,12 @@ function buildTailwindStyleBlock(userCss) {
830
776
  ${parts.join("\n\n")}
831
777
  </style>`;
832
778
  }
833
- var COLOR_VAR_REGEX;
779
+ var COLOR_VAR_REGEX, MAX_CSS_INPUT_LENGTH;
834
780
  var init_css_to_theme = __esm({
835
781
  "libs/uipack/src/theme/css-to-theme.ts"() {
836
782
  "use strict";
837
783
  COLOR_VAR_REGEX = /--(color-[\w-]+):\s*([^;]+);/g;
784
+ MAX_CSS_INPUT_LENGTH = 1e5;
838
785
  }
839
786
  });
840
787
 
@@ -879,6 +826,9 @@ function isTemplateBuilderFunction(fn) {
879
826
  return true;
880
827
  }
881
828
  function containsJsx(source) {
829
+ if (source.length > MAX_TEMPLATE_LENGTH) {
830
+ return false;
831
+ }
882
832
  if (/<[A-Z][a-zA-Z0-9]*(\s|>|\/)/.test(source)) {
883
833
  return true;
884
834
  }
@@ -903,6 +853,9 @@ function containsJsx(source) {
903
853
  return false;
904
854
  }
905
855
  function containsMdxSyntax(source) {
856
+ if (source.length > MAX_TEMPLATE_LENGTH) {
857
+ return false;
858
+ }
906
859
  if (/<[A-Z][a-zA-Z0-9]*/.test(source)) {
907
860
  return true;
908
861
  }
@@ -976,9 +929,11 @@ function detectTemplateType(template) {
976
929
  reason: "Unknown template type, defaulting to HTML"
977
930
  };
978
931
  }
932
+ var MAX_TEMPLATE_LENGTH;
979
933
  var init_detect = __esm({
980
934
  "libs/uipack/src/renderers/utils/detect.ts"() {
981
935
  "use strict";
936
+ MAX_TEMPLATE_LENGTH = 5e4;
982
937
  }
983
938
  });
984
939
 
@@ -2417,9 +2372,9 @@ var init_renderers = __esm({
2417
2372
 
2418
2373
  // libs/uipack/src/bundler/file-cache/hash-calculator.ts
2419
2374
  import { createHash } from "crypto";
2420
- import { readFile } from "fs/promises";
2421
2375
  import { existsSync } from "fs";
2422
2376
  import { join as join2, dirname, resolve } from "path";
2377
+ import { readFile, readFileBuffer } from "@frontmcp/utils";
2423
2378
  function sha256(content) {
2424
2379
  return createHash("sha256").update(content, "utf8").digest("hex");
2425
2380
  }
@@ -2428,7 +2383,7 @@ function sha256Buffer(buffer) {
2428
2383
  }
2429
2384
  async function hashFile(filePath) {
2430
2385
  try {
2431
- const content = await readFile(filePath);
2386
+ const content = await readFileBuffer(filePath);
2432
2387
  return sha256Buffer(content);
2433
2388
  } catch {
2434
2389
  return void 0;
@@ -2479,7 +2434,7 @@ async function collectLocalDependencies(filePath, baseDir, collected, maxDepth,
2479
2434
  if (!existsSync(filePath)) return;
2480
2435
  collected.add(filePath);
2481
2436
  try {
2482
- const content = await readFile(filePath, "utf8");
2437
+ const content = await readFile(filePath);
2483
2438
  const imports = extractImportPaths(content);
2484
2439
  for (const importPath of imports) {
2485
2440
  if (!importPath.startsWith(".") && !importPath.startsWith("/")) {
@@ -3397,7 +3352,10 @@ function generateUMDShim(dependencies, options = {}) {
3397
3352
  console.warn('UMD shim failed:', e);
3398
3353
  }
3399
3354
  })();` : `window.__esm_shim = ${shimObject};`;
3400
- return minify ? code.replace(/\s+/g, " ").replace(/\s*([{},:])\s*/g, "$1") : code;
3355
+ if (minify && code.length <= 1e5) {
3356
+ return code.replace(/\s+/g, " ").replace(/\s*([{},:])\s*/g, "$1");
3357
+ }
3358
+ return code;
3401
3359
  }
3402
3360
  function generateCDNScriptTags(dependencies) {
3403
3361
  return dependencies.filter((dep) => !dep.esm).map((dep) => {
@@ -3696,10 +3654,10 @@ __export(filesystem_exports, {
3696
3654
  StorageNotInitializedError: () => StorageNotInitializedError,
3697
3655
  createFilesystemStorage: () => createFilesystemStorage
3698
3656
  });
3699
- import { mkdir, readFile as readFile2, writeFile, readdir, unlink, rm } from "fs/promises";
3700
3657
  import { join as join3, dirname as dirname2 } from "path";
3701
3658
  import { existsSync as existsSync2 } from "fs";
3702
3659
  import { createHash as createHash3 } from "crypto";
3660
+ import { mkdir, readFile as readFile2, writeFile, readdir, unlink, rm } from "@frontmcp/utils";
3703
3661
  function createFilesystemStorage(options) {
3704
3662
  return new FilesystemStorage(options);
3705
3663
  }
@@ -3935,7 +3893,7 @@ var init_filesystem = __esm({
3935
3893
  */
3936
3894
  async writeEntry(filePath, entry) {
3937
3895
  await mkdir(dirname2(filePath), { recursive: true });
3938
- await writeFile(filePath, JSON.stringify(entry, null, 2), "utf8");
3896
+ await writeFile(filePath, JSON.stringify(entry, null, 2));
3939
3897
  }
3940
3898
  /**
3941
3899
  * Ensure the storage is initialized.
@@ -4292,10 +4250,10 @@ var init_redis = __esm({
4292
4250
  });
4293
4251
 
4294
4252
  // libs/uipack/src/bundler/file-cache/component-builder.ts
4295
- import { readFile as readFile3 } from "fs/promises";
4296
4253
  import { existsSync as existsSync3 } from "fs";
4297
4254
  import { resolve as resolve2, extname, basename } from "path";
4298
4255
  import { randomUUID } from "crypto";
4256
+ import { readFile as readFile3 } from "@frontmcp/utils";
4299
4257
  async function createFilesystemBuilder(cacheDir = ".frontmcp-cache/builds") {
4300
4258
  const { FilesystemStorage: FilesystemStorage2 } = await Promise.resolve().then(() => (init_filesystem(), filesystem_exports));
4301
4259
  const storage = new FilesystemStorage2({ cacheDir });
@@ -4658,16 +4616,13 @@ function buildUIMeta(options) {
4658
4616
  case "generic-mcp":
4659
4617
  case "gemini":
4660
4618
  default:
4661
- meta["frontmcp/html"] = html;
4662
- meta["frontmcp/mimeType"] = "text/html+mcp";
4663
- if (rendererType) meta["frontmcp/type"] = rendererType;
4664
- if (contentHash) meta["frontmcp/contentHash"] = contentHash;
4665
- if (manifestUri) meta["frontmcp/manifestUri"] = manifestUri;
4666
- if (token) meta["frontmcp/widgetToken"] = token;
4667
- if (directUrl) meta["frontmcp/directUrl"] = directUrl;
4668
4619
  meta["ui/html"] = html;
4669
4620
  meta["ui/mimeType"] = "text/html+mcp";
4670
4621
  if (rendererType) meta["ui/type"] = rendererType;
4622
+ if (contentHash) meta["ui/contentHash"] = contentHash;
4623
+ if (manifestUri) meta["ui/manifestUri"] = manifestUri;
4624
+ if (token) meta["ui/widgetToken"] = token;
4625
+ if (directUrl) meta["ui/directUrl"] = directUrl;
4671
4626
  if (platformType === "claude") {
4672
4627
  return buildClaudeMeta(meta, uiConfig);
4673
4628
  } else if (platformType === "gemini") {
@@ -4726,34 +4681,37 @@ function buildIDEMeta(meta, uiConfig) {
4726
4681
  }
4727
4682
  return meta;
4728
4683
  }
4729
- function buildFrontMCPCSP(csp) {
4730
- const result = {};
4731
- if (csp.connectDomains?.length) {
4732
- result.connectDomains = csp.connectDomains;
4733
- }
4734
- if (csp.resourceDomains?.length) {
4735
- result.resourceDomains = csp.resourceDomains;
4736
- }
4737
- return result;
4738
- }
4739
4684
  function buildGenericMeta(meta, uiConfig) {
4740
- if (uiConfig.widgetAccessible) {
4741
- meta["frontmcp/widgetAccessible"] = true;
4742
- }
4743
4685
  if (uiConfig.csp) {
4744
- meta["frontmcp/widgetCSP"] = buildFrontMCPCSP(uiConfig.csp);
4686
+ const csp = {};
4687
+ if (uiConfig.csp.connectDomains?.length) {
4688
+ csp.connectDomains = uiConfig.csp.connectDomains;
4689
+ }
4690
+ if (uiConfig.csp.resourceDomains?.length) {
4691
+ csp.resourceDomains = uiConfig.csp.resourceDomains;
4692
+ }
4693
+ if (Object.keys(csp).length > 0) {
4694
+ meta["ui/csp"] = csp;
4695
+ }
4745
4696
  }
4746
4697
  if (uiConfig.displayMode) {
4747
- meta["frontmcp/displayMode"] = uiConfig.displayMode;
4748
- }
4749
- if (uiConfig.widgetDescription) {
4750
- meta["frontmcp/widgetDescription"] = uiConfig.widgetDescription;
4698
+ const displayModeMap = {
4699
+ inline: "inline",
4700
+ fullscreen: "fullscreen",
4701
+ pip: "pip",
4702
+ widget: "inline",
4703
+ panel: "fullscreen"
4704
+ };
4705
+ const mappedMode = displayModeMap[uiConfig.displayMode];
4706
+ if (mappedMode) {
4707
+ meta["ui/displayMode"] = mappedMode;
4708
+ }
4751
4709
  }
4752
4710
  if (uiConfig.prefersBorder !== void 0) {
4753
- meta["frontmcp/prefersBorder"] = uiConfig.prefersBorder;
4711
+ meta["ui/prefersBorder"] = uiConfig.prefersBorder;
4754
4712
  }
4755
4713
  if (uiConfig.sandboxDomain) {
4756
- meta["frontmcp/domain"] = uiConfig.sandboxDomain;
4714
+ meta["ui/domain"] = uiConfig.sandboxDomain;
4757
4715
  }
4758
4716
  return meta;
4759
4717
  }
@@ -5005,12 +4963,22 @@ function buildToolResponseContent(options) {
5005
4963
  }
5006
4964
  if (useStructuredContent) {
5007
4965
  if (htmlContent) {
5008
- return {
5009
- content: [{ type: "text", text: htmlContent }],
5010
- structuredContent: rawOutput,
5011
- contentCleared: false,
5012
- format: "structured-content"
5013
- };
4966
+ const htmlInContent = platformType === "openai" || platformType === "ext-apps";
4967
+ if (htmlInContent) {
4968
+ return {
4969
+ content: [{ type: "text", text: htmlContent }],
4970
+ structuredContent: rawOutput,
4971
+ contentCleared: false,
4972
+ format: "structured-content"
4973
+ };
4974
+ } else {
4975
+ return {
4976
+ content: [{ type: "text", text: safeStringify(rawOutput) }],
4977
+ structuredContent: rawOutput,
4978
+ contentCleared: false,
4979
+ format: "structured-content"
4980
+ };
4981
+ }
5014
4982
  }
5015
4983
  return {
5016
4984
  content: [{ type: "text", text: safeStringify(rawOutput) }],
@@ -5882,7 +5850,11 @@ FrontMcpBridge.prototype._setupDataToolCallHandler = function() {
5882
5850
  };
5883
5851
  `.trim();
5884
5852
  }
5853
+ var MAX_MINIFY_CODE_LENGTH = 5e5;
5885
5854
  function minifyJS(code) {
5855
+ if (code.length > MAX_MINIFY_CODE_LENGTH) {
5856
+ return code;
5857
+ }
5886
5858
  return code.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "").replace(/\s+/g, " ").replace(/\s*([{};,:()[\]])\s*/g, "$1").replace(/;\}/g, "}").trim();
5887
5859
  }
5888
5860
  function generatePlatformBundle(platform, options = {}) {
@@ -6522,7 +6494,11 @@ function detectPIIType(value) {
6522
6494
  if (isIPv4(value)) return "IP";
6523
6495
  return null;
6524
6496
  }
6497
+ var MAX_PII_TEXT_LENGTH = 1e5;
6525
6498
  function redactPIIFromText(text) {
6499
+ if (text.length > MAX_PII_TEXT_LENGTH) {
6500
+ return text;
6501
+ }
6526
6502
  let result = text;
6527
6503
  result = result.replace(PII_PATTERNS.creditCardInText, REDACTION_TOKENS.CARD);
6528
6504
  result = result.replace(PII_PATTERNS.ssnInText, REDACTION_TOKENS.ID);
@@ -8507,7 +8483,7 @@ function describeZodType(schema) {
8507
8483
  }
8508
8484
 
8509
8485
  // libs/uipack/src/validation/template-validator.ts
8510
- init_expression_extractor();
8486
+ init_handlebars();
8511
8487
  function validateTemplate(template, outputSchema, options = {}) {
8512
8488
  const { inputSchema, warnOnOptional = true, suggestSimilar = true, maxSuggestionDistance = 3 } = options;
8513
8489
  const errors = [];
@@ -11203,13 +11179,12 @@ var GenericPreview = class {
11203
11179
  forDiscoveryStatic(result, toolName, _description) {
11204
11180
  const resourceUri = `resource://widget/${toolName}`;
11205
11181
  const _meta = {
11206
- // Primary namespace
11207
- "frontmcp/outputTemplate": resourceUri,
11208
- "frontmcp/widgetCSP": {
11209
- connect_domains: ["esm.sh", "cdn.tailwindcss.com"],
11210
- resource_domains: ["esm.sh", "cdn.tailwindcss.com", "fonts.googleapis.com", "fonts.gstatic.com"]
11182
+ // Use ui/* namespace for generic MCP clients
11183
+ "ui/resourceUri": resourceUri,
11184
+ "ui/widgetCSP": {
11185
+ connectDomains: ["esm.sh", "cdn.tailwindcss.com"],
11186
+ resourceDomains: ["esm.sh", "cdn.tailwindcss.com", "fonts.googleapis.com", "fonts.gstatic.com"]
11211
11187
  },
11212
- // Fallback for compatibility
11213
11188
  "ui/mimeType": "text/html+mcp"
11214
11189
  };
11215
11190
  return {
@@ -11220,10 +11195,11 @@ var GenericPreview = class {
11220
11195
  }
11221
11196
  forDiscoveryHybrid(result, _toolName, _description) {
11222
11197
  const _meta = {
11223
- "frontmcp/outputTemplate": result.shellResourceUri,
11224
- "frontmcp/widgetCSP": {
11225
- connect_domains: ["esm.sh", "cdn.tailwindcss.com"],
11226
- resource_domains: ["esm.sh", "cdn.tailwindcss.com", "fonts.googleapis.com", "fonts.gstatic.com"]
11198
+ // Use ui/* namespace for generic MCP clients
11199
+ "ui/resourceUri": result.shellResourceUri,
11200
+ "ui/widgetCSP": {
11201
+ connectDomains: ["esm.sh", "cdn.tailwindcss.com"],
11202
+ resourceDomains: ["esm.sh", "cdn.tailwindcss.com", "fonts.googleapis.com", "fonts.gstatic.com"]
11227
11203
  },
11228
11204
  "ui/mimeType": "text/html+mcp"
11229
11205
  };
@@ -11235,7 +11211,7 @@ var GenericPreview = class {
11235
11211
  }
11236
11212
  forDiscoveryInline(result, _toolName, _description) {
11237
11213
  const _meta = {
11238
- "frontmcp/html": result.loaderShell,
11214
+ // Use ui/* namespace for generic MCP clients
11239
11215
  "ui/html": result.loaderShell,
11240
11216
  "ui/mimeType": "text/html+mcp"
11241
11217
  };
@@ -11251,7 +11227,6 @@ var GenericPreview = class {
11251
11227
  const html = this.injectBuilderMode(result.html, input, output, mockData);
11252
11228
  return {
11253
11229
  _meta: {
11254
- "frontmcp/html": html,
11255
11230
  "ui/html": html
11256
11231
  },
11257
11232
  html,
@@ -11267,13 +11242,12 @@ var GenericPreview = class {
11267
11242
  }
11268
11243
  forExecutionHybrid(result, input, output, builderMode, mockData) {
11269
11244
  const _meta = {
11270
- "frontmcp/component": result.componentChunk
11245
+ "ui/component": result.componentChunk
11271
11246
  };
11272
11247
  if (builderMode) {
11273
11248
  const html = this.combineHybridForBuilder(result, input, output, mockData);
11274
11249
  return {
11275
11250
  _meta: {
11276
- "frontmcp/html": html,
11277
11251
  "ui/html": html
11278
11252
  },
11279
11253
  html,
@@ -11289,7 +11263,6 @@ var GenericPreview = class {
11289
11263
  }
11290
11264
  forExecutionInline(result, input, output, _builderMode, _mockData) {
11291
11265
  const _meta = {
11292
- "frontmcp/html": "<!-- Full widget will be generated -->",
11293
11266
  "ui/html": "<!-- Full widget will be generated -->"
11294
11267
  };
11295
11268
  return {
@@ -12474,7 +12447,11 @@ init_renderers();
12474
12447
  import { createHash as createHash2 } from "crypto";
12475
12448
 
12476
12449
  // libs/uipack/src/registry/render-template.ts
12450
+ var MAX_MDX_SOURCE_LENGTH = 1e5;
12477
12451
  function containsMdxSyntax2(source) {
12452
+ if (source.length > MAX_MDX_SOURCE_LENGTH) {
12453
+ return false;
12454
+ }
12478
12455
  if (/<[A-Z][a-zA-Z0-9]*/.test(source)) {
12479
12456
  return true;
12480
12457
  }
@@ -13317,7 +13294,11 @@ function getSubpathFromSpecifier(specifier) {
13317
13294
  }
13318
13295
  return void 0;
13319
13296
  }
13297
+ var MAX_IMPORT_STATEMENT_LENGTH = 2e3;
13320
13298
  function parseImportStatement(statement) {
13299
+ if (statement.length > MAX_IMPORT_STATEMENT_LENGTH) {
13300
+ return null;
13301
+ }
13321
13302
  const namedMatch = /import\s+(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+['"]([^'"]+)['"]/.exec(statement);
13322
13303
  if (namedMatch) {
13323
13304
  return namedMatch[1];
package/esm/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/uipack",
3
- "version": "0.6.3",
3
+ "version": "0.7.2",
4
4
  "description": "FrontMCP UIpack - Bundling, build tools, and platform adapters for MCP UI development (React-free core)",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "homepage": "https://docs.agentfront.dev",
@@ -55,8 +55,9 @@
55
55
  "./esm": null
56
56
  },
57
57
  "dependencies": {
58
+ "@frontmcp/utils": "0.7.2",
58
59
  "@swc/core": "^1.5.0",
59
- "enclave-vm": "^1.0.3",
60
+ "enclave-vm": "^2.7.0",
60
61
  "esbuild": "^0.27.1",
61
62
  "handlebars": "^4.7.8",
62
63
  "zod": "^4.0.0"
@@ -548,31 +548,18 @@ var init_theme2 = __esm({
548
548
  }
549
549
  });
550
550
 
551
- // libs/uipack/src/utils/escape-html.ts
552
- function escapeHtml(str) {
553
- if (str === null || str === void 0) {
554
- return "";
555
- }
556
- const s = String(str);
557
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
558
- }
559
- function escapeJsString(str) {
560
- return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
561
- }
562
- function escapeScriptClose(jsonString) {
563
- return jsonString.replace(/<\//g, "<\\/");
564
- }
565
- var init_escape_html = __esm({
566
- "libs/uipack/src/utils/escape-html.ts"() {
567
- "use strict";
568
- }
569
- });
570
-
571
551
  // libs/uipack/src/utils/index.ts
552
+ import {
553
+ safeStringify,
554
+ escapeHtml,
555
+ escapeHtmlAttr,
556
+ escapeJsString,
557
+ escapeScriptClose,
558
+ safeJsonForScript
559
+ } from "@frontmcp/utils";
572
560
  var init_utils = __esm({
573
561
  "libs/uipack/src/utils/index.ts"() {
574
562
  "use strict";
575
- init_escape_html();
576
563
  }
577
564
  });
578
565
 
@@ -826,6 +813,9 @@ function isTemplateBuilderFunction(fn) {
826
813
  return true;
827
814
  }
828
815
  function containsJsx(source) {
816
+ if (source.length > MAX_TEMPLATE_LENGTH) {
817
+ return false;
818
+ }
829
819
  if (/<[A-Z][a-zA-Z0-9]*(\s|>|\/)/.test(source)) {
830
820
  return true;
831
821
  }
@@ -850,6 +840,9 @@ function containsJsx(source) {
850
840
  return false;
851
841
  }
852
842
  function containsMdxSyntax(source) {
843
+ if (source.length > MAX_TEMPLATE_LENGTH) {
844
+ return false;
845
+ }
853
846
  if (/<[A-Z][a-zA-Z0-9]*/.test(source)) {
854
847
  return true;
855
848
  }
@@ -923,9 +916,11 @@ function detectTemplateType(template) {
923
916
  reason: "Unknown template type, defaulting to HTML"
924
917
  };
925
918
  }
919
+ var MAX_TEMPLATE_LENGTH;
926
920
  var init_detect = __esm({
927
921
  "libs/uipack/src/renderers/utils/detect.ts"() {
928
922
  "use strict";
923
+ MAX_TEMPLATE_LENGTH = 5e4;
929
924
  }
930
925
  });
931
926
 
@@ -2143,6 +2138,7 @@ var init_renderers = __esm({
2143
2138
 
2144
2139
  // libs/uipack/src/bundler/file-cache/hash-calculator.ts
2145
2140
  import { createHash } from "crypto";
2141
+ import { readFile, readFileBuffer } from "@frontmcp/utils";
2146
2142
  function sha256(content) {
2147
2143
  return createHash("sha256").update(content, "utf8").digest("hex");
2148
2144
  }
@@ -2980,7 +2976,11 @@ FrontMcpBridge.prototype._setupDataToolCallHandler = function() {
2980
2976
  };
2981
2977
  `.trim();
2982
2978
  }
2979
+ var MAX_MINIFY_CODE_LENGTH = 5e5;
2983
2980
  function minifyJS(code) {
2981
+ if (code.length > MAX_MINIFY_CODE_LENGTH) {
2982
+ return code;
2983
+ }
2984
2984
  return code.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "").replace(/\s+/g, " ").replace(/\s*([{};,:()[\]])\s*/g, "$1").replace(/;\}/g, "}").trim();
2985
2985
  }
2986
2986
  function generatePlatformBundle(platform, options = {}) {
@@ -4422,7 +4422,11 @@ function wrapStaticWidgetUniversal(options) {
4422
4422
  }
4423
4423
 
4424
4424
  // libs/uipack/src/registry/render-template.ts
4425
+ var MAX_MDX_SOURCE_LENGTH = 1e5;
4425
4426
  function containsMdxSyntax2(source) {
4427
+ if (source.length > MAX_MDX_SOURCE_LENGTH) {
4428
+ return false;
4429
+ }
4426
4430
  if (/<[A-Z][a-zA-Z0-9]*/.test(source)) {
4427
4431
  return true;
4428
4432
  }
@@ -4590,16 +4594,13 @@ function buildUIMeta(options) {
4590
4594
  case "generic-mcp":
4591
4595
  case "gemini":
4592
4596
  default:
4593
- meta["frontmcp/html"] = html;
4594
- meta["frontmcp/mimeType"] = "text/html+mcp";
4595
- if (rendererType) meta["frontmcp/type"] = rendererType;
4596
- if (contentHash) meta["frontmcp/contentHash"] = contentHash;
4597
- if (manifestUri) meta["frontmcp/manifestUri"] = manifestUri;
4598
- if (token) meta["frontmcp/widgetToken"] = token;
4599
- if (directUrl) meta["frontmcp/directUrl"] = directUrl;
4600
4597
  meta["ui/html"] = html;
4601
4598
  meta["ui/mimeType"] = "text/html+mcp";
4602
4599
  if (rendererType) meta["ui/type"] = rendererType;
4600
+ if (contentHash) meta["ui/contentHash"] = contentHash;
4601
+ if (manifestUri) meta["ui/manifestUri"] = manifestUri;
4602
+ if (token) meta["ui/widgetToken"] = token;
4603
+ if (directUrl) meta["ui/directUrl"] = directUrl;
4603
4604
  if (platformType === "claude") {
4604
4605
  return buildClaudeMeta(meta, uiConfig);
4605
4606
  } else if (platformType === "gemini") {
@@ -4648,34 +4649,37 @@ function buildIDEMeta(meta, uiConfig) {
4648
4649
  }
4649
4650
  return meta;
4650
4651
  }
4651
- function buildFrontMCPCSP(csp) {
4652
- const result = {};
4653
- if (csp.connectDomains?.length) {
4654
- result.connectDomains = csp.connectDomains;
4655
- }
4656
- if (csp.resourceDomains?.length) {
4657
- result.resourceDomains = csp.resourceDomains;
4658
- }
4659
- return result;
4660
- }
4661
4652
  function buildGenericMeta(meta, uiConfig) {
4662
- if (uiConfig.widgetAccessible) {
4663
- meta["frontmcp/widgetAccessible"] = true;
4664
- }
4665
4653
  if (uiConfig.csp) {
4666
- meta["frontmcp/widgetCSP"] = buildFrontMCPCSP(uiConfig.csp);
4654
+ const csp = {};
4655
+ if (uiConfig.csp.connectDomains?.length) {
4656
+ csp.connectDomains = uiConfig.csp.connectDomains;
4657
+ }
4658
+ if (uiConfig.csp.resourceDomains?.length) {
4659
+ csp.resourceDomains = uiConfig.csp.resourceDomains;
4660
+ }
4661
+ if (Object.keys(csp).length > 0) {
4662
+ meta["ui/csp"] = csp;
4663
+ }
4667
4664
  }
4668
4665
  if (uiConfig.displayMode) {
4669
- meta["frontmcp/displayMode"] = uiConfig.displayMode;
4670
- }
4671
- if (uiConfig.widgetDescription) {
4672
- meta["frontmcp/widgetDescription"] = uiConfig.widgetDescription;
4666
+ const displayModeMap = {
4667
+ inline: "inline",
4668
+ fullscreen: "fullscreen",
4669
+ pip: "pip",
4670
+ widget: "inline",
4671
+ panel: "fullscreen"
4672
+ };
4673
+ const mappedMode = displayModeMap[uiConfig.displayMode];
4674
+ if (mappedMode) {
4675
+ meta["ui/displayMode"] = mappedMode;
4676
+ }
4673
4677
  }
4674
4678
  if (uiConfig.prefersBorder !== void 0) {
4675
- meta["frontmcp/prefersBorder"] = uiConfig.prefersBorder;
4679
+ meta["ui/prefersBorder"] = uiConfig.prefersBorder;
4676
4680
  }
4677
4681
  if (uiConfig.sandboxDomain) {
4678
- meta["frontmcp/domain"] = uiConfig.sandboxDomain;
4682
+ meta["ui/domain"] = uiConfig.sandboxDomain;
4679
4683
  }
4680
4684
  return meta;
4681
4685
  }
@@ -4949,7 +4953,7 @@ function getSchemaPathStrings(schema, prefix = "output") {
4949
4953
  }
4950
4954
 
4951
4955
  // libs/uipack/src/validation/template-validator.ts
4952
- init_expression_extractor();
4956
+ init_handlebars();
4953
4957
  function validateTemplate(template, outputSchema, options = {}) {
4954
4958
  const { inputSchema, warnOnOptional = true, suggestSimilar = true, maxSuggestionDistance = 3 } = options;
4955
4959
  const errors = [];