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
@@ -139,60 +139,68 @@ import {
139
139
  use,
140
140
  var_,
141
141
  video
142
- } from "./chunk-P3XWXJZU.js";
142
+ } from "./chunk-R73P76YZ.js";
143
143
  import {
144
144
  watch
145
- } from "./chunk-GJPXRJ45.js";
145
+ } from "./chunk-ITX6OO3F.js";
146
+ import {
147
+ trustHTML
148
+ } from "./chunk-JYD2PWXH.js";
146
149
  import {
147
150
  context
148
- } from "./chunk-6BMPXPUW.js";
151
+ } from "./chunk-GTBNNBJ6.js";
149
152
  import {
150
153
  SVG_NS,
151
154
  bindChildNode,
152
155
  tagFactory
153
- } from "./chunk-SFKNRVCU.js";
156
+ } from "./chunk-KLRMB5ZS.js";
154
157
  import {
155
158
  bindAttribute,
156
- bindDynamic,
159
+ bindDynamic
160
+ } from "./chunk-DFPFITST.js";
161
+ import {
162
+ derived
163
+ } from "./chunk-54EDRCEF.js";
164
+ import {
157
165
  checkLeaks,
158
166
  dispose,
159
167
  registerDisposer
160
- } from "./chunk-5ZYQ6KDD.js";
161
- import {
162
- derived
163
- } from "./chunk-XHK6BDAJ.js";
168
+ } from "./chunk-2UPRY23K.js";
164
169
  import {
165
170
  isUrlAttribute,
171
+ sanitizeSrcset,
166
172
  sanitizeUrl
167
- } from "./chunk-CMBFNA7L.js";
173
+ } from "./chunk-UCS6AMJ7.js";
168
174
  import {
169
175
  effect,
170
176
  on
171
- } from "./chunk-VQNQZCWJ.js";
177
+ } from "./chunk-HB24TBAF.js";
172
178
  import {
173
179
  disableSSR,
174
180
  enableSSR,
181
+ getSSRStore,
175
182
  isSSR,
183
+ runInSSRContext,
176
184
  withSSR
177
- } from "./chunk-EUZND3CB.js";
185
+ } from "./chunk-2RA7SHDA.js";
178
186
  import {
179
187
  batch,
180
188
  enqueueBatchedSignal,
181
189
  isBatching,
182
190
  signal
183
- } from "./chunk-NZIIMDWI.js";
191
+ } from "./chunk-CC65Y57T.js";
184
192
  import {
185
193
  notifySubscribers,
186
194
  recordDependency,
187
195
  track,
188
196
  untracked
189
- } from "./chunk-K4G4ZQNR.js";
197
+ } from "./chunk-VLPPXTYG.js";
190
198
  import {
191
199
  __export,
192
200
  devAssert,
193
201
  devWarn,
194
202
  isDev
195
- } from "./chunk-5X6PP2UK.js";
203
+ } from "./chunk-LMLD24FC.js";
196
204
 
197
205
  // index.ts
198
206
  var index_exports = {};
@@ -276,6 +284,7 @@ __export(index_exports, {
276
284
  footer: () => footer,
277
285
  form: () => form,
278
286
  g: () => g,
287
+ getSSRStore: () => getSSRStore,
279
288
  getSlot: () => getSlot,
280
289
  h1: () => h1,
281
290
  h2: () => h2,
@@ -348,6 +357,7 @@ __export(index_exports, {
348
357
  rp: () => rp,
349
358
  rt: () => rt,
350
359
  ruby: () => ruby,
360
+ runInSSRContext: () => runInSSRContext,
351
361
  s: () => s,
352
362
  samp: () => samp,
353
363
  script: () => script,
@@ -373,6 +383,7 @@ __export(index_exports, {
373
383
  symbol: () => symbol,
374
384
  table: () => table,
375
385
  tagFactory: () => tagFactory,
386
+ takePendingError: () => takePendingError,
376
387
  tbody: () => tbody,
377
388
  td: () => td,
378
389
  template: () => template,
@@ -387,6 +398,7 @@ __export(index_exports, {
387
398
  track: () => track2,
388
399
  transition: () => transition,
389
400
  trapFocus: () => trapFocus,
401
+ trustHTML: () => trustHTML,
390
402
  tspan: () => tspan,
391
403
  u: () => u,
392
404
  ul: () => ul,
@@ -402,6 +414,8 @@ __export(index_exports, {
402
414
  });
403
415
 
404
416
  // src/core/rendering/htm.ts
417
+ var _isDev = isDev();
418
+ var RAW_TEXT_TAGS = /* @__PURE__ */ new Set(["script", "style"]);
405
419
  var VOID_ELEMENTS = /* @__PURE__ */ new Set([
406
420
  "area",
407
421
  "base",
@@ -586,6 +600,15 @@ function parseTemplate(strings) {
586
600
  children.push({ t: 0, el: { tag, svg: SVG_TAGS.has(tag), attrs, children: [] } });
587
601
  } else {
588
602
  const inner = parseChildren();
603
+ if (RAW_TEXT_TAGS.has(tag.toLowerCase())) {
604
+ for (let i2 = 0; i2 < inner.length; i2++) {
605
+ if (inner[i2].t === 2) {
606
+ throw new Error(
607
+ `html: dynamic \${...} expressions are not allowed inside <${tag}> (raw-text context). Build the content separately and append it as a Node.`
608
+ );
609
+ }
610
+ }
611
+ }
589
612
  if (template2[pos] === "<" && pos + 1 < len && template2[pos + 1] === "/") {
590
613
  pos += 2;
591
614
  readTagName();
@@ -612,27 +635,50 @@ function executeElement(tmpl, values) {
612
635
  break;
613
636
  case 1: {
614
637
  const name = attr.name;
615
- if (name[0] === "o" && name[1] === "n") break;
638
+ const lname = name.toLowerCase();
639
+ if (lname[0] === "o" && lname[1] === "n") break;
616
640
  const val = values[attr.idx];
617
641
  if (typeof val === "function") {
618
642
  registerDisposer(el, bindAttribute(el, name, val));
619
643
  } else if (val != null) {
620
644
  const str = String(val);
621
- el.setAttribute(name, isUrlAttribute(name) ? sanitizeUrl(str) : str);
645
+ if (lname === "srcset") {
646
+ el.setAttribute(name, sanitizeSrcset(str));
647
+ } else if (isUrlAttribute(lname)) {
648
+ el.setAttribute(name, sanitizeUrl(str));
649
+ } else {
650
+ el.setAttribute(name, str);
651
+ }
622
652
  }
623
653
  break;
624
654
  }
625
655
  case 2: {
626
656
  let val = attr.statics[0];
627
657
  for (let j = 0; j < attr.exprs.length; j++) {
628
- val += String(values[attr.exprs[j]]) + attr.statics[j + 1];
658
+ const ev = values[attr.exprs[j]];
659
+ val += (ev == null ? "" : String(ev)) + attr.statics[j + 1];
660
+ }
661
+ const lname2 = attr.name.toLowerCase();
662
+ if (lname2 === "srcset") {
663
+ el.setAttribute(attr.name, sanitizeSrcset(val));
664
+ } else if (isUrlAttribute(lname2)) {
665
+ el.setAttribute(attr.name, sanitizeUrl(val));
666
+ } else {
667
+ el.setAttribute(attr.name, val);
629
668
  }
630
- el.setAttribute(attr.name, val);
631
669
  break;
632
670
  }
633
- case 3:
634
- el.addEventListener(attr.name, values[attr.idx]);
671
+ case 3: {
672
+ const fn = values[attr.idx];
673
+ if (typeof fn === "function") {
674
+ el.addEventListener(attr.name, fn);
675
+ } else if (_isDev) {
676
+ devWarn(
677
+ `html: on:${attr.name} handler is not a function (got ${typeof fn}). Event listener was not attached.`
678
+ );
679
+ }
635
680
  break;
681
+ }
636
682
  case 4:
637
683
  el.setAttribute(attr.name, "");
638
684
  break;
@@ -726,7 +772,7 @@ function html(strings, ...values) {
726
772
  function mount(component, container) {
727
773
  if (!container) {
728
774
  throw new Error(
729
- "[Sibu] mount: container element not found. Make sure the DOM element exists before calling mount()."
775
+ "[SibuJS mount] container element not found. Make sure the DOM element exists before calling mount()."
730
776
  );
731
777
  }
732
778
  devAssert(
@@ -754,7 +800,7 @@ function mount(component, container) {
754
800
  }
755
801
 
756
802
  // src/core/rendering/each.ts
757
- var _isDev = isDev();
803
+ var _isDev2 = isDev();
758
804
  function resolveNodeChild(child) {
759
805
  if (typeof child === "function") {
760
806
  return resolveNodeChild(child());
@@ -849,17 +895,31 @@ function each(getArray, render, options) {
849
895
  node = existing;
850
896
  } else {
851
897
  const itemKey = key;
852
- const itemGetter = () => getArray()[keyIndexMap.get(itemKey)];
898
+ const itemGetter = () => untracked(() => getArray()[keyIndexMap.get(itemKey)]);
853
899
  const indexGetter = () => keyIndexMap.get(itemKey);
854
900
  try {
855
901
  node = resolveNodeChild(render(itemGetter, indexGetter));
856
902
  } catch (err) {
857
- if (_isDev) {
903
+ if (_isDev2) {
858
904
  devWarn(
859
905
  `each: render threw for item at index ${i2} (key="${newKeys[i2]}"): ${err instanceof Error ? err.message : String(err)}`
860
906
  );
861
907
  }
862
908
  node = document.createComment(`each:error:${i2}`);
909
+ const errorObj = err instanceof Error ? err : new Error(String(err));
910
+ queueMicrotask(() => {
911
+ try {
912
+ const target = anchor.parentNode;
913
+ if (target?.dispatchEvent) {
914
+ target.dispatchEvent(
915
+ new CustomEvent("sibu:error-propagate", { bubbles: true, detail: { error: errorObj } })
916
+ );
917
+ } else if (_isDev2) {
918
+ devWarn(`each: error not surfaced \u2014 anchor detached: ${errorObj.message}`);
919
+ }
920
+ } catch {
921
+ }
922
+ });
863
923
  }
864
924
  }
865
925
  workMap.set(key, node);
@@ -928,7 +988,8 @@ function each(getArray, render, options) {
928
988
  workMap = tmp;
929
989
  initialized = true;
930
990
  };
931
- track(update);
991
+ const untrack = track(update);
992
+ registerDisposer(anchor, untrack);
932
993
  if (!initialized) {
933
994
  queueMicrotask(() => {
934
995
  if (!initialized && anchor.parentNode) {
@@ -975,7 +1036,9 @@ function Portal(nodes, target) {
975
1036
  const anchor = document.createComment("portal");
976
1037
  const container = target || document.body;
977
1038
  let portalContent = null;
1039
+ let disposed = false;
978
1040
  queueMicrotask(() => {
1041
+ if (disposed) return;
979
1042
  try {
980
1043
  portalContent = nodes();
981
1044
  container.appendChild(portalContent);
@@ -983,9 +1046,22 @@ function Portal(nodes, target) {
983
1046
  if (typeof console !== "undefined") {
984
1047
  console.error("[Portal] Render error:", err);
985
1048
  }
1049
+ const errorObj = err instanceof Error ? err : new Error(String(err));
1050
+ queueMicrotask(() => {
1051
+ try {
1052
+ const target2 = anchor.parentNode;
1053
+ if (target2?.dispatchEvent) {
1054
+ target2.dispatchEvent(
1055
+ new CustomEvent("sibu:error-propagate", { bubbles: true, detail: { error: errorObj } })
1056
+ );
1057
+ }
1058
+ } catch {
1059
+ }
1060
+ });
986
1061
  }
987
1062
  });
988
1063
  registerDisposer(anchor, () => {
1064
+ disposed = true;
989
1065
  if (portalContent) {
990
1066
  dispose(portalContent);
991
1067
  portalContent.remove();
@@ -1025,7 +1101,8 @@ function DynamicComponent(is) {
1025
1101
  }
1026
1102
  container.replaceChildren(el);
1027
1103
  }
1028
- track(render);
1104
+ const untrack = track(render);
1105
+ registerDisposer(container, untrack);
1029
1106
  return container;
1030
1107
  }
1031
1108
 
@@ -1115,11 +1192,16 @@ function KeepAlive(activeKey, cases, options) {
1115
1192
  const anchor = document.createComment("keep-alive");
1116
1193
  const cache2 = /* @__PURE__ */ new Map();
1117
1194
  const lruOrder = [];
1118
- const max = options?.max ?? 0;
1195
+ const max = options?.max ?? 10;
1196
+ if (max === 0 && isDev()) {
1197
+ devWarn("KeepAlive: unbounded cache (max: 0). Cached subtrees will never be evicted \u2014 set `max` to bound memory.");
1198
+ }
1119
1199
  let currentKey;
1120
1200
  let currentNode = null;
1121
1201
  let initialized = false;
1202
+ let disposed = false;
1122
1203
  const update = () => {
1204
+ if (disposed) return;
1123
1205
  const key = activeKey();
1124
1206
  const parent = anchor.parentNode;
1125
1207
  if (!parent) return;
@@ -1159,12 +1241,23 @@ function KeepAlive(activeKey, cases, options) {
1159
1241
  currentNode = node;
1160
1242
  initialized = true;
1161
1243
  };
1162
- track(update);
1244
+ const untrack = track(update);
1163
1245
  if (!initialized) {
1164
1246
  queueMicrotask(() => {
1165
1247
  if (!initialized && anchor.parentNode) update();
1166
1248
  });
1167
1249
  }
1250
+ registerDisposer(anchor, () => {
1251
+ disposed = true;
1252
+ untrack();
1253
+ for (const node of cache2.values()) {
1254
+ dispose(node);
1255
+ if (node.parentNode) node.parentNode.removeChild(node);
1256
+ }
1257
+ cache2.clear();
1258
+ lruOrder.length = 0;
1259
+ currentNode = null;
1260
+ });
1168
1261
  return anchor;
1169
1262
  }
1170
1263
 
@@ -1314,7 +1407,7 @@ function store(initialState) {
1314
1407
  },
1315
1408
  set() {
1316
1409
  throw new Error(
1317
- "[Sibu] store: Direct mutation is not allowed. Use actions.setState() to update store properties."
1410
+ "[SibuJS store] Direct mutation is not allowed. Use actions.setState() to update store properties."
1318
1411
  );
1319
1412
  }
1320
1413
  });
@@ -1328,16 +1421,20 @@ function store(initialState) {
1328
1421
  const setState = (patch) => {
1329
1422
  const current = getSnapshot();
1330
1423
  const nextState = typeof patch === "function" ? patch(current) : patch;
1331
- Object.entries(nextState).forEach(([key, value]) => {
1332
- if (key in signals) {
1333
- signals[key][1](value);
1334
- }
1424
+ batch(() => {
1425
+ Object.entries(nextState).forEach(([key, value]) => {
1426
+ if (key in signals) {
1427
+ signals[key][1](value);
1428
+ }
1429
+ });
1335
1430
  });
1336
1431
  };
1337
1432
  const reset = () => {
1338
- Object.keys(initialState).forEach((key) => {
1339
- const setter = signals[key][1];
1340
- setter(initialState[key]);
1433
+ batch(() => {
1434
+ Object.keys(initialState).forEach((key) => {
1435
+ const setter = signals[key][1];
1436
+ setter(initialState[key]);
1437
+ });
1341
1438
  });
1342
1439
  };
1343
1440
  const subscribe = (callback) => {
@@ -1471,7 +1568,8 @@ function reactiveArray(initial = []) {
1471
1568
  function get() {
1472
1569
  recordDependency(signal2);
1473
1570
  if (snapshot === null) {
1474
- snapshot = Object.freeze([...data2]);
1571
+ const copy = data2.slice();
1572
+ snapshot = Object.freeze(copy);
1475
1573
  }
1476
1574
  return snapshot;
1477
1575
  }
@@ -1667,26 +1765,34 @@ function asyncDerived(factory, initial) {
1667
1765
  effect(() => {
1668
1766
  tick();
1669
1767
  const currentRun = ++runId;
1670
- setLoading(true);
1671
- setError(null);
1768
+ batch(() => {
1769
+ setLoading(true);
1770
+ setError(null);
1771
+ });
1672
1772
  let promise;
1673
1773
  try {
1674
1774
  promise = factory();
1675
1775
  } catch (err) {
1676
- setError(err);
1677
- setLoading(false);
1776
+ batch(() => {
1777
+ setError(err);
1778
+ setLoading(false);
1779
+ });
1678
1780
  return;
1679
1781
  }
1680
1782
  promise.then(
1681
1783
  (result) => {
1682
1784
  if (currentRun !== runId) return;
1683
- setValue(result);
1684
- setLoading(false);
1785
+ batch(() => {
1786
+ setValue(result);
1787
+ setLoading(false);
1788
+ });
1685
1789
  },
1686
1790
  (err) => {
1687
1791
  if (currentRun !== runId) return;
1688
- setError(err);
1689
- setLoading(false);
1792
+ batch(() => {
1793
+ setError(err);
1794
+ setLoading(false);
1795
+ });
1690
1796
  }
1691
1797
  );
1692
1798
  });
@@ -1713,26 +1819,186 @@ function runMountCallback(callback, hookName, element) {
1713
1819
  registerDisposer(element, cleanup);
1714
1820
  }
1715
1821
  }
1822
+ var mountWatchers = /* @__PURE__ */ new WeakMap();
1823
+ var unmountWatchers = /* @__PURE__ */ new WeakMap();
1824
+ var watchedMountElements = /* @__PURE__ */ new Set();
1825
+ var watchedUnmountElements = /* @__PURE__ */ new Set();
1826
+ var sharedObserver = null;
1827
+ var mutationCounter = 0;
1828
+ var FULL_SWEEP_INTERVAL = 256;
1829
+ function fireMount(el) {
1830
+ const cbs = mountWatchers.get(el);
1831
+ if (!cbs) return;
1832
+ mountWatchers.delete(el);
1833
+ watchedMountElements.delete(el);
1834
+ for (const cb of cbs) {
1835
+ try {
1836
+ cb();
1837
+ } catch {
1838
+ }
1839
+ }
1840
+ }
1841
+ function fireUnmount(el) {
1842
+ const cbs = unmountWatchers.get(el);
1843
+ if (!cbs) return;
1844
+ queueMicrotask(() => {
1845
+ if (el.isConnected) return;
1846
+ const stillCbs = unmountWatchers.get(el);
1847
+ if (!stillCbs) return;
1848
+ unmountWatchers.delete(el);
1849
+ watchedUnmountElements.delete(el);
1850
+ for (const cb of stillCbs) {
1851
+ try {
1852
+ cb();
1853
+ } catch {
1854
+ }
1855
+ }
1856
+ });
1857
+ }
1858
+ function visitAddedNode(node) {
1859
+ if (watchedMountElements.size === 0) return;
1860
+ if (node.nodeType !== 1) return;
1861
+ const el = node;
1862
+ if (watchedMountElements.has(el) && el.isConnected) {
1863
+ fireMount(el);
1864
+ }
1865
+ if (el.firstElementChild) {
1866
+ for (const watched of Array.from(watchedMountElements)) {
1867
+ if (watched !== el && watched.isConnected && el.contains(watched)) {
1868
+ fireMount(watched);
1869
+ }
1870
+ }
1871
+ }
1872
+ }
1873
+ function visitRemovedNode(node) {
1874
+ if (watchedUnmountElements.size === 0) return;
1875
+ if (node.nodeType !== 1) return;
1876
+ const el = node;
1877
+ if (watchedUnmountElements.has(el) && !el.isConnected) {
1878
+ fireUnmount(el);
1879
+ }
1880
+ if (el.firstElementChild) {
1881
+ for (const watched of Array.from(watchedUnmountElements)) {
1882
+ if (watched !== el && !watched.isConnected && el.contains(watched)) {
1883
+ fireUnmount(watched);
1884
+ }
1885
+ }
1886
+ }
1887
+ }
1888
+ function fullSweep() {
1889
+ if (watchedMountElements.size > 0) {
1890
+ for (const el of Array.from(watchedMountElements)) {
1891
+ if (el.isConnected) fireMount(el);
1892
+ }
1893
+ }
1894
+ if (watchedUnmountElements.size > 0) {
1895
+ for (const el of Array.from(watchedUnmountElements)) {
1896
+ if (!el.isConnected) fireUnmount(el);
1897
+ }
1898
+ }
1899
+ }
1900
+ function ensureObserver() {
1901
+ if (sharedObserver || typeof document === "undefined") return;
1902
+ sharedObserver = new MutationObserver((mutations) => {
1903
+ for (const m of mutations) {
1904
+ if (m.type !== "childList") continue;
1905
+ if (m.addedNodes.length > 0) {
1906
+ for (let i2 = 0; i2 < m.addedNodes.length; i2++) {
1907
+ visitAddedNode(m.addedNodes[i2]);
1908
+ }
1909
+ }
1910
+ if (m.removedNodes.length > 0) {
1911
+ for (let i2 = 0; i2 < m.removedNodes.length; i2++) {
1912
+ visitRemovedNode(m.removedNodes[i2]);
1913
+ }
1914
+ }
1915
+ }
1916
+ mutationCounter += mutations.length;
1917
+ if (mutationCounter >= FULL_SWEEP_INTERVAL) {
1918
+ mutationCounter = 0;
1919
+ fullSweep();
1920
+ }
1921
+ maybeDisconnectObserver();
1922
+ });
1923
+ sharedObserver.observe(document.body, { childList: true, subtree: true });
1924
+ }
1925
+ function maybeDisconnectObserver() {
1926
+ if (!sharedObserver) return;
1927
+ if (watchedMountElements.size === 0 && watchedUnmountElements.size === 0) {
1928
+ sharedObserver.disconnect();
1929
+ sharedObserver = null;
1930
+ mutationCounter = 0;
1931
+ }
1932
+ }
1933
+ function registerMountWatcher(element, cb) {
1934
+ let list = mountWatchers.get(element);
1935
+ if (!list) {
1936
+ list = [];
1937
+ mountWatchers.set(element, list);
1938
+ }
1939
+ list.push(cb);
1940
+ watchedMountElements.add(element);
1941
+ ensureObserver();
1942
+ return () => {
1943
+ const cbs = mountWatchers.get(element);
1944
+ if (cbs) {
1945
+ const idx = cbs.indexOf(cb);
1946
+ if (idx !== -1) cbs.splice(idx, 1);
1947
+ if (cbs.length === 0) {
1948
+ mountWatchers.delete(element);
1949
+ watchedMountElements.delete(element);
1950
+ }
1951
+ }
1952
+ maybeDisconnectObserver();
1953
+ };
1954
+ }
1955
+ function registerUnmountWatcher(element, cb) {
1956
+ let list = unmountWatchers.get(element);
1957
+ if (!list) {
1958
+ list = [];
1959
+ unmountWatchers.set(element, list);
1960
+ }
1961
+ list.push(cb);
1962
+ watchedUnmountElements.add(element);
1963
+ ensureObserver();
1964
+ return () => {
1965
+ const cbs = unmountWatchers.get(element);
1966
+ if (cbs) {
1967
+ const idx = cbs.indexOf(cb);
1968
+ if (idx !== -1) cbs.splice(idx, 1);
1969
+ if (cbs.length === 0) {
1970
+ unmountWatchers.delete(element);
1971
+ watchedUnmountElements.delete(element);
1972
+ }
1973
+ }
1974
+ maybeDisconnectObserver();
1975
+ };
1976
+ }
1716
1977
  function onMount(callback, element) {
1717
1978
  if (typeof document === "undefined") return;
1718
1979
  if (element) {
1980
+ let disposed = false;
1981
+ registerDisposer(element, () => {
1982
+ disposed = true;
1983
+ });
1719
1984
  if (element.isConnected) {
1720
- queueMicrotask(() => runMountCallback(callback, "onMount", element));
1985
+ queueMicrotask(() => {
1986
+ if (disposed) return;
1987
+ runMountCallback(callback, "onMount", element);
1988
+ });
1721
1989
  return;
1722
1990
  }
1723
- const observer = new MutationObserver(() => {
1724
- if (element.isConnected) {
1725
- observer.disconnect();
1726
- runMountCallback(callback, "onMount", element);
1727
- }
1728
- });
1729
- registerDisposer(element, () => observer.disconnect());
1730
1991
  queueMicrotask(() => {
1992
+ if (disposed) return;
1731
1993
  if (element.isConnected) {
1732
1994
  runMountCallback(callback, "onMount", element);
1733
- } else {
1734
- observer.observe(document.body, { childList: true, subtree: true });
1995
+ return;
1735
1996
  }
1997
+ const unregister = registerMountWatcher(element, () => {
1998
+ if (disposed) return;
1999
+ runMountCallback(callback, "onMount", element);
2000
+ });
2001
+ registerDisposer(element, unregister);
1736
2002
  });
1737
2003
  } else {
1738
2004
  queueMicrotask(() => {
@@ -1741,22 +2007,24 @@ function onMount(callback, element) {
1741
2007
  }
1742
2008
  }
1743
2009
  function onUnmount(callback, element) {
1744
- registerDisposer(element, () => safeCall(callback, "onUnmount"));
1745
- const startObserving = () => {
1746
- const observer = new MutationObserver(() => {
1747
- if (!element.isConnected) {
1748
- observer.disconnect();
1749
- safeCall(callback, "onUnmount");
1750
- }
1751
- });
1752
- observer.observe(document.body, { childList: true, subtree: true });
1753
- registerDisposer(element, () => observer.disconnect());
2010
+ if (typeof document === "undefined") return;
2011
+ let fired = false;
2012
+ const fireOnce = () => {
2013
+ if (fired) return;
2014
+ fired = true;
2015
+ safeCall(callback, "onUnmount");
2016
+ };
2017
+ registerDisposer(element, fireOnce);
2018
+ const startWatching = () => {
2019
+ if (fired) return;
2020
+ const unregister = registerUnmountWatcher(element, fireOnce);
2021
+ registerDisposer(element, unregister);
1754
2022
  };
1755
2023
  if (element.isConnected) {
1756
- startObserving();
2024
+ startWatching();
1757
2025
  } else {
1758
2026
  onMount(() => {
1759
- startObserving();
2027
+ startWatching();
1760
2028
  return void 0;
1761
2029
  }, element);
1762
2030
  }
@@ -1773,7 +2041,7 @@ function strict(fn) {
1773
2041
  try {
1774
2042
  fn();
1775
2043
  } catch (err) {
1776
- console.warn("[Sibu strict] second run threw:", err);
2044
+ console.warn("[SibuJS strict] second run threw:", err);
1777
2045
  }
1778
2046
  });
1779
2047
  }
@@ -1789,7 +2057,7 @@ function strictEffect(fn) {
1789
2057
  try {
1790
2058
  secondTeardown = effect(fn);
1791
2059
  } catch (err) {
1792
- console.warn("[Sibu strictEffect] second run threw:", err);
2060
+ console.warn("[SibuJS strictEffect] second run threw:", err);
1793
2061
  }
1794
2062
  });
1795
2063
  return () => {
@@ -1815,9 +2083,11 @@ function nextTick() {
1815
2083
  function defer(getter) {
1816
2084
  const [value, setValue] = signal(getter());
1817
2085
  let pending = false;
2086
+ let disposed = false;
1818
2087
  let latest = value();
1819
2088
  const flush = () => {
1820
2089
  pending = false;
2090
+ if (disposed) return;
1821
2091
  setValue(latest);
1822
2092
  };
1823
2093
  const schedule = () => {
@@ -1831,11 +2101,17 @@ function defer(getter) {
1831
2101
  }
1832
2102
  });
1833
2103
  };
1834
- track(() => {
2104
+ const teardown = track(() => {
1835
2105
  latest = getter();
1836
2106
  schedule();
1837
2107
  });
1838
- return value;
2108
+ const accessor = (() => value());
2109
+ accessor.dispose = () => {
2110
+ if (disposed) return;
2111
+ disposed = true;
2112
+ teardown();
2113
+ };
2114
+ return accessor;
1839
2115
  }
1840
2116
  var IDLE_FALLBACK_MS = 16;
1841
2117
  function scheduleIdle(fn) {
@@ -1876,6 +2152,32 @@ function transition() {
1876
2152
  }
1877
2153
 
1878
2154
  // src/core/rendering/lazy.ts
2155
+ var PENDING_ERROR = "__sibuPendingError";
2156
+ function dispatchPropagate(node, error) {
2157
+ const fire = () => {
2158
+ try {
2159
+ if (!node.parentNode) return false;
2160
+ node.dispatchEvent(new CustomEvent("sibu:error-propagate", { bubbles: true, detail: { error } }));
2161
+ return true;
2162
+ } catch {
2163
+ return false;
2164
+ }
2165
+ };
2166
+ if (node.parentNode && fire()) return;
2167
+ queueMicrotask(() => {
2168
+ if (fire()) return;
2169
+ node[PENDING_ERROR] = error;
2170
+ });
2171
+ }
2172
+ function takePendingError(node) {
2173
+ const rec = node;
2174
+ const err = rec[PENDING_ERROR];
2175
+ if (err instanceof Error) {
2176
+ delete rec[PENDING_ERROR];
2177
+ return err;
2178
+ }
2179
+ return void 0;
2180
+ }
1879
2181
  function lazy(importFn) {
1880
2182
  let cached = null;
1881
2183
  return function LazyComponent() {
@@ -1892,14 +2194,14 @@ function lazy(importFn) {
1892
2194
  }).catch((err) => {
1893
2195
  if (disposed) return;
1894
2196
  const errorObj = err instanceof Error ? err : new Error(String(err));
1895
- container.replaceChildren(div("sibu-lazy-error", `Failed to load component: ${errorObj.message}`));
2197
+ devWarn(`[SibuJS] lazy() failed to load component: ${errorObj.message}`);
2198
+ container.replaceChildren(div({ class: "sibu-lazy-error" }, `Failed to load component: ${errorObj.message}`));
2199
+ dispatchPropagate(container, errorObj);
1896
2200
  });
1897
2201
  container.appendChild(span("sibu-lazy-loading", "Loading..."));
1898
- const origRemove = container.remove.bind(container);
1899
- container.remove = () => {
2202
+ registerDisposer(container, () => {
1900
2203
  disposed = true;
1901
- origRemove();
1902
- };
2204
+ });
1903
2205
  return container;
1904
2206
  };
1905
2207
  }
@@ -1907,32 +2209,48 @@ function Suspense({ nodes, fallback }) {
1907
2209
  const container = div({ class: "sibu-suspense" });
1908
2210
  const fallbackEl = fallback();
1909
2211
  container.appendChild(fallbackEl);
2212
+ let suspenseDisposed = false;
2213
+ let observer = null;
2214
+ registerDisposer(container, () => {
2215
+ suspenseDisposed = true;
2216
+ if (observer) {
2217
+ observer.disconnect();
2218
+ observer = null;
2219
+ }
2220
+ });
1910
2221
  queueMicrotask(() => {
2222
+ if (suspenseDisposed) return;
1911
2223
  try {
1912
2224
  const childEl = nodes();
1913
2225
  if (childEl.classList.contains("sibu-lazy")) {
1914
- const observer = new MutationObserver(() => {
2226
+ if (!childEl.querySelector(".sibu-lazy-loading")) {
2227
+ container.replaceChildren(childEl);
2228
+ return;
2229
+ }
2230
+ observer = new MutationObserver(() => {
2231
+ if (suspenseDisposed) return;
1915
2232
  const loading = childEl.querySelector(".sibu-lazy-loading");
1916
2233
  if (!loading) {
1917
- observer.disconnect();
2234
+ observer?.disconnect();
2235
+ observer = null;
1918
2236
  container.replaceChildren(childEl);
1919
2237
  }
1920
2238
  });
1921
2239
  observer.observe(childEl, { childList: true, subtree: true });
1922
- if (!childEl.querySelector(".sibu-lazy-loading")) {
1923
- container.replaceChildren(childEl);
1924
- }
1925
2240
  } else {
1926
2241
  container.replaceChildren(childEl);
1927
2242
  }
1928
- } catch {
2243
+ } catch (err) {
2244
+ const errorObj = err instanceof Error ? err : new Error(String(err));
2245
+ devWarn(`[SibuJS] Suspense nodes() threw: ${errorObj.message}`);
2246
+ dispatchPropagate(container, errorObj);
1929
2247
  }
1930
2248
  });
1931
2249
  return container;
1932
2250
  }
1933
2251
 
1934
2252
  // src/components/ErrorDisplay.ts
1935
- var _isDev2 = isDev();
2253
+ var _isDev3 = isDev();
1936
2254
  var STYLES = `
1937
2255
  .sibu-error-display {
1938
2256
  border: 1px solid var(--sibu-err-border, #e5484d);
@@ -2018,20 +2336,21 @@ var STYLES = `
2018
2336
  font-weight: 600;
2019
2337
  }
2020
2338
  .sibu-error-display .sibu-err-copy-btn {
2021
- background: transparent;
2022
- border: 1px solid #3a3a4e;
2339
+ background: rgba(0, 0, 0, 0.22);
2340
+ border: 1px solid rgba(255, 255, 255, 0.15);
2023
2341
  border-radius: 4px;
2024
- color: #a0a3b8;
2342
+ color: rgba(255, 255, 255, 0.85);
2025
2343
  cursor: pointer;
2026
2344
  padding: 2px 10px;
2027
- font-size: 0.95em;
2345
+ font-size: 0.78em;
2028
2346
  font-family: inherit;
2029
2347
  transition: all 0.12s ease;
2348
+ flex-shrink: 0;
2030
2349
  }
2031
2350
  .sibu-error-display .sibu-err-copy-btn:hover {
2032
- background: #2a2a3e;
2033
- color: #e5e7eb;
2034
- border-color: #4a4a5e;
2351
+ background: rgba(0, 0, 0, 0.35);
2352
+ color: white;
2353
+ border-color: rgba(255, 255, 255, 0.3);
2035
2354
  }
2036
2355
 
2037
2356
  .sibu-error-display .sibu-err-stack {
@@ -2156,21 +2475,25 @@ function normalizeError(err) {
2156
2475
  cause: null
2157
2476
  };
2158
2477
  }
2159
- function buildCopyText(err, meta2) {
2478
+ function buildCopyText(err, meta2, headline) {
2160
2479
  const lines = [];
2480
+ lines.push(headline);
2161
2481
  lines.push(`[${err.code}] ${err.message}`);
2162
2482
  if (err.stack) {
2163
2483
  lines.push("");
2484
+ lines.push("Stack Trace:");
2164
2485
  lines.push(err.stack);
2165
2486
  }
2166
- if (err.cause) {
2487
+ let cause = err.cause;
2488
+ while (cause) {
2167
2489
  lines.push("");
2168
2490
  lines.push("Caused by:");
2169
- lines.push(` [${err.cause.code}] ${err.cause.message}`);
2170
- if (err.cause.stack) {
2171
- const indented = err.cause.stack.split("\n").map((l) => ` ${l}`).join("\n");
2491
+ lines.push(` [${cause.code}] ${cause.message}`);
2492
+ if (cause.stack) {
2493
+ const indented = cause.stack.split("\n").map((l) => ` ${l}`).join("\n");
2172
2494
  lines.push(indented);
2173
2495
  }
2496
+ cause = cause.cause;
2174
2497
  }
2175
2498
  if (meta2 && Object.keys(meta2).length > 0) {
2176
2499
  lines.push("");
@@ -2180,9 +2503,13 @@ function buildCopyText(err, meta2) {
2180
2503
  }
2181
2504
  }
2182
2505
  lines.push("");
2183
- lines.push(`At: ${(/* @__PURE__ */ new Date()).toISOString()}`);
2506
+ lines.push("Environment:");
2507
+ lines.push(` Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}`);
2508
+ if (typeof location !== "undefined") {
2509
+ lines.push(` URL: ${location.href}`);
2510
+ }
2184
2511
  if (typeof navigator !== "undefined" && navigator.userAgent) {
2185
- lines.push(`UA: ${navigator.userAgent}`);
2512
+ lines.push(` User Agent: ${navigator.userAgent}`);
2186
2513
  }
2187
2514
  return lines.join("\n");
2188
2515
  }
@@ -2234,7 +2561,7 @@ function ErrorDisplay(props) {
2234
2561
  injectStyles();
2235
2562
  const severity = props.severity ?? "error";
2236
2563
  const normalized = normalizeError(props.error);
2237
- const showDetails = props.alwaysShowDetails ?? _isDev2;
2564
+ const showDetails = props.alwaysShowDetails ?? _isDev3;
2238
2565
  const headline = props.title ?? normalized.message;
2239
2566
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
2240
2567
  const [copyLabel, setCopyLabel] = signal("Copy");
@@ -2243,7 +2570,7 @@ function ErrorDisplay(props) {
2243
2570
  nodes: () => copyLabel(),
2244
2571
  on: {
2245
2572
  click: () => {
2246
- const text2 = buildCopyText(normalized, props.metadata);
2573
+ const text2 = buildCopyText(normalized, props.metadata, headline);
2247
2574
  if (typeof navigator !== "undefined" && navigator.clipboard) {
2248
2575
  navigator.clipboard.writeText(text2).then(
2249
2576
  () => {
@@ -2264,6 +2591,7 @@ function ErrorDisplay(props) {
2264
2591
  nodes: [
2265
2592
  code({ class: "sibu-err-icon", nodes: normalized.code }),
2266
2593
  h3({ class: "sibu-err-title", nodes: headline }),
2594
+ copyBtn,
2267
2595
  span({ class: "sibu-err-timestamp", nodes: timestamp })
2268
2596
  ]
2269
2597
  });
@@ -2275,25 +2603,12 @@ function ErrorDisplay(props) {
2275
2603
  nodes: [
2276
2604
  div({
2277
2605
  class: "sibu-err-section-head",
2278
- nodes: [span({ nodes: "Stack Trace" }), copyBtn]
2606
+ nodes: [span({ nodes: "Stack Trace" })]
2279
2607
  }),
2280
2608
  renderFrames(normalized.frames)
2281
2609
  ]
2282
2610
  })
2283
2611
  );
2284
- } else if (showDetails) {
2285
- bodyChildren.push(
2286
- div({
2287
- class: "sibu-err-section",
2288
- nodes: [
2289
- div({
2290
- class: "sibu-err-section-head",
2291
- nodes: [span({ nodes: "Details" }), copyBtn]
2292
- }),
2293
- div({ class: "sibu-err-stack", nodes: "(no stack available)" })
2294
- ]
2295
- })
2296
- );
2297
2612
  }
2298
2613
  if (showDetails) {
2299
2614
  bodyChildren.push(...renderCauseChain(normalized.cause));
@@ -2309,37 +2624,6 @@ function ErrorDisplay(props) {
2309
2624
  })
2310
2625
  );
2311
2626
  }
2312
- if (showDetails && typeof navigator !== "undefined" && navigator.userAgent) {
2313
- bodyChildren.push(
2314
- div({
2315
- class: "sibu-err-section",
2316
- nodes: [
2317
- div({ class: "sibu-err-section-head", nodes: [span({ nodes: "Environment" })] }),
2318
- div({
2319
- class: "sibu-err-meta",
2320
- nodes: (() => {
2321
- const dl2 = document.createElement("dl");
2322
- dl2.className = "sibu-err-meta";
2323
- const entries = [
2324
- ["User Agent", navigator.userAgent],
2325
- ["URL", typeof location !== "undefined" ? location.href : "(n/a)"],
2326
- ["Timestamp", (/* @__PURE__ */ new Date()).toISOString()]
2327
- ];
2328
- for (const [k, v] of entries) {
2329
- const dt2 = document.createElement("dt");
2330
- dt2.textContent = k;
2331
- const dd2 = document.createElement("dd");
2332
- dd2.textContent = v;
2333
- dl2.appendChild(dt2);
2334
- dl2.appendChild(dd2);
2335
- }
2336
- return dl2;
2337
- })()
2338
- })
2339
- ]
2340
- })
2341
- );
2342
- }
2343
2627
  const actionButtons = [];
2344
2628
  if (props.onRetry) {
2345
2629
  actionButtons.push(
@@ -2534,6 +2818,7 @@ function injectStyles2() {
2534
2818
  stylesInjected = true;
2535
2819
  }
2536
2820
  }
2821
+ var FALLBACK_CACHE_MAX = 50;
2537
2822
  var fallbackCache = /* @__PURE__ */ new WeakMap();
2538
2823
  function getMemoizedFallback(fallbackFn, error, retry) {
2539
2824
  let cache2 = fallbackCache.get(fallbackFn);
@@ -2542,27 +2827,42 @@ function getMemoizedFallback(fallbackFn, error, retry) {
2542
2827
  fallbackCache.set(fallbackFn, cache2);
2543
2828
  }
2544
2829
  const key = error.message;
2545
- if (!cache2.has(key)) {
2546
- cache2.set(key, fallbackFn(error, retry));
2830
+ let factory = cache2.get(key);
2831
+ if (factory) {
2832
+ cache2.delete(key);
2833
+ cache2.set(key, factory);
2834
+ } else {
2835
+ factory = () => fallbackFn(error, retry);
2836
+ cache2.set(key, factory);
2837
+ if (cache2.size > FALLBACK_CACHE_MAX) {
2838
+ const oldestKey = cache2.keys().next().value;
2839
+ if (oldestKey !== void 0) cache2.delete(oldestKey);
2840
+ }
2547
2841
  }
2548
- return cache2.get(key);
2842
+ return factory();
2549
2843
  }
2550
2844
  function ErrorBoundary({ nodes, fallback, onError, resetKeys }) {
2551
2845
  injectStyles2();
2552
2846
  const [error, setError] = signal(null);
2553
2847
  const retry = () => {
2554
2848
  if (fallback) {
2555
- fallbackCache.delete(fallback);
2849
+ const cur = error();
2850
+ const inner = fallbackCache.get(fallback);
2851
+ if (cur && inner) inner.delete(cur.message);
2556
2852
  }
2557
2853
  setError(null);
2558
2854
  };
2855
+ let resetKeysTeardown = null;
2559
2856
  if (resetKeys && resetKeys.length > 0) {
2560
2857
  let initialized = false;
2561
- effect(() => {
2858
+ resetKeysTeardown = effect(() => {
2562
2859
  for (const k of resetKeys) {
2563
2860
  try {
2564
2861
  k();
2565
- } catch {
2862
+ } catch (err) {
2863
+ if (typeof console !== "undefined") {
2864
+ console.warn("[SibuJS ErrorBoundary] resetKeys getter threw:", err);
2865
+ }
2566
2866
  }
2567
2867
  }
2568
2868
  if (!initialized) {
@@ -2575,7 +2875,15 @@ function ErrorBoundary({ nodes, fallback, onError, resetKeys }) {
2575
2875
  const handleError = (e) => {
2576
2876
  const errorObj = e instanceof Error ? e : new Error(String(e));
2577
2877
  setError(errorObj);
2578
- onError?.(errorObj);
2878
+ if (onError) {
2879
+ try {
2880
+ onError(errorObj);
2881
+ } catch (cbErr) {
2882
+ if (typeof console !== "undefined") {
2883
+ console.error("[SibuJS ErrorBoundary] onError callback threw:", cbErr);
2884
+ }
2885
+ }
2886
+ }
2579
2887
  return errorObj;
2580
2888
  };
2581
2889
  const defaultFallback = (err, retryFn) => {
@@ -2627,7 +2935,7 @@ function ErrorBoundary({ nodes, fallback, onError, resetKeys }) {
2627
2935
  }
2628
2936
  }
2629
2937
  });
2630
- container.addEventListener("sibu:error-propagate", (e) => {
2938
+ const propagateListener = (e) => {
2631
2939
  if (error()) return;
2632
2940
  e.stopPropagation();
2633
2941
  const customEvent = e;
@@ -2635,6 +2943,30 @@ function ErrorBoundary({ nodes, fallback, onError, resetKeys }) {
2635
2943
  if (propagatedError) {
2636
2944
  handleError(propagatedError);
2637
2945
  }
2946
+ };
2947
+ container.addEventListener("sibu:error-propagate", propagateListener);
2948
+ onMount(() => {
2949
+ const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT);
2950
+ const collected = [];
2951
+ let node = walker.currentNode;
2952
+ while (node) {
2953
+ const pending = takePendingError(node);
2954
+ if (pending) collected.push(pending);
2955
+ node = walker.nextNode();
2956
+ }
2957
+ if (collected.length === 1) {
2958
+ handleError(collected[0]);
2959
+ } else if (collected.length > 1) {
2960
+ const Agg = globalThis.AggregateError;
2961
+ handleError(
2962
+ Agg ? new Agg(collected, `${collected.length} pre-mount errors caught by ErrorBoundary`) : new Error(collected.map((e) => e.message).join("; "))
2963
+ );
2964
+ }
2965
+ return void 0;
2966
+ }, container);
2967
+ registerDisposer(container, () => {
2968
+ if (resetKeysTeardown) resetKeysTeardown();
2969
+ container.removeEventListener("sibu:error-propagate", propagateListener);
2638
2970
  });
2639
2971
  return container;
2640
2972
  }
@@ -2770,6 +3102,7 @@ export {
2770
3102
  nextTick,
2771
3103
  defer,
2772
3104
  transition,
3105
+ takePendingError,
2773
3106
  lazy,
2774
3107
  Suspense,
2775
3108
  ErrorDisplay,