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
package/dist/index.cjs CHANGED
@@ -99,6 +99,7 @@ __export(index_exports, {
99
99
  footer: () => footer,
100
100
  form: () => form,
101
101
  g: () => g,
102
+ getRequestScopedCache: () => getRequestScopedCache,
102
103
  getSSRStore: () => getSSRStore,
103
104
  getSlot: () => getSlot,
104
105
  h1: () => h1,
@@ -248,9 +249,17 @@ function devWarn(message) {
248
249
  }
249
250
 
250
251
  // src/utils/sanitize.ts
252
+ function stripControlChars(value) {
253
+ return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
254
+ }
255
+ function isEventHandlerAttr(name) {
256
+ if (name.length < 3) return false;
257
+ const lower = name.toLowerCase();
258
+ return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
259
+ }
251
260
  var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
252
261
  function sanitizeUrl(url) {
253
- const trimmed = url.replace(/[\x00-\x20\x7f-\x9f]+/g, "").trim();
262
+ const trimmed = stripControlChars(url).trim();
254
263
  if (!trimmed) return "";
255
264
  const lower = trimmed.toLowerCase();
256
265
  let schemeEnd = -1;
@@ -313,7 +322,7 @@ var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
313
322
  "data"
314
323
  ]);
315
324
  function isUrlAttribute(attr) {
316
- return URL_ATTRIBUTES.has(attr);
325
+ return URL_ATTRIBUTES.has(attr.toLowerCase());
317
326
  }
318
327
 
319
328
  // src/reactivity/track.ts
@@ -492,7 +501,7 @@ function track(effectFn, subscriber) {
492
501
  function reactiveBinding(commit) {
493
502
  const run = () => {
494
503
  const s2 = subscriber;
495
- if (s2._reentrant) return;
504
+ if (s2._disposed || s2._reentrant) return;
496
505
  s2._reentrant = true;
497
506
  try {
498
507
  retrack(commit, subscriber);
@@ -508,8 +517,12 @@ function reactiveBinding(commit) {
508
517
  subscriber._runEpoch = 0;
509
518
  subscriber._runs = 0;
510
519
  subscriber._reentrant = false;
520
+ subscriber._disposed = false;
511
521
  run();
512
- return subscriber._dispose ?? (subscriber._dispose = () => cleanup(subscriber));
522
+ return subscriber._dispose ?? (subscriber._dispose = () => {
523
+ subscriber._disposed = true;
524
+ cleanup(subscriber);
525
+ });
513
526
  }
514
527
  function recordDependency(signal2) {
515
528
  if (!currentSubscriber) return;
@@ -702,11 +715,6 @@ var _isDev3 = isDev();
702
715
  function setProp(el, key, val) {
703
716
  el[key] = val;
704
717
  }
705
- function isEventHandlerAttr(name) {
706
- if (name.length < 3) return false;
707
- const lower = name.toLowerCase();
708
- return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
709
- }
710
718
  function bindAttribute(el, attr, getter) {
711
719
  if (isEventHandlerAttr(attr)) {
712
720
  if (_isDev3)
@@ -761,7 +769,7 @@ function bindDynamic(el, nameGetter, valueGetter) {
761
769
  if (_isDev3) devWarn(`bindDynamic: value getter threw: ${err instanceof Error ? err.message : String(err)}`);
762
770
  return;
763
771
  }
764
- if ((name[0] === "o" || name[0] === "O") && (name[1] === "n" || name[1] === "N")) return;
772
+ if (isEventHandlerAttr(name)) return;
765
773
  if (prevName !== null && prevName !== name) {
766
774
  el.removeAttribute(prevName);
767
775
  }
@@ -782,8 +790,78 @@ function bindDynamic(el, nameGetter, valueGetter) {
782
790
  };
783
791
  }
784
792
 
785
- // src/reactivity/bindChildNode.ts
793
+ // src/core/rendering/dispose.ts
794
+ var elementDisposers = /* @__PURE__ */ new WeakMap();
786
795
  var _isDev4 = isDev();
796
+ var activeBindingCount = 0;
797
+ function registerDisposer(node, teardown) {
798
+ let disposers = elementDisposers.get(node);
799
+ if (!disposers) {
800
+ disposers = [];
801
+ elementDisposers.set(node, disposers);
802
+ }
803
+ disposers.push(teardown);
804
+ if (_isDev4) activeBindingCount++;
805
+ }
806
+ function dispose(node) {
807
+ const stack = [node];
808
+ const order = [];
809
+ while (stack.length > 0) {
810
+ const current = stack.pop();
811
+ order.push(current);
812
+ const children = Array.from(current.childNodes);
813
+ for (let i2 = 0; i2 < children.length; i2++) {
814
+ stack.push(children[i2]);
815
+ }
816
+ }
817
+ for (let i2 = order.length - 1; i2 >= 0; i2--) {
818
+ const current = order[i2];
819
+ const disposers = elementDisposers.get(current);
820
+ if (disposers) {
821
+ const snapshot = disposers.slice();
822
+ elementDisposers.delete(current);
823
+ if (_isDev4) activeBindingCount -= snapshot.length;
824
+ for (const d of snapshot) {
825
+ try {
826
+ d();
827
+ } catch (err) {
828
+ if (_isDev4 && typeof console !== "undefined") {
829
+ console.warn("[SibuJS] Disposer threw during cleanup:", err);
830
+ }
831
+ }
832
+ }
833
+ let extraPasses = 0;
834
+ while (extraPasses++ < 8) {
835
+ const added = elementDisposers.get(current);
836
+ if (!added || added.length === 0) break;
837
+ const moreSnapshot = added.slice();
838
+ elementDisposers.delete(current);
839
+ if (_isDev4) activeBindingCount -= moreSnapshot.length;
840
+ for (const d of moreSnapshot) {
841
+ try {
842
+ d();
843
+ } catch (err) {
844
+ if (_isDev4 && typeof console !== "undefined") {
845
+ console.warn("[SibuJS] Disposer threw during cleanup:", err);
846
+ }
847
+ }
848
+ }
849
+ }
850
+ }
851
+ }
852
+ }
853
+ function checkLeaks(warnThreshold = 0) {
854
+ if (!_isDev4) return 0;
855
+ if (warnThreshold > 0 && activeBindingCount > warnThreshold) {
856
+ devWarn(
857
+ `checkLeaks: ${activeBindingCount} active DOM bindings detected. Expected \u2264${warnThreshold}. This may indicate a component was removed from the DOM without calling dispose().`
858
+ );
859
+ }
860
+ return activeBindingCount;
861
+ }
862
+
863
+ // src/reactivity/bindChildNode.ts
864
+ var _isDev5 = isDev();
787
865
  function bindChildNode(placeholder, getter) {
788
866
  let lastNodes = [];
789
867
  function commit() {
@@ -791,12 +869,13 @@ function bindChildNode(placeholder, getter) {
791
869
  try {
792
870
  result = getter();
793
871
  } catch (err) {
794
- if (_isDev4) devWarn(`bindChildNode: getter threw: ${err instanceof Error ? err.message : String(err)}`);
872
+ if (_isDev5) devWarn(`bindChildNode: getter threw: ${err instanceof Error ? err.message : String(err)}`);
795
873
  return;
796
874
  }
797
875
  if (result == null || typeof result === "boolean") {
798
876
  for (let i2 = 0; i2 < lastNodes.length; i2++) {
799
877
  const node = lastNodes[i2];
878
+ dispose(node);
800
879
  if (node.parentNode) node.parentNode.removeChild(node);
801
880
  }
802
881
  lastNodes.length = 0;
@@ -816,7 +895,7 @@ function bindChildNode(placeholder, getter) {
816
895
  if (item == null || typeof item === "boolean") continue;
817
896
  const node = item instanceof Node ? item : document.createTextNode(String(item));
818
897
  if (seen.has(node)) {
819
- if (_isDev4)
898
+ if (_isDev5)
820
899
  devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
821
900
  continue;
822
901
  }
@@ -838,94 +917,22 @@ function bindChildNode(placeholder, getter) {
838
917
  for (let i2 = 0; i2 < lastNodes.length; i2++) {
839
918
  const node = lastNodes[i2];
840
919
  if (reused?.has(node)) continue;
920
+ dispose(node);
841
921
  if (node.parentNode) node.parentNode.removeChild(node);
842
922
  }
843
- const anchor = placeholder.nextSibling;
923
+ let prev = placeholder;
844
924
  for (let i2 = 0; i2 < newNodes.length; i2++) {
845
925
  const node = newNodes[i2];
846
- if (reused?.has(node) && node.parentNode === parent) {
847
- if (node.nextSibling !== anchor) {
848
- parent.insertBefore(node, anchor);
849
- }
850
- } else {
851
- parent.insertBefore(node, anchor);
926
+ if (prev.nextSibling !== node) {
927
+ parent.insertBefore(node, prev.nextSibling);
852
928
  }
929
+ prev = node;
853
930
  }
854
931
  lastNodes = newNodes;
855
932
  }
856
933
  return reactiveBinding(commit);
857
934
  }
858
935
 
859
- // src/core/rendering/dispose.ts
860
- var elementDisposers = /* @__PURE__ */ new WeakMap();
861
- var _isDev5 = isDev();
862
- var activeBindingCount = 0;
863
- function registerDisposer(node, teardown) {
864
- let disposers = elementDisposers.get(node);
865
- if (!disposers) {
866
- disposers = [];
867
- elementDisposers.set(node, disposers);
868
- }
869
- disposers.push(teardown);
870
- if (_isDev5) activeBindingCount++;
871
- }
872
- function dispose(node) {
873
- const stack = [node];
874
- const order = [];
875
- while (stack.length > 0) {
876
- const current = stack.pop();
877
- order.push(current);
878
- const children = Array.from(current.childNodes);
879
- for (let i2 = 0; i2 < children.length; i2++) {
880
- stack.push(children[i2]);
881
- }
882
- }
883
- for (let i2 = order.length - 1; i2 >= 0; i2--) {
884
- const current = order[i2];
885
- const disposers = elementDisposers.get(current);
886
- if (disposers) {
887
- const snapshot = disposers.slice();
888
- elementDisposers.delete(current);
889
- if (_isDev5) activeBindingCount -= snapshot.length;
890
- for (const d of snapshot) {
891
- try {
892
- d();
893
- } catch (err) {
894
- if (_isDev5 && typeof console !== "undefined") {
895
- console.warn("[SibuJS] Disposer threw during cleanup:", err);
896
- }
897
- }
898
- }
899
- let extraPasses = 0;
900
- while (extraPasses++ < 8) {
901
- const added = elementDisposers.get(current);
902
- if (!added || added.length === 0) break;
903
- const moreSnapshot = added.slice();
904
- elementDisposers.delete(current);
905
- if (_isDev5) activeBindingCount -= moreSnapshot.length;
906
- for (const d of moreSnapshot) {
907
- try {
908
- d();
909
- } catch (err) {
910
- if (_isDev5 && typeof console !== "undefined") {
911
- console.warn("[SibuJS] Disposer threw during cleanup:", err);
912
- }
913
- }
914
- }
915
- }
916
- }
917
- }
918
- }
919
- function checkLeaks(warnThreshold = 0) {
920
- if (!_isDev5) return 0;
921
- if (warnThreshold > 0 && activeBindingCount > warnThreshold) {
922
- devWarn(
923
- `checkLeaks: ${activeBindingCount} active DOM bindings detected. Expected \u2264${warnThreshold}. This may indicate a component was removed from the DOM without calling dispose().`
924
- );
925
- }
926
- return activeBindingCount;
927
- }
928
-
929
936
  // src/core/rendering/tagFactory.ts
930
937
  var SVG_NS = "http://www.w3.org/2000/svg";
931
938
  var _isDev6 = isDev();
@@ -1161,7 +1168,7 @@ var tagFactory = (tag, ns) => {
1161
1168
  const value = props[key];
1162
1169
  if (value == null) continue;
1163
1170
  const lkey = key.toLowerCase();
1164
- if (lkey[0] === "o" && lkey[1] === "n") continue;
1171
+ if (isEventHandlerAttr(key)) continue;
1165
1172
  if (typeof value === "function") {
1166
1173
  registerDisposer(el, bindAttribute(el, key, value));
1167
1174
  } else if (typeof value === "boolean") {
@@ -1442,14 +1449,28 @@ function parseTemplate(strings) {
1442
1449
  }
1443
1450
  return { kind: "mixed", statics, exprs };
1444
1451
  }
1445
- const valStart = pos;
1446
- while (pos < len) {
1447
- const c = template2.charCodeAt(pos);
1448
- if (c === 32 || c === 9 || c === 10 || c === 13 || c === 62 || c === 47) break;
1449
- pos++;
1452
+ {
1453
+ const statics = [];
1454
+ const exprs = [];
1455
+ let current = "";
1456
+ while (pos < len) {
1457
+ const c = template2.charCodeAt(pos);
1458
+ if (c === 32 || c === 9 || c === 10 || c === 13 || c === 62) break;
1459
+ const innerIdx = tryExprIdx();
1460
+ if (innerIdx >= 0) {
1461
+ statics.push(current);
1462
+ current = "";
1463
+ exprs.push(innerIdx);
1464
+ } else {
1465
+ current += template2[pos++];
1466
+ }
1467
+ }
1468
+ statics.push(current);
1469
+ if (exprs.length === 0) {
1470
+ return { kind: "static", value: statics[0] };
1471
+ }
1472
+ return { kind: "mixed", statics, exprs };
1450
1473
  }
1451
- const val = template2.slice(valStart, pos);
1452
- return { kind: "static", value: val };
1453
1474
  }
1454
1475
  function parseAttrs() {
1455
1476
  const attrs = [];
@@ -1506,6 +1527,30 @@ function parseTemplate(strings) {
1506
1527
  while (pos < len) {
1507
1528
  if (template2[pos] === "<" && pos + 1 < len && template2[pos + 1] === "/") break;
1508
1529
  if (template2[pos] === "<") {
1530
+ const next = template2[pos + 1];
1531
+ if (next === "!") {
1532
+ if (template2.startsWith("<!--", pos)) {
1533
+ const end = template2.indexOf("-->", pos + 4);
1534
+ pos = end === -1 ? len : end + 3;
1535
+ } else if (template2.startsWith("<![CDATA[", pos)) {
1536
+ const end = template2.indexOf("]]>", pos + 9);
1537
+ pos = end === -1 ? len : end + 3;
1538
+ } else {
1539
+ const end = template2.indexOf(">", pos);
1540
+ pos = end === -1 ? len : end + 1;
1541
+ }
1542
+ continue;
1543
+ }
1544
+ if (next === "?") {
1545
+ const end = template2.indexOf(">", pos);
1546
+ pos = end === -1 ? len : end + 1;
1547
+ continue;
1548
+ }
1549
+ if (!(next >= "a" && next <= "z") && !(next >= "A" && next <= "Z")) {
1550
+ children.push({ t: 1, value: "<" });
1551
+ pos++;
1552
+ continue;
1553
+ }
1509
1554
  pos++;
1510
1555
  const tag = readTagName();
1511
1556
  const attrs = parseAttrs();
@@ -1554,7 +1599,7 @@ function executeElement(tmpl, values) {
1554
1599
  case 1: {
1555
1600
  const name = attr.name;
1556
1601
  const lname = name.toLowerCase();
1557
- if (lname[0] === "o" && lname[1] === "n") break;
1602
+ if (isEventHandlerAttr(name)) break;
1558
1603
  const val = values[attr.idx];
1559
1604
  if (typeof val === "function") {
1560
1605
  registerDisposer(el, bindAttribute(el, name, val));
@@ -1803,6 +1848,11 @@ function each(getArray, render, options) {
1803
1848
  workMap.clear();
1804
1849
  keyIndexMap.clear();
1805
1850
  for (let i2 = 0; i2 < newLen; i2++) {
1851
+ if (_isDev8 && keyIndexMap.has(newKeys[i2])) {
1852
+ devWarn(
1853
+ `each: duplicate key "${String(newKeys[i2])}" at index ${i2} (first seen at ${keyIndexMap.get(newKeys[i2])}). Keys must be unique \u2014 duplicates cause rows to be dropped or mis-ordered.`
1854
+ );
1855
+ }
1806
1856
  keyIndexMap.set(newKeys[i2], i2);
1807
1857
  }
1808
1858
  for (let i2 = 0; i2 < newLen; i2++) {
@@ -2034,7 +2084,7 @@ function show(condition, element) {
2034
2084
  const update = () => {
2035
2085
  element.style.display = condition() ? "" : "none";
2036
2086
  };
2037
- track(update);
2087
+ registerDisposer(element, track(update));
2038
2088
  return element;
2039
2089
  }
2040
2090
  function when(condition, thenBranch, elseBranch) {
@@ -2061,7 +2111,7 @@ function when(condition, thenBranch, elseBranch) {
2061
2111
  }
2062
2112
  initialized = true;
2063
2113
  };
2064
- track(update);
2114
+ registerDisposer(anchor, track(update));
2065
2115
  if (!initialized) {
2066
2116
  queueMicrotask(() => {
2067
2117
  if (!initialized && anchor.parentNode) update();
@@ -2096,7 +2146,7 @@ function match(value, cases, fallback) {
2096
2146
  }
2097
2147
  initialized = true;
2098
2148
  };
2099
- track(update);
2149
+ registerDisposer(anchor, track(update));
2100
2150
  if (!initialized) {
2101
2151
  queueMicrotask(() => {
2102
2152
  if (!initialized && anchor.parentNode) update();
@@ -2137,6 +2187,12 @@ function KeepAlive(activeKey, cases, options) {
2137
2187
  return;
2138
2188
  }
2139
2189
  node = factory();
2190
+ if (node instanceof DocumentFragment) {
2191
+ const wrapper = document.createElement("div");
2192
+ wrapper.style.display = "contents";
2193
+ wrapper.appendChild(node);
2194
+ node = wrapper;
2195
+ }
2140
2196
  cache2.set(key, node);
2141
2197
  lruOrder.push(key);
2142
2198
  if (max > 0 && lruOrder.length > max) {
@@ -2421,11 +2477,15 @@ function signal(initial, options) {
2421
2477
  var als = null;
2422
2478
  try {
2423
2479
  if (typeof process !== "undefined" && process.versions && process.versions.node) {
2424
- const req = Function("return typeof require==='function'?require:null")();
2425
- if (req) {
2426
- const mod = req("node:async_hooks");
2427
- als = new mod.AsyncLocalStorage();
2480
+ let mod = null;
2481
+ const getBuiltin = process.getBuiltinModule;
2482
+ if (typeof getBuiltin === "function") {
2483
+ mod = getBuiltin("node:async_hooks");
2484
+ } else {
2485
+ const req = Function("return typeof require==='function'?require:null")();
2486
+ if (req) mod = req("node:async_hooks");
2428
2487
  }
2488
+ if (mod) als = new mod.AsyncLocalStorage();
2429
2489
  }
2430
2490
  } catch {
2431
2491
  als = null;
@@ -2441,6 +2501,17 @@ function getSSRStore() {
2441
2501
  function isSSR() {
2442
2502
  return getSSRStore().ssr;
2443
2503
  }
2504
+ function getRequestScopedCache(name) {
2505
+ if (!isSSR()) return null;
2506
+ const store2 = getSSRStore();
2507
+ const caches = store2.caches ?? (store2.caches = /* @__PURE__ */ new Map());
2508
+ let c = caches.get(name);
2509
+ if (!c) {
2510
+ c = /* @__PURE__ */ new Map();
2511
+ caches.set(name, c);
2512
+ }
2513
+ return c;
2514
+ }
2444
2515
  function enableSSR() {
2445
2516
  getSSRStore().ssr = true;
2446
2517
  }
@@ -2575,6 +2646,7 @@ function effect(effectFn, options) {
2575
2646
  ctx.fn(ctx.onCleanup);
2576
2647
  };
2577
2648
  const sub2 = (() => {
2649
+ if (ctx.disposed) return;
2578
2650
  if (ctx.running) {
2579
2651
  ctx.rerunPending = true;
2580
2652
  return;
@@ -2617,6 +2689,7 @@ function derived(getter, options) {
2617
2689
  const equals = options?.equals;
2618
2690
  const cs = {};
2619
2691
  cs._d = false;
2692
+ cs._init = false;
2620
2693
  cs._g = getter;
2621
2694
  cs.__v = 0;
2622
2695
  const markDirty = () => {
@@ -2625,11 +2698,18 @@ function derived(getter, options) {
2625
2698
  };
2626
2699
  markDirty._c = 1;
2627
2700
  markDirty._sig = cs;
2701
+ const recompute = () => {
2702
+ const next = getter();
2703
+ cs._v = equals && cs._init ? equals(cs._v, next) ? cs._v : next : next;
2704
+ cs._d = false;
2705
+ cs._init = true;
2706
+ };
2628
2707
  track(() => {
2629
2708
  let threw = true;
2630
2709
  try {
2631
2710
  cs._v = getter();
2632
2711
  cs._d = false;
2712
+ cs._init = true;
2633
2713
  threw = false;
2634
2714
  } finally {
2635
2715
  if (threw) cs._d = true;
@@ -2645,20 +2725,13 @@ function derived(getter, options) {
2645
2725
  }
2646
2726
  if (trackingSuspended) {
2647
2727
  if (cs._d) {
2728
+ const prev = cs._v;
2648
2729
  evaluating = true;
2649
- let threw = true;
2650
2730
  try {
2651
- const prev = cs._v;
2652
- retrack(() => {
2653
- const next = getter();
2654
- cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
2655
- cs._d = false;
2656
- threw = false;
2657
- }, markDirty);
2731
+ retrack(recompute, markDirty);
2658
2732
  if (!Object.is(prev, cs._v)) cs.__v++;
2659
2733
  } finally {
2660
2734
  evaluating = false;
2661
- if (threw) cs._d = true;
2662
2735
  }
2663
2736
  }
2664
2737
  return cs._v;
@@ -2667,18 +2740,11 @@ function derived(getter, options) {
2667
2740
  if (cs._d) {
2668
2741
  const oldValue = cs._v;
2669
2742
  evaluating = true;
2670
- let threw = true;
2671
2743
  try {
2672
- retrack(() => {
2673
- const next = getter();
2674
- cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
2675
- cs._d = false;
2676
- threw = false;
2677
- }, markDirty);
2744
+ retrack(recompute, markDirty);
2678
2745
  if (!Object.is(oldValue, cs._v)) cs.__v++;
2679
2746
  } finally {
2680
2747
  evaluating = false;
2681
- if (threw) cs._d = true;
2682
2748
  }
2683
2749
  if (hook && oldValue !== cs._v) {
2684
2750
  hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
@@ -2731,12 +2797,12 @@ function store(initialState) {
2731
2797
  signals[key] = [getter, setter];
2732
2798
  });
2733
2799
  const store2 = new Proxy({}, {
2734
- get(_, prop) {
2735
- if (prop in signals) {
2800
+ get(target, prop) {
2801
+ if (typeof prop === "string" && Object.hasOwn(signals, prop)) {
2736
2802
  const getter = signals[prop][0];
2737
2803
  return getter();
2738
2804
  }
2739
- return void 0;
2805
+ return Reflect.get(target, prop);
2740
2806
  },
2741
2807
  set() {
2742
2808
  throw new Error(
@@ -2756,7 +2822,7 @@ function store(initialState) {
2756
2822
  const nextState = typeof patch === "function" ? patch(current) : patch;
2757
2823
  batch(() => {
2758
2824
  Object.entries(nextState).forEach(([key, value]) => {
2759
- if (key in signals) {
2825
+ if (Object.hasOwn(signals, key)) {
2760
2826
  signals[key][1](value);
2761
2827
  }
2762
2828
  });
@@ -3054,6 +3120,14 @@ function deepEqual(a2, b2, seen) {
3054
3120
  }
3055
3121
  return true;
3056
3122
  }
3123
+ if (a2 instanceof DataView) {
3124
+ if (!(b2 instanceof DataView)) return false;
3125
+ if (a2.byteLength !== b2.byteLength) return false;
3126
+ for (let i2 = 0; i2 < a2.byteLength; i2++) {
3127
+ if (a2.getUint8(i2) !== b2.getUint8(i2)) return false;
3128
+ }
3129
+ return true;
3130
+ }
3057
3131
  if (ArrayBuffer.isView(a2) && ArrayBuffer.isView(b2)) {
3058
3132
  const ta = a2;
3059
3133
  const tb = b2;
@@ -3072,7 +3146,7 @@ function deepEqual(a2, b2, seen) {
3072
3146
  const keysB = Object.keys(objB);
3073
3147
  if (keysA.length !== keysB.length) return false;
3074
3148
  return keysA.every(
3075
- (key) => deepEqual(objA[key], objB[key], seen)
3149
+ (key) => Object.hasOwn(objB, key) && deepEqual(objA[key], objB[key], seen)
3076
3150
  );
3077
3151
  }
3078
3152
  function deepSignal(initial) {
@@ -3575,34 +3649,37 @@ function Suspense({ nodes, fallback }) {
3575
3649
  container.appendChild(fallbackEl);
3576
3650
  let suspenseDisposed = false;
3577
3651
  let observer = null;
3652
+ let childEl = null;
3578
3653
  registerDisposer(container, () => {
3579
3654
  suspenseDisposed = true;
3580
3655
  if (observer) {
3581
3656
  observer.disconnect();
3582
3657
  observer = null;
3583
3658
  }
3659
+ if (childEl && !container.contains(childEl)) dispose(childEl);
3584
3660
  });
3585
3661
  queueMicrotask(() => {
3586
3662
  if (suspenseDisposed) return;
3587
3663
  try {
3588
- const childEl = nodes();
3589
- if (childEl.classList.contains("sibu-lazy")) {
3590
- if (!childEl.querySelector(".sibu-lazy-loading")) {
3591
- container.replaceChildren(childEl);
3664
+ const el = nodes();
3665
+ childEl = el;
3666
+ if (el.classList.contains("sibu-lazy")) {
3667
+ if (!el.querySelector(".sibu-lazy-loading")) {
3668
+ container.replaceChildren(el);
3592
3669
  return;
3593
3670
  }
3594
3671
  observer = new MutationObserver(() => {
3595
3672
  if (suspenseDisposed) return;
3596
- const loading = childEl.querySelector(".sibu-lazy-loading");
3673
+ const loading = el.querySelector(".sibu-lazy-loading");
3597
3674
  if (!loading) {
3598
3675
  observer?.disconnect();
3599
3676
  observer = null;
3600
- container.replaceChildren(childEl);
3677
+ container.replaceChildren(el);
3601
3678
  }
3602
3679
  });
3603
- observer.observe(childEl, { childList: true, subtree: true });
3680
+ observer.observe(el, { childList: true, subtree: true });
3604
3681
  } else {
3605
- container.replaceChildren(childEl);
3682
+ container.replaceChildren(el);
3606
3683
  }
3607
3684
  } catch (err) {
3608
3685
  const errorObj = err instanceof Error ? err : new Error(String(err));
@@ -4516,6 +4593,7 @@ function Loading(props = {}) {
4516
4593
  footer,
4517
4594
  form,
4518
4595
  g,
4596
+ getRequestScopedCache,
4519
4597
  getSSRStore,
4520
4598
  getSlot,
4521
4599
  h1,
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { T as TagProps, N as NodeChildren, a as NodeChild } from './tagFactory-S17H2qxu.cjs';
2
2
  export { D as Dispose, S as SVG_NS, t as tagFactory } from './tagFactory-S17H2qxu.cjs';
3
3
  import { R as ReactiveSignal } from './signal-BnWpq6WB.cjs';
4
- export { T as TrustedHTML, t as trustHTML } from './ssr-CrVNy6Pa.cjs';
4
+ export { T as TrustedHTML, t as trustHTML } from './ssr-D62yFwuw.cjs';
5
5
 
6
6
  type reactive<T> = T | (() => T);
7
7
  interface AnchorProps extends TagProps {
@@ -1226,11 +1226,24 @@ declare function strictEffect(fn: () => void): () => void;
1226
1226
  interface SSRStore {
1227
1227
  ssr: boolean;
1228
1228
  suspenseIdCounter: number;
1229
+ /**
1230
+ * Per-request data caches (e.g. the query cache). Lazily created and keyed
1231
+ * by subsystem so request-scoped data never bleeds between concurrent
1232
+ * server renders. Typed loosely to avoid a dependency cycle with data/.
1233
+ */
1234
+ caches?: Map<string, Map<string, unknown>>;
1229
1235
  }
1230
1236
  /** Returns the active store (ALS or fallback). */
1231
1237
  declare function getSSRStore(): SSRStore;
1232
1238
  /** Returns true when running in SSR mode. */
1233
1239
  declare function isSSR(): boolean;
1240
+ /**
1241
+ * Returns a request-scoped cache map for the given subsystem when running
1242
+ * under SSR (so concurrent requests never share it), or `null` on the client
1243
+ * where a process-global cache is correct. On Node the store is backed by
1244
+ * AsyncLocalStorage, giving each request its own caches.
1245
+ */
1246
+ declare function getRequestScopedCache<V>(name: string): Map<string, V> | null;
1234
1247
  /** Enable SSR mode. Side effects (effect, watch, onMount) become no-ops. */
1235
1248
  declare function enableSSR(): void;
1236
1249
  /** Disable SSR mode. Side effects resume normal behavior. */
@@ -1538,4 +1551,4 @@ interface LoadingProps {
1538
1551
  */
1539
1552
  declare function Loading(props?: LoadingProps): HTMLElement;
1540
1553
 
1541
- export { type Accessor, type ActionFn, type AnchorProps, type ArrayActions, type AsyncDerivedState, type AudioProps, type ButtonProps, type Context, DynamicComponent, type EffectBody, type EffectOptions, ErrorBoundary, type ErrorBoundaryOptions, type ErrorBoundaryProps, ErrorDisplay, type ErrorDisplayProps, type ErrorSeverity, type FormProps, Fragment, type ImgProps, type InputProps, type InputType, KeepAlive, type KeepAliveOptions, type LabelProps, Loading, type LoadingProps, type LongPressOptions, type MediaProps, NodeChild, NodeChildren, type OnCleanup, type OptionProps, Portal, type Ref, type SSRStore, type SelectProps, type SignalOptions, type SlotFn, type Slots, type StoreActions, Suspense, type SuspenseProps, TagProps, type TextareaProps, type TypedTagFunction, type VideoProps, __resetIdCounter, a, abbr, action, address, area, array, article, aside, asyncDerived, audio, autoResize, b, base, batch, bdi, bdo, bindDynamic, blockquote, body, br, button, canvas, caption, catchError, catchErrorAsync, center, checkLeaks, circle, cite, clickOutside, clipPath, code, col, colgroup, context, copyOnClick, createId, customElement, data, datalist, dd, deepEqual, deepSignal, defer, defs, del, derived, details, dfn, dialog, disableSSR, dispose, div, dl, dt, each, effect, ellipse, em, embed, enableSSR, enqueueBatchedSignal, fieldset, figcaption, figure, font, footer, form, g, getSSRStore, getSlot, h1, h2, h3, h4, h5, h6, head, header, hr, html, i, iframe, img, input, ins, isBatching, isSSR, kbd, label, lazy, legend, li, line, linearGradient, link, longPress, main, map, mark, marker, marquee, mask, match, math, menu, meta, meter, mount, nav, nextTick, noscript, object, ol, on, onCleanup, onMount, onUnmount, optgroup, option, output, p, param, path, pattern, picture, polygon, polyline, portal, pre, progress, q, radialGradient, reactiveArray, rect, ref, registerComponent, registerDisposer, resolveComponent, retrack, rp, rt, ruby, runInSSRContext, s, samp, script, section, select, setGlobalErrorHandler, setMaxDrainIterations, show, signal, slot, small, source, span, stop, store, strict, strictEffect, strong, style, sub, summary, sup, svg, symbol, table, takePendingError, tbody, td, template, text, textarea, tfoot, th, thead, time, title, tr, track, transition, trapFocus, tspan, u, ul, unregisterComponent, untracked, use, var_, video, watch, when, withSSR, writable };
1554
+ export { type Accessor, type ActionFn, type AnchorProps, type ArrayActions, type AsyncDerivedState, type AudioProps, type ButtonProps, type Context, DynamicComponent, type EffectBody, type EffectOptions, ErrorBoundary, type ErrorBoundaryOptions, type ErrorBoundaryProps, ErrorDisplay, type ErrorDisplayProps, type ErrorSeverity, type FormProps, Fragment, type ImgProps, type InputProps, type InputType, KeepAlive, type KeepAliveOptions, type LabelProps, Loading, type LoadingProps, type LongPressOptions, type MediaProps, NodeChild, NodeChildren, type OnCleanup, type OptionProps, Portal, type Ref, type SSRStore, type SelectProps, type SignalOptions, type SlotFn, type Slots, type StoreActions, Suspense, type SuspenseProps, TagProps, type TextareaProps, type TypedTagFunction, type VideoProps, __resetIdCounter, a, abbr, action, address, area, array, article, aside, asyncDerived, audio, autoResize, b, base, batch, bdi, bdo, bindDynamic, blockquote, body, br, button, canvas, caption, catchError, catchErrorAsync, center, checkLeaks, circle, cite, clickOutside, clipPath, code, col, colgroup, context, copyOnClick, createId, customElement, data, datalist, dd, deepEqual, deepSignal, defer, defs, del, derived, details, dfn, dialog, disableSSR, dispose, div, dl, dt, each, effect, ellipse, em, embed, enableSSR, enqueueBatchedSignal, fieldset, figcaption, figure, font, footer, form, g, getRequestScopedCache, getSSRStore, getSlot, h1, h2, h3, h4, h5, h6, head, header, hr, html, i, iframe, img, input, ins, isBatching, isSSR, kbd, label, lazy, legend, li, line, linearGradient, link, longPress, main, map, mark, marker, marquee, mask, match, math, menu, meta, meter, mount, nav, nextTick, noscript, object, ol, on, onCleanup, onMount, onUnmount, optgroup, option, output, p, param, path, pattern, picture, polygon, polyline, portal, pre, progress, q, radialGradient, reactiveArray, rect, ref, registerComponent, registerDisposer, resolveComponent, retrack, rp, rt, ruby, runInSSRContext, s, samp, script, section, select, setGlobalErrorHandler, setMaxDrainIterations, show, signal, slot, small, source, span, stop, store, strict, strictEffect, strong, style, sub, summary, sup, svg, symbol, table, takePendingError, tbody, td, template, text, textarea, tfoot, th, thead, time, title, tr, track, transition, trapFocus, tspan, u, ul, unregisterComponent, untracked, use, var_, video, watch, when, withSSR, writable };