sibujs 3.1.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +6 -0
  2. package/dist/browser.cjs +16 -8
  3. package/dist/browser.js +6 -5
  4. package/dist/build.cjs +235 -147
  5. package/dist/build.js +35 -24
  6. package/dist/cdn.global.js +7 -7
  7. package/dist/{chunk-WYU7CYJ3.js → chunk-2C4E3HBM.js} +5 -5
  8. package/dist/{chunk-3DYB5B3S.js → chunk-4JCAUOLN.js} +45 -23
  9. package/dist/{chunk-2HAGQWDV.js → chunk-5N74TKLD.js} +1 -1
  10. package/dist/{chunk-SVVAUX7J.js → chunk-7XDYVJLE.js} +19 -9
  11. package/dist/{chunk-2N2UL7O4.js → chunk-BGNLPNGV.js} +20 -12
  12. package/dist/{chunk-RK4BQG25.js → chunk-C427DVQF.js} +1 -1
  13. package/dist/{chunk-ZIBE2SAT.js → chunk-FDY42FIU.js} +3 -2
  14. package/dist/{chunk-GQ7RRFPU.js → chunk-FOI23UJL.js} +11 -1
  15. package/dist/{chunk-2RA7SHDA.js → chunk-GOJMFRBL.js} +20 -4
  16. package/dist/{chunk-IVOUCSZL.js → chunk-GOUM4JCT.js} +6 -6
  17. package/dist/chunk-H3SRKIYX.js +17 -0
  18. package/dist/{chunk-3DJH25UO.js → chunk-H6PCHJZQ.js} +2 -2
  19. package/dist/{chunk-UCS6AMJ7.js → chunk-HMJFCBRR.js} +26 -3
  20. package/dist/{chunk-JYD2PWXH.js → chunk-HXMS4SNP.js} +22 -15
  21. package/dist/{chunk-SC437AMI.js → chunk-JYXOEYI4.js} +12 -18
  22. package/dist/{chunk-KB3BA2XK.js → chunk-NFYWLRUO.js} +11 -18
  23. package/dist/{chunk-QNQY5DUS.js → chunk-NPIEEKPT.js} +20 -11
  24. package/dist/{chunk-UYX2NDOH.js → chunk-OYLPZO4N.js} +33 -15
  25. package/dist/{chunk-LYTCUZ7H.js → chunk-RDRSWYNP.js} +1 -1
  26. package/dist/{chunk-2ZJ7TSW4.js → chunk-RLUJL2MV.js} +4 -8
  27. package/dist/{chunk-CR4MXPHB.js → chunk-V2MTG5FT.js} +99 -36
  28. package/dist/{chunk-CNZ35WI2.js → chunk-VJE6DDYM.js} +2 -2
  29. package/dist/{chunk-PMSDFTK3.js → chunk-VOCE4NNK.js} +157 -75
  30. package/dist/{chunk-WKUXSE7V.js → chunk-X67UYC74.js} +12 -11
  31. package/dist/{chunk-EFOAE5NC.js → chunk-YFDGQWDA.js} +1 -1
  32. package/dist/{chunk-3U4ZVXVD.js → chunk-Z2FWAE4B.js} +6 -2
  33. package/dist/data.cjs +190 -94
  34. package/dist/data.d.cts +7 -1
  35. package/dist/data.d.ts +7 -1
  36. package/dist/data.js +8 -8
  37. package/dist/devtools.cjs +38 -10
  38. package/dist/devtools.d.cts +1 -1
  39. package/dist/devtools.d.ts +1 -1
  40. package/dist/devtools.js +6 -6
  41. package/dist/ecosystem.cjs +123 -63
  42. package/dist/ecosystem.js +9 -9
  43. package/dist/extras.cjs +380 -196
  44. package/dist/extras.d.cts +2 -2
  45. package/dist/extras.d.ts +2 -2
  46. package/dist/extras.js +27 -24
  47. package/dist/index.cjs +214 -136
  48. package/dist/index.d.cts +15 -2
  49. package/dist/index.d.ts +15 -2
  50. package/dist/index.js +15 -13
  51. package/dist/{introspect-BZWKvQUZ.d.ts → introspect-DOZfmC-4.d.ts} +1 -1
  52. package/dist/{introspect-DsJlDD2T.d.cts → introspect-RjLfIFpL.d.cts} +1 -1
  53. package/dist/motion.cjs +10 -0
  54. package/dist/motion.js +3 -3
  55. package/dist/patterns.cjs +45 -40
  56. package/dist/patterns.js +8 -7
  57. package/dist/performance.cjs +101 -25
  58. package/dist/performance.d.cts +2 -2
  59. package/dist/performance.d.ts +2 -2
  60. package/dist/performance.js +8 -7
  61. package/dist/plugins.cjs +234 -160
  62. package/dist/plugins.d.cts +1 -1
  63. package/dist/plugins.d.ts +1 -1
  64. package/dist/plugins.js +127 -69
  65. package/dist/{ssr-FXD2PPMC.js → ssr-2QDQ27EV.js} +5 -3
  66. package/dist/{ssr-CrVNy6Pa.d.cts → ssr-D62yFwuw.d.cts} +8 -1
  67. package/dist/{ssr-CrVNy6Pa.d.ts → ssr-D62yFwuw.d.ts} +8 -1
  68. package/dist/ssr.cjs +145 -66
  69. package/dist/ssr.d.cts +1 -1
  70. package/dist/ssr.d.ts +1 -1
  71. package/dist/ssr.js +12 -10
  72. package/dist/testing.cjs +9 -4
  73. package/dist/testing.js +3 -3
  74. package/dist/ui.cjs +54 -38
  75. package/dist/ui.js +10 -9
  76. package/dist/widgets.cjs +40 -24
  77. package/dist/widgets.js +8 -8
  78. package/package.json +3 -1
@@ -3,18 +3,18 @@ import {
3
3
  } from "./chunk-2UPRY23K.js";
4
4
  import {
5
5
  stripHtml
6
- } from "./chunk-UCS6AMJ7.js";
6
+ } from "./chunk-HMJFCBRR.js";
7
7
  import {
8
8
  effect
9
- } from "./chunk-ZIBE2SAT.js";
9
+ } from "./chunk-FDY42FIU.js";
10
10
  import {
11
11
  signal
12
- } from "./chunk-RK4BQG25.js";
12
+ } from "./chunk-C427DVQF.js";
13
13
  import {
14
14
  forEachSubscriber,
15
15
  getSubscriberCount,
16
16
  getSubscriberDeps
17
- } from "./chunk-3U4ZVXVD.js";
17
+ } from "./chunk-Z2FWAE4B.js";
18
18
  import {
19
19
  isDev
20
20
  } from "./chunk-LMLD24FC.js";
@@ -22,6 +22,7 @@ import {
22
22
  // src/devtools/debug.ts
23
23
  var debugEnabled = false;
24
24
  var perfMarks = /* @__PURE__ */ new Map();
25
+ var MAX_PERF_SAMPLES = 1e3;
25
26
  function enableDebug() {
26
27
  debugEnabled = true;
27
28
  console.log("[SibuJS] Debug mode enabled");
@@ -46,7 +47,11 @@ function perfTracker(label) {
46
47
  }
47
48
  function endMeasure() {
48
49
  const elapsed = globalThis.performance.now() - startTime;
49
- perfMarks.get(label)?.push(elapsed);
50
+ const marks = perfMarks.get(label);
51
+ if (marks) {
52
+ marks.push(elapsed);
53
+ if (marks.length > MAX_PERF_SAMPLES) marks.shift();
54
+ }
50
55
  if (debugEnabled) {
51
56
  debugLog("Perf", `${label}: ${elapsed.toFixed(2)}ms`);
52
57
  }
@@ -1000,7 +1005,7 @@ function withErrorTracking(name, component, reporter) {
1000
1005
  }
1001
1006
  };
1002
1007
  }
1003
- function formatError(error, context) {
1008
+ function formatError(error, context, seen = /* @__PURE__ */ new Set([error])) {
1004
1009
  const lines = [];
1005
1010
  const componentLabel = context?.component ?? (error instanceof SibuError ? error.component : void 0);
1006
1011
  if (componentLabel) {
@@ -1025,10 +1030,11 @@ function formatError(error, context) {
1025
1030
  lines.push(stackBody);
1026
1031
  }
1027
1032
  const cause = error.cause;
1028
- if (cause instanceof Error) {
1033
+ if (cause instanceof Error && !seen.has(cause)) {
1034
+ seen.add(cause);
1029
1035
  lines.push("");
1030
1036
  lines.push("Caused by:");
1031
- lines.push(formatError(cause));
1037
+ lines.push(formatError(cause, context, seen));
1032
1038
  }
1033
1039
  return lines.join("\n");
1034
1040
  }
@@ -1042,7 +1048,11 @@ function debugValue(value, formatter) {
1042
1048
  const dispose2 = effect(() => {
1043
1049
  const resolved = value();
1044
1050
  entry.value = resolved;
1045
- entry.label = format(resolved);
1051
+ try {
1052
+ entry.label = format(resolved);
1053
+ } catch (err) {
1054
+ entry.label = `<format error: ${err instanceof Error ? err.message : String(err)}>`;
1055
+ }
1046
1056
  });
1047
1057
  return () => {
1048
1058
  dispose2();
@@ -3,23 +3,35 @@ import {
3
3
  } from "./chunk-3JHCYHWN.js";
4
4
  import {
5
5
  tagFactory
6
- } from "./chunk-WKUXSE7V.js";
6
+ } from "./chunk-X67UYC74.js";
7
7
  import {
8
8
  derived
9
- } from "./chunk-SC437AMI.js";
9
+ } from "./chunk-JYXOEYI4.js";
10
10
  import {
11
11
  effect
12
- } from "./chunk-ZIBE2SAT.js";
12
+ } from "./chunk-FDY42FIU.js";
13
13
  import {
14
14
  batch,
15
15
  signal
16
- } from "./chunk-RK4BQG25.js";
16
+ } from "./chunk-C427DVQF.js";
17
17
 
18
18
  // src/ecosystem/adapters/mobx.ts
19
19
  function mobXAdapter(options) {
20
20
  return createPlugin("sibu-mobx", (ctx) => {
21
21
  const { autorun } = options;
22
22
  const disposers = [];
23
+ function trackDisposer(rawDispose) {
24
+ let done = false;
25
+ const wrapped = () => {
26
+ if (done) return;
27
+ done = true;
28
+ const i = disposers.indexOf(wrapped);
29
+ if (i >= 0) disposers.splice(i, 1);
30
+ rawDispose();
31
+ };
32
+ disposers.push(wrapped);
33
+ return wrapped;
34
+ }
23
35
  function fromMobX(expression) {
24
36
  const [getValue, setValue] = signal(void 0);
25
37
  const disposer = autorun(() => {
@@ -28,22 +40,18 @@ function mobXAdapter(options) {
28
40
  setValue(newValue);
29
41
  });
30
42
  });
31
- disposers.push(disposer);
32
43
  const getter = (() => getValue());
33
- getter.dispose = () => {
34
- const i = disposers.indexOf(disposer);
35
- if (i >= 0) disposers.splice(i, 1);
36
- disposer();
37
- };
44
+ getter.dispose = trackDisposer(disposer);
38
45
  return getter;
39
46
  }
40
47
  function toMobX(sibuGetter, callback) {
41
- return effect(() => {
48
+ const stop = effect(() => {
42
49
  callback(sibuGetter());
43
50
  });
51
+ return trackDisposer(stop);
44
52
  }
45
53
  function destroy() {
46
- for (const disposer of disposers) {
54
+ for (const disposer of [...disposers]) {
47
55
  disposer();
48
56
  }
49
57
  disposers.length = 0;
@@ -3,7 +3,7 @@ import {
3
3
  notifySubscribers,
4
4
  queueSignalNotification,
5
5
  recordDependency
6
- } from "./chunk-3U4ZVXVD.js";
6
+ } from "./chunk-Z2FWAE4B.js";
7
7
  import {
8
8
  isDev
9
9
  } from "./chunk-LMLD24FC.js";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  isSSR
3
- } from "./chunk-2RA7SHDA.js";
3
+ } from "./chunk-GOJMFRBL.js";
4
4
  import {
5
5
  cleanup,
6
6
  retrack,
7
7
  untracked
8
- } from "./chunk-3U4ZVXVD.js";
8
+ } from "./chunk-Z2FWAE4B.js";
9
9
  import {
10
10
  devAssert
11
11
  } from "./chunk-LMLD24FC.js";
@@ -111,6 +111,7 @@ function effect(effectFn, options) {
111
111
  ctx.fn(ctx.onCleanup);
112
112
  };
113
113
  const sub = (() => {
114
+ if (ctx.disposed) return;
114
115
  if (ctx.running) {
115
116
  ctx.rerunPending = true;
116
117
  return;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  signal
3
- } from "./chunk-RK4BQG25.js";
3
+ } from "./chunk-C427DVQF.js";
4
4
 
5
5
  // src/ui/transition.ts
6
6
  function transition(element, options = {}) {
@@ -17,11 +17,17 @@ function transition(element, options = {}) {
17
17
  } = options;
18
18
  const transitionValue = `${property} ${duration}ms ${easing} ${delay}ms`;
19
19
  let activeTimer = null;
20
+ let pendingResolve = null;
20
21
  function cancelPending() {
21
22
  if (activeTimer !== null) {
22
23
  clearTimeout(activeTimer);
23
24
  activeTimer = null;
24
25
  }
26
+ if (pendingResolve !== null) {
27
+ const resolvePrev = pendingResolve;
28
+ pendingResolve = null;
29
+ resolvePrev();
30
+ }
25
31
  }
26
32
  function enter() {
27
33
  return new Promise((resolve) => {
@@ -33,11 +39,13 @@ function transition(element, options = {}) {
33
39
  if (activeClass) element.classList.add(activeClass);
34
40
  const done = () => {
35
41
  activeTimer = null;
42
+ pendingResolve = null;
36
43
  if (enterClass) element.classList.remove(enterClass);
37
44
  onEnterDone?.();
38
45
  resolve();
39
46
  };
40
47
  if (duration > 0) {
48
+ pendingResolve = resolve;
41
49
  activeTimer = setTimeout(done, duration + delay);
42
50
  } else {
43
51
  done();
@@ -53,11 +61,13 @@ function transition(element, options = {}) {
53
61
  if (enterClass) element.classList.remove(enterClass);
54
62
  const done = () => {
55
63
  activeTimer = null;
64
+ pendingResolve = null;
56
65
  if (leaveClass) element.classList.remove(leaveClass);
57
66
  onLeaveDone?.();
58
67
  resolve();
59
68
  };
60
69
  if (duration > 0) {
70
+ pendingResolve = resolve;
61
71
  activeTimer = setTimeout(done, duration + delay);
62
72
  } else {
63
73
  done();
@@ -2,11 +2,15 @@
2
2
  var als = null;
3
3
  try {
4
4
  if (typeof process !== "undefined" && process.versions && process.versions.node) {
5
- const req = Function("return typeof require==='function'?require:null")();
6
- if (req) {
7
- const mod = req("node:async_hooks");
8
- als = new mod.AsyncLocalStorage();
5
+ let mod = null;
6
+ const getBuiltin = process.getBuiltinModule;
7
+ if (typeof getBuiltin === "function") {
8
+ mod = getBuiltin("node:async_hooks");
9
+ } else {
10
+ const req = Function("return typeof require==='function'?require:null")();
11
+ if (req) mod = req("node:async_hooks");
9
12
  }
13
+ if (mod) als = new mod.AsyncLocalStorage();
10
14
  }
11
15
  } catch {
12
16
  als = null;
@@ -22,6 +26,17 @@ function getSSRStore() {
22
26
  function isSSR() {
23
27
  return getSSRStore().ssr;
24
28
  }
29
+ function getRequestScopedCache(name) {
30
+ if (!isSSR()) return null;
31
+ const store = getSSRStore();
32
+ const caches = store.caches ?? (store.caches = /* @__PURE__ */ new Map());
33
+ let c = caches.get(name);
34
+ if (!c) {
35
+ c = /* @__PURE__ */ new Map();
36
+ caches.set(name, c);
37
+ }
38
+ return c;
39
+ }
25
40
  function enableSSR() {
26
41
  getSSRStore().ssr = true;
27
42
  }
@@ -58,6 +73,7 @@ function withSSR(fn) {
58
73
  export {
59
74
  getSSRStore,
60
75
  isSSR,
76
+ getRequestScopedCache,
61
77
  enableSSR,
62
78
  disableSSR,
63
79
  runInSSRContext,
@@ -1,10 +1,13 @@
1
+ import {
2
+ isUnsafeKey
3
+ } from "./chunk-H3SRKIYX.js";
1
4
  import {
2
5
  effect
3
- } from "./chunk-ZIBE2SAT.js";
6
+ } from "./chunk-FDY42FIU.js";
4
7
  import {
5
8
  batch,
6
9
  signal
7
- } from "./chunk-RK4BQG25.js";
10
+ } from "./chunk-C427DVQF.js";
8
11
 
9
12
  // src/browser/media.ts
10
13
  function media(query) {
@@ -399,10 +402,7 @@ function dropZone(element, options) {
399
402
  const raw = e.dataTransfer.getData("application/json");
400
403
  if (raw) {
401
404
  try {
402
- transferData = JSON.parse(
403
- raw,
404
- (k, v) => k === "__proto__" || k === "constructor" || k === "prototype" ? void 0 : v
405
- );
405
+ transferData = JSON.parse(raw, (k, v) => isUnsafeKey(k) ? void 0 : v);
406
406
  } catch {
407
407
  transferData = raw;
408
408
  }
@@ -0,0 +1,17 @@
1
+ // src/utils/guards.ts
2
+ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
3
+ function isUnsafeKey(key) {
4
+ return UNSAFE_KEYS.has(key);
5
+ }
6
+ function stripUnsafeKeys(obj) {
7
+ const out = {};
8
+ for (const k of Object.keys(obj)) {
9
+ if (!isUnsafeKey(k)) out[k] = obj[k];
10
+ }
11
+ return out;
12
+ }
13
+
14
+ export {
15
+ isUnsafeKey,
16
+ stripUnsafeKeys
17
+ };
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  isSSR
3
- } from "./chunk-2RA7SHDA.js";
3
+ } from "./chunk-GOJMFRBL.js";
4
4
  import {
5
5
  track
6
- } from "./chunk-3U4ZVXVD.js";
6
+ } from "./chunk-Z2FWAE4B.js";
7
7
  import {
8
8
  devAssert
9
9
  } from "./chunk-LMLD24FC.js";
@@ -1,7 +1,15 @@
1
1
  // src/utils/sanitize.ts
2
+ function stripControlChars(value) {
3
+ return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
4
+ }
5
+ function isEventHandlerAttr(name) {
6
+ if (name.length < 3) return false;
7
+ const lower = name.toLowerCase();
8
+ return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
9
+ }
2
10
  var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
3
11
  function sanitizeUrl(url) {
4
- const trimmed = url.replace(/[\x00-\x20\x7f-\x9f]+/g, "").trim();
12
+ const trimmed = stripControlChars(url).trim();
5
13
  if (!trimmed) return "";
6
14
  const lower = trimmed.toLowerCase();
7
15
  let schemeEnd = -1;
@@ -50,7 +58,20 @@ function sanitizeCSSValue(value) {
50
58
  return value;
51
59
  }
52
60
  function stripHtml(html) {
53
- return String(html).replace(/<[^>]*>/g, "");
61
+ const input = String(html);
62
+ if (typeof DOMParser !== "undefined") {
63
+ try {
64
+ return new DOMParser().parseFromString(input, "text/html").body.textContent ?? "";
65
+ } catch {
66
+ }
67
+ }
68
+ let prev;
69
+ let out = input;
70
+ do {
71
+ prev = out;
72
+ out = out.replace(/<[^>]*>/g, "");
73
+ } while (out !== prev);
74
+ return out.replace(/<[^>]*$/, "");
54
75
  }
55
76
  var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
56
77
  "href",
@@ -67,10 +88,12 @@ var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
67
88
  "data"
68
89
  ]);
69
90
  function isUrlAttribute(attr) {
70
- return URL_ATTRIBUTES.has(attr);
91
+ return URL_ATTRIBUTES.has(attr.toLowerCase());
71
92
  }
72
93
 
73
94
  export {
95
+ stripControlChars,
96
+ isEventHandlerAttr,
74
97
  sanitizeUrl,
75
98
  sanitizeSrcset,
76
99
  sanitizeCSSValue,
@@ -1,24 +1,25 @@
1
1
  import {
2
- sanitizeUrl
3
- } from "./chunk-UCS6AMJ7.js";
2
+ isEventHandlerAttr,
3
+ sanitizeSrcset,
4
+ sanitizeUrl,
5
+ stripControlChars
6
+ } from "./chunk-HMJFCBRR.js";
4
7
  import {
5
8
  getSSRStore
6
- } from "./chunk-2RA7SHDA.js";
9
+ } from "./chunk-GOJMFRBL.js";
7
10
  import {
8
11
  isDev
9
12
  } from "./chunk-LMLD24FC.js";
10
13
 
11
14
  // src/platform/ssr.ts
15
+ function sanitizeUrlAttr(name, value) {
16
+ return name === "srcset" ? sanitizeSrcset(value) : sanitizeUrl(value);
17
+ }
12
18
  var _isDev = isDev();
13
19
  var SAFE_ATTR_NAME = /^[A-Za-z_:][-A-Za-z0-9_.:]*$/;
14
20
  function isSafeAttrName(name) {
15
21
  return SAFE_ATTR_NAME.test(name);
16
22
  }
17
- function isEventHandlerAttr(name) {
18
- if (name.length < 3) return false;
19
- const lower = name.toLowerCase();
20
- return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
21
- }
22
23
  var URL_ATTRS = /* @__PURE__ */ new Set([
23
24
  "href",
24
25
  "src",
@@ -93,7 +94,7 @@ function renderToString(element) {
93
94
  const lowerName = rawName.toLowerCase();
94
95
  let value = attr.value;
95
96
  if (URL_ATTRS.has(lowerName)) {
96
- value = sanitizeUrl(value);
97
+ value = sanitizeUrlAttr(lowerName, value);
97
98
  if (!value) continue;
98
99
  }
99
100
  html += ` ${rawName}="${escapeAttr(value)}"`;
@@ -234,7 +235,7 @@ function buildAttrString(attrs, { allowEventHandlers = false } = {}) {
234
235
  const lowerKey = rawKey.toLowerCase();
235
236
  let value = String(attrs[rawKey]);
236
237
  if (URL_ATTRS.has(lowerKey)) {
237
- value = sanitizeUrl(value);
238
+ value = sanitizeUrlAttr(lowerKey, value);
238
239
  if (!value) continue;
239
240
  }
240
241
  out.push(`${rawKey}="${escapeAttr(value)}"`);
@@ -242,12 +243,17 @@ function buildAttrString(attrs, { allowEventHandlers = false } = {}) {
242
243
  return out.join(" ");
243
244
  }
244
245
  function isDangerousMetaRefresh(metaProps) {
245
- const httpEquiv = metaProps["http-equiv"];
246
+ let httpEquiv;
247
+ let content;
248
+ for (const k in metaProps) {
249
+ const lk = k.toLowerCase();
250
+ if (lk === "http-equiv") httpEquiv = metaProps[k];
251
+ else if (lk === "content") content = metaProps[k];
252
+ }
246
253
  if (typeof httpEquiv !== "string") return false;
247
254
  if (httpEquiv.toLowerCase() !== "refresh") return false;
248
- const content = metaProps.content;
249
255
  if (typeof content !== "string") return false;
250
- const normalized = content.replace(/[\x00-\x20\x7f-\x9f]+/g, "").toLowerCase();
256
+ const normalized = stripControlChars(content).toLowerCase();
251
257
  return normalized.includes("url=javascript:") || normalized.includes("url=data:") || normalized.includes("url=vbscript:") || normalized.includes("url=blob:");
252
258
  }
253
259
  function renderToDocument(component, options = {}) {
@@ -329,7 +335,7 @@ async function* renderToStream(element) {
329
335
  const lowerName = rawName.toLowerCase();
330
336
  let value = attr.value;
331
337
  if (URL_ATTRS.has(lowerName)) {
332
- value = sanitizeUrl(value);
338
+ value = sanitizeUrlAttr(lowerName, value);
333
339
  if (!value) continue;
334
340
  }
335
341
  openTag += ` ${rawName}="${escapeAttr(value)}"`;
@@ -406,11 +412,11 @@ function hydrateProgressively(container, islands, options) {
406
412
  (entries) => {
407
413
  for (const entry of entries) {
408
414
  if (entry.isIntersecting) {
415
+ observer.disconnect();
409
416
  const clientTree = factory();
410
417
  clientTree.setAttribute("data-sibu-island", id);
411
418
  clientTree.setAttribute("data-sibu-hydrated", "true");
412
419
  marker.replaceWith(clientTree);
413
- observer.disconnect();
414
420
  break;
415
421
  }
416
422
  }
@@ -519,6 +525,7 @@ export {
519
525
  renderToString,
520
526
  hydrate,
521
527
  trustHTML,
528
+ isDangerousMetaRefresh,
522
529
  renderToDocument,
523
530
  renderToStream,
524
531
  collectStream,
@@ -3,7 +3,7 @@ import {
3
3
  retrack,
4
4
  track,
5
5
  trackingSuspended
6
- } from "./chunk-3U4ZVXVD.js";
6
+ } from "./chunk-Z2FWAE4B.js";
7
7
  import {
8
8
  devAssert
9
9
  } from "./chunk-LMLD24FC.js";
@@ -15,6 +15,7 @@ function derived(getter, options) {
15
15
  const equals = options?.equals;
16
16
  const cs = {};
17
17
  cs._d = false;
18
+ cs._init = false;
18
19
  cs._g = getter;
19
20
  cs.__v = 0;
20
21
  const markDirty = () => {
@@ -23,11 +24,18 @@ function derived(getter, options) {
23
24
  };
24
25
  markDirty._c = 1;
25
26
  markDirty._sig = cs;
27
+ const recompute = () => {
28
+ const next = getter();
29
+ cs._v = equals && cs._init ? equals(cs._v, next) ? cs._v : next : next;
30
+ cs._d = false;
31
+ cs._init = true;
32
+ };
26
33
  track(() => {
27
34
  let threw = true;
28
35
  try {
29
36
  cs._v = getter();
30
37
  cs._d = false;
38
+ cs._init = true;
31
39
  threw = false;
32
40
  } finally {
33
41
  if (threw) cs._d = true;
@@ -43,20 +51,13 @@ function derived(getter, options) {
43
51
  }
44
52
  if (trackingSuspended) {
45
53
  if (cs._d) {
54
+ const prev = cs._v;
46
55
  evaluating = true;
47
- let threw = true;
48
56
  try {
49
- const prev = cs._v;
50
- retrack(() => {
51
- const next = getter();
52
- cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
53
- cs._d = false;
54
- threw = false;
55
- }, markDirty);
57
+ retrack(recompute, markDirty);
56
58
  if (!Object.is(prev, cs._v)) cs.__v++;
57
59
  } finally {
58
60
  evaluating = false;
59
- if (threw) cs._d = true;
60
61
  }
61
62
  }
62
63
  return cs._v;
@@ -65,18 +66,11 @@ function derived(getter, options) {
65
66
  if (cs._d) {
66
67
  const oldValue = cs._v;
67
68
  evaluating = true;
68
- let threw = true;
69
69
  try {
70
- retrack(() => {
71
- const next = getter();
72
- cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
73
- cs._d = false;
74
- threw = false;
75
- }, markDirty);
70
+ retrack(recompute, markDirty);
76
71
  if (!Object.is(oldValue, cs._v)) cs.__v++;
77
72
  } finally {
78
73
  evaluating = false;
79
- if (threw) cs._d = true;
80
74
  }
81
75
  if (hook && oldValue !== cs._v) {
82
76
  hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
@@ -1,13 +1,17 @@
1
+ import {
2
+ isUnsafeKey,
3
+ stripUnsafeKeys
4
+ } from "./chunk-H3SRKIYX.js";
1
5
  import {
2
6
  derived
3
- } from "./chunk-SC437AMI.js";
7
+ } from "./chunk-JYXOEYI4.js";
4
8
  import {
5
9
  effect
6
- } from "./chunk-ZIBE2SAT.js";
10
+ } from "./chunk-FDY42FIU.js";
7
11
  import {
8
12
  batch,
9
13
  signal
10
- } from "./chunk-RK4BQG25.js";
14
+ } from "./chunk-C427DVQF.js";
11
15
 
12
16
  // src/patterns/machine.ts
13
17
  function machine(config) {
@@ -40,11 +44,7 @@ function machine(config) {
40
44
  }
41
45
  if (action) {
42
46
  const rawPatch = action(ctx);
43
- const next = { ...ctx };
44
- for (const key of Object.keys(rawPatch)) {
45
- if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
46
- next[key] = rawPatch[key];
47
- }
47
+ const next = { ...ctx, ...stripUnsafeKeys(rawPatch) };
48
48
  setContext(next);
49
49
  }
50
50
  setState(target);
@@ -75,10 +75,7 @@ function machine(config) {
75
75
  function persisted(key, initial, options = {}) {
76
76
  const storage = options.session ? sessionStorage : localStorage;
77
77
  const serialize = options.serialize || JSON.stringify;
78
- const safeReviver = (k, v) => {
79
- if (k === "__proto__" || k === "constructor" || k === "prototype") return void 0;
80
- return v;
81
- };
78
+ const safeReviver = (k, v) => isUnsafeKey(k) ? void 0 : v;
82
79
  const deserialize = options.deserialize || ((raw) => JSON.parse(raw, safeReviver));
83
80
  const encrypt = options.encrypt;
84
81
  const decrypt = options.decrypt;
@@ -368,6 +365,7 @@ function deepClone(value) {
368
365
  if (Array.isArray(v)) return v.map(clone);
369
366
  const out = {};
370
367
  for (const k of Object.keys(v)) {
368
+ if (k === "__proto__") continue;
371
369
  out[k] = clone(v[k]);
372
370
  }
373
371
  return out;
@@ -385,12 +383,7 @@ function globalStore(config) {
385
383
  const execute = () => {
386
384
  const current = getState();
387
385
  const rawPatch = actionFn(current, payload);
388
- const patch = {};
389
- for (const key of Object.keys(rawPatch)) {
390
- if (key !== "__proto__" && key !== "constructor" && key !== "prototype") {
391
- patch[key] = rawPatch[key];
392
- }
393
- }
386
+ const patch = stripUnsafeKeys(rawPatch);
394
387
  setState({ ...current, ...patch });
395
388
  const newState = getState();
396
389
  for (const listener of listeners) {