sibujs 3.4.1 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +784 -392
  8. package/dist/build.js +15 -15
  9. package/dist/cdn.global.js +11 -7
  10. package/dist/{chunk-PBZWJQNY.js → chunk-52ERIVFD.js} +8 -8
  11. package/dist/chunk-52XFPGSN.js +123 -0
  12. package/dist/{chunk-Y22QAKJX.js → chunk-5BVKQX2F.js} +4 -4
  13. package/dist/chunk-5INI7D2L.js +194 -0
  14. package/dist/{chunk-4I3M326N.js → chunk-AD5YSZAN.js} +19 -25
  15. package/dist/{chunk-F7HW2NI5.js → chunk-AW6HPJ3L.js} +1 -1
  16. package/dist/chunk-DHDZ7IVN.js +109 -0
  17. package/dist/{chunk-VQZDHAEK.js → chunk-E72G5JSK.js} +1 -1
  18. package/dist/{chunk-MPE75KOA.js → chunk-HPXTUPJD.js} +259 -124
  19. package/dist/{chunk-EX77FXTT.js → chunk-HYCCIYNS.js} +228 -51
  20. package/dist/{chunk-FWFEBYQ6.js → chunk-IKVUUE7D.js} +115 -41
  21. package/dist/{chunk-5MFF5EPT.js → chunk-J4WZMCIW.js} +5 -5
  22. package/dist/{chunk-BQLVTAUZ.js → chunk-JYXQCELN.js} +57 -22
  23. package/dist/{chunk-WEZ5SP7L.js → chunk-PHB3MCK4.js} +73 -34
  24. package/dist/chunk-PHRH66Y7.js +147 -0
  25. package/dist/{chunk-S2VW4NBA.js → chunk-PJDSI2K7.js} +295 -198
  26. package/dist/{chunk-QHPUFNHZ.js → chunk-PTLJ7NQX.js} +3 -3
  27. package/dist/{chunk-NXR2YFZB.js → chunk-QD4I7ZGZ.js} +24 -34
  28. package/dist/{chunk-S3NFJO6L.js → chunk-TIRZCERI.js} +36 -5
  29. package/dist/{chunk-7PNKW3FJ.js → chunk-TNEHT3NG.js} +232 -67
  30. package/dist/{chunk-335KJEN2.js → chunk-TVURNWDK.js} +5 -3
  31. package/dist/{chunk-CV7FAQ2R.js → chunk-UNAYBND2.js} +9 -3
  32. package/dist/chunk-VPP2FONR.js +142 -0
  33. package/dist/{chunk-X4JS367G.js → chunk-XDOMTQHM.js} +14 -10
  34. package/dist/chunk-XET2RUJF.js +61 -0
  35. package/dist/{chunk-3FFCUIGV.js → chunk-XZMCVZW6.js} +309 -188
  36. package/dist/{chunk-YDWP3ZOU.js → chunk-YLV26GAJ.js} +228 -86
  37. package/dist/{contracts-ey_Qh8ef.d.ts → contracts-Hg6ITAEF.d.cts} +6 -6
  38. package/dist/{contracts-ey_Qh8ef.d.cts → contracts-Hg6ITAEF.d.ts} +6 -6
  39. package/dist/{customElement-CPfIrbvg.d.cts → customElement-CKLoO63w.d.cts} +73 -11
  40. package/dist/{customElement-CPfIrbvg.d.ts → 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 +426 -182
  49. package/dist/ecosystem.js +11 -11
  50. package/dist/extras.cjs +1988 -772
  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 +791 -392
  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 +1378 -583
  71. package/dist/plugins.d.cts +227 -9
  72. package/dist/plugins.d.ts +227 -9
  73. package/dist/plugins.js +610 -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 +1111 -450
  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-6CAJU5TP.js +0 -38
  96. package/dist/chunk-COY6PUD2.js +0 -34
  97. package/dist/chunk-DLBFEAIS.js +0 -96
  98. package/dist/chunk-L3GAGWCC.js +0 -111
package/dist/ui.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- export { B as BoundFieldProps, C as CustomElementOptions, F as FieldConfig, a as FocusTrap, b as FormConfig, c as FormField, d as FormReturn, I as IntersectionResult, M as MaskOptions, T as Toast, e as ToastInstance, V as ValidatorFn, f as VirtualList, g as VirtualListProps, _ as __resetDialogStack, h as announce, i as aria, j as bindAttrs, k as bindBoolAttr, l as bindData, m as bindField, n as creditCardMask, o as custom, p as dateMask, q as defineElement, r as dialog, s as email, t as eventBus, u as focus, v as form, w as hotkey, x as infiniteScroll, y as inputMask, z as intersection, A as lazyLoad, D as matchesPattern, E as max, G as maxLength, H as min, J as minLength, K as pagination, L as phoneMask, N as removeScopedStyle, O as required, P as scopedStyle, Q as ssnMask, R as svgElement, S as timeMask, U as toast, W as withScopedStyle, X as zipMask } from './customElement-CPfIrbvg.cjs';
2
- export { C as ComponentProps, P as PropDef, a as PropSchema, R as RenderProp, V as Validator, b as assertType, c as compose, d as createGuard, e as createSlots, f as defineComponent, g as defineSlottedComponent, h as defineStrictComponent, v as validateProps, i as validators, w as withBoundary, j as withDefaults, k as withProps, l as withWrapper } from './contracts-ey_Qh8ef.cjs';
1
+ export { A as AttributeSource, a as AttributeValue, B as BoundFieldProps, C as CustomElementOptions, F as FieldConfig, b as FocusTrap, c as FormConfig, d as FormField, e as FormReturn, I as IntersectionResult, M as MaskOptions, T as Toast, f as ToastInstance, V as ValidatorFn, g as VirtualList, h as VirtualListProps, _ as __resetDialogStack, i as announce, j as aria, k as bindAttrs, l as bindBoolAttr, m as bindData, n as bindField, o as creditCardMask, p as custom, q as dateMask, r as defineElement, s as dialog, t as email, u as eventBus, v as focus, w as form, x as hotkey, y as infiniteScroll, z as inputMask, D as intersection, E as lazyLoad, G as matchesPattern, H as max, J as maxLength, K as min, L as minLength, N as pagination, O as phoneMask, P as removeScopedStyle, Q as required, R as scopedStyle, S as ssnMask, U as svgElement, W as timeMask, X as toast, Y as withScopedStyle, Z as zipMask } from './customElement-CKLoO63w.cjs';
2
+ export { C as ComponentProps, P as PropDef, a as PropSchema, R as RenderProp, V as Validator, b as assertType, c as compose, d as createGuard, e as createSlots, f as defineComponent, g as defineSlottedComponent, h as defineStrictComponent, v as validateProps, i as validators, w as withBoundary, j as withDefaults, k as withProps, l as withWrapper } from './contracts-Hg6ITAEF.cjs';
3
3
 
4
4
  interface FormActionHandle<TArgs extends unknown[], TResult> {
5
5
  /** Invoke the action. Rejections become `error()`, resolutions `result()`. */
package/dist/ui.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { B as BoundFieldProps, C as CustomElementOptions, F as FieldConfig, a as FocusTrap, b as FormConfig, c as FormField, d as FormReturn, I as IntersectionResult, M as MaskOptions, T as Toast, e as ToastInstance, V as ValidatorFn, f as VirtualList, g as VirtualListProps, _ as __resetDialogStack, h as announce, i as aria, j as bindAttrs, k as bindBoolAttr, l as bindData, m as bindField, n as creditCardMask, o as custom, p as dateMask, q as defineElement, r as dialog, s as email, t as eventBus, u as focus, v as form, w as hotkey, x as infiniteScroll, y as inputMask, z as intersection, A as lazyLoad, D as matchesPattern, E as max, G as maxLength, H as min, J as minLength, K as pagination, L as phoneMask, N as removeScopedStyle, O as required, P as scopedStyle, Q as ssnMask, R as svgElement, S as timeMask, U as toast, W as withScopedStyle, X as zipMask } from './customElement-CPfIrbvg.js';
2
- export { C as ComponentProps, P as PropDef, a as PropSchema, R as RenderProp, V as Validator, b as assertType, c as compose, d as createGuard, e as createSlots, f as defineComponent, g as defineSlottedComponent, h as defineStrictComponent, v as validateProps, i as validators, w as withBoundary, j as withDefaults, k as withProps, l as withWrapper } from './contracts-ey_Qh8ef.js';
1
+ export { A as AttributeSource, a as AttributeValue, B as BoundFieldProps, C as CustomElementOptions, F as FieldConfig, b as FocusTrap, c as FormConfig, d as FormField, e as FormReturn, I as IntersectionResult, M as MaskOptions, T as Toast, f as ToastInstance, V as ValidatorFn, g as VirtualList, h as VirtualListProps, _ as __resetDialogStack, i as announce, j as aria, k as bindAttrs, l as bindBoolAttr, m as bindData, n as bindField, o as creditCardMask, p as custom, q as dateMask, r as defineElement, s as dialog, t as email, u as eventBus, v as focus, w as form, x as hotkey, y as infiniteScroll, z as inputMask, D as intersection, E as lazyLoad, G as matchesPattern, H as max, J as maxLength, K as min, L as minLength, N as pagination, O as phoneMask, P as removeScopedStyle, Q as required, R as scopedStyle, S as ssnMask, U as svgElement, W as timeMask, X as toast, Y as withScopedStyle, Z as zipMask } from './customElement-CKLoO63w.js';
2
+ export { C as ComponentProps, P as PropDef, a as PropSchema, R as RenderProp, V as Validator, b as assertType, c as compose, d as createGuard, e as createSlots, f as defineComponent, g as defineSlottedComponent, h as defineStrictComponent, v as validateProps, i as validators, w as withBoundary, j as withDefaults, k as withProps, l as withWrapper } from './contracts-Hg6ITAEF.js';
3
3
 
4
4
  interface FormActionHandle<TArgs extends unknown[], TResult> {
5
5
  /** Invoke the action. Rejections become `error()`, resolutions `result()`. */
package/dist/ui.js CHANGED
@@ -38,7 +38,7 @@ import {
38
38
  toast,
39
39
  withScopedStyle,
40
40
  zipMask
41
- } from "./chunk-7PNKW3FJ.js";
41
+ } from "./chunk-TNEHT3NG.js";
42
42
  import {
43
43
  RenderProp,
44
44
  assertType,
@@ -58,24 +58,24 @@ import {
58
58
  import {
59
59
  createId
60
60
  } from "./chunk-CCSJMTRN.js";
61
- import "./chunk-DLBFEAIS.js";
62
- import "./chunk-4I3M326N.js";
61
+ import "./chunk-PHRH66Y7.js";
62
+ import "./chunk-AD5YSZAN.js";
63
+ import "./chunk-5INI7D2L.js";
63
64
  import {
64
65
  globalSingleton
65
66
  } from "./chunk-7ZHH77QA.js";
66
- import "./chunk-L3GAGWCC.js";
67
67
  import {
68
68
  effect
69
- } from "./chunk-X4JS367G.js";
70
- import "./chunk-S3NFJO6L.js";
69
+ } from "./chunk-XDOMTQHM.js";
70
+ import "./chunk-TIRZCERI.js";
71
71
  import {
72
72
  registerDisposer
73
- } from "./chunk-5VGSK6D2.js";
73
+ } from "./chunk-DHDZ7IVN.js";
74
74
  import {
75
75
  signal
76
- } from "./chunk-335KJEN2.js";
77
- import "./chunk-BQLVTAUZ.js";
78
- import "./chunk-COY6PUD2.js";
76
+ } from "./chunk-TVURNWDK.js";
77
+ import "./chunk-JYXQCELN.js";
78
+ import "./chunk-VPP2FONR.js";
79
79
 
80
80
  // src/ui/formAction.ts
81
81
  function formAction(fn) {
package/dist/widgets.cjs CHANGED
@@ -62,8 +62,95 @@ function devWarn(message) {
62
62
  }
63
63
  }
64
64
 
65
+ // src/core/errors.ts
66
+ var ERROR_STATE_KEY = /* @__PURE__ */ Symbol.for("sibujs.runtime-errors.v1");
67
+ function state() {
68
+ const g = globalThis;
69
+ const existing = g[ERROR_STATE_KEY];
70
+ if (existing) return existing;
71
+ const created = { handler: null, handlerDepth: 0 };
72
+ g[ERROR_STATE_KEY] = created;
73
+ return created;
74
+ }
75
+ function normalizeError(value) {
76
+ if (value instanceof Error) return value;
77
+ const message = typeof value === "string" ? value : `Non-Error value thrown: ${safeStringify(value)}`;
78
+ return new Error(message, { cause: value });
79
+ }
80
+ function safeStringify(value) {
81
+ if (typeof value === "symbol") return value.toString();
82
+ try {
83
+ return typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
84
+ } catch {
85
+ return Object.prototype.toString.call(value);
86
+ }
87
+ }
88
+ function describe(context) {
89
+ return context.name ? `${context.phase} "${context.name}"` : context.phase;
90
+ }
91
+ var REACTIVE_REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
92
+ function untrackedRun(fn) {
93
+ const api = globalThis[REACTIVE_REGISTRY_KEY];
94
+ return api?.untracked ? api.untracked(fn) : fn();
95
+ }
96
+ var PROPAGATE_EVENT = "sibu:error-propagate";
97
+ function claimedByBoundary(error, context) {
98
+ const raw = context.node;
99
+ if (!raw || typeof CustomEvent === "undefined") return false;
100
+ const target = resolveEventTarget(raw);
101
+ if (!target) return false;
102
+ try {
103
+ const event = new CustomEvent(PROPAGATE_EVENT, {
104
+ bubbles: true,
105
+ cancelable: true,
106
+ detail: { error, context }
107
+ });
108
+ return target.dispatchEvent(event) === false;
109
+ } catch {
110
+ return false;
111
+ }
112
+ }
113
+ function resolveEventTarget(node) {
114
+ const ELEMENT_NODE = 1;
115
+ let current = node;
116
+ while (current) {
117
+ if (current.nodeType === ELEMENT_NODE && typeof current.dispatchEvent === "function") {
118
+ return current;
119
+ }
120
+ current = current.parentNode;
121
+ }
122
+ const self = node;
123
+ return typeof self.dispatchEvent === "function" ? self : null;
124
+ }
125
+ function defaultReport(error, context) {
126
+ if (typeof console === "undefined") return;
127
+ console.error(`[SibuJS] Uncaught error during ${describe(context)}: ${error.message}`, error);
128
+ }
129
+ function reportError(error, context) {
130
+ const err = normalizeError(error);
131
+ untrackedRun(() => {
132
+ if (claimedByBoundary(err, context)) return;
133
+ const s = state();
134
+ const handler = s.handler;
135
+ if (handler && s.handlerDepth === 0) {
136
+ s.handlerDepth++;
137
+ try {
138
+ handler(error instanceof Error ? error : err, context);
139
+ return;
140
+ } catch (handlerError) {
141
+ if (typeof console !== "undefined") {
142
+ const detail = handlerError instanceof Error ? handlerError.message : String(handlerError);
143
+ console.error(`[SibuJS] runtime error handler itself threw: ${detail}`, handlerError);
144
+ }
145
+ } finally {
146
+ s.handlerDepth--;
147
+ }
148
+ }
149
+ defaultReport(err, context);
150
+ });
151
+ }
152
+
65
153
  // src/reactivity/track-core.ts
66
- var _isDev2 = isDev();
67
154
  var POOL_MAX = 4096;
68
155
  var nodePool = [];
69
156
  function createNode() {
@@ -71,6 +158,7 @@ function createNode() {
71
158
  sig: null,
72
159
  sub: null,
73
160
  epoch: 0,
161
+ depVersion: 0,
74
162
  sigPrev: null,
75
163
  sigNext: null,
76
164
  subPrev: null,
@@ -155,9 +243,28 @@ function safeInvoke(sub) {
155
243
  try {
156
244
  sub();
157
245
  } catch (err) {
158
- if (_isDev2) devWarn(`Subscriber threw during notification: ${err instanceof Error ? err.message : String(err)}`);
246
+ const s = sub;
247
+ reportError(err, { phase: s._errorPhase ?? "effect", name: s.__name, node: s._errorNode });
159
248
  }
160
249
  }
250
+ function depsChanged(sub) {
251
+ let node = sub.depsHead ?? null;
252
+ if (node === null) return true;
253
+ while (node !== null) {
254
+ const sig = node.sig;
255
+ if (sig === null) return true;
256
+ if (sig._d === true && sig._validate !== void 0) {
257
+ try {
258
+ sig._validate();
259
+ } catch {
260
+ return true;
261
+ }
262
+ }
263
+ if (node.depVersion !== sig.__v) return true;
264
+ node = node.subNext;
265
+ }
266
+ return false;
267
+ }
161
268
  var suspendDepth = 0;
162
269
  var trackingSuspended = false;
163
270
  function suspendTracking() {
@@ -238,7 +345,7 @@ function track(effectFn, subscriber) {
238
345
  const sub = subscriber;
239
346
  return sub._dispose ?? (sub._dispose = () => cleanup(subscriber));
240
347
  }
241
- function reactiveBinding(commit) {
348
+ function reactiveBinding(commit, ownerNode) {
242
349
  const run = () => {
243
350
  const s = subscriber;
244
351
  if (s._disposed || s._reentrant) return;
@@ -254,13 +361,17 @@ function reactiveBinding(commit) {
254
361
  subscriber.depsTail = null;
255
362
  subscriber._epoch = 0;
256
363
  subscriber._structDirty = false;
364
+ subscriber._hasComputedDep = false;
257
365
  subscriber._runEpoch = 0;
258
366
  subscriber._runs = 0;
259
367
  subscriber._reentrant = false;
260
368
  subscriber._disposed = false;
369
+ subscriber._errorPhase = "binding";
370
+ subscriber._errorNode = ownerNode;
261
371
  run();
262
372
  return subscriber._dispose ?? (subscriber._dispose = () => {
263
373
  subscriber._disposed = true;
374
+ subscriber._errorNode = void 0;
264
375
  cleanup(subscriber);
265
376
  });
266
377
  }
@@ -272,9 +383,12 @@ function recordDependency(signal2) {
272
383
  const active = sig.__activeNode ?? null;
273
384
  if (active !== null && active.sub === sub) {
274
385
  active.epoch = epoch;
386
+ active.depVersion = sig.__v ?? Number.NaN;
275
387
  return;
276
388
  }
389
+ if (sig._validate !== void 0) sub._hasComputedDep = true;
277
390
  const node = allocNode(signal2, sub, epoch);
391
+ node.depVersion = sig.__v ?? Number.NaN;
278
392
  node.prevActive = active;
279
393
  sig.__activeNode = node;
280
394
  linkSub(sub, node);
@@ -293,9 +407,10 @@ function cleanup(subscriber) {
293
407
  node = next;
294
408
  }
295
409
  }
296
- var maxSubscriberRepeats = 50;
410
+ var maxSubscriberRepeats = 1e3;
297
411
  var maxDrainIterations = 1e6;
298
412
  var drainEpoch = 0;
413
+ var quarantined = /* @__PURE__ */ new Set();
299
414
  function setMaxSubscriberRepeats(n) {
300
415
  const prev = maxSubscriberRepeats;
301
416
  if (Number.isFinite(n) && n > 0) maxSubscriberRepeats = Math.floor(n);
@@ -317,19 +432,21 @@ function tickRepeat(sub) {
317
432
  return s._runs > maxSubscriberRepeats;
318
433
  }
319
434
  function cycleError(sub) {
320
- if (typeof console !== "undefined") {
321
- const name = sub.__name ?? "<unnamed>";
322
- console.error(
323
- `[SibuJS] subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. Breaking to prevent infinite loop.`
324
- );
325
- }
435
+ const name = sub.__name ?? "<unnamed>";
436
+ reportError(
437
+ new Error(
438
+ `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.`
439
+ ),
440
+ { phase: "scheduler", name }
441
+ );
326
442
  }
327
443
  function absoluteDrainError() {
328
- if (typeof console !== "undefined") {
329
- console.error(
330
- `[SibuJS] Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
331
- );
332
- }
444
+ reportError(
445
+ new Error(
446
+ `Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
447
+ ),
448
+ { phase: "scheduler" }
449
+ );
333
450
  }
334
451
  function drainQueue() {
335
452
  let i = 0;
@@ -339,11 +456,14 @@ function drainQueue() {
339
456
  break;
340
457
  }
341
458
  const sub = pendingQueue[i++];
459
+ pendingSet.delete(sub);
460
+ if (quarantined.size > 0 && quarantined.has(sub)) continue;
461
+ if (sub._hasComputedDep === true && !depsChanged(sub)) continue;
342
462
  if (tickRepeat(sub)) {
343
463
  cycleError(sub);
344
- break;
464
+ quarantined.add(sub);
465
+ continue;
345
466
  }
346
- pendingSet.delete(sub);
347
467
  safeInvoke(sub);
348
468
  }
349
469
  }
@@ -358,6 +478,7 @@ function drainNotificationQueue() {
358
478
  if (notifyDepth === 0) {
359
479
  pendingQueue.length = 0;
360
480
  pendingSet.clear();
481
+ if (quarantined.size > 0) quarantined.clear();
361
482
  }
362
483
  }
363
484
  }
@@ -451,6 +572,7 @@ function notifySubscribers(signal2) {
451
572
  if (notifyDepth === 0) {
452
573
  pendingQueue.length = 0;
453
574
  pendingSet.clear();
575
+ if (quarantined.size > 0) quarantined.clear();
454
576
  }
455
577
  }
456
578
  }
@@ -477,14 +599,14 @@ function forEachSubscriber(signal2, visit) {
477
599
  }
478
600
 
479
601
  // src/reactivity/track.ts
480
- var _isDev3 = isDev();
481
- var _runtimeVersion = true ? "3.4.1" : "dev";
602
+ var _isDev2 = isDev();
603
+ var _runtimeVersion = true ? "4.0.1" : "dev";
482
604
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
483
605
  function resolveReactiveApi() {
484
606
  const g = globalThis;
485
607
  const existing = g[REGISTRY_KEY];
486
608
  if (existing) {
487
- if (_isDev3 && !existing.__dupWarned) {
609
+ if (_isDev2 && !existing.__dupWarned) {
488
610
  existing.__dupWarned = true;
489
611
  devWarn(
490
612
  `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']).`
@@ -569,6 +691,21 @@ function derived(getter, options) {
569
691
  }, markDirty);
570
692
  const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
571
693
  let evaluating = false;
694
+ const validate = () => {
695
+ if (!cs._d) return;
696
+ const oldValue = cs._v;
697
+ evaluating = true;
698
+ try {
699
+ retrack2(recompute, markDirty);
700
+ if (!Object.is(oldValue, cs._v)) cs.__v++;
701
+ } finally {
702
+ evaluating = false;
703
+ }
704
+ if (hook && !Object.is(oldValue, cs._v)) {
705
+ hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
706
+ }
707
+ };
708
+ cs._validate = validate;
572
709
  function computedGetter() {
573
710
  if (evaluating) {
574
711
  throw new Error(
@@ -576,32 +713,11 @@ function derived(getter, options) {
576
713
  );
577
714
  }
578
715
  if (isTrackingSuspended2()) {
579
- if (cs._d) {
580
- const prev = cs._v;
581
- evaluating = true;
582
- try {
583
- retrack2(recompute, markDirty);
584
- if (!Object.is(prev, cs._v)) cs.__v++;
585
- } finally {
586
- evaluating = false;
587
- }
588
- }
716
+ if (cs._d) validate();
589
717
  return cs._v;
590
718
  }
719
+ if (cs._d) validate();
591
720
  recordDependency2(cs);
592
- if (cs._d) {
593
- const oldValue = cs._v;
594
- evaluating = true;
595
- try {
596
- retrack2(recompute, markDirty);
597
- if (!Object.is(oldValue, cs._v)) cs.__v++;
598
- } finally {
599
- evaluating = false;
600
- }
601
- if (hook && oldValue !== cs._v) {
602
- hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
603
- }
604
- }
605
721
  return cs._v;
606
722
  }
607
723
  if (debugName) {
@@ -623,20 +739,24 @@ function detectSSRShared() {
623
739
  const getBuiltin = process.getBuiltinModule;
624
740
  if (typeof getBuiltin === "function") {
625
741
  mod = getBuiltin("node:async_hooks");
626
- } else {
627
- const req = Function("return typeof require==='function'?require:null")();
628
- if (req) mod = req("node:async_hooks");
742
+ } else if (typeof require === "function") {
743
+ mod = require("async_hooks");
629
744
  }
630
745
  if (mod) detected = new mod.AsyncLocalStorage();
631
746
  }
632
747
  } catch {
633
748
  detected = null;
634
749
  }
635
- return { als: detected, fallbackStore: { ssr: false, suspenseIdCounter: 0 } };
750
+ return {
751
+ als: detected,
752
+ fallbackStore: { ssr: false, suspenseIdCounter: 0, locale: void 0 },
753
+ fallbackDepth: 0
754
+ };
636
755
  }
637
756
  var _shared = globalThis[SSR_KEY] ?? (globalThis[SSR_KEY] = detectSSRShared());
638
757
  var als = _shared.als;
639
758
  var fallbackStore = _shared.fallbackStore;
759
+ _shared.fallbackDepth ?? (_shared.fallbackDepth = 0);
640
760
  function getSSRStore() {
641
761
  if (als) {
642
762
  const s = als.getStore();
@@ -659,7 +779,7 @@ function flushUserCleanups(ctx) {
659
779
  try {
660
780
  list[i]();
661
781
  } catch (err) {
662
- if (typeof console !== "undefined") console.warn("[SibuJS effect] onCleanup threw:", err);
782
+ reportError(err, { phase: "cleanup" });
663
783
  }
664
784
  }
665
785
  }
@@ -672,11 +792,12 @@ function drainReruns(ctx) {
672
792
  } while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
673
793
  if (ctx.rerunPending) {
674
794
  ctx.rerunPending = false;
675
- if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
676
- console.error(
677
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
678
- );
679
- }
795
+ reportError(
796
+ new Error(
797
+ `effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
798
+ ),
799
+ { phase: "effect" }
800
+ );
680
801
  }
681
802
  }
682
803
  function disposeEffect(ctx) {
@@ -753,6 +874,8 @@ function effect(effectFn, options) {
753
874
  sub.depsTail = null;
754
875
  sub._epoch = 0;
755
876
  sub._structDirty = false;
877
+ sub._hasComputedDep = false;
878
+ sub._errorPhase = "effect";
756
879
  sub._runEpoch = 0;
757
880
  sub._runs = 0;
758
881
  ctx.subscriber = sub;
@@ -821,70 +944,72 @@ var isBatching = API2.isBatching;
821
944
 
822
945
  // src/core/signals/signal.ts
823
946
  var _g2 = globalThis;
824
- var _isDev4 = isDev();
947
+ var _isDev3 = isDev();
825
948
  function signal(initial, options) {
826
- const state = {
949
+ const state2 = {
827
950
  value: initial,
828
951
  __v: 0,
829
952
  __sc: 0,
830
953
  subsHead: null,
831
954
  subsTail: null,
832
955
  __activeNode: null,
833
- __name: void 0
956
+ __name: void 0,
957
+ _d: false,
958
+ _validate: void 0
834
959
  };
835
- const debugName = _isDev4 ? options?.name : void 0;
960
+ const debugName = _isDev3 ? options?.name : void 0;
836
961
  const equalsFn = options?.equals;
837
- if (debugName) state.__name = debugName;
962
+ if (debugName) state2.__name = debugName;
838
963
  function get() {
839
- recordDependency2(state);
840
- return state.value;
964
+ recordDependency2(state2);
965
+ return state2.value;
841
966
  }
842
- get.__signal = state;
967
+ get.__signal = state2;
843
968
  if (debugName) get.__name = debugName;
844
969
  let set;
845
970
  if (equalsFn) {
846
971
  set = (next) => {
847
- const prev = state.value;
972
+ const prev = state2.value;
848
973
  const newValue = typeof next === "function" ? next(prev) : next;
849
974
  if (equalsFn(prev, newValue)) return;
850
- state.value = newValue;
851
- state.__v++;
852
- if (_isDev4) {
975
+ state2.value = newValue;
976
+ state2.__v++;
977
+ if (_isDev3) {
853
978
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
854
- if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
979
+ if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
855
980
  }
856
- if (!enqueueBatchedSignal(state)) {
857
- notifySubscribers2(state);
981
+ if (!enqueueBatchedSignal(state2)) {
982
+ notifySubscribers2(state2);
858
983
  }
859
984
  };
860
- } else if (_isDev4) {
985
+ } else if (_isDev3) {
861
986
  set = (next) => {
862
- const prev = state.value;
987
+ const prev = state2.value;
863
988
  const newValue = typeof next === "function" ? next(prev) : next;
864
989
  if (Object.is(newValue, prev)) return;
865
- state.value = newValue;
866
- state.__v++;
990
+ state2.value = newValue;
991
+ state2.__v++;
867
992
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
868
- if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
869
- if (!enqueueBatchedSignal(state)) {
870
- notifySubscribers2(state);
993
+ if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
994
+ if (!enqueueBatchedSignal(state2)) {
995
+ notifySubscribers2(state2);
871
996
  }
872
997
  };
873
998
  } else {
874
999
  set = (next) => {
875
- const prev = state.value;
1000
+ const prev = state2.value;
876
1001
  const newValue = typeof next === "function" ? next(prev) : next;
877
1002
  if (Object.is(newValue, prev)) return;
878
- state.value = newValue;
879
- state.__v++;
880
- if (!enqueueBatchedSignal(state)) {
881
- notifySubscribers2(state);
1003
+ state2.value = newValue;
1004
+ state2.__v++;
1005
+ if (!enqueueBatchedSignal(state2)) {
1006
+ notifySubscribers2(state2);
882
1007
  }
883
1008
  };
884
1009
  }
885
- if (_isDev4) {
1010
+ if (_isDev3) {
886
1011
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
887
- if (hook) hook.emit("signal:create", { signal: state, name: debugName, getter: get, initial });
1012
+ if (hook) hook.emit("signal:create", { signal: state2, name: debugName, getter: get, initial });
888
1013
  }
889
1014
  return [get, set];
890
1015
  }
package/dist/widgets.js CHANGED
@@ -8,16 +8,16 @@ import {
8
8
  select,
9
9
  tabs,
10
10
  tooltip
11
- } from "./chunk-5MFF5EPT.js";
12
- import "./chunk-QHPUFNHZ.js";
11
+ } from "./chunk-J4WZMCIW.js";
12
+ import "./chunk-PTLJ7NQX.js";
13
13
  import "./chunk-CCSJMTRN.js";
14
- import "./chunk-4I3M326N.js";
15
- import "./chunk-L3GAGWCC.js";
16
- import "./chunk-X4JS367G.js";
17
- import "./chunk-S3NFJO6L.js";
18
- import "./chunk-335KJEN2.js";
19
- import "./chunk-BQLVTAUZ.js";
20
- import "./chunk-COY6PUD2.js";
14
+ import "./chunk-AD5YSZAN.js";
15
+ import "./chunk-5INI7D2L.js";
16
+ import "./chunk-XDOMTQHM.js";
17
+ import "./chunk-TIRZCERI.js";
18
+ import "./chunk-TVURNWDK.js";
19
+ import "./chunk-JYXQCELN.js";
20
+ import "./chunk-VPP2FONR.js";
21
21
  export {
22
22
  accordion,
23
23
  combobox,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sibujs",
3
- "version": "3.4.1",
3
+ "version": "4.0.1",
4
4
  "description": "A lightweight, function-based frontend framework that combines the best of React, Svelte, and Vue — with zero VDOM and maximum simplicity. Designed for developers who want fine-grained reactivity and full control without compilation or magic.",
5
5
  "keywords": [
6
6
  "frontend",
@@ -35,6 +35,11 @@
35
35
  "test:ui": "vitest --ui",
36
36
  "test:browser": "npm run build && playwright test",
37
37
  "test:browser:install": "playwright install chromium firefox webkit",
38
+ "test:soak": "vitest run -c vitest.soak.config.ts",
39
+ "test:soak:gc": "node --expose-gc ./node_modules/vitest/vitest.mjs run -c vitest.soak.config.ts",
40
+ "typecheck": "tsc --noEmit",
41
+ "typecheck:tests": "tsc -p tsconfig.test.json",
42
+ "certify:rc": "node scripts/certify/run.mjs",
38
43
  "build": "tsup index.ts data.ts browser.ts patterns.ts motion.ts ui.ts widgets.ts ssr.ts devtools.ts performance.ts ecosystem.ts plugins.ts build.ts testing.ts extras.ts --dts --format esm,cjs --out-dir dist --clean && tsup cdn.ts --format iife --globalName Sibu --out-dir dist --no-dts --minify",
39
44
  "bench": "node bench.mjs",
40
45
  "bench:save": "node bench.mjs --save",
@@ -127,18 +132,18 @@
127
132
  "access": "public"
128
133
  },
129
134
  "browserslist": [
130
- "Chrome >= 80",
131
- "Firefox >= 78",
132
- "Safari >= 14",
133
- "Edge >= 80"
135
+ "Chrome >= 93",
136
+ "Firefox >= 92",
137
+ "Safari >= 15.4",
138
+ "Edge >= 93"
134
139
  ],
135
140
  "engines": {
136
- "node": ">=18.0.0"
141
+ "node": ">=22.3.0"
137
142
  },
138
143
  "devDependencies": {
139
144
  "@biomejs/biome": "2.4.7",
140
145
  "@playwright/test": "^1.61.1",
141
- "@types/node": "^25.5.0",
146
+ "@types/node": "^22.20.1",
142
147
  "@vitest/coverage-v8": "^3.1.3",
143
148
  "@vitest/ui": "^3.1.3",
144
149
  "fake-indexeddb": "^6.2.5",