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/devtools.cjs CHANGED
@@ -193,8 +193,95 @@ function devWarn(message) {
193
193
  }
194
194
  }
195
195
 
196
+ // src/core/errors.ts
197
+ var ERROR_STATE_KEY = /* @__PURE__ */ Symbol.for("sibujs.runtime-errors.v1");
198
+ function state() {
199
+ const g = globalThis;
200
+ const existing = g[ERROR_STATE_KEY];
201
+ if (existing) return existing;
202
+ const created = { handler: null, handlerDepth: 0 };
203
+ g[ERROR_STATE_KEY] = created;
204
+ return created;
205
+ }
206
+ function normalizeError(value) {
207
+ if (value instanceof Error) return value;
208
+ const message = typeof value === "string" ? value : `Non-Error value thrown: ${safeStringify(value)}`;
209
+ return new Error(message, { cause: value });
210
+ }
211
+ function safeStringify(value) {
212
+ if (typeof value === "symbol") return value.toString();
213
+ try {
214
+ return typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
215
+ } catch {
216
+ return Object.prototype.toString.call(value);
217
+ }
218
+ }
219
+ function describe(context) {
220
+ return context.name ? `${context.phase} "${context.name}"` : context.phase;
221
+ }
222
+ var REACTIVE_REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
223
+ function untrackedRun(fn) {
224
+ const api = globalThis[REACTIVE_REGISTRY_KEY];
225
+ return api?.untracked ? api.untracked(fn) : fn();
226
+ }
227
+ var PROPAGATE_EVENT = "sibu:error-propagate";
228
+ function claimedByBoundary(error, context) {
229
+ const raw = context.node;
230
+ if (!raw || typeof CustomEvent === "undefined") return false;
231
+ const target = resolveEventTarget(raw);
232
+ if (!target) return false;
233
+ try {
234
+ const event = new CustomEvent(PROPAGATE_EVENT, {
235
+ bubbles: true,
236
+ cancelable: true,
237
+ detail: { error, context }
238
+ });
239
+ return target.dispatchEvent(event) === false;
240
+ } catch {
241
+ return false;
242
+ }
243
+ }
244
+ function resolveEventTarget(node) {
245
+ const ELEMENT_NODE = 1;
246
+ let current = node;
247
+ while (current) {
248
+ if (current.nodeType === ELEMENT_NODE && typeof current.dispatchEvent === "function") {
249
+ return current;
250
+ }
251
+ current = current.parentNode;
252
+ }
253
+ const self = node;
254
+ return typeof self.dispatchEvent === "function" ? self : null;
255
+ }
256
+ function defaultReport(error, context) {
257
+ if (typeof console === "undefined") return;
258
+ console.error(`[SibuJS] Uncaught error during ${describe(context)}: ${error.message}`, error);
259
+ }
260
+ function reportError(error, context) {
261
+ const err = normalizeError(error);
262
+ untrackedRun(() => {
263
+ if (claimedByBoundary(err, context)) return;
264
+ const s = state();
265
+ const handler = s.handler;
266
+ if (handler && s.handlerDepth === 0) {
267
+ s.handlerDepth++;
268
+ try {
269
+ handler(error instanceof Error ? error : err, context);
270
+ return;
271
+ } catch (handlerError) {
272
+ if (typeof console !== "undefined") {
273
+ const detail = handlerError instanceof Error ? handlerError.message : String(handlerError);
274
+ console.error(`[SibuJS] runtime error handler itself threw: ${detail}`, handlerError);
275
+ }
276
+ } finally {
277
+ s.handlerDepth--;
278
+ }
279
+ }
280
+ defaultReport(err, context);
281
+ });
282
+ }
283
+
196
284
  // src/reactivity/track-core.ts
197
- var _isDev2 = isDev();
198
285
  var POOL_MAX = 4096;
199
286
  var nodePool = [];
200
287
  function createNode() {
@@ -202,6 +289,7 @@ function createNode() {
202
289
  sig: null,
203
290
  sub: null,
204
291
  epoch: 0,
292
+ depVersion: 0,
205
293
  sigPrev: null,
206
294
  sigNext: null,
207
295
  subPrev: null,
@@ -286,8 +374,27 @@ function safeInvoke(sub) {
286
374
  try {
287
375
  sub();
288
376
  } catch (err) {
289
- if (_isDev2) devWarn(`Subscriber threw during notification: ${err instanceof Error ? err.message : String(err)}`);
377
+ const s = sub;
378
+ reportError(err, { phase: s._errorPhase ?? "effect", name: s.__name, node: s._errorNode });
379
+ }
380
+ }
381
+ function depsChanged(sub) {
382
+ let node = sub.depsHead ?? null;
383
+ if (node === null) return true;
384
+ while (node !== null) {
385
+ const sig = node.sig;
386
+ if (sig === null) return true;
387
+ if (sig._d === true && sig._validate !== void 0) {
388
+ try {
389
+ sig._validate();
390
+ } catch {
391
+ return true;
392
+ }
393
+ }
394
+ if (node.depVersion !== sig.__v) return true;
395
+ node = node.subNext;
290
396
  }
397
+ return false;
291
398
  }
292
399
  var suspendDepth = 0;
293
400
  var trackingSuspended = false;
@@ -369,7 +476,7 @@ function track(effectFn, subscriber) {
369
476
  const sub = subscriber;
370
477
  return sub._dispose ?? (sub._dispose = () => cleanup(subscriber));
371
478
  }
372
- function reactiveBinding(commit) {
479
+ function reactiveBinding(commit, ownerNode) {
373
480
  const run = () => {
374
481
  const s = subscriber;
375
482
  if (s._disposed || s._reentrant) return;
@@ -385,13 +492,17 @@ function reactiveBinding(commit) {
385
492
  subscriber.depsTail = null;
386
493
  subscriber._epoch = 0;
387
494
  subscriber._structDirty = false;
495
+ subscriber._hasComputedDep = false;
388
496
  subscriber._runEpoch = 0;
389
497
  subscriber._runs = 0;
390
498
  subscriber._reentrant = false;
391
499
  subscriber._disposed = false;
500
+ subscriber._errorPhase = "binding";
501
+ subscriber._errorNode = ownerNode;
392
502
  run();
393
503
  return subscriber._dispose ?? (subscriber._dispose = () => {
394
504
  subscriber._disposed = true;
505
+ subscriber._errorNode = void 0;
395
506
  cleanup(subscriber);
396
507
  });
397
508
  }
@@ -403,9 +514,12 @@ function recordDependency(signal2) {
403
514
  const active = sig.__activeNode ?? null;
404
515
  if (active !== null && active.sub === sub) {
405
516
  active.epoch = epoch;
517
+ active.depVersion = sig.__v ?? Number.NaN;
406
518
  return;
407
519
  }
520
+ if (sig._validate !== void 0) sub._hasComputedDep = true;
408
521
  const node = allocNode(signal2, sub, epoch);
522
+ node.depVersion = sig.__v ?? Number.NaN;
409
523
  node.prevActive = active;
410
524
  sig.__activeNode = node;
411
525
  linkSub(sub, node);
@@ -424,9 +538,10 @@ function cleanup(subscriber) {
424
538
  node = next;
425
539
  }
426
540
  }
427
- var maxSubscriberRepeats = 50;
541
+ var maxSubscriberRepeats = 1e3;
428
542
  var maxDrainIterations = 1e6;
429
543
  var drainEpoch = 0;
544
+ var quarantined = /* @__PURE__ */ new Set();
430
545
  function setMaxSubscriberRepeats(n) {
431
546
  const prev = maxSubscriberRepeats;
432
547
  if (Number.isFinite(n) && n > 0) maxSubscriberRepeats = Math.floor(n);
@@ -448,19 +563,21 @@ function tickRepeat(sub) {
448
563
  return s._runs > maxSubscriberRepeats;
449
564
  }
450
565
  function cycleError(sub) {
451
- if (typeof console !== "undefined") {
452
- const name = sub.__name ?? "<unnamed>";
453
- console.error(
454
- `[SibuJS] subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. Breaking to prevent infinite loop.`
455
- );
456
- }
566
+ const name = sub.__name ?? "<unnamed>";
567
+ reportError(
568
+ new Error(
569
+ `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.`
570
+ ),
571
+ { phase: "scheduler", name }
572
+ );
457
573
  }
458
574
  function absoluteDrainError() {
459
- if (typeof console !== "undefined") {
460
- console.error(
461
- `[SibuJS] Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
462
- );
463
- }
575
+ reportError(
576
+ new Error(
577
+ `Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
578
+ ),
579
+ { phase: "scheduler" }
580
+ );
464
581
  }
465
582
  function drainQueue() {
466
583
  let i = 0;
@@ -470,11 +587,14 @@ function drainQueue() {
470
587
  break;
471
588
  }
472
589
  const sub = pendingQueue[i++];
590
+ pendingSet.delete(sub);
591
+ if (quarantined.size > 0 && quarantined.has(sub)) continue;
592
+ if (sub._hasComputedDep === true && !depsChanged(sub)) continue;
473
593
  if (tickRepeat(sub)) {
474
594
  cycleError(sub);
475
- break;
595
+ quarantined.add(sub);
596
+ continue;
476
597
  }
477
- pendingSet.delete(sub);
478
598
  safeInvoke(sub);
479
599
  }
480
600
  }
@@ -489,6 +609,7 @@ function drainNotificationQueue() {
489
609
  if (notifyDepth === 0) {
490
610
  pendingQueue.length = 0;
491
611
  pendingSet.clear();
612
+ if (quarantined.size > 0) quarantined.clear();
492
613
  }
493
614
  }
494
615
  }
@@ -582,6 +703,7 @@ function notifySubscribers(signal2) {
582
703
  if (notifyDepth === 0) {
583
704
  pendingQueue.length = 0;
584
705
  pendingSet.clear();
706
+ if (quarantined.size > 0) quarantined.clear();
585
707
  }
586
708
  }
587
709
  }
@@ -608,14 +730,14 @@ function forEachSubscriber(signal2, visit) {
608
730
  }
609
731
 
610
732
  // src/reactivity/track.ts
611
- var _isDev3 = isDev();
612
- var _runtimeVersion = true ? "3.4.0" : "dev";
733
+ var _isDev2 = isDev();
734
+ var _runtimeVersion = true ? "4.0.0" : "dev";
613
735
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
614
736
  function resolveReactiveApi() {
615
737
  const g = globalThis;
616
738
  const existing = g[REGISTRY_KEY];
617
739
  if (existing) {
618
- if (_isDev3 && !existing.__dupWarned) {
740
+ if (_isDev2 && !existing.__dupWarned) {
619
741
  existing.__dupWarned = true;
620
742
  devWarn(
621
743
  `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']).`
@@ -717,70 +839,72 @@ var isBatching = API2.isBatching;
717
839
 
718
840
  // src/core/signals/signal.ts
719
841
  var _g = globalThis;
720
- var _isDev4 = isDev();
842
+ var _isDev3 = isDev();
721
843
  function signal(initial, options) {
722
- const state = {
844
+ const state2 = {
723
845
  value: initial,
724
846
  __v: 0,
725
847
  __sc: 0,
726
848
  subsHead: null,
727
849
  subsTail: null,
728
850
  __activeNode: null,
729
- __name: void 0
851
+ __name: void 0,
852
+ _d: false,
853
+ _validate: void 0
730
854
  };
731
- const debugName = _isDev4 ? options?.name : void 0;
855
+ const debugName = _isDev3 ? options?.name : void 0;
732
856
  const equalsFn = options?.equals;
733
- if (debugName) state.__name = debugName;
857
+ if (debugName) state2.__name = debugName;
734
858
  function get() {
735
- recordDependency2(state);
736
- return state.value;
859
+ recordDependency2(state2);
860
+ return state2.value;
737
861
  }
738
- get.__signal = state;
862
+ get.__signal = state2;
739
863
  if (debugName) get.__name = debugName;
740
864
  let set;
741
865
  if (equalsFn) {
742
866
  set = (next) => {
743
- const prev = state.value;
867
+ const prev = state2.value;
744
868
  const newValue = typeof next === "function" ? next(prev) : next;
745
869
  if (equalsFn(prev, newValue)) return;
746
- state.value = newValue;
747
- state.__v++;
748
- if (_isDev4) {
870
+ state2.value = newValue;
871
+ state2.__v++;
872
+ if (_isDev3) {
749
873
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
750
- if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
874
+ if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
751
875
  }
752
- if (!enqueueBatchedSignal(state)) {
753
- notifySubscribers2(state);
876
+ if (!enqueueBatchedSignal(state2)) {
877
+ notifySubscribers2(state2);
754
878
  }
755
879
  };
756
- } else if (_isDev4) {
880
+ } else if (_isDev3) {
757
881
  set = (next) => {
758
- const prev = state.value;
882
+ const prev = state2.value;
759
883
  const newValue = typeof next === "function" ? next(prev) : next;
760
884
  if (Object.is(newValue, prev)) return;
761
- state.value = newValue;
762
- state.__v++;
885
+ state2.value = newValue;
886
+ state2.__v++;
763
887
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
764
- if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
765
- if (!enqueueBatchedSignal(state)) {
766
- notifySubscribers2(state);
888
+ if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
889
+ if (!enqueueBatchedSignal(state2)) {
890
+ notifySubscribers2(state2);
767
891
  }
768
892
  };
769
893
  } else {
770
894
  set = (next) => {
771
- const prev = state.value;
895
+ const prev = state2.value;
772
896
  const newValue = typeof next === "function" ? next(prev) : next;
773
897
  if (Object.is(newValue, prev)) return;
774
- state.value = newValue;
775
- state.__v++;
776
- if (!enqueueBatchedSignal(state)) {
777
- notifySubscribers2(state);
898
+ state2.value = newValue;
899
+ state2.__v++;
900
+ if (!enqueueBatchedSignal(state2)) {
901
+ notifySubscribers2(state2);
778
902
  }
779
903
  };
780
904
  }
781
- if (_isDev4) {
905
+ if (_isDev3) {
782
906
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
783
- if (hook) hook.emit("signal:create", { signal: state, name: debugName, getter: get, initial });
907
+ if (hook) hook.emit("signal:create", { signal: state2, name: debugName, getter: get, initial });
784
908
  }
785
909
  return [get, set];
786
910
  }
@@ -1026,8 +1150,8 @@ function initDevTools(config) {
1026
1150
  function clearEvents() {
1027
1151
  eventLog.length = 0;
1028
1152
  }
1029
- function registerComponent(name, element, state) {
1030
- hook.components.set(name, { element, state });
1153
+ function registerComponent(name, element, state2) {
1154
+ hook.components.set(name, { element, state: state2 });
1031
1155
  emit();
1032
1156
  }
1033
1157
  function unregisterComponent(name) {
@@ -1472,7 +1596,15 @@ function devState(name, initial) {
1472
1596
 
1473
1597
  // src/core/rendering/dispose.ts
1474
1598
  var elementDisposers = /* @__PURE__ */ new WeakMap();
1475
- var _isDev5 = isDev();
1599
+ var MAX_DRAIN_TEARDOWNS = 1e4;
1600
+ function reportDrainRunaway(label, executed, remaining) {
1601
+ if (typeof console === "undefined") return;
1602
+ console.error(
1603
+ `[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.`,
1604
+ { executed, remaining }
1605
+ );
1606
+ }
1607
+ var _isDev4 = isDev();
1476
1608
  var activeBindingCount = 0;
1477
1609
  function dispose(node) {
1478
1610
  const stack = [node];
@@ -1487,34 +1619,30 @@ function dispose(node) {
1487
1619
  }
1488
1620
  for (let i = order.length - 1; i >= 0; i--) {
1489
1621
  const current = order[i];
1490
- const disposers = elementDisposers.get(current);
1491
- if (disposers) {
1492
- const snapshot = disposers.slice();
1493
- elementDisposers.delete(current);
1494
- if (_isDev5) activeBindingCount -= snapshot.length;
1495
- for (const d of snapshot) {
1496
- try {
1497
- d();
1498
- } catch (err) {
1499
- if (_isDev5 && typeof console !== "undefined") {
1500
- console.warn("[SibuJS] Disposer threw during cleanup:", err);
1501
- }
1502
- }
1503
- }
1504
- let extraPasses = 0;
1505
- while (extraPasses++ < 8) {
1506
- const added = elementDisposers.get(current);
1507
- if (!added || added.length === 0) break;
1508
- const moreSnapshot = added.slice();
1622
+ if (elementDisposers.has(current)) {
1623
+ let executed = 0;
1624
+ let runaway = false;
1625
+ while (!runaway) {
1626
+ const pending = elementDisposers.get(current);
1627
+ if (!pending || pending.length === 0) break;
1628
+ const snapshot = pending.slice();
1509
1629
  elementDisposers.delete(current);
1510
- if (_isDev5) activeBindingCount -= moreSnapshot.length;
1511
- for (const d of moreSnapshot) {
1630
+ if (_isDev4) activeBindingCount -= snapshot.length;
1631
+ for (let i2 = 0; i2 < snapshot.length; i2++) {
1632
+ if (executed >= MAX_DRAIN_TEARDOWNS) {
1633
+ const rest = snapshot.slice(i2);
1634
+ const added = elementDisposers.get(current);
1635
+ elementDisposers.set(current, added ? rest.concat(added) : rest);
1636
+ if (_isDev4) activeBindingCount += rest.length;
1637
+ reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
1638
+ runaway = true;
1639
+ break;
1640
+ }
1641
+ executed++;
1512
1642
  try {
1513
- d();
1643
+ snapshot[i2]();
1514
1644
  } catch (err) {
1515
- if (_isDev5 && typeof console !== "undefined") {
1516
- console.warn("[SibuJS] Disposer threw during cleanup:", err);
1517
- }
1645
+ reportError(err, { phase: "cleanup", name: "disposer" });
1518
1646
  }
1519
1647
  }
1520
1648
  }
@@ -1826,20 +1954,24 @@ function detectSSRShared() {
1826
1954
  const getBuiltin = process.getBuiltinModule;
1827
1955
  if (typeof getBuiltin === "function") {
1828
1956
  mod = getBuiltin("node:async_hooks");
1829
- } else {
1830
- const req = Function("return typeof require==='function'?require:null")();
1831
- if (req) mod = req("node:async_hooks");
1957
+ } else if (typeof require === "function") {
1958
+ mod = require("async_hooks");
1832
1959
  }
1833
1960
  if (mod) detected = new mod.AsyncLocalStorage();
1834
1961
  }
1835
1962
  } catch {
1836
1963
  detected = null;
1837
1964
  }
1838
- return { als: detected, fallbackStore: { ssr: false, suspenseIdCounter: 0 } };
1965
+ return {
1966
+ als: detected,
1967
+ fallbackStore: { ssr: false, suspenseIdCounter: 0, locale: void 0 },
1968
+ fallbackDepth: 0
1969
+ };
1839
1970
  }
1840
1971
  var _shared = globalThis[SSR_KEY] ?? (globalThis[SSR_KEY] = detectSSRShared());
1841
1972
  var als = _shared.als;
1842
1973
  var fallbackStore = _shared.fallbackStore;
1974
+ _shared.fallbackDepth ?? (_shared.fallbackDepth = 0);
1843
1975
  function getSSRStore() {
1844
1976
  if (als) {
1845
1977
  const s = als.getStore();
@@ -1862,7 +1994,7 @@ function flushUserCleanups(ctx) {
1862
1994
  try {
1863
1995
  list[i]();
1864
1996
  } catch (err) {
1865
- if (typeof console !== "undefined") console.warn("[SibuJS effect] onCleanup threw:", err);
1997
+ reportError(err, { phase: "cleanup" });
1866
1998
  }
1867
1999
  }
1868
2000
  }
@@ -1875,11 +2007,12 @@ function drainReruns(ctx) {
1875
2007
  } while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
1876
2008
  if (ctx.rerunPending) {
1877
2009
  ctx.rerunPending = false;
1878
- if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
1879
- console.error(
1880
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
1881
- );
1882
- }
2010
+ reportError(
2011
+ new Error(
2012
+ `effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
2013
+ ),
2014
+ { phase: "effect" }
2015
+ );
1883
2016
  }
1884
2017
  }
1885
2018
  function disposeEffect(ctx) {
@@ -1956,6 +2089,8 @@ function effect(effectFn, options) {
1956
2089
  sub.depsTail = null;
1957
2090
  sub._epoch = 0;
1958
2091
  sub._structDirty = false;
2092
+ sub._hasComputedDep = false;
2093
+ sub._errorPhase = "effect";
1959
2094
  sub._runEpoch = 0;
1960
2095
  sub._runs = 0;
1961
2096
  ctx.subscriber = sub;
package/dist/devtools.js CHANGED
@@ -35,17 +35,17 @@ import {
35
35
  trackCleanup,
36
36
  walkDependencyGraph,
37
37
  withErrorTracking
38
- } from "./chunk-3DVGCW7O.js";
38
+ } from "./chunk-F64ZPCFE.js";
39
+ import "./chunk-5INI7D2L.js";
39
40
  import "./chunk-7ZHH77QA.js";
40
- import "./chunk-L3GAGWCC.js";
41
- import "./chunk-BUKYCWHX.js";
42
- import "./chunk-S3NFJO6L.js";
43
- import "./chunk-5VGSK6D2.js";
44
- import "./chunk-KZBEVFXZ.js";
45
- import "./chunk-OOUQUCNN.js";
41
+ import "./chunk-PBQEW5VW.js";
42
+ import "./chunk-TIRZCERI.js";
43
+ import "./chunk-DHDZ7IVN.js";
44
+ import "./chunk-W55YHPEP.js";
45
+ import "./chunk-ACBT6UZS.js";
46
46
  import {
47
47
  isDev
48
- } from "./chunk-COY6PUD2.js";
48
+ } from "./chunk-VPP2FONR.js";
49
49
 
50
50
  // src/devtools/signalGraph.ts
51
51
  function getHook() {
@@ -0,0 +1,19 @@
1
+ import {
2
+ MAX_DRAIN_TEARDOWNS,
3
+ checkLeaks,
4
+ dispose,
5
+ registerDisposer,
6
+ replaceChildrenSafely,
7
+ reportDrainRunaway,
8
+ unregisterDisposer
9
+ } from "./chunk-DHDZ7IVN.js";
10
+ import "./chunk-VPP2FONR.js";
11
+ export {
12
+ MAX_DRAIN_TEARDOWNS,
13
+ checkLeaks,
14
+ dispose,
15
+ registerDisposer,
16
+ replaceChildrenSafely,
17
+ reportDrainRunaway,
18
+ unregisterDisposer
19
+ };