@frontmcp/ui 0.8.1 → 0.10.0

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/index.js CHANGED
@@ -1219,6 +1219,7 @@ var dangerButton = (text, opts) => button(text, { ...opts, variant: "danger" });
1219
1219
  var linkButton = (text, opts) => button(text, { ...opts, variant: "link" });
1220
1220
 
1221
1221
  // libs/ui/src/components/card.ts
1222
+ var import_runtime = require("@frontmcp/uipack/runtime");
1222
1223
  function getVariantClasses2(variant) {
1223
1224
  const variants = {
1224
1225
  default: "bg-white border border-border rounded-xl shadow-sm",
@@ -1253,33 +1254,38 @@ function card(content, options = {}) {
1253
1254
  id,
1254
1255
  data,
1255
1256
  clickable = false,
1256
- href
1257
+ href,
1258
+ sanitize = false
1257
1259
  } = options;
1260
+ const safeContent = sanitize ? (0, import_runtime.sanitizeHtmlContent)(content) : content;
1261
+ const safeHeaderActions = sanitize && headerActions ? (0, import_runtime.sanitizeHtmlContent)(headerActions) : headerActions;
1262
+ const safeFooter = sanitize && footer ? (0, import_runtime.sanitizeHtmlContent)(footer) : footer;
1258
1263
  const variantClasses = getVariantClasses2(variant);
1259
1264
  const sizeClasses = getSizeClasses2(size);
1260
1265
  const clickableClasses = clickable ? "cursor-pointer hover:shadow-md transition-shadow" : "";
1261
- const allClasses = [variantClasses, sizeClasses, clickableClasses, className].filter(Boolean).join(" ");
1266
+ const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1267
+ const allClasses = [variantClasses, sizeClasses, clickableClasses, safeClassName].filter(Boolean).join(" ");
1262
1268
  const dataAttrs = buildDataAttrs(data);
1263
1269
  const idAttr = id ? `id="${(0, import_utils2.escapeHtml)(id)}"` : "";
1264
- const hasHeader = title || subtitle || headerActions;
1270
+ const hasHeader = title || subtitle || safeHeaderActions;
1265
1271
  const headerHtml = hasHeader ? `<div class="flex items-start justify-between mb-4">
1266
1272
  <div>
1267
1273
  ${title ? `<h3 class="text-lg font-semibold text-text-primary">${(0, import_utils2.escapeHtml)(title)}</h3>` : ""}
1268
1274
  ${subtitle ? `<p class="text-sm text-text-secondary mt-1">${(0, import_utils2.escapeHtml)(subtitle)}</p>` : ""}
1269
1275
  </div>
1270
- ${headerActions ? `<div class="flex items-center gap-2">${headerActions}</div>` : ""}
1276
+ ${safeHeaderActions ? `<div class="flex items-center gap-2">${safeHeaderActions}</div>` : ""}
1271
1277
  </div>` : "";
1272
- const footerHtml = footer ? `<div class="mt-4 pt-4 border-t border-divider">${footer}</div>` : "";
1278
+ const footerHtml = safeFooter ? `<div class="mt-4 pt-4 border-t border-divider">${safeFooter}</div>` : "";
1273
1279
  if (href) {
1274
1280
  return `<a href="${(0, import_utils2.escapeHtml)(href)}" class="${allClasses}" ${idAttr} ${dataAttrs}>
1275
1281
  ${headerHtml}
1276
- ${content}
1282
+ ${safeContent}
1277
1283
  ${footerHtml}
1278
1284
  </a>`;
1279
1285
  }
1280
1286
  return `<div class="${allClasses}" ${idAttr} ${dataAttrs}>
1281
1287
  ${headerHtml}
1282
- ${content}
1288
+ ${safeContent}
1283
1289
  ${footerHtml}
1284
1290
  </div>`;
1285
1291
  }
@@ -1287,12 +1293,14 @@ function cardGroup(cards, options = {}) {
1287
1293
  const { direction = "vertical", gap = "md", className = "" } = options;
1288
1294
  const gapClasses = { sm: "gap-2", md: "gap-4", lg: "gap-6" };
1289
1295
  const directionClasses = direction === "horizontal" ? "flex flex-row flex-wrap" : "flex flex-col";
1290
- return `<div class="${directionClasses} ${gapClasses[gap]} ${className}">
1296
+ const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1297
+ return `<div class="${directionClasses} ${gapClasses[gap]} ${safeClassName}">
1291
1298
  ${cards.join("\n")}
1292
1299
  </div>`;
1293
1300
  }
1294
1301
 
1295
1302
  // libs/ui/src/components/form.ts
1303
+ var import_runtime2 = require("@frontmcp/uipack/runtime");
1296
1304
  function getInputSizeClasses(size) {
1297
1305
  const sizes = {
1298
1306
  sm: "px-3 py-1.5 text-sm",
@@ -1337,11 +1345,15 @@ function input(options) {
1337
1345
  className = "",
1338
1346
  data,
1339
1347
  iconBefore,
1340
- iconAfter
1348
+ iconAfter,
1349
+ sanitize = false
1341
1350
  } = options;
1351
+ const safeIconBefore = sanitize && iconBefore ? (0, import_runtime2.sanitizeHtmlContent)(iconBefore) : iconBefore;
1352
+ const safeIconAfter = sanitize && iconAfter ? (0, import_runtime2.sanitizeHtmlContent)(iconAfter) : iconAfter;
1342
1353
  const sizeClasses = getInputSizeClasses(size);
1343
1354
  const stateClasses = getInputStateClasses(state);
1344
- const hasIcon = iconBefore || iconAfter;
1355
+ const hasIcon = safeIconBefore || safeIconAfter;
1356
+ const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1345
1357
  const baseClasses = [
1346
1358
  "w-full rounded-lg border bg-white",
1347
1359
  "transition-colors duration-200",
@@ -1349,8 +1361,8 @@ function input(options) {
1349
1361
  disabled ? "opacity-50 cursor-not-allowed bg-gray-50" : "",
1350
1362
  sizeClasses,
1351
1363
  stateClasses,
1352
- hasIcon ? (iconBefore ? "pl-10" : "") + (iconAfter ? " pr-10" : "") : "",
1353
- className
1364
+ hasIcon ? (safeIconBefore ? "pl-10" : "") + (safeIconAfter ? " pr-10" : "") : "",
1365
+ safeClassName
1354
1366
  ].filter(Boolean).join(" ");
1355
1367
  const dataAttrs = buildDataAttrs2(data);
1356
1368
  const inputAttrs = [
@@ -1375,8 +1387,8 @@ function input(options) {
1375
1387
  </label>` : "";
1376
1388
  const helperHtml = helper && !error ? `<p class="mt-1.5 text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(helper)}</p>` : "";
1377
1389
  const errorHtml = error ? `<p class="mt-1.5 text-sm text-danger">${(0, import_utils2.escapeHtml)(error)}</p>` : "";
1378
- const iconBeforeHtml = iconBefore ? `<span class="absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary">${iconBefore}</span>` : "";
1379
- const iconAfterHtml = iconAfter ? `<span class="absolute right-3 top-1/2 -translate-y-1/2 text-text-secondary">${iconAfter}</span>` : "";
1390
+ const iconBeforeHtml = safeIconBefore ? `<span class="absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary">${safeIconBefore}</span>` : "";
1391
+ const iconAfterHtml = safeIconAfter ? `<span class="absolute right-3 top-1/2 -translate-y-1/2 text-text-secondary">${safeIconAfter}</span>` : "";
1380
1392
  const inputHtml = hasIcon ? `<div class="relative">
1381
1393
  ${iconBeforeHtml}
1382
1394
  <input ${inputAttrs}>
@@ -1408,6 +1420,7 @@ function select(options) {
1408
1420
  } = options;
1409
1421
  const sizeClasses = getInputSizeClasses(size);
1410
1422
  const stateClasses = getInputStateClasses(state);
1423
+ const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1411
1424
  const baseClasses = [
1412
1425
  "w-full rounded-lg border bg-white",
1413
1426
  "transition-colors duration-200",
@@ -1415,7 +1428,7 @@ function select(options) {
1415
1428
  disabled ? "opacity-50 cursor-not-allowed bg-gray-50" : "",
1416
1429
  sizeClasses,
1417
1430
  stateClasses,
1418
- className
1431
+ safeClassName
1419
1432
  ].filter(Boolean).join(" ");
1420
1433
  const dataAttrs = buildDataAttrs2(data);
1421
1434
  const optionsHtml = selectOptions.map((opt) => {
@@ -1472,6 +1485,7 @@ function textarea(options) {
1472
1485
  horizontal: "resize-x",
1473
1486
  both: "resize"
1474
1487
  };
1488
+ const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1475
1489
  const baseClasses = [
1476
1490
  "w-full rounded-lg border bg-white",
1477
1491
  "transition-colors duration-200",
@@ -1480,7 +1494,7 @@ function textarea(options) {
1480
1494
  sizeClasses,
1481
1495
  stateClasses,
1482
1496
  resizeClasses[resize],
1483
- className
1497
+ safeClassName
1484
1498
  ].filter(Boolean).join(" ");
1485
1499
  const dataAttrs = buildDataAttrs2(data);
1486
1500
  const labelHtml = label ? `<label for="${(0, import_utils2.escapeHtml)(id)}" class="block text-sm font-medium text-text-primary mb-1.5">
@@ -1524,7 +1538,8 @@ function checkbox(options) {
1524
1538
  ].join(" ");
1525
1539
  const helperHtml = helper && !error ? `<p class="text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(helper)}</p>` : "";
1526
1540
  const errorHtml = error ? `<p class="text-sm text-danger">${(0, import_utils2.escapeHtml)(error)}</p>` : "";
1527
- return `<div class="form-field ${className}">
1541
+ const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1542
+ return `<div class="form-field ${safeClassName}">
1528
1543
  <label class="flex items-start gap-3 ${disabled ? "cursor-not-allowed" : "cursor-pointer"}">
1529
1544
  <input
1530
1545
  type="checkbox"
@@ -1568,7 +1583,8 @@ function radioGroup(options) {
1568
1583
  const labelHtml = label ? `<label class="block text-sm font-medium text-text-primary mb-2">${(0, import_utils2.escapeHtml)(label)}</label>` : "";
1569
1584
  const helperHtml = helper && !error ? `<p class="mt-1.5 text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(helper)}</p>` : "";
1570
1585
  const errorHtml = error ? `<p class="mt-1.5 text-sm text-danger">${(0, import_utils2.escapeHtml)(error)}</p>` : "";
1571
- return `<div class="form-field ${className}" role="radiogroup">
1586
+ const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1587
+ return `<div class="form-field ${safeClassName}" role="radiogroup">
1572
1588
  ${labelHtml}
1573
1589
  <div class="${directionClasses}">
1574
1590
  ${radiosHtml}
@@ -1590,10 +1606,26 @@ function form(content, options = {}) {
1590
1606
  ].filter(Boolean).join(" ");
1591
1607
  return `<form ${attrs}>${content}</form>`;
1592
1608
  }
1609
+ var GRID_COLS_MAP = {
1610
+ 1: "grid-cols-1",
1611
+ 2: "grid-cols-2",
1612
+ 3: "grid-cols-3",
1613
+ 4: "grid-cols-4",
1614
+ 5: "grid-cols-5",
1615
+ 6: "grid-cols-6",
1616
+ 7: "grid-cols-7",
1617
+ 8: "grid-cols-8",
1618
+ 9: "grid-cols-9",
1619
+ 10: "grid-cols-10",
1620
+ 11: "grid-cols-11",
1621
+ 12: "grid-cols-12"
1622
+ };
1593
1623
  function formRow(fields, options = {}) {
1594
1624
  const { gap = "md", className = "" } = options;
1595
1625
  const gapClasses = { sm: "gap-2", md: "gap-4", lg: "gap-6" };
1596
- return `<div class="grid grid-cols-${fields.length} ${gapClasses[gap]} ${className}">
1626
+ const gridCols = GRID_COLS_MAP[fields.length] ?? "grid-cols-1";
1627
+ const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1628
+ return `<div class="grid ${gridCols} ${gapClasses[gap]} ${safeClassName}">
1597
1629
  ${fields.join("\n")}
1598
1630
  </div>`;
1599
1631
  }
@@ -1603,7 +1635,8 @@ function formSection(content, options = {}) {
1603
1635
  <h3 class="text-lg font-semibold text-text-primary">${(0, import_utils2.escapeHtml)(title)}</h3>
1604
1636
  ${description ? `<p class="text-sm text-text-secondary mt-1">${(0, import_utils2.escapeHtml)(description)}</p>` : ""}
1605
1637
  </div>` : "";
1606
- return `<div class="form-section ${className}">
1638
+ const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1639
+ return `<div class="form-section ${safeClassName}">
1607
1640
  ${headerHtml}
1608
1641
  <div class="space-y-4">
1609
1642
  ${content}
@@ -1618,7 +1651,8 @@ function formActions(buttons, options = {}) {
1618
1651
  right: "justify-end",
1619
1652
  between: "justify-between"
1620
1653
  };
1621
- return `<div class="flex items-center gap-3 pt-4 ${alignClasses[align]} ${className}">
1654
+ const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1655
+ return `<div class="flex items-center gap-3 pt-4 ${alignClasses[align]} ${safeClassName}">
1622
1656
  ${buttons.join("\n")}
1623
1657
  </div>`;
1624
1658
  }
@@ -1630,6 +1664,7 @@ function csrfInput(token) {
1630
1664
  }
1631
1665
 
1632
1666
  // libs/ui/src/components/badge.ts
1667
+ var import_runtime3 = require("@frontmcp/uipack/runtime");
1633
1668
  function getVariantClasses3(variant) {
1634
1669
  const variants = {
1635
1670
  default: "bg-gray-100 text-gray-800",
@@ -1667,8 +1702,11 @@ function badge(text, options = {}) {
1667
1702
  icon,
1668
1703
  dot = false,
1669
1704
  className = "",
1670
- removable = false
1705
+ removable = false,
1706
+ sanitize = false
1671
1707
  } = options;
1708
+ const safeIcon = sanitize && icon ? (0, import_runtime3.sanitizeHtmlContent)(icon) : icon;
1709
+ const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1672
1710
  if (dot) {
1673
1711
  const dotVariants = {
1674
1712
  default: "bg-gray-400",
@@ -1680,7 +1718,7 @@ function badge(text, options = {}) {
1680
1718
  info: "bg-blue-500",
1681
1719
  outline: "border border-current"
1682
1720
  };
1683
- const dotClasses = ["inline-block rounded-full", getSizeClasses3(size, true), dotVariants[variant], className].filter(Boolean).join(" ");
1721
+ const dotClasses = ["inline-block rounded-full", getSizeClasses3(size, true), dotVariants[variant], safeClassName].filter(Boolean).join(" ");
1684
1722
  return `<span class="${dotClasses}" aria-label="${(0, import_utils2.escapeHtml)(text)}" title="${(0, import_utils2.escapeHtml)(text)}"></span>`;
1685
1723
  }
1686
1724
  const variantClasses = getVariantClasses3(variant);
@@ -1690,9 +1728,9 @@ function badge(text, options = {}) {
1690
1728
  pill ? "rounded-full" : "rounded-md",
1691
1729
  variantClasses,
1692
1730
  sizeClasses,
1693
- className
1731
+ safeClassName
1694
1732
  ].filter(Boolean).join(" ");
1695
- const iconHtml = icon ? `<span class="mr-1">${icon}</span>` : "";
1733
+ const iconHtml = safeIcon ? `<span class="mr-1">${safeIcon}</span>` : "";
1696
1734
  const removeHtml = removable ? `<button
1697
1735
  type="button"
1698
1736
  class="ml-1.5 -mr-1 hover:opacity-70 transition-opacity"
@@ -1710,7 +1748,8 @@ function badge(text, options = {}) {
1710
1748
  function badgeGroup(badges, options = {}) {
1711
1749
  const { gap = "sm", className = "" } = options;
1712
1750
  const gapClasses = { sm: "gap-1", md: "gap-2", lg: "gap-3" };
1713
- return `<div class="inline-flex flex-wrap ${gapClasses[gap]} ${className}">
1751
+ const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1752
+ return `<div class="inline-flex flex-wrap ${gapClasses[gap]} ${safeClassName}">
1714
1753
  ${badges.join("\n")}
1715
1754
  </div>`;
1716
1755
  }
@@ -1726,6 +1765,7 @@ var busyDot = (label = "Busy") => badge(label, { variant: "danger", dot: true })
1726
1765
  var awayDot = (label = "Away") => badge(label, { variant: "warning", dot: true });
1727
1766
 
1728
1767
  // libs/ui/src/components/alert.ts
1768
+ var import_runtime4 = require("@frontmcp/uipack/runtime");
1729
1769
  var alertIcons = {
1730
1770
  info: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1731
1771
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
@@ -1769,11 +1809,24 @@ function getVariantClasses4(variant) {
1769
1809
  return variants[variant];
1770
1810
  }
1771
1811
  function alert(message, options = {}) {
1772
- const { variant = "info", title, showIcon = true, icon, dismissible = false, className = "", id, actions } = options;
1812
+ const {
1813
+ variant = "info",
1814
+ title,
1815
+ showIcon = true,
1816
+ icon,
1817
+ dismissible = false,
1818
+ className = "",
1819
+ id,
1820
+ actions,
1821
+ sanitize = false
1822
+ } = options;
1823
+ const safeIcon = sanitize && icon ? (0, import_runtime4.sanitizeHtmlContent)(icon) : icon;
1824
+ const safeActions = sanitize && actions ? (0, import_runtime4.sanitizeHtmlContent)(actions) : actions;
1773
1825
  const variantClasses = getVariantClasses4(variant);
1774
- const baseClasses = ["rounded-lg border p-4", variantClasses.container, className].filter(Boolean).join(" ");
1826
+ const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1827
+ const baseClasses = ["rounded-lg border p-4", variantClasses.container, safeClassName].filter(Boolean).join(" ");
1775
1828
  const iconHtml = showIcon ? `<div class="flex-shrink-0 ${variantClasses.icon}">
1776
- ${icon || alertIcons[variant]}
1829
+ ${safeIcon || alertIcons[variant]}
1777
1830
  </div>` : "";
1778
1831
  const titleHtml = title ? `<h3 class="font-semibold">${(0, import_utils2.escapeHtml)(title)}</h3>` : "";
1779
1832
  const dismissHtml = dismissible ? `<button
@@ -1786,7 +1839,7 @@ function alert(message, options = {}) {
1786
1839
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
1787
1840
  </svg>
1788
1841
  </button>` : "";
1789
- const actionsHtml = actions ? `<div class="mt-3">${actions}</div>` : "";
1842
+ const actionsHtml = safeActions ? `<div class="mt-3">${safeActions}</div>` : "";
1790
1843
  const idAttr = id ? `id="${(0, import_utils2.escapeHtml)(id)}"` : "";
1791
1844
  return `<div class="alert ${baseClasses}" role="alert" ${idAttr}>
1792
1845
  <div class="flex gap-3">
@@ -5258,7 +5311,17 @@ var ReactRendererAdapter = class {
5258
5311
  return true;
5259
5312
  }
5260
5313
  if (typeof content === "string") {
5261
- return content.includes("React.createElement") || content.includes("jsx(") || content.includes("jsxs(") || /function\s+\w+\s*\([^)]*\)\s*\{[\s\S]*return\s*[\s\S]*</.test(content);
5314
+ if (content.includes("React.createElement") || content.includes("jsx(") || content.includes("jsxs(")) {
5315
+ return true;
5316
+ }
5317
+ const funcIndex = content.indexOf("function");
5318
+ if (funcIndex !== -1) {
5319
+ const afterFunc = content.slice(funcIndex, Math.min(funcIndex + 2e3, content.length));
5320
+ if (afterFunc.includes("return") && afterFunc.includes("<")) {
5321
+ return true;
5322
+ }
5323
+ }
5324
+ return false;
5262
5325
  }
5263
5326
  return false;
5264
5327
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/ui",
3
- "version": "0.8.1",
3
+ "version": "0.10.0",
4
4
  "description": "FrontMCP UI - React components and hooks for MCP applications",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "homepage": "https://docs.agentfront.dev",
@@ -58,13 +58,13 @@
58
58
  "dependencies": {
59
59
  "@mdx-js/mdx": "^3.1.1",
60
60
  "@swc/core": "^1.5.0",
61
- "esbuild": "^0.27.1",
61
+ "esbuild": "^0.27.3",
62
62
  "zod": "^4.0.0"
63
63
  },
64
64
  "peerDependencies": {
65
65
  "react": "^18.0.0 || ^19.0.0",
66
66
  "react-dom": "^18.0.0 || ^19.0.0",
67
- "@frontmcp/uipack": "0.8.1"
67
+ "@frontmcp/uipack": "0.10.0"
68
68
  },
69
69
  "devDependencies": {
70
70
  "@types/react": "^19.0.0",
@@ -250,7 +250,17 @@ var ReactRendererAdapter = class {
250
250
  return true;
251
251
  }
252
252
  if (typeof content === "string") {
253
- return content.includes("React.createElement") || content.includes("jsx(") || content.includes("jsxs(") || /function\s+\w+\s*\([^)]*\)\s*\{[\s\S]*return\s*[\s\S]*</.test(content);
253
+ if (content.includes("React.createElement") || content.includes("jsx(") || content.includes("jsxs(")) {
254
+ return true;
255
+ }
256
+ const funcIndex = content.indexOf("function");
257
+ if (funcIndex !== -1) {
258
+ const afterFunc = content.slice(funcIndex, Math.min(funcIndex + 2e3, content.length));
259
+ if (afterFunc.includes("return") && afterFunc.includes("<")) {
260
+ return true;
261
+ }
262
+ }
263
+ return false;
254
264
  }
255
265
  return false;
256
266
  }
@@ -1 +1 @@
1
- {"version":3,"file":"react.adapter.d.ts","sourceRoot":"","sources":["../../src/renderers/react.adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC5G,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAsDrD;;;;;;;GAOG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAW;IAGhC,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,WAAW,CAA8B;IAEjD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO;IAqB7C;;;OAGG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAMhG;;OAEG;IACG,WAAW,CACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,YAAY,CAAC;IA4DxB;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAI1G;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAsChF;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAQlC;;OAEG;YACW,iBAAiB;IAa/B;;OAEG;YACW,SAAS;IAmCvB;;OAEG;IACH,OAAO,CAAC,YAAY;CAsBrB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,oBAAoB,CAEzD;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,eAAe,CAAC,CAEjE"}
1
+ {"version":3,"file":"react.adapter.d.ts","sourceRoot":"","sources":["../../src/renderers/react.adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC5G,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAsDrD;;;;;;;GAOG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAW;IAGhC,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,WAAW,CAA8B;IAEjD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO;IAiC7C;;;OAGG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAMhG;;OAEG;IACG,WAAW,CACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,YAAY,CAAC;IA4DxB;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAI1G;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAsChF;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAQlC;;OAEG;YACW,iBAAiB;IAa/B;;OAEG;YACW,SAAS;IAmCvB;;OAEG;IACH,OAAO,CAAC,YAAY;CAsBrB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,oBAAoB,CAEzD;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,eAAe,CAAC,CAEjE"}
@@ -287,6 +287,8 @@ function withFrontMCP(Component) {
287
287
 
288
288
  // libs/ui/src/universal/renderers/html.renderer.ts
289
289
  var import_react3 = __toESM(require("react"));
290
+ var import_runtime = require("@frontmcp/uipack/runtime");
291
+ var sanitizeHtml = import_runtime.sanitizeHtmlContent;
290
292
  var htmlRenderer = {
291
293
  type: "html",
292
294
  priority: 0,
@@ -305,13 +307,6 @@ var htmlRenderer = {
305
307
  });
306
308
  }
307
309
  };
308
- function sanitizeHtml(html) {
309
- let sanitized = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "");
310
- sanitized = sanitized.replace(/\s+on\w+\s*=\s*["'][^"']*["']/gi, "");
311
- sanitized = sanitized.replace(/\s+on\w+\s*=\s*[^\s>]*/gi, "");
312
- sanitized = sanitized.replace(/href\s*=\s*["']javascript:[^"']*["']/gi, 'href="#"');
313
- return sanitized;
314
- }
315
310
  var safeHtmlRenderer = {
316
311
  type: "html",
317
312
  priority: 0,
@@ -1177,7 +1172,7 @@ function buildMinimalRuntime(options) {
1177
1172
  }
1178
1173
 
1179
1174
  // libs/ui/src/universal/cached-runtime.ts
1180
- var import_runtime = require("@frontmcp/uipack/runtime");
1175
+ var import_runtime2 = require("@frontmcp/uipack/runtime");
1181
1176
  var import_build = require("@frontmcp/uipack/build");
1182
1177
  var RUNTIME_PLACEHOLDERS = {
1183
1178
  /** Placeholder for transpiled component code */
@@ -1655,7 +1650,7 @@ function getCachedRuntime(options, config = {}) {
1655
1650
  }
1656
1651
  const vendorParts = [];
1657
1652
  if (options.includeBridge) {
1658
- vendorParts.push((0, import_runtime.getMCPBridgeScript)());
1653
+ vendorParts.push((0, import_runtime2.getMCPBridgeScript)());
1659
1654
  }
1660
1655
  vendorParts.push(buildStoreRuntime2(), buildRequireShim());
1661
1656
  if (options.cdnType === "umd" || options.includeMarkdown) {
@@ -5,6 +5,12 @@
5
5
  * Used for pre-rendered or server-side generated HTML content.
6
6
  */
7
7
  import type { ClientRenderer } from '../types';
8
+ import { sanitizeHtmlContent } from '@frontmcp/uipack/runtime';
9
+ /**
10
+ * Re-export sanitizeHtmlContent as sanitizeHtml for backward compatibility.
11
+ * Uses DOMPurify in browser environments for robust sanitization.
12
+ */
13
+ export declare const sanitizeHtml: typeof sanitizeHtmlContent;
8
14
  /**
9
15
  * HTML renderer implementation.
10
16
  *
@@ -22,16 +28,9 @@ import type { ClientRenderer } from '../types';
22
28
  * ```
23
29
  */
24
30
  export declare const htmlRenderer: ClientRenderer;
25
- /**
26
- * Sanitize HTML string (basic XSS protection).
27
- * For production use, consider using a library like DOMPurify.
28
- *
29
- * @param html - HTML string to sanitize
30
- * @returns Sanitized HTML string
31
- */
32
- export declare function sanitizeHtml(html: string): string;
33
31
  /**
34
32
  * Create a safe HTML renderer that sanitizes content.
33
+ * Uses DOMPurify in browser environments for robust protection against XSS.
35
34
  */
36
35
  export declare const safeHtmlRenderer: ClientRenderer;
37
36
  //# sourceMappingURL=html.renderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"html.renderer.d.ts","sourceRoot":"","sources":["../../../src/universal/renderers/html.renderer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAmC,MAAM,UAAU,CAAC;AAEhF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,YAAY,EAAE,cAsB1B,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYjD;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,cAsB9B,CAAC"}
1
+ {"version":3,"file":"html.renderer.d.ts","sourceRoot":"","sources":["../../../src/universal/renderers/html.renderer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAmC,MAAM,UAAU,CAAC;AAChF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D;;;GAGG;AACH,eAAO,MAAM,YAAY,4BAAsB,CAAC;AAEhD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,YAAY,EAAE,cAsB1B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,cAsB9B,CAAC"}