sibujs 4.5.0 → 4.7.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 (116) hide show
  1. package/README.md +1 -1
  2. package/dist/browser.cjs +326 -133
  3. package/dist/browser.d.cts +46 -14
  4. package/dist/browser.d.ts +46 -14
  5. package/dist/browser.js +8 -6
  6. package/dist/build.cjs +2094 -1033
  7. package/dist/build.d.cts +133 -44
  8. package/dist/build.d.ts +133 -44
  9. package/dist/build.js +1372 -574
  10. package/dist/cdn.dev.global.js +10 -10
  11. package/dist/cdn.full.dev.global.js +11 -11
  12. package/dist/cdn.full.global.js +10 -10
  13. package/dist/cdn.global.js +10 -10
  14. package/dist/{chunk-2DCGACUU.js → chunk-2BPG2XDA.js} +251 -66
  15. package/dist/{chunk-IXKSNWV5.js → chunk-2INLLLMZ.js} +1 -1
  16. package/dist/{chunk-4PMLNECI.js → chunk-3QWBSL5R.js} +98 -29
  17. package/dist/{chunk-KKLW7YWL.js → chunk-4AWA2PVD.js} +275 -144
  18. package/dist/chunk-5HZXGZ6T.js +24 -0
  19. package/dist/{chunk-PCT43HW3.js → chunk-7LUJQAOJ.js} +1 -1
  20. package/dist/{chunk-5DXA2J44.js → chunk-7XHATCIH.js} +5 -2
  21. package/dist/chunk-BC2SECJD.js +44 -0
  22. package/dist/{chunk-TBYTO6BS.js → chunk-BSY63EM6.js} +136 -80
  23. package/dist/{chunk-FTIR4QW2.js → chunk-DKXRACVN.js} +6 -8
  24. package/dist/{chunk-ONOHFDLG.js → chunk-FNJXNGYZ.js} +3 -3
  25. package/dist/{chunk-XZZOBQAY.js → chunk-FQRUXCEE.js} +6 -5
  26. package/dist/{chunk-NIOYEGBQ.js → chunk-HURREPU2.js} +27 -13
  27. package/dist/chunk-J6FW5TV6.js +233 -0
  28. package/dist/{chunk-UGRX3S57.js → chunk-JWKYU5GV.js} +22 -4
  29. package/dist/chunk-NYNYSPK7.js +318 -0
  30. package/dist/{chunk-RBTPLM32.js → chunk-RUSSKG6G.js} +13 -12
  31. package/dist/{chunk-7LN645I6.js → chunk-SLM3IA34.js} +3 -3
  32. package/dist/{chunk-R25EFXXC.js → chunk-TUCPL2HB.js} +3 -3
  33. package/dist/{chunk-B3WHI2QA.js → chunk-UNWRJRKC.js} +55 -31
  34. package/dist/{chunk-KEISJXBU.js → chunk-UOL2ECCS.js} +44 -17
  35. package/dist/{chunk-RJE2BNI4.js → chunk-VZSG24LS.js} +108 -45
  36. package/dist/{chunk-RIXRAYIU.js → chunk-WEQ3DMVL.js} +10 -4
  37. package/dist/{chunk-3JZ4L5TJ.js → chunk-WOLJZUFQ.js} +354 -90
  38. package/dist/{chunk-S373NSMK.js → chunk-XYV3EDB7.js} +283 -123
  39. package/dist/{chunk-VZKNK2V7.js → chunk-XZR4PXRE.js} +296 -38
  40. package/dist/{chunk-GW3SCCZG.js → chunk-Z3OHK6QT.js} +153 -110
  41. package/dist/{chunk-OMJJM3KM.js → chunk-ZVL7TY4K.js} +287 -130
  42. package/dist/{contracts-DBdg9J_a.d.ts → contracts-CLqzJnOV.d.ts} +36 -17
  43. package/dist/{contracts-DBdg9J_a.d.cts → contracts-CTOJXu-x.d.cts} +36 -17
  44. package/dist/{customElement-OB9CIsc5.d.cts → customElement-MmInOW1U.d.cts} +21 -0
  45. package/dist/{customElement-OB9CIsc5.d.ts → customElement-MmInOW1U.d.ts} +21 -0
  46. package/dist/data.cjs +410 -155
  47. package/dist/data.d.cts +166 -12
  48. package/dist/data.d.ts +166 -12
  49. package/dist/data.js +12 -9
  50. package/dist/devtools.cjs +98 -61
  51. package/dist/devtools.js +7 -8
  52. package/dist/dispose-GEIG2KOF.js +28 -0
  53. package/dist/ecosystem.cjs +372 -126
  54. package/dist/ecosystem.d.cts +20 -3
  55. package/dist/ecosystem.d.ts +20 -3
  56. package/dist/ecosystem.js +12 -12
  57. package/dist/extras.cjs +2366 -909
  58. package/dist/extras.d.cts +11 -9
  59. package/dist/extras.d.ts +11 -9
  60. package/dist/extras.js +39 -28
  61. package/dist/index.cjs +421 -158
  62. package/dist/index.d.cts +213 -171
  63. package/dist/index.d.ts +213 -171
  64. package/dist/index.js +24 -27
  65. package/dist/motion.cjs +118 -44
  66. package/dist/motion.js +5 -5
  67. package/dist/patterns.cjs +344 -53
  68. package/dist/patterns.d.cts +28 -9
  69. package/dist/patterns.d.ts +28 -9
  70. package/dist/patterns.js +8 -8
  71. package/dist/performance.cjs +325 -220
  72. package/dist/performance.d.cts +2 -2
  73. package/dist/performance.d.ts +2 -2
  74. package/dist/performance.js +8 -9
  75. package/dist/plugin-DVgSnTfK.d.cts +112 -0
  76. package/dist/plugin-DVgSnTfK.d.ts +112 -0
  77. package/dist/plugins.cjs +664 -233
  78. package/dist/plugins.d.cts +127 -14
  79. package/dist/plugins.d.ts +127 -14
  80. package/dist/plugins.js +96 -42
  81. package/dist/signal-EotCj4hS.d.cts +110 -0
  82. package/dist/signal-EotCj4hS.d.ts +110 -0
  83. package/dist/{ssr-BiPRdZ6n.d.cts → ssr-Bli9XRW5.d.cts} +5 -0
  84. package/dist/{ssr-BiPRdZ6n.d.ts → ssr-Bli9XRW5.d.ts} +5 -0
  85. package/dist/{ssr-Y7XOEPEN.js → ssr-XOTUASDO.js} +4 -5
  86. package/dist/ssr.cjs +229 -84
  87. package/dist/ssr.d.cts +9 -3
  88. package/dist/ssr.d.ts +9 -3
  89. package/dist/ssr.js +11 -12
  90. package/dist/{startup-BMpaiMhP.d.ts → startup-BLfSeL15.d.cts} +73 -22
  91. package/dist/{startup-BMpaiMhP.d.cts → startup-BLfSeL15.d.ts} +73 -22
  92. package/dist/tagFactory-8qL9LCIx.d.cts +156 -0
  93. package/dist/tagFactory-BL2fymez.d.ts +156 -0
  94. package/dist/testing.cjs +2503 -2191
  95. package/dist/testing.d.cts +56 -5
  96. package/dist/testing.d.ts +56 -5
  97. package/dist/testing.js +580 -307
  98. package/dist/types-CJFViL6Q.d.cts +26 -0
  99. package/dist/types-CJFViL6Q.d.ts +26 -0
  100. package/dist/ui.cjs +732 -329
  101. package/dist/ui.d.cts +41 -7
  102. package/dist/ui.d.ts +41 -7
  103. package/dist/ui.js +151 -56
  104. package/dist/widgets.cjs +267 -291
  105. package/dist/widgets.js +9 -10
  106. package/package.json +4 -2
  107. package/dist/chunk-2WLZ6757.js +0 -149
  108. package/dist/chunk-CCSJMTRN.js +0 -15
  109. package/dist/chunk-QKRPLZ2V.js +0 -108
  110. package/dist/chunk-VUF4ALSW.js +0 -60
  111. package/dist/chunk-WWV3SJ3L.js +0 -131
  112. package/dist/dispose-46BOMMQJ.js +0 -19
  113. package/dist/plugin-D30wlGW5.d.cts +0 -71
  114. package/dist/plugin-D30wlGW5.d.ts +0 -71
  115. package/dist/tagFactory-DVoDpHye.d.cts +0 -215
  116. package/dist/tagFactory-DVoDpHye.d.ts +0 -215
package/dist/ssr.cjs CHANGED
@@ -186,6 +186,23 @@ function reportDrainRunaway(label2, executed, remaining) {
186
186
  );
187
187
  }
188
188
  var activeBindingCount = 0;
189
+ function resolveCapture(capture) {
190
+ let frame = capture;
191
+ while (frame?.closed) frame = frame.forwardTo;
192
+ return frame ?? null;
193
+ }
194
+ var registrationCaptures = [];
195
+ function currentDisposerCapture() {
196
+ return resolveCapture(registrationCaptures[registrationCaptures.length - 1]);
197
+ }
198
+ function beginDisposerCapture(capture) {
199
+ if (capture === null && registrationCaptures.length === 0) return false;
200
+ registrationCaptures.push(resolveCapture(capture));
201
+ return true;
202
+ }
203
+ function endDisposerCapture() {
204
+ registrationCaptures.pop();
205
+ }
189
206
  function registerDisposer(node, teardown) {
190
207
  let disposers = elementDisposers.get(node);
191
208
  if (!disposers) {
@@ -194,6 +211,8 @@ function registerDisposer(node, teardown) {
194
211
  }
195
212
  disposers.push(teardown);
196
213
  if (DEV) activeBindingCount++;
214
+ const capture = resolveCapture(registrationCaptures[registrationCaptures.length - 1]);
215
+ if (capture) capture.entries.push([node, teardown]);
197
216
  }
198
217
  function dispose(node) {
199
218
  const stack = [node];
@@ -207,33 +226,34 @@ function dispose(node) {
207
226
  }
208
227
  }
209
228
  for (let i2 = order.length - 1; i2 >= 0; i2--) {
210
- const current = order[i2];
211
- if (elementDisposers.has(current)) {
212
- let executed = 0;
213
- let runaway = false;
214
- while (!runaway) {
215
- const pending = elementDisposers.get(current);
216
- if (!pending || pending.length === 0) break;
217
- const snapshot = pending.slice();
218
- elementDisposers.delete(current);
219
- if (DEV) activeBindingCount -= snapshot.length;
220
- for (let i3 = 0; i3 < snapshot.length; i3++) {
221
- if (executed >= MAX_DRAIN_TEARDOWNS) {
222
- const rest = snapshot.slice(i3);
223
- const added = elementDisposers.get(current);
224
- elementDisposers.set(current, added ? rest.concat(added) : rest);
225
- if (DEV) activeBindingCount += rest.length;
226
- reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
227
- runaway = true;
228
- break;
229
- }
230
- executed++;
231
- try {
232
- snapshot[i3]();
233
- } catch (err) {
234
- reportError(err, { phase: "cleanup", name: "disposer" });
235
- }
236
- }
229
+ disposeNodeOwn(order[i2]);
230
+ }
231
+ }
232
+ function disposeNodeOwn(node) {
233
+ if (!elementDisposers.has(node)) return;
234
+ let executed = 0;
235
+ let runaway = false;
236
+ while (!runaway) {
237
+ const pending = elementDisposers.get(node);
238
+ if (!pending || pending.length === 0) break;
239
+ const snapshot = pending.slice();
240
+ elementDisposers.delete(node);
241
+ if (DEV) activeBindingCount -= snapshot.length;
242
+ for (let i2 = 0; i2 < snapshot.length; i2++) {
243
+ if (executed >= MAX_DRAIN_TEARDOWNS) {
244
+ const rest = snapshot.slice(i2);
245
+ const added = elementDisposers.get(node);
246
+ elementDisposers.set(node, added ? rest.concat(added) : rest);
247
+ if (DEV) activeBindingCount += rest.length;
248
+ reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
249
+ runaway = true;
250
+ break;
251
+ }
252
+ executed++;
253
+ try {
254
+ snapshot[i2]();
255
+ } catch (err) {
256
+ reportError(err, { phase: "cleanup", name: "disposer" });
237
257
  }
238
258
  }
239
259
  }
@@ -938,7 +958,7 @@ function renderToDocument(component, options = {}) {
938
958
  <head>
939
959
  <meta charset="UTF-8" />
940
960
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
941
- ${options.title ? `<title>${escapeHtml(options.title)}</title>` : ""}
961
+ ${options.title != null ? `<title>${escapeHtml(options.title)}</title>` : ""}
942
962
  ${metaTags}
943
963
  ${linkTags}
944
964
  ${options.headExtra || ""}
@@ -1113,16 +1133,32 @@ function ssrSuspense(props) {
1113
1133
  const timeoutPromise = new Promise((_, reject) => {
1114
1134
  timer = setTimeout(() => reject(new Error(`[SibuJS SSR] ssrSuspense timed out after ${timeoutMs}ms`)), timeoutMs);
1115
1135
  });
1116
- const raced = Promise.race([props.content(), timeoutPromise]);
1136
+ let contentPromise;
1137
+ try {
1138
+ contentPromise = Promise.resolve(props.content());
1139
+ } catch (err) {
1140
+ contentPromise = Promise.reject(err);
1141
+ }
1142
+ const toFallback = (err) => {
1143
+ if (DEV) console.warn("[SibuJS SSR] ssrSuspense rejected:", err);
1144
+ return { id, html: fallbackHtml };
1145
+ };
1146
+ const clearTimer = () => {
1147
+ if (timer !== void 0) clearTimeout(timer);
1148
+ };
1149
+ const raced = Promise.race([contentPromise, timeoutPromise]);
1117
1150
  const promise = raced.then(
1118
1151
  (resolvedEl) => {
1119
- if (timer) clearTimeout(timer);
1120
- return { id, html: renderToString(resolvedEl) };
1152
+ clearTimer();
1153
+ try {
1154
+ return { id, html: renderToString(resolvedEl) };
1155
+ } catch (err) {
1156
+ return toFallback(err);
1157
+ }
1121
1158
  },
1122
1159
  (err) => {
1123
- if (timer) clearTimeout(timer);
1124
- if (DEV) console.warn("[SibuJS SSR] ssrSuspense rejected:", err);
1125
- return { id, html: fallbackHtml };
1160
+ clearTimer();
1161
+ return toFallback(err);
1126
1162
  }
1127
1163
  );
1128
1164
  promise.catch(noop);
@@ -1343,6 +1379,7 @@ function retrack(effectFn, subscriber) {
1343
1379
  }
1344
1380
  currentSubscriber = subscriber;
1345
1381
  const sub2 = subscriber;
1382
+ if (sub2._cap === void 0) sub2._cap = currentDisposerCapture();
1346
1383
  const epoch = ++subscriberEpochCounter;
1347
1384
  sub2._epoch = epoch;
1348
1385
  sub2._structDirty = false;
@@ -1534,7 +1571,12 @@ function drainQueue() {
1534
1571
  quarantined.add(sub2);
1535
1572
  continue;
1536
1573
  }
1537
- safeInvoke(sub2);
1574
+ const pushed = beginDisposerCapture(sub2._cap ?? null);
1575
+ try {
1576
+ safeInvoke(sub2);
1577
+ } finally {
1578
+ if (pushed) endDisposerCapture();
1579
+ }
1538
1580
  }
1539
1581
  }
1540
1582
  function drainNotificationQueue() {
@@ -1670,7 +1712,7 @@ function forEachSubscriber(signal2, visit) {
1670
1712
  }
1671
1713
 
1672
1714
  // src/reactivity/track.ts
1673
- var _runtimeVersion = true ? "4.5.0" : "dev";
1715
+ var _runtimeVersion = true ? "4.7.0" : "dev";
1674
1716
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
1675
1717
  function resolveReactiveApi() {
1676
1718
  const g2 = globalThis;
@@ -1726,6 +1768,14 @@ var getSubscriberCount2 = API.getSubscriberCount;
1726
1768
  var getSubscriberDeps2 = API.getSubscriberDeps;
1727
1769
  var forEachSubscriber2 = API.forEachSubscriber;
1728
1770
 
1771
+ // src/core/devtoolsHook.ts
1772
+ function emitDevtools(hook, event, payload) {
1773
+ try {
1774
+ hook.emit(event, payload);
1775
+ } catch {
1776
+ }
1777
+ }
1778
+
1729
1779
  // src/core/signals/effect.ts
1730
1780
  var _g = globalThis;
1731
1781
  var MAX_RERUNS = 100;
@@ -1841,12 +1891,17 @@ function effect(effectFn, options) {
1841
1891
  try {
1842
1892
  retrack2(ctx.bodyFn, ctx.subscriber);
1843
1893
  if (ctx.rerunPending) drainReruns(ctx);
1894
+ } catch (err) {
1895
+ ctx.disposed = true;
1896
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
1897
+ cleanup2(ctx.subscriber);
1898
+ throw err;
1844
1899
  } finally {
1845
1900
  ctx.running = false;
1846
1901
  ctx.rerunPending = false;
1847
1902
  }
1848
1903
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1849
- if (hook) hook.emit("effect:create", { effectFn });
1904
+ if (hook) emitDevtools(hook, "effect:create", { effectFn });
1850
1905
  return () => disposeEffect(ctx);
1851
1906
  }
1852
1907
 
@@ -2036,7 +2091,7 @@ function Head(props) {
2036
2091
  };
2037
2092
  const apply = () => {
2038
2093
  cleanup3();
2039
- if (props.title) {
2094
+ if (props.title != null) {
2040
2095
  if (typeof props.title === "function") {
2041
2096
  const getter = props.title;
2042
2097
  let lease = null;
@@ -2091,13 +2146,14 @@ function Head(props) {
2091
2146
  return anchor;
2092
2147
  }
2093
2148
  function setStructuredData(data2) {
2094
- const existing = document.head.querySelector('script[type="application/ld+json"][data-sibu]');
2095
- if (existing) existing.remove();
2149
+ const json = escapeScriptJsonLocal(JSON.stringify(data2));
2096
2150
  const script2 = document.createElement("script");
2097
2151
  script2.type = "application/ld+json";
2098
2152
  script2.setAttribute("data-sibu", "true");
2099
- script2.textContent = escapeScriptJsonLocal(JSON.stringify(data2));
2100
- document.head.appendChild(script2);
2153
+ script2.textContent = json;
2154
+ const existing = document.head.querySelector('script[type="application/ld+json"][data-sibu]');
2155
+ if (existing) existing.replaceWith(script2);
2156
+ else document.head.appendChild(script2);
2101
2157
  }
2102
2158
  function setCanonical(url) {
2103
2159
  let link2 = document.head.querySelector('link[rel="canonical"]');
@@ -2213,7 +2269,7 @@ function signal(initial, options) {
2213
2269
  state2.__v++;
2214
2270
  if (DEV) {
2215
2271
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
2216
- if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
2272
+ if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
2217
2273
  }
2218
2274
  if (!enqueueBatchedSignal(state2)) {
2219
2275
  notifySubscribers2(state2);
@@ -2227,7 +2283,7 @@ function signal(initial, options) {
2227
2283
  state2.value = newValue;
2228
2284
  state2.__v++;
2229
2285
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
2230
- if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
2286
+ if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
2231
2287
  if (!enqueueBatchedSignal(state2)) {
2232
2288
  notifySubscribers2(state2);
2233
2289
  }
@@ -2246,7 +2302,7 @@ function signal(initial, options) {
2246
2302
  }
2247
2303
  if (DEV) {
2248
2304
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
2249
- if (hook) hook.emit("signal:create", { signal: state2, name: debugName, getter: get, initial });
2305
+ if (hook) emitDevtools(hook, "signal:create", { signal: state2, name: debugName, getter: get, initial });
2250
2306
  }
2251
2307
  return [get, set];
2252
2308
  }
@@ -2254,15 +2310,31 @@ function signal(initial, options) {
2254
2310
  // src/platform/incrementalRegeneration.ts
2255
2311
  function createISR(options) {
2256
2312
  const { revalidateAfter, fetcher, initialData } = options;
2313
+ if (!Number.isFinite(revalidateAfter) || revalidateAfter <= 0) {
2314
+ throw new RangeError(`[SibuJS ISR] revalidateAfter must be a positive finite number, got ${revalidateAfter}`);
2315
+ }
2257
2316
  const [data2, setData] = signal(initialData);
2258
- const [timestamp, setTimestamp] = signal(initialData !== void 0 ? Date.now() : 0);
2317
+ const [stale, setStale] = signal(initialData === void 0);
2259
2318
  const controller = new AbortController();
2260
2319
  let inFlight = false;
2261
2320
  let disposed = false;
2262
- const isStale = () => {
2263
- const ts = timestamp();
2264
- if (ts === 0) return true;
2265
- return Date.now() - ts >= revalidateAfter;
2321
+ let deadline;
2322
+ const clearDeadline = () => {
2323
+ if (deadline !== void 0) {
2324
+ clearTimeout(deadline);
2325
+ deadline = void 0;
2326
+ }
2327
+ };
2328
+ const armDeadline = () => {
2329
+ clearDeadline();
2330
+ deadline = setTimeout(() => {
2331
+ deadline = void 0;
2332
+ if (disposed) return;
2333
+ setStale(true);
2334
+ revalidate().catch((err) => {
2335
+ if (typeof console !== "undefined") console.warn("[SibuJS ISR] revalidate failed", err);
2336
+ });
2337
+ }, revalidateAfter);
2266
2338
  };
2267
2339
  const revalidate = async () => {
2268
2340
  if (disposed || inFlight) return;
@@ -2271,8 +2343,14 @@ function createISR(options) {
2271
2343
  try {
2272
2344
  const result = await fetcher({ signal: controller.signal });
2273
2345
  if (disposed || controller.signal.aborted) return;
2274
- setData(result);
2275
- setTimestamp(Date.now());
2346
+ batch(() => {
2347
+ setData(result);
2348
+ setStale(false);
2349
+ });
2350
+ armDeadline();
2351
+ } catch (err) {
2352
+ if (!disposed && !controller.signal.aborted) armDeadline();
2353
+ throw err;
2276
2354
  } finally {
2277
2355
  inFlight = false;
2278
2356
  }
@@ -2281,19 +2359,16 @@ function createISR(options) {
2281
2359
  revalidate().catch((err) => {
2282
2360
  if (typeof console !== "undefined") console.warn("[SibuJS ISR] initial fetch failed", err);
2283
2361
  });
2362
+ } else {
2363
+ armDeadline();
2284
2364
  }
2285
- const intervalId = setInterval(() => {
2286
- revalidate().catch((err) => {
2287
- if (typeof console !== "undefined") console.warn("[SibuJS ISR] revalidate failed", err);
2288
- });
2289
- }, revalidateAfter);
2290
2365
  const dispose2 = () => {
2291
2366
  if (disposed) return;
2292
2367
  disposed = true;
2293
- clearInterval(intervalId);
2368
+ clearDeadline();
2294
2369
  controller.abort();
2295
2370
  };
2296
- return { data: data2, isStale, revalidate, dispose: dispose2 };
2371
+ return { data: data2, isStale: stale, revalidate, dispose: dispose2 };
2297
2372
  }
2298
2373
 
2299
2374
  // src/platform/routeActions.ts
@@ -2750,8 +2825,34 @@ function toKebab(prop) {
2750
2825
  }
2751
2826
  function applyStyle(el, style2) {
2752
2827
  if (typeof style2 === "function") {
2828
+ const getter = style2;
2829
+ let written = [];
2830
+ let wroteString = false;
2753
2831
  const teardown = reactiveBinding2(() => {
2754
- el.setAttribute("style", sanitizeStyleAttribute(String(style2()), { element: el }));
2832
+ const value = getter();
2833
+ if (value === null || typeof value !== "object") {
2834
+ written = [];
2835
+ wroteString = true;
2836
+ el.setAttribute("style", sanitizeStyleAttribute(String(value), { element: el }));
2837
+ return;
2838
+ }
2839
+ const decl = el.style;
2840
+ if (wroteString) {
2841
+ el.removeAttribute("style");
2842
+ wroteString = false;
2843
+ }
2844
+ const next = [];
2845
+ for (const prop in value) {
2846
+ const val = value[prop];
2847
+ if (val == null) continue;
2848
+ const name = toKebab(prop);
2849
+ next.push(name);
2850
+ decl.setProperty(name, sanitizeCSSValue(String(val), { property: name, element: el }));
2851
+ }
2852
+ for (let i2 = 0; i2 < written.length; i2++) {
2853
+ if (next.indexOf(written[i2]) === -1) decl.removeProperty(written[i2]);
2854
+ }
2855
+ written = next;
2755
2856
  }, el);
2756
2857
  registerDisposer(el, teardown);
2757
2858
  return;
@@ -2782,7 +2883,9 @@ function applyClass(el, cls) {
2782
2883
  }
2783
2884
  if (typeof cls === "function") {
2784
2885
  const teardown = reactiveBinding2(() => {
2785
- el.setAttribute("class", cls());
2886
+ const value = cls();
2887
+ if (value == null || value === false) el.removeAttribute("class");
2888
+ else el.setAttribute("class", value);
2786
2889
  }, el);
2787
2890
  registerDisposer(el, teardown);
2788
2891
  return;
@@ -2864,7 +2967,7 @@ function appendChildren(el, nodes) {
2864
2967
  }
2865
2968
  }
2866
2969
  }
2867
- var tagFactory = (tag, ns) => {
2970
+ function tagFactory(tag, ns) {
2868
2971
  const blocked = isBlockedTag(tag);
2869
2972
  return (first, second) => {
2870
2973
  if (blocked) {
@@ -2913,7 +3016,9 @@ var tagFactory = (tag, ns) => {
2913
3016
  const pClass = props.class;
2914
3017
  if (pClass != null) applyClass(el, pClass);
2915
3018
  const pId = props.id;
2916
- if (pId != null) {
3019
+ if (typeof pId === "function") {
3020
+ registerDisposer(el, bindAttribute(el, "id", pId));
3021
+ } else if (pId != null) {
2917
3022
  if (DEV && typeof pId === "string" && CLOBBER_RISKY_IDS.has(pId.toLowerCase())) {
2918
3023
  devWarn(
2919
3024
  `tagFactory: element id="${pId}" matches a common global and may cause DOM clobbering. Avoid setting ids from untrusted input.`
@@ -2963,12 +3068,10 @@ var tagFactory = (tag, ns) => {
2963
3068
  }
2964
3069
  }
2965
3070
  }
2966
- if (props.onElement && typeof props.onElement === "function") {
2967
- props.onElement(el);
2968
- }
3071
+ if (typeof props.onElement === "function") props.onElement(el);
2969
3072
  return el;
2970
3073
  };
2971
- };
3074
+ }
2972
3075
 
2973
3076
  // src/core/rendering/html.ts
2974
3077
  var html = tagFactory("html");
@@ -3203,13 +3306,13 @@ function createSharedScope(initialState) {
3203
3306
  for (const key of Object.keys(initialState)) {
3204
3307
  const [get2, set2] = signal(initialState[key]);
3205
3308
  signals.set(key, { get: get2, set: set2 });
3206
- subscribers.set(key, /* @__PURE__ */ new Set());
3309
+ subscribers.set(key, /* @__PURE__ */ new Map());
3207
3310
  }
3208
3311
  function ensureSignal(key) {
3209
3312
  if (!signals.has(key)) {
3210
3313
  const [get2, set2] = signal(void 0);
3211
3314
  signals.set(key, { get: get2, set: set2 });
3212
- subscribers.set(key, /* @__PURE__ */ new Set());
3315
+ subscribers.set(key, /* @__PURE__ */ new Map());
3213
3316
  }
3214
3317
  }
3215
3318
  function get(key) {
@@ -3220,9 +3323,14 @@ function createSharedScope(initialState) {
3220
3323
  ensureSignal(key);
3221
3324
  signals.get(key)?.set(value);
3222
3325
  const subs = subscribers.get(key);
3223
- if (subs) {
3224
- for (const cb of subs) {
3225
- cb(value);
3326
+ if (subs && subs.size > 0) {
3327
+ for (const subscription of Array.from(subs.values())) {
3328
+ if (!subscription.active) continue;
3329
+ try {
3330
+ subscription.callback(value);
3331
+ } catch (err) {
3332
+ reportError(err, { phase: "event", name: `sharedScope(${String(key)})` });
3333
+ }
3226
3334
  }
3227
3335
  }
3228
3336
  }
@@ -3233,9 +3341,17 @@ function createSharedScope(initialState) {
3233
3341
  return () => {
3234
3342
  };
3235
3343
  }
3236
- subs.add(callback);
3344
+ const cb = callback;
3345
+ let subscription = subs.get(cb);
3346
+ if (!subscription) {
3347
+ subscription = { callback: cb, active: true };
3348
+ subs.set(cb, subscription);
3349
+ }
3350
+ const own = subscription;
3237
3351
  return () => {
3238
- subs.delete(callback);
3352
+ if (subs.get(cb) !== own) return;
3353
+ own.active = false;
3354
+ subs.delete(cb);
3239
3355
  };
3240
3356
  }
3241
3357
  return { get, set, subscribe };
@@ -3366,6 +3482,11 @@ function serviceWorker(scriptUrl, options) {
3366
3482
  }
3367
3483
 
3368
3484
  // src/platform/worker.ts
3485
+ function toError(err) {
3486
+ if (err instanceof Error) return err;
3487
+ if (err !== null && typeof err === "object" && "name" in err && "message" in err) return err;
3488
+ return new Error(String(err));
3489
+ }
3369
3490
  function worker(workerFn2) {
3370
3491
  const [result, setResult] = signal(null);
3371
3492
  const [error, setError] = signal(null);
@@ -3388,8 +3509,11 @@ function worker(workerFn2) {
3388
3509
  worker2 = new Worker(blobUrl);
3389
3510
  worker2.addEventListener("message", (e) => {
3390
3511
  revokeBlobUrl();
3391
- setResult(e.data);
3392
- setLoading(false);
3512
+ batch(() => {
3513
+ setResult(e.data);
3514
+ setError(null);
3515
+ setLoading(false);
3516
+ });
3393
3517
  });
3394
3518
  worker2.addEventListener("error", (e) => {
3395
3519
  revokeBlobUrl();
@@ -3406,10 +3530,17 @@ function worker(workerFn2) {
3406
3530
  }
3407
3531
  function post(data2) {
3408
3532
  if (!worker2) return;
3409
- setLoading(true);
3410
- setError(null);
3411
- setResult(null);
3412
- worker2.postMessage(data2);
3533
+ try {
3534
+ worker2.postMessage(data2);
3535
+ } catch (err) {
3536
+ setError(toError(err));
3537
+ return;
3538
+ }
3539
+ batch(() => {
3540
+ setLoading(true);
3541
+ setError(null);
3542
+ setResult(null);
3543
+ });
3413
3544
  }
3414
3545
  function terminate() {
3415
3546
  if (!worker2) return;
@@ -3473,9 +3604,14 @@ function workerFn(fn) {
3473
3604
  reject(new Error("Worker is not available"));
3474
3605
  return;
3475
3606
  }
3476
- setLoading(true);
3607
+ try {
3608
+ worker2.postMessage(args);
3609
+ } catch (err) {
3610
+ reject(toError(err));
3611
+ return;
3612
+ }
3477
3613
  queue.push({ resolve, reject });
3478
- worker2.postMessage(args);
3614
+ setLoading(true);
3479
3615
  });
3480
3616
  }
3481
3617
  function terminate() {
@@ -3505,7 +3641,11 @@ function createWorkerPool(workerFn2, poolSize) {
3505
3641
  }
3506
3642
  };
3507
3643
  function dispatchNext(idx) {
3508
- if (!alive || inflight[idx] || queues[idx].length === 0) return;
3644
+ while (alive && !inflight[idx] && queues[idx].length > 0) {
3645
+ dispatchOne(idx);
3646
+ }
3647
+ }
3648
+ function dispatchOne(idx) {
3509
3649
  const w = workers[idx];
3510
3650
  const slot2 = queues[idx].shift();
3511
3651
  const onMsg = (e) => {
@@ -3530,10 +3670,15 @@ function createWorkerPool(workerFn2, poolSize) {
3530
3670
  slot2.reject(new Error(e.message || "Worker error"));
3531
3671
  dispatchNext(idx);
3532
3672
  };
3673
+ try {
3674
+ w.postMessage(slot2.data);
3675
+ } catch (err) {
3676
+ slot2.reject(toError(err));
3677
+ return;
3678
+ }
3533
3679
  inflight[idx] = { ...slot2, onMsg, onErr };
3534
3680
  w.addEventListener("message", onMsg);
3535
3681
  w.addEventListener("error", onErr);
3536
- w.postMessage(slot2.data);
3537
3682
  }
3538
3683
  try {
3539
3684
  if (typeof Worker === "undefined") {
package/dist/ssr.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { H as HydrateOptions, a as HydrationMismatch, T as TrustedHTML, c as collectStream, d as deserializeState, e as escapeScriptJson, h as hydrate, b as hydrateIslands, f as hydrateProgressively, i as isDangerousMetaRefresh, g as island, r as renderToDocument, j as renderToReadableStream, k as renderToStream, l as renderToString, m as renderToSuspenseStream, n as resetSSRState, s as serializeState, o as ssrSuspense, p as suspenseSwapScript, t as trustHTML } from './ssr-BiPRdZ6n.cjs';
1
+ export { H as HydrateOptions, a as HydrationMismatch, T as TrustedHTML, c as collectStream, d as deserializeState, e as escapeScriptJson, h as hydrate, b as hydrateIslands, f as hydrateProgressively, i as isDangerousMetaRefresh, g as island, r as renderToDocument, j as renderToReadableStream, k as renderToStream, l as renderToString, m as renderToSuspenseStream, n as resetSSRState, s as serializeState, o as ssrSuspense, p as suspenseSwapScript, t as trustHTML } from './ssr-Bli9XRW5.cjs';
2
2
 
3
3
  interface HeadProps {
4
4
  title?: string | (() => string);
@@ -482,8 +482,14 @@ interface ISROptions<T> {
482
482
  }
483
483
  /**
484
484
  * Creates an Incremental Static Regeneration (ISR) resource.
485
- * Data is fetched initially, then automatically revalidated after the
486
- * specified interval using setInterval.
485
+ * Data is fetched initially, then automatically revalidated once it goes stale.
486
+ *
487
+ * `isStale()` is a reactive signal: it flips to `true` when `revalidateAfter`
488
+ * elapses since the last successful fetch (effects re-run at that moment), stays
489
+ * `true` while a revalidation is pending or after one fails, and returns to
490
+ * `false` when a revalidation succeeds.
491
+ *
492
+ * @throws RangeError when `revalidateAfter` is not a positive finite number.
487
493
  */
488
494
  declare function createISR<T>(options: ISROptions<T>): {
489
495
  data: () => T | undefined;
package/dist/ssr.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { H as HydrateOptions, a as HydrationMismatch, T as TrustedHTML, c as collectStream, d as deserializeState, e as escapeScriptJson, h as hydrate, b as hydrateIslands, f as hydrateProgressively, i as isDangerousMetaRefresh, g as island, r as renderToDocument, j as renderToReadableStream, k as renderToStream, l as renderToString, m as renderToSuspenseStream, n as resetSSRState, s as serializeState, o as ssrSuspense, p as suspenseSwapScript, t as trustHTML } from './ssr-BiPRdZ6n.js';
1
+ export { H as HydrateOptions, a as HydrationMismatch, T as TrustedHTML, c as collectStream, d as deserializeState, e as escapeScriptJson, h as hydrate, b as hydrateIslands, f as hydrateProgressively, i as isDangerousMetaRefresh, g as island, r as renderToDocument, j as renderToReadableStream, k as renderToStream, l as renderToString, m as renderToSuspenseStream, n as resetSSRState, s as serializeState, o as ssrSuspense, p as suspenseSwapScript, t as trustHTML } from './ssr-Bli9XRW5.js';
2
2
 
3
3
  interface HeadProps {
4
4
  title?: string | (() => string);
@@ -482,8 +482,14 @@ interface ISROptions<T> {
482
482
  }
483
483
  /**
484
484
  * Creates an Incremental Static Regeneration (ISR) resource.
485
- * Data is fetched initially, then automatically revalidated after the
486
- * specified interval using setInterval.
485
+ * Data is fetched initially, then automatically revalidated once it goes stale.
486
+ *
487
+ * `isStale()` is a reactive signal: it flips to `true` when `revalidateAfter`
488
+ * elapses since the last successful fetch (effects re-run at that moment), stays
489
+ * `true` while a revalidation is pending or after one fails, and returns to
490
+ * `false` when a revalidation succeeds.
491
+ *
492
+ * @throws RangeError when `revalidateAfter` is not a positive finite number.
487
493
  */
488
494
  declare function createISR<T>(options: ISROptions<T>): {
489
495
  data: () => T | undefined;
package/dist/ssr.js CHANGED
@@ -23,9 +23,9 @@ import {
23
23
  wasm,
24
24
  worker,
25
25
  workerFn
26
- } from "./chunk-RJE2BNI4.js";
26
+ } from "./chunk-VZSG24LS.js";
27
27
  import "./chunk-52XFPGSN.js";
28
- import "./chunk-PCT43HW3.js";
28
+ import "./chunk-7LUJQAOJ.js";
29
29
  import {
30
30
  collectStream,
31
31
  deserializeState,
@@ -45,17 +45,16 @@ import {
45
45
  ssrSuspense,
46
46
  suspenseSwapScript,
47
47
  trustHTML
48
- } from "./chunk-NIOYEGBQ.js";
49
- import "./chunk-KEISJXBU.js";
50
- import "./chunk-ONOHFDLG.js";
51
- import "./chunk-IXKSNWV5.js";
48
+ } from "./chunk-HURREPU2.js";
49
+ import "./chunk-UOL2ECCS.js";
50
+ import "./chunk-FNJXNGYZ.js";
51
+ import "./chunk-2INLLLMZ.js";
52
52
  import "./chunk-7ZHH77QA.js";
53
- import "./chunk-RIXRAYIU.js";
54
- import "./chunk-5DXA2J44.js";
55
- import "./chunk-QKRPLZ2V.js";
56
- import "./chunk-XZZOBQAY.js";
57
- import "./chunk-UGRX3S57.js";
58
- import "./chunk-2WLZ6757.js";
53
+ import "./chunk-WEQ3DMVL.js";
54
+ import "./chunk-7XHATCIH.js";
55
+ import "./chunk-FQRUXCEE.js";
56
+ import "./chunk-JWKYU5GV.js";
57
+ import "./chunk-NYNYSPK7.js";
59
58
  export {
60
59
  Head,
61
60
  clearWasmCache,