sibujs 1.4.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 (190) hide show
  1. package/README.md +105 -119
  2. package/dist/browser.cjs +288 -80
  3. package/dist/browser.d.cts +19 -9
  4. package/dist/browser.d.ts +19 -9
  5. package/dist/browser.js +6 -6
  6. package/dist/build.cjs +1019 -313
  7. package/dist/build.d.cts +1 -1
  8. package/dist/build.d.ts +1 -1
  9. package/dist/build.js +15 -13
  10. package/dist/cdn.global.js +17 -16
  11. package/dist/chunk-2RA7SHDA.js +65 -0
  12. package/dist/chunk-2UPRY23K.js +80 -0
  13. package/dist/chunk-3JHCYHWN.js +125 -0
  14. package/dist/{chunk-ZWKZCBO6.js → chunk-3LR7GLWQ.js} +154 -33
  15. package/dist/{chunk-3AIRKM3B.js → chunk-3NSGB5JN.js} +115 -34
  16. package/dist/{chunk-3ARAQO7B.js → chunk-52YJLLRO.js} +29 -6
  17. package/dist/chunk-54EDRCEF.js +93 -0
  18. package/dist/chunk-7JDB7I65.js +1327 -0
  19. package/dist/{chunk-WZSPOOER.js → chunk-CC65Y57T.js} +8 -5
  20. package/dist/{chunk-23VV7YD3.js → chunk-DFPFITST.js} +25 -30
  21. package/dist/{chunk-WR5D4EGH.js → chunk-GTBNNBJ6.js} +14 -2
  22. package/dist/chunk-HB24TBAF.js +121 -0
  23. package/dist/{chunk-CZUGLNJS.js → chunk-ITX6OO3F.js} +3 -3
  24. package/dist/{chunk-JAKHTMQU.js → chunk-JA6667UN.js} +206 -46
  25. package/dist/{chunk-77L6NL3X.js → chunk-JXMMDLBY.js} +306 -183
  26. package/dist/{chunk-3X2YG6YM.js → chunk-JYD2PWXH.js} +59 -28
  27. package/dist/{chunk-F3FA4F32.js → chunk-KLRMB5ZS.js} +135 -79
  28. package/dist/{chunk-5X6PP2UK.js → chunk-LMLD24FC.js} +2 -2
  29. package/dist/{chunk-M4NLBH4I.js → chunk-LYTCUZ7H.js} +3 -2
  30. package/dist/{chunk-TSOKIX5Z.js → chunk-MIUAXB7K.js} +126 -74
  31. package/dist/{chunk-QWZG56ET.js → chunk-ND2664SF.js} +558 -190
  32. package/dist/{chunk-JCI5M6U6.js → chunk-O2MNQFLP.js} +261 -79
  33. package/dist/{chunk-EWFVA3TJ.js → chunk-R73P76YZ.js} +1 -1
  34. package/dist/{chunk-2BYQDGN3.js → chunk-SAHNHTFC.js} +234 -63
  35. package/dist/chunk-UCS6AMJ7.js +79 -0
  36. package/dist/{chunk-ZD6OAMTH.js → chunk-VLPPXTYG.js} +90 -35
  37. package/dist/{chunk-OUZZEE4S.js → chunk-WOMYAHHI.js} +17 -11
  38. package/dist/{contracts-xo5ckdRP.d.cts → contracts-ey_Qh8ef.d.cts} +7 -8
  39. package/dist/{contracts-xo5ckdRP.d.ts → contracts-ey_Qh8ef.d.ts} +7 -8
  40. package/dist/{customElement-D2DJp_xn.d.cts → customElement-CPfIrbvg.d.cts} +18 -9
  41. package/dist/{customElement-D2DJp_xn.d.ts → customElement-CPfIrbvg.d.ts} +18 -9
  42. package/dist/data.cjs +452 -100
  43. package/dist/data.d.cts +20 -2
  44. package/dist/data.d.ts +20 -2
  45. package/dist/data.js +11 -9
  46. package/dist/devtools.cjs +535 -247
  47. package/dist/devtools.d.cts +1 -1
  48. package/dist/devtools.d.ts +1 -1
  49. package/dist/devtools.js +34 -30
  50. package/dist/ecosystem.cjs +499 -143
  51. package/dist/ecosystem.d.cts +13 -11
  52. package/dist/ecosystem.d.ts +13 -11
  53. package/dist/ecosystem.js +12 -11
  54. package/dist/extras.cjs +3639 -1629
  55. package/dist/extras.d.cts +11 -11
  56. package/dist/extras.d.ts +11 -11
  57. package/dist/extras.js +58 -45
  58. package/dist/index.cjs +1023 -313
  59. package/dist/index.d.cts +128 -55
  60. package/dist/index.d.ts +128 -55
  61. package/dist/index.js +28 -16
  62. package/dist/{introspect-BumjnBKr.d.cts → introspect-BWNjNw64.d.cts} +22 -2
  63. package/dist/{introspect-CZrlcaYy.d.ts → introspect-cY2pg9pW.d.ts} +22 -2
  64. package/dist/motion.cjs +90 -36
  65. package/dist/motion.d.cts +1 -1
  66. package/dist/motion.d.ts +1 -1
  67. package/dist/motion.js +4 -4
  68. package/dist/patterns.cjs +414 -81
  69. package/dist/patterns.d.cts +53 -20
  70. package/dist/patterns.d.ts +53 -20
  71. package/dist/patterns.js +7 -7
  72. package/dist/performance.cjs +364 -108
  73. package/dist/performance.d.cts +29 -17
  74. package/dist/performance.d.ts +29 -17
  75. package/dist/performance.js +13 -6
  76. package/dist/plugin-D30wlGW5.d.cts +71 -0
  77. package/dist/plugin-D30wlGW5.d.ts +71 -0
  78. package/dist/plugins.cjs +652 -271
  79. package/dist/plugins.d.cts +13 -6
  80. package/dist/plugins.d.ts +13 -6
  81. package/dist/plugins.js +116 -50
  82. package/dist/{ssr-Do_SiVoL.d.cts → ssr-CrVNy6Pa.d.cts} +9 -15
  83. package/dist/{ssr-Do_SiVoL.d.ts → ssr-CrVNy6Pa.d.ts} +9 -15
  84. package/dist/{ssr-4PBXAOO3.js → ssr-FXD2PPMC.js} +4 -3
  85. package/dist/ssr.cjs +648 -219
  86. package/dist/ssr.d.cts +27 -7
  87. package/dist/ssr.d.ts +27 -7
  88. package/dist/ssr.js +12 -11
  89. package/dist/{tagFactory-DaJ0YWX6.d.ts → tagFactory-S17H2qxu.d.cts} +9 -1
  90. package/dist/{tagFactory-DaJ0YWX6.d.cts → tagFactory-S17H2qxu.d.ts} +9 -1
  91. package/dist/testing.cjs +252 -63
  92. package/dist/testing.d.cts +17 -4
  93. package/dist/testing.d.ts +17 -4
  94. package/dist/testing.js +100 -44
  95. package/dist/ui.cjs +576 -168
  96. package/dist/ui.d.cts +13 -16
  97. package/dist/ui.d.ts +13 -16
  98. package/dist/ui.js +20 -17
  99. package/dist/widgets.cjs +1001 -93
  100. package/dist/widgets.d.cts +104 -2
  101. package/dist/widgets.d.ts +104 -2
  102. package/dist/widgets.js +9 -7
  103. package/package.json +8 -2
  104. package/dist/chunk-32DY64NT.js +0 -282
  105. package/dist/chunk-3CRQALYP.js +0 -877
  106. package/dist/chunk-4EI4AG32.js +0 -482
  107. package/dist/chunk-4MYMUBRS.js +0 -21
  108. package/dist/chunk-6HLLIF3K.js +0 -398
  109. package/dist/chunk-6LSNVCS2.js +0 -937
  110. package/dist/chunk-6SA3QQES.js +0 -61
  111. package/dist/chunk-7BF6TK55.js +0 -1097
  112. package/dist/chunk-7TQKR4PP.js +0 -294
  113. package/dist/chunk-7V26P53V.js +0 -712
  114. package/dist/chunk-AZ3ISID5.js +0 -298
  115. package/dist/chunk-B7SWRFUT.js +0 -332
  116. package/dist/chunk-BGN5ZMP4.js +0 -26
  117. package/dist/chunk-BTU3TJDS.js +0 -365
  118. package/dist/chunk-BW3WT46K.js +0 -937
  119. package/dist/chunk-C6KFWOFV.js +0 -616
  120. package/dist/chunk-CHF5OHIA.js +0 -61
  121. package/dist/chunk-CHJ27IGK.js +0 -26
  122. package/dist/chunk-CMBFNA7L.js +0 -27
  123. package/dist/chunk-DAHRH4ON.js +0 -331
  124. package/dist/chunk-DKOHBI74.js +0 -924
  125. package/dist/chunk-DTCOOBMX.js +0 -725
  126. package/dist/chunk-EBGIRKQY.js +0 -616
  127. package/dist/chunk-EUZND3CB.js +0 -27
  128. package/dist/chunk-EVCZO745.js +0 -365
  129. package/dist/chunk-FGOEVHY3.js +0 -60
  130. package/dist/chunk-G3BOQPVO.js +0 -365
  131. package/dist/chunk-GCOK2LC3.js +0 -282
  132. package/dist/chunk-HGMJFBC7.js +0 -654
  133. package/dist/chunk-K5ZUMYVS.js +0 -89
  134. package/dist/chunk-KQPDEVVS.js +0 -398
  135. package/dist/chunk-L6JRBDNS.js +0 -60
  136. package/dist/chunk-LA6KQEDU.js +0 -712
  137. package/dist/chunk-MDVXJWFN.js +0 -304
  138. package/dist/chunk-MEZVEBPN.js +0 -2008
  139. package/dist/chunk-MK4ERFYL.js +0 -2249
  140. package/dist/chunk-MLKGABMK.js +0 -9
  141. package/dist/chunk-MQ5GOYPH.js +0 -2249
  142. package/dist/chunk-N6IZB6KJ.js +0 -567
  143. package/dist/chunk-NEKUBFPT.js +0 -60
  144. package/dist/chunk-NHUC2QWH.js +0 -282
  145. package/dist/chunk-NMRUZALC.js +0 -1097
  146. package/dist/chunk-NYVAC6P5.js +0 -37
  147. package/dist/chunk-OF7UZIVB.js +0 -725
  148. package/dist/chunk-P6W3STU4.js +0 -2249
  149. package/dist/chunk-PBHF5WKN.js +0 -616
  150. package/dist/chunk-PTQJDMRT.js +0 -146
  151. package/dist/chunk-PZEGYCF5.js +0 -61
  152. package/dist/chunk-QBMDLBU2.js +0 -975
  153. package/dist/chunk-RQGQSLQK.js +0 -725
  154. package/dist/chunk-SDLZDHKP.js +0 -107
  155. package/dist/chunk-TNQWPPE6.js +0 -37
  156. package/dist/chunk-UHNL42EF.js +0 -2730
  157. package/dist/chunk-UNXCEF6S.js +0 -21
  158. package/dist/chunk-V2XTI523.js +0 -347
  159. package/dist/chunk-VAU366PN.js +0 -2241
  160. package/dist/chunk-VMVDTCXB.js +0 -712
  161. package/dist/chunk-VRW3FULF.js +0 -725
  162. package/dist/chunk-WADYRCO2.js +0 -304
  163. package/dist/chunk-WILQZRO4.js +0 -282
  164. package/dist/chunk-WUHJISPP.js +0 -298
  165. package/dist/chunk-XYU6TZOW.js +0 -182
  166. package/dist/chunk-Y6GP4QGG.js +0 -276
  167. package/dist/chunk-YECR7UIA.js +0 -347
  168. package/dist/chunk-YUTWTI4B.js +0 -654
  169. package/dist/chunk-Z65KYU7I.js +0 -26
  170. package/dist/chunk-Z6POF5YC.js +0 -975
  171. package/dist/chunk-ZBJP6WFL.js +0 -482
  172. package/dist/contracts-DDrwxvJ-.d.cts +0 -245
  173. package/dist/contracts-DDrwxvJ-.d.ts +0 -245
  174. package/dist/contracts-DOrhwbke.d.cts +0 -245
  175. package/dist/contracts-DOrhwbke.d.ts +0 -245
  176. package/dist/customElement-BKQfbSZQ.d.cts +0 -262
  177. package/dist/customElement-BKQfbSZQ.d.ts +0 -262
  178. package/dist/customElement-yz8uyk-0.d.cts +0 -308
  179. package/dist/customElement-yz8uyk-0.d.ts +0 -308
  180. package/dist/introspect-Cb0zgpi2.d.cts +0 -477
  181. package/dist/introspect-Y2xNXGSf.d.ts +0 -477
  182. package/dist/plugin-Bek4RhJY.d.cts +0 -43
  183. package/dist/plugin-Bek4RhJY.d.ts +0 -43
  184. package/dist/ssr-3RXHP5ES.js +0 -38
  185. package/dist/ssr-6GIMY5MX.js +0 -38
  186. package/dist/ssr-BA6sxxUd.d.cts +0 -135
  187. package/dist/ssr-BA6sxxUd.d.ts +0 -135
  188. package/dist/ssr-WKUPVSSK.js +0 -36
  189. package/dist/tagFactory-Dl8QCLga.d.cts +0 -23
  190. package/dist/tagFactory-Dl8QCLga.d.ts +0 -23
package/dist/index.cjs CHANGED
@@ -99,6 +99,7 @@ __export(index_exports, {
99
99
  footer: () => footer,
100
100
  form: () => form,
101
101
  g: () => g,
102
+ getSSRStore: () => getSSRStore,
102
103
  getSlot: () => getSlot,
103
104
  h1: () => h1,
104
105
  h2: () => h2,
@@ -171,6 +172,7 @@ __export(index_exports, {
171
172
  rp: () => rp,
172
173
  rt: () => rt,
173
174
  ruby: () => ruby,
175
+ runInSSRContext: () => runInSSRContext,
174
176
  s: () => s,
175
177
  samp: () => samp,
176
178
  script: () => script,
@@ -196,6 +198,7 @@ __export(index_exports, {
196
198
  symbol: () => symbol,
197
199
  table: () => table,
198
200
  tagFactory: () => tagFactory,
201
+ takePendingError: () => takePendingError,
199
202
  tbody: () => tbody,
200
203
  td: () => td,
201
204
  template: () => template,
@@ -210,6 +213,7 @@ __export(index_exports, {
210
213
  track: () => track2,
211
214
  transition: () => transition,
212
215
  trapFocus: () => trapFocus,
216
+ trustHTML: () => trustHTML,
213
217
  tspan: () => tspan,
214
218
  u: () => u,
215
219
  ul: () => ul,
@@ -232,33 +236,80 @@ function isDev() {
232
236
  var _isDev = isDev();
233
237
  function devAssert(condition, message) {
234
238
  if (_isDev && !condition) {
235
- throw new Error(`[Sibu] ${message}`);
239
+ throw new Error(`[SibuJS] ${message}`);
236
240
  }
237
241
  }
238
242
  function devWarn(message) {
239
243
  if (_isDev) {
240
- console.warn(`[Sibu] ${message}`);
244
+ console.warn(`[SibuJS] ${message}`);
241
245
  }
242
246
  }
243
247
 
244
248
  // src/utils/sanitize.ts
249
+ var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
245
250
  function sanitizeUrl(url) {
246
251
  const trimmed = url.replace(/[\x00-\x20\x7f-\x9f]+/g, "").trim();
247
252
  if (!trimmed) return "";
248
253
  const lower = trimmed.toLowerCase();
249
- if (lower.startsWith("javascript:") || lower.startsWith("data:") || lower.startsWith("vbscript:") || lower.startsWith("blob:")) {
250
- return "";
254
+ let schemeEnd = -1;
255
+ for (let i2 = 0; i2 < lower.length; i2++) {
256
+ const ch = lower.charCodeAt(i2);
257
+ if (ch === 58) {
258
+ schemeEnd = i2;
259
+ break;
260
+ }
261
+ if (ch === 47 || ch === 63 || ch === 35) break;
251
262
  }
263
+ if (schemeEnd === -1) return trimmed;
264
+ const scheme = lower.slice(0, schemeEnd + 1);
265
+ if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return trimmed;
266
+ if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
252
267
  return trimmed;
253
268
  }
269
+ function sanitizeSrcset(value) {
270
+ const parts = value.split(",");
271
+ const out = [];
272
+ for (let i2 = 0; i2 < parts.length; i2++) {
273
+ const part = parts[i2].trim();
274
+ if (!part) continue;
275
+ const m = part.match(/^(\S+)(\s+.+)?$/);
276
+ if (!m) continue;
277
+ const safe = sanitizeUrl(m[1]);
278
+ if (!safe) continue;
279
+ out.push(m[2] ? `${safe}${m[2]}` : safe);
280
+ }
281
+ return out.join(", ");
282
+ }
254
283
  function sanitizeCSSValue(value) {
255
- const lower = value.toLowerCase().replace(/\s+/g, "");
256
- if (lower.includes("url(") || lower.includes("expression(") || lower.includes("javascript:") || lower.includes("-moz-binding")) {
284
+ const decoded = value.replace(/\\([0-9a-fA-F]{1,6})\s?/g, (_m, hex) => {
285
+ const code2 = Number.parseInt(hex, 16);
286
+ if (!Number.isFinite(code2) || code2 < 0 || code2 > 1114111) return "";
287
+ try {
288
+ return String.fromCodePoint(code2);
289
+ } catch {
290
+ return "";
291
+ }
292
+ });
293
+ const lower = decoded.toLowerCase().replace(/\s+/g, "");
294
+ if (lower.includes("url(") || lower.includes("expression(") || lower.includes("javascript:") || lower.includes("vbscript:") || lower.includes("-moz-binding") || lower.includes("behavior:") || lower.includes("@import") || lower.includes("image-set(") || lower.includes("filter:progid")) {
257
295
  return "";
258
296
  }
259
297
  return value;
260
298
  }
261
- var URL_ATTRIBUTES = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "cite", "poster", "background", "srcset"]);
299
+ var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
300
+ "href",
301
+ "xlink:href",
302
+ "src",
303
+ "action",
304
+ "formaction",
305
+ "formtarget",
306
+ "cite",
307
+ "poster",
308
+ "background",
309
+ "srcset",
310
+ "ping",
311
+ "data"
312
+ ]);
262
313
  function isUrlAttribute(attr) {
263
314
  return URL_ATTRIBUTES.has(attr);
264
315
  }
@@ -269,11 +320,11 @@ var subscriberStack = new Array(32);
269
320
  var stackCapacity = 32;
270
321
  var stackTop = -1;
271
322
  var currentSubscriber = null;
272
- var signalSubscribers = /* @__PURE__ */ new WeakMap();
273
323
  var SUBS = "__s";
274
324
  var notifyDepth = 0;
275
325
  var pendingQueue = [];
276
326
  var pendingSet = /* @__PURE__ */ new Set();
327
+ var propagateStack = [];
277
328
  function safeInvoke(sub2) {
278
329
  try {
279
330
  sub2();
@@ -283,6 +334,15 @@ function safeInvoke(sub2) {
283
334
  }
284
335
  var suspendDepth = 0;
285
336
  var trackingSuspended = false;
337
+ function retrack(effectFn, subscriber) {
338
+ const prev = currentSubscriber;
339
+ currentSubscriber = subscriber;
340
+ try {
341
+ effectFn();
342
+ } finally {
343
+ currentSubscriber = prev;
344
+ }
345
+ }
286
346
  function track(effectFn, subscriber) {
287
347
  if (!subscriber) subscriber = effectFn;
288
348
  cleanup(subscriber);
@@ -350,7 +410,6 @@ function recordDependency(signal2) {
350
410
  let subs = signal2[SUBS];
351
411
  if (!subs) {
352
412
  subs = /* @__PURE__ */ new Set();
353
- signalSubscribers.set(signal2, subs);
354
413
  signal2[SUBS] = subs;
355
414
  }
356
415
  subs.add(currentSubscriber);
@@ -372,57 +431,71 @@ function queueSignalNotification(signal2) {
372
431
  }
373
432
  }
374
433
  }
434
+ var maxDrainIterations = 1e5;
375
435
  function drainNotificationQueue() {
376
436
  if (notifyDepth > 0) return;
377
437
  notifyDepth++;
378
438
  try {
379
439
  let i2 = 0;
380
440
  while (i2 < pendingQueue.length) {
441
+ if (i2 >= maxDrainIterations) {
442
+ if (typeof console !== "undefined") {
443
+ console.error(
444
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
445
+ );
446
+ }
447
+ break;
448
+ }
381
449
  safeInvoke(pendingQueue[i2]);
382
450
  i2++;
383
451
  }
384
452
  } finally {
385
- pendingQueue.length = 0;
386
- pendingSet.clear();
387
453
  notifyDepth--;
454
+ if (notifyDepth === 0) {
455
+ pendingQueue.length = 0;
456
+ pendingSet.clear();
457
+ }
388
458
  }
389
459
  }
390
460
  function propagateDirty(sub2) {
391
461
  sub2();
392
- let sig = sub2._sig;
393
- while (sig) {
462
+ const rootSig = sub2._sig;
463
+ if (!rootSig) return;
464
+ const stack = propagateStack;
465
+ const baseLen = stack.length;
466
+ stack.push(rootSig);
467
+ while (stack.length > baseLen) {
468
+ const sig = stack.pop();
394
469
  const first = sig.__f;
395
470
  if (first) {
396
471
  if (first._c) {
397
472
  const nSig = first._sig;
398
- nSig._d = true;
399
- sig = nSig;
400
- continue;
401
- }
402
- if (!pendingSet.has(first)) {
473
+ if (!nSig._d) {
474
+ nSig._d = true;
475
+ stack.push(nSig);
476
+ }
477
+ } else if (!pendingSet.has(first)) {
403
478
  pendingSet.add(first);
404
479
  pendingQueue.push(first);
405
480
  }
406
- break;
481
+ continue;
407
482
  }
408
483
  const subs = sig[SUBS];
409
- if (!subs) break;
410
- let nextSig;
484
+ if (!subs) continue;
411
485
  for (const s2 of subs) {
412
486
  if (s2._c) {
413
- s2();
414
487
  const nSig = s2._sig;
415
- if (nSig && !nextSig) {
416
- nextSig = nSig;
417
- } else if (nSig) {
418
- propagateDirty(s2);
488
+ if (nSig && !nSig._d) {
489
+ nSig._d = true;
490
+ stack.push(nSig);
491
+ } else if (!nSig) {
492
+ s2();
419
493
  }
420
494
  } else if (!pendingSet.has(s2)) {
421
495
  pendingSet.add(s2);
422
496
  pendingQueue.push(s2);
423
497
  }
424
498
  }
425
- sig = nextSig;
426
499
  }
427
500
  }
428
501
  function notifySubscribers(signal2) {
@@ -446,13 +519,23 @@ function notifySubscribers(signal2) {
446
519
  }
447
520
  let i2 = 0;
448
521
  while (i2 < pendingQueue.length) {
522
+ if (i2 >= maxDrainIterations) {
523
+ if (typeof console !== "undefined") {
524
+ console.error(
525
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
526
+ );
527
+ }
528
+ break;
529
+ }
449
530
  safeInvoke(pendingQueue[i2]);
450
531
  i2++;
451
532
  }
452
533
  } finally {
453
- pendingQueue.length = 0;
454
- pendingSet.clear();
455
534
  notifyDepth--;
535
+ if (notifyDepth === 0) {
536
+ pendingQueue.length = 0;
537
+ pendingSet.clear();
538
+ }
456
539
  }
457
540
  return;
458
541
  }
@@ -472,30 +555,48 @@ function notifySubscribers(signal2) {
472
555
  notifyDepth++;
473
556
  try {
474
557
  let directCount = 0;
558
+ let hasComputedSub = false;
475
559
  for (const sub2 of subs) {
560
+ if (sub2._c) hasComputedSub = true;
476
561
  pendingQueue[directCount++] = sub2;
477
562
  }
478
- for (let i3 = 0; i3 < directCount; i3++) {
479
- if (pendingQueue[i3]._c) {
480
- propagateDirty(pendingQueue[i3]);
563
+ if (!hasComputedSub) {
564
+ for (let i3 = 0; i3 < directCount; i3++) {
565
+ safeInvoke(pendingQueue[i3]);
481
566
  }
482
- }
483
- for (let i3 = 0; i3 < directCount; i3++) {
484
- if (!pendingQueue[i3]._c) {
485
- if (!pendingSet.has(pendingQueue[i3])) {
486
- safeInvoke(pendingQueue[i3]);
567
+ } else {
568
+ for (let i3 = 0; i3 < directCount; i3++) {
569
+ if (pendingQueue[i3]._c) {
570
+ propagateDirty(pendingQueue[i3]);
571
+ }
572
+ }
573
+ for (let i3 = 0; i3 < directCount; i3++) {
574
+ const sub2 = pendingQueue[i3];
575
+ if (!sub2._c && !pendingSet.has(sub2)) {
576
+ pendingSet.add(sub2);
577
+ safeInvoke(sub2);
487
578
  }
488
579
  }
489
580
  }
490
581
  let i2 = directCount;
491
582
  while (i2 < pendingQueue.length) {
583
+ if (i2 - directCount >= maxDrainIterations) {
584
+ if (typeof console !== "undefined") {
585
+ console.error(
586
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
587
+ );
588
+ }
589
+ break;
590
+ }
492
591
  safeInvoke(pendingQueue[i2]);
493
592
  i2++;
494
593
  }
495
594
  } finally {
496
- pendingQueue.length = 0;
497
- pendingSet.clear();
498
595
  notifyDepth--;
596
+ if (notifyDepth === 0) {
597
+ pendingQueue.length = 0;
598
+ pendingSet.clear();
599
+ }
499
600
  }
500
601
  }
501
602
  function cleanup(subscriber) {
@@ -506,7 +607,9 @@ function cleanup(subscriber) {
506
607
  if (subs) {
507
608
  subs.delete(subscriber);
508
609
  if (singleDep.__f === subscriber) {
509
- singleDep.__f = void 0;
610
+ singleDep.__f = subs.size === 1 ? subs.values().next().value : void 0;
611
+ } else if (subs.size === 1 && singleDep.__f === void 0) {
612
+ singleDep.__f = subs.values().next().value;
510
613
  }
511
614
  }
512
615
  sub2._dep = void 0;
@@ -519,7 +622,9 @@ function cleanup(subscriber) {
519
622
  if (subs) {
520
623
  subs.delete(subscriber);
521
624
  if (signal2.__f === subscriber) {
522
- signal2.__f = void 0;
625
+ signal2.__f = subs.size === 1 ? subs.values().next().value : void 0;
626
+ } else if (subs.size === 1 && signal2.__f === void 0) {
627
+ signal2.__f = subs.values().next().value;
523
628
  }
524
629
  }
525
630
  }
@@ -528,6 +633,9 @@ function cleanup(subscriber) {
528
633
 
529
634
  // src/reactivity/bindAttribute.ts
530
635
  var _isDev3 = isDev();
636
+ function setProp(el, key, val) {
637
+ el[key] = val;
638
+ }
531
639
  function isEventHandlerAttr(name) {
532
640
  if (name.length < 3) return false;
533
641
  const lower = name.toLowerCase();
@@ -553,7 +661,7 @@ function bindAttribute(el, attr, getter) {
553
661
  }
554
662
  if (typeof value === "boolean") {
555
663
  if (attr in el && (attr === "checked" || attr === "disabled" || attr === "selected")) {
556
- el[attr] = value;
664
+ setProp(el, attr, value);
557
665
  } else if (value) {
558
666
  el.setAttribute(attr, "");
559
667
  } else {
@@ -563,7 +671,7 @@ function bindAttribute(el, attr, getter) {
563
671
  }
564
672
  const str = String(value);
565
673
  if ((attr === "value" || attr === "checked") && attr in el) {
566
- el[attr] = attr === "checked" ? Boolean(value) : str;
674
+ setProp(el, attr, attr === "checked" ? Boolean(value) : str);
567
675
  } else {
568
676
  el.setAttribute(attr, isUrlAttribute(attr) ? sanitizeUrl(str) : str);
569
677
  }
@@ -594,7 +702,7 @@ function bindDynamic(el, nameGetter, valueGetter) {
594
702
  }
595
703
  const str = String(value);
596
704
  if ((name === "value" || name === "checked") && name in el) {
597
- el[name] = name === "checked" ? Boolean(value) : str;
705
+ setProp(el, name, name === "checked" ? Boolean(value) : str);
598
706
  } else {
599
707
  el.setAttribute(name, isUrlAttribute(name) ? sanitizeUrl(str) : str);
600
708
  }
@@ -637,24 +745,29 @@ function bindChildNode(placeholder, getter) {
637
745
  let newNodes;
638
746
  if (Array.isArray(result)) {
639
747
  newNodes = [];
748
+ const seen = /* @__PURE__ */ new Set();
640
749
  for (let i2 = 0; i2 < result.length; i2++) {
641
750
  const item = result[i2];
642
751
  if (item == null || typeof item === "boolean") continue;
643
- newNodes.push(item instanceof Node ? item : document.createTextNode(String(item)));
752
+ const node = item instanceof Node ? item : document.createTextNode(String(item));
753
+ if (seen.has(node)) {
754
+ if (_isDev4)
755
+ devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
756
+ continue;
757
+ }
758
+ seen.add(node);
759
+ newNodes.push(node);
644
760
  }
645
761
  } else {
646
762
  const node = result instanceof Node ? result : document.createTextNode(String(result));
647
763
  newNodes = [node];
648
764
  }
649
- const reused = lastNodes.length > 0 && newNodes.length > 0 ? /* @__PURE__ */ new Set() : void 0;
650
- if (reused) {
765
+ let reused;
766
+ if (lastNodes.length > 0 && newNodes.length > 0) {
767
+ const lastSet = new Set(lastNodes);
768
+ reused = /* @__PURE__ */ new Set();
651
769
  for (let i2 = 0; i2 < newNodes.length; i2++) {
652
- for (let j = 0; j < lastNodes.length; j++) {
653
- if (newNodes[i2] === lastNodes[j]) {
654
- reused.add(newNodes[i2]);
655
- break;
656
- }
657
- }
770
+ if (lastSet.has(newNodes[i2])) reused.add(newNodes[i2]);
658
771
  }
659
772
  }
660
773
  for (let i2 = 0; i2 < lastNodes.length; i2++) {
@@ -697,7 +810,7 @@ function dispose(node) {
697
810
  while (stack.length > 0) {
698
811
  const current = stack.pop();
699
812
  order.push(current);
700
- const children = current.childNodes;
813
+ const children = Array.from(current.childNodes);
701
814
  for (let i2 = 0; i2 < children.length; i2++) {
702
815
  stack.push(children[i2]);
703
816
  }
@@ -706,9 +819,35 @@ function dispose(node) {
706
819
  const current = order[i2];
707
820
  const disposers = elementDisposers.get(current);
708
821
  if (disposers) {
709
- if (_isDev5) activeBindingCount -= disposers.length;
710
- for (const d of disposers) d();
822
+ const snapshot = disposers.slice();
711
823
  elementDisposers.delete(current);
824
+ if (_isDev5) activeBindingCount -= snapshot.length;
825
+ for (const d of snapshot) {
826
+ try {
827
+ d();
828
+ } catch (err) {
829
+ if (_isDev5 && typeof console !== "undefined") {
830
+ console.warn("[SibuJS] Disposer threw during cleanup:", err);
831
+ }
832
+ }
833
+ }
834
+ let extraPasses = 0;
835
+ while (extraPasses++ < 8) {
836
+ const added = elementDisposers.get(current);
837
+ if (!added || added.length === 0) break;
838
+ const moreSnapshot = added.slice();
839
+ elementDisposers.delete(current);
840
+ if (_isDev5) activeBindingCount -= moreSnapshot.length;
841
+ for (const d of moreSnapshot) {
842
+ try {
843
+ d();
844
+ } catch (err) {
845
+ if (_isDev5 && typeof console !== "undefined") {
846
+ console.warn("[SibuJS] Disposer threw during cleanup:", err);
847
+ }
848
+ }
849
+ }
850
+ }
712
851
  }
713
852
  }
714
853
  }
@@ -724,6 +863,30 @@ function checkLeaks(warnThreshold = 0) {
724
863
 
725
864
  // src/core/rendering/tagFactory.ts
726
865
  var SVG_NS = "http://www.w3.org/2000/svg";
866
+ var _isDev6 = isDev();
867
+ var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
868
+ function validateTagName(tag) {
869
+ const lower = tag.toLowerCase();
870
+ if (BLOCKED_TAGS.has(lower)) {
871
+ throw new Error(`tagFactory: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
872
+ }
873
+ }
874
+ var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
875
+ "config",
876
+ "location",
877
+ "history",
878
+ "document",
879
+ "window",
880
+ "navigator",
881
+ "name",
882
+ "top",
883
+ "parent",
884
+ "self",
885
+ "frames"
886
+ ]);
887
+ function setProp2(el, key, val) {
888
+ el[key] = val;
889
+ }
727
890
  var kebabCache = /* @__PURE__ */ new Map();
728
891
  function toKebab(prop) {
729
892
  let cached = kebabCache.get(prop);
@@ -848,79 +1011,103 @@ function appendChildren(el, nodes) {
848
1011
  }
849
1012
  }
850
1013
  }
851
- var tagFactory = (tag, ns) => (first, second) => {
852
- const el = ns ? document.createElementNS(ns, tag) : document.createElement(tag);
853
- if (first === void 0) return el;
854
- if (typeof first === "string") {
855
- if (second !== void 0) {
856
- el.setAttribute("class", first);
857
- appendChildren(el, second);
1014
+ var tagFactory = (tag, ns) => {
1015
+ return (first, second) => {
1016
+ validateTagName(tag);
1017
+ const el = ns ? document.createElementNS(ns, tag) : document.createElement(tag);
1018
+ if (first === void 0) return el;
1019
+ if (typeof first === "string") {
1020
+ if (second !== void 0) {
1021
+ el.setAttribute("class", first);
1022
+ appendChildren(el, second);
1023
+ return el;
1024
+ }
1025
+ el.textContent = first;
858
1026
  return el;
859
1027
  }
860
- el.textContent = first;
861
- return el;
862
- }
863
- if (typeof first === "number") {
864
- el.textContent = String(first);
865
- return el;
866
- }
867
- if (Array.isArray(first) || first instanceof Node || typeof first === "function") {
868
- appendChildren(el, first);
869
- return el;
870
- }
871
- const props = first;
872
- const pClass = props.class;
873
- if (pClass != null) applyClass(el, pClass);
874
- const pId = props.id;
875
- if (pId != null) el.id = pId;
876
- const pNodes = second !== void 0 ? second : props.nodes;
877
- if (pNodes != null) appendChildren(el, pNodes);
878
- const pOn = props.on;
879
- if (pOn) {
880
- for (const ev in pOn) {
881
- el.addEventListener(ev, pOn[ev]);
882
- }
883
- }
884
- const pStyle = props.style;
885
- if (pStyle != null) applyStyle(el, pStyle);
886
- const pRef = props.ref;
887
- if (pRef) pRef.current = el;
888
- for (const key in props) {
889
- switch (key) {
890
- case "class":
891
- case "id":
892
- case "nodes":
893
- case "on":
894
- case "style":
895
- case "ref":
896
- case "onElement":
897
- continue;
898
- // already handled above / below
899
- default: {
900
- const value = props[key];
901
- if (value == null) continue;
902
- if (key[0] === "o" && key[1] === "n") continue;
903
- if (typeof value === "function") {
904
- registerDisposer(el, bindAttribute(el, key, value));
905
- } else if (typeof value === "boolean") {
906
- if (key in el && (key === "checked" || key === "disabled" || key === "selected")) {
907
- el[key] = value;
908
- } else if (value) {
909
- el.setAttribute(key, "");
1028
+ if (typeof first === "number") {
1029
+ el.textContent = String(first);
1030
+ return el;
1031
+ }
1032
+ if (Array.isArray(first) || first instanceof Node || typeof first === "function") {
1033
+ appendChildren(el, first);
1034
+ return el;
1035
+ }
1036
+ const props = first;
1037
+ const pClass = props.class;
1038
+ if (pClass != null) applyClass(el, pClass);
1039
+ const pId = props.id;
1040
+ if (pId != null) {
1041
+ if (_isDev6 && typeof pId === "string" && CLOBBER_RISKY_IDS.has(pId.toLowerCase())) {
1042
+ devWarn(
1043
+ `tagFactory: element id="${pId}" matches a common global and may cause DOM clobbering. Avoid setting ids from untrusted input.`
1044
+ );
1045
+ }
1046
+ el.id = pId;
1047
+ }
1048
+ const pNodes = second !== void 0 ? second : props.nodes;
1049
+ if (pNodes != null) appendChildren(el, pNodes);
1050
+ const pOn = props.on;
1051
+ if (pOn) {
1052
+ for (const ev in pOn) {
1053
+ const handler = pOn[ev];
1054
+ if (typeof handler === "function") {
1055
+ el.addEventListener(ev, handler);
1056
+ } else if (_isDev6) {
1057
+ devWarn(
1058
+ `tagFactory: on.${ev} handler is not a function (got ${typeof handler}). Event listener was not attached.`
1059
+ );
1060
+ }
1061
+ }
1062
+ }
1063
+ const pStyle = props.style;
1064
+ if (pStyle != null) applyStyle(el, pStyle);
1065
+ const pRef = props.ref;
1066
+ if (pRef) pRef.current = el;
1067
+ for (const key in props) {
1068
+ switch (key) {
1069
+ case "class":
1070
+ case "id":
1071
+ case "nodes":
1072
+ case "on":
1073
+ case "style":
1074
+ case "ref":
1075
+ case "onElement":
1076
+ continue;
1077
+ // already handled above / below
1078
+ default: {
1079
+ const value = props[key];
1080
+ if (value == null) continue;
1081
+ const lkey = key.toLowerCase();
1082
+ if (lkey[0] === "o" && lkey[1] === "n") continue;
1083
+ if (typeof value === "function") {
1084
+ registerDisposer(el, bindAttribute(el, key, value));
1085
+ } else if (typeof value === "boolean") {
1086
+ if (key in el && (key === "checked" || key === "disabled" || key === "selected")) {
1087
+ setProp2(el, key, value);
1088
+ } else if (value) {
1089
+ el.setAttribute(key, "");
1090
+ } else {
1091
+ el.removeAttribute(key);
1092
+ }
910
1093
  } else {
911
- el.removeAttribute(key);
1094
+ const str = String(value);
1095
+ if (lkey === "srcset") {
1096
+ el.setAttribute(key, sanitizeSrcset(str));
1097
+ } else if (isUrlAttribute(lkey)) {
1098
+ el.setAttribute(key, sanitizeUrl(str));
1099
+ } else {
1100
+ el.setAttribute(key, str);
1101
+ }
912
1102
  }
913
- } else {
914
- const str = String(value);
915
- el.setAttribute(key, isUrlAttribute(key) ? sanitizeUrl(str) : str);
916
1103
  }
917
1104
  }
918
1105
  }
919
- }
920
- if (props.onElement && typeof props.onElement === "function") {
921
- props.onElement(el);
922
- }
923
- return el;
1106
+ if (props.onElement && typeof props.onElement === "function") {
1107
+ props.onElement(el);
1108
+ }
1109
+ return el;
1110
+ };
924
1111
  };
925
1112
 
926
1113
  // src/core/rendering/html.ts
@@ -1063,6 +1250,8 @@ var marquee = tagFactory("marquee");
1063
1250
  var customElement = (tagName) => tagFactory(tagName);
1064
1251
 
1065
1252
  // src/core/rendering/htm.ts
1253
+ var _isDev7 = isDev();
1254
+ var RAW_TEXT_TAGS = /* @__PURE__ */ new Set(["script", "style"]);
1066
1255
  var VOID_ELEMENTS = /* @__PURE__ */ new Set([
1067
1256
  "area",
1068
1257
  "base",
@@ -1247,6 +1436,15 @@ function parseTemplate(strings) {
1247
1436
  children.push({ t: 0, el: { tag, svg: SVG_TAGS.has(tag), attrs, children: [] } });
1248
1437
  } else {
1249
1438
  const inner = parseChildren();
1439
+ if (RAW_TEXT_TAGS.has(tag.toLowerCase())) {
1440
+ for (let i2 = 0; i2 < inner.length; i2++) {
1441
+ if (inner[i2].t === 2) {
1442
+ throw new Error(
1443
+ `html: dynamic \${...} expressions are not allowed inside <${tag}> (raw-text context). Build the content separately and append it as a Node.`
1444
+ );
1445
+ }
1446
+ }
1447
+ }
1250
1448
  if (template2[pos] === "<" && pos + 1 < len && template2[pos + 1] === "/") {
1251
1449
  pos += 2;
1252
1450
  readTagName();
@@ -1273,27 +1471,50 @@ function executeElement(tmpl, values) {
1273
1471
  break;
1274
1472
  case 1: {
1275
1473
  const name = attr.name;
1276
- if (name[0] === "o" && name[1] === "n") break;
1474
+ const lname = name.toLowerCase();
1475
+ if (lname[0] === "o" && lname[1] === "n") break;
1277
1476
  const val = values[attr.idx];
1278
1477
  if (typeof val === "function") {
1279
1478
  registerDisposer(el, bindAttribute(el, name, val));
1280
1479
  } else if (val != null) {
1281
1480
  const str = String(val);
1282
- el.setAttribute(name, isUrlAttribute(name) ? sanitizeUrl(str) : str);
1481
+ if (lname === "srcset") {
1482
+ el.setAttribute(name, sanitizeSrcset(str));
1483
+ } else if (isUrlAttribute(lname)) {
1484
+ el.setAttribute(name, sanitizeUrl(str));
1485
+ } else {
1486
+ el.setAttribute(name, str);
1487
+ }
1283
1488
  }
1284
1489
  break;
1285
1490
  }
1286
1491
  case 2: {
1287
1492
  let val = attr.statics[0];
1288
1493
  for (let j = 0; j < attr.exprs.length; j++) {
1289
- val += String(values[attr.exprs[j]]) + attr.statics[j + 1];
1494
+ const ev = values[attr.exprs[j]];
1495
+ val += (ev == null ? "" : String(ev)) + attr.statics[j + 1];
1496
+ }
1497
+ const lname2 = attr.name.toLowerCase();
1498
+ if (lname2 === "srcset") {
1499
+ el.setAttribute(attr.name, sanitizeSrcset(val));
1500
+ } else if (isUrlAttribute(lname2)) {
1501
+ el.setAttribute(attr.name, sanitizeUrl(val));
1502
+ } else {
1503
+ el.setAttribute(attr.name, val);
1290
1504
  }
1291
- el.setAttribute(attr.name, val);
1292
1505
  break;
1293
1506
  }
1294
- case 3:
1295
- el.addEventListener(attr.name, values[attr.idx]);
1507
+ case 3: {
1508
+ const fn = values[attr.idx];
1509
+ if (typeof fn === "function") {
1510
+ el.addEventListener(attr.name, fn);
1511
+ } else if (_isDev7) {
1512
+ devWarn(
1513
+ `html: on:${attr.name} handler is not a function (got ${typeof fn}). Event listener was not attached.`
1514
+ );
1515
+ }
1296
1516
  break;
1517
+ }
1297
1518
  case 4:
1298
1519
  el.setAttribute(attr.name, "");
1299
1520
  break;
@@ -1387,7 +1608,7 @@ function html2(strings, ...values) {
1387
1608
  function mount(component, container) {
1388
1609
  if (!container) {
1389
1610
  throw new Error(
1390
- "[Sibu] mount: container element not found. Make sure the DOM element exists before calling mount()."
1611
+ "[SibuJS mount] container element not found. Make sure the DOM element exists before calling mount()."
1391
1612
  );
1392
1613
  }
1393
1614
  devAssert(
@@ -1415,7 +1636,7 @@ function mount(component, container) {
1415
1636
  }
1416
1637
 
1417
1638
  // src/core/rendering/each.ts
1418
- var _isDev6 = isDev();
1639
+ var _isDev8 = isDev();
1419
1640
  function resolveNodeChild(child) {
1420
1641
  if (typeof child === "function") {
1421
1642
  return resolveNodeChild(child());
@@ -1510,17 +1731,31 @@ function each(getArray, render, options) {
1510
1731
  node = existing;
1511
1732
  } else {
1512
1733
  const itemKey = key;
1513
- const itemGetter = () => getArray()[keyIndexMap.get(itemKey)];
1734
+ const itemGetter = () => untracked(() => getArray()[keyIndexMap.get(itemKey)]);
1514
1735
  const indexGetter = () => keyIndexMap.get(itemKey);
1515
1736
  try {
1516
1737
  node = resolveNodeChild(render(itemGetter, indexGetter));
1517
1738
  } catch (err) {
1518
- if (_isDev6) {
1739
+ if (_isDev8) {
1519
1740
  devWarn(
1520
1741
  `each: render threw for item at index ${i2} (key="${newKeys[i2]}"): ${err instanceof Error ? err.message : String(err)}`
1521
1742
  );
1522
1743
  }
1523
1744
  node = document.createComment(`each:error:${i2}`);
1745
+ const errorObj = err instanceof Error ? err : new Error(String(err));
1746
+ queueMicrotask(() => {
1747
+ try {
1748
+ const target = anchor.parentNode;
1749
+ if (target?.dispatchEvent) {
1750
+ target.dispatchEvent(
1751
+ new CustomEvent("sibu:error-propagate", { bubbles: true, detail: { error: errorObj } })
1752
+ );
1753
+ } else if (_isDev8) {
1754
+ devWarn(`each: error not surfaced \u2014 anchor detached: ${errorObj.message}`);
1755
+ }
1756
+ } catch {
1757
+ }
1758
+ });
1524
1759
  }
1525
1760
  }
1526
1761
  workMap.set(key, node);
@@ -1589,7 +1824,8 @@ function each(getArray, render, options) {
1589
1824
  workMap = tmp;
1590
1825
  initialized = true;
1591
1826
  };
1592
- track(update);
1827
+ const untrack = track(update);
1828
+ registerDisposer(anchor, untrack);
1593
1829
  if (!initialized) {
1594
1830
  queueMicrotask(() => {
1595
1831
  if (!initialized && anchor.parentNode) {
@@ -1636,24 +1872,36 @@ function Portal(nodes, target) {
1636
1872
  const anchor = document.createComment("portal");
1637
1873
  const container = target || document.body;
1638
1874
  let portalContent = null;
1875
+ let disposed = false;
1639
1876
  queueMicrotask(() => {
1877
+ if (disposed) return;
1640
1878
  try {
1641
1879
  portalContent = nodes();
1642
1880
  container.appendChild(portalContent);
1643
1881
  } catch (err) {
1644
- console.error("[Portal] Render error:", err);
1882
+ if (typeof console !== "undefined") {
1883
+ console.error("[Portal] Render error:", err);
1884
+ }
1885
+ const errorObj = err instanceof Error ? err : new Error(String(err));
1886
+ queueMicrotask(() => {
1887
+ try {
1888
+ const target2 = anchor.parentNode;
1889
+ if (target2?.dispatchEvent) {
1890
+ target2.dispatchEvent(
1891
+ new CustomEvent("sibu:error-propagate", { bubbles: true, detail: { error: errorObj } })
1892
+ );
1893
+ }
1894
+ } catch {
1895
+ }
1896
+ });
1645
1897
  }
1646
1898
  });
1647
- const observer = new MutationObserver(() => {
1648
- if (!anchor.isConnected && portalContent) {
1899
+ registerDisposer(anchor, () => {
1900
+ disposed = true;
1901
+ if (portalContent) {
1902
+ dispose(portalContent);
1649
1903
  portalContent.remove();
1650
1904
  portalContent = null;
1651
- observer.disconnect();
1652
- }
1653
- });
1654
- queueMicrotask(() => {
1655
- if (anchor.parentNode) {
1656
- observer.observe(anchor.parentNode, { childList: true });
1657
1905
  }
1658
1906
  });
1659
1907
  return anchor;
@@ -1689,7 +1937,8 @@ function DynamicComponent(is) {
1689
1937
  }
1690
1938
  container.replaceChildren(el);
1691
1939
  }
1692
- track(render);
1940
+ const untrack = track(render);
1941
+ registerDisposer(container, untrack);
1693
1942
  return container;
1694
1943
  }
1695
1944
 
@@ -1779,11 +2028,16 @@ function KeepAlive(activeKey, cases, options) {
1779
2028
  const anchor = document.createComment("keep-alive");
1780
2029
  const cache2 = /* @__PURE__ */ new Map();
1781
2030
  const lruOrder = [];
1782
- const max = options?.max ?? 0;
2031
+ const max = options?.max ?? 10;
2032
+ if (max === 0 && isDev()) {
2033
+ devWarn("KeepAlive: unbounded cache (max: 0). Cached subtrees will never be evicted \u2014 set `max` to bound memory.");
2034
+ }
1783
2035
  let currentKey;
1784
2036
  let currentNode = null;
1785
2037
  let initialized = false;
2038
+ let disposed = false;
1786
2039
  const update = () => {
2040
+ if (disposed) return;
1787
2041
  const key = activeKey();
1788
2042
  const parent = anchor.parentNode;
1789
2043
  if (!parent) return;
@@ -1823,12 +2077,23 @@ function KeepAlive(activeKey, cases, options) {
1823
2077
  currentNode = node;
1824
2078
  initialized = true;
1825
2079
  };
1826
- track(update);
2080
+ const untrack = track(update);
1827
2081
  if (!initialized) {
1828
2082
  queueMicrotask(() => {
1829
2083
  if (!initialized && anchor.parentNode) update();
1830
2084
  });
1831
2085
  }
2086
+ registerDisposer(anchor, () => {
2087
+ disposed = true;
2088
+ untrack();
2089
+ for (const node of cache2.values()) {
2090
+ dispose(node);
2091
+ if (node.parentNode) node.parentNode.removeChild(node);
2092
+ }
2093
+ cache2.clear();
2094
+ lruOrder.length = 0;
2095
+ currentNode = null;
2096
+ });
1832
2097
  return anchor;
1833
2098
  }
1834
2099
 
@@ -1990,19 +2255,22 @@ function isBatching() {
1990
2255
  return batchDepth > 0;
1991
2256
  }
1992
2257
  function flushBatch() {
1993
- for (const signal2 of pendingSignals) {
1994
- queueSignalNotification(signal2);
2258
+ try {
2259
+ for (const signal2 of pendingSignals) {
2260
+ queueSignalNotification(signal2);
2261
+ }
2262
+ } finally {
2263
+ pendingSignals.clear();
1995
2264
  }
1996
- pendingSignals.clear();
1997
2265
  drainNotificationQueue();
1998
2266
  }
1999
2267
 
2000
2268
  // src/core/signals/signal.ts
2001
2269
  var _g = globalThis;
2002
- var _isDev7 = isDev();
2270
+ var _isDev9 = isDev();
2003
2271
  function signal(initial, options) {
2004
2272
  const state = { value: initial };
2005
- const debugName = _isDev7 ? options?.name : void 0;
2273
+ const debugName = _isDev9 ? options?.name : void 0;
2006
2274
  const equalsFn = options?.equals;
2007
2275
  if (debugName) {
2008
2276
  state.__name = debugName;
@@ -2016,7 +2284,7 @@ function signal(initial, options) {
2016
2284
  function set(next) {
2017
2285
  const newValue = typeof next === "function" ? next(state.value) : next;
2018
2286
  if (equalsFn ? equalsFn(state.value, newValue) : Object.is(newValue, state.value)) return;
2019
- if (_isDev7) {
2287
+ if (_isDev9) {
2020
2288
  const oldValue = state.value;
2021
2289
  state.value = newValue;
2022
2290
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
@@ -2028,7 +2296,7 @@ function signal(initial, options) {
2028
2296
  notifySubscribers(state);
2029
2297
  }
2030
2298
  }
2031
- if (_isDev7) {
2299
+ if (_isDev9) {
2032
2300
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
2033
2301
  if (hook) hook.emit("signal:create", { signal: state, name: debugName, getter: get, initial });
2034
2302
  }
@@ -2036,23 +2304,59 @@ function signal(initial, options) {
2036
2304
  }
2037
2305
 
2038
2306
  // src/core/ssr-context.ts
2039
- var ssrMode = false;
2307
+ var als = null;
2308
+ try {
2309
+ if (typeof process !== "undefined" && process.versions && process.versions.node) {
2310
+ const req = Function("return typeof require==='function'?require:null")();
2311
+ if (req) {
2312
+ const mod = req("node:async_hooks");
2313
+ als = new mod.AsyncLocalStorage();
2314
+ }
2315
+ }
2316
+ } catch {
2317
+ als = null;
2318
+ }
2319
+ var fallbackStore = { ssr: false, suspenseIdCounter: 0 };
2320
+ function getSSRStore() {
2321
+ if (als) {
2322
+ const s2 = als.getStore();
2323
+ if (s2) return s2;
2324
+ }
2325
+ return fallbackStore;
2326
+ }
2040
2327
  function isSSR() {
2041
- return ssrMode;
2328
+ return getSSRStore().ssr;
2042
2329
  }
2043
2330
  function enableSSR() {
2044
- ssrMode = true;
2331
+ getSSRStore().ssr = true;
2045
2332
  }
2046
2333
  function disableSSR() {
2047
- ssrMode = false;
2334
+ getSSRStore().ssr = false;
2335
+ }
2336
+ function runInSSRContext(fn) {
2337
+ const store2 = { ssr: true, suspenseIdCounter: 0 };
2338
+ if (als) {
2339
+ return als.run(store2, fn);
2340
+ }
2341
+ const prevSSR = fallbackStore.ssr;
2342
+ const prevCounter = fallbackStore.suspenseIdCounter;
2343
+ fallbackStore.ssr = true;
2344
+ fallbackStore.suspenseIdCounter = 0;
2345
+ try {
2346
+ return fn();
2347
+ } finally {
2348
+ fallbackStore.ssr = prevSSR;
2349
+ fallbackStore.suspenseIdCounter = prevCounter;
2350
+ }
2048
2351
  }
2049
2352
  function withSSR(fn) {
2050
- const wasSSR = ssrMode;
2051
- enableSSR();
2353
+ const store2 = getSSRStore();
2354
+ const wasSSR = store2.ssr;
2355
+ store2.ssr = true;
2052
2356
  try {
2053
2357
  return fn();
2054
2358
  } finally {
2055
- if (!wasSSR) disableSSR();
2359
+ if (!wasSSR) store2.ssr = false;
2056
2360
  }
2057
2361
  }
2058
2362
 
@@ -2079,26 +2383,86 @@ function effect(effectFn, options) {
2079
2383
  if (isSSR()) return () => {
2080
2384
  };
2081
2385
  const onError = options?.onError;
2386
+ let userCleanups = [];
2387
+ const onCleanup2 = (fn) => {
2388
+ userCleanups.push(fn);
2389
+ };
2390
+ const runUserCleanups = () => {
2391
+ if (userCleanups.length === 0) return;
2392
+ const list = userCleanups;
2393
+ userCleanups = [];
2394
+ for (let i2 = list.length - 1; i2 >= 0; i2--) {
2395
+ try {
2396
+ list[i2]();
2397
+ } catch (err) {
2398
+ if (typeof console !== "undefined") {
2399
+ console.warn("[SibuJS effect] onCleanup threw:", err);
2400
+ }
2401
+ }
2402
+ }
2403
+ };
2404
+ const invokeBody = () => effectFn(onCleanup2);
2082
2405
  const wrappedFn = onError ? () => {
2083
2406
  try {
2084
- effectFn();
2407
+ invokeBody();
2085
2408
  } catch (err) {
2086
2409
  onError(err);
2087
2410
  }
2088
- } : effectFn;
2411
+ } : invokeBody;
2089
2412
  let cleanupHandle = () => {
2090
2413
  };
2414
+ let running = false;
2091
2415
  const subscriber = () => {
2092
- cleanupHandle();
2093
- cleanupHandle = track(wrappedFn, subscriber);
2416
+ if (running) {
2417
+ if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
2418
+ console.warn(
2419
+ "[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."
2420
+ );
2421
+ }
2422
+ return;
2423
+ }
2424
+ running = true;
2425
+ try {
2426
+ runUserCleanups();
2427
+ cleanupHandle();
2428
+ cleanupHandle = track(wrappedFn, subscriber);
2429
+ } finally {
2430
+ running = false;
2431
+ }
2094
2432
  };
2095
- cleanupHandle = track(wrappedFn, subscriber);
2433
+ running = true;
2434
+ try {
2435
+ cleanupHandle = track(wrappedFn, subscriber);
2436
+ } finally {
2437
+ running = false;
2438
+ }
2096
2439
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
2097
2440
  if (hook) hook.emit("effect:create", { effectFn });
2441
+ let disposed = false;
2098
2442
  return () => {
2443
+ if (disposed) return;
2444
+ disposed = true;
2099
2445
  const h = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
2100
- if (h) h.emit("effect:destroy", { effectFn });
2101
- cleanupHandle();
2446
+ if (h) {
2447
+ try {
2448
+ h.emit("effect:destroy", { effectFn });
2449
+ } catch {
2450
+ }
2451
+ }
2452
+ try {
2453
+ runUserCleanups();
2454
+ } catch (err) {
2455
+ if (typeof console !== "undefined") {
2456
+ console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
2457
+ }
2458
+ }
2459
+ try {
2460
+ cleanupHandle();
2461
+ } catch (err) {
2462
+ if (typeof console !== "undefined") {
2463
+ console.warn("[SibuJS effect] dispose threw:", err);
2464
+ }
2465
+ }
2102
2466
  };
2103
2467
  }
2104
2468
 
@@ -2106,6 +2470,7 @@ function effect(effectFn, options) {
2106
2470
  function derived(getter, options) {
2107
2471
  devAssert(typeof getter === "function", "derived: argument must be a getter function.");
2108
2472
  const debugName = options?.name;
2473
+ const equals = options?.equals;
2109
2474
  const cs = {};
2110
2475
  cs._d = false;
2111
2476
  cs._g = getter;
@@ -2116,25 +2481,56 @@ function derived(getter, options) {
2116
2481
  markDirty._c = 1;
2117
2482
  markDirty._sig = cs;
2118
2483
  track(() => {
2119
- cs._d = false;
2120
- cs._v = getter();
2484
+ let threw = true;
2485
+ try {
2486
+ cs._v = getter();
2487
+ cs._d = false;
2488
+ threw = false;
2489
+ } finally {
2490
+ if (threw) cs._d = true;
2491
+ }
2121
2492
  }, markDirty);
2122
2493
  const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
2494
+ let evaluating = false;
2123
2495
  function computedGetter() {
2496
+ if (evaluating) {
2497
+ throw new Error(
2498
+ `[SibuJS] Circular dependency detected in derived${debugName ? ` "${debugName}"` : ""}. A derived signal cannot read itself (directly or through a chain).`
2499
+ );
2500
+ }
2124
2501
  if (trackingSuspended) {
2125
2502
  if (cs._d) {
2126
- cs._d = false;
2127
- cs._v = getter();
2503
+ evaluating = true;
2504
+ let threw = true;
2505
+ try {
2506
+ retrack(() => {
2507
+ cs._v = getter();
2508
+ cs._d = false;
2509
+ threw = false;
2510
+ }, markDirty);
2511
+ } finally {
2512
+ evaluating = false;
2513
+ if (threw) cs._d = true;
2514
+ }
2128
2515
  }
2129
2516
  return cs._v;
2130
2517
  }
2131
2518
  recordDependency(cs);
2132
2519
  if (cs._d) {
2133
2520
  const oldValue = cs._v;
2134
- track(() => {
2135
- cs._d = false;
2136
- cs._v = getter();
2137
- }, markDirty);
2521
+ evaluating = true;
2522
+ let threw = true;
2523
+ try {
2524
+ retrack(() => {
2525
+ const next = getter();
2526
+ cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
2527
+ cs._d = false;
2528
+ threw = false;
2529
+ }, markDirty);
2530
+ } finally {
2531
+ evaluating = false;
2532
+ if (threw) cs._d = true;
2533
+ }
2138
2534
  if (hook && oldValue !== cs._v) {
2139
2535
  hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
2140
2536
  }
@@ -2195,7 +2591,7 @@ function store(initialState) {
2195
2591
  },
2196
2592
  set() {
2197
2593
  throw new Error(
2198
- "[Sibu] store: Direct mutation is not allowed. Use actions.setState() to update store properties."
2594
+ "[SibuJS store] Direct mutation is not allowed. Use actions.setState() to update store properties."
2199
2595
  );
2200
2596
  }
2201
2597
  });
@@ -2209,16 +2605,20 @@ function store(initialState) {
2209
2605
  const setState = (patch) => {
2210
2606
  const current = getSnapshot();
2211
2607
  const nextState = typeof patch === "function" ? patch(current) : patch;
2212
- Object.entries(nextState).forEach(([key, value]) => {
2213
- if (key in signals) {
2214
- signals[key][1](value);
2215
- }
2608
+ batch(() => {
2609
+ Object.entries(nextState).forEach(([key, value]) => {
2610
+ if (key in signals) {
2611
+ signals[key][1](value);
2612
+ }
2613
+ });
2216
2614
  });
2217
2615
  };
2218
2616
  const reset = () => {
2219
- Object.keys(initialState).forEach((key) => {
2220
- const setter = signals[key][1];
2221
- setter(initialState[key]);
2617
+ batch(() => {
2618
+ Object.keys(initialState).forEach((key) => {
2619
+ const setter = signals[key][1];
2620
+ setter(initialState[key]);
2621
+ });
2222
2622
  });
2223
2623
  };
2224
2624
  const subscribe = (callback) => {
@@ -2352,7 +2752,8 @@ function reactiveArray(initial = []) {
2352
2752
  function get() {
2353
2753
  recordDependency(signal2);
2354
2754
  if (snapshot === null) {
2355
- snapshot = Object.freeze([...data2]);
2755
+ const copy = data2.slice();
2756
+ snapshot = Object.freeze(copy);
2356
2757
  }
2357
2758
  return snapshot;
2358
2759
  }
@@ -2462,21 +2863,67 @@ function deepEqual(a2, b2, seen) {
2462
2863
  if (a2 == null || b2 == null) return false;
2463
2864
  if (typeof a2 !== typeof b2) return false;
2464
2865
  if (typeof a2 !== "object") return false;
2465
- if (a2 instanceof Date && b2 instanceof Date) return a2.getTime() === b2.getTime();
2466
- if (a2 instanceof RegExp && b2 instanceof RegExp) return a2.toString() === b2.toString();
2467
- if (!seen) seen = /* @__PURE__ */ new Set();
2468
- if (seen.has(a2)) return true;
2469
- seen.add(a2);
2866
+ const objA = a2;
2867
+ const objB = b2;
2868
+ if (objA.constructor !== objB.constructor) return false;
2869
+ if (a2 instanceof Date) return a2.getTime() === b2.getTime();
2870
+ if (a2 instanceof RegExp) {
2871
+ const rb = b2;
2872
+ return a2.source === rb.source && a2.flags === rb.flags;
2873
+ }
2874
+ if (!seen) seen = /* @__PURE__ */ new Map();
2875
+ let peers = seen.get(objA);
2876
+ if (peers?.has(objB)) return true;
2877
+ if (!peers) {
2878
+ peers = /* @__PURE__ */ new Set();
2879
+ seen.set(objA, peers);
2880
+ }
2881
+ peers.add(objB);
2882
+ if (a2 instanceof Map) {
2883
+ const mb = b2;
2884
+ if (a2.size !== mb.size) return false;
2885
+ for (const [k, v] of a2) {
2886
+ if (!mb.has(k)) return false;
2887
+ if (!deepEqual(v, mb.get(k), seen)) return false;
2888
+ }
2889
+ return true;
2890
+ }
2891
+ if (a2 instanceof Set) {
2892
+ const sb = b2;
2893
+ if (a2.size !== sb.size) return false;
2894
+ for (const item of a2) {
2895
+ if (!sb.has(item)) return false;
2896
+ }
2897
+ return true;
2898
+ }
2899
+ if (a2 instanceof ArrayBuffer) {
2900
+ const viewA = new Uint8Array(a2);
2901
+ const viewB = new Uint8Array(b2);
2902
+ if (viewA.length !== viewB.length) return false;
2903
+ for (let i2 = 0; i2 < viewA.length; i2++) {
2904
+ if (viewA[i2] !== viewB[i2]) return false;
2905
+ }
2906
+ return true;
2907
+ }
2908
+ if (ArrayBuffer.isView(a2) && ArrayBuffer.isView(b2)) {
2909
+ const ta = a2;
2910
+ const tb = b2;
2911
+ if (ta.length !== tb.length) return false;
2912
+ for (let i2 = 0; i2 < ta.length; i2++) {
2913
+ if (ta[i2] !== tb[i2]) return false;
2914
+ }
2915
+ return true;
2916
+ }
2470
2917
  if (Array.isArray(a2)) {
2471
2918
  if (!Array.isArray(b2)) return false;
2472
2919
  if (a2.length !== b2.length) return false;
2473
2920
  return a2.every((val, i2) => deepEqual(val, b2[i2], seen));
2474
2921
  }
2475
- const keysA = Object.keys(a2);
2476
- const keysB = Object.keys(b2);
2922
+ const keysA = Object.keys(objA);
2923
+ const keysB = Object.keys(objB);
2477
2924
  if (keysA.length !== keysB.length) return false;
2478
2925
  return keysA.every(
2479
- (key) => deepEqual(a2[key], b2[key], seen)
2926
+ (key) => deepEqual(objA[key], objB[key], seen)
2480
2927
  );
2481
2928
  }
2482
2929
  function deepSignal(initial) {
@@ -2502,26 +2949,34 @@ function asyncDerived(factory, initial) {
2502
2949
  effect(() => {
2503
2950
  tick();
2504
2951
  const currentRun = ++runId;
2505
- setLoading(true);
2506
- setError(null);
2952
+ batch(() => {
2953
+ setLoading(true);
2954
+ setError(null);
2955
+ });
2507
2956
  let promise;
2508
2957
  try {
2509
2958
  promise = factory();
2510
2959
  } catch (err) {
2511
- setError(err);
2512
- setLoading(false);
2960
+ batch(() => {
2961
+ setError(err);
2962
+ setLoading(false);
2963
+ });
2513
2964
  return;
2514
2965
  }
2515
2966
  promise.then(
2516
2967
  (result) => {
2517
2968
  if (currentRun !== runId) return;
2518
- setValue(result);
2519
- setLoading(false);
2969
+ batch(() => {
2970
+ setValue(result);
2971
+ setLoading(false);
2972
+ });
2520
2973
  },
2521
2974
  (err) => {
2522
2975
  if (currentRun !== runId) return;
2523
- setError(err);
2524
- setLoading(false);
2976
+ batch(() => {
2977
+ setError(err);
2978
+ setLoading(false);
2979
+ });
2525
2980
  }
2526
2981
  );
2527
2982
  });
@@ -2536,32 +2991,198 @@ function asyncDerived(factory, initial) {
2536
2991
  // src/core/rendering/lifecycle.ts
2537
2992
  function safeCall(cb, hookName) {
2538
2993
  try {
2539
- cb();
2994
+ return cb();
2540
2995
  } catch (err) {
2541
2996
  devWarn(`${hookName}: callback threw: ${err instanceof Error ? err.message : String(err)}`);
2997
+ return void 0;
2998
+ }
2999
+ }
3000
+ function runMountCallback(callback, hookName, element) {
3001
+ const cleanup2 = safeCall(callback, hookName);
3002
+ if (typeof cleanup2 === "function" && element) {
3003
+ registerDisposer(element, cleanup2);
3004
+ }
3005
+ }
3006
+ var mountWatchers = /* @__PURE__ */ new WeakMap();
3007
+ var unmountWatchers = /* @__PURE__ */ new WeakMap();
3008
+ var watchedMountElements = /* @__PURE__ */ new Set();
3009
+ var watchedUnmountElements = /* @__PURE__ */ new Set();
3010
+ var sharedObserver = null;
3011
+ var mutationCounter = 0;
3012
+ var FULL_SWEEP_INTERVAL = 256;
3013
+ function fireMount(el) {
3014
+ const cbs = mountWatchers.get(el);
3015
+ if (!cbs) return;
3016
+ mountWatchers.delete(el);
3017
+ watchedMountElements.delete(el);
3018
+ for (const cb of cbs) {
3019
+ try {
3020
+ cb();
3021
+ } catch {
3022
+ }
3023
+ }
3024
+ }
3025
+ function fireUnmount(el) {
3026
+ const cbs = unmountWatchers.get(el);
3027
+ if (!cbs) return;
3028
+ queueMicrotask(() => {
3029
+ if (el.isConnected) return;
3030
+ const stillCbs = unmountWatchers.get(el);
3031
+ if (!stillCbs) return;
3032
+ unmountWatchers.delete(el);
3033
+ watchedUnmountElements.delete(el);
3034
+ for (const cb of stillCbs) {
3035
+ try {
3036
+ cb();
3037
+ } catch {
3038
+ }
3039
+ }
3040
+ });
3041
+ }
3042
+ function visitAddedNode(node) {
3043
+ if (watchedMountElements.size === 0) return;
3044
+ if (node.nodeType !== 1) return;
3045
+ const el = node;
3046
+ if (watchedMountElements.has(el) && el.isConnected) {
3047
+ fireMount(el);
3048
+ }
3049
+ if (el.firstElementChild) {
3050
+ for (const watched of Array.from(watchedMountElements)) {
3051
+ if (watched !== el && watched.isConnected && el.contains(watched)) {
3052
+ fireMount(watched);
3053
+ }
3054
+ }
3055
+ }
3056
+ }
3057
+ function visitRemovedNode(node) {
3058
+ if (watchedUnmountElements.size === 0) return;
3059
+ if (node.nodeType !== 1) return;
3060
+ const el = node;
3061
+ if (watchedUnmountElements.has(el) && !el.isConnected) {
3062
+ fireUnmount(el);
3063
+ }
3064
+ if (el.firstElementChild) {
3065
+ for (const watched of Array.from(watchedUnmountElements)) {
3066
+ if (watched !== el && !watched.isConnected && el.contains(watched)) {
3067
+ fireUnmount(watched);
3068
+ }
3069
+ }
3070
+ }
3071
+ }
3072
+ function fullSweep() {
3073
+ if (watchedMountElements.size > 0) {
3074
+ for (const el of Array.from(watchedMountElements)) {
3075
+ if (el.isConnected) fireMount(el);
3076
+ }
3077
+ }
3078
+ if (watchedUnmountElements.size > 0) {
3079
+ for (const el of Array.from(watchedUnmountElements)) {
3080
+ if (!el.isConnected) fireUnmount(el);
3081
+ }
2542
3082
  }
2543
3083
  }
3084
+ function ensureObserver() {
3085
+ if (sharedObserver || typeof document === "undefined") return;
3086
+ sharedObserver = new MutationObserver((mutations) => {
3087
+ for (const m of mutations) {
3088
+ if (m.type !== "childList") continue;
3089
+ if (m.addedNodes.length > 0) {
3090
+ for (let i2 = 0; i2 < m.addedNodes.length; i2++) {
3091
+ visitAddedNode(m.addedNodes[i2]);
3092
+ }
3093
+ }
3094
+ if (m.removedNodes.length > 0) {
3095
+ for (let i2 = 0; i2 < m.removedNodes.length; i2++) {
3096
+ visitRemovedNode(m.removedNodes[i2]);
3097
+ }
3098
+ }
3099
+ }
3100
+ mutationCounter += mutations.length;
3101
+ if (mutationCounter >= FULL_SWEEP_INTERVAL) {
3102
+ mutationCounter = 0;
3103
+ fullSweep();
3104
+ }
3105
+ maybeDisconnectObserver();
3106
+ });
3107
+ sharedObserver.observe(document.body, { childList: true, subtree: true });
3108
+ }
3109
+ function maybeDisconnectObserver() {
3110
+ if (!sharedObserver) return;
3111
+ if (watchedMountElements.size === 0 && watchedUnmountElements.size === 0) {
3112
+ sharedObserver.disconnect();
3113
+ sharedObserver = null;
3114
+ mutationCounter = 0;
3115
+ }
3116
+ }
3117
+ function registerMountWatcher(element, cb) {
3118
+ let list = mountWatchers.get(element);
3119
+ if (!list) {
3120
+ list = [];
3121
+ mountWatchers.set(element, list);
3122
+ }
3123
+ list.push(cb);
3124
+ watchedMountElements.add(element);
3125
+ ensureObserver();
3126
+ return () => {
3127
+ const cbs = mountWatchers.get(element);
3128
+ if (cbs) {
3129
+ const idx = cbs.indexOf(cb);
3130
+ if (idx !== -1) cbs.splice(idx, 1);
3131
+ if (cbs.length === 0) {
3132
+ mountWatchers.delete(element);
3133
+ watchedMountElements.delete(element);
3134
+ }
3135
+ }
3136
+ maybeDisconnectObserver();
3137
+ };
3138
+ }
3139
+ function registerUnmountWatcher(element, cb) {
3140
+ let list = unmountWatchers.get(element);
3141
+ if (!list) {
3142
+ list = [];
3143
+ unmountWatchers.set(element, list);
3144
+ }
3145
+ list.push(cb);
3146
+ watchedUnmountElements.add(element);
3147
+ ensureObserver();
3148
+ return () => {
3149
+ const cbs = unmountWatchers.get(element);
3150
+ if (cbs) {
3151
+ const idx = cbs.indexOf(cb);
3152
+ if (idx !== -1) cbs.splice(idx, 1);
3153
+ if (cbs.length === 0) {
3154
+ unmountWatchers.delete(element);
3155
+ watchedUnmountElements.delete(element);
3156
+ }
3157
+ }
3158
+ maybeDisconnectObserver();
3159
+ };
3160
+ }
2544
3161
  function onMount(callback, element) {
2545
3162
  if (typeof document === "undefined") return;
2546
3163
  if (element) {
3164
+ let disposed = false;
3165
+ registerDisposer(element, () => {
3166
+ disposed = true;
3167
+ });
2547
3168
  if (element.isConnected) {
2548
3169
  queueMicrotask(() => {
2549
- safeCall(callback, "onMount");
3170
+ if (disposed) return;
3171
+ runMountCallback(callback, "onMount", element);
2550
3172
  });
2551
3173
  return;
2552
3174
  }
2553
- const observer = new MutationObserver(() => {
2554
- if (element.isConnected) {
2555
- observer.disconnect();
2556
- safeCall(callback, "onMount");
2557
- }
2558
- });
2559
3175
  queueMicrotask(() => {
3176
+ if (disposed) return;
2560
3177
  if (element.isConnected) {
2561
- safeCall(callback, "onMount");
2562
- } else {
2563
- observer.observe(document.body, { childList: true, subtree: true });
3178
+ runMountCallback(callback, "onMount", element);
3179
+ return;
2564
3180
  }
3181
+ const unregister = registerMountWatcher(element, () => {
3182
+ if (disposed) return;
3183
+ runMountCallback(callback, "onMount", element);
3184
+ });
3185
+ registerDisposer(element, unregister);
2565
3186
  });
2566
3187
  } else {
2567
3188
  queueMicrotask(() => {
@@ -2570,20 +3191,24 @@ function onMount(callback, element) {
2570
3191
  }
2571
3192
  }
2572
3193
  function onUnmount(callback, element) {
2573
- const startObserving = () => {
2574
- const observer = new MutationObserver(() => {
2575
- if (!element.isConnected) {
2576
- observer.disconnect();
2577
- safeCall(callback, "onUnmount");
2578
- }
2579
- });
2580
- observer.observe(document.body, { childList: true, subtree: true });
3194
+ if (typeof document === "undefined") return;
3195
+ let fired = false;
3196
+ const fireOnce = () => {
3197
+ if (fired) return;
3198
+ fired = true;
3199
+ safeCall(callback, "onUnmount");
3200
+ };
3201
+ registerDisposer(element, fireOnce);
3202
+ const startWatching = () => {
3203
+ if (fired) return;
3204
+ const unregister = registerUnmountWatcher(element, fireOnce);
3205
+ registerDisposer(element, unregister);
2581
3206
  };
2582
3207
  if (element.isConnected) {
2583
- startObserving();
3208
+ startWatching();
2584
3209
  } else {
2585
3210
  onMount(() => {
2586
- startObserving();
3211
+ startWatching();
2587
3212
  return void 0;
2588
3213
  }, element);
2589
3214
  }
@@ -2595,9 +3220,11 @@ function onCleanup(callback, element) {
2595
3220
  // src/core/rendering/context.ts
2596
3221
  function context(defaultValue) {
2597
3222
  const [getValue, setValue] = signal(defaultValue);
2598
- return {
3223
+ const ctx = {
2599
3224
  provide(value) {
3225
+ const previous = getValue();
2600
3226
  setValue(value);
3227
+ return () => setValue(previous);
2601
3228
  },
2602
3229
  use() {
2603
3230
  return getValue;
@@ -2607,8 +3234,18 @@ function context(defaultValue) {
2607
3234
  },
2608
3235
  set(value) {
2609
3236
  setValue(value);
3237
+ },
3238
+ withContext(value, fn) {
3239
+ const previous = getValue();
3240
+ setValue(value);
3241
+ try {
3242
+ return fn();
3243
+ } finally {
3244
+ setValue(previous);
3245
+ }
2610
3246
  }
2611
3247
  };
3248
+ return ctx;
2612
3249
  }
2613
3250
 
2614
3251
  // src/core/strict.ts
@@ -2619,7 +3256,7 @@ function strict(fn) {
2619
3256
  try {
2620
3257
  fn();
2621
3258
  } catch (err) {
2622
- console.warn("[Sibu strict] second run threw:", err);
3259
+ console.warn("[SibuJS strict] second run threw:", err);
2623
3260
  }
2624
3261
  });
2625
3262
  }
@@ -2635,7 +3272,7 @@ function strictEffect(fn) {
2635
3272
  try {
2636
3273
  secondTeardown = effect(fn);
2637
3274
  } catch (err) {
2638
- console.warn("[Sibu strictEffect] second run threw:", err);
3275
+ console.warn("[SibuJS strictEffect] second run threw:", err);
2639
3276
  }
2640
3277
  });
2641
3278
  return () => {
@@ -2661,9 +3298,11 @@ function nextTick() {
2661
3298
  function defer(getter) {
2662
3299
  const [value, setValue] = signal(getter());
2663
3300
  let pending = false;
3301
+ let disposed = false;
2664
3302
  let latest = value();
2665
3303
  const flush = () => {
2666
3304
  pending = false;
3305
+ if (disposed) return;
2667
3306
  setValue(latest);
2668
3307
  };
2669
3308
  const schedule = () => {
@@ -2677,11 +3316,17 @@ function defer(getter) {
2677
3316
  }
2678
3317
  });
2679
3318
  };
2680
- track(() => {
3319
+ const teardown = track(() => {
2681
3320
  latest = getter();
2682
3321
  schedule();
2683
3322
  });
2684
- return value;
3323
+ const accessor = (() => value());
3324
+ accessor.dispose = () => {
3325
+ if (disposed) return;
3326
+ disposed = true;
3327
+ teardown();
3328
+ };
3329
+ return accessor;
2685
3330
  }
2686
3331
  var IDLE_FALLBACK_MS = 16;
2687
3332
  function scheduleIdle(fn) {
@@ -2722,32 +3367,56 @@ function transition() {
2722
3367
  }
2723
3368
 
2724
3369
  // src/core/rendering/lazy.ts
3370
+ var PENDING_ERROR = "__sibuPendingError";
3371
+ function dispatchPropagate(node, error) {
3372
+ const fire = () => {
3373
+ try {
3374
+ if (!node.parentNode) return false;
3375
+ node.dispatchEvent(new CustomEvent("sibu:error-propagate", { bubbles: true, detail: { error } }));
3376
+ return true;
3377
+ } catch {
3378
+ return false;
3379
+ }
3380
+ };
3381
+ if (node.parentNode && fire()) return;
3382
+ queueMicrotask(() => {
3383
+ if (fire()) return;
3384
+ node[PENDING_ERROR] = error;
3385
+ });
3386
+ }
3387
+ function takePendingError(node) {
3388
+ const rec = node;
3389
+ const err = rec[PENDING_ERROR];
3390
+ if (err instanceof Error) {
3391
+ delete rec[PENDING_ERROR];
3392
+ return err;
3393
+ }
3394
+ return void 0;
3395
+ }
2725
3396
  function lazy(importFn) {
2726
3397
  let cached = null;
2727
3398
  return function LazyComponent() {
2728
3399
  if (cached) {
2729
3400
  return cached();
2730
3401
  }
2731
- const [_status, setStatus] = signal("loading");
2732
- const [_error, setError] = signal(null);
2733
3402
  const container = div({ class: "sibu-lazy" });
3403
+ let disposed = false;
2734
3404
  importFn().then((mod) => {
3405
+ if (disposed) return;
2735
3406
  cached = mod.default;
2736
3407
  const rendered = cached();
2737
3408
  container.replaceChildren(rendered);
2738
- setStatus("loaded");
2739
3409
  }).catch((err) => {
3410
+ if (disposed) return;
2740
3411
  const errorObj = err instanceof Error ? err : new Error(String(err));
2741
- setError(errorObj);
2742
- setStatus("error");
2743
- container.replaceChildren(
2744
- div({
2745
- class: "sibu-lazy-error",
2746
- nodes: `Failed to load component: ${errorObj.message}`
2747
- })
2748
- );
3412
+ devWarn(`[SibuJS] lazy() failed to load component: ${errorObj.message}`);
3413
+ container.replaceChildren(div({ class: "sibu-lazy-error" }, `Failed to load component: ${errorObj.message}`));
3414
+ dispatchPropagate(container, errorObj);
3415
+ });
3416
+ container.appendChild(span("sibu-lazy-loading", "Loading..."));
3417
+ registerDisposer(container, () => {
3418
+ disposed = true;
2749
3419
  });
2750
- container.appendChild(span({ class: "sibu-lazy-loading", nodes: "Loading..." }));
2751
3420
  return container;
2752
3421
  };
2753
3422
  }
@@ -2755,32 +3424,55 @@ function Suspense({ nodes, fallback }) {
2755
3424
  const container = div({ class: "sibu-suspense" });
2756
3425
  const fallbackEl = fallback();
2757
3426
  container.appendChild(fallbackEl);
3427
+ let suspenseDisposed = false;
3428
+ let observer = null;
3429
+ registerDisposer(container, () => {
3430
+ suspenseDisposed = true;
3431
+ if (observer) {
3432
+ observer.disconnect();
3433
+ observer = null;
3434
+ }
3435
+ });
2758
3436
  queueMicrotask(() => {
3437
+ if (suspenseDisposed) return;
2759
3438
  try {
2760
3439
  const childEl = nodes();
2761
3440
  if (childEl.classList.contains("sibu-lazy")) {
2762
- const observer = new MutationObserver(() => {
3441
+ if (!childEl.querySelector(".sibu-lazy-loading")) {
3442
+ container.replaceChildren(childEl);
3443
+ return;
3444
+ }
3445
+ observer = new MutationObserver(() => {
3446
+ if (suspenseDisposed) return;
2763
3447
  const loading = childEl.querySelector(".sibu-lazy-loading");
2764
3448
  if (!loading) {
2765
- observer.disconnect();
3449
+ observer?.disconnect();
3450
+ observer = null;
2766
3451
  container.replaceChildren(childEl);
2767
3452
  }
2768
3453
  });
2769
3454
  observer.observe(childEl, { childList: true, subtree: true });
2770
- if (!childEl.querySelector(".sibu-lazy-loading")) {
2771
- container.replaceChildren(childEl);
2772
- }
2773
3455
  } else {
2774
3456
  container.replaceChildren(childEl);
2775
3457
  }
2776
- } catch {
3458
+ } catch (err) {
3459
+ const errorObj = err instanceof Error ? err : new Error(String(err));
3460
+ devWarn(`[SibuJS] Suspense nodes() threw: ${errorObj.message}`);
3461
+ dispatchPropagate(container, errorObj);
2777
3462
  }
2778
3463
  });
2779
3464
  return container;
2780
3465
  }
2781
3466
 
3467
+ // src/platform/ssr.ts
3468
+ var _isDev10 = isDev();
3469
+ function trustHTML(html3) {
3470
+ return html3;
3471
+ }
3472
+ var DEFAULT_MAX_SSR_BYTES = 1024 * 1024;
3473
+
2782
3474
  // src/components/ErrorDisplay.ts
2783
- var _isDev8 = isDev();
3475
+ var _isDev11 = isDev();
2784
3476
  var STYLES = `
2785
3477
  .sibu-error-display {
2786
3478
  border: 1px solid var(--sibu-err-border, #e5484d);
@@ -2866,20 +3558,21 @@ var STYLES = `
2866
3558
  font-weight: 600;
2867
3559
  }
2868
3560
  .sibu-error-display .sibu-err-copy-btn {
2869
- background: transparent;
2870
- border: 1px solid #3a3a4e;
3561
+ background: rgba(0, 0, 0, 0.22);
3562
+ border: 1px solid rgba(255, 255, 255, 0.15);
2871
3563
  border-radius: 4px;
2872
- color: #a0a3b8;
3564
+ color: rgba(255, 255, 255, 0.85);
2873
3565
  cursor: pointer;
2874
3566
  padding: 2px 10px;
2875
- font-size: 0.95em;
3567
+ font-size: 0.78em;
2876
3568
  font-family: inherit;
2877
3569
  transition: all 0.12s ease;
3570
+ flex-shrink: 0;
2878
3571
  }
2879
3572
  .sibu-error-display .sibu-err-copy-btn:hover {
2880
- background: #2a2a3e;
2881
- color: #e5e7eb;
2882
- border-color: #4a4a5e;
3573
+ background: rgba(0, 0, 0, 0.35);
3574
+ color: white;
3575
+ border-color: rgba(255, 255, 255, 0.3);
2883
3576
  }
2884
3577
 
2885
3578
  .sibu-error-display .sibu-err-stack {
@@ -3004,21 +3697,25 @@ function normalizeError(err) {
3004
3697
  cause: null
3005
3698
  };
3006
3699
  }
3007
- function buildCopyText(err, meta2) {
3700
+ function buildCopyText(err, meta2, headline) {
3008
3701
  const lines = [];
3702
+ lines.push(headline);
3009
3703
  lines.push(`[${err.code}] ${err.message}`);
3010
3704
  if (err.stack) {
3011
3705
  lines.push("");
3706
+ lines.push("Stack Trace:");
3012
3707
  lines.push(err.stack);
3013
3708
  }
3014
- if (err.cause) {
3709
+ let cause = err.cause;
3710
+ while (cause) {
3015
3711
  lines.push("");
3016
3712
  lines.push("Caused by:");
3017
- lines.push(` [${err.cause.code}] ${err.cause.message}`);
3018
- if (err.cause.stack) {
3019
- const indented = err.cause.stack.split("\n").map((l) => ` ${l}`).join("\n");
3713
+ lines.push(` [${cause.code}] ${cause.message}`);
3714
+ if (cause.stack) {
3715
+ const indented = cause.stack.split("\n").map((l) => ` ${l}`).join("\n");
3020
3716
  lines.push(indented);
3021
3717
  }
3718
+ cause = cause.cause;
3022
3719
  }
3023
3720
  if (meta2 && Object.keys(meta2).length > 0) {
3024
3721
  lines.push("");
@@ -3028,9 +3725,13 @@ function buildCopyText(err, meta2) {
3028
3725
  }
3029
3726
  }
3030
3727
  lines.push("");
3031
- lines.push(`At: ${(/* @__PURE__ */ new Date()).toISOString()}`);
3728
+ lines.push("Environment:");
3729
+ lines.push(` Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}`);
3730
+ if (typeof location !== "undefined") {
3731
+ lines.push(` URL: ${location.href}`);
3732
+ }
3032
3733
  if (typeof navigator !== "undefined" && navigator.userAgent) {
3033
- lines.push(`UA: ${navigator.userAgent}`);
3734
+ lines.push(` User Agent: ${navigator.userAgent}`);
3034
3735
  }
3035
3736
  return lines.join("\n");
3036
3737
  }
@@ -3082,7 +3783,7 @@ function ErrorDisplay(props) {
3082
3783
  injectStyles();
3083
3784
  const severity = props.severity ?? "error";
3084
3785
  const normalized = normalizeError(props.error);
3085
- const showDetails = props.alwaysShowDetails ?? _isDev8;
3786
+ const showDetails = props.alwaysShowDetails ?? _isDev11;
3086
3787
  const headline = props.title ?? normalized.message;
3087
3788
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
3088
3789
  const [copyLabel, setCopyLabel] = signal("Copy");
@@ -3091,7 +3792,7 @@ function ErrorDisplay(props) {
3091
3792
  nodes: () => copyLabel(),
3092
3793
  on: {
3093
3794
  click: () => {
3094
- const text2 = buildCopyText(normalized, props.metadata);
3795
+ const text2 = buildCopyText(normalized, props.metadata, headline);
3095
3796
  if (typeof navigator !== "undefined" && navigator.clipboard) {
3096
3797
  navigator.clipboard.writeText(text2).then(
3097
3798
  () => {
@@ -3112,6 +3813,7 @@ function ErrorDisplay(props) {
3112
3813
  nodes: [
3113
3814
  code({ class: "sibu-err-icon", nodes: normalized.code }),
3114
3815
  h3({ class: "sibu-err-title", nodes: headline }),
3816
+ copyBtn,
3115
3817
  span({ class: "sibu-err-timestamp", nodes: timestamp })
3116
3818
  ]
3117
3819
  });
@@ -3123,25 +3825,12 @@ function ErrorDisplay(props) {
3123
3825
  nodes: [
3124
3826
  div({
3125
3827
  class: "sibu-err-section-head",
3126
- nodes: [span({ nodes: "Stack Trace" }), copyBtn]
3828
+ nodes: [span({ nodes: "Stack Trace" })]
3127
3829
  }),
3128
3830
  renderFrames(normalized.frames)
3129
3831
  ]
3130
3832
  })
3131
3833
  );
3132
- } else if (showDetails) {
3133
- bodyChildren.push(
3134
- div({
3135
- class: "sibu-err-section",
3136
- nodes: [
3137
- div({
3138
- class: "sibu-err-section-head",
3139
- nodes: [span({ nodes: "Details" }), copyBtn]
3140
- }),
3141
- div({ class: "sibu-err-stack", nodes: "(no stack available)" })
3142
- ]
3143
- })
3144
- );
3145
3834
  }
3146
3835
  if (showDetails) {
3147
3836
  bodyChildren.push(...renderCauseChain(normalized.cause));
@@ -3157,37 +3846,6 @@ function ErrorDisplay(props) {
3157
3846
  })
3158
3847
  );
3159
3848
  }
3160
- if (showDetails && typeof navigator !== "undefined" && navigator.userAgent) {
3161
- bodyChildren.push(
3162
- div({
3163
- class: "sibu-err-section",
3164
- nodes: [
3165
- div({ class: "sibu-err-section-head", nodes: [span({ nodes: "Environment" })] }),
3166
- div({
3167
- class: "sibu-err-meta",
3168
- nodes: (() => {
3169
- const dl2 = document.createElement("dl");
3170
- dl2.className = "sibu-err-meta";
3171
- const entries = [
3172
- ["User Agent", navigator.userAgent],
3173
- ["URL", typeof location !== "undefined" ? location.href : "(n/a)"],
3174
- ["Timestamp", (/* @__PURE__ */ new Date()).toISOString()]
3175
- ];
3176
- for (const [k, v] of entries) {
3177
- const dt2 = document.createElement("dt");
3178
- dt2.textContent = k;
3179
- const dd2 = document.createElement("dd");
3180
- dd2.textContent = v;
3181
- dl2.appendChild(dt2);
3182
- dl2.appendChild(dd2);
3183
- }
3184
- return dl2;
3185
- })()
3186
- })
3187
- ]
3188
- })
3189
- );
3190
- }
3191
3849
  const actionButtons = [];
3192
3850
  if (props.onRetry) {
3193
3851
  actionButtons.push(
@@ -3382,6 +4040,7 @@ function injectStyles2() {
3382
4040
  stylesInjected = true;
3383
4041
  }
3384
4042
  }
4043
+ var FALLBACK_CACHE_MAX = 50;
3385
4044
  var fallbackCache = /* @__PURE__ */ new WeakMap();
3386
4045
  function getMemoizedFallback(fallbackFn, error, retry) {
3387
4046
  let cache2 = fallbackCache.get(fallbackFn);
@@ -3390,27 +4049,42 @@ function getMemoizedFallback(fallbackFn, error, retry) {
3390
4049
  fallbackCache.set(fallbackFn, cache2);
3391
4050
  }
3392
4051
  const key = error.message;
3393
- if (!cache2.has(key)) {
3394
- cache2.set(key, fallbackFn(error, retry));
4052
+ let factory = cache2.get(key);
4053
+ if (factory) {
4054
+ cache2.delete(key);
4055
+ cache2.set(key, factory);
4056
+ } else {
4057
+ factory = () => fallbackFn(error, retry);
4058
+ cache2.set(key, factory);
4059
+ if (cache2.size > FALLBACK_CACHE_MAX) {
4060
+ const oldestKey = cache2.keys().next().value;
4061
+ if (oldestKey !== void 0) cache2.delete(oldestKey);
4062
+ }
3395
4063
  }
3396
- return cache2.get(key);
4064
+ return factory();
3397
4065
  }
3398
4066
  function ErrorBoundary({ nodes, fallback, onError, resetKeys }) {
3399
4067
  injectStyles2();
3400
4068
  const [error, setError] = signal(null);
3401
4069
  const retry = () => {
3402
4070
  if (fallback) {
3403
- fallbackCache.delete(fallback);
4071
+ const cur = error();
4072
+ const inner = fallbackCache.get(fallback);
4073
+ if (cur && inner) inner.delete(cur.message);
3404
4074
  }
3405
4075
  setError(null);
3406
4076
  };
4077
+ let resetKeysTeardown = null;
3407
4078
  if (resetKeys && resetKeys.length > 0) {
3408
4079
  let initialized = false;
3409
- effect(() => {
4080
+ resetKeysTeardown = effect(() => {
3410
4081
  for (const k of resetKeys) {
3411
4082
  try {
3412
4083
  k();
3413
- } catch {
4084
+ } catch (err) {
4085
+ if (typeof console !== "undefined") {
4086
+ console.warn("[SibuJS ErrorBoundary] resetKeys getter threw:", err);
4087
+ }
3414
4088
  }
3415
4089
  }
3416
4090
  if (!initialized) {
@@ -3423,7 +4097,15 @@ function ErrorBoundary({ nodes, fallback, onError, resetKeys }) {
3423
4097
  const handleError = (e) => {
3424
4098
  const errorObj = e instanceof Error ? e : new Error(String(e));
3425
4099
  setError(errorObj);
3426
- onError?.(errorObj);
4100
+ if (onError) {
4101
+ try {
4102
+ onError(errorObj);
4103
+ } catch (cbErr) {
4104
+ if (typeof console !== "undefined") {
4105
+ console.error("[SibuJS ErrorBoundary] onError callback threw:", cbErr);
4106
+ }
4107
+ }
4108
+ }
3427
4109
  return errorObj;
3428
4110
  };
3429
4111
  const defaultFallback = (err, retryFn) => {
@@ -3475,7 +4157,7 @@ function ErrorBoundary({ nodes, fallback, onError, resetKeys }) {
3475
4157
  }
3476
4158
  }
3477
4159
  });
3478
- container.addEventListener("sibu:error-propagate", (e) => {
4160
+ const propagateListener = (e) => {
3479
4161
  if (error()) return;
3480
4162
  e.stopPropagation();
3481
4163
  const customEvent = e;
@@ -3483,6 +4165,30 @@ function ErrorBoundary({ nodes, fallback, onError, resetKeys }) {
3483
4165
  if (propagatedError) {
3484
4166
  handleError(propagatedError);
3485
4167
  }
4168
+ };
4169
+ container.addEventListener("sibu:error-propagate", propagateListener);
4170
+ onMount(() => {
4171
+ const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT);
4172
+ const collected = [];
4173
+ let node = walker.currentNode;
4174
+ while (node) {
4175
+ const pending = takePendingError(node);
4176
+ if (pending) collected.push(pending);
4177
+ node = walker.nextNode();
4178
+ }
4179
+ if (collected.length === 1) {
4180
+ handleError(collected[0]);
4181
+ } else if (collected.length > 1) {
4182
+ const Agg = globalThis.AggregateError;
4183
+ handleError(
4184
+ Agg ? new Agg(collected, `${collected.length} pre-mount errors caught by ErrorBoundary`) : new Error(collected.map((e) => e.message).join("; "))
4185
+ );
4186
+ }
4187
+ return void 0;
4188
+ }, container);
4189
+ registerDisposer(container, () => {
4190
+ if (resetKeysTeardown) resetKeysTeardown();
4191
+ container.removeEventListener("sibu:error-propagate", propagateListener);
3486
4192
  });
3487
4193
  return container;
3488
4194
  }
@@ -3658,6 +4364,7 @@ function Loading(props = {}) {
3658
4364
  footer,
3659
4365
  form,
3660
4366
  g,
4367
+ getSSRStore,
3661
4368
  getSlot,
3662
4369
  h1,
3663
4370
  h2,
@@ -3730,6 +4437,7 @@ function Loading(props = {}) {
3730
4437
  rp,
3731
4438
  rt,
3732
4439
  ruby,
4440
+ runInSSRContext,
3733
4441
  s,
3734
4442
  samp,
3735
4443
  script,
@@ -3755,6 +4463,7 @@ function Loading(props = {}) {
3755
4463
  symbol,
3756
4464
  table,
3757
4465
  tagFactory,
4466
+ takePendingError,
3758
4467
  tbody,
3759
4468
  td,
3760
4469
  template,
@@ -3769,6 +4478,7 @@ function Loading(props = {}) {
3769
4478
  track,
3770
4479
  transition,
3771
4480
  trapFocus,
4481
+ trustHTML,
3772
4482
  tspan,
3773
4483
  u,
3774
4484
  ul,