sibujs 4.8.0 → 4.9.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 (66) hide show
  1. package/dist/browser.cjs +4 -3
  2. package/dist/browser.d.cts +3 -2
  3. package/dist/browser.d.ts +3 -2
  4. package/dist/browser.js +4 -4
  5. package/dist/build.cjs +27 -19
  6. package/dist/build.js +10 -10
  7. package/dist/cdn.dev.global.js +12 -12
  8. package/dist/cdn.full.dev.global.js +13 -13
  9. package/dist/cdn.full.global.js +12 -12
  10. package/dist/cdn.global.js +12 -12
  11. package/dist/{chunk-GSGNX35Q.js → chunk-2K3Z3XO4.js} +4 -4
  12. package/dist/{chunk-UCNP3HVM.js → chunk-562UVHMM.js} +24 -11
  13. package/dist/{chunk-VWT3VXPL.js → chunk-5MLWTIQE.js} +2 -2
  14. package/dist/{chunk-4WMSTZ7J.js → chunk-7OV5Q2UU.js} +4 -4
  15. package/dist/{chunk-CZPRSWSS.js → chunk-CDBKFGXN.js} +1 -1
  16. package/dist/{chunk-QGMSESDD.js → chunk-CF2KCWRE.js} +2 -2
  17. package/dist/{chunk-C5PEWEGH.js → chunk-DRMLIF6M.js} +2 -2
  18. package/dist/{chunk-C7AA2CZX.js → chunk-FHCZMHHE.js} +1 -1
  19. package/dist/{chunk-J3YQ457H.js → chunk-FNOK662L.js} +35 -27
  20. package/dist/{chunk-TQQUN4WR.js → chunk-G2WHYEL7.js} +1 -1
  21. package/dist/{chunk-44MTL7ED.js → chunk-K6K5ACO6.js} +3 -3
  22. package/dist/{chunk-JUTFX2RM.js → chunk-KG25XMGP.js} +30 -10
  23. package/dist/{chunk-O6TRVMJI.js → chunk-MPWDSTYK.js} +1 -1
  24. package/dist/{chunk-LI4W3U6C.js → chunk-NQMKWBKU.js} +1 -1
  25. package/dist/{chunk-Q5J2LVKH.js → chunk-QBKCK6MJ.js} +1 -1
  26. package/dist/{chunk-V3LHZSU5.js → chunk-SBTZEYNI.js} +1 -1
  27. package/dist/{chunk-DSID757X.js → chunk-SYHGGDNW.js} +1 -1
  28. package/dist/{chunk-RGLPEBDE.js → chunk-TV464N2M.js} +3 -3
  29. package/dist/{chunk-KJ3UKABJ.js → chunk-X7NRHFZR.js} +1 -1
  30. package/dist/{chunk-ZVLHNEEL.js → chunk-XJVTQUIV.js} +6 -6
  31. package/dist/{chunk-EGUQLBHE.js → chunk-YW6HQKGO.js} +5 -4
  32. package/dist/data.cjs +21 -8
  33. package/dist/data.d.cts +23 -4
  34. package/dist/data.d.ts +23 -4
  35. package/dist/data.js +5 -5
  36. package/dist/devtools.cjs +1 -1
  37. package/dist/devtools.js +4 -4
  38. package/dist/ecosystem.cjs +1 -1
  39. package/dist/ecosystem.js +7 -7
  40. package/dist/extras.cjs +54 -20
  41. package/dist/extras.js +20 -20
  42. package/dist/index.cjs +27 -19
  43. package/dist/index.d.cts +6 -0
  44. package/dist/index.d.ts +6 -0
  45. package/dist/index.js +10 -10
  46. package/dist/motion.cjs +1 -1
  47. package/dist/motion.js +3 -3
  48. package/dist/patterns.cjs +1 -1
  49. package/dist/patterns.js +5 -5
  50. package/dist/performance.cjs +1 -1
  51. package/dist/performance.js +4 -4
  52. package/dist/plugins.cjs +16 -12
  53. package/dist/plugins.d.cts +6 -0
  54. package/dist/plugins.d.ts +6 -0
  55. package/dist/plugins.js +20 -16
  56. package/dist/ssr.cjs +28 -8
  57. package/dist/ssr.d.cts +4 -0
  58. package/dist/ssr.d.ts +4 -0
  59. package/dist/ssr.js +7 -7
  60. package/dist/testing.cjs +1 -1
  61. package/dist/testing.js +2 -2
  62. package/dist/ui.cjs +2 -2
  63. package/dist/ui.js +7 -7
  64. package/dist/widgets.cjs +1 -1
  65. package/dist/widgets.js +6 -6
  66. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -1697,7 +1697,7 @@ function forEachSubscriber(signal2, visit) {
1697
1697
  }
1698
1698
 
1699
1699
  // src/reactivity/track.ts
1700
- var _runtimeVersion = true ? "4.8.0" : "dev";
1700
+ var _runtimeVersion = true ? "4.9.0" : "dev";
1701
1701
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
1702
1702
  function resolveReactiveApi() {
1703
1703
  const g2 = globalThis;
@@ -3966,37 +3966,44 @@ function action(element, action2, param2) {
3966
3966
  }
3967
3967
  }
3968
3968
  var clickOutside = (element, callback) => {
3969
+ const doc = element.ownerDocument;
3969
3970
  const handler = (e) => {
3970
- if (!element.contains(e.target)) {
3971
- callback();
3972
- }
3971
+ const target = e.target;
3972
+ if (!(typeof target?.nodeType === "number" && element.contains(target))) callback();
3973
3973
  };
3974
- document.addEventListener("pointerdown", handler, true);
3975
- return () => document.removeEventListener("pointerdown", handler, true);
3974
+ doc.addEventListener("pointerdown", handler, true);
3975
+ return () => doc.removeEventListener("pointerdown", handler, true);
3976
3976
  };
3977
+ var PRESS_END_EVENTS = ["pointerup", "pointerleave", "pointercancel"];
3977
3978
  var longPress = (element, options) => {
3978
3979
  const duration = options.duration ?? 500;
3979
3980
  let timer = null;
3980
- const start = () => {
3981
- timer = setTimeout(() => {
3982
- options.callback();
3983
- timer = null;
3984
- }, duration);
3985
- };
3981
+ let owner;
3986
3982
  const cancel = () => {
3987
3983
  if (timer !== null) {
3988
3984
  clearTimeout(timer);
3989
3985
  timer = null;
3990
3986
  }
3991
3987
  };
3988
+ const start = (e) => {
3989
+ const id = e.pointerId;
3990
+ if (timer !== null && id !== owner) return;
3991
+ cancel();
3992
+ owner = id;
3993
+ timer = setTimeout(() => {
3994
+ timer = null;
3995
+ options.callback();
3996
+ }, duration);
3997
+ };
3998
+ const end = (e) => {
3999
+ if (timer !== null && e.pointerId === owner) cancel();
4000
+ };
3992
4001
  element.addEventListener("pointerdown", start);
3993
- element.addEventListener("pointerup", cancel);
3994
- element.addEventListener("pointerleave", cancel);
4002
+ for (const type of PRESS_END_EVENTS) element.addEventListener(type, end);
3995
4003
  return () => {
3996
4004
  cancel();
3997
4005
  element.removeEventListener("pointerdown", start);
3998
- element.removeEventListener("pointerup", cancel);
3999
- element.removeEventListener("pointerleave", cancel);
4006
+ for (const type of PRESS_END_EVENTS) element.removeEventListener(type, end);
4000
4007
  };
4001
4008
  };
4002
4009
  var copyOnClick = (element, getText) => {
@@ -4030,10 +4037,11 @@ var trapFocus = (element) => {
4030
4037
  if (elements.length === 0) return;
4031
4038
  const first = elements[0];
4032
4039
  const last = elements[elements.length - 1];
4033
- if (e.shiftKey && document.activeElement === first) {
4040
+ const active = element.ownerDocument.activeElement;
4041
+ if (e.shiftKey && active === first) {
4034
4042
  e.preventDefault();
4035
4043
  last.focus();
4036
- } else if (!e.shiftKey && document.activeElement === last) {
4044
+ } else if (!e.shiftKey && active === last) {
4037
4045
  e.preventDefault();
4038
4046
  first.focus();
4039
4047
  }
@@ -5034,7 +5042,7 @@ function KeepAlive(activeKey, cases, options) {
5034
5042
  return;
5035
5043
  }
5036
5044
  node = factory();
5037
- if (node instanceof DocumentFragment) {
5045
+ if (node.nodeType === 11) {
5038
5046
  const wrapper = document.createElement("div");
5039
5047
  wrapper.style.display = "contents";
5040
5048
  wrapper.appendChild(node);
package/dist/index.d.cts CHANGED
@@ -289,6 +289,12 @@ interface LongPressOptions {
289
289
  /**
290
290
  * Fires a callback after a sustained press on the element.
291
291
  *
292
+ * One press at a time, owned by the pointer that started it: only that
293
+ * pointer's `pointerup`, `pointerleave` or `pointercancel` ends it, and another
294
+ * pointer going down meanwhile is ignored. The same pointer going down again
295
+ * restarts the press. Cleanup cancels a pending press, so the callback never
296
+ * fires after the action is disposed.
297
+ *
292
298
  * @example
293
299
  * ```ts
294
300
  * action(el, longPress, { duration: 800, callback: onLongPress });
package/dist/index.d.ts CHANGED
@@ -289,6 +289,12 @@ interface LongPressOptions {
289
289
  /**
290
290
  * Fires a callback after a sustained press on the element.
291
291
  *
292
+ * One press at a time, owned by the pointer that started it: only that
293
+ * pointer's `pointerup`, `pointerleave` or `pointercancel` ends it, and another
294
+ * pointer going down meanwhile is ignored. The same pointer going down again
295
+ * restarts the press. Cleanup cancels a pending press, so the callback never
296
+ * fires after the action is disposed.
297
+ *
292
298
  * @example
293
299
  * ```ts
294
300
  * action(el, longPress, { duration: 800, callback: onLongPress });
package/dist/index.js CHANGED
@@ -54,7 +54,7 @@ import {
54
54
  unregisterIsland,
55
55
  when,
56
56
  writable
57
- } from "./chunk-J3YQ457H.js";
57
+ } from "./chunk-FNOK662L.js";
58
58
  import {
59
59
  a,
60
60
  abbr,
@@ -192,34 +192,34 @@ import {
192
192
  use,
193
193
  var_,
194
194
  video
195
- } from "./chunk-Q5J2LVKH.js";
195
+ } from "./chunk-QBKCK6MJ.js";
196
196
  import {
197
197
  trustHTML
198
198
  } from "./chunk-FC6KCJSA.js";
199
199
  import {
200
200
  watch
201
- } from "./chunk-CZPRSWSS.js";
201
+ } from "./chunk-CDBKFGXN.js";
202
202
  import {
203
203
  __resetIdCounter,
204
204
  createId
205
- } from "./chunk-C7AA2CZX.js";
205
+ } from "./chunk-FHCZMHHE.js";
206
206
  import "./chunk-62BDYGAG.js";
207
207
  import {
208
208
  SVG_NS,
209
209
  tagFactory
210
- } from "./chunk-VWT3VXPL.js";
210
+ } from "./chunk-5MLWTIQE.js";
211
211
  import {
212
212
  bindDynamic
213
- } from "./chunk-O6TRVMJI.js";
213
+ } from "./chunk-MPWDSTYK.js";
214
214
  import "./chunk-3ACAAQIN.js";
215
215
  import {
216
216
  derived
217
- } from "./chunk-KJ3UKABJ.js";
217
+ } from "./chunk-X7NRHFZR.js";
218
218
  import "./chunk-7ZHH77QA.js";
219
219
  import {
220
220
  effect,
221
221
  on
222
- } from "./chunk-V3LHZSU5.js";
222
+ } from "./chunk-SBTZEYNI.js";
223
223
  import "./chunk-EXXSN3BW.js";
224
224
  import {
225
225
  disableSSR,
@@ -237,12 +237,12 @@ import {
237
237
  external,
238
238
  isBatching,
239
239
  signal
240
- } from "./chunk-DSID757X.js";
240
+ } from "./chunk-SYHGGDNW.js";
241
241
  import {
242
242
  retrack,
243
243
  setMaxDrainIterations,
244
244
  untracked
245
- } from "./chunk-TQQUN4WR.js";
245
+ } from "./chunk-G2WHYEL7.js";
246
246
  import {
247
247
  MAX_DRAIN_TEARDOWNS,
248
248
  checkLeaks,
package/dist/motion.cjs CHANGED
@@ -761,7 +761,7 @@ function forEachSubscriber(signal2, visit) {
761
761
  }
762
762
 
763
763
  // src/reactivity/track.ts
764
- var _runtimeVersion = true ? "4.8.0" : "dev";
764
+ var _runtimeVersion = true ? "4.9.0" : "dev";
765
765
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
766
766
  function resolveReactiveApi() {
767
767
  const g = globalThis;
package/dist/motion.js CHANGED
@@ -20,10 +20,10 @@ import {
20
20
  stagger,
21
21
  transition,
22
22
  viewTransition
23
- } from "./chunk-LI4W3U6C.js";
23
+ } from "./chunk-NQMKWBKU.js";
24
24
  import "./chunk-5HZXGZ6T.js";
25
- import "./chunk-DSID757X.js";
26
- import "./chunk-TQQUN4WR.js";
25
+ import "./chunk-SYHGGDNW.js";
26
+ import "./chunk-G2WHYEL7.js";
27
27
  import "./chunk-NYNYSPK7.js";
28
28
  export {
29
29
  TransitionGroup,
package/dist/patterns.cjs CHANGED
@@ -657,7 +657,7 @@ function forEachSubscriber(signal2, visit) {
657
657
  }
658
658
 
659
659
  // src/reactivity/track.ts
660
- var _runtimeVersion = true ? "4.8.0" : "dev";
660
+ var _runtimeVersion = true ? "4.9.0" : "dev";
661
661
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
662
662
  function resolveReactiveApi() {
663
663
  const g = globalThis;
package/dist/patterns.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  optimisticList,
6
6
  persisted,
7
7
  timeline
8
- } from "./chunk-RGLPEBDE.js";
8
+ } from "./chunk-TV464N2M.js";
9
9
  import {
10
10
  RenderProp,
11
11
  assertType,
@@ -23,11 +23,11 @@ import {
23
23
  withWrapper
24
24
  } from "./chunk-TUCPL2HB.js";
25
25
  import "./chunk-62BDYGAG.js";
26
- import "./chunk-KJ3UKABJ.js";
27
- import "./chunk-V3LHZSU5.js";
26
+ import "./chunk-X7NRHFZR.js";
27
+ import "./chunk-SBTZEYNI.js";
28
28
  import "./chunk-7XHATCIH.js";
29
- import "./chunk-DSID757X.js";
30
- import "./chunk-TQQUN4WR.js";
29
+ import "./chunk-SYHGGDNW.js";
30
+ import "./chunk-G2WHYEL7.js";
31
31
  import "./chunk-NYNYSPK7.js";
32
32
  export {
33
33
  RenderProp,
@@ -923,7 +923,7 @@ function forEachSubscriber(signal2, visit) {
923
923
  }
924
924
 
925
925
  // src/reactivity/track.ts
926
- var _runtimeVersion = true ? "4.8.0" : "dev";
926
+ var _runtimeVersion = true ? "4.9.0" : "dev";
927
927
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
928
928
  function resolveReactiveApi() {
929
929
  const g = globalThis;
@@ -33,18 +33,18 @@ import {
33
33
  transitionState,
34
34
  uniqueId,
35
35
  yieldToMain
36
- } from "./chunk-C5PEWEGH.js";
36
+ } from "./chunk-DRMLIF6M.js";
37
37
  import {
38
38
  trustHTML
39
39
  } from "./chunk-FC6KCJSA.js";
40
40
  import "./chunk-62BDYGAG.js";
41
41
  import "./chunk-3ACAAQIN.js";
42
42
  import "./chunk-7ZHH77QA.js";
43
- import "./chunk-V3LHZSU5.js";
43
+ import "./chunk-SBTZEYNI.js";
44
44
  import "./chunk-EXXSN3BW.js";
45
45
  import "./chunk-7XHATCIH.js";
46
- import "./chunk-DSID757X.js";
47
- import "./chunk-TQQUN4WR.js";
46
+ import "./chunk-SYHGGDNW.js";
47
+ import "./chunk-G2WHYEL7.js";
48
48
  import "./chunk-NYNYSPK7.js";
49
49
  export {
50
50
  DOMPool,
package/dist/plugins.cjs CHANGED
@@ -2355,7 +2355,7 @@ function forEachSubscriber(signal2, visit) {
2355
2355
  }
2356
2356
 
2357
2357
  // src/reactivity/track.ts
2358
- var _runtimeVersion = true ? "4.8.0" : "dev";
2358
+ var _runtimeVersion = true ? "4.9.0" : "dev";
2359
2359
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
2360
2360
  function resolveReactiveApi() {
2361
2361
  const g2 = globalThis;
@@ -3418,9 +3418,14 @@ function normalizePathname(path2) {
3418
3418
  const trimmed = path2.length > 1 ? path2.replace(/\/+$/, "") : path2;
3419
3419
  return trimmed || "/";
3420
3420
  }
3421
- function normalizeQuery(query) {
3422
- const params = new URLSearchParams(query);
3423
- return [...params.entries()].sort(([a2], [b2]) => a2 < b2 ? -1 : a2 > b2 ? 1 : 0).map(([k, v]) => `${k}=${v}`).join("&");
3421
+ function parseQuery(query) {
3422
+ return Object.fromEntries(new URLSearchParams(query));
3423
+ }
3424
+ function paramsIdentity(params) {
3425
+ return JSON.stringify(Object.entries(params).sort(([a2], [b2]) => a2 < b2 ? -1 : a2 > b2 ? 1 : 0));
3426
+ }
3427
+ function queryIdentity(query) {
3428
+ return paramsIdentity(typeof query === "string" ? parseQuery(query) : query);
3424
3429
  }
3425
3430
  function isPathnameAncestor(target, current) {
3426
3431
  if (target === current) return true;
@@ -4121,7 +4126,7 @@ var _SibuRouter = class _SibuRouter {
4121
4126
  }
4122
4127
  createRouteContext(fullPath) {
4123
4128
  const { path: path2, query: queryString, hash } = splitRouteUrl(fullPath);
4124
- const query = Object.fromEntries(new URLSearchParams(queryString));
4129
+ const query = parseQuery(queryString);
4125
4130
  const match = this.matcher.match(path2 || "/");
4126
4131
  const params = match?.params || {};
4127
4132
  const meta2 = match?.route.meta || {};
@@ -4285,7 +4290,7 @@ var _SibuRouter = class _SibuRouter {
4285
4290
  }
4286
4291
  isSameRoute(from, to) {
4287
4292
  if (from.matched.length === 0 && to.matched.length > 0) return false;
4288
- return from.path === to.path && JSON.stringify(from.params) === JSON.stringify(to.params) && JSON.stringify(from.query) === JSON.stringify(to.query) && from.hash === to.hash;
4293
+ return from.path === to.path && paramsIdentity(from.params) === paramsIdentity(to.params) && queryIdentity(from.query) === queryIdentity(to.query) && from.hash === to.hash;
4289
4294
  }
4290
4295
  updateHistory(to, options) {
4291
4296
  const fullPath = this.options.base + to.path + (Object.keys(to.query).length ? `?${new URLSearchParams(to.query).toString()}` : "") + (to.hash ? `#${to.hash}` : "");
@@ -4795,8 +4800,7 @@ function KeepAliveRoute(options) {
4795
4800
  return;
4796
4801
  }
4797
4802
  if (!("component" in routeDef)) return;
4798
- const queryStr = Object.keys(route2.query).length > 0 ? `?${new URLSearchParams(route2.query).toString()}` : "";
4799
- const cacheKey = `${route2.path}${queryStr}${route2.hash ? `#${route2.hash}` : ""}`;
4803
+ const cacheKey = JSON.stringify([route2.path, queryIdentity(route2.query), route2.hash]);
4800
4804
  const shouldCache = !includeNames || routeDef.name != null && includeNames.includes(routeDef.name);
4801
4805
  if (cacheKey === currentKey && currentNode) return;
4802
4806
  if (!anchor.parentNode) return;
@@ -4898,7 +4902,7 @@ function RouterLink(props, children) {
4898
4902
  const href = kind === "unsafe" ? "#" : rawHref;
4899
4903
  const { path: hrefPathRaw, query: hrefQueryRaw, hash: hrefHash } = splitRouteUrl(href);
4900
4904
  const targetPath = normalizePathname(hrefPathRaw);
4901
- const targetQuery = normalizeQuery(hrefQueryRaw);
4905
+ const targetQuery = queryIdentity(hrefQueryRaw);
4902
4906
  const link2 = document.createElement("a");
4903
4907
  link2.href = href;
4904
4908
  if (target) {
@@ -4916,7 +4920,7 @@ function RouterLink(props, children) {
4916
4920
  const route2 = routeGetter();
4917
4921
  const currentPath = normalizePathname(route2.path);
4918
4922
  const isActive = kind === "internal" && isPathnameAncestor(targetPath, currentPath);
4919
- const isExactActive = kind === "internal" && currentPath === targetPath && normalizeQuery(route2.query) === targetQuery && route2.hash === hrefHash;
4923
+ const isExactActive = kind === "internal" && currentPath === targetPath && queryIdentity(route2.query) === targetQuery && route2.hash === hrefHash;
4920
4924
  const classes = [];
4921
4925
  if (isActive) {
4922
4926
  if (activeClass) classes.push(activeClass);
@@ -5905,7 +5909,7 @@ var CDN_ENTRY_POINTS = {
5905
5909
  };
5906
5910
  var packageInfo = {
5907
5911
  name: "sibujs",
5908
- version: true ? "4.8.0" : "dev",
5912
+ version: true ? "4.9.0" : "dev",
5909
5913
  entryPoints: MODULE_ENTRY_POINTS,
5910
5914
  /**
5911
5915
  * Generate the package.json `exports` map. Module entries resolve to the
@@ -6050,7 +6054,7 @@ var env = {
6050
6054
  };
6051
6055
 
6052
6056
  // src/plugins/versioning.ts
6053
- var VERSION = true ? "4.8.0" : "dev";
6057
+ var VERSION = true ? "4.9.0" : "dev";
6054
6058
  var NUM = "(?:0|[1-9]\\d*)";
6055
6059
  var PRE_ID = `(?:${NUM}|\\d*[a-zA-Z-][0-9a-zA-Z-]*)`;
6056
6060
  var BUILD_ID = "[0-9a-zA-Z-]+";
@@ -180,6 +180,12 @@ type Params = Record<string, string>;
180
180
  interface RouteContext {
181
181
  readonly path: string;
182
182
  readonly params: Params;
183
+ /**
184
+ * The decoded query (`+` is a space, `%XX` is decoded). A repeated key keeps
185
+ * its last value: `?tag=a&tag=b` is `{ tag: "b" }`. Two locations are the
186
+ * same route — for duplicate detection and `RouterLink` exact-active — when
187
+ * their queries have the same entries in any order.
188
+ */
183
189
  readonly query: Params;
184
190
  readonly hash: string;
185
191
  readonly meta: RouteMeta;
package/dist/plugins.d.ts CHANGED
@@ -180,6 +180,12 @@ type Params = Record<string, string>;
180
180
  interface RouteContext {
181
181
  readonly path: string;
182
182
  readonly params: Params;
183
+ /**
184
+ * The decoded query (`+` is a space, `%XX` is decoded). A repeated key keeps
185
+ * its last value: `?tag=a&tag=b` is `{ tag: "b" }`. Two locations are the
186
+ * same route — for duplicate detection and `RouterLink` exact-active — when
187
+ * their queries have the same entries in any order.
188
+ */
183
189
  readonly query: Params;
184
190
  readonly hash: string;
185
191
  readonly meta: RouteMeta;
package/dist/plugins.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  preloadCritical,
20
20
  prerenderRoutes,
21
21
  satisfies
22
- } from "./chunk-QGMSESDD.js";
22
+ } from "./chunk-CF2KCWRE.js";
23
23
  import {
24
24
  PluginInstallCancelledError,
25
25
  createPlugin,
@@ -35,7 +35,7 @@ import {
35
35
  } from "./chunk-J6FW5TV6.js";
36
36
  import {
37
37
  span
38
- } from "./chunk-Q5J2LVKH.js";
38
+ } from "./chunk-QBKCK6MJ.js";
39
39
  import {
40
40
  escapeScriptJson,
41
41
  renderToString,
@@ -48,17 +48,17 @@ import {
48
48
  import {
49
49
  appendChildren,
50
50
  resolveClassValue
51
- } from "./chunk-VWT3VXPL.js";
51
+ } from "./chunk-5MLWTIQE.js";
52
52
  import {
53
53
  setSafeAttribute
54
- } from "./chunk-O6TRVMJI.js";
54
+ } from "./chunk-MPWDSTYK.js";
55
55
  import "./chunk-3ACAAQIN.js";
56
56
  import {
57
57
  globalSingleton
58
58
  } from "./chunk-7ZHH77QA.js";
59
59
  import {
60
60
  effect
61
- } from "./chunk-V3LHZSU5.js";
61
+ } from "./chunk-SBTZEYNI.js";
62
62
  import {
63
63
  sanitizeUrl,
64
64
  stripControlChars
@@ -69,11 +69,11 @@ import {
69
69
  import "./chunk-5HZXGZ6T.js";
70
70
  import {
71
71
  signal
72
- } from "./chunk-DSID757X.js";
72
+ } from "./chunk-SYHGGDNW.js";
73
73
  import {
74
74
  track,
75
75
  untracked
76
- } from "./chunk-TQQUN4WR.js";
76
+ } from "./chunk-G2WHYEL7.js";
77
77
  import {
78
78
  devWarn,
79
79
  dispose,
@@ -180,9 +180,14 @@ function normalizePathname(path) {
180
180
  const trimmed = path.length > 1 ? path.replace(/\/+$/, "") : path;
181
181
  return trimmed || "/";
182
182
  }
183
- function normalizeQuery(query) {
184
- const params = new URLSearchParams(query);
185
- return [...params.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([k, v]) => `${k}=${v}`).join("&");
183
+ function parseQuery(query) {
184
+ return Object.fromEntries(new URLSearchParams(query));
185
+ }
186
+ function paramsIdentity(params) {
187
+ return JSON.stringify(Object.entries(params).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0));
188
+ }
189
+ function queryIdentity(query) {
190
+ return paramsIdentity(typeof query === "string" ? parseQuery(query) : query);
186
191
  }
187
192
  function isPathnameAncestor(target, current) {
188
193
  if (target === current) return true;
@@ -883,7 +888,7 @@ var _SibuRouter = class _SibuRouter {
883
888
  }
884
889
  createRouteContext(fullPath) {
885
890
  const { path, query: queryString, hash } = splitRouteUrl(fullPath);
886
- const query = Object.fromEntries(new URLSearchParams(queryString));
891
+ const query = parseQuery(queryString);
887
892
  const match = this.matcher.match(path || "/");
888
893
  const params = match?.params || {};
889
894
  const meta = match?.route.meta || {};
@@ -1047,7 +1052,7 @@ var _SibuRouter = class _SibuRouter {
1047
1052
  }
1048
1053
  isSameRoute(from, to) {
1049
1054
  if (from.matched.length === 0 && to.matched.length > 0) return false;
1050
- return from.path === to.path && JSON.stringify(from.params) === JSON.stringify(to.params) && JSON.stringify(from.query) === JSON.stringify(to.query) && from.hash === to.hash;
1055
+ return from.path === to.path && paramsIdentity(from.params) === paramsIdentity(to.params) && queryIdentity(from.query) === queryIdentity(to.query) && from.hash === to.hash;
1051
1056
  }
1052
1057
  updateHistory(to, options) {
1053
1058
  const fullPath = this.options.base + to.path + (Object.keys(to.query).length ? `?${new URLSearchParams(to.query).toString()}` : "") + (to.hash ? `#${to.hash}` : "");
@@ -1557,8 +1562,7 @@ function KeepAliveRoute(options) {
1557
1562
  return;
1558
1563
  }
1559
1564
  if (!("component" in routeDef)) return;
1560
- const queryStr = Object.keys(route2.query).length > 0 ? `?${new URLSearchParams(route2.query).toString()}` : "";
1561
- const cacheKey = `${route2.path}${queryStr}${route2.hash ? `#${route2.hash}` : ""}`;
1565
+ const cacheKey = JSON.stringify([route2.path, queryIdentity(route2.query), route2.hash]);
1562
1566
  const shouldCache = !includeNames || routeDef.name != null && includeNames.includes(routeDef.name);
1563
1567
  if (cacheKey === currentKey && currentNode) return;
1564
1568
  if (!anchor.parentNode) return;
@@ -1660,7 +1664,7 @@ function RouterLink(props, children) {
1660
1664
  const href = kind === "unsafe" ? "#" : rawHref;
1661
1665
  const { path: hrefPathRaw, query: hrefQueryRaw, hash: hrefHash } = splitRouteUrl(href);
1662
1666
  const targetPath = normalizePathname(hrefPathRaw);
1663
- const targetQuery = normalizeQuery(hrefQueryRaw);
1667
+ const targetQuery = queryIdentity(hrefQueryRaw);
1664
1668
  const link = document.createElement("a");
1665
1669
  link.href = href;
1666
1670
  if (target) {
@@ -1678,7 +1682,7 @@ function RouterLink(props, children) {
1678
1682
  const route2 = routeGetter();
1679
1683
  const currentPath = normalizePathname(route2.path);
1680
1684
  const isActive = kind === "internal" && isPathnameAncestor(targetPath, currentPath);
1681
- const isExactActive = kind === "internal" && currentPath === targetPath && normalizeQuery(route2.query) === targetQuery && route2.hash === hrefHash;
1685
+ const isExactActive = kind === "internal" && currentPath === targetPath && queryIdentity(route2.query) === targetQuery && route2.hash === hrefHash;
1682
1686
  const classes = [];
1683
1687
  if (isActive) {
1684
1688
  if (activeClass) classes.push(activeClass);
package/dist/ssr.cjs CHANGED
@@ -1997,7 +1997,7 @@ function forEachSubscriber(signal2, visit) {
1997
1997
  }
1998
1998
 
1999
1999
  // src/reactivity/track.ts
2000
- var _runtimeVersion = true ? "4.8.0" : "dev";
2000
+ var _runtimeVersion = true ? "4.9.0" : "dev";
2001
2001
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
2002
2002
  function resolveReactiveApi() {
2003
2003
  const g2 = globalThis;
@@ -2601,7 +2601,7 @@ function createISR(options) {
2601
2601
  const [data2, setData] = signal(initialData);
2602
2602
  const [stale, setStale] = signal(initialData === void 0);
2603
2603
  const controller = new AbortController();
2604
- let inFlight = false;
2604
+ let inFlight = null;
2605
2605
  let disposed = false;
2606
2606
  let deadline;
2607
2607
  const clearDeadline = () => {
@@ -2621,10 +2621,7 @@ function createISR(options) {
2621
2621
  });
2622
2622
  }, revalidateAfter);
2623
2623
  };
2624
- const revalidate = async () => {
2625
- if (disposed || inFlight) return;
2626
- if (controller.signal.aborted) return;
2627
- inFlight = true;
2624
+ const run = async () => {
2628
2625
  try {
2629
2626
  const result = await fetcher({ signal: controller.signal });
2630
2627
  if (disposed || controller.signal.aborted) return;
@@ -2636,10 +2633,33 @@ function createISR(options) {
2636
2633
  } catch (err) {
2637
2634
  if (!disposed && !controller.signal.aborted) armDeadline();
2638
2635
  throw err;
2639
- } finally {
2640
- inFlight = false;
2641
2636
  }
2642
2637
  };
2638
+ const revalidate = () => {
2639
+ if (disposed || controller.signal.aborted) return Promise.resolve();
2640
+ if (inFlight) return inFlight;
2641
+ let resolve;
2642
+ let reject;
2643
+ const current = new Promise((res, rej) => {
2644
+ resolve = res;
2645
+ reject = rej;
2646
+ });
2647
+ inFlight = current;
2648
+ const release = () => {
2649
+ if (inFlight === current) inFlight = null;
2650
+ };
2651
+ run().then(
2652
+ () => {
2653
+ release();
2654
+ resolve();
2655
+ },
2656
+ (err) => {
2657
+ release();
2658
+ reject(err);
2659
+ }
2660
+ );
2661
+ return current;
2662
+ };
2643
2663
  if (initialData === void 0) {
2644
2664
  revalidate().catch((err) => {
2645
2665
  if (typeof console !== "undefined") console.warn("[SibuJS ISR] initial fetch failed", err);
package/dist/ssr.d.cts CHANGED
@@ -539,6 +539,10 @@ interface ISROptions<T> {
539
539
  * `true` while a revalidation is pending or after one fails, and returns to
540
540
  * `false` when a revalidation succeeds.
541
541
  *
542
+ * `revalidate()` called while a revalidation is running joins it instead of
543
+ * starting another: the fetcher runs once, and every caller's promise settles
544
+ * — resolving, or rejecting with the same error — when that fetch does.
545
+ *
542
546
  * @throws RangeError when `revalidateAfter` is not a positive finite number.
543
547
  */
544
548
  declare function createISR<T>(options: ISROptions<T>): {
package/dist/ssr.d.ts CHANGED
@@ -539,6 +539,10 @@ interface ISROptions<T> {
539
539
  * `true` while a revalidation is pending or after one fails, and returns to
540
540
  * `false` when a revalidation succeeds.
541
541
  *
542
+ * `revalidate()` called while a revalidation is running joins it instead of
543
+ * starting another: the fetcher runs once, and every caller's promise settles
544
+ * — resolving, or rejecting with the same error — when that fetch does.
545
+ *
542
546
  * @throws RangeError when `revalidateAfter` is not a positive finite number.
543
547
  */
544
548
  declare function createISR<T>(options: ISROptions<T>): {
package/dist/ssr.js CHANGED
@@ -23,9 +23,9 @@ import {
23
23
  wasm,
24
24
  worker,
25
25
  workerFn
26
- } from "./chunk-JUTFX2RM.js";
26
+ } from "./chunk-KG25XMGP.js";
27
27
  import "./chunk-52XFPGSN.js";
28
- import "./chunk-Q5J2LVKH.js";
28
+ import "./chunk-QBKCK6MJ.js";
29
29
  import {
30
30
  collectStream,
31
31
  deserializeState,
@@ -47,15 +47,15 @@ import {
47
47
  trustHTML
48
48
  } from "./chunk-FC6KCJSA.js";
49
49
  import "./chunk-62BDYGAG.js";
50
- import "./chunk-VWT3VXPL.js";
51
- import "./chunk-O6TRVMJI.js";
50
+ import "./chunk-5MLWTIQE.js";
51
+ import "./chunk-MPWDSTYK.js";
52
52
  import "./chunk-3ACAAQIN.js";
53
53
  import "./chunk-7ZHH77QA.js";
54
- import "./chunk-V3LHZSU5.js";
54
+ import "./chunk-SBTZEYNI.js";
55
55
  import "./chunk-EXXSN3BW.js";
56
56
  import "./chunk-7XHATCIH.js";
57
- import "./chunk-DSID757X.js";
58
- import "./chunk-TQQUN4WR.js";
57
+ import "./chunk-SYHGGDNW.js";
58
+ import "./chunk-G2WHYEL7.js";
59
59
  import "./chunk-NYNYSPK7.js";
60
60
  export {
61
61
  Head,
package/dist/testing.cjs CHANGED
@@ -754,7 +754,7 @@ function forEachSubscriber(signal, visit) {
754
754
  }
755
755
 
756
756
  // src/reactivity/track.ts
757
- var _runtimeVersion = true ? "4.8.0" : "dev";
757
+ var _runtimeVersion = true ? "4.9.0" : "dev";
758
758
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
759
759
  function resolveReactiveApi() {
760
760
  const g = globalThis;
package/dist/testing.js CHANGED
@@ -3,9 +3,9 @@ import {
3
3
  } from "./chunk-7ZHH77QA.js";
4
4
  import {
5
5
  effect
6
- } from "./chunk-V3LHZSU5.js";
6
+ } from "./chunk-SBTZEYNI.js";
7
7
  import "./chunk-7XHATCIH.js";
8
- import "./chunk-TQQUN4WR.js";
8
+ import "./chunk-G2WHYEL7.js";
9
9
  import {
10
10
  dispose,
11
11
  replaceChildrenSafely,