sibujs 2.1.0 → 3.0.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 (62) hide show
  1. package/dist/browser.cjs +324 -273
  2. package/dist/browser.js +4 -4
  3. package/dist/build.cjs +363 -330
  4. package/dist/build.js +10 -10
  5. package/dist/cdn.global.js +8 -8
  6. package/dist/{chunk-ZAQSMOED.js → chunk-2JQUV4Y3.js} +4 -4
  7. package/dist/{chunk-GWWURC5M.js → chunk-2KM2724A.js} +2 -2
  8. package/dist/{chunk-NASX6ST2.js → chunk-4YTVESDX.js} +1 -1
  9. package/dist/chunk-5WD7BYTZ.js +152 -0
  10. package/dist/{chunk-RDTDJCAB.js → chunk-6QZO7MMG.js} +48 -16
  11. package/dist/{chunk-DRUZZAK4.js → chunk-DF3GTP4Q.js} +7 -2
  12. package/dist/{chunk-AMK2TYNW.js → chunk-INBOWHQ3.js} +14 -11
  13. package/dist/{chunk-O6EFQ3KT.js → chunk-KH4OE6WY.js} +5 -5
  14. package/dist/{chunk-V6C4FADE.js → chunk-KZA7ANXP.js} +3 -3
  15. package/dist/chunk-L4DAT4WU.js +400 -0
  16. package/dist/{chunk-WANSMF2L.js → chunk-L52H775O.js} +4 -4
  17. package/dist/{chunk-45YP72ZQ.js → chunk-NEWH4O5U.js} +1 -1
  18. package/dist/{chunk-ON5MMR2J.js → chunk-RJIRT46U.js} +4 -4
  19. package/dist/{chunk-P2HSJDDN.js → chunk-STFTTMO2.js} +2 -2
  20. package/dist/{chunk-WIPZPFBQ.js → chunk-UKMXT5T6.js} +1 -1
  21. package/dist/{chunk-KGYT6UO6.js → chunk-V65KTDZW.js} +3 -3
  22. package/dist/{chunk-CWBVQML6.js → chunk-VSNLICTS.js} +1 -1
  23. package/dist/{chunk-3DZP6OIT.js → chunk-XDKP4T7G.js} +2 -2
  24. package/dist/{chunk-TH2ILCYW.js → chunk-XVYB3J6C.js} +27 -33
  25. package/dist/{chunk-OJ3P4ECI.js → chunk-YMOIAHWA.js} +1 -1
  26. package/dist/data.cjs +332 -298
  27. package/dist/data.js +6 -6
  28. package/dist/devtools.cjs +353 -296
  29. package/dist/devtools.d.cts +1 -1
  30. package/dist/devtools.d.ts +1 -1
  31. package/dist/devtools.js +4 -4
  32. package/dist/ecosystem.cjs +332 -298
  33. package/dist/ecosystem.js +7 -7
  34. package/dist/extras.cjs +372 -328
  35. package/dist/extras.d.cts +1 -1
  36. package/dist/extras.d.ts +1 -1
  37. package/dist/extras.js +19 -19
  38. package/dist/index.cjs +363 -330
  39. package/dist/index.d.cts +26 -36
  40. package/dist/index.d.ts +26 -36
  41. package/dist/index.js +10 -10
  42. package/dist/{introspect-DnIpHQQz.d.ts → introspect-BZWKvQUZ.d.ts} +2 -3
  43. package/dist/{introspect-2TOlQ7oa.d.cts → introspect-DsJlDD2T.d.cts} +2 -3
  44. package/dist/motion.cjs +147 -123
  45. package/dist/motion.js +3 -3
  46. package/dist/patterns.cjs +332 -298
  47. package/dist/patterns.js +5 -5
  48. package/dist/performance.cjs +315 -268
  49. package/dist/performance.js +4 -4
  50. package/dist/plugins.cjs +332 -266
  51. package/dist/plugins.js +6 -6
  52. package/dist/ssr.cjs +340 -270
  53. package/dist/ssr.js +7 -7
  54. package/dist/testing.cjs +167 -146
  55. package/dist/testing.js +2 -2
  56. package/dist/ui.cjs +324 -294
  57. package/dist/ui.js +6 -6
  58. package/dist/widgets.cjs +332 -298
  59. package/dist/widgets.js +6 -6
  60. package/package.json +1 -1
  61. package/dist/chunk-QO3WC6FS.js +0 -384
  62. package/dist/chunk-WZA53FXU.js +0 -149
package/dist/plugins.cjs CHANGED
@@ -775,24 +775,88 @@ init_sanitize();
775
775
  // src/reactivity/track.ts
776
776
  init_dev();
777
777
  var _isDev2 = isDev();
778
- var STACK_INITIAL = 32;
779
- var STACK_SHRINK_THRESHOLD = 128;
780
- var subscriberStack = new Array(STACK_INITIAL);
781
- var stackCapacity = STACK_INITIAL;
782
- var stackTop = -1;
783
- var currentSubscriber = null;
784
- var SUBS = "__s";
785
- function syncFastPath(signal2, subs) {
786
- const size = subs.size;
787
- if (size === 0) {
788
- signal2.__f = void 0;
789
- delete signal2[SUBS];
790
- } else if (size === 1) {
791
- signal2.__f = subs.values().next().value;
792
- } else {
793
- signal2.__f = void 0;
794
- }
778
+ var POOL_MAX = 4096;
779
+ var nodePool = [];
780
+ function createNode() {
781
+ return {
782
+ sig: null,
783
+ sub: null,
784
+ epoch: 0,
785
+ sigPrev: null,
786
+ sigNext: null,
787
+ subPrev: null,
788
+ subNext: null,
789
+ prevActive: null
790
+ };
791
+ }
792
+ function allocNode(sig, sub2, epoch) {
793
+ const n = nodePool.pop();
794
+ if (n) {
795
+ n.sig = sig;
796
+ n.sub = sub2;
797
+ n.epoch = epoch;
798
+ return n;
799
+ }
800
+ const fresh = createNode();
801
+ fresh.sig = sig;
802
+ fresh.sub = sub2;
803
+ fresh.epoch = epoch;
804
+ return fresh;
805
+ }
806
+ function freeNode(node) {
807
+ node.sig = null;
808
+ node.sub = null;
809
+ node.sigPrev = null;
810
+ node.sigNext = null;
811
+ node.subPrev = null;
812
+ node.subNext = null;
813
+ node.prevActive = null;
814
+ if (nodePool.length < POOL_MAX) nodePool.push(node);
815
+ }
816
+ function linkSignal(sig, node) {
817
+ const oldHead = sig.subsHead ?? null;
818
+ node.sigPrev = null;
819
+ node.sigNext = oldHead;
820
+ if (oldHead) oldHead.sigPrev = node;
821
+ else sig.subsTail = node;
822
+ sig.subsHead = node;
823
+ sig.__sc = (sig.__sc ?? 0) + 1;
824
+ }
825
+ function unlinkSignal(node) {
826
+ const sig = node.sig;
827
+ if (!sig) return;
828
+ const prev = node.sigPrev;
829
+ const next = node.sigNext;
830
+ if (prev) prev.sigNext = next;
831
+ else sig.subsHead = next;
832
+ if (next) next.sigPrev = prev;
833
+ else sig.subsTail = prev;
834
+ sig.__sc = (sig.__sc ?? 1) - 1;
835
+ if (sig.__activeNode === node) sig.__activeNode = node.prevActive;
836
+ if (sig.__sc === 0) {
837
+ sig.subsHead = null;
838
+ sig.subsTail = null;
839
+ }
840
+ }
841
+ function linkSub(sub2, node) {
842
+ const oldTail = sub2.depsTail ?? null;
843
+ node.subPrev = oldTail;
844
+ node.subNext = null;
845
+ if (oldTail) oldTail.subNext = node;
846
+ else sub2.depsHead = node;
847
+ sub2.depsTail = node;
848
+ }
849
+ function unlinkSub(node) {
850
+ const sub2 = node.sub;
851
+ if (!sub2) return;
852
+ const prev = node.subPrev;
853
+ const next = node.subNext;
854
+ if (prev) prev.subNext = next;
855
+ else sub2.depsHead = next;
856
+ if (next) next.subPrev = prev;
857
+ else sub2.depsTail = prev;
795
858
  }
859
+ var currentSubscriber = null;
796
860
  var notifyDepth = 0;
797
861
  var pendingQueue = [];
798
862
  var pendingSet = /* @__PURE__ */ new Set();
@@ -804,64 +868,84 @@ function safeInvoke(sub2) {
804
868
  if (_isDev2) devWarn(`Subscriber threw during notification: ${err instanceof Error ? err.message : String(err)}`);
805
869
  }
806
870
  }
871
+ var subscriberEpochCounter = 0;
872
+ function retrack(effectFn, subscriber) {
873
+ const prev = currentSubscriber;
874
+ currentSubscriber = subscriber;
875
+ const sub2 = subscriber;
876
+ const epoch = ++subscriberEpochCounter;
877
+ sub2._epoch = epoch;
878
+ sub2._structDirty = false;
879
+ for (let n = sub2.depsHead ?? null; n !== null; n = n.subNext) {
880
+ const sig = n.sig;
881
+ n.prevActive = sig.__activeNode ?? null;
882
+ sig.__activeNode = n;
883
+ }
884
+ try {
885
+ effectFn();
886
+ } finally {
887
+ currentSubscriber = prev;
888
+ let node = sub2.depsHead ?? null;
889
+ while (node !== null) {
890
+ const next = node.subNext;
891
+ const sig = node.sig;
892
+ sig.__activeNode = node.prevActive;
893
+ node.prevActive = null;
894
+ if (node.epoch !== epoch) {
895
+ unlinkSub(node);
896
+ unlinkSignal(node);
897
+ freeNode(node);
898
+ }
899
+ node = next;
900
+ }
901
+ }
902
+ }
807
903
  function track(effectFn, subscriber) {
808
904
  if (!subscriber) subscriber = effectFn;
809
905
  cleanup(subscriber);
810
- ++stackTop;
811
- if (stackTop >= stackCapacity) {
812
- stackCapacity *= 2;
813
- subscriberStack.length = stackCapacity;
814
- }
815
- subscriberStack[stackTop] = subscriber;
906
+ const prev = currentSubscriber;
816
907
  currentSubscriber = subscriber;
817
908
  try {
818
909
  effectFn();
819
910
  } finally {
820
- stackTop--;
821
- currentSubscriber = stackTop >= 0 ? subscriberStack[stackTop] : null;
822
- if (stackTop < 0 && stackCapacity > STACK_SHRINK_THRESHOLD) {
823
- stackCapacity = Math.max(STACK_INITIAL, stackCapacity >>> 1);
824
- subscriberStack.length = stackCapacity;
911
+ currentSubscriber = prev;
912
+ const sub3 = subscriber;
913
+ for (let n = sub3.depsHead ?? null; n !== null; n = n.subNext) {
914
+ const sig = n.sig;
915
+ sig.__activeNode = n.prevActive;
916
+ n.prevActive = null;
825
917
  }
826
918
  }
827
- return () => cleanup(subscriber);
919
+ const sub2 = subscriber;
920
+ return sub2._dispose ?? (sub2._dispose = () => cleanup(subscriber));
828
921
  }
829
922
  function recordDependency(signal2) {
830
923
  if (!currentSubscriber) return;
831
924
  const sub2 = currentSubscriber;
832
- const epoch = sub2._epoch;
833
- if (sub2._dep === signal2) {
834
- sub2._depEpoch = epoch;
835
- return;
836
- }
837
- const deps = sub2._deps;
838
- if (deps) {
839
- deps.set(signal2, epoch);
840
- } else if (sub2._dep !== void 0) {
841
- const map2 = /* @__PURE__ */ new Map();
842
- map2.set(sub2._dep, sub2._depEpoch);
843
- map2.set(signal2, epoch);
844
- sub2._deps = map2;
845
- sub2._dep = void 0;
846
- sub2._depEpoch = void 0;
847
- } else {
848
- sub2._dep = signal2;
849
- sub2._depEpoch = epoch;
850
- }
851
925
  const sig = signal2;
852
- let subs = sig[SUBS];
853
- if (!subs) {
854
- subs = /* @__PURE__ */ new Set();
855
- sig[SUBS] = subs;
926
+ const epoch = sub2._epoch ?? 0;
927
+ const active = sig.__activeNode ?? null;
928
+ if (active !== null && active.sub === sub2) {
929
+ active.epoch = epoch;
930
+ return;
856
931
  }
857
- const prevSize = subs.size;
858
- subs.add(currentSubscriber);
859
- if (subs.size !== prevSize) {
860
- if (subs.size === 1) {
861
- sig.__f = currentSubscriber;
862
- } else if (sig.__f !== void 0) {
863
- sig.__f = void 0;
864
- }
932
+ const node = allocNode(signal2, sub2, epoch);
933
+ node.prevActive = active;
934
+ sig.__activeNode = node;
935
+ linkSub(sub2, node);
936
+ linkSignal(sig, node);
937
+ sub2._structDirty = true;
938
+ }
939
+ function cleanup(subscriber) {
940
+ const sub2 = subscriber;
941
+ let node = sub2.depsHead ?? null;
942
+ sub2.depsHead = null;
943
+ sub2.depsTail = null;
944
+ while (node) {
945
+ const next = node.subNext;
946
+ unlinkSignal(node);
947
+ freeNode(node);
948
+ node = next;
865
949
  }
866
950
  }
867
951
  var maxSubscriberRepeats = 50;
@@ -874,7 +958,8 @@ function tickRepeat(sub2) {
874
958
  s2._runs = 1;
875
959
  return false;
876
960
  }
877
- return ++s2._runs > maxSubscriberRepeats;
961
+ s2._runs = (s2._runs ?? 0) + 1;
962
+ return s2._runs > maxSubscriberRepeats;
878
963
  }
879
964
  function cycleError(sub2) {
880
965
  if (typeof console !== "undefined") {
@@ -916,93 +1001,64 @@ function propagateDirty(sub2) {
916
1001
  stack.push(rootSig);
917
1002
  while (stack.length > baseLen) {
918
1003
  const sig = stack.pop();
919
- const first = sig.__f;
920
- if (first) {
921
- if (first._c) {
922
- const nSig = first._sig;
923
- if (!nSig._d) {
924
- nSig._d = true;
925
- stack.push(nSig);
926
- }
927
- } else if (!pendingSet.has(first)) {
928
- pendingSet.add(first);
929
- pendingQueue.push(first);
930
- }
931
- continue;
932
- }
933
- const subs = sig[SUBS];
934
- if (!subs) continue;
935
- for (const s2 of subs) {
936
- if (s2._c) {
937
- const nSig = s2._sig;
938
- if (nSig && !nSig._d) {
939
- nSig._d = true;
940
- stack.push(nSig);
941
- } else if (!nSig) {
942
- s2();
1004
+ let node = sig.subsHead ?? null;
1005
+ while (node) {
1006
+ const s2 = node.sub;
1007
+ if (s2) {
1008
+ if (s2._c) {
1009
+ const nSig = s2._sig;
1010
+ if (nSig) {
1011
+ if (!nSig._d) {
1012
+ nSig._d = true;
1013
+ stack.push(nSig);
1014
+ }
1015
+ } else {
1016
+ s2();
1017
+ }
1018
+ } else if (!pendingSet.has(s2)) {
1019
+ pendingSet.add(s2);
1020
+ pendingQueue.push(s2);
943
1021
  }
944
- } else if (!pendingSet.has(s2)) {
945
- pendingSet.add(s2);
946
- pendingQueue.push(s2);
947
1022
  }
1023
+ node = node.sigNext;
948
1024
  }
949
1025
  }
950
1026
  }
951
1027
  function notifySubscribers(signal2) {
952
- const first = signal2.__f;
953
- if (first) {
954
- if (notifyDepth > 0) {
955
- if (first._c) {
956
- propagateDirty(first);
957
- } else if (!pendingSet.has(first)) {
958
- pendingSet.add(first);
959
- pendingQueue.push(first);
960
- }
961
- return;
962
- }
963
- notifyDepth++;
964
- drainEpoch++;
965
- try {
966
- if (first._c) {
967
- propagateDirty(first);
968
- } else if (tickRepeat(first)) {
969
- cycleError(first);
970
- } else {
971
- safeInvoke(first);
972
- }
973
- drainQueue();
974
- } finally {
975
- notifyDepth--;
976
- if (notifyDepth === 0) {
977
- pendingQueue.length = 0;
978
- pendingSet.clear();
979
- }
980
- }
981
- return;
982
- }
983
- const subs = signal2[SUBS];
984
- if (!subs || subs.size === 0) return;
1028
+ const sig = signal2;
1029
+ const head2 = sig.subsHead;
1030
+ if (!head2) return;
985
1031
  if (notifyDepth > 0) {
986
- for (const sub2 of subs) {
987
- if (sub2._c) {
988
- propagateDirty(sub2);
989
- } else if (!pendingSet.has(sub2)) {
990
- pendingSet.add(sub2);
991
- pendingQueue.push(sub2);
1032
+ let node = head2;
1033
+ while (node) {
1034
+ const s2 = node.sub;
1035
+ if (s2) {
1036
+ if (s2._c) {
1037
+ propagateDirty(s2);
1038
+ } else if (!pendingSet.has(s2)) {
1039
+ pendingSet.add(s2);
1040
+ pendingQueue.push(s2);
1041
+ }
992
1042
  }
1043
+ node = node.sigNext;
993
1044
  }
994
1045
  return;
995
1046
  }
996
1047
  notifyDepth++;
997
1048
  drainEpoch++;
998
1049
  try {
999
- for (const sub2 of subs) {
1000
- if (sub2._c) {
1001
- propagateDirty(sub2);
1002
- } else if (!pendingSet.has(sub2)) {
1003
- pendingSet.add(sub2);
1004
- pendingQueue.push(sub2);
1050
+ let node = head2;
1051
+ while (node) {
1052
+ const s2 = node.sub;
1053
+ if (s2) {
1054
+ if (s2._c) {
1055
+ propagateDirty(s2);
1056
+ } else if (!pendingSet.has(s2)) {
1057
+ pendingSet.add(s2);
1058
+ pendingQueue.push(s2);
1059
+ }
1005
1060
  }
1061
+ node = node.sigNext;
1006
1062
  }
1007
1063
  drainQueue();
1008
1064
  } finally {
@@ -1013,30 +1069,6 @@ function notifySubscribers(signal2) {
1013
1069
  }
1014
1070
  }
1015
1071
  }
1016
- function cleanup(subscriber) {
1017
- const sub2 = subscriber;
1018
- const singleDep = sub2._dep;
1019
- if (singleDep !== void 0) {
1020
- const sig = singleDep;
1021
- const subs = sig[SUBS];
1022
- if (subs?.delete(subscriber)) {
1023
- syncFastPath(sig, subs);
1024
- }
1025
- sub2._dep = void 0;
1026
- sub2._depEpoch = void 0;
1027
- return;
1028
- }
1029
- const deps = sub2._deps;
1030
- if (!deps || deps.size === 0) return;
1031
- for (const signal2 of deps.keys()) {
1032
- const sig = signal2;
1033
- const subs = sig[SUBS];
1034
- if (subs?.delete(subscriber)) {
1035
- syncFastPath(sig, subs);
1036
- }
1037
- }
1038
- deps.clear();
1039
- }
1040
1072
 
1041
1073
  // src/reactivity/bindAttribute.ts
1042
1074
  var _isDev3 = isDev();
@@ -1628,32 +1660,64 @@ init_dev();
1628
1660
  var _g = globalThis;
1629
1661
  var _isDev7 = isDev();
1630
1662
  function signal(initial, options) {
1631
- const state = { value: initial };
1663
+ const state = {
1664
+ value: initial,
1665
+ __v: 0,
1666
+ __sc: 0,
1667
+ subsHead: null,
1668
+ subsTail: null,
1669
+ __activeNode: null,
1670
+ __name: void 0
1671
+ };
1632
1672
  const debugName = _isDev7 ? options?.name : void 0;
1633
1673
  const equalsFn = options?.equals;
1634
- if (debugName) {
1635
- state.__name = debugName;
1636
- }
1674
+ if (debugName) state.__name = debugName;
1637
1675
  function get() {
1638
1676
  recordDependency(state);
1639
1677
  return state.value;
1640
1678
  }
1641
1679
  get.__signal = state;
1642
1680
  if (debugName) get.__name = debugName;
1643
- function set(next) {
1644
- const newValue = typeof next === "function" ? next(state.value) : next;
1645
- if (equalsFn ? equalsFn(state.value, newValue) : Object.is(newValue, state.value)) return;
1646
- if (_isDev7) {
1647
- const oldValue = state.value;
1681
+ let set;
1682
+ if (equalsFn) {
1683
+ set = (next) => {
1684
+ const prev = state.value;
1685
+ const newValue = typeof next === "function" ? next(prev) : next;
1686
+ if (equalsFn(prev, newValue)) return;
1648
1687
  state.value = newValue;
1688
+ state.__v++;
1689
+ if (_isDev7) {
1690
+ const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1691
+ if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
1692
+ }
1693
+ if (!enqueueBatchedSignal(state)) {
1694
+ notifySubscribers(state);
1695
+ }
1696
+ };
1697
+ } else if (_isDev7) {
1698
+ set = (next) => {
1699
+ const prev = state.value;
1700
+ const newValue = typeof next === "function" ? next(prev) : next;
1701
+ if (Object.is(newValue, prev)) return;
1702
+ state.value = newValue;
1703
+ state.__v++;
1649
1704
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1650
- if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue, newValue });
1651
- } else {
1705
+ if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
1706
+ if (!enqueueBatchedSignal(state)) {
1707
+ notifySubscribers(state);
1708
+ }
1709
+ };
1710
+ } else {
1711
+ set = (next) => {
1712
+ const prev = state.value;
1713
+ const newValue = typeof next === "function" ? next(prev) : next;
1714
+ if (Object.is(newValue, prev)) return;
1652
1715
  state.value = newValue;
1653
- }
1654
- if (!enqueueBatchedSignal(state)) {
1655
- notifySubscribers(state);
1656
- }
1716
+ state.__v++;
1717
+ if (!enqueueBatchedSignal(state)) {
1718
+ notifySubscribers(state);
1719
+ }
1720
+ };
1657
1721
  }
1658
1722
  if (_isDev7) {
1659
1723
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
@@ -1694,120 +1758,122 @@ function getAvailableLocales() {
1694
1758
  init_dev();
1695
1759
  init_ssr_context();
1696
1760
  var _g2 = globalThis;
1761
+ var MAX_RERUNS = 100;
1762
+ function flushUserCleanups(ctx) {
1763
+ const list = ctx.userCleanups;
1764
+ if (list.length === 0) return;
1765
+ ctx.userCleanups = [];
1766
+ for (let i2 = list.length - 1; i2 >= 0; i2--) {
1767
+ try {
1768
+ list[i2]();
1769
+ } catch (err) {
1770
+ if (typeof console !== "undefined") console.warn("[SibuJS effect] onCleanup threw:", err);
1771
+ }
1772
+ }
1773
+ }
1774
+ function drainReruns(ctx) {
1775
+ let reruns = 1;
1776
+ do {
1777
+ ctx.rerunPending = false;
1778
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
1779
+ retrack(ctx.bodyFn, ctx.subscriber);
1780
+ } while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
1781
+ if (ctx.rerunPending) {
1782
+ ctx.rerunPending = false;
1783
+ if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
1784
+ console.error(
1785
+ `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
1786
+ );
1787
+ }
1788
+ }
1789
+ }
1790
+ function disposeEffect(ctx) {
1791
+ if (ctx.disposed) return;
1792
+ ctx.disposed = true;
1793
+ const h = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1794
+ if (h) {
1795
+ try {
1796
+ h.emit("effect:destroy", { effectFn: ctx.fn });
1797
+ } catch {
1798
+ }
1799
+ }
1800
+ try {
1801
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
1802
+ } catch (err) {
1803
+ if (typeof console !== "undefined") {
1804
+ console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
1805
+ }
1806
+ }
1807
+ try {
1808
+ cleanup(ctx.subscriber);
1809
+ } catch (err) {
1810
+ if (typeof console !== "undefined") {
1811
+ console.warn("[SibuJS effect] dispose threw:", err);
1812
+ }
1813
+ }
1814
+ }
1697
1815
  function effect(effectFn, options) {
1698
1816
  devAssert(typeof effectFn === "function", "effect: argument must be a function.");
1699
1817
  if (isSSR()) return () => {
1700
1818
  };
1701
- const onError = options?.onError;
1702
- let userCleanups = [];
1703
- const onCleanup = (fn) => {
1704
- userCleanups.push(fn);
1819
+ const ctx = {
1820
+ fn: effectFn,
1821
+ onError: options?.onError,
1822
+ userCleanups: [],
1823
+ running: false,
1824
+ rerunPending: false,
1825
+ disposed: false,
1826
+ onCleanup: null,
1827
+ subscriber: null,
1828
+ bodyFn: null
1705
1829
  };
1706
- const runUserCleanups = () => {
1707
- if (userCleanups.length === 0) return;
1708
- const list = userCleanups;
1709
- userCleanups = [];
1710
- for (let i2 = list.length - 1; i2 >= 0; i2--) {
1711
- try {
1712
- list[i2]();
1713
- } catch (err) {
1714
- if (typeof console !== "undefined") {
1715
- console.warn("[SibuJS effect] onCleanup threw:", err);
1716
- }
1717
- }
1718
- }
1830
+ ctx.onCleanup = (fn) => {
1831
+ ctx.userCleanups.push(fn);
1719
1832
  };
1720
- const invokeBody = () => effectFn(onCleanup);
1721
- const wrappedFn = onError ? () => {
1833
+ const onErrorCaptured = ctx.onError;
1834
+ ctx.bodyFn = onErrorCaptured ? () => {
1722
1835
  try {
1723
- invokeBody();
1836
+ ctx.fn(ctx.onCleanup);
1724
1837
  } catch (err) {
1725
- onError(err);
1838
+ onErrorCaptured(err);
1726
1839
  }
1727
- } : invokeBody;
1728
- let cleanupHandle = () => {
1840
+ } : () => {
1841
+ ctx.fn(ctx.onCleanup);
1729
1842
  };
1730
- let running = false;
1731
- let rerunPending = false;
1732
- const MAX_RERUNS = 100;
1733
- const subscriber = () => {
1734
- if (running) {
1735
- rerunPending = true;
1843
+ const sub2 = (() => {
1844
+ if (ctx.running) {
1845
+ ctx.rerunPending = true;
1736
1846
  return;
1737
1847
  }
1738
- running = true;
1848
+ ctx.running = true;
1739
1849
  try {
1740
- let reruns = 0;
1741
- do {
1742
- rerunPending = false;
1743
- runUserCleanups();
1744
- cleanupHandle();
1745
- cleanupHandle = track(wrappedFn, subscriber);
1746
- if (++reruns > MAX_RERUNS) {
1747
- if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
1748
- console.error(
1749
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
1750
- );
1751
- }
1752
- rerunPending = false;
1753
- break;
1754
- }
1755
- } while (rerunPending);
1850
+ ctx.rerunPending = false;
1851
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
1852
+ retrack(ctx.bodyFn, sub2);
1853
+ if (ctx.rerunPending) drainReruns(ctx);
1756
1854
  } finally {
1757
- running = false;
1758
- rerunPending = false;
1855
+ ctx.running = false;
1856
+ ctx.rerunPending = false;
1759
1857
  }
1760
- };
1761
- running = true;
1858
+ });
1859
+ sub2.depsHead = null;
1860
+ sub2.depsTail = null;
1861
+ sub2._epoch = 0;
1862
+ sub2._structDirty = false;
1863
+ sub2._runEpoch = 0;
1864
+ sub2._runs = 0;
1865
+ ctx.subscriber = sub2;
1866
+ ctx.running = true;
1762
1867
  try {
1763
- let reruns = 0;
1764
- do {
1765
- rerunPending = false;
1766
- runUserCleanups();
1767
- cleanupHandle();
1768
- cleanupHandle = track(wrappedFn, subscriber);
1769
- if (++reruns > MAX_RERUNS) {
1770
- if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
1771
- console.error(
1772
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times on initial run \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
1773
- );
1774
- }
1775
- rerunPending = false;
1776
- break;
1777
- }
1778
- } while (rerunPending);
1868
+ retrack(ctx.bodyFn, ctx.subscriber);
1869
+ if (ctx.rerunPending) drainReruns(ctx);
1779
1870
  } finally {
1780
- running = false;
1781
- rerunPending = false;
1871
+ ctx.running = false;
1872
+ ctx.rerunPending = false;
1782
1873
  }
1783
1874
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1784
1875
  if (hook) hook.emit("effect:create", { effectFn });
1785
- let disposed = false;
1786
- return () => {
1787
- if (disposed) return;
1788
- disposed = true;
1789
- const h = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1790
- if (h) {
1791
- try {
1792
- h.emit("effect:destroy", { effectFn });
1793
- } catch {
1794
- }
1795
- }
1796
- try {
1797
- runUserCleanups();
1798
- } catch (err) {
1799
- if (typeof console !== "undefined") {
1800
- console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
1801
- }
1802
- }
1803
- try {
1804
- cleanupHandle();
1805
- } catch (err) {
1806
- if (typeof console !== "undefined") {
1807
- console.warn("[SibuJS effect] dispose threw:", err);
1808
- }
1809
- }
1810
- };
1876
+ return () => disposeEffect(ctx);
1811
1877
  }
1812
1878
 
1813
1879
  // src/plugins/router.ts