sibujs 4.7.0 → 4.8.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.
Files changed (81) hide show
  1. package/dist/browser.cjs +45 -4
  2. package/dist/browser.d.cts +23 -0
  3. package/dist/browser.d.ts +23 -0
  4. package/dist/browser.js +6 -5
  5. package/dist/build.cjs +513 -78
  6. package/dist/build.d.cts +22 -8
  7. package/dist/build.d.ts +22 -8
  8. package/dist/build.js +68 -21
  9. package/dist/cdn.dev.global.js +15 -13
  10. package/dist/cdn.full.dev.global.js +15 -13
  11. package/dist/cdn.full.global.js +14 -12
  12. package/dist/cdn.global.js +14 -12
  13. package/dist/chunk-3ACAAQIN.js +224 -0
  14. package/dist/{chunk-DKXRACVN.js → chunk-44MTL7ED.js} +6 -6
  15. package/dist/{chunk-3QWBSL5R.js → chunk-4WMSTZ7J.js} +8 -5
  16. package/dist/{chunk-H3SRKIYX.js → chunk-62BDYGAG.js} +8 -0
  17. package/dist/{chunk-BSY63EM6.js → chunk-C5PEWEGH.js} +20 -5
  18. package/dist/{chunk-BC2SECJD.js → chunk-C7AA2CZX.js} +1 -1
  19. package/dist/{chunk-SLM3IA34.js → chunk-CZPRSWSS.js} +1 -1
  20. package/dist/{chunk-FQRUXCEE.js → chunk-DSID757X.js} +1 -1
  21. package/dist/{chunk-ZVL7TY4K.js → chunk-EGUQLBHE.js} +22 -8
  22. package/dist/{chunk-2INLLLMZ.js → chunk-EXXSN3BW.js} +202 -26
  23. package/dist/{chunk-HURREPU2.js → chunk-FC6KCJSA.js} +87 -150
  24. package/dist/{chunk-Z3OHK6QT.js → chunk-GSGNX35Q.js} +5 -5
  25. package/dist/{chunk-XYV3EDB7.js → chunk-J3YQ457H.js} +37 -20
  26. package/dist/{chunk-VZSG24LS.js → chunk-JUTFX2RM.js} +18 -10
  27. package/dist/{chunk-RUSSKG6G.js → chunk-KJ3UKABJ.js} +1 -1
  28. package/dist/{chunk-UNWRJRKC.js → chunk-LI4W3U6C.js} +1 -1
  29. package/dist/{chunk-FNJXNGYZ.js → chunk-O6TRVMJI.js} +58 -6
  30. package/dist/{chunk-7LUJQAOJ.js → chunk-Q5J2LVKH.js} +1 -1
  31. package/dist/{chunk-4AWA2PVD.js → chunk-QGMSESDD.js} +10 -5
  32. package/dist/{chunk-XZR4PXRE.js → chunk-RGLPEBDE.js} +13 -10
  33. package/dist/{chunk-JWKYU5GV.js → chunk-TQQUN4WR.js} +1 -1
  34. package/dist/{chunk-WOLJZUFQ.js → chunk-UCNP3HVM.js} +12 -8
  35. package/dist/{chunk-WEQ3DMVL.js → chunk-V3LHZSU5.js} +1 -1
  36. package/dist/{chunk-UOL2ECCS.js → chunk-VWT3VXPL.js} +18 -12
  37. package/dist/{chunk-2BPG2XDA.js → chunk-ZVLHNEEL.js} +17 -35
  38. package/dist/{customElement-MmInOW1U.d.ts → customElement-pYDKUzWl.d.cts} +11 -3
  39. package/dist/{customElement-MmInOW1U.d.cts → customElement-pYDKUzWl.d.ts} +11 -3
  40. package/dist/data.cjs +9 -2
  41. package/dist/data.js +6 -6
  42. package/dist/devtools.cjs +1 -1
  43. package/dist/devtools.js +5 -5
  44. package/dist/ecosystem.cjs +400 -37
  45. package/dist/ecosystem.js +9 -8
  46. package/dist/extras.cjs +621 -252
  47. package/dist/extras.d.cts +2 -2
  48. package/dist/extras.d.ts +2 -2
  49. package/dist/extras.js +24 -23
  50. package/dist/index.cjs +464 -70
  51. package/dist/index.d.cts +28 -2
  52. package/dist/index.d.ts +28 -2
  53. package/dist/index.js +16 -12
  54. package/dist/motion.cjs +1 -1
  55. package/dist/motion.js +3 -3
  56. package/dist/patterns.cjs +10 -7
  57. package/dist/patterns.js +6 -6
  58. package/dist/performance.cjs +31 -2
  59. package/dist/performance.d.cts +12 -2
  60. package/dist/performance.d.ts +12 -2
  61. package/dist/performance.js +8 -6
  62. package/dist/plugins.cjs +558 -231
  63. package/dist/plugins.d.cts +8 -3
  64. package/dist/plugins.d.ts +8 -3
  65. package/dist/plugins.js +22 -28
  66. package/dist/{ssr-XOTUASDO.js → ssr-5OWAH3U2.js} +4 -2
  67. package/dist/{ssr-Bli9XRW5.d.ts → ssr-C8hgIAw7.d.cts} +6 -0
  68. package/dist/{ssr-Bli9XRW5.d.cts → ssr-C8hgIAw7.d.ts} +6 -0
  69. package/dist/ssr.cjs +457 -131
  70. package/dist/ssr.d.cts +55 -5
  71. package/dist/ssr.d.ts +55 -5
  72. package/dist/ssr.js +11 -9
  73. package/dist/testing.cjs +3 -3
  74. package/dist/testing.js +4 -4
  75. package/dist/ui.cjs +608 -240
  76. package/dist/ui.d.cts +1 -1
  77. package/dist/ui.d.ts +1 -1
  78. package/dist/ui.js +9 -8
  79. package/dist/widgets.cjs +1 -1
  80. package/dist/widgets.js +7 -7
  81. package/package.json +5 -4
@@ -716,7 +716,7 @@ function forEachSubscriber(signal2, visit) {
716
716
  }
717
717
 
718
718
  // src/reactivity/track.ts
719
- var _runtimeVersion = true ? "4.7.0" : "dev";
719
+ var _runtimeVersion = true ? "4.8.0" : "dev";
720
720
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
721
721
  function resolveReactiveApi() {
722
722
  const g = globalThis;
@@ -1484,6 +1484,11 @@ function zustandAdapter(options) {
1484
1484
  function stripControlChars(value) {
1485
1485
  return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
1486
1486
  }
1487
+ var ASCII_UPPER = /[A-Z]/;
1488
+ var ASCII_UPPER_G = /[A-Z]/g;
1489
+ function canonicalAttrName(name) {
1490
+ return ASCII_UPPER.test(name) ? name.replace(ASCII_UPPER_G, (ch) => String.fromCharCode(ch.charCodeAt(0) + 32)) : name;
1491
+ }
1487
1492
  function isEventHandlerAttr(name) {
1488
1493
  if (name.length < 3) return false;
1489
1494
  const lower = name.toLowerCase();
@@ -1495,6 +1500,9 @@ function sanitizeUrl(url) {
1495
1500
  const probe = stripControlChars(url).trim();
1496
1501
  if (!probe) return "";
1497
1502
  const output = url.replace(OUTER_TRIM, "");
1503
+ if (probe.length >= 2 && (probe[0] === "\\" || probe[0] === "/") && (probe[1] === "\\" || probe[1] === "/") && (probe[0] === "\\" || probe[1] === "\\")) {
1504
+ return "";
1505
+ }
1498
1506
  const lower = probe.toLowerCase();
1499
1507
  let schemeEnd = -1;
1500
1508
  for (let i = 0; i < lower.length; i++) {
@@ -1511,19 +1519,58 @@ function sanitizeUrl(url) {
1511
1519
  if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
1512
1520
  return output;
1513
1521
  }
1514
- var SRCSET_DESCRIPTOR = /^\s+\d+(\.\d+)?[wx]$/;
1522
+ var SRCSET_DESCRIPTOR = /^\d+(\.\d+)?[wx]$/;
1523
+ function isSrcsetWhitespace(ch) {
1524
+ return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
1525
+ }
1515
1526
  function sanitizeSrcset(value) {
1516
- const parts = value.split(",");
1527
+ const input = String(value);
1517
1528
  const out = [];
1518
- for (let i = 0; i < parts.length; i++) {
1519
- const part = parts[i].trim();
1520
- if (!part) continue;
1521
- const m = part.match(/^(\S+)(\s+.+)?$/);
1522
- if (!m) continue;
1523
- if (m[2] !== void 0 && !SRCSET_DESCRIPTOR.test(m[2])) continue;
1524
- const safe = sanitizeUrl(m[1]);
1529
+ let i = 0;
1530
+ const n = input.length;
1531
+ while (i < n) {
1532
+ while (i < n && (isSrcsetWhitespace(input[i]) || input[i] === ",")) i++;
1533
+ if (i >= n) break;
1534
+ const urlStart = i;
1535
+ while (i < n && !isSrcsetWhitespace(input[i])) i++;
1536
+ let url = input.slice(urlStart, i);
1537
+ const descriptors = [];
1538
+ if (url.endsWith(",")) {
1539
+ url = url.replace(/,+$/, "");
1540
+ } else {
1541
+ let current = "";
1542
+ let inParens = false;
1543
+ while (i < n) {
1544
+ const ch = input[i];
1545
+ if (inParens) {
1546
+ current += ch;
1547
+ if (ch === ")") inParens = false;
1548
+ i++;
1549
+ continue;
1550
+ }
1551
+ if (isSrcsetWhitespace(ch)) {
1552
+ if (current) descriptors.push(current);
1553
+ current = "";
1554
+ i++;
1555
+ continue;
1556
+ }
1557
+ if (ch === ",") {
1558
+ i++;
1559
+ break;
1560
+ }
1561
+ if (ch === "(") inParens = true;
1562
+ current += ch;
1563
+ i++;
1564
+ }
1565
+ if (current) descriptors.push(current);
1566
+ }
1567
+ if (url === "") continue;
1568
+ if (descriptors.length > 1) continue;
1569
+ if (descriptors.length === 1 && !SRCSET_DESCRIPTOR.test(descriptors[0])) continue;
1570
+ const safe = sanitizeUrl(url);
1525
1571
  if (!safe) continue;
1526
- out.push(m[2] ? `${safe}${m[2]}` : safe);
1572
+ if (safe.startsWith(",") || safe.endsWith(",")) continue;
1573
+ out.push(descriptors.length === 1 ? `${safe} ${descriptors[0]}` : safe);
1527
1574
  }
1528
1575
  return out.join(", ");
1529
1576
  }
@@ -1582,8 +1629,16 @@ var BLOCKED_CSS_NEEDLES = [
1582
1629
  "behavior:",
1583
1630
  "@import",
1584
1631
  "image-set(",
1585
- "filter:progid"
1632
+ "filter:progid",
1633
+ // CSS Images 4 `image("…")` and CSS Values 5 `src("…")` take a URL as a
1634
+ // plain STRING, so they fetch without ever spelling `url(`. Support is thin
1635
+ // today, which is exactly when a blocklist should get ahead of it.
1636
+ "image(",
1637
+ "src("
1586
1638
  ];
1639
+ var CSS_REASON_MOZ_BINDING = 4;
1640
+ var CSS_REASON_BEHAVIOR = 5;
1641
+ var CSS_REASON_PROGID = 8;
1587
1642
  function describeElement(el) {
1588
1643
  if (!el) return "an element";
1589
1644
  let out = el.tagName.toLowerCase();
@@ -1607,7 +1662,9 @@ function warnDroppedDeclaration(value, reason, ctx) {
1607
1662
  "behavior: loads and runs a remote HTC script",
1608
1663
  "@import pulls in a remote stylesheet",
1609
1664
  "image-set() fetches remote images, the same exfiltration channel as url()",
1610
- "filter:progid activates legacy scriptable filters"
1665
+ "filter:progid activates legacy scriptable filters",
1666
+ "image() fetches its string argument as a URL, the same exfiltration channel as url()",
1667
+ "src() fetches its string argument as a URL, the same exfiltration channel as url()"
1611
1668
  ];
1612
1669
  const declaration = ctx?.property ? `${ctx.property}: ${value}` : value;
1613
1670
  const where = describeElement(ctx?.element);
@@ -1622,27 +1679,110 @@ function warnDroppedDeclaration(value, reason, ctx) {
1622
1679
  return `style declaration "${declaration}" was dropped by the style sanitizer on ${where} \u2014 ${reasons[reason]}. The element renders without it, which usually looks like a missing image rather than an error. Sanctioned alternatives: for a content image use an <img> element (or a <picture>); for decoration, put the rule in a stylesheet and set a class instead \u2014 stylesheet CSS is not sanitized, only inline style attributes are. If this declaration is not yours, it came from untrusted data and the drop just prevented an exfiltration.`;
1623
1680
  });
1624
1681
  }
1682
+ function normalizeCssForScan(value) {
1683
+ const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
1684
+ return normalized.toLowerCase().replace(/\s+/g, "");
1685
+ }
1625
1686
  function blockedCssReason(value) {
1626
1687
  if (!CSS_DANGER_GATE.test(value)) return -1;
1627
- const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
1628
- const lower = normalized.toLowerCase().replace(/\s+/g, "");
1688
+ const lower = normalizeCssForScan(value);
1629
1689
  for (let i = 0; i < BLOCKED_CSS_NEEDLES.length; i++) {
1630
1690
  if (lower.includes(BLOCKED_CSS_NEEDLES[i])) return i;
1631
1691
  }
1632
1692
  return -1;
1633
1693
  }
1634
- function sanitizeCSSValue(value, context) {
1635
- const reason = blockedCssReason(value);
1694
+ function sanitizeCSSDeclaration(property, value, context) {
1695
+ const reason = blockedDeclarationReason(property, value);
1636
1696
  if (reason === -1) return value;
1637
- warnDroppedDeclaration(value, reason, context);
1697
+ warnDroppedDeclaration(value, reason, { property, element: context?.element });
1638
1698
  return "";
1639
1699
  }
1700
+ function blockedDeclarationReason(property, value) {
1701
+ const reason = blockedCssReason(value);
1702
+ if (reason !== -1) return reason;
1703
+ const name = canonicalAttrName(property);
1704
+ if (name === "behavior") return CSS_REASON_BEHAVIOR;
1705
+ if (name === "-moz-binding") return CSS_REASON_MOZ_BINDING;
1706
+ if ((name === "filter" || name === "-ms-filter") && normalizeCssForScan(value).includes("progid:")) {
1707
+ return CSS_REASON_PROGID;
1708
+ }
1709
+ return -1;
1710
+ }
1711
+ function parseStyleDeclarations(css) {
1712
+ const chunks = [];
1713
+ let buf = "";
1714
+ let depth = 0;
1715
+ let quote2 = "";
1716
+ for (let i = 0; i < css.length; i++) {
1717
+ const ch = css[i];
1718
+ if (quote2) {
1719
+ buf += ch;
1720
+ if (ch === "\\" && i + 1 < css.length) buf += css[++i];
1721
+ else if (ch === quote2) quote2 = "";
1722
+ continue;
1723
+ }
1724
+ if (ch === "\\") {
1725
+ buf += ch;
1726
+ if (i + 1 < css.length) buf += css[++i];
1727
+ continue;
1728
+ }
1729
+ if (ch === "/" && css[i + 1] === "*") {
1730
+ const end = css.indexOf("*/", i + 2);
1731
+ if (end === -1) return null;
1732
+ i = end + 1;
1733
+ continue;
1734
+ }
1735
+ if (ch === '"' || ch === "'") quote2 = ch;
1736
+ else if (ch === "(" || ch === "[") depth++;
1737
+ else if (ch === ")" || ch === "]") {
1738
+ if (--depth < 0) return null;
1739
+ } else if (ch === "{" || ch === "}") return null;
1740
+ else if (ch === ";" && depth === 0) {
1741
+ chunks.push(buf);
1742
+ buf = "";
1743
+ continue;
1744
+ }
1745
+ buf += ch;
1746
+ }
1747
+ if (quote2 || depth !== 0) return null;
1748
+ chunks.push(buf);
1749
+ const out = [];
1750
+ for (const chunk of chunks) {
1751
+ const colon = chunk.indexOf(":");
1752
+ if (colon === -1) continue;
1753
+ const rawName = chunk.slice(0, colon).trim();
1754
+ if (!/^(--[\w-]+|-?[a-zA-Z_][\w-]*)$/.test(rawName)) continue;
1755
+ let value = chunk.slice(colon + 1).trim();
1756
+ const bang = /!\s*important\s*$/i.exec(value);
1757
+ if (bang) value = value.slice(0, bang.index).trim();
1758
+ if (value === "") continue;
1759
+ const property = rawName.startsWith("--") ? rawName : canonicalAttrName(rawName);
1760
+ out.push([property, value, bang !== null]);
1761
+ }
1762
+ return out;
1763
+ }
1764
+ function sanitizeStyleDeclarationList(cssText, context) {
1765
+ const input = String(cssText);
1766
+ const declarations = parseStyleDeclarations(input);
1767
+ if (declarations === null) {
1768
+ if (blockedCssReason(input) !== -1) warnDroppedDeclaration(input, blockedCssReason(input), context);
1769
+ return "";
1770
+ }
1771
+ const kept = [];
1772
+ for (const [property, value, important] of declarations) {
1773
+ const reason = blockedDeclarationReason(property, value);
1774
+ if (reason !== -1) {
1775
+ warnDroppedDeclaration(value, reason, { property, element: context?.element });
1776
+ continue;
1777
+ }
1778
+ kept.push(`${property}: ${value}${important ? " !important" : ""}`);
1779
+ }
1780
+ return kept.join("; ");
1781
+ }
1640
1782
  function sanitizeStyleAttribute(cssText, context) {
1641
1783
  const input = String(cssText);
1642
1784
  if (input.trim() === "") return "";
1643
- if (typeof document === "undefined") {
1644
- return sanitizeCSSValue(input, context) === "" ? "" : input;
1645
- }
1785
+ if (typeof document === "undefined") return sanitizeStyleDeclarationList(input, context);
1646
1786
  const probe = document.createElement("div");
1647
1787
  try {
1648
1788
  probe.style.cssText = input;
@@ -1653,8 +1793,7 @@ function sanitizeStyleAttribute(cssText, context) {
1653
1793
  for (let i = 0; i < probe.style.length; i++) {
1654
1794
  const property = probe.style[i];
1655
1795
  const value = probe.style.getPropertyValue(property);
1656
- let reason = blockedCssReason(value);
1657
- if (reason === -1) reason = blockedCssReason(`${property}:${value}`);
1796
+ const reason = blockedDeclarationReason(property, value);
1658
1797
  if (reason !== -1) {
1659
1798
  warnDroppedDeclaration(value, reason, { property, element: context?.element });
1660
1799
  continue;
@@ -1686,6 +1825,13 @@ var HTML_CONTENT_ATTRIBUTES = /* @__PURE__ */ new Set(["srcdoc"]);
1686
1825
  function isHtmlContentAttribute(name) {
1687
1826
  return HTML_CONTENT_ATTRIBUTES.has(name.toLowerCase());
1688
1827
  }
1828
+ function isUrlAttribute(attr) {
1829
+ return URL_ATTRIBUTES.has(attr.toLowerCase());
1830
+ }
1831
+ function isPolicyAttribute(name) {
1832
+ const lower = name.toLowerCase();
1833
+ return lower === "style" || URL_ATTRIBUTES.has(lower);
1834
+ }
1689
1835
  function sanitizeAttributeString(attr, value, context) {
1690
1836
  const lower = attr.toLowerCase();
1691
1837
  if (lower === "srcset") return sanitizeSrcset(value);
@@ -1693,27 +1839,229 @@ function sanitizeAttributeString(attr, value, context) {
1693
1839
  if (lower === "style") return sanitizeStyleAttribute(value, context);
1694
1840
  return value;
1695
1841
  }
1842
+ function resolveAttributeValue(attr, value, context) {
1843
+ if (!isPolicyAttribute(attr)) return value;
1844
+ const safe = sanitizeAttributeString(attr, value, context);
1845
+ return safe === "" ? null : safe;
1846
+ }
1696
1847
 
1697
- // src/utils/setSafeAttribute.ts
1848
+ // src/utils/metaRefresh.ts
1849
+ function isAsciiWhitespace(ch) {
1850
+ return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
1851
+ }
1852
+ function trimAsciiWhitespace(value) {
1853
+ let start = 0;
1854
+ let end = value.length;
1855
+ while (start < end && isAsciiWhitespace(value[start])) start++;
1856
+ while (end > start && isAsciiWhitespace(value[end - 1])) end--;
1857
+ return value.slice(start, end);
1858
+ }
1859
+ var forbidden = (reason) => ({ kind: "forbidden", reason });
1860
+ function parseMetaRefreshContent(content) {
1861
+ const raw = trimAsciiWhitespace(stripControlChars(content));
1862
+ if (raw === "") return forbidden(DEV ? "empty content" : "");
1863
+ let i = 0;
1864
+ while (i < raw.length && raw[i] >= "0" && raw[i] <= "9") i++;
1865
+ if (i === 0) return forbidden(DEV ? "missing or non-numeric delay" : "");
1866
+ const delay = Number.parseInt(raw.slice(0, i), 10);
1867
+ if (!Number.isFinite(delay)) return forbidden(DEV ? "unparseable delay" : "");
1868
+ while (i < raw.length && isAsciiWhitespace(raw[i])) i++;
1869
+ if (i === raw.length) return { kind: "delay-only", delay };
1870
+ if (raw[i] !== ";" && raw[i] !== ",") return forbidden(DEV ? "unexpected text after delay" : "");
1871
+ i++;
1872
+ while (i < raw.length && isAsciiWhitespace(raw[i])) i++;
1873
+ const keyStart = i;
1874
+ while (i < raw.length && !isAsciiWhitespace(raw[i]) && raw[i] !== "=") i++;
1875
+ const key = raw.slice(keyStart, i).toLowerCase();
1876
+ if (key !== "url") return forbidden(DEV ? `unsupported refresh key ${JSON.stringify(key)}` : "");
1877
+ while (i < raw.length && isAsciiWhitespace(raw[i])) i++;
1878
+ if (raw[i] !== "=") return forbidden(DEV ? "missing '=' after url" : "");
1879
+ i++;
1880
+ while (i < raw.length && isAsciiWhitespace(raw[i])) i++;
1881
+ let destination;
1882
+ const quote2 = raw[i];
1883
+ if (quote2 === '"' || quote2 === "'") {
1884
+ const close = raw.indexOf(quote2, i + 1);
1885
+ if (close === -1) return forbidden(DEV ? "unterminated quoted destination" : "");
1886
+ destination = raw.slice(i + 1, close);
1887
+ const rest = trimAsciiWhitespace(raw.slice(close + 1));
1888
+ if (rest !== "") return forbidden(DEV ? "trailing text after quoted destination" : "");
1889
+ } else {
1890
+ destination = trimAsciiWhitespace(raw.slice(i));
1891
+ if (/[;,]/.test(destination)) return forbidden(DEV ? "multiple refresh assignments" : "");
1892
+ }
1893
+ if (destination === "") return forbidden(DEV ? "empty destination" : "");
1894
+ const sanitizedDestination = sanitizeUrl(destination);
1895
+ if (sanitizedDestination === "") return forbidden(DEV ? "destination uses a disallowed protocol" : "");
1896
+ return { kind: "allowed", delay, destination, sanitizedDestination };
1897
+ }
1898
+ function resolveMetaRefreshPolicy(attributes) {
1899
+ let httpEquiv;
1900
+ let content;
1901
+ let duplicateName;
1902
+ const seen = /* @__PURE__ */ new Set();
1903
+ for (const [key, value] of attributes) {
1904
+ const canonical = canonicalAttrName(key);
1905
+ if (seen.has(canonical)) duplicateName = canonical;
1906
+ seen.add(canonical);
1907
+ if (canonical === "http-equiv") httpEquiv = value;
1908
+ else if (canonical === "content") content = value;
1909
+ }
1910
+ if (duplicateName !== void 0) {
1911
+ return forbidden(DEV ? `duplicate case-insensitive attribute ${JSON.stringify(duplicateName)}` : "");
1912
+ }
1913
+ if (typeof httpEquiv !== "string") return { kind: "not-refresh" };
1914
+ if (trimAsciiWhitespace(stripControlChars(httpEquiv)).toLowerCase() !== "refresh") {
1915
+ return { kind: "not-refresh" };
1916
+ }
1917
+ if (typeof content !== "string") return { kind: "not-refresh" };
1918
+ return parseMetaRefreshContent(content);
1919
+ }
1920
+
1921
+ // src/utils/elementPolicy.ts
1698
1922
  var HTML_NS = "http://www.w3.org/1999/xhtml";
1699
1923
  var SVG_NS = "http://www.w3.org/2000/svg";
1924
+ var BLOCKED_ELEMENTS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
1925
+ function canonicalTagName(tag) {
1926
+ return canonicalAttrName(tag);
1927
+ }
1928
+ function isBlockedElement(tag) {
1929
+ return BLOCKED_ELEMENTS.has(canonicalTagName(tag));
1930
+ }
1931
+ var ContextualRefusal = {
1932
+ None: 0,
1933
+ /** The element would carry a refresh directive the shared policy forbids. */
1934
+ MetaRefreshForbidden: 1,
1935
+ /** A `<meta>` with a reactive binding may not carry any refresh directive. */
1936
+ MetaRefreshReactive: 2,
1937
+ /** A runtime value may not choose which program a `<script>` runs. */
1938
+ ScriptSource: 3,
1939
+ /** An SVG animation may not target a URL, handler or document attribute. */
1940
+ AnimationTarget: 4,
1941
+ /** A runtime-written `href` may not become an applied stylesheet. */
1942
+ StylesheetSource: 5
1943
+ };
1944
+ var SCRIPT_SOURCE_ATTRIBUTES = /* @__PURE__ */ new Set(["src", "href", "xlink:href", "type", "language"]);
1945
+ var SVG_ANIMATION_ELEMENTS = /* @__PURE__ */ new Set(["animate", "set", "animateMotion", "animateTransform", "animateColor"]);
1946
+ var reactiveMetaElements = /* @__PURE__ */ new WeakSet();
1947
+ function isHtmlNamespace(el) {
1948
+ return el.namespaceURI === HTML_NS || el.namespaceURI === null;
1949
+ }
1950
+ function metaSnapshot(el, canonical, value) {
1951
+ const snapshot = /* @__PURE__ */ new Map();
1952
+ const attrs = el.attributes;
1953
+ for (let i = 0; i < attrs.length; i++) {
1954
+ const attr = attrs[i];
1955
+ if (attr.name === canonical) continue;
1956
+ snapshot.set(attr.name, attr.value);
1957
+ }
1958
+ if (canonical !== null && value !== null) snapshot.set(canonical, value);
1959
+ return snapshot;
1960
+ }
1961
+ function claimReactiveMeta(el) {
1962
+ if (reactiveMetaElements.has(el)) return;
1963
+ reactiveMetaElements.add(el);
1964
+ if (el.getAttribute("content") === null) return;
1965
+ if (resolveMetaRefreshPolicy(metaSnapshot(el, null, null)).kind !== "not-refresh") {
1966
+ el.removeAttribute("content");
1967
+ }
1968
+ }
1969
+ function metaRefusal(el, name, value, origin) {
1970
+ if (!isHtmlNamespace(el)) return ContextualRefusal.None;
1971
+ const canonical = canonicalAttrName(name);
1972
+ if (canonical !== "http-equiv" && canonical !== "content") return ContextualRefusal.None;
1973
+ if (origin === "reactive") claimReactiveMeta(el);
1974
+ if (value === null) return ContextualRefusal.None;
1975
+ if (canonical === "content" && !el.hasAttribute("http-equiv")) return ContextualRefusal.None;
1976
+ const decision = resolveMetaRefreshPolicy(metaSnapshot(el, canonical, value));
1977
+ if (decision.kind === "forbidden") return ContextualRefusal.MetaRefreshForbidden;
1978
+ if (decision.kind !== "not-refresh" && reactiveMetaElements.has(el)) return ContextualRefusal.MetaRefreshReactive;
1979
+ return ContextualRefusal.None;
1980
+ }
1981
+ function animationRefusal(name, value) {
1982
+ if (value === null || canonicalAttrName(name) !== "attributename") return ContextualRefusal.None;
1983
+ const target = stripControlChars(value);
1984
+ return isUrlAttribute(target) || isEventHandlerAttr(target) || isHtmlContentAttribute(target) ? ContextualRefusal.AnimationTarget : ContextualRefusal.None;
1985
+ }
1986
+ var runtimeHrefLinks = /* @__PURE__ */ new WeakSet();
1987
+ function relHasStylesheet(rel) {
1988
+ if (rel === null) return false;
1989
+ const lower = canonicalAttrName(rel);
1990
+ if (!lower.includes("stylesheet")) return false;
1991
+ const tokens = lower.split(/[\t\n\f\r ]+/);
1992
+ for (let i = 0; i < tokens.length; i++) if (tokens[i] === "stylesheet") return true;
1993
+ return false;
1994
+ }
1995
+ function stylesheetRefusal(el, name, value, origin) {
1996
+ if (!isHtmlNamespace(el)) return ContextualRefusal.None;
1997
+ const canonical = canonicalAttrName(name);
1998
+ if (canonical === "href") {
1999
+ if (origin === "static" || value === null) return ContextualRefusal.None;
2000
+ if (relHasStylesheet(el.getAttribute("rel"))) return ContextualRefusal.StylesheetSource;
2001
+ runtimeHrefLinks.add(el);
2002
+ return ContextualRefusal.None;
2003
+ }
2004
+ if (canonical === "rel") {
2005
+ if (!relHasStylesheet(value)) return ContextualRefusal.None;
2006
+ return runtimeHrefLinks.has(el) && el.hasAttribute("href") ? ContextualRefusal.StylesheetSource : ContextualRefusal.None;
2007
+ }
2008
+ return ContextualRefusal.None;
2009
+ }
2010
+ function contextualAttributeRefusal(el, name, value, origin) {
2011
+ const local = el.localName;
2012
+ if (local === "meta") return metaRefusal(el, name, value, origin);
2013
+ if (local === "link") return stylesheetRefusal(el, name, value, origin);
2014
+ if (local === "script") {
2015
+ if (origin === "static" || value === null) return ContextualRefusal.None;
2016
+ return SCRIPT_SOURCE_ATTRIBUTES.has(canonicalAttrName(name)) ? ContextualRefusal.ScriptSource : ContextualRefusal.None;
2017
+ }
2018
+ if (SVG_ANIMATION_ELEMENTS.has(local) && el.namespaceURI === SVG_NS) return animationRefusal(name, value);
2019
+ return ContextualRefusal.None;
2020
+ }
2021
+ function settleAttributeProvenance(el, name, origin) {
2022
+ if (el.localName !== "link" || canonicalAttrName(name) !== "href") return;
2023
+ if (origin !== "static" && el.hasAttribute("href")) runtimeHrefLinks.add(el);
2024
+ else runtimeHrefLinks.delete(el);
2025
+ }
2026
+
2027
+ // src/utils/setSafeAttribute.ts
2028
+ var HTML_NS2 = "http://www.w3.org/1999/xhtml";
2029
+ var SVG_NS2 = "http://www.w3.org/2000/svg";
1700
2030
  var XLINK_NS = "http://www.w3.org/1999/xlink";
1701
2031
  var XML_NS = "http://www.w3.org/XML/1998/namespace";
1702
2032
  var BOOLEAN_IDL_ATTRS = /* @__PURE__ */ new Set(["checked", "disabled", "selected"]);
1703
2033
  function isHtmlElement(el) {
1704
- return el.namespaceURI === null || el.namespaceURI === HTML_NS;
2034
+ return el.namespaceURI === null || el.namespaceURI === HTML_NS2;
2035
+ }
2036
+ function warnContextualRefusal(label, name, refusal) {
2037
+ devWarnLazy(() => {
2038
+ const reasons = [
2039
+ "",
2040
+ 'the element would become a <meta http-equiv="refresh"> directive the shared refresh policy forbids (a destination outside the URL allowlist, or a directive too malformed to read unambiguously)',
2041
+ "a <meta> whose http-equiv or content is reactive may never carry a refresh directive: a browser schedules the navigation as soon as the directive is valid, and nothing can withdraw it when the state changes back",
2042
+ "a runtime value may not choose the program a <script> runs; name the script in static template source, or load it through Head({ script }) as an explicit trust decision",
2043
+ "an SVG animation may not target a URL, event-handler or nested-document attribute; its to / values would be written into that attribute without passing the URL policy",
2044
+ 'a runtime-chosen href may not become an applied <link rel="stylesheet">: a well-formed URL is not a trusted stylesheet. Name the stylesheet in static template source, or load a runtime-chosen one through Head({ link }) as an explicit trust decision'
2045
+ ];
2046
+ return `${label}: refusing "${name}" in this element's context \u2014 ${reasons[refusal]}. The write was not performed.`;
2047
+ });
1705
2048
  }
1706
2049
  function setProp(el, key, val) {
1707
2050
  el[key] = val;
1708
2051
  }
1709
2052
  function namespaceFor(el, name) {
1710
- if (el.namespaceURI !== SVG_NS) return null;
2053
+ if (el.namespaceURI !== SVG_NS2) return null;
1711
2054
  const lower = name.toLowerCase();
1712
2055
  if (lower.startsWith("xlink:")) return XLINK_NS;
1713
2056
  if (lower.startsWith("xml:")) return XML_NS;
1714
2057
  return null;
1715
2058
  }
1716
2059
  function setSafeAttribute(el, name, value, options = {}) {
2060
+ const written = commitSafeAttribute(el, name, value, options);
2061
+ if (el.localName === "link") settleAttributeProvenance(el, name, options.reactive ? "reactive" : "runtime");
2062
+ return written;
2063
+ }
2064
+ function commitSafeAttribute(el, name, value, options) {
1717
2065
  const ns = namespaceFor(el, name);
1718
2066
  const localName = ns ? name.slice(name.indexOf(":") + 1) : name;
1719
2067
  if (isEventHandlerAttr(name)) {
@@ -1726,6 +2074,14 @@ function setSafeAttribute(el, name, value, options = {}) {
1726
2074
  else el.removeAttribute(name);
1727
2075
  return false;
1728
2076
  }
2077
+ const pending = value == null || value === false ? null : value === true ? "" : String(value);
2078
+ const refusal = contextualAttributeRefusal(el, name, pending, options.reactive ? "reactive" : "runtime");
2079
+ if (refusal !== ContextualRefusal.None) {
2080
+ warnContextualRefusal(options.label ?? "setSafeAttribute", name, refusal);
2081
+ if (ns) el.removeAttributeNS(ns, localName);
2082
+ else el.removeAttribute(name);
2083
+ return false;
2084
+ }
1729
2085
  if (value == null) {
1730
2086
  if (ns) el.removeAttributeNS(ns, localName);
1731
2087
  else el.removeAttribute(name);
@@ -1769,7 +2125,12 @@ function setSafeAttribute(el, name, value, options = {}) {
1769
2125
  setProp(el, idlName, idlName === "checked" ? Boolean(value) : str);
1770
2126
  return true;
1771
2127
  }
1772
- const safe = sanitizeAttributeString(name, str, { element: el });
2128
+ const safe = str === "" ? "" : resolveAttributeValue(name, str, { element: el });
2129
+ if (safe === null) {
2130
+ if (ns) el.removeAttributeNS(ns, localName);
2131
+ else el.removeAttribute(name);
2132
+ return true;
2133
+ }
1773
2134
  const current = ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name);
1774
2135
  if (current === safe) return true;
1775
2136
  if (ns) el.setAttributeNS(ns, name, safe);
@@ -1792,7 +2153,7 @@ function bindAttribute(el, attr, getter) {
1792
2153
  reportError(err, { phase: "binding", name: `bindAttribute("${attr}")`, node: el });
1793
2154
  return;
1794
2155
  }
1795
- setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")` });
2156
+ setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")`, reactive: true });
1796
2157
  }
1797
2158
  return reactiveBinding2(commit, el);
1798
2159
  }
@@ -1966,10 +2327,6 @@ function bindChildNode(placeholder, getter) {
1966
2327
  }
1967
2328
 
1968
2329
  // src/core/rendering/tagFactory.ts
1969
- var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
1970
- function isBlockedTag(tag) {
1971
- return BLOCKED_TAGS.has(tag.toLowerCase());
1972
- }
1973
2330
  var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
1974
2331
  "config",
1975
2332
  "location",
@@ -2014,11 +2371,12 @@ function applyStyle(el, style) {
2014
2371
  }
2015
2372
  const next = [];
2016
2373
  for (const prop in value) {
2374
+ if (!Object.hasOwn(value, prop)) continue;
2017
2375
  const val = value[prop];
2018
2376
  if (val == null) continue;
2019
2377
  const name = toKebab(prop);
2020
2378
  next.push(name);
2021
- decl.setProperty(name, sanitizeCSSValue(String(val), { property: name, element: el }));
2379
+ decl.setProperty(name, sanitizeCSSDeclaration(name, String(val), { element: el }));
2022
2380
  }
2023
2381
  for (let i = 0; i < written.length; i++) {
2024
2382
  if (next.indexOf(written[i]) === -1) decl.removeProperty(written[i]);
@@ -2034,16 +2392,17 @@ function applyStyle(el, style) {
2034
2392
  }
2035
2393
  const htmlEl = el;
2036
2394
  for (const prop in style) {
2395
+ if (!Object.hasOwn(style, prop)) continue;
2037
2396
  const val = style[prop];
2038
2397
  const name = toKebab(prop);
2039
2398
  if (typeof val === "function") {
2040
2399
  const getter = val;
2041
2400
  const teardown = reactiveBinding2(() => {
2042
- htmlEl.style.setProperty(name, sanitizeCSSValue(String(getter()), { property: name, element: el }));
2401
+ htmlEl.style.setProperty(name, sanitizeCSSDeclaration(name, String(getter()), { element: el }));
2043
2402
  }, el);
2044
2403
  registerDisposer(el, teardown);
2045
2404
  } else {
2046
- htmlEl.style.setProperty(name, sanitizeCSSValue(String(val), { property: name, element: el }));
2405
+ htmlEl.style.setProperty(name, sanitizeCSSDeclaration(name, String(val), { element: el }));
2047
2406
  }
2048
2407
  }
2049
2408
  }
@@ -2065,6 +2424,7 @@ function applyClass(el, cls) {
2065
2424
  let hasReactive = false;
2066
2425
  let result = "";
2067
2426
  for (const name in obj) {
2427
+ if (!Object.hasOwn(obj, name)) continue;
2068
2428
  const val = obj[name];
2069
2429
  if (typeof val === "function") {
2070
2430
  hasReactive = true;
@@ -2076,6 +2436,7 @@ function applyClass(el, cls) {
2076
2436
  const update = () => {
2077
2437
  let r = "";
2078
2438
  for (const name in obj) {
2439
+ if (!Object.hasOwn(obj, name)) continue;
2079
2440
  const val = obj[name];
2080
2441
  const active = typeof val === "function" ? val() : val;
2081
2442
  if (active) r = r ? `${r} ${name}` : name;
@@ -2139,7 +2500,7 @@ function appendChildren(el, nodes) {
2139
2500
  }
2140
2501
  }
2141
2502
  function tagFactory(tag, ns) {
2142
- const blocked = isBlockedTag(tag);
2503
+ const blocked = isBlockedElement(tag);
2143
2504
  return (first, second) => {
2144
2505
  if (blocked) {
2145
2506
  throw new Error(`tagFactory: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
@@ -2202,6 +2563,7 @@ function tagFactory(tag, ns) {
2202
2563
  const pOn = props.on;
2203
2564
  if (pOn) {
2204
2565
  for (const ev in pOn) {
2566
+ if (!Object.hasOwn(pOn, ev)) continue;
2205
2567
  const handler = pOn[ev];
2206
2568
  if (typeof handler === "function") {
2207
2569
  el.addEventListener(ev, handler);
@@ -2228,6 +2590,7 @@ function tagFactory(tag, ns) {
2228
2590
  continue;
2229
2591
  // already handled above / below
2230
2592
  default: {
2593
+ if (!Object.hasOwn(props, key)) continue;
2231
2594
  const value = props[key];
2232
2595
  if (value == null) continue;
2233
2596
  if (isEventHandlerAttr(key)) continue;
@@ -2252,7 +2615,7 @@ var _themeLayers = globalSingleton(
2252
2615
  function commitThemeProperty(root, name, record) {
2253
2616
  const top = record.layers[record.layers.length - 1];
2254
2617
  if (top) {
2255
- root.style.setProperty(name, top.value);
2618
+ root.style.setProperty(name, sanitizeCSSDeclaration(name, String(top.value), { element: root }));
2256
2619
  return;
2257
2620
  }
2258
2621
  _themeLayers.get(root)?.delete(name);
package/dist/ecosystem.js CHANGED
@@ -7,18 +7,19 @@ import {
7
7
  mobXAdapter,
8
8
  reduxAdapter,
9
9
  zustandAdapter
10
- } from "./chunk-3QWBSL5R.js";
10
+ } from "./chunk-4WMSTZ7J.js";
11
11
  import "./chunk-J6FW5TV6.js";
12
- import "./chunk-UOL2ECCS.js";
13
- import "./chunk-FNJXNGYZ.js";
14
- import "./chunk-RUSSKG6G.js";
15
- import "./chunk-2INLLLMZ.js";
12
+ import "./chunk-VWT3VXPL.js";
13
+ import "./chunk-O6TRVMJI.js";
14
+ import "./chunk-3ACAAQIN.js";
15
+ import "./chunk-KJ3UKABJ.js";
16
16
  import "./chunk-7ZHH77QA.js";
17
- import "./chunk-WEQ3DMVL.js";
17
+ import "./chunk-V3LHZSU5.js";
18
+ import "./chunk-EXXSN3BW.js";
18
19
  import "./chunk-7XHATCIH.js";
19
20
  import "./chunk-5HZXGZ6T.js";
20
- import "./chunk-FQRUXCEE.js";
21
- import "./chunk-JWKYU5GV.js";
21
+ import "./chunk-DSID757X.js";
22
+ import "./chunk-TQQUN4WR.js";
22
23
  import "./chunk-NYNYSPK7.js";
23
24
  export {
24
25
  antdAdapter,