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/patterns.cjs CHANGED
@@ -65,8 +65,95 @@ function devWarn(message) {
65
65
  }
66
66
  }
67
67
 
68
+ // src/core/errors.ts
69
+ var ERROR_STATE_KEY = /* @__PURE__ */ Symbol.for("sibujs.runtime-errors.v1");
70
+ function state() {
71
+ const g = globalThis;
72
+ const existing = g[ERROR_STATE_KEY];
73
+ if (existing) return existing;
74
+ const created = { handler: null, handlerDepth: 0 };
75
+ g[ERROR_STATE_KEY] = created;
76
+ return created;
77
+ }
78
+ function normalizeError(value) {
79
+ if (value instanceof Error) return value;
80
+ const message = typeof value === "string" ? value : `Non-Error value thrown: ${safeStringify(value)}`;
81
+ return new Error(message, { cause: value });
82
+ }
83
+ function safeStringify(value) {
84
+ if (typeof value === "symbol") return value.toString();
85
+ try {
86
+ return typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
87
+ } catch {
88
+ return Object.prototype.toString.call(value);
89
+ }
90
+ }
91
+ function describe(context) {
92
+ return context.name ? `${context.phase} "${context.name}"` : context.phase;
93
+ }
94
+ var REACTIVE_REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
95
+ function untrackedRun(fn) {
96
+ const api = globalThis[REACTIVE_REGISTRY_KEY];
97
+ return api?.untracked ? api.untracked(fn) : fn();
98
+ }
99
+ var PROPAGATE_EVENT = "sibu:error-propagate";
100
+ function claimedByBoundary(error, context) {
101
+ const raw = context.node;
102
+ if (!raw || typeof CustomEvent === "undefined") return false;
103
+ const target = resolveEventTarget(raw);
104
+ if (!target) return false;
105
+ try {
106
+ const event = new CustomEvent(PROPAGATE_EVENT, {
107
+ bubbles: true,
108
+ cancelable: true,
109
+ detail: { error, context }
110
+ });
111
+ return target.dispatchEvent(event) === false;
112
+ } catch {
113
+ return false;
114
+ }
115
+ }
116
+ function resolveEventTarget(node) {
117
+ const ELEMENT_NODE = 1;
118
+ let current = node;
119
+ while (current) {
120
+ if (current.nodeType === ELEMENT_NODE && typeof current.dispatchEvent === "function") {
121
+ return current;
122
+ }
123
+ current = current.parentNode;
124
+ }
125
+ const self = node;
126
+ return typeof self.dispatchEvent === "function" ? self : null;
127
+ }
128
+ function defaultReport(error, context) {
129
+ if (typeof console === "undefined") return;
130
+ console.error(`[SibuJS] Uncaught error during ${describe(context)}: ${error.message}`, error);
131
+ }
132
+ function reportError(error, context) {
133
+ const err = normalizeError(error);
134
+ untrackedRun(() => {
135
+ if (claimedByBoundary(err, context)) return;
136
+ const s = state();
137
+ const handler = s.handler;
138
+ if (handler && s.handlerDepth === 0) {
139
+ s.handlerDepth++;
140
+ try {
141
+ handler(error instanceof Error ? error : err, context);
142
+ return;
143
+ } catch (handlerError) {
144
+ if (typeof console !== "undefined") {
145
+ const detail = handlerError instanceof Error ? handlerError.message : String(handlerError);
146
+ console.error(`[SibuJS] runtime error handler itself threw: ${detail}`, handlerError);
147
+ }
148
+ } finally {
149
+ s.handlerDepth--;
150
+ }
151
+ }
152
+ defaultReport(err, context);
153
+ });
154
+ }
155
+
68
156
  // src/reactivity/track-core.ts
69
- var _isDev2 = isDev();
70
157
  var POOL_MAX = 4096;
71
158
  var nodePool = [];
72
159
  function createNode() {
@@ -74,6 +161,7 @@ function createNode() {
74
161
  sig: null,
75
162
  sub: null,
76
163
  epoch: 0,
164
+ depVersion: 0,
77
165
  sigPrev: null,
78
166
  sigNext: null,
79
167
  subPrev: null,
@@ -158,8 +246,27 @@ function safeInvoke(sub) {
158
246
  try {
159
247
  sub();
160
248
  } catch (err) {
161
- if (_isDev2) devWarn(`Subscriber threw during notification: ${err instanceof Error ? err.message : String(err)}`);
249
+ const s = sub;
250
+ reportError(err, { phase: s._errorPhase ?? "effect", name: s.__name, node: s._errorNode });
251
+ }
252
+ }
253
+ function depsChanged(sub) {
254
+ let node = sub.depsHead ?? null;
255
+ if (node === null) return true;
256
+ while (node !== null) {
257
+ const sig = node.sig;
258
+ if (sig === null) return true;
259
+ if (sig._d === true && sig._validate !== void 0) {
260
+ try {
261
+ sig._validate();
262
+ } catch {
263
+ return true;
264
+ }
265
+ }
266
+ if (node.depVersion !== sig.__v) return true;
267
+ node = node.subNext;
162
268
  }
269
+ return false;
163
270
  }
164
271
  var suspendDepth = 0;
165
272
  var trackingSuspended = false;
@@ -241,7 +348,7 @@ function track(effectFn, subscriber) {
241
348
  const sub = subscriber;
242
349
  return sub._dispose ?? (sub._dispose = () => cleanup(subscriber));
243
350
  }
244
- function reactiveBinding(commit) {
351
+ function reactiveBinding(commit, ownerNode) {
245
352
  const run = () => {
246
353
  const s = subscriber;
247
354
  if (s._disposed || s._reentrant) return;
@@ -257,13 +364,17 @@ function reactiveBinding(commit) {
257
364
  subscriber.depsTail = null;
258
365
  subscriber._epoch = 0;
259
366
  subscriber._structDirty = false;
367
+ subscriber._hasComputedDep = false;
260
368
  subscriber._runEpoch = 0;
261
369
  subscriber._runs = 0;
262
370
  subscriber._reentrant = false;
263
371
  subscriber._disposed = false;
372
+ subscriber._errorPhase = "binding";
373
+ subscriber._errorNode = ownerNode;
264
374
  run();
265
375
  return subscriber._dispose ?? (subscriber._dispose = () => {
266
376
  subscriber._disposed = true;
377
+ subscriber._errorNode = void 0;
267
378
  cleanup(subscriber);
268
379
  });
269
380
  }
@@ -275,9 +386,12 @@ function recordDependency(signal2) {
275
386
  const active = sig.__activeNode ?? null;
276
387
  if (active !== null && active.sub === sub) {
277
388
  active.epoch = epoch;
389
+ active.depVersion = sig.__v ?? Number.NaN;
278
390
  return;
279
391
  }
392
+ if (sig._validate !== void 0) sub._hasComputedDep = true;
280
393
  const node = allocNode(signal2, sub, epoch);
394
+ node.depVersion = sig.__v ?? Number.NaN;
281
395
  node.prevActive = active;
282
396
  sig.__activeNode = node;
283
397
  linkSub(sub, node);
@@ -296,9 +410,10 @@ function cleanup(subscriber) {
296
410
  node = next;
297
411
  }
298
412
  }
299
- var maxSubscriberRepeats = 50;
413
+ var maxSubscriberRepeats = 1e3;
300
414
  var maxDrainIterations = 1e6;
301
415
  var drainEpoch = 0;
416
+ var quarantined = /* @__PURE__ */ new Set();
302
417
  function setMaxSubscriberRepeats(n) {
303
418
  const prev = maxSubscriberRepeats;
304
419
  if (Number.isFinite(n) && n > 0) maxSubscriberRepeats = Math.floor(n);
@@ -320,19 +435,21 @@ function tickRepeat(sub) {
320
435
  return s._runs > maxSubscriberRepeats;
321
436
  }
322
437
  function cycleError(sub) {
323
- if (typeof console !== "undefined") {
324
- const name = sub.__name ?? "<unnamed>";
325
- console.error(
326
- `[SibuJS] subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. Breaking to prevent infinite loop.`
327
- );
328
- }
438
+ const name = sub.__name ?? "<unnamed>";
439
+ reportError(
440
+ new Error(
441
+ `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.`
442
+ ),
443
+ { phase: "scheduler", name }
444
+ );
329
445
  }
330
446
  function absoluteDrainError() {
331
- if (typeof console !== "undefined") {
332
- console.error(
333
- `[SibuJS] Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
334
- );
335
- }
447
+ reportError(
448
+ new Error(
449
+ `Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
450
+ ),
451
+ { phase: "scheduler" }
452
+ );
336
453
  }
337
454
  function drainQueue() {
338
455
  let i = 0;
@@ -342,11 +459,14 @@ function drainQueue() {
342
459
  break;
343
460
  }
344
461
  const sub = pendingQueue[i++];
462
+ pendingSet.delete(sub);
463
+ if (quarantined.size > 0 && quarantined.has(sub)) continue;
464
+ if (sub._hasComputedDep === true && !depsChanged(sub)) continue;
345
465
  if (tickRepeat(sub)) {
346
466
  cycleError(sub);
347
- break;
467
+ quarantined.add(sub);
468
+ continue;
348
469
  }
349
- pendingSet.delete(sub);
350
470
  safeInvoke(sub);
351
471
  }
352
472
  }
@@ -361,6 +481,7 @@ function drainNotificationQueue() {
361
481
  if (notifyDepth === 0) {
362
482
  pendingQueue.length = 0;
363
483
  pendingSet.clear();
484
+ if (quarantined.size > 0) quarantined.clear();
364
485
  }
365
486
  }
366
487
  }
@@ -454,6 +575,7 @@ function notifySubscribers(signal2) {
454
575
  if (notifyDepth === 0) {
455
576
  pendingQueue.length = 0;
456
577
  pendingSet.clear();
578
+ if (quarantined.size > 0) quarantined.clear();
457
579
  }
458
580
  }
459
581
  }
@@ -480,14 +602,14 @@ function forEachSubscriber(signal2, visit) {
480
602
  }
481
603
 
482
604
  // src/reactivity/track.ts
483
- var _isDev3 = isDev();
484
- var _runtimeVersion = true ? "3.4.0" : "dev";
605
+ var _isDev2 = isDev();
606
+ var _runtimeVersion = true ? "4.0.0" : "dev";
485
607
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
486
608
  function resolveReactiveApi() {
487
609
  const g = globalThis;
488
610
  const existing = g[REGISTRY_KEY];
489
611
  if (existing) {
490
- if (_isDev3 && !existing.__dupWarned) {
612
+ if (_isDev2 && !existing.__dupWarned) {
491
613
  existing.__dupWarned = true;
492
614
  devWarn(
493
615
  `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']).`
@@ -589,70 +711,72 @@ var isBatching = API2.isBatching;
589
711
 
590
712
  // src/core/signals/signal.ts
591
713
  var _g = globalThis;
592
- var _isDev4 = isDev();
714
+ var _isDev3 = isDev();
593
715
  function signal(initial, options) {
594
- const state = {
716
+ const state2 = {
595
717
  value: initial,
596
718
  __v: 0,
597
719
  __sc: 0,
598
720
  subsHead: null,
599
721
  subsTail: null,
600
722
  __activeNode: null,
601
- __name: void 0
723
+ __name: void 0,
724
+ _d: false,
725
+ _validate: void 0
602
726
  };
603
- const debugName = _isDev4 ? options?.name : void 0;
727
+ const debugName = _isDev3 ? options?.name : void 0;
604
728
  const equalsFn = options?.equals;
605
- if (debugName) state.__name = debugName;
729
+ if (debugName) state2.__name = debugName;
606
730
  function get() {
607
- recordDependency2(state);
608
- return state.value;
731
+ recordDependency2(state2);
732
+ return state2.value;
609
733
  }
610
- get.__signal = state;
734
+ get.__signal = state2;
611
735
  if (debugName) get.__name = debugName;
612
736
  let set;
613
737
  if (equalsFn) {
614
738
  set = (next) => {
615
- const prev = state.value;
739
+ const prev = state2.value;
616
740
  const newValue = typeof next === "function" ? next(prev) : next;
617
741
  if (equalsFn(prev, newValue)) return;
618
- state.value = newValue;
619
- state.__v++;
620
- if (_isDev4) {
742
+ state2.value = newValue;
743
+ state2.__v++;
744
+ if (_isDev3) {
621
745
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
622
- if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
746
+ if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
623
747
  }
624
- if (!enqueueBatchedSignal(state)) {
625
- notifySubscribers2(state);
748
+ if (!enqueueBatchedSignal(state2)) {
749
+ notifySubscribers2(state2);
626
750
  }
627
751
  };
628
- } else if (_isDev4) {
752
+ } else if (_isDev3) {
629
753
  set = (next) => {
630
- const prev = state.value;
754
+ const prev = state2.value;
631
755
  const newValue = typeof next === "function" ? next(prev) : next;
632
756
  if (Object.is(newValue, prev)) return;
633
- state.value = newValue;
634
- state.__v++;
757
+ state2.value = newValue;
758
+ state2.__v++;
635
759
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
636
- if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
637
- if (!enqueueBatchedSignal(state)) {
638
- notifySubscribers2(state);
760
+ if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
761
+ if (!enqueueBatchedSignal(state2)) {
762
+ notifySubscribers2(state2);
639
763
  }
640
764
  };
641
765
  } else {
642
766
  set = (next) => {
643
- const prev = state.value;
767
+ const prev = state2.value;
644
768
  const newValue = typeof next === "function" ? next(prev) : next;
645
769
  if (Object.is(newValue, prev)) return;
646
- state.value = newValue;
647
- state.__v++;
648
- if (!enqueueBatchedSignal(state)) {
649
- notifySubscribers2(state);
770
+ state2.value = newValue;
771
+ state2.__v++;
772
+ if (!enqueueBatchedSignal(state2)) {
773
+ notifySubscribers2(state2);
650
774
  }
651
775
  };
652
776
  }
653
- if (_isDev4) {
777
+ if (_isDev3) {
654
778
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
655
- if (hook) hook.emit("signal:create", { signal: state, name: debugName, getter: get, initial });
779
+ if (hook) hook.emit("signal:create", { signal: state2, name: debugName, getter: get, initial });
656
780
  }
657
781
  return [get, set];
658
782
  }
@@ -672,14 +796,14 @@ function stripUnsafeKeys(obj) {
672
796
 
673
797
  // src/patterns/machine.ts
674
798
  function machine(config) {
675
- const [state, setState] = signal(config.initial);
799
+ const [state2, setState] = signal(config.initial);
676
800
  const [context, setContext] = signal(config.context || {});
677
801
  const initialDef = config.states[config.initial];
678
802
  if (initialDef?.entry) {
679
803
  initialDef.entry(context());
680
804
  }
681
805
  function send(event) {
682
- const currentState = state();
806
+ const currentState = state2();
683
807
  const stateDef = config.states[currentState];
684
808
  if (!stateDef?.on) return;
685
809
  const transition = stateDef.on[event];
@@ -711,10 +835,10 @@ function machine(config) {
711
835
  }
712
836
  }
713
837
  function matches(s) {
714
- return state() === s;
838
+ return state2() === s;
715
839
  }
716
840
  function can(event) {
717
- const currentState = state();
841
+ const currentState = state2();
718
842
  const stateDef = config.states[currentState];
719
843
  if (!stateDef?.on) return false;
720
844
  const transition = stateDef.on[event];
@@ -725,7 +849,7 @@ function machine(config) {
725
849
  }
726
850
  return true;
727
851
  }
728
- return { state, context, send, matches, can };
852
+ return { state: state2, context, send, matches, can };
729
853
  }
730
854
 
731
855
  // src/core/ssr-context.ts
@@ -738,20 +862,24 @@ function detectSSRShared() {
738
862
  const getBuiltin = process.getBuiltinModule;
739
863
  if (typeof getBuiltin === "function") {
740
864
  mod = getBuiltin("node:async_hooks");
741
- } else {
742
- const req = Function("return typeof require==='function'?require:null")();
743
- if (req) mod = req("node:async_hooks");
865
+ } else if (typeof require === "function") {
866
+ mod = require("async_hooks");
744
867
  }
745
868
  if (mod) detected = new mod.AsyncLocalStorage();
746
869
  }
747
870
  } catch {
748
871
  detected = null;
749
872
  }
750
- return { als: detected, fallbackStore: { ssr: false, suspenseIdCounter: 0 } };
873
+ return {
874
+ als: detected,
875
+ fallbackStore: { ssr: false, suspenseIdCounter: 0, locale: void 0 },
876
+ fallbackDepth: 0
877
+ };
751
878
  }
752
879
  var _shared = globalThis[SSR_KEY] ?? (globalThis[SSR_KEY] = detectSSRShared());
753
880
  var als = _shared.als;
754
881
  var fallbackStore = _shared.fallbackStore;
882
+ _shared.fallbackDepth ?? (_shared.fallbackDepth = 0);
755
883
  function getSSRStore() {
756
884
  if (als) {
757
885
  const s = als.getStore();
@@ -774,7 +902,7 @@ function flushUserCleanups(ctx) {
774
902
  try {
775
903
  list[i]();
776
904
  } catch (err) {
777
- if (typeof console !== "undefined") console.warn("[SibuJS effect] onCleanup threw:", err);
905
+ reportError(err, { phase: "cleanup" });
778
906
  }
779
907
  }
780
908
  }
@@ -787,11 +915,12 @@ function drainReruns(ctx) {
787
915
  } while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
788
916
  if (ctx.rerunPending) {
789
917
  ctx.rerunPending = false;
790
- if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
791
- console.error(
792
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
793
- );
794
- }
918
+ reportError(
919
+ new Error(
920
+ `effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
921
+ ),
922
+ { phase: "effect" }
923
+ );
795
924
  }
796
925
  }
797
926
  function disposeEffect(ctx) {
@@ -868,6 +997,8 @@ function effect(effectFn, options) {
868
997
  sub.depsTail = null;
869
998
  sub._epoch = 0;
870
999
  sub._structDirty = false;
1000
+ sub._hasComputedDep = false;
1001
+ sub._errorPhase = "effect";
871
1002
  sub._runEpoch = 0;
872
1003
  sub._runs = 0;
873
1004
  ctx.subscriber = sub;
@@ -990,116 +1121,258 @@ function optimistic(initialValue) {
990
1121
  }
991
1122
  } finally {
992
1123
  inflightCount--;
993
- if (inflightCount === 0) setPending(false);
1124
+ if (inflightCount <= 0) {
1125
+ inflightCount = 0;
1126
+ setPending(false);
1127
+ }
994
1128
  }
995
1129
  }
996
1130
  return { value, pending, update };
997
1131
  }
998
1132
  function optimisticList(initialValue) {
999
- const [items, setItems] = signal([...initialValue]);
1133
+ let nextRowId = 0;
1134
+ let nextKey = 0;
1135
+ let nextOpId = 0;
1136
+ const records = /* @__PURE__ */ new Map();
1137
+ let order = [];
1138
+ for (const value of initialValue) {
1139
+ const row = { id: nextRowId++, key: nextKey++, base: value, claims: [], visible: true, refs: 0 };
1140
+ records.set(row.id, row);
1141
+ order.push(row.id);
1142
+ }
1143
+ function effectiveValue(row) {
1144
+ const claims = row.claims;
1145
+ return claims.length > 0 ? claims[claims.length - 1].value : row.base;
1146
+ }
1147
+ function valueBelow(row, opId) {
1148
+ const claims = row.claims;
1149
+ for (let i = claims.length - 1; i >= 0; i--) {
1150
+ if (claims[i].opId < opId) return claims[i].value;
1151
+ }
1152
+ return row.base;
1153
+ }
1154
+ function stake(row, opId, value) {
1155
+ const claim = { opId, value, settled: false };
1156
+ const claims = row.claims;
1157
+ let at = claims.length;
1158
+ while (at > 0 && claims[at - 1].opId > opId) at--;
1159
+ claims.splice(at, 0, claim);
1160
+ return claim;
1161
+ }
1162
+ function dropClaim(row, claim) {
1163
+ const at = row.claims.indexOf(claim);
1164
+ if (at !== -1) row.claims.splice(at, 1);
1165
+ }
1166
+ function collapse(row) {
1167
+ const claims = row.claims;
1168
+ let i = 0;
1169
+ while (i < claims.length && claims[i].settled) {
1170
+ row.base = claims[i].value;
1171
+ i++;
1172
+ }
1173
+ if (i > 0) claims.splice(0, i);
1174
+ }
1175
+ const [items, setItems] = signal(order.map((id) => effectiveValue(records.get(id))));
1000
1176
  const [pending, setPending] = signal(false);
1001
- let inflightCount = 0;
1002
- let version = 0;
1003
- let tempIdCounter = 0;
1004
- const itemIds = /* @__PURE__ */ new WeakMap();
1005
- const idToItem = /* @__PURE__ */ new Map();
1006
- function tagItem(item) {
1007
- const id = ++tempIdCounter;
1008
- if (item !== null && typeof item === "object") {
1009
- itemIds.set(item, id);
1010
- }
1011
- idToItem.set(id, item);
1012
- return id;
1013
- }
1014
- function findIndexById(list, id) {
1015
- for (let i = 0; i < list.length; i++) {
1016
- const it = list[i];
1017
- if (it !== null && typeof it === "object" && itemIds.get(it) === id) {
1018
- return i;
1177
+ let inflight = 0;
1178
+ const retiredRowIds = /* @__PURE__ */ new Set();
1179
+ function project() {
1180
+ const out = new Array(order.length);
1181
+ for (let i = 0; i < order.length; i++) out[i] = effectiveValue(records.get(order[i]));
1182
+ return out;
1183
+ }
1184
+ function commit(mutate) {
1185
+ batch(() => {
1186
+ let visibleChanged = false;
1187
+ try {
1188
+ visibleChanged = mutate();
1189
+ } finally {
1190
+ setPending(inflight > 0);
1191
+ if (visibleChanged) setItems(project());
1019
1192
  }
1020
- if (Object.is(it, idToItem.get(id))) return i;
1193
+ });
1194
+ }
1195
+ function hide(id) {
1196
+ const row = records.get(id);
1197
+ if (!row || !row.visible) return false;
1198
+ row.visible = false;
1199
+ order = order.filter((x) => x !== id);
1200
+ return true;
1201
+ }
1202
+ function restore(ids) {
1203
+ const restorable = [];
1204
+ for (const id of ids) {
1205
+ const row = records.get(id);
1206
+ if (!row || row.visible || retiredRowIds.has(id)) continue;
1207
+ restorable.push(id);
1208
+ }
1209
+ if (restorable.length === 0) return false;
1210
+ const merged = new Array(order.length + restorable.length);
1211
+ let i = 0;
1212
+ let j = 0;
1213
+ let w = 0;
1214
+ while (i < order.length && j < restorable.length) {
1215
+ const a = records.get(order[i]).key;
1216
+ const b = records.get(restorable[j]).key;
1217
+ merged[w++] = a <= b ? order[i++] : restorable[j++];
1021
1218
  }
1022
- return -1;
1219
+ while (i < order.length) merged[w++] = order[i++];
1220
+ while (j < restorable.length) merged[w++] = restorable[j++];
1221
+ for (const id of restorable) records.get(id).visible = true;
1222
+ order = merged;
1223
+ return true;
1023
1224
  }
1024
- function begin() {
1025
- const v = ++version;
1026
- inflightCount++;
1027
- setPending(true);
1028
- return v;
1225
+ function retain(ids) {
1226
+ for (const id of ids) {
1227
+ const row = records.get(id);
1228
+ if (row) row.refs++;
1229
+ }
1029
1230
  }
1030
- function end(myVersion, revertFn) {
1031
- if (revertFn && version === myVersion) {
1032
- revertFn();
1231
+ function release(ids) {
1232
+ for (const id of ids) {
1233
+ const row = records.get(id);
1234
+ if (!row) continue;
1235
+ row.refs--;
1236
+ if (row.refs <= 0 && !row.visible) {
1237
+ records.delete(id);
1238
+ retiredRowIds.delete(id);
1239
+ }
1240
+ }
1241
+ }
1242
+ function settle(heldIds) {
1243
+ release(heldIds);
1244
+ inflight--;
1245
+ if (inflight <= 0) {
1246
+ inflight = 0;
1247
+ retiredRowIds.clear();
1248
+ if (records.size !== order.length) {
1249
+ for (const [id, row] of records) {
1250
+ if (!row.visible) records.delete(id);
1251
+ }
1252
+ }
1033
1253
  }
1034
- inflightCount--;
1035
- if (inflightCount === 0) setPending(false);
1036
1254
  }
1037
1255
  async function add(item, asyncAction) {
1038
- const prev = items();
1039
- const id = tagItem(item);
1040
- setItems([...prev, item]);
1041
- const myVersion = begin();
1256
+ const opId = ++nextOpId;
1257
+ const row = { id: nextRowId++, key: nextKey++, base: item, claims: [], visible: false, refs: 1 };
1258
+ const claim = stake(row, opId, item);
1259
+ commit(() => {
1260
+ records.set(row.id, row);
1261
+ row.visible = true;
1262
+ order = [...order, row.id];
1263
+ inflight++;
1264
+ return true;
1265
+ });
1266
+ let result;
1267
+ let failed = false;
1042
1268
  try {
1043
- const result = await asyncAction();
1044
- setItems((current) => {
1045
- const idx = findIndexById(current, id);
1046
- if (idx >= 0) {
1047
- const next = [...current];
1048
- next[idx] = result;
1049
- return next;
1050
- }
1051
- return [...current, result];
1052
- });
1053
- idToItem.delete(id);
1054
- end(myVersion);
1269
+ result = await asyncAction();
1055
1270
  } catch {
1056
- idToItem.delete(id);
1057
- end(myVersion, () => setItems(prev));
1271
+ failed = true;
1058
1272
  }
1273
+ commit(() => {
1274
+ try {
1275
+ if (failed) {
1276
+ retiredRowIds.add(row.id);
1277
+ dropClaim(row, claim);
1278
+ return hide(row.id);
1279
+ }
1280
+ const before = effectiveValue(row);
1281
+ claim.value = result;
1282
+ claim.settled = true;
1283
+ collapse(row);
1284
+ return row.visible && !Object.is(before, effectiveValue(row));
1285
+ } finally {
1286
+ settle([row.id]);
1287
+ }
1288
+ });
1059
1289
  }
1060
1290
  async function remove(predicate, asyncAction) {
1061
- const prev = items();
1062
- setItems(prev.filter((item) => !predicate(item)));
1063
- const myVersion = begin();
1291
+ const opId = ++nextOpId;
1292
+ const matchedIds = [];
1293
+ for (const id of order) {
1294
+ if (predicate(valueBelow(records.get(id), opId))) matchedIds.push(id);
1295
+ }
1296
+ commit(() => {
1297
+ retain(matchedIds);
1298
+ inflight++;
1299
+ if (matchedIds.length === 0) return false;
1300
+ const removing = new Set(matchedIds);
1301
+ for (const id of matchedIds) {
1302
+ const row = records.get(id);
1303
+ if (row) row.visible = false;
1304
+ }
1305
+ order = order.filter((id) => !removing.has(id));
1306
+ return true;
1307
+ });
1308
+ let failed = false;
1064
1309
  try {
1065
1310
  await asyncAction();
1066
- end(myVersion);
1067
1311
  } catch {
1068
- end(myVersion, () => setItems(prev));
1312
+ failed = true;
1069
1313
  }
1314
+ commit(() => {
1315
+ try {
1316
+ if (!failed) {
1317
+ for (const id of matchedIds) retiredRowIds.add(id);
1318
+ return false;
1319
+ }
1320
+ return restore(matchedIds);
1321
+ } finally {
1322
+ settle(matchedIds);
1323
+ }
1324
+ });
1070
1325
  }
1071
1326
  async function updateItem(predicate, patch, asyncAction) {
1072
- const prev = items();
1073
- const patchedIds = [];
1074
- setItems(
1075
- prev.map((item) => {
1076
- if (predicate(item)) {
1077
- const patched = { ...item, ...patch };
1078
- const id = tagItem(patched);
1079
- patchedIds.push(id);
1080
- return patched;
1081
- }
1082
- return item;
1083
- })
1084
- );
1085
- const myVersion = begin();
1327
+ const opId = ++nextOpId;
1328
+ const prepared = [];
1329
+ for (const id of order) {
1330
+ const row = records.get(id);
1331
+ const seen = valueBelow(row, opId);
1332
+ if (!predicate(seen)) continue;
1333
+ prepared.push({ row, nextValue: { ...seen, ...patch } });
1334
+ }
1335
+ const preparedIds = prepared.map((p) => p.row.id);
1336
+ const claims = [];
1337
+ commit(() => {
1338
+ retain(preparedIds);
1339
+ inflight++;
1340
+ let visibleChanged = false;
1341
+ for (const p of prepared) {
1342
+ const before = effectiveValue(p.row);
1343
+ claims.push(stake(p.row, opId, p.nextValue));
1344
+ if (p.row.visible && !Object.is(before, effectiveValue(p.row))) visibleChanged = true;
1345
+ }
1346
+ return visibleChanged;
1347
+ });
1348
+ let result;
1349
+ let failed = false;
1086
1350
  try {
1087
- const result = await asyncAction();
1088
- setItems(
1089
- (current) => current.map((item) => {
1090
- if (item !== null && typeof item === "object") {
1091
- const existingId = itemIds.get(item);
1092
- if (existingId !== void 0 && patchedIds.includes(existingId)) return result;
1093
- }
1094
- return item;
1095
- })
1096
- );
1097
- for (const id of patchedIds) idToItem.delete(id);
1098
- end(myVersion);
1351
+ result = await asyncAction();
1099
1352
  } catch {
1100
- for (const id of patchedIds) idToItem.delete(id);
1101
- end(myVersion, () => setItems(prev));
1353
+ failed = true;
1102
1354
  }
1355
+ commit(() => {
1356
+ try {
1357
+ let visibleChanged = false;
1358
+ for (let i = 0; i < claims.length; i++) {
1359
+ const row = prepared[i].row;
1360
+ const claim = claims[i];
1361
+ const before = effectiveValue(row);
1362
+ if (failed) {
1363
+ dropClaim(row, claim);
1364
+ } else {
1365
+ claim.value = result;
1366
+ claim.settled = true;
1367
+ }
1368
+ collapse(row);
1369
+ if (row.visible && !Object.is(before, effectiveValue(row))) visibleChanged = true;
1370
+ }
1371
+ return visibleChanged;
1372
+ } finally {
1373
+ settle(preparedIds);
1374
+ }
1375
+ });
1103
1376
  }
1104
1377
  return {
1105
1378
  items,
@@ -1145,6 +1418,21 @@ function derived(getter, options) {
1145
1418
  }, markDirty);
1146
1419
  const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1147
1420
  let evaluating = false;
1421
+ const validate = () => {
1422
+ if (!cs._d) return;
1423
+ const oldValue = cs._v;
1424
+ evaluating = true;
1425
+ try {
1426
+ retrack2(recompute, markDirty);
1427
+ if (!Object.is(oldValue, cs._v)) cs.__v++;
1428
+ } finally {
1429
+ evaluating = false;
1430
+ }
1431
+ if (hook && !Object.is(oldValue, cs._v)) {
1432
+ hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
1433
+ }
1434
+ };
1435
+ cs._validate = validate;
1148
1436
  function computedGetter() {
1149
1437
  if (evaluating) {
1150
1438
  throw new Error(
@@ -1152,32 +1440,11 @@ function derived(getter, options) {
1152
1440
  );
1153
1441
  }
1154
1442
  if (isTrackingSuspended2()) {
1155
- if (cs._d) {
1156
- const prev = cs._v;
1157
- evaluating = true;
1158
- try {
1159
- retrack2(recompute, markDirty);
1160
- if (!Object.is(prev, cs._v)) cs.__v++;
1161
- } finally {
1162
- evaluating = false;
1163
- }
1164
- }
1443
+ if (cs._d) validate();
1165
1444
  return cs._v;
1166
1445
  }
1446
+ if (cs._d) validate();
1167
1447
  recordDependency2(cs);
1168
- if (cs._d) {
1169
- const oldValue = cs._v;
1170
- evaluating = true;
1171
- try {
1172
- retrack2(recompute, markDirty);
1173
- if (!Object.is(oldValue, cs._v)) cs.__v++;
1174
- } finally {
1175
- evaluating = false;
1176
- }
1177
- if (hook && oldValue !== cs._v) {
1178
- hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
1179
- }
1180
- }
1181
1448
  return cs._v;
1182
1449
  }
1183
1450
  if (debugName) {