sibujs 1.5.0 → 2.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 (207) hide show
  1. package/dist/browser.cjs +238 -69
  2. package/dist/browser.d.cts +5 -0
  3. package/dist/browser.d.ts +5 -0
  4. package/dist/browser.js +6 -6
  5. package/dist/build.cjs +916 -292
  6. package/dist/build.js +15 -13
  7. package/dist/cdn.global.js +17 -16
  8. package/dist/chunk-2RA7SHDA.js +65 -0
  9. package/dist/chunk-2UPRY23K.js +80 -0
  10. package/dist/chunk-3JHCYHWN.js +125 -0
  11. package/dist/{chunk-VAPYJN4X.js → chunk-3LR7GLWQ.js} +93 -23
  12. package/dist/{chunk-RJ46C3CS.js → chunk-3NSGB5JN.js} +71 -20
  13. package/dist/{chunk-XUEEGU5O.js → chunk-52YJLLRO.js} +16 -4
  14. package/dist/{chunk-XHK6BDAJ.js → chunk-54EDRCEF.js} +25 -8
  15. package/dist/chunk-7JDB7I65.js +1327 -0
  16. package/dist/{chunk-WZSPOOER.js → chunk-CC65Y57T.js} +8 -5
  17. package/dist/{chunk-23VV7YD3.js → chunk-DFPFITST.js} +25 -30
  18. package/dist/{chunk-BGN5ZMP4.js → chunk-GTBNNBJ6.js} +14 -2
  19. package/dist/chunk-HB24TBAF.js +121 -0
  20. package/dist/{chunk-CZUGLNJS.js → chunk-ITX6OO3F.js} +3 -3
  21. package/dist/{chunk-BGTHZHJ5.js → chunk-JA6667UN.js} +188 -44
  22. package/dist/{chunk-7GRNSCFT.js → chunk-JXMMDLBY.js} +306 -183
  23. package/dist/{chunk-3X2YG6YM.js → chunk-JYD2PWXH.js} +59 -28
  24. package/dist/{chunk-SFKNRVCU.js → chunk-KLRMB5ZS.js} +135 -79
  25. package/dist/{chunk-5X6PP2UK.js → chunk-LMLD24FC.js} +2 -2
  26. package/dist/{chunk-M4NLBH4I.js → chunk-LYTCUZ7H.js} +3 -2
  27. package/dist/{chunk-BMPL52BF.js → chunk-MIUAXB7K.js} +118 -66
  28. package/dist/{chunk-JCDUJN2F.js → chunk-ND2664SF.js} +486 -153
  29. package/dist/{chunk-VQDZK23A.js → chunk-O2MNQFLP.js} +181 -66
  30. package/dist/{chunk-NHUC2QWH.js → chunk-R73P76YZ.js} +1 -1
  31. package/dist/{chunk-2BYQDGN3.js → chunk-SAHNHTFC.js} +234 -63
  32. package/dist/chunk-UCS6AMJ7.js +79 -0
  33. package/dist/{chunk-K4G4ZQNR.js → chunk-VLPPXTYG.js} +84 -38
  34. package/dist/{chunk-OUZZEE4S.js → chunk-WOMYAHHI.js} +17 -11
  35. package/dist/{customElement-BL3Uo8dL.d.cts → customElement-CPfIrbvg.d.cts} +14 -10
  36. package/dist/{customElement-BL3Uo8dL.d.ts → customElement-CPfIrbvg.d.ts} +14 -10
  37. package/dist/data.cjs +410 -99
  38. package/dist/data.d.cts +20 -2
  39. package/dist/data.d.ts +20 -2
  40. package/dist/data.js +11 -9
  41. package/dist/devtools.cjs +513 -223
  42. package/dist/devtools.d.cts +1 -1
  43. package/dist/devtools.d.ts +1 -1
  44. package/dist/devtools.js +12 -6
  45. package/dist/ecosystem.cjs +475 -144
  46. package/dist/ecosystem.d.cts +9 -7
  47. package/dist/ecosystem.d.ts +9 -7
  48. package/dist/ecosystem.js +12 -11
  49. package/dist/extras.cjs +3355 -1541
  50. package/dist/extras.d.cts +9 -9
  51. package/dist/extras.d.ts +9 -9
  52. package/dist/extras.js +58 -45
  53. package/dist/index.cjs +920 -292
  54. package/dist/index.d.cts +71 -8
  55. package/dist/index.d.ts +71 -8
  56. package/dist/index.js +28 -16
  57. package/dist/{introspect-BumjnBKr.d.cts → introspect-BWNjNw64.d.cts} +22 -2
  58. package/dist/{introspect-CZrlcaYy.d.ts → introspect-cY2pg9pW.d.ts} +22 -2
  59. package/dist/motion.cjs +77 -34
  60. package/dist/motion.js +4 -4
  61. package/dist/patterns.cjs +335 -69
  62. package/dist/patterns.d.cts +11 -12
  63. package/dist/patterns.d.ts +11 -12
  64. package/dist/patterns.js +7 -7
  65. package/dist/performance.cjs +279 -108
  66. package/dist/performance.d.cts +23 -16
  67. package/dist/performance.d.ts +23 -16
  68. package/dist/performance.js +13 -8
  69. package/dist/plugin-D30wlGW5.d.cts +71 -0
  70. package/dist/plugin-D30wlGW5.d.ts +71 -0
  71. package/dist/plugins.cjs +635 -260
  72. package/dist/plugins.d.cts +10 -3
  73. package/dist/plugins.d.ts +10 -3
  74. package/dist/plugins.js +106 -38
  75. package/dist/{ssr-Do_SiVoL.d.cts → ssr-CrVNy6Pa.d.cts} +9 -15
  76. package/dist/{ssr-Do_SiVoL.d.ts → ssr-CrVNy6Pa.d.ts} +9 -15
  77. package/dist/{ssr-4PBXAOO3.js → ssr-FXD2PPMC.js} +4 -3
  78. package/dist/ssr.cjs +642 -222
  79. package/dist/ssr.d.cts +26 -6
  80. package/dist/ssr.d.ts +26 -6
  81. package/dist/ssr.js +12 -11
  82. package/dist/{tagFactory-DaJ0YWX6.d.cts → tagFactory-S17H2qxu.d.cts} +9 -1
  83. package/dist/{tagFactory-DaJ0YWX6.d.ts → tagFactory-S17H2qxu.d.ts} +9 -1
  84. package/dist/testing.cjs +252 -63
  85. package/dist/testing.d.cts +17 -4
  86. package/dist/testing.d.ts +17 -4
  87. package/dist/testing.js +100 -44
  88. package/dist/ui.cjs +463 -137
  89. package/dist/ui.d.cts +1 -1
  90. package/dist/ui.d.ts +1 -1
  91. package/dist/ui.js +20 -17
  92. package/dist/widgets.cjs +977 -94
  93. package/dist/widgets.d.cts +104 -2
  94. package/dist/widgets.d.ts +104 -2
  95. package/dist/widgets.js +9 -7
  96. package/package.json +8 -2
  97. package/dist/chunk-32DY64NT.js +0 -282
  98. package/dist/chunk-3AIRKM3B.js +0 -1263
  99. package/dist/chunk-3ARAQO7B.js +0 -398
  100. package/dist/chunk-3CRQALYP.js +0 -877
  101. package/dist/chunk-4EI4AG32.js +0 -482
  102. package/dist/chunk-4MYMUBRS.js +0 -21
  103. package/dist/chunk-5ZYQ6KDD.js +0 -154
  104. package/dist/chunk-6BMPXPUW.js +0 -26
  105. package/dist/chunk-6HLLIF3K.js +0 -398
  106. package/dist/chunk-6LSNVCS2.js +0 -937
  107. package/dist/chunk-6SA3QQES.js +0 -61
  108. package/dist/chunk-77L6NL3X.js +0 -1097
  109. package/dist/chunk-7BF6TK55.js +0 -1097
  110. package/dist/chunk-7TQKR4PP.js +0 -294
  111. package/dist/chunk-7V26P53V.js +0 -712
  112. package/dist/chunk-AZ3ISID5.js +0 -298
  113. package/dist/chunk-B7SWRFUT.js +0 -332
  114. package/dist/chunk-BTU3TJDS.js +0 -365
  115. package/dist/chunk-BW3WT46K.js +0 -937
  116. package/dist/chunk-C6KFWOFV.js +0 -616
  117. package/dist/chunk-CHF5OHIA.js +0 -61
  118. package/dist/chunk-CHJ27IGK.js +0 -26
  119. package/dist/chunk-CMBFNA7L.js +0 -27
  120. package/dist/chunk-DAHRH4ON.js +0 -331
  121. package/dist/chunk-DKOHBI74.js +0 -924
  122. package/dist/chunk-DTCOOBMX.js +0 -725
  123. package/dist/chunk-EBGIRKQY.js +0 -616
  124. package/dist/chunk-EUZND3CB.js +0 -27
  125. package/dist/chunk-EVCZO745.js +0 -365
  126. package/dist/chunk-EWFVA3TJ.js +0 -282
  127. package/dist/chunk-F3FA4F32.js +0 -292
  128. package/dist/chunk-FGOEVHY3.js +0 -60
  129. package/dist/chunk-G3BOQPVO.js +0 -365
  130. package/dist/chunk-GCOK2LC3.js +0 -282
  131. package/dist/chunk-GJPXRJ45.js +0 -37
  132. package/dist/chunk-HGMJFBC7.js +0 -654
  133. package/dist/chunk-JAKHTMQU.js +0 -1000
  134. package/dist/chunk-JCI5M6U6.js +0 -956
  135. package/dist/chunk-K5ZUMYVS.js +0 -89
  136. package/dist/chunk-KQPDEVVS.js +0 -398
  137. package/dist/chunk-L6JRBDNS.js +0 -60
  138. package/dist/chunk-LA6KQEDU.js +0 -712
  139. package/dist/chunk-MB6QFH3I.js +0 -2776
  140. package/dist/chunk-MDVXJWFN.js +0 -304
  141. package/dist/chunk-MEZVEBPN.js +0 -2008
  142. package/dist/chunk-MK4ERFYL.js +0 -2249
  143. package/dist/chunk-MLKGABMK.js +0 -9
  144. package/dist/chunk-MQ5GOYPH.js +0 -2249
  145. package/dist/chunk-MYRV7VDM.js +0 -742
  146. package/dist/chunk-N6IZB6KJ.js +0 -567
  147. package/dist/chunk-NEKUBFPT.js +0 -60
  148. package/dist/chunk-NMRUZALC.js +0 -1097
  149. package/dist/chunk-NYVAC6P5.js +0 -37
  150. package/dist/chunk-NZIIMDWI.js +0 -84
  151. package/dist/chunk-OF7UZIVB.js +0 -725
  152. package/dist/chunk-P3XWXJZU.js +0 -282
  153. package/dist/chunk-P6W3STU4.js +0 -2249
  154. package/dist/chunk-PBHF5WKN.js +0 -616
  155. package/dist/chunk-PDZQY43A.js +0 -616
  156. package/dist/chunk-PTQJDMRT.js +0 -146
  157. package/dist/chunk-PZEGYCF5.js +0 -61
  158. package/dist/chunk-QBMDLBU2.js +0 -975
  159. package/dist/chunk-QWZG56ET.js +0 -2744
  160. package/dist/chunk-RQGQSLQK.js +0 -725
  161. package/dist/chunk-SDLZDHKP.js +0 -107
  162. package/dist/chunk-TDGZL5CU.js +0 -365
  163. package/dist/chunk-TNQWPPE6.js +0 -37
  164. package/dist/chunk-TSOKIX5Z.js +0 -654
  165. package/dist/chunk-UHNL42EF.js +0 -2730
  166. package/dist/chunk-UNXCEF6S.js +0 -21
  167. package/dist/chunk-V2XTI523.js +0 -347
  168. package/dist/chunk-VAU366PN.js +0 -2241
  169. package/dist/chunk-VMVDTCXB.js +0 -712
  170. package/dist/chunk-VQNQZCWJ.js +0 -61
  171. package/dist/chunk-VRW3FULF.js +0 -725
  172. package/dist/chunk-WADYRCO2.js +0 -304
  173. package/dist/chunk-WILQZRO4.js +0 -282
  174. package/dist/chunk-WR5D4EGH.js +0 -26
  175. package/dist/chunk-WUHJISPP.js +0 -298
  176. package/dist/chunk-XYU6TZOW.js +0 -182
  177. package/dist/chunk-Y6GP4QGG.js +0 -276
  178. package/dist/chunk-YECR7UIA.js +0 -347
  179. package/dist/chunk-YUTWTI4B.js +0 -654
  180. package/dist/chunk-Z65KYU7I.js +0 -26
  181. package/dist/chunk-Z6POF5YC.js +0 -975
  182. package/dist/chunk-ZBJP6WFL.js +0 -482
  183. package/dist/chunk-ZD6OAMTH.js +0 -277
  184. package/dist/chunk-ZWKZCBO6.js +0 -317
  185. package/dist/contracts-DDrwxvJ-.d.cts +0 -245
  186. package/dist/contracts-DDrwxvJ-.d.ts +0 -245
  187. package/dist/contracts-DOrhwbke.d.cts +0 -245
  188. package/dist/contracts-DOrhwbke.d.ts +0 -245
  189. package/dist/contracts-xo5ckdRP.d.cts +0 -240
  190. package/dist/contracts-xo5ckdRP.d.ts +0 -240
  191. package/dist/customElement-BKQfbSZQ.d.cts +0 -262
  192. package/dist/customElement-BKQfbSZQ.d.ts +0 -262
  193. package/dist/customElement-D2DJp_xn.d.cts +0 -313
  194. package/dist/customElement-D2DJp_xn.d.ts +0 -313
  195. package/dist/customElement-yz8uyk-0.d.cts +0 -308
  196. package/dist/customElement-yz8uyk-0.d.ts +0 -308
  197. package/dist/introspect-Cb0zgpi2.d.cts +0 -477
  198. package/dist/introspect-Y2xNXGSf.d.ts +0 -477
  199. package/dist/plugin-Bek4RhJY.d.cts +0 -43
  200. package/dist/plugin-Bek4RhJY.d.ts +0 -43
  201. package/dist/ssr-3RXHP5ES.js +0 -38
  202. package/dist/ssr-6GIMY5MX.js +0 -38
  203. package/dist/ssr-BA6sxxUd.d.cts +0 -135
  204. package/dist/ssr-BA6sxxUd.d.ts +0 -135
  205. package/dist/ssr-WKUPVSSK.js +0 -36
  206. package/dist/tagFactory-Dl8QCLga.d.cts +0 -23
  207. package/dist/tagFactory-Dl8QCLga.d.ts +0 -23
package/dist/patterns.cjs CHANGED
@@ -50,12 +50,12 @@ function isDev() {
50
50
  var _isDev = isDev();
51
51
  function devAssert(condition, message) {
52
52
  if (_isDev && !condition) {
53
- throw new Error(`[Sibu] ${message}`);
53
+ throw new Error(`[SibuJS] ${message}`);
54
54
  }
55
55
  }
56
56
  function devWarn(message) {
57
57
  if (_isDev) {
58
- console.warn(`[Sibu] ${message}`);
58
+ console.warn(`[SibuJS] ${message}`);
59
59
  }
60
60
  }
61
61
 
@@ -65,11 +65,11 @@ var subscriberStack = new Array(32);
65
65
  var stackCapacity = 32;
66
66
  var stackTop = -1;
67
67
  var currentSubscriber = null;
68
- var signalSubscribers = /* @__PURE__ */ new WeakMap();
69
68
  var SUBS = "__s";
70
69
  var notifyDepth = 0;
71
70
  var pendingQueue = [];
72
71
  var pendingSet = /* @__PURE__ */ new Set();
72
+ var propagateStack = [];
73
73
  function safeInvoke(sub) {
74
74
  try {
75
75
  sub();
@@ -78,6 +78,15 @@ function safeInvoke(sub) {
78
78
  }
79
79
  }
80
80
  var trackingSuspended = false;
81
+ function retrack(effectFn, subscriber) {
82
+ const prev = currentSubscriber;
83
+ currentSubscriber = subscriber;
84
+ try {
85
+ effectFn();
86
+ } finally {
87
+ currentSubscriber = prev;
88
+ }
89
+ }
81
90
  function track(effectFn, subscriber) {
82
91
  if (!subscriber) subscriber = effectFn;
83
92
  cleanup(subscriber);
@@ -116,7 +125,6 @@ function recordDependency(signal2) {
116
125
  let subs = signal2[SUBS];
117
126
  if (!subs) {
118
127
  subs = /* @__PURE__ */ new Set();
119
- signalSubscribers.set(signal2, subs);
120
128
  signal2[SUBS] = subs;
121
129
  }
122
130
  subs.add(currentSubscriber);
@@ -126,42 +134,83 @@ function recordDependency(signal2) {
126
134
  signal2.__f = void 0;
127
135
  }
128
136
  }
137
+ function queueSignalNotification(signal2) {
138
+ const subs = signal2[SUBS];
139
+ if (!subs) return;
140
+ for (const sub of subs) {
141
+ if (sub._c) {
142
+ propagateDirty(sub);
143
+ } else if (!pendingSet.has(sub)) {
144
+ pendingSet.add(sub);
145
+ pendingQueue.push(sub);
146
+ }
147
+ }
148
+ }
149
+ var maxDrainIterations = 1e5;
150
+ function drainNotificationQueue() {
151
+ if (notifyDepth > 0) return;
152
+ notifyDepth++;
153
+ try {
154
+ let i = 0;
155
+ while (i < pendingQueue.length) {
156
+ if (i >= maxDrainIterations) {
157
+ if (typeof console !== "undefined") {
158
+ console.error(
159
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
160
+ );
161
+ }
162
+ break;
163
+ }
164
+ safeInvoke(pendingQueue[i]);
165
+ i++;
166
+ }
167
+ } finally {
168
+ notifyDepth--;
169
+ if (notifyDepth === 0) {
170
+ pendingQueue.length = 0;
171
+ pendingSet.clear();
172
+ }
173
+ }
174
+ }
129
175
  function propagateDirty(sub) {
130
176
  sub();
131
- let sig = sub._sig;
132
- while (sig) {
177
+ const rootSig = sub._sig;
178
+ if (!rootSig) return;
179
+ const stack = propagateStack;
180
+ const baseLen = stack.length;
181
+ stack.push(rootSig);
182
+ while (stack.length > baseLen) {
183
+ const sig = stack.pop();
133
184
  const first = sig.__f;
134
185
  if (first) {
135
186
  if (first._c) {
136
187
  const nSig = first._sig;
137
- nSig._d = true;
138
- sig = nSig;
139
- continue;
140
- }
141
- if (!pendingSet.has(first)) {
188
+ if (!nSig._d) {
189
+ nSig._d = true;
190
+ stack.push(nSig);
191
+ }
192
+ } else if (!pendingSet.has(first)) {
142
193
  pendingSet.add(first);
143
194
  pendingQueue.push(first);
144
195
  }
145
- break;
196
+ continue;
146
197
  }
147
198
  const subs = sig[SUBS];
148
- if (!subs) break;
149
- let nextSig;
199
+ if (!subs) continue;
150
200
  for (const s of subs) {
151
201
  if (s._c) {
152
- s();
153
202
  const nSig = s._sig;
154
- if (nSig && !nextSig) {
155
- nextSig = nSig;
156
- } else if (nSig) {
157
- propagateDirty(s);
203
+ if (nSig && !nSig._d) {
204
+ nSig._d = true;
205
+ stack.push(nSig);
206
+ } else if (!nSig) {
207
+ s();
158
208
  }
159
209
  } else if (!pendingSet.has(s)) {
160
210
  pendingSet.add(s);
161
211
  pendingQueue.push(s);
162
212
  }
163
213
  }
164
- sig = nextSig;
165
214
  }
166
215
  }
167
216
  function notifySubscribers(signal2) {
@@ -185,13 +234,23 @@ function notifySubscribers(signal2) {
185
234
  }
186
235
  let i = 0;
187
236
  while (i < pendingQueue.length) {
237
+ if (i >= maxDrainIterations) {
238
+ if (typeof console !== "undefined") {
239
+ console.error(
240
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
241
+ );
242
+ }
243
+ break;
244
+ }
188
245
  safeInvoke(pendingQueue[i]);
189
246
  i++;
190
247
  }
191
248
  } finally {
192
- pendingQueue.length = 0;
193
- pendingSet.clear();
194
249
  notifyDepth--;
250
+ if (notifyDepth === 0) {
251
+ pendingQueue.length = 0;
252
+ pendingSet.clear();
253
+ }
195
254
  }
196
255
  return;
197
256
  }
@@ -211,30 +270,48 @@ function notifySubscribers(signal2) {
211
270
  notifyDepth++;
212
271
  try {
213
272
  let directCount = 0;
273
+ let hasComputedSub = false;
214
274
  for (const sub of subs) {
275
+ if (sub._c) hasComputedSub = true;
215
276
  pendingQueue[directCount++] = sub;
216
277
  }
217
- for (let i2 = 0; i2 < directCount; i2++) {
218
- if (pendingQueue[i2]._c) {
219
- propagateDirty(pendingQueue[i2]);
278
+ if (!hasComputedSub) {
279
+ for (let i2 = 0; i2 < directCount; i2++) {
280
+ safeInvoke(pendingQueue[i2]);
220
281
  }
221
- }
222
- for (let i2 = 0; i2 < directCount; i2++) {
223
- if (!pendingQueue[i2]._c) {
224
- if (!pendingSet.has(pendingQueue[i2])) {
225
- safeInvoke(pendingQueue[i2]);
282
+ } else {
283
+ for (let i2 = 0; i2 < directCount; i2++) {
284
+ if (pendingQueue[i2]._c) {
285
+ propagateDirty(pendingQueue[i2]);
286
+ }
287
+ }
288
+ for (let i2 = 0; i2 < directCount; i2++) {
289
+ const sub = pendingQueue[i2];
290
+ if (!sub._c && !pendingSet.has(sub)) {
291
+ pendingSet.add(sub);
292
+ safeInvoke(sub);
226
293
  }
227
294
  }
228
295
  }
229
296
  let i = directCount;
230
297
  while (i < pendingQueue.length) {
298
+ if (i - directCount >= maxDrainIterations) {
299
+ if (typeof console !== "undefined") {
300
+ console.error(
301
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
302
+ );
303
+ }
304
+ break;
305
+ }
231
306
  safeInvoke(pendingQueue[i]);
232
307
  i++;
233
308
  }
234
309
  } finally {
235
- pendingQueue.length = 0;
236
- pendingSet.clear();
237
310
  notifyDepth--;
311
+ if (notifyDepth === 0) {
312
+ pendingQueue.length = 0;
313
+ pendingSet.clear();
314
+ }
238
315
  }
239
316
  }
240
317
  function cleanup(subscriber) {
@@ -245,7 +322,9 @@ function cleanup(subscriber) {
245
322
  if (subs) {
246
323
  subs.delete(subscriber);
247
324
  if (singleDep.__f === subscriber) {
248
- singleDep.__f = void 0;
325
+ singleDep.__f = subs.size === 1 ? subs.values().next().value : void 0;
326
+ } else if (subs.size === 1 && singleDep.__f === void 0) {
327
+ singleDep.__f = subs.values().next().value;
249
328
  }
250
329
  }
251
330
  sub._dep = void 0;
@@ -258,7 +337,9 @@ function cleanup(subscriber) {
258
337
  if (subs) {
259
338
  subs.delete(subscriber);
260
339
  if (signal2.__f === subscriber) {
261
- signal2.__f = void 0;
340
+ signal2.__f = subs.size === 1 ? subs.values().next().value : void 0;
341
+ } else if (subs.size === 1 && signal2.__f === void 0) {
342
+ signal2.__f = subs.values().next().value;
262
343
  }
263
344
  }
264
345
  }
@@ -268,11 +349,32 @@ function cleanup(subscriber) {
268
349
  // src/reactivity/batch.ts
269
350
  var batchDepth = 0;
270
351
  var pendingSignals = /* @__PURE__ */ new Set();
352
+ function batch(fn) {
353
+ batchDepth++;
354
+ try {
355
+ return fn();
356
+ } finally {
357
+ batchDepth--;
358
+ if (batchDepth === 0) {
359
+ flushBatch();
360
+ }
361
+ }
362
+ }
271
363
  function enqueueBatchedSignal(signal2) {
272
364
  if (batchDepth === 0) return false;
273
365
  pendingSignals.add(signal2);
274
366
  return true;
275
367
  }
368
+ function flushBatch() {
369
+ try {
370
+ for (const signal2 of pendingSignals) {
371
+ queueSignalNotification(signal2);
372
+ }
373
+ } finally {
374
+ pendingSignals.clear();
375
+ }
376
+ drainNotificationQueue();
377
+ }
276
378
 
277
379
  // src/core/signals/signal.ts
278
380
  var _g = globalThis;
@@ -375,9 +477,28 @@ function machine(config) {
375
477
  }
376
478
 
377
479
  // src/core/ssr-context.ts
378
- var ssrMode = false;
480
+ var als = null;
481
+ try {
482
+ if (typeof process !== "undefined" && process.versions && process.versions.node) {
483
+ const req = Function("return typeof require==='function'?require:null")();
484
+ if (req) {
485
+ const mod = req("node:async_hooks");
486
+ als = new mod.AsyncLocalStorage();
487
+ }
488
+ }
489
+ } catch {
490
+ als = null;
491
+ }
492
+ var fallbackStore = { ssr: false, suspenseIdCounter: 0 };
493
+ function getSSRStore() {
494
+ if (als) {
495
+ const s = als.getStore();
496
+ if (s) return s;
497
+ }
498
+ return fallbackStore;
499
+ }
379
500
  function isSSR() {
380
- return ssrMode;
501
+ return getSSRStore().ssr;
381
502
  }
382
503
 
383
504
  // src/core/signals/effect.ts
@@ -387,26 +508,86 @@ function effect(effectFn, options) {
387
508
  if (isSSR()) return () => {
388
509
  };
389
510
  const onError = options?.onError;
511
+ let userCleanups = [];
512
+ const onCleanup = (fn) => {
513
+ userCleanups.push(fn);
514
+ };
515
+ const runUserCleanups = () => {
516
+ if (userCleanups.length === 0) return;
517
+ const list = userCleanups;
518
+ userCleanups = [];
519
+ for (let i = list.length - 1; i >= 0; i--) {
520
+ try {
521
+ list[i]();
522
+ } catch (err) {
523
+ if (typeof console !== "undefined") {
524
+ console.warn("[SibuJS effect] onCleanup threw:", err);
525
+ }
526
+ }
527
+ }
528
+ };
529
+ const invokeBody = () => effectFn(onCleanup);
390
530
  const wrappedFn = onError ? () => {
391
531
  try {
392
- effectFn();
532
+ invokeBody();
393
533
  } catch (err) {
394
534
  onError(err);
395
535
  }
396
- } : effectFn;
536
+ } : invokeBody;
397
537
  let cleanupHandle = () => {
398
538
  };
539
+ let running = false;
399
540
  const subscriber = () => {
400
- cleanupHandle();
401
- cleanupHandle = track(wrappedFn, subscriber);
541
+ if (running) {
542
+ if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
543
+ console.warn(
544
+ "[SibuJS] effect re-entered itself while running \u2014 the triggering update will be ignored. Wrap mutual writes in `batch()` or split the effect to avoid this."
545
+ );
546
+ }
547
+ return;
548
+ }
549
+ running = true;
550
+ try {
551
+ runUserCleanups();
552
+ cleanupHandle();
553
+ cleanupHandle = track(wrappedFn, subscriber);
554
+ } finally {
555
+ running = false;
556
+ }
402
557
  };
403
- cleanupHandle = track(wrappedFn, subscriber);
558
+ running = true;
559
+ try {
560
+ cleanupHandle = track(wrappedFn, subscriber);
561
+ } finally {
562
+ running = false;
563
+ }
404
564
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
405
565
  if (hook) hook.emit("effect:create", { effectFn });
566
+ let disposed = false;
406
567
  return () => {
568
+ if (disposed) return;
569
+ disposed = true;
407
570
  const h = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
408
- if (h) h.emit("effect:destroy", { effectFn });
409
- cleanupHandle();
571
+ if (h) {
572
+ try {
573
+ h.emit("effect:destroy", { effectFn });
574
+ } catch {
575
+ }
576
+ }
577
+ try {
578
+ runUserCleanups();
579
+ } catch (err) {
580
+ if (typeof console !== "undefined") {
581
+ console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
582
+ }
583
+ }
584
+ try {
585
+ cleanupHandle();
586
+ } catch (err) {
587
+ if (typeof console !== "undefined") {
588
+ console.warn("[SibuJS effect] dispose threw:", err);
589
+ }
590
+ }
410
591
  };
411
592
  }
412
593
 
@@ -414,7 +595,11 @@ function effect(effectFn, options) {
414
595
  function persisted(key, initial, options = {}) {
415
596
  const storage = options.session ? sessionStorage : localStorage;
416
597
  const serialize = options.serialize || JSON.stringify;
417
- const deserialize = options.deserialize || JSON.parse;
598
+ const safeReviver = (k, v) => {
599
+ if (k === "__proto__" || k === "constructor" || k === "prototype") return void 0;
600
+ return v;
601
+ };
602
+ const deserialize = options.deserialize || ((raw) => JSON.parse(raw, safeReviver));
418
603
  const encrypt = options.encrypt;
419
604
  const decrypt = options.decrypt;
420
605
  const syncTabs = options.session ? false : options.syncTabs ?? true;
@@ -518,6 +703,27 @@ function optimisticList(initialValue) {
518
703
  const [pending, setPending] = signal(false);
519
704
  let inflightCount = 0;
520
705
  let version = 0;
706
+ let tempIdCounter = 0;
707
+ const itemIds = /* @__PURE__ */ new WeakMap();
708
+ const idToItem = /* @__PURE__ */ new Map();
709
+ function tagItem(item) {
710
+ const id = ++tempIdCounter;
711
+ if (item !== null && typeof item === "object") {
712
+ itemIds.set(item, id);
713
+ }
714
+ idToItem.set(id, item);
715
+ return id;
716
+ }
717
+ function findIndexById(list, id) {
718
+ for (let i = 0; i < list.length; i++) {
719
+ const it = list[i];
720
+ if (it !== null && typeof it === "object" && itemIds.get(it) === id) {
721
+ return i;
722
+ }
723
+ if (Object.is(it, idToItem.get(id))) return i;
724
+ }
725
+ return -1;
726
+ }
521
727
  function begin() {
522
728
  const v = ++version;
523
729
  inflightCount++;
@@ -533,12 +739,13 @@ function optimisticList(initialValue) {
533
739
  }
534
740
  async function add(item, asyncAction) {
535
741
  const prev = items();
742
+ const id = tagItem(item);
536
743
  setItems([...prev, item]);
537
744
  const myVersion = begin();
538
745
  try {
539
746
  const result = await asyncAction();
540
747
  setItems((current) => {
541
- const idx = current.lastIndexOf(item);
748
+ const idx = findIndexById(current, id);
542
749
  if (idx >= 0) {
543
750
  const next = [...current];
544
751
  next[idx] = result;
@@ -546,8 +753,10 @@ function optimisticList(initialValue) {
546
753
  }
547
754
  return [...current, result];
548
755
  });
756
+ idToItem.delete(id);
549
757
  end(myVersion);
550
758
  } catch {
759
+ idToItem.delete(id);
551
760
  end(myVersion, () => setItems(prev));
552
761
  }
553
762
  }
@@ -564,12 +773,13 @@ function optimisticList(initialValue) {
564
773
  }
565
774
  async function updateItem(predicate, patch, asyncAction) {
566
775
  const prev = items();
567
- const patchedRefs = [];
776
+ const patchedIds = [];
568
777
  setItems(
569
778
  prev.map((item) => {
570
779
  if (predicate(item)) {
571
780
  const patched = { ...item, ...patch };
572
- patchedRefs.push(patched);
781
+ const id = tagItem(patched);
782
+ patchedIds.push(id);
573
783
  return patched;
574
784
  }
575
785
  return item;
@@ -578,9 +788,19 @@ function optimisticList(initialValue) {
578
788
  const myVersion = begin();
579
789
  try {
580
790
  const result = await asyncAction();
581
- setItems((current) => current.map((item) => patchedRefs.includes(item) ? result : item));
791
+ setItems(
792
+ (current) => current.map((item) => {
793
+ if (item !== null && typeof item === "object") {
794
+ const existingId = itemIds.get(item);
795
+ if (existingId !== void 0 && patchedIds.includes(existingId)) return result;
796
+ }
797
+ return item;
798
+ })
799
+ );
800
+ for (const id of patchedIds) idToItem.delete(id);
582
801
  end(myVersion);
583
802
  } catch {
803
+ for (const id of patchedIds) idToItem.delete(id);
584
804
  end(myVersion, () => setItems(prev));
585
805
  }
586
806
  }
@@ -589,10 +809,7 @@ function optimisticList(initialValue) {
589
809
  pending,
590
810
  add,
591
811
  remove,
592
- update: updateItem,
593
- addOptimistic: add,
594
- removeOptimistic: remove,
595
- updateOptimistic: updateItem
812
+ update: updateItem
596
813
  };
597
814
  }
598
815
 
@@ -600,6 +817,7 @@ function optimisticList(initialValue) {
600
817
  function derived(getter, options) {
601
818
  devAssert(typeof getter === "function", "derived: argument must be a getter function.");
602
819
  const debugName = options?.name;
820
+ const equals = options?.equals;
603
821
  const cs = {};
604
822
  cs._d = false;
605
823
  cs._g = getter;
@@ -610,8 +828,14 @@ function derived(getter, options) {
610
828
  markDirty._c = 1;
611
829
  markDirty._sig = cs;
612
830
  track(() => {
613
- cs._d = false;
614
- cs._v = getter();
831
+ let threw = true;
832
+ try {
833
+ cs._v = getter();
834
+ cs._d = false;
835
+ threw = false;
836
+ } finally {
837
+ if (threw) cs._d = true;
838
+ }
615
839
  }, markDirty);
616
840
  const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
617
841
  let evaluating = false;
@@ -624,11 +848,16 @@ function derived(getter, options) {
624
848
  if (trackingSuspended) {
625
849
  if (cs._d) {
626
850
  evaluating = true;
851
+ let threw = true;
627
852
  try {
628
- cs._d = false;
629
- cs._v = getter();
853
+ retrack(() => {
854
+ cs._v = getter();
855
+ cs._d = false;
856
+ threw = false;
857
+ }, markDirty);
630
858
  } finally {
631
859
  evaluating = false;
860
+ if (threw) cs._d = true;
632
861
  }
633
862
  }
634
863
  return cs._v;
@@ -637,13 +866,17 @@ function derived(getter, options) {
637
866
  if (cs._d) {
638
867
  const oldValue = cs._v;
639
868
  evaluating = true;
869
+ let threw = true;
640
870
  try {
641
- track(() => {
871
+ retrack(() => {
872
+ const next = getter();
873
+ cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
642
874
  cs._d = false;
643
- cs._v = getter();
875
+ threw = false;
644
876
  }, markDirty);
645
877
  } finally {
646
878
  evaluating = false;
879
+ if (threw) cs._d = true;
647
880
  }
648
881
  if (hook && oldValue !== cs._v) {
649
882
  hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
@@ -675,14 +908,16 @@ function timeline(initial, maxHistory = 100) {
675
908
  const idx = index();
676
909
  const newHistory = hist.slice(0, idx + 1);
677
910
  newHistory.push(newValue);
678
- if (newHistory.length > maxHistory) {
679
- newHistory.shift();
680
- setHistory(newHistory);
681
- setIndex(newHistory.length - 1);
682
- } else {
683
- setHistory(newHistory);
684
- setIndex(idx + 1);
685
- }
911
+ batch(() => {
912
+ if (newHistory.length > maxHistory) {
913
+ newHistory.shift();
914
+ setHistory(newHistory);
915
+ setIndex(newHistory.length - 1);
916
+ } else {
917
+ setHistory(newHistory);
918
+ setIndex(idx + 1);
919
+ }
920
+ });
686
921
  }
687
922
  function undo() {
688
923
  if (canUndo()) {
@@ -695,8 +930,10 @@ function timeline(initial, maxHistory = 100) {
695
930
  }
696
931
  }
697
932
  function reset() {
698
- setHistory([initial]);
699
- setIndex(0);
933
+ batch(() => {
934
+ setHistory([initial]);
935
+ setIndex(0);
936
+ });
700
937
  }
701
938
  function jumpTo(targetIndex) {
702
939
  const hist = history();
@@ -708,8 +945,37 @@ function timeline(initial, maxHistory = 100) {
708
945
  }
709
946
 
710
947
  // src/patterns/globalStore.ts
948
+ function deepClone(value) {
949
+ if (typeof structuredClone === "function") {
950
+ return structuredClone(value);
951
+ }
952
+ const seen = /* @__PURE__ */ new WeakSet();
953
+ const clone = (v) => {
954
+ if (v === null || typeof v !== "object") return v;
955
+ if (seen.has(v)) throw new Error("deepClone: circular reference");
956
+ seen.add(v);
957
+ if (v instanceof Date) return new Date(v.getTime());
958
+ if (v instanceof Map) {
959
+ const out2 = /* @__PURE__ */ new Map();
960
+ for (const [k, val] of v) out2.set(clone(k), clone(val));
961
+ return out2;
962
+ }
963
+ if (v instanceof Set) {
964
+ const out2 = /* @__PURE__ */ new Set();
965
+ for (const val of v) out2.add(clone(val));
966
+ return out2;
967
+ }
968
+ if (Array.isArray(v)) return v.map(clone);
969
+ const out = {};
970
+ for (const k of Object.keys(v)) {
971
+ out[k] = clone(v[k]);
972
+ }
973
+ return out;
974
+ };
975
+ return clone(value);
976
+ }
711
977
  function globalStore(config) {
712
- const initialState = JSON.parse(JSON.stringify(config.state));
978
+ const initialState = deepClone(config.state);
713
979
  const [getState, setState] = signal({ ...initialState });
714
980
  const listeners = /* @__PURE__ */ new Set();
715
981
  const middlewares = config.middleware || [];
@@ -71,19 +71,24 @@ interface PersistOptions<T = unknown> {
71
71
  * - use XOR with a static key — trivially reversible
72
72
  * - roll your own cipher — nearly always broken
73
73
  *
74
+ * **Sync only:** because `persisted()` exposes synchronous getters and
75
+ * setters, both `encrypt` and `decrypt` must be SYNCHRONOUS. Async
76
+ * crypto (e.g. `crypto.subtle.encrypt`) is NOT supported here — derive
77
+ * keys ahead of time and use a sync wrapper, or pre/post-process the
78
+ * value yourself before/after `setValue`.
79
+ *
74
80
  * @example
75
81
  * ```ts
82
+ * // Pre-derived key + sync wrapper
76
83
  * persisted("token", "", {
77
- * encrypt: async (v) => aesGcmEncrypt(v, await getKey()),
78
- * decrypt: async (v) => aesGcmDecrypt(v, await getKey()),
84
+ * encrypt: (v) => syncAesGcmEncrypt(v, derivedKey),
85
+ * decrypt: (v) => syncAesGcmDecrypt(v, derivedKey),
79
86
  * });
80
87
  * ```
81
- *
82
- * Note that because localStorage is synchronous, any real AES-GCM
83
- * flow needs pre-derived keys and is inherently best-effort.
84
88
  */
85
89
  encrypt?: (value: string) => string;
86
- /** Decrypt the stored value before deserialization. Required if `encrypt` is set. */
90
+ /** Decrypt the stored value before deserialization. Required if `encrypt` is set.
91
+ * Must be synchronous — see `encrypt` docs. */
87
92
  decrypt?: (value: string) => string;
88
93
  }
89
94
  declare function persisted<T>(key: string, initial: T, options?: PersistOptions<T>): [() => T, (next: T | ((prev: T) => T)) => void];
@@ -141,12 +146,6 @@ declare function optimisticList<T>(initialValue: T[]): {
141
146
  add: (item: T, asyncAction: () => Promise<T>) => Promise<void>;
142
147
  remove: (predicate: (item: T) => boolean, asyncAction: () => Promise<void>) => Promise<void>;
143
148
  update: (predicate: (item: T) => boolean, patch: Partial<T>, asyncAction: () => Promise<T>) => Promise<void>;
144
- /** @deprecated Use `add` instead */
145
- addOptimistic: (item: T, asyncAction: () => Promise<T>) => Promise<void>;
146
- /** @deprecated Use `remove` instead */
147
- removeOptimistic: (predicate: (item: T) => boolean, asyncAction: () => Promise<void>) => Promise<void>;
148
- /** @deprecated Use `update` instead */
149
- updateOptimistic: (predicate: (item: T) => boolean, patch: Partial<T>, asyncAction: () => Promise<T>) => Promise<void>;
150
149
  };
151
150
 
152
151
  interface TimeTravelReturn<T> {