sibujs 3.4.0 → 4.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 (98) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +118 -15
  3. package/dist/browser.cjs +410 -101
  4. package/dist/browser.d.cts +50 -5
  5. package/dist/browser.d.ts +50 -5
  6. package/dist/browser.js +8 -6
  7. package/dist/build.cjs +777 -385
  8. package/dist/build.js +15 -15
  9. package/dist/cdn.global.js +11 -7
  10. package/dist/{chunk-JCO7AHNU.js → chunk-3EKJK5FZ.js} +73 -34
  11. package/dist/chunk-4MFZMLUU.js +147 -0
  12. package/dist/chunk-52XFPGSN.js +123 -0
  13. package/dist/chunk-5INI7D2L.js +194 -0
  14. package/dist/{chunk-OAVXAFAY.js → chunk-6LG2T7LO.js} +5 -5
  15. package/dist/{chunk-OOUQUCNN.js → chunk-ACBT6UZS.js} +57 -22
  16. package/dist/{chunk-F7HW2NI5.js → chunk-AW6HPJ3L.js} +1 -1
  17. package/dist/chunk-DHDZ7IVN.js +109 -0
  18. package/dist/{chunk-JNGGM2XE.js → chunk-DQVUBVNX.js} +16 -25
  19. package/dist/{chunk-AXFWGY32.js → chunk-DR7H6UGM.js} +232 -67
  20. package/dist/{chunk-WSGLJYFI.js → chunk-E62UADKL.js} +9 -3
  21. package/dist/{chunk-3Z2NGWQI.js → chunk-ES2GERY2.js} +1 -1
  22. package/dist/{chunk-S3V6ZXPI.js → chunk-EWEE7NBF.js} +115 -41
  23. package/dist/{chunk-3DVGCW7O.js → chunk-F64ZPCFE.js} +8 -8
  24. package/dist/{chunk-APFRCIRI.js → chunk-GCSGGA3Q.js} +295 -198
  25. package/dist/{chunk-EX77FXTT.js → chunk-HYCCIYNS.js} +228 -51
  26. package/dist/{chunk-ELXMRSVN.js → chunk-NF3LYCQH.js} +259 -124
  27. package/dist/chunk-O3QQ3XOL.js +61 -0
  28. package/dist/{chunk-BUKYCWHX.js → chunk-PBQEW5VW.js} +14 -10
  29. package/dist/{chunk-H5FI5WDP.js → chunk-RRIDJQ5C.js} +3 -3
  30. package/dist/{chunk-S3NFJO6L.js → chunk-TIRZCERI.js} +36 -5
  31. package/dist/{chunk-ODXVQ3CS.js → chunk-VFHIVEPF.js} +309 -188
  32. package/dist/chunk-VPP2FONR.js +142 -0
  33. package/dist/{chunk-KZBEVFXZ.js → chunk-W55YHPEP.js} +5 -3
  34. package/dist/{chunk-FKQG7FTY.js → chunk-WN6WDFCB.js} +4 -4
  35. package/dist/{chunk-CEBWDD63.js → chunk-WOOMUJFT.js} +228 -86
  36. package/dist/{chunk-ITWCTZYH.js → chunk-Z2CE42DB.js} +19 -25
  37. package/dist/{contracts-ey_Qh8ef.d.cts → contracts-Hg6ITAEF.d.cts} +6 -6
  38. package/dist/{contracts-ey_Qh8ef.d.ts → contracts-Hg6ITAEF.d.ts} +6 -6
  39. package/dist/{customElement-CPfIrbvg.d.ts → customElement-CKLoO63w.d.cts} +73 -11
  40. package/dist/{customElement-CPfIrbvg.d.cts → customElement-CKLoO63w.d.ts} +73 -11
  41. package/dist/data.cjs +483 -205
  42. package/dist/data.d.cts +139 -7
  43. package/dist/data.d.ts +139 -7
  44. package/dist/data.js +9 -9
  45. package/dist/devtools.cjs +222 -87
  46. package/dist/devtools.js +8 -8
  47. package/dist/dispose-4FZ6OFXR.js +19 -0
  48. package/dist/ecosystem.cjs +419 -175
  49. package/dist/ecosystem.js +11 -11
  50. package/dist/extras.cjs +1981 -765
  51. package/dist/extras.d.cts +7 -7
  52. package/dist/extras.d.ts +7 -7
  53. package/dist/extras.js +29 -26
  54. package/dist/index.cjs +784 -385
  55. package/dist/index.d.cts +299 -28
  56. package/dist/index.d.ts +299 -28
  57. package/dist/index.js +33 -18
  58. package/dist/motion.cjs +180 -50
  59. package/dist/motion.d.cts +26 -0
  60. package/dist/motion.d.ts +26 -0
  61. package/dist/motion.js +5 -5
  62. package/dist/patterns.cjs +437 -170
  63. package/dist/patterns.d.cts +60 -13
  64. package/dist/patterns.d.ts +60 -13
  65. package/dist/patterns.js +7 -7
  66. package/dist/performance.cjs +333 -148
  67. package/dist/performance.d.cts +55 -7
  68. package/dist/performance.d.ts +55 -7
  69. package/dist/performance.js +9 -9
  70. package/dist/plugins.cjs +1374 -576
  71. package/dist/plugins.d.cts +227 -9
  72. package/dist/plugins.d.ts +227 -9
  73. package/dist/plugins.js +613 -321
  74. package/dist/{ssr-D62yFwuw.d.cts → ssr-BiPRdZ6n.d.cts} +44 -15
  75. package/dist/{ssr-D62yFwuw.d.ts → ssr-BiPRdZ6n.d.ts} +44 -15
  76. package/dist/{ssr-2PPULEK2.js → ssr-JFP5535P.js} +5 -4
  77. package/dist/ssr.cjs +1104 -443
  78. package/dist/ssr.d.cts +230 -20
  79. package/dist/ssr.d.ts +230 -20
  80. package/dist/ssr.js +15 -12
  81. package/dist/{startup-0Qv6aosO.d.cts → startup-BMpaiMhP.d.cts} +1 -1
  82. package/dist/{startup-0Qv6aosO.d.ts → startup-BMpaiMhP.d.ts} +1 -1
  83. package/dist/testing.cjs +205 -63
  84. package/dist/testing.d.cts +1 -1
  85. package/dist/testing.d.ts +1 -1
  86. package/dist/testing.js +8 -10
  87. package/dist/ui.cjs +640 -199
  88. package/dist/ui.d.cts +2 -2
  89. package/dist/ui.d.ts +2 -2
  90. package/dist/ui.js +10 -10
  91. package/dist/widgets.cjs +207 -82
  92. package/dist/widgets.js +9 -9
  93. package/package.json +12 -7
  94. package/dist/chunk-5VGSK6D2.js +0 -80
  95. package/dist/chunk-COY6PUD2.js +0 -34
  96. package/dist/chunk-K35BAR4P.js +0 -96
  97. package/dist/chunk-L3GAGWCC.js +0 -111
  98. package/dist/chunk-RT3IYFN2.js +0 -38
package/dist/testing.cjs CHANGED
@@ -88,8 +88,104 @@ function devWarn(message) {
88
88
  }
89
89
  }
90
90
 
91
+ // src/core/errors.ts
92
+ var ERROR_STATE_KEY = /* @__PURE__ */ Symbol.for("sibujs.runtime-errors.v1");
93
+ function state() {
94
+ const g = globalThis;
95
+ const existing = g[ERROR_STATE_KEY];
96
+ if (existing) return existing;
97
+ const created = { handler: null, handlerDepth: 0 };
98
+ g[ERROR_STATE_KEY] = created;
99
+ return created;
100
+ }
101
+ function normalizeError(value) {
102
+ if (value instanceof Error) return value;
103
+ const message = typeof value === "string" ? value : `Non-Error value thrown: ${safeStringify(value)}`;
104
+ return new Error(message, { cause: value });
105
+ }
106
+ function safeStringify(value) {
107
+ if (typeof value === "symbol") return value.toString();
108
+ try {
109
+ return typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
110
+ } catch {
111
+ return Object.prototype.toString.call(value);
112
+ }
113
+ }
114
+ function describe(context) {
115
+ return context.name ? `${context.phase} "${context.name}"` : context.phase;
116
+ }
117
+ var REACTIVE_REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
118
+ function untrackedRun(fn) {
119
+ const api = globalThis[REACTIVE_REGISTRY_KEY];
120
+ return api?.untracked ? api.untracked(fn) : fn();
121
+ }
122
+ var PROPAGATE_EVENT = "sibu:error-propagate";
123
+ function claimedByBoundary(error, context) {
124
+ const raw = context.node;
125
+ if (!raw || typeof CustomEvent === "undefined") return false;
126
+ const target = resolveEventTarget(raw);
127
+ if (!target) return false;
128
+ try {
129
+ const event = new CustomEvent(PROPAGATE_EVENT, {
130
+ bubbles: true,
131
+ cancelable: true,
132
+ detail: { error, context }
133
+ });
134
+ return target.dispatchEvent(event) === false;
135
+ } catch {
136
+ return false;
137
+ }
138
+ }
139
+ function resolveEventTarget(node) {
140
+ const ELEMENT_NODE = 1;
141
+ let current = node;
142
+ while (current) {
143
+ if (current.nodeType === ELEMENT_NODE && typeof current.dispatchEvent === "function") {
144
+ return current;
145
+ }
146
+ current = current.parentNode;
147
+ }
148
+ const self = node;
149
+ return typeof self.dispatchEvent === "function" ? self : null;
150
+ }
151
+ function defaultReport(error, context) {
152
+ if (typeof console === "undefined") return;
153
+ console.error(`[SibuJS] Uncaught error during ${describe(context)}: ${error.message}`, error);
154
+ }
155
+ function reportError(error, context) {
156
+ const err = normalizeError(error);
157
+ untrackedRun(() => {
158
+ if (claimedByBoundary(err, context)) return;
159
+ const s = state();
160
+ const handler = s.handler;
161
+ if (handler && s.handlerDepth === 0) {
162
+ s.handlerDepth++;
163
+ try {
164
+ handler(error instanceof Error ? error : err, context);
165
+ return;
166
+ } catch (handlerError) {
167
+ if (typeof console !== "undefined") {
168
+ const detail = handlerError instanceof Error ? handlerError.message : String(handlerError);
169
+ console.error(`[SibuJS] runtime error handler itself threw: ${detail}`, handlerError);
170
+ }
171
+ } finally {
172
+ s.handlerDepth--;
173
+ }
174
+ }
175
+ defaultReport(err, context);
176
+ });
177
+ }
178
+
91
179
  // src/core/rendering/dispose.ts
92
180
  var elementDisposers = /* @__PURE__ */ new WeakMap();
181
+ var MAX_DRAIN_TEARDOWNS = 1e4;
182
+ function reportDrainRunaway(label, executed, remaining) {
183
+ if (typeof console === "undefined") return;
184
+ console.error(
185
+ `[SibuJS ${label}] runaway cleanup: stopped after running ${executed} teardowns with ${remaining} still queued. Cleanup production did not stabilize before the teardown safety ceiling was reached \u2014 the remaining work was NOT run.`,
186
+ { executed, remaining }
187
+ );
188
+ }
93
189
  var _isDev2 = isDev();
94
190
  var activeBindingCount = 0;
95
191
  function dispose(node) {
@@ -105,40 +201,47 @@ function dispose(node) {
105
201
  }
106
202
  for (let i = order.length - 1; i >= 0; i--) {
107
203
  const current = order[i];
108
- const disposers = elementDisposers.get(current);
109
- if (disposers) {
110
- const snapshot = disposers.slice();
111
- elementDisposers.delete(current);
112
- if (_isDev2) activeBindingCount -= snapshot.length;
113
- for (const d of snapshot) {
114
- try {
115
- d();
116
- } catch (err) {
117
- if (_isDev2 && typeof console !== "undefined") {
118
- console.warn("[SibuJS] Disposer threw during cleanup:", err);
119
- }
120
- }
121
- }
122
- let extraPasses = 0;
123
- while (extraPasses++ < 8) {
124
- const added = elementDisposers.get(current);
125
- if (!added || added.length === 0) break;
126
- const moreSnapshot = added.slice();
204
+ if (elementDisposers.has(current)) {
205
+ let executed = 0;
206
+ let runaway = false;
207
+ while (!runaway) {
208
+ const pending = elementDisposers.get(current);
209
+ if (!pending || pending.length === 0) break;
210
+ const snapshot = pending.slice();
127
211
  elementDisposers.delete(current);
128
- if (_isDev2) activeBindingCount -= moreSnapshot.length;
129
- for (const d of moreSnapshot) {
212
+ if (_isDev2) activeBindingCount -= snapshot.length;
213
+ for (let i2 = 0; i2 < snapshot.length; i2++) {
214
+ if (executed >= MAX_DRAIN_TEARDOWNS) {
215
+ const rest = snapshot.slice(i2);
216
+ const added = elementDisposers.get(current);
217
+ elementDisposers.set(current, added ? rest.concat(added) : rest);
218
+ if (_isDev2) activeBindingCount += rest.length;
219
+ reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
220
+ runaway = true;
221
+ break;
222
+ }
223
+ executed++;
130
224
  try {
131
- d();
225
+ snapshot[i2]();
132
226
  } catch (err) {
133
- if (_isDev2 && typeof console !== "undefined") {
134
- console.warn("[SibuJS] Disposer threw during cleanup:", err);
135
- }
227
+ reportError(err, { phase: "cleanup", name: "disposer" });
136
228
  }
137
229
  }
138
230
  }
139
231
  }
140
232
  }
141
233
  }
234
+ function replaceChildrenSafely(parent, ...next) {
235
+ for (let i = 0; i < next.length; i++) {
236
+ const node = next[i];
237
+ node.parentNode?.removeChild(node);
238
+ }
239
+ const current = Array.from(parent.childNodes);
240
+ for (let i = 0; i < current.length; i++) {
241
+ dispose(current[i]);
242
+ }
243
+ parent.replaceChildren(...next);
244
+ }
142
245
 
143
246
  // src/utils/globalSingleton.ts
144
247
  function globalSingleton(key, create) {
@@ -1579,7 +1682,6 @@ function testComponent(component, options = {}) {
1579
1682
  }
1580
1683
 
1581
1684
  // src/reactivity/track-core.ts
1582
- var _isDev3 = isDev();
1583
1685
  var POOL_MAX = 4096;
1584
1686
  var nodePool = [];
1585
1687
  function createNode() {
@@ -1587,6 +1689,7 @@ function createNode() {
1587
1689
  sig: null,
1588
1690
  sub: null,
1589
1691
  epoch: 0,
1692
+ depVersion: 0,
1590
1693
  sigPrev: null,
1591
1694
  sigNext: null,
1592
1695
  subPrev: null,
@@ -1671,9 +1774,28 @@ function safeInvoke(sub) {
1671
1774
  try {
1672
1775
  sub();
1673
1776
  } catch (err) {
1674
- if (_isDev3) devWarn(`Subscriber threw during notification: ${err instanceof Error ? err.message : String(err)}`);
1777
+ const s = sub;
1778
+ reportError(err, { phase: s._errorPhase ?? "effect", name: s.__name, node: s._errorNode });
1675
1779
  }
1676
1780
  }
1781
+ function depsChanged(sub) {
1782
+ let node = sub.depsHead ?? null;
1783
+ if (node === null) return true;
1784
+ while (node !== null) {
1785
+ const sig = node.sig;
1786
+ if (sig === null) return true;
1787
+ if (sig._d === true && sig._validate !== void 0) {
1788
+ try {
1789
+ sig._validate();
1790
+ } catch {
1791
+ return true;
1792
+ }
1793
+ }
1794
+ if (node.depVersion !== sig.__v) return true;
1795
+ node = node.subNext;
1796
+ }
1797
+ return false;
1798
+ }
1677
1799
  var suspendDepth = 0;
1678
1800
  var trackingSuspended = false;
1679
1801
  function suspendTracking() {
@@ -1754,7 +1876,7 @@ function track(effectFn, subscriber) {
1754
1876
  const sub = subscriber;
1755
1877
  return sub._dispose ?? (sub._dispose = () => cleanup(subscriber));
1756
1878
  }
1757
- function reactiveBinding(commit) {
1879
+ function reactiveBinding(commit, ownerNode) {
1758
1880
  const run = () => {
1759
1881
  const s = subscriber;
1760
1882
  if (s._disposed || s._reentrant) return;
@@ -1770,13 +1892,17 @@ function reactiveBinding(commit) {
1770
1892
  subscriber.depsTail = null;
1771
1893
  subscriber._epoch = 0;
1772
1894
  subscriber._structDirty = false;
1895
+ subscriber._hasComputedDep = false;
1773
1896
  subscriber._runEpoch = 0;
1774
1897
  subscriber._runs = 0;
1775
1898
  subscriber._reentrant = false;
1776
1899
  subscriber._disposed = false;
1900
+ subscriber._errorPhase = "binding";
1901
+ subscriber._errorNode = ownerNode;
1777
1902
  run();
1778
1903
  return subscriber._dispose ?? (subscriber._dispose = () => {
1779
1904
  subscriber._disposed = true;
1905
+ subscriber._errorNode = void 0;
1780
1906
  cleanup(subscriber);
1781
1907
  });
1782
1908
  }
@@ -1788,9 +1914,12 @@ function recordDependency(signal) {
1788
1914
  const active = sig.__activeNode ?? null;
1789
1915
  if (active !== null && active.sub === sub) {
1790
1916
  active.epoch = epoch;
1917
+ active.depVersion = sig.__v ?? Number.NaN;
1791
1918
  return;
1792
1919
  }
1920
+ if (sig._validate !== void 0) sub._hasComputedDep = true;
1793
1921
  const node = allocNode(signal, sub, epoch);
1922
+ node.depVersion = sig.__v ?? Number.NaN;
1794
1923
  node.prevActive = active;
1795
1924
  sig.__activeNode = node;
1796
1925
  linkSub(sub, node);
@@ -1809,9 +1938,10 @@ function cleanup(subscriber) {
1809
1938
  node = next;
1810
1939
  }
1811
1940
  }
1812
- var maxSubscriberRepeats = 50;
1941
+ var maxSubscriberRepeats = 1e3;
1813
1942
  var maxDrainIterations = 1e6;
1814
1943
  var drainEpoch = 0;
1944
+ var quarantined = /* @__PURE__ */ new Set();
1815
1945
  function setMaxSubscriberRepeats(n) {
1816
1946
  const prev = maxSubscriberRepeats;
1817
1947
  if (Number.isFinite(n) && n > 0) maxSubscriberRepeats = Math.floor(n);
@@ -1833,19 +1963,21 @@ function tickRepeat(sub) {
1833
1963
  return s._runs > maxSubscriberRepeats;
1834
1964
  }
1835
1965
  function cycleError(sub) {
1836
- if (typeof console !== "undefined") {
1837
- const name = sub.__name ?? "<unnamed>";
1838
- console.error(
1839
- `[SibuJS] subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. Breaking to prevent infinite loop.`
1840
- );
1841
- }
1966
+ const name = sub.__name ?? "<unnamed>";
1967
+ reportError(
1968
+ new Error(
1969
+ `subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. This subscriber is quarantined for the rest of this update; other pending work still runs.`
1970
+ ),
1971
+ { phase: "scheduler", name }
1972
+ );
1842
1973
  }
1843
1974
  function absoluteDrainError() {
1844
- if (typeof console !== "undefined") {
1845
- console.error(
1846
- `[SibuJS] Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
1847
- );
1848
- }
1975
+ reportError(
1976
+ new Error(
1977
+ `Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
1978
+ ),
1979
+ { phase: "scheduler" }
1980
+ );
1849
1981
  }
1850
1982
  function drainQueue() {
1851
1983
  let i = 0;
@@ -1855,11 +1987,14 @@ function drainQueue() {
1855
1987
  break;
1856
1988
  }
1857
1989
  const sub = pendingQueue[i++];
1990
+ pendingSet.delete(sub);
1991
+ if (quarantined.size > 0 && quarantined.has(sub)) continue;
1992
+ if (sub._hasComputedDep === true && !depsChanged(sub)) continue;
1858
1993
  if (tickRepeat(sub)) {
1859
1994
  cycleError(sub);
1860
- break;
1995
+ quarantined.add(sub);
1996
+ continue;
1861
1997
  }
1862
- pendingSet.delete(sub);
1863
1998
  safeInvoke(sub);
1864
1999
  }
1865
2000
  }
@@ -1874,6 +2009,7 @@ function drainNotificationQueue() {
1874
2009
  if (notifyDepth === 0) {
1875
2010
  pendingQueue.length = 0;
1876
2011
  pendingSet.clear();
2012
+ if (quarantined.size > 0) quarantined.clear();
1877
2013
  }
1878
2014
  }
1879
2015
  }
@@ -1967,6 +2103,7 @@ function notifySubscribers(signal) {
1967
2103
  if (notifyDepth === 0) {
1968
2104
  pendingQueue.length = 0;
1969
2105
  pendingSet.clear();
2106
+ if (quarantined.size > 0) quarantined.clear();
1970
2107
  }
1971
2108
  }
1972
2109
  }
@@ -1993,14 +2130,14 @@ function forEachSubscriber(signal, visit) {
1993
2130
  }
1994
2131
 
1995
2132
  // src/reactivity/track.ts
1996
- var _isDev4 = isDev();
1997
- var _runtimeVersion = true ? "3.4.0" : "dev";
2133
+ var _isDev3 = isDev();
2134
+ var _runtimeVersion = true ? "4.0.0" : "dev";
1998
2135
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
1999
2136
  function resolveReactiveApi() {
2000
2137
  const g = globalThis;
2001
2138
  const existing = g[REGISTRY_KEY];
2002
2139
  if (existing) {
2003
- if (_isDev4 && !existing.__dupWarned) {
2140
+ if (_isDev3 && !existing.__dupWarned) {
2004
2141
  existing.__dupWarned = true;
2005
2142
  devWarn(
2006
2143
  `Multiple instances of the reactive runtime detected on this page (active: ${existing.version}, duplicate: ${_runtimeVersion}). Reactivity still works \u2014 all copies share the first one \u2014 but de-duplicate sibujs in your bundler (e.g. Vite optimizeDeps.exclude: ['sibujs'] or resolve.dedupe: ['sibujs']).`
@@ -2060,20 +2197,24 @@ function detectSSRShared() {
2060
2197
  const getBuiltin = process.getBuiltinModule;
2061
2198
  if (typeof getBuiltin === "function") {
2062
2199
  mod = getBuiltin("node:async_hooks");
2063
- } else {
2064
- const req = Function("return typeof require==='function'?require:null")();
2065
- if (req) mod = req("node:async_hooks");
2200
+ } else if (typeof require === "function") {
2201
+ mod = require("async_hooks");
2066
2202
  }
2067
2203
  if (mod) detected = new mod.AsyncLocalStorage();
2068
2204
  }
2069
2205
  } catch {
2070
2206
  detected = null;
2071
2207
  }
2072
- return { als: detected, fallbackStore: { ssr: false, suspenseIdCounter: 0 } };
2208
+ return {
2209
+ als: detected,
2210
+ fallbackStore: { ssr: false, suspenseIdCounter: 0, locale: void 0 },
2211
+ fallbackDepth: 0
2212
+ };
2073
2213
  }
2074
2214
  var _shared = globalThis[SSR_KEY] ?? (globalThis[SSR_KEY] = detectSSRShared());
2075
2215
  var als = _shared.als;
2076
2216
  var fallbackStore = _shared.fallbackStore;
2217
+ _shared.fallbackDepth ?? (_shared.fallbackDepth = 0);
2077
2218
  function getSSRStore() {
2078
2219
  if (als) {
2079
2220
  const s = als.getStore();
@@ -2096,7 +2237,7 @@ function flushUserCleanups(ctx) {
2096
2237
  try {
2097
2238
  list[i]();
2098
2239
  } catch (err) {
2099
- if (typeof console !== "undefined") console.warn("[SibuJS effect] onCleanup threw:", err);
2240
+ reportError(err, { phase: "cleanup" });
2100
2241
  }
2101
2242
  }
2102
2243
  }
@@ -2109,11 +2250,12 @@ function drainReruns(ctx) {
2109
2250
  } while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
2110
2251
  if (ctx.rerunPending) {
2111
2252
  ctx.rerunPending = false;
2112
- if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
2113
- console.error(
2114
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
2115
- );
2116
- }
2253
+ reportError(
2254
+ new Error(
2255
+ `effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
2256
+ ),
2257
+ { phase: "effect" }
2258
+ );
2117
2259
  }
2118
2260
  }
2119
2261
  function disposeEffect(ctx) {
@@ -2190,6 +2332,8 @@ function effect(effectFn, options) {
2190
2332
  sub.depsTail = null;
2191
2333
  sub._epoch = 0;
2192
2334
  sub._structDirty = false;
2335
+ sub._hasComputedDep = false;
2336
+ sub._errorPhase = "effect";
2193
2337
  sub._runEpoch = 0;
2194
2338
  sub._runs = 0;
2195
2339
  ctx.subscriber = sub;
@@ -2671,8 +2815,7 @@ function escapeSelector(value) {
2671
2815
  var _renderedContainers = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.testing.containers.v1"), () => /* @__PURE__ */ new Set());
2672
2816
  function unmountAll() {
2673
2817
  for (const container of _renderedContainers) {
2674
- for (const child of Array.from(container.childNodes)) dispose(child);
2675
- container.replaceChildren();
2818
+ replaceChildrenSafely(container);
2676
2819
  if (container.parentNode) container.parentNode.removeChild(container);
2677
2820
  }
2678
2821
  _renderedContainers.clear();
@@ -2706,8 +2849,7 @@ function render(component) {
2706
2849
  return Array.from(container.querySelectorAll(selector));
2707
2850
  }
2708
2851
  function unmount() {
2709
- for (const child of Array.from(container.childNodes)) dispose(child);
2710
- container.replaceChildren();
2852
+ replaceChildrenSafely(container);
2711
2853
  if (container.parentNode) container.parentNode.removeChild(container);
2712
2854
  _renderedContainers.delete(container);
2713
2855
  }
@@ -2767,14 +2909,14 @@ function mockRouter(initialPath = "/") {
2767
2909
  return { currentPath, navigate, history };
2768
2910
  }
2769
2911
  function mockStore(initialState) {
2770
- let state = { ...initialState };
2912
+ let state2 = { ...initialState };
2771
2913
  return {
2772
- getState: () => ({ ...state }),
2914
+ getState: () => ({ ...state2 }),
2773
2915
  setState: (patch) => {
2774
- state = { ...state, ...patch };
2916
+ state2 = { ...state2, ...patch };
2775
2917
  },
2776
2918
  reset: () => {
2777
- state = { ...initialState };
2919
+ state2 = { ...initialState };
2778
2920
  }
2779
2921
  };
2780
2922
  }
@@ -536,7 +536,7 @@ declare function mockRouter(initialPath?: string): {
536
536
  /**
537
537
  * Creates a mock store for testing.
538
538
  */
539
- declare function mockStore<T extends Record<string, unknown>>(initialState: T): {
539
+ declare function mockStore<T extends object>(initialState: T): {
540
540
  getState: () => T;
541
541
  setState: (patch: Partial<T>) => void;
542
542
  reset: () => void;
package/dist/testing.d.ts CHANGED
@@ -536,7 +536,7 @@ declare function mockRouter(initialPath?: string): {
536
536
  /**
537
537
  * Creates a mock store for testing.
538
538
  */
539
- declare function mockStore<T extends Record<string, unknown>>(initialState: T): {
539
+ declare function mockStore<T extends object>(initialState: T): {
540
540
  getState: () => T;
541
541
  setState: (patch: Partial<T>) => void;
542
542
  reset: () => void;
package/dist/testing.js CHANGED
@@ -3,13 +3,13 @@ import {
3
3
  } from "./chunk-7ZHH77QA.js";
4
4
  import {
5
5
  effect
6
- } from "./chunk-BUKYCWHX.js";
7
- import "./chunk-S3NFJO6L.js";
6
+ } from "./chunk-PBQEW5VW.js";
7
+ import "./chunk-TIRZCERI.js";
8
8
  import {
9
- dispose
10
- } from "./chunk-5VGSK6D2.js";
11
- import "./chunk-OOUQUCNN.js";
12
- import "./chunk-COY6PUD2.js";
9
+ replaceChildrenSafely
10
+ } from "./chunk-DHDZ7IVN.js";
11
+ import "./chunk-ACBT6UZS.js";
12
+ import "./chunk-VPP2FONR.js";
13
13
 
14
14
  // src/testing/a11y.ts
15
15
  function escSel(value) {
@@ -1908,8 +1908,7 @@ function escapeSelector(value) {
1908
1908
  var _renderedContainers = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.testing.containers.v1"), () => /* @__PURE__ */ new Set());
1909
1909
  function unmountAll() {
1910
1910
  for (const container of _renderedContainers) {
1911
- for (const child of Array.from(container.childNodes)) dispose(child);
1912
- container.replaceChildren();
1911
+ replaceChildrenSafely(container);
1913
1912
  if (container.parentNode) container.parentNode.removeChild(container);
1914
1913
  }
1915
1914
  _renderedContainers.clear();
@@ -1943,8 +1942,7 @@ function render(component) {
1943
1942
  return Array.from(container.querySelectorAll(selector));
1944
1943
  }
1945
1944
  function unmount() {
1946
- for (const child of Array.from(container.childNodes)) dispose(child);
1947
- container.replaceChildren();
1945
+ replaceChildrenSafely(container);
1948
1946
  if (container.parentNode) container.parentNode.removeChild(container);
1949
1947
  _renderedContainers.delete(container);
1950
1948
  }