sibujs 3.0.0 → 3.2.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 (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 +276 -150
  5. package/dist/build.js +35 -24
  6. package/dist/cdn.global.js +7 -7
  7. package/dist/{chunk-RJIRT46U.js → chunk-2C4E3HBM.js} +5 -5
  8. package/dist/{chunk-XDKP4T7G.js → chunk-4JCAUOLN.js} +45 -23
  9. package/dist/{chunk-VSNLICTS.js → chunk-5N74TKLD.js} +1 -1
  10. package/dist/{chunk-XVYB3J6C.js → chunk-7XDYVJLE.js} +19 -9
  11. package/dist/{chunk-L52H775O.js → chunk-BGNLPNGV.js} +20 -12
  12. package/dist/{chunk-6QZO7MMG.js → chunk-C427DVQF.js} +1 -1
  13. package/dist/{chunk-5WD7BYTZ.js → chunk-FDY42FIU.js} +3 -2
  14. package/dist/{chunk-4YTVESDX.js → chunk-FOI23UJL.js} +11 -1
  15. package/dist/{chunk-2RA7SHDA.js → chunk-GOJMFRBL.js} +20 -4
  16. package/dist/{chunk-2KM2724A.js → chunk-GOUM4JCT.js} +6 -6
  17. package/dist/chunk-H3SRKIYX.js +17 -0
  18. package/dist/{chunk-NEWH4O5U.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-DF3GTP4Q.js → chunk-JYXOEYI4.js} +12 -18
  22. package/dist/{chunk-KZA7ANXP.js → chunk-NFYWLRUO.js} +11 -18
  23. package/dist/{chunk-KH4OE6WY.js → chunk-NPIEEKPT.js} +20 -11
  24. package/dist/{chunk-V65KTDZW.js → chunk-OYLPZO4N.js} +33 -15
  25. package/dist/{chunk-LYTCUZ7H.js → chunk-RDRSWYNP.js} +1 -1
  26. package/dist/{chunk-UKMXT5T6.js → chunk-RLUJL2MV.js} +7 -12
  27. package/dist/{chunk-INBOWHQ3.js → chunk-V2MTG5FT.js} +99 -36
  28. package/dist/{chunk-CNZ35WI2.js → chunk-VJE6DDYM.js} +2 -2
  29. package/dist/{chunk-2JQUV4Y3.js → chunk-VOCE4NNK.js} +157 -75
  30. package/dist/{chunk-STFTTMO2.js → chunk-X67UYC74.js} +31 -12
  31. package/dist/{chunk-YMOIAHWA.js → chunk-YFDGQWDA.js} +1 -1
  32. package/dist/{chunk-L4DAT4WU.js → chunk-Z2FWAE4B.js} +28 -1
  33. package/dist/data.cjs +211 -93
  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 +163 -65
  42. package/dist/ecosystem.js +9 -9
  43. package/dist/extras.cjs +420 -198
  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 +255 -139
  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 +66 -39
  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 +243 -138
  62. package/dist/plugins.d.cts +1 -1
  63. package/dist/plugins.d.ts +1 -1
  64. package/dist/plugins.js +96 -45
  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 +185 -68
  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 +76 -39
  75. package/dist/ui.js +10 -9
  76. package/dist/widgets.cjs +61 -23
  77. package/dist/widgets.js +8 -8
  78. package/package.json +3 -1
package/dist/ssr.cjs CHANGED
@@ -38,6 +38,7 @@ __export(ssr_exports, {
38
38
  hydrate: () => hydrate,
39
39
  hydrateIslands: () => hydrateIslands,
40
40
  hydrateProgressively: () => hydrateProgressively,
41
+ isDangerousMetaRefresh: () => isDangerousMetaRefresh,
41
42
  isWasmCached: () => isWasmCached,
42
43
  island: () => island,
43
44
  loadRemoteModule: () => loadRemoteModule,
@@ -83,11 +84,15 @@ function devWarn(message) {
83
84
  var als = null;
84
85
  try {
85
86
  if (typeof process !== "undefined" && process.versions && process.versions.node) {
86
- const req = Function("return typeof require==='function'?require:null")();
87
- if (req) {
88
- const mod = req("node:async_hooks");
89
- als = new mod.AsyncLocalStorage();
87
+ let mod = null;
88
+ const getBuiltin = process.getBuiltinModule;
89
+ if (typeof getBuiltin === "function") {
90
+ mod = getBuiltin("node:async_hooks");
91
+ } else {
92
+ const req = Function("return typeof require==='function'?require:null")();
93
+ if (req) mod = req("node:async_hooks");
90
94
  }
95
+ if (mod) als = new mod.AsyncLocalStorage();
91
96
  }
92
97
  } catch {
93
98
  als = null;
@@ -105,9 +110,17 @@ function isSSR() {
105
110
  }
106
111
 
107
112
  // src/utils/sanitize.ts
113
+ function stripControlChars(value) {
114
+ return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
115
+ }
116
+ function isEventHandlerAttr(name) {
117
+ if (name.length < 3) return false;
118
+ const lower = name.toLowerCase();
119
+ return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
120
+ }
108
121
  var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
109
122
  function sanitizeUrl(url) {
110
- const trimmed = url.replace(/[\x00-\x20\x7f-\x9f]+/g, "").trim();
123
+ const trimmed = stripControlChars(url).trim();
111
124
  if (!trimmed) return "";
112
125
  const lower = trimmed.toLowerCase();
113
126
  let schemeEnd = -1;
@@ -170,20 +183,18 @@ var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
170
183
  "data"
171
184
  ]);
172
185
  function isUrlAttribute(attr) {
173
- return URL_ATTRIBUTES.has(attr);
186
+ return URL_ATTRIBUTES.has(attr.toLowerCase());
174
187
  }
175
188
 
176
189
  // src/platform/ssr.ts
190
+ function sanitizeUrlAttr(name, value) {
191
+ return name === "srcset" ? sanitizeSrcset(value) : sanitizeUrl(value);
192
+ }
177
193
  var _isDev2 = isDev();
178
194
  var SAFE_ATTR_NAME = /^[A-Za-z_:][-A-Za-z0-9_.:]*$/;
179
195
  function isSafeAttrName(name) {
180
196
  return SAFE_ATTR_NAME.test(name);
181
197
  }
182
- function isEventHandlerAttr(name) {
183
- if (name.length < 3) return false;
184
- const lower = name.toLowerCase();
185
- return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
186
- }
187
198
  var URL_ATTRS = /* @__PURE__ */ new Set([
188
199
  "href",
189
200
  "src",
@@ -258,7 +269,7 @@ function renderToString(element) {
258
269
  const lowerName = rawName.toLowerCase();
259
270
  let value = attr.value;
260
271
  if (URL_ATTRS.has(lowerName)) {
261
- value = sanitizeUrl(value);
272
+ value = sanitizeUrlAttr(lowerName, value);
262
273
  if (!value) continue;
263
274
  }
264
275
  html2 += ` ${rawName}="${escapeAttr(value)}"`;
@@ -399,7 +410,7 @@ function buildAttrString(attrs, { allowEventHandlers = false } = {}) {
399
410
  const lowerKey = rawKey.toLowerCase();
400
411
  let value = String(attrs[rawKey]);
401
412
  if (URL_ATTRS.has(lowerKey)) {
402
- value = sanitizeUrl(value);
413
+ value = sanitizeUrlAttr(lowerKey, value);
403
414
  if (!value) continue;
404
415
  }
405
416
  out.push(`${rawKey}="${escapeAttr(value)}"`);
@@ -407,12 +418,17 @@ function buildAttrString(attrs, { allowEventHandlers = false } = {}) {
407
418
  return out.join(" ");
408
419
  }
409
420
  function isDangerousMetaRefresh(metaProps) {
410
- const httpEquiv = metaProps["http-equiv"];
421
+ let httpEquiv;
422
+ let content;
423
+ for (const k in metaProps) {
424
+ const lk = k.toLowerCase();
425
+ if (lk === "http-equiv") httpEquiv = metaProps[k];
426
+ else if (lk === "content") content = metaProps[k];
427
+ }
411
428
  if (typeof httpEquiv !== "string") return false;
412
429
  if (httpEquiv.toLowerCase() !== "refresh") return false;
413
- const content = metaProps.content;
414
430
  if (typeof content !== "string") return false;
415
- const normalized = content.replace(/[\x00-\x20\x7f-\x9f]+/g, "").toLowerCase();
431
+ const normalized = stripControlChars(content).toLowerCase();
416
432
  return normalized.includes("url=javascript:") || normalized.includes("url=data:") || normalized.includes("url=vbscript:") || normalized.includes("url=blob:");
417
433
  }
418
434
  function renderToDocument(component, options = {}) {
@@ -494,7 +510,7 @@ async function* renderToStream(element) {
494
510
  const lowerName = rawName.toLowerCase();
495
511
  let value = attr.value;
496
512
  if (URL_ATTRS.has(lowerName)) {
497
- value = sanitizeUrl(value);
513
+ value = sanitizeUrlAttr(lowerName, value);
498
514
  if (!value) continue;
499
515
  }
500
516
  openTag += ` ${rawName}="${escapeAttr(value)}"`;
@@ -571,11 +587,11 @@ function hydrateProgressively(container, islands, options) {
571
587
  (entries) => {
572
588
  for (const entry of entries) {
573
589
  if (entry.isIntersecting) {
590
+ observer.disconnect();
574
591
  const clientTree = factory();
575
592
  clientTree.setAttribute("data-sibu-island", id);
576
593
  clientTree.setAttribute("data-sibu-hydrated", "true");
577
594
  marker2.replaceWith(clientTree);
578
- observer.disconnect();
579
595
  break;
580
596
  }
581
597
  }
@@ -808,7 +824,7 @@ function retrack(effectFn, subscriber) {
808
824
  }
809
825
  }
810
826
  function track(effectFn, subscriber) {
811
- if (!subscriber) subscriber = effectFn;
827
+ if (!subscriber) return reactiveBinding(effectFn);
812
828
  cleanup(subscriber);
813
829
  const prev = currentSubscriber;
814
830
  currentSubscriber = subscriber;
@@ -826,6 +842,32 @@ function track(effectFn, subscriber) {
826
842
  const sub2 = subscriber;
827
843
  return sub2._dispose ?? (sub2._dispose = () => cleanup(subscriber));
828
844
  }
845
+ function reactiveBinding(commit) {
846
+ const run = () => {
847
+ const s2 = subscriber;
848
+ if (s2._disposed || s2._reentrant) return;
849
+ s2._reentrant = true;
850
+ try {
851
+ retrack(commit, subscriber);
852
+ } finally {
853
+ s2._reentrant = false;
854
+ }
855
+ };
856
+ const subscriber = run;
857
+ subscriber.depsHead = null;
858
+ subscriber.depsTail = null;
859
+ subscriber._epoch = 0;
860
+ subscriber._structDirty = false;
861
+ subscriber._runEpoch = 0;
862
+ subscriber._runs = 0;
863
+ subscriber._reentrant = false;
864
+ subscriber._disposed = false;
865
+ run();
866
+ return subscriber._dispose ?? (subscriber._dispose = () => {
867
+ subscriber._disposed = true;
868
+ cleanup(subscriber);
869
+ });
870
+ }
829
871
  function recordDependency(signal2) {
830
872
  if (!currentSubscriber) return;
831
873
  const sub2 = currentSubscriber;
@@ -1092,6 +1134,7 @@ function effect(effectFn, options) {
1092
1134
  ctx.fn(ctx.onCleanup);
1093
1135
  };
1094
1136
  const sub2 = (() => {
1137
+ if (ctx.disposed) return;
1095
1138
  if (ctx.running) {
1096
1139
  ctx.rerunPending = true;
1097
1140
  return;
@@ -1133,24 +1176,28 @@ function sanitizeHeadAttr(key, value) {
1133
1176
  if (HEAD_URL_ATTRS.has(key)) return sanitizeUrl(value);
1134
1177
  return value;
1135
1178
  }
1179
+ function isDangerousRefreshContent(content) {
1180
+ const normalized = stripControlChars(content).toLowerCase();
1181
+ return normalized.includes("url=javascript:") || normalized.includes("url=data:") || normalized.includes("url=vbscript:") || normalized.includes("url=blob:");
1182
+ }
1183
+ function getMetaAttr(metaProps, name) {
1184
+ for (const k in metaProps) {
1185
+ if (k.toLowerCase() === name) return metaProps[k];
1186
+ }
1187
+ return void 0;
1188
+ }
1136
1189
  function isDangerousMetaRefresh2(metaProps) {
1137
- const httpEquiv = metaProps["http-equiv"];
1190
+ const httpEquiv = getMetaAttr(metaProps, "http-equiv");
1138
1191
  if (typeof httpEquiv !== "string") return false;
1139
1192
  if (httpEquiv.toLowerCase() !== "refresh") return false;
1140
- const content = metaProps.content;
1193
+ const content = getMetaAttr(metaProps, "content");
1141
1194
  if (typeof content !== "string") return false;
1142
- const normalized = content.replace(/[\x00-\x20\x7f-\x9f]+/g, "").toLowerCase();
1143
- return normalized.includes("url=javascript:") || normalized.includes("url=data:") || normalized.includes("url=vbscript:") || normalized.includes("url=blob:");
1195
+ return isDangerousRefreshContent(content);
1144
1196
  }
1145
1197
  var SAFE_HEAD_ATTR_NAME = /^[A-Za-z_:][-A-Za-z0-9_.:]*$/;
1146
- function isEventHandlerAttr2(name) {
1147
- if (name.length < 3) return false;
1148
- const lower = name.toLowerCase();
1149
- return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
1150
- }
1151
1198
  function isSafeHeadAttr(name) {
1152
1199
  if (!SAFE_HEAD_ATTR_NAME.test(name)) return false;
1153
- if (isEventHandlerAttr2(name)) return false;
1200
+ if (isEventHandlerAttr(name)) return false;
1154
1201
  return true;
1155
1202
  }
1156
1203
  function escapeScriptJsonLocal(json) {
@@ -1183,15 +1230,27 @@ function Head(props) {
1183
1230
  if (props.meta) {
1184
1231
  for (const metaProps of props.meta) {
1185
1232
  if (isDangerousMetaRefresh2(metaProps)) continue;
1233
+ const httpEquiv = getMetaAttr(metaProps, "http-equiv");
1234
+ const isRefreshNow = () => {
1235
+ const eq = typeof httpEquiv === "function" ? httpEquiv() : httpEquiv;
1236
+ return typeof eq === "string" && eq.toLowerCase() === "refresh";
1237
+ };
1186
1238
  const el = document.createElement("meta");
1187
1239
  for (const [key, value] of Object.entries(metaProps)) {
1188
1240
  if (!isSafeHeadAttr(key)) continue;
1241
+ const isContent = key.toLowerCase() === "content";
1189
1242
  if (typeof value === "function") {
1190
1243
  const cleanupFn = effect(() => {
1191
- el.setAttribute(key, sanitizeHeadAttr(key, value()));
1244
+ const resolved = value();
1245
+ if (isContent && isRefreshNow() && isDangerousRefreshContent(resolved)) {
1246
+ el.removeAttribute(key);
1247
+ return;
1248
+ }
1249
+ el.setAttribute(key, sanitizeHeadAttr(key, resolved));
1192
1250
  });
1193
1251
  effectCleanups.push(cleanupFn);
1194
1252
  } else {
1253
+ if (isContent && isRefreshNow() && isDangerousRefreshContent(value)) continue;
1195
1254
  el.setAttribute(key, sanitizeHeadAttr(key, value));
1196
1255
  }
1197
1256
  }
@@ -1411,13 +1470,13 @@ function createISR(options) {
1411
1470
  if (typeof console !== "undefined") console.warn("[SibuJS ISR] revalidate failed", err);
1412
1471
  });
1413
1472
  }, revalidateAfter);
1414
- const dispose = () => {
1473
+ const dispose2 = () => {
1415
1474
  if (disposed) return;
1416
1475
  disposed = true;
1417
1476
  clearInterval(intervalId);
1418
1477
  controller.abort();
1419
1478
  };
1420
- return { data: data2, isStale, revalidate, dispose };
1479
+ return { data: data2, isStale, revalidate, dispose: dispose2 };
1421
1480
  }
1422
1481
 
1423
1482
  // src/platform/routeActions.ts
@@ -1480,14 +1539,14 @@ function scrollRestoration(options) {
1480
1539
  };
1481
1540
  window.addEventListener("popstate", popstateHandler);
1482
1541
  }
1483
- const dispose = () => {
1542
+ const dispose2 = () => {
1484
1543
  if (popstateHandler) {
1485
1544
  window.removeEventListener("popstate", popstateHandler);
1486
1545
  popstateHandler = null;
1487
1546
  }
1488
1547
  positions.clear();
1489
1548
  };
1490
- return { save, restore, getPosition, dispose };
1549
+ return { save, restore, getPosition, dispose: dispose2 };
1491
1550
  }
1492
1551
 
1493
1552
  // src/platform/routeMiddleware.ts
@@ -1526,13 +1585,8 @@ var _isDev5 = isDev();
1526
1585
  function setProp(el, key, val) {
1527
1586
  el[key] = val;
1528
1587
  }
1529
- function isEventHandlerAttr3(name) {
1530
- if (name.length < 3) return false;
1531
- const lower = name.toLowerCase();
1532
- return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
1533
- }
1534
1588
  function bindAttribute(el, attr, getter) {
1535
- if (isEventHandlerAttr3(attr)) {
1589
+ if (isEventHandlerAttr(attr)) {
1536
1590
  if (_isDev5)
1537
1591
  devWarn(
1538
1592
  `bindAttribute: refusing to bind event-handler attribute "${attr}". Use on:{ ${attr.slice(2)}: fn } instead.`
@@ -1566,12 +1620,72 @@ function bindAttribute(el, attr, getter) {
1566
1620
  el.setAttribute(attr, isUrlAttribute(attr) ? sanitizeUrl(str) : str);
1567
1621
  }
1568
1622
  }
1569
- const teardown = track(commit);
1570
- return teardown;
1623
+ return reactiveBinding(commit);
1571
1624
  }
1572
1625
 
1573
- // src/reactivity/bindChildNode.ts
1626
+ // src/core/rendering/dispose.ts
1627
+ var elementDisposers = /* @__PURE__ */ new WeakMap();
1574
1628
  var _isDev6 = isDev();
1629
+ var activeBindingCount = 0;
1630
+ function registerDisposer(node, teardown) {
1631
+ let disposers = elementDisposers.get(node);
1632
+ if (!disposers) {
1633
+ disposers = [];
1634
+ elementDisposers.set(node, disposers);
1635
+ }
1636
+ disposers.push(teardown);
1637
+ if (_isDev6) activeBindingCount++;
1638
+ }
1639
+ function dispose(node) {
1640
+ const stack = [node];
1641
+ const order = [];
1642
+ while (stack.length > 0) {
1643
+ const current = stack.pop();
1644
+ order.push(current);
1645
+ const children = Array.from(current.childNodes);
1646
+ for (let i2 = 0; i2 < children.length; i2++) {
1647
+ stack.push(children[i2]);
1648
+ }
1649
+ }
1650
+ for (let i2 = order.length - 1; i2 >= 0; i2--) {
1651
+ const current = order[i2];
1652
+ const disposers = elementDisposers.get(current);
1653
+ if (disposers) {
1654
+ const snapshot = disposers.slice();
1655
+ elementDisposers.delete(current);
1656
+ if (_isDev6) activeBindingCount -= snapshot.length;
1657
+ for (const d of snapshot) {
1658
+ try {
1659
+ d();
1660
+ } catch (err) {
1661
+ if (_isDev6 && typeof console !== "undefined") {
1662
+ console.warn("[SibuJS] Disposer threw during cleanup:", err);
1663
+ }
1664
+ }
1665
+ }
1666
+ let extraPasses = 0;
1667
+ while (extraPasses++ < 8) {
1668
+ const added = elementDisposers.get(current);
1669
+ if (!added || added.length === 0) break;
1670
+ const moreSnapshot = added.slice();
1671
+ elementDisposers.delete(current);
1672
+ if (_isDev6) activeBindingCount -= moreSnapshot.length;
1673
+ for (const d of moreSnapshot) {
1674
+ try {
1675
+ d();
1676
+ } catch (err) {
1677
+ if (_isDev6 && typeof console !== "undefined") {
1678
+ console.warn("[SibuJS] Disposer threw during cleanup:", err);
1679
+ }
1680
+ }
1681
+ }
1682
+ }
1683
+ }
1684
+ }
1685
+ }
1686
+
1687
+ // src/reactivity/bindChildNode.ts
1688
+ var _isDev7 = isDev();
1575
1689
  function bindChildNode(placeholder, getter) {
1576
1690
  let lastNodes = [];
1577
1691
  function commit() {
@@ -1579,12 +1693,13 @@ function bindChildNode(placeholder, getter) {
1579
1693
  try {
1580
1694
  result = getter();
1581
1695
  } catch (err) {
1582
- if (_isDev6) devWarn(`bindChildNode: getter threw: ${err instanceof Error ? err.message : String(err)}`);
1696
+ if (_isDev7) devWarn(`bindChildNode: getter threw: ${err instanceof Error ? err.message : String(err)}`);
1583
1697
  return;
1584
1698
  }
1585
1699
  if (result == null || typeof result === "boolean") {
1586
1700
  for (let i2 = 0; i2 < lastNodes.length; i2++) {
1587
1701
  const node = lastNodes[i2];
1702
+ dispose(node);
1588
1703
  if (node.parentNode) node.parentNode.removeChild(node);
1589
1704
  }
1590
1705
  lastNodes.length = 0;
@@ -1604,7 +1719,7 @@ function bindChildNode(placeholder, getter) {
1604
1719
  if (item == null || typeof item === "boolean") continue;
1605
1720
  const node = item instanceof Node ? item : document.createTextNode(String(item));
1606
1721
  if (seen.has(node)) {
1607
- if (_isDev6)
1722
+ if (_isDev7)
1608
1723
  devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
1609
1724
  continue;
1610
1725
  }
@@ -1626,36 +1741,20 @@ function bindChildNode(placeholder, getter) {
1626
1741
  for (let i2 = 0; i2 < lastNodes.length; i2++) {
1627
1742
  const node = lastNodes[i2];
1628
1743
  if (reused?.has(node)) continue;
1744
+ dispose(node);
1629
1745
  if (node.parentNode) node.parentNode.removeChild(node);
1630
1746
  }
1631
- const anchor = placeholder.nextSibling;
1747
+ let prev = placeholder;
1632
1748
  for (let i2 = 0; i2 < newNodes.length; i2++) {
1633
1749
  const node = newNodes[i2];
1634
- if (reused?.has(node) && node.parentNode === parent) {
1635
- if (node.nextSibling !== anchor) {
1636
- parent.insertBefore(node, anchor);
1637
- }
1638
- } else {
1639
- parent.insertBefore(node, anchor);
1750
+ if (prev.nextSibling !== node) {
1751
+ parent.insertBefore(node, prev.nextSibling);
1640
1752
  }
1753
+ prev = node;
1641
1754
  }
1642
1755
  lastNodes = newNodes;
1643
1756
  }
1644
- return track(commit);
1645
- }
1646
-
1647
- // src/core/rendering/dispose.ts
1648
- var elementDisposers = /* @__PURE__ */ new WeakMap();
1649
- var _isDev7 = isDev();
1650
- var activeBindingCount = 0;
1651
- function registerDisposer(node, teardown) {
1652
- let disposers = elementDisposers.get(node);
1653
- if (!disposers) {
1654
- disposers = [];
1655
- elementDisposers.set(node, disposers);
1656
- }
1657
- disposers.push(teardown);
1658
- if (_isDev7) activeBindingCount++;
1757
+ return reactiveBinding(commit);
1659
1758
  }
1660
1759
 
1661
1760
  // src/core/rendering/tagFactory.ts
@@ -1684,6 +1783,18 @@ var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
1684
1783
  function setProp2(el, key, val) {
1685
1784
  el[key] = val;
1686
1785
  }
1786
+ function looksLikeClassList(s2) {
1787
+ const t = s2.trim();
1788
+ if (!t) return false;
1789
+ const tokens = t.split(/\s+/);
1790
+ let sawClassish = false;
1791
+ for (let i2 = 0; i2 < tokens.length; i2++) {
1792
+ const tok = tokens[i2];
1793
+ if (!/^-?[A-Za-z_][A-Za-z0-9_:/.-]*$/.test(tok)) return false;
1794
+ if (/[-:/0-9]/.test(tok)) sawClassish = true;
1795
+ }
1796
+ return sawClassish;
1797
+ }
1687
1798
  var kebabCache = /* @__PURE__ */ new Map();
1688
1799
  function toKebab(prop) {
1689
1800
  let cached = kebabCache.get(prop);
@@ -1819,6 +1930,11 @@ var tagFactory = (tag, ns) => {
1819
1930
  appendChildren(el, second);
1820
1931
  return el;
1821
1932
  }
1933
+ if (_isDev8 && looksLikeClassList(first)) {
1934
+ devWarn(
1935
+ `tagFactory: lone string "${first}" looks like a class list but is being rendered as TEXT. For a class, use ${tag}({ class: "${first}" }) \u2014 or ${tag}("${first}", children) to set the class AND add children.`
1936
+ );
1937
+ }
1822
1938
  el.textContent = first;
1823
1939
  return el;
1824
1940
  }
@@ -1876,7 +1992,7 @@ var tagFactory = (tag, ns) => {
1876
1992
  const value = props[key];
1877
1993
  if (value == null) continue;
1878
1994
  const lkey = key.toLowerCase();
1879
- if (lkey[0] === "o" && lkey[1] === "n") continue;
1995
+ if (isEventHandlerAttr(key)) continue;
1880
1996
  if (typeof value === "function") {
1881
1997
  registerDisposer(el, bindAttribute(el, key, value));
1882
1998
  } else if (typeof value === "boolean") {
@@ -2643,6 +2759,7 @@ function isWasmCached(key) {
2643
2759
  hydrate,
2644
2760
  hydrateIslands,
2645
2761
  hydrateProgressively,
2762
+ isDangerousMetaRefresh,
2646
2763
  isWasmCached,
2647
2764
  island,
2648
2765
  loadRemoteModule,
package/dist/ssr.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { H as HydrateOptions, a as HydrationMismatch, T as TrustedHTML, c as collectStream, d as deserializeState, e as escapeScriptJson, h as hydrate, b as hydrateIslands, f as hydrateProgressively, i as island, r as renderToDocument, g as renderToReadableStream, j as renderToStream, k as renderToString, l as renderToSuspenseStream, m as resetSSRState, s as serializeState, n as ssrSuspense, o as suspenseSwapScript, t as trustHTML } from './ssr-CrVNy6Pa.cjs';
1
+ export { H as HydrateOptions, a as HydrationMismatch, T as TrustedHTML, c as collectStream, d as deserializeState, e as escapeScriptJson, h as hydrate, b as hydrateIslands, f as hydrateProgressively, i as isDangerousMetaRefresh, g as island, r as renderToDocument, j as renderToReadableStream, k as renderToStream, l as renderToString, m as renderToSuspenseStream, n as resetSSRState, s as serializeState, o as ssrSuspense, p as suspenseSwapScript, t as trustHTML } from './ssr-D62yFwuw.cjs';
2
2
 
3
3
  interface HeadProps {
4
4
  title?: string | (() => string);
package/dist/ssr.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { H as HydrateOptions, a as HydrationMismatch, T as TrustedHTML, c as collectStream, d as deserializeState, e as escapeScriptJson, h as hydrate, b as hydrateIslands, f as hydrateProgressively, i as island, r as renderToDocument, g as renderToReadableStream, j as renderToStream, k as renderToString, l as renderToSuspenseStream, m as resetSSRState, s as serializeState, n as ssrSuspense, o as suspenseSwapScript, t as trustHTML } from './ssr-CrVNy6Pa.js';
1
+ export { H as HydrateOptions, a as HydrationMismatch, T as TrustedHTML, c as collectStream, d as deserializeState, e as escapeScriptJson, h as hydrate, b as hydrateIslands, f as hydrateProgressively, i as isDangerousMetaRefresh, g as island, r as renderToDocument, j as renderToReadableStream, k as renderToStream, l as renderToString, m as renderToSuspenseStream, n as resetSSRState, s as serializeState, o as ssrSuspense, p as suspenseSwapScript, t as trustHTML } from './ssr-D62yFwuw.js';
2
2
 
3
3
  interface HeadProps {
4
4
  title?: string | (() => string);
package/dist/ssr.js CHANGED
@@ -22,8 +22,8 @@ import {
22
22
  wasm,
23
23
  worker,
24
24
  workerFn
25
- } from "./chunk-V65KTDZW.js";
26
- import "./chunk-VSNLICTS.js";
25
+ } from "./chunk-OYLPZO4N.js";
26
+ import "./chunk-5N74TKLD.js";
27
27
  import {
28
28
  collectStream,
29
29
  deserializeState,
@@ -31,6 +31,7 @@ import {
31
31
  hydrate,
32
32
  hydrateIslands,
33
33
  hydrateProgressively,
34
+ isDangerousMetaRefresh,
34
35
  island,
35
36
  renderToDocument,
36
37
  renderToReadableStream,
@@ -42,15 +43,15 @@ import {
42
43
  ssrSuspense,
43
44
  suspenseSwapScript,
44
45
  trustHTML
45
- } from "./chunk-JYD2PWXH.js";
46
- import "./chunk-STFTTMO2.js";
47
- import "./chunk-UKMXT5T6.js";
46
+ } from "./chunk-HXMS4SNP.js";
47
+ import "./chunk-X67UYC74.js";
48
+ import "./chunk-RLUJL2MV.js";
48
49
  import "./chunk-2UPRY23K.js";
49
- import "./chunk-UCS6AMJ7.js";
50
- import "./chunk-5WD7BYTZ.js";
51
- import "./chunk-2RA7SHDA.js";
52
- import "./chunk-6QZO7MMG.js";
53
- import "./chunk-L4DAT4WU.js";
50
+ import "./chunk-HMJFCBRR.js";
51
+ import "./chunk-FDY42FIU.js";
52
+ import "./chunk-GOJMFRBL.js";
53
+ import "./chunk-C427DVQF.js";
54
+ import "./chunk-Z2FWAE4B.js";
54
55
  import "./chunk-LMLD24FC.js";
55
56
  export {
56
57
  Head,
@@ -71,6 +72,7 @@ export {
71
72
  hydrate,
72
73
  hydrateIslands,
73
74
  hydrateProgressively,
75
+ isDangerousMetaRefresh,
74
76
  isWasmCached,
75
77
  island,
76
78
  loadRemoteModule,
package/dist/testing.cjs CHANGED
@@ -1637,11 +1637,15 @@ function cleanup(subscriber) {
1637
1637
  var als = null;
1638
1638
  try {
1639
1639
  if (typeof process !== "undefined" && process.versions && process.versions.node) {
1640
- const req = Function("return typeof require==='function'?require:null")();
1641
- if (req) {
1642
- const mod = req("node:async_hooks");
1643
- als = new mod.AsyncLocalStorage();
1640
+ let mod = null;
1641
+ const getBuiltin = process.getBuiltinModule;
1642
+ if (typeof getBuiltin === "function") {
1643
+ mod = getBuiltin("node:async_hooks");
1644
+ } else {
1645
+ const req = Function("return typeof require==='function'?require:null")();
1646
+ if (req) mod = req("node:async_hooks");
1644
1647
  }
1648
+ if (mod) als = new mod.AsyncLocalStorage();
1645
1649
  }
1646
1650
  } catch {
1647
1651
  als = null;
@@ -1743,6 +1747,7 @@ function effect(effectFn, options) {
1743
1747
  ctx.fn(ctx.onCleanup);
1744
1748
  };
1745
1749
  const sub = (() => {
1750
+ if (ctx.disposed) return;
1746
1751
  if (ctx.running) {
1747
1752
  ctx.rerunPending = true;
1748
1753
  return;
package/dist/testing.js CHANGED
@@ -3,9 +3,9 @@ import {
3
3
  } from "./chunk-2UPRY23K.js";
4
4
  import {
5
5
  effect
6
- } from "./chunk-5WD7BYTZ.js";
7
- import "./chunk-2RA7SHDA.js";
8
- import "./chunk-L4DAT4WU.js";
6
+ } from "./chunk-FDY42FIU.js";
7
+ import "./chunk-GOJMFRBL.js";
8
+ import "./chunk-Z2FWAE4B.js";
9
9
  import "./chunk-LMLD24FC.js";
10
10
 
11
11
  // src/testing/a11y.ts