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
@@ -0,0 +1,224 @@
1
+ import {
2
+ canonicalAttrName,
3
+ isEventHandlerAttr,
4
+ isHtmlContentAttribute,
5
+ isUrlAttribute,
6
+ sanitizeUrl,
7
+ stripControlChars
8
+ } from "./chunk-EXXSN3BW.js";
9
+ import {
10
+ DEV
11
+ } from "./chunk-NYNYSPK7.js";
12
+
13
+ // src/utils/metaRefresh.ts
14
+ function isAsciiWhitespace(ch) {
15
+ return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
16
+ }
17
+ function trimAsciiWhitespace(value) {
18
+ let start = 0;
19
+ let end = value.length;
20
+ while (start < end && isAsciiWhitespace(value[start])) start++;
21
+ while (end > start && isAsciiWhitespace(value[end - 1])) end--;
22
+ return value.slice(start, end);
23
+ }
24
+ var forbidden = (reason) => ({ kind: "forbidden", reason });
25
+ function parseMetaRefreshContent(content) {
26
+ const raw = trimAsciiWhitespace(stripControlChars(content));
27
+ if (raw === "") return forbidden(DEV ? "empty content" : "");
28
+ let i = 0;
29
+ while (i < raw.length && raw[i] >= "0" && raw[i] <= "9") i++;
30
+ if (i === 0) return forbidden(DEV ? "missing or non-numeric delay" : "");
31
+ const delay = Number.parseInt(raw.slice(0, i), 10);
32
+ if (!Number.isFinite(delay)) return forbidden(DEV ? "unparseable delay" : "");
33
+ while (i < raw.length && isAsciiWhitespace(raw[i])) i++;
34
+ if (i === raw.length) return { kind: "delay-only", delay };
35
+ if (raw[i] !== ";" && raw[i] !== ",") return forbidden(DEV ? "unexpected text after delay" : "");
36
+ i++;
37
+ while (i < raw.length && isAsciiWhitespace(raw[i])) i++;
38
+ const keyStart = i;
39
+ while (i < raw.length && !isAsciiWhitespace(raw[i]) && raw[i] !== "=") i++;
40
+ const key = raw.slice(keyStart, i).toLowerCase();
41
+ if (key !== "url") return forbidden(DEV ? `unsupported refresh key ${JSON.stringify(key)}` : "");
42
+ while (i < raw.length && isAsciiWhitespace(raw[i])) i++;
43
+ if (raw[i] !== "=") return forbidden(DEV ? "missing '=' after url" : "");
44
+ i++;
45
+ while (i < raw.length && isAsciiWhitespace(raw[i])) i++;
46
+ let destination;
47
+ const quote = raw[i];
48
+ if (quote === '"' || quote === "'") {
49
+ const close = raw.indexOf(quote, i + 1);
50
+ if (close === -1) return forbidden(DEV ? "unterminated quoted destination" : "");
51
+ destination = raw.slice(i + 1, close);
52
+ const rest = trimAsciiWhitespace(raw.slice(close + 1));
53
+ if (rest !== "") return forbidden(DEV ? "trailing text after quoted destination" : "");
54
+ } else {
55
+ destination = trimAsciiWhitespace(raw.slice(i));
56
+ if (/[;,]/.test(destination)) return forbidden(DEV ? "multiple refresh assignments" : "");
57
+ }
58
+ if (destination === "") return forbidden(DEV ? "empty destination" : "");
59
+ const sanitizedDestination = sanitizeUrl(destination);
60
+ if (sanitizedDestination === "") return forbidden(DEV ? "destination uses a disallowed protocol" : "");
61
+ return { kind: "allowed", delay, destination, sanitizedDestination };
62
+ }
63
+ function resolveMetaRefreshPolicy(attributes) {
64
+ let httpEquiv;
65
+ let content;
66
+ let duplicateName;
67
+ const seen = /* @__PURE__ */ new Set();
68
+ for (const [key, value] of attributes) {
69
+ const canonical = canonicalAttrName(key);
70
+ if (seen.has(canonical)) duplicateName = canonical;
71
+ seen.add(canonical);
72
+ if (canonical === "http-equiv") httpEquiv = value;
73
+ else if (canonical === "content") content = value;
74
+ }
75
+ if (duplicateName !== void 0) {
76
+ return forbidden(DEV ? `duplicate case-insensitive attribute ${JSON.stringify(duplicateName)}` : "");
77
+ }
78
+ if (typeof httpEquiv !== "string") return { kind: "not-refresh" };
79
+ if (trimAsciiWhitespace(stripControlChars(httpEquiv)).toLowerCase() !== "refresh") {
80
+ return { kind: "not-refresh" };
81
+ }
82
+ if (typeof content !== "string") return { kind: "not-refresh" };
83
+ return parseMetaRefreshContent(content);
84
+ }
85
+ function normalizeMetaAttributes(props) {
86
+ const out = /* @__PURE__ */ new Map();
87
+ const seen = /* @__PURE__ */ new Set();
88
+ for (const key of Object.keys(props)) {
89
+ const canonical = canonicalAttrName(key);
90
+ if (seen.has(canonical)) return null;
91
+ seen.add(canonical);
92
+ out.set(key, props[key]);
93
+ }
94
+ return out;
95
+ }
96
+ function isForbiddenMetaEntry(props) {
97
+ const normalized = normalizeMetaAttributes(props);
98
+ if (normalized === null) return true;
99
+ return resolveMetaRefreshPolicy(normalized).kind === "forbidden";
100
+ }
101
+
102
+ // src/utils/elementPolicy.ts
103
+ var HTML_NS = "http://www.w3.org/1999/xhtml";
104
+ var SVG_NS = "http://www.w3.org/2000/svg";
105
+ var BLOCKED_ELEMENTS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
106
+ function canonicalTagName(tag) {
107
+ return canonicalAttrName(tag);
108
+ }
109
+ function isBlockedElement(tag) {
110
+ return BLOCKED_ELEMENTS.has(canonicalTagName(tag));
111
+ }
112
+ var CODE_TEXT_ELEMENTS = /* @__PURE__ */ new Set(["script", "style"]);
113
+ function isCodeTextElement(tag) {
114
+ return CODE_TEXT_ELEMENTS.has(canonicalTagName(tag));
115
+ }
116
+ var ContextualRefusal = {
117
+ None: 0,
118
+ /** The element would carry a refresh directive the shared policy forbids. */
119
+ MetaRefreshForbidden: 1,
120
+ /** A `<meta>` with a reactive binding may not carry any refresh directive. */
121
+ MetaRefreshReactive: 2,
122
+ /** A runtime value may not choose which program a `<script>` runs. */
123
+ ScriptSource: 3,
124
+ /** An SVG animation may not target a URL, handler or document attribute. */
125
+ AnimationTarget: 4,
126
+ /** A runtime-written `href` may not become an applied stylesheet. */
127
+ StylesheetSource: 5
128
+ };
129
+ var SCRIPT_SOURCE_ATTRIBUTES = /* @__PURE__ */ new Set(["src", "href", "xlink:href", "type", "language"]);
130
+ var SVG_ANIMATION_ELEMENTS = /* @__PURE__ */ new Set(["animate", "set", "animateMotion", "animateTransform", "animateColor"]);
131
+ var reactiveMetaElements = /* @__PURE__ */ new WeakSet();
132
+ function isHtmlNamespace(el) {
133
+ return el.namespaceURI === HTML_NS || el.namespaceURI === null;
134
+ }
135
+ function metaSnapshot(el, canonical, value) {
136
+ const snapshot = /* @__PURE__ */ new Map();
137
+ const attrs = el.attributes;
138
+ for (let i = 0; i < attrs.length; i++) {
139
+ const attr = attrs[i];
140
+ if (attr.name === canonical) continue;
141
+ snapshot.set(attr.name, attr.value);
142
+ }
143
+ if (canonical !== null && value !== null) snapshot.set(canonical, value);
144
+ return snapshot;
145
+ }
146
+ function claimReactiveMeta(el) {
147
+ if (reactiveMetaElements.has(el)) return;
148
+ reactiveMetaElements.add(el);
149
+ if (el.getAttribute("content") === null) return;
150
+ if (resolveMetaRefreshPolicy(metaSnapshot(el, null, null)).kind !== "not-refresh") {
151
+ el.removeAttribute("content");
152
+ }
153
+ }
154
+ function metaRefusal(el, name, value, origin) {
155
+ if (!isHtmlNamespace(el)) return ContextualRefusal.None;
156
+ const canonical = canonicalAttrName(name);
157
+ if (canonical !== "http-equiv" && canonical !== "content") return ContextualRefusal.None;
158
+ if (origin === "reactive") claimReactiveMeta(el);
159
+ if (value === null) return ContextualRefusal.None;
160
+ if (canonical === "content" && !el.hasAttribute("http-equiv")) return ContextualRefusal.None;
161
+ const decision = resolveMetaRefreshPolicy(metaSnapshot(el, canonical, value));
162
+ if (decision.kind === "forbidden") return ContextualRefusal.MetaRefreshForbidden;
163
+ if (decision.kind !== "not-refresh" && reactiveMetaElements.has(el)) return ContextualRefusal.MetaRefreshReactive;
164
+ return ContextualRefusal.None;
165
+ }
166
+ function animationRefusal(name, value) {
167
+ if (value === null || canonicalAttrName(name) !== "attributename") return ContextualRefusal.None;
168
+ const target = stripControlChars(value);
169
+ return isUrlAttribute(target) || isEventHandlerAttr(target) || isHtmlContentAttribute(target) ? ContextualRefusal.AnimationTarget : ContextualRefusal.None;
170
+ }
171
+ var runtimeHrefLinks = /* @__PURE__ */ new WeakSet();
172
+ function relHasStylesheet(rel) {
173
+ if (rel === null) return false;
174
+ const lower = canonicalAttrName(rel);
175
+ if (!lower.includes("stylesheet")) return false;
176
+ const tokens = lower.split(/[\t\n\f\r ]+/);
177
+ for (let i = 0; i < tokens.length; i++) if (tokens[i] === "stylesheet") return true;
178
+ return false;
179
+ }
180
+ function stylesheetRefusal(el, name, value, origin) {
181
+ if (!isHtmlNamespace(el)) return ContextualRefusal.None;
182
+ const canonical = canonicalAttrName(name);
183
+ if (canonical === "href") {
184
+ if (origin === "static" || value === null) return ContextualRefusal.None;
185
+ if (relHasStylesheet(el.getAttribute("rel"))) return ContextualRefusal.StylesheetSource;
186
+ runtimeHrefLinks.add(el);
187
+ return ContextualRefusal.None;
188
+ }
189
+ if (canonical === "rel") {
190
+ if (!relHasStylesheet(value)) return ContextualRefusal.None;
191
+ return runtimeHrefLinks.has(el) && el.hasAttribute("href") ? ContextualRefusal.StylesheetSource : ContextualRefusal.None;
192
+ }
193
+ return ContextualRefusal.None;
194
+ }
195
+ function contextualAttributeRefusal(el, name, value, origin) {
196
+ const local = el.localName;
197
+ if (local === "meta") return metaRefusal(el, name, value, origin);
198
+ if (local === "link") return stylesheetRefusal(el, name, value, origin);
199
+ if (local === "script") {
200
+ if (origin === "static" || value === null) return ContextualRefusal.None;
201
+ return SCRIPT_SOURCE_ATTRIBUTES.has(canonicalAttrName(name)) ? ContextualRefusal.ScriptSource : ContextualRefusal.None;
202
+ }
203
+ if (SVG_ANIMATION_ELEMENTS.has(local) && el.namespaceURI === SVG_NS) return animationRefusal(name, value);
204
+ return ContextualRefusal.None;
205
+ }
206
+ function settleAttributeProvenance(el, name, origin) {
207
+ if (el.localName !== "link" || canonicalAttrName(name) !== "href") return;
208
+ if (origin !== "static" && el.hasAttribute("href")) runtimeHrefLinks.add(el);
209
+ else runtimeHrefLinks.delete(el);
210
+ }
211
+ function isForbiddenMetaSnapshot(attributes) {
212
+ return resolveMetaRefreshPolicy(attributes).kind === "forbidden";
213
+ }
214
+
215
+ export {
216
+ resolveMetaRefreshPolicy,
217
+ isForbiddenMetaEntry,
218
+ isBlockedElement,
219
+ isCodeTextElement,
220
+ ContextualRefusal,
221
+ contextualAttributeRefusal,
222
+ settleAttributeProvenance,
223
+ isForbiddenMetaSnapshot
224
+ };
@@ -1,20 +1,20 @@
1
- import {
2
- stripHtml
3
- } from "./chunk-2INLLLMZ.js";
4
1
  import {
5
2
  globalSingleton
6
3
  } from "./chunk-7ZHH77QA.js";
7
4
  import {
8
5
  effect
9
- } from "./chunk-WEQ3DMVL.js";
6
+ } from "./chunk-V3LHZSU5.js";
7
+ import {
8
+ stripHtml
9
+ } from "./chunk-EXXSN3BW.js";
10
10
  import {
11
11
  signal
12
- } from "./chunk-FQRUXCEE.js";
12
+ } from "./chunk-DSID757X.js";
13
13
  import {
14
14
  forEachSubscriber,
15
15
  getSubscriberCount,
16
16
  getSubscriberDeps
17
- } from "./chunk-JWKYU5GV.js";
17
+ } from "./chunk-TQQUN4WR.js";
18
18
  import {
19
19
  dispose,
20
20
  isDev
@@ -3,20 +3,23 @@ import {
3
3
  } from "./chunk-J6FW5TV6.js";
4
4
  import {
5
5
  tagFactory
6
- } from "./chunk-UOL2ECCS.js";
6
+ } from "./chunk-VWT3VXPL.js";
7
7
  import {
8
8
  derived
9
- } from "./chunk-RUSSKG6G.js";
9
+ } from "./chunk-KJ3UKABJ.js";
10
10
  import {
11
11
  globalSingleton
12
12
  } from "./chunk-7ZHH77QA.js";
13
13
  import {
14
14
  effect
15
- } from "./chunk-WEQ3DMVL.js";
15
+ } from "./chunk-V3LHZSU5.js";
16
+ import {
17
+ sanitizeCSSDeclaration
18
+ } from "./chunk-EXXSN3BW.js";
16
19
  import {
17
20
  batch,
18
21
  signal
19
- } from "./chunk-FQRUXCEE.js";
22
+ } from "./chunk-DSID757X.js";
20
23
 
21
24
  // src/ecosystem/adapters/mobx.ts
22
25
  function mobXAdapter(options) {
@@ -121,7 +124,7 @@ var _themeLayers = globalSingleton(
121
124
  function commitThemeProperty(root, name, record) {
122
125
  const top = record.layers[record.layers.length - 1];
123
126
  if (top) {
124
- root.style.setProperty(name, top.value);
127
+ root.style.setProperty(name, sanitizeCSSDeclaration(name, String(top.value), { element: root }));
125
128
  return;
126
129
  }
127
130
  _themeLayers.get(root)?.delete(name);
@@ -3,6 +3,13 @@ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototyp
3
3
  function isUnsafeKey(key) {
4
4
  return UNSAFE_KEYS.has(key);
5
5
  }
6
+ function readOwnGlobal(key) {
7
+ if (typeof window === "undefined") return void 0;
8
+ if (!Object.hasOwn(window, key)) return void 0;
9
+ const value = window[key];
10
+ if (typeof Node !== "undefined" && value instanceof Node) return void 0;
11
+ return value;
12
+ }
6
13
  function stripUnsafeKeys(obj) {
7
14
  const out = {};
8
15
  for (const k of Object.keys(obj)) {
@@ -13,5 +20,6 @@ function stripUnsafeKeys(obj) {
13
20
 
14
21
  export {
15
22
  isUnsafeKey,
23
+ readOwnGlobal,
16
24
  stripUnsafeKeys
17
25
  };
@@ -1,15 +1,18 @@
1
1
  import {
2
- sanitizeUrl
3
- } from "./chunk-2INLLLMZ.js";
2
+ isBlockedElement
3
+ } from "./chunk-3ACAAQIN.js";
4
4
  import {
5
5
  globalSingleton
6
6
  } from "./chunk-7ZHH77QA.js";
7
7
  import {
8
8
  effect
9
- } from "./chunk-WEQ3DMVL.js";
9
+ } from "./chunk-V3LHZSU5.js";
10
+ import {
11
+ sanitizeUrl
12
+ } from "./chunk-EXXSN3BW.js";
10
13
  import {
11
14
  signal
12
- } from "./chunk-FQRUXCEE.js";
15
+ } from "./chunk-DSID757X.js";
13
16
  import {
14
17
  DEV,
15
18
  devWarn,
@@ -239,6 +242,9 @@ var DOMPool = class {
239
242
  * Get a recycled element or create a new one.
240
243
  */
241
244
  acquire(tag) {
245
+ if (isBlockedElement(tag)) {
246
+ throw new Error(`DOMPool: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
247
+ }
242
248
  const pool = this.pools.get(tag);
243
249
  if (pool && pool.length > 0) {
244
250
  const el = pool.pop();
@@ -344,10 +350,19 @@ function prefetch(url) {
344
350
  }
345
351
  function preloadImage(src) {
346
352
  return new Promise((resolve, reject) => {
353
+ const safe = sanitizeUrl(String(src));
354
+ if (!safe) {
355
+ reject(
356
+ new Error(
357
+ String(src).trim() === "" ? "preloadImage: no image URL was given." : "preloadImage: refusing an image URL outside the URL policy."
358
+ )
359
+ );
360
+ return;
361
+ }
347
362
  const img = new Image();
348
363
  img.onload = () => resolve(img);
349
364
  img.onerror = reject;
350
- img.src = src;
365
+ img.src = safe;
351
366
  });
352
367
  }
353
368
 
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-7XHATCIH.js";
5
5
  import {
6
6
  reactiveBinding
7
- } from "./chunk-JWKYU5GV.js";
7
+ } from "./chunk-TQQUN4WR.js";
8
8
 
9
9
  // src/core/rendering/createId.ts
10
10
  var COUNTER_KEY = /* @__PURE__ */ Symbol.for("sibujs.createId.v1");
@@ -5,7 +5,7 @@ import {
5
5
  resumeTracking,
6
6
  suspendTracking,
7
7
  track
8
- } from "./chunk-JWKYU5GV.js";
8
+ } from "./chunk-TQQUN4WR.js";
9
9
  import {
10
10
  devAssert
11
11
  } from "./chunk-NYNYSPK7.js";
@@ -4,7 +4,7 @@ import {
4
4
  notifySubscribers,
5
5
  queueSignalNotification,
6
6
  recordDependency
7
- } from "./chunk-JWKYU5GV.js";
7
+ } from "./chunk-TQQUN4WR.js";
8
8
  import {
9
9
  DEV
10
10
  } from "./chunk-NYNYSPK7.js";
@@ -1,19 +1,22 @@
1
- import {
2
- isUnsafeKey
3
- } from "./chunk-H3SRKIYX.js";
4
1
  import {
5
2
  acquireTitle
6
3
  } from "./chunk-52XFPGSN.js";
4
+ import {
5
+ isUnsafeKey
6
+ } from "./chunk-62BDYGAG.js";
7
7
  import {
8
8
  globalSingleton
9
9
  } from "./chunk-7ZHH77QA.js";
10
10
  import {
11
11
  effect
12
- } from "./chunk-WEQ3DMVL.js";
12
+ } from "./chunk-V3LHZSU5.js";
13
+ import {
14
+ sanitizeUrl
15
+ } from "./chunk-EXXSN3BW.js";
13
16
  import {
14
17
  batch,
15
18
  signal
16
- } from "./chunk-FQRUXCEE.js";
19
+ } from "./chunk-DSID757X.js";
17
20
  import {
18
21
  reportError
19
22
  } from "./chunk-NYNYSPK7.js";
@@ -533,13 +536,19 @@ function colorScheme() {
533
536
  }
534
537
 
535
538
  // src/browser/format.ts
539
+ var I18N_STATE = /* @__PURE__ */ Symbol.for("sibujs.i18n.v1");
540
+ function activeI18nLocale() {
541
+ const state = globalThis[I18N_STATE];
542
+ if (!state) return void 0;
543
+ return state.getLocale ? state.getLocale() : state.locale?.[0]();
544
+ }
536
545
  function formatNumber(value, options) {
537
546
  const { locale, ...formatOptions } = options ?? {};
538
- return new Intl.NumberFormat(locale, formatOptions).format(value);
547
+ return new Intl.NumberFormat(locale ?? activeI18nLocale(), formatOptions).format(value);
539
548
  }
540
549
  function formatCurrency(value, currency, options) {
541
550
  const { locale, ...formatOptions } = options ?? {};
542
- return new Intl.NumberFormat(locale, {
551
+ return new Intl.NumberFormat(locale ?? activeI18nLocale(), {
543
552
  ...formatOptions,
544
553
  style: "currency",
545
554
  currency
@@ -1508,6 +1517,11 @@ function imageLoader(src) {
1508
1517
  abandonCurrent();
1509
1518
  resetState();
1510
1519
  if (disposed || token !== startToken) return;
1520
+ const safe = sanitizeUrl(String(url));
1521
+ if (!safe) {
1522
+ setStatus("error");
1523
+ return;
1524
+ }
1511
1525
  const img = new Image();
1512
1526
  current = img;
1513
1527
  currentSettled = false;
@@ -1526,7 +1540,7 @@ function imageLoader(src) {
1526
1540
  currentSettled = true;
1527
1541
  setStatus("error");
1528
1542
  };
1529
- img.src = url;
1543
+ img.src = safe;
1530
1544
  }
1531
1545
  let srcEffectTeardown = null;
1532
1546
  if (typeof src === "function") {