sibujs 4.6.0 → 4.8.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 (94) hide show
  1. package/README.md +1 -1
  2. package/dist/browser.cjs +62 -8
  3. package/dist/browser.d.cts +23 -0
  4. package/dist/browser.d.ts +23 -0
  5. package/dist/browser.js +6 -5
  6. package/dist/build.cjs +2388 -1004
  7. package/dist/build.d.cts +147 -44
  8. package/dist/build.d.ts +147 -44
  9. package/dist/build.js +1410 -564
  10. package/dist/cdn.dev.global.js +14 -12
  11. package/dist/cdn.full.dev.global.js +15 -13
  12. package/dist/cdn.full.global.js +14 -12
  13. package/dist/cdn.global.js +12 -10
  14. package/dist/chunk-3ACAAQIN.js +224 -0
  15. package/dist/{chunk-7NCARGJW.js → chunk-44MTL7ED.js} +6 -6
  16. package/dist/{chunk-BAAG6ZTI.js → chunk-4WMSTZ7J.js} +8 -5
  17. package/dist/{chunk-H3SRKIYX.js → chunk-62BDYGAG.js} +8 -0
  18. package/dist/{chunk-DKGBBKOF.js → chunk-C5PEWEGH.js} +20 -5
  19. package/dist/{chunk-3ISI6ACU.js → chunk-C7AA2CZX.js} +1 -1
  20. package/dist/{chunk-UZQ6ALFS.js → chunk-CZPRSWSS.js} +1 -1
  21. package/dist/{chunk-D33YTSX5.js → chunk-DSID757X.js} +5 -4
  22. package/dist/{chunk-OXUY2A6L.js → chunk-EGUQLBHE.js} +22 -8
  23. package/dist/{chunk-2INLLLMZ.js → chunk-EXXSN3BW.js} +202 -26
  24. package/dist/{chunk-HURREPU2.js → chunk-FC6KCJSA.js} +87 -150
  25. package/dist/{chunk-HYXDKS4N.js → chunk-GSGNX35Q.js} +5 -5
  26. package/dist/{chunk-7GQCWFOE.js → chunk-J3YQ457H.js} +171 -85
  27. package/dist/{chunk-ORMZXBKQ.js → chunk-JUTFX2RM.js} +18 -10
  28. package/dist/{chunk-QE4TTDU3.js → chunk-KJ3UKABJ.js} +12 -11
  29. package/dist/{chunk-XRRZKZYX.js → chunk-LI4W3U6C.js} +1 -1
  30. package/dist/{chunk-47M47FOM.js → chunk-O6TRVMJI.js} +58 -6
  31. package/dist/{chunk-JSXPZCET.js → chunk-Q5J2LVKH.js} +1 -1
  32. package/dist/{chunk-5MT6SJ3P.js → chunk-QGMSESDD.js} +10 -5
  33. package/dist/{chunk-AIF3Z2T7.js → chunk-RGLPEBDE.js} +13 -10
  34. package/dist/{chunk-5Q4R7HCL.js → chunk-TQQUN4WR.js} +11 -2
  35. package/dist/{chunk-PK6FK2G2.js → chunk-UCNP3HVM.js} +183 -30
  36. package/dist/{chunk-XC4MEKGA.js → chunk-V3LHZSU5.js} +8 -2
  37. package/dist/{chunk-VVWPJ543.js → chunk-VWT3VXPL.js} +55 -20
  38. package/dist/{chunk-SXXVZMKZ.js → chunk-ZVLHNEEL.js} +17 -35
  39. package/dist/{contracts-DRIuclVT.d.cts → contracts-CLqzJnOV.d.ts} +28 -17
  40. package/dist/{contracts-DRIuclVT.d.ts → contracts-CTOJXu-x.d.cts} +28 -17
  41. package/dist/{customElement-MmInOW1U.d.ts → customElement-pYDKUzWl.d.cts} +11 -3
  42. package/dist/{customElement-MmInOW1U.d.cts → customElement-pYDKUzWl.d.ts} +11 -3
  43. package/dist/data.cjs +205 -39
  44. package/dist/data.d.cts +119 -3
  45. package/dist/data.d.ts +119 -3
  46. package/dist/data.js +6 -6
  47. package/dist/devtools.cjs +18 -5
  48. package/dist/devtools.js +5 -5
  49. package/dist/ecosystem.cjs +462 -58
  50. package/dist/ecosystem.d.cts +2 -1
  51. package/dist/ecosystem.d.ts +2 -1
  52. package/dist/ecosystem.js +9 -8
  53. package/dist/extras.cjs +852 -296
  54. package/dist/extras.d.cts +5 -4
  55. package/dist/extras.d.ts +5 -4
  56. package/dist/extras.js +24 -23
  57. package/dist/index.cjs +721 -176
  58. package/dist/index.d.cts +220 -169
  59. package/dist/index.d.ts +220 -169
  60. package/dist/index.js +16 -12
  61. package/dist/motion.cjs +12 -4
  62. package/dist/motion.js +3 -3
  63. package/dist/patterns.cjs +37 -21
  64. package/dist/patterns.d.cts +2 -1
  65. package/dist/patterns.d.ts +2 -1
  66. package/dist/patterns.js +6 -6
  67. package/dist/performance.cjs +48 -6
  68. package/dist/performance.d.cts +12 -2
  69. package/dist/performance.d.ts +12 -2
  70. package/dist/performance.js +8 -6
  71. package/dist/plugins.cjs +672 -261
  72. package/dist/plugins.d.cts +131 -13
  73. package/dist/plugins.d.ts +131 -13
  74. package/dist/plugins.js +83 -47
  75. package/dist/{ssr-XOTUASDO.js → ssr-5OWAH3U2.js} +4 -2
  76. package/dist/{ssr-Bli9XRW5.d.cts → ssr-C8hgIAw7.d.cts} +6 -0
  77. package/dist/{ssr-Bli9XRW5.d.ts → ssr-C8hgIAw7.d.ts} +6 -0
  78. package/dist/ssr.cjs +509 -142
  79. package/dist/ssr.d.cts +55 -5
  80. package/dist/ssr.d.ts +55 -5
  81. package/dist/ssr.js +11 -9
  82. package/dist/{tagFactory-DFstCLQV.d.cts → tagFactory-8qL9LCIx.d.cts} +58 -19
  83. package/dist/{tagFactory-DkaNVUNV.d.ts → tagFactory-BL2fymez.d.ts} +58 -19
  84. package/dist/testing.cjs +17 -4
  85. package/dist/testing.js +4 -4
  86. package/dist/types-CJFViL6Q.d.cts +26 -0
  87. package/dist/types-CJFViL6Q.d.ts +26 -0
  88. package/dist/ui.cjs +635 -254
  89. package/dist/ui.d.cts +3 -2
  90. package/dist/ui.d.ts +3 -2
  91. package/dist/ui.js +9 -8
  92. package/dist/widgets.cjs +22 -14
  93. package/dist/widgets.js +7 -7
  94. package/package.json +8 -5
package/README.md CHANGED
@@ -188,7 +188,7 @@ Accessible `Combobox`, `Tabs`, `Accordion`, `Popover`, `Select`, `Tooltip`, `Fil
188
188
  `machine` (finite state machines), `persist`, `optimistic`, `timeTravel`, `globalStore`; plus `hoc`, `composable`, `componentProps`, and `contracts`.
189
189
 
190
190
  ### `sibujs/plugins` — First-party plugins
191
- **Router** — `createRouter`, `Route`/`Outlet`/`RouterLink`, nested routes, guards (`beforeEach`, `beforeResolve`, `afterEach`), programmatic navigation, `preloadRoute`, memory router, and per-route transitions. **i18n** — `setLocale`, `t`, `Trans`, `registerTranslations`, reactive locale switching. Plus the plugin system (`modular`, `ecosystem`, `versioning`, `startup`).
191
+ **Router** — `createRouter`, `Route`/`Outlet`/`RouterLink`, nested routes, guards (`beforeEach`, `beforeResolve`, `afterEach`), programmatic navigation, `preloadRoute`, memory router, and per-route transitions. **i18n** — `setLocale`, `t`, `translated`, `Trans`, `registerTranslations`, live locale switching for text and attributes. Plus the plugin system (`modular`, `ecosystem`, `versioning`, `startup`).
192
192
 
193
193
  ### `sibujs/ssr` — Server rendering
194
194
  `renderToString`, `renderToReadableStream`, `renderToDocument`, `hydrate`, streaming `Suspense`, `head` management, static site generation, incremental regeneration, route actions/middleware, scroll restoration, service worker & web/wasm workers, and microfrontend helpers.
package/dist/browser.cjs CHANGED
@@ -674,7 +674,7 @@ function forEachSubscriber(signal2, visit) {
674
674
  }
675
675
 
676
676
  // src/reactivity/track.ts
677
- var _runtimeVersion = true ? "4.6.0" : "dev";
677
+ var _runtimeVersion = true ? "4.8.0" : "dev";
678
678
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
679
679
  function resolveReactiveApi() {
680
680
  const g = globalThis;
@@ -780,6 +780,14 @@ var batch = API2.batch;
780
780
  var enqueueBatchedSignal = API2.enqueueBatchedSignal;
781
781
  var isBatching = API2.isBatching;
782
782
 
783
+ // src/core/devtoolsHook.ts
784
+ function emitDevtools(hook, event, payload) {
785
+ try {
786
+ hook.emit(event, payload);
787
+ } catch {
788
+ }
789
+ }
790
+
783
791
  // src/core/signals/signal.ts
784
792
  var _g = globalThis;
785
793
  function signal(initial, options) {
@@ -813,7 +821,7 @@ function signal(initial, options) {
813
821
  state2.__v++;
814
822
  if (DEV) {
815
823
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
816
- if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
824
+ if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
817
825
  }
818
826
  if (!enqueueBatchedSignal(state2)) {
819
827
  notifySubscribers2(state2);
@@ -827,7 +835,7 @@ function signal(initial, options) {
827
835
  state2.value = newValue;
828
836
  state2.__v++;
829
837
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
830
- if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
838
+ if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
831
839
  if (!enqueueBatchedSignal(state2)) {
832
840
  notifySubscribers2(state2);
833
841
  }
@@ -846,7 +854,7 @@ function signal(initial, options) {
846
854
  }
847
855
  if (DEV) {
848
856
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
849
- if (hook) hook.emit("signal:create", { signal: state2, name: debugName, getter: get, initial });
857
+ if (hook) emitDevtools(hook, "signal:create", { signal: state2, name: debugName, getter: get, initial });
850
858
  }
851
859
  return [get, set];
852
860
  }
@@ -1024,12 +1032,17 @@ function effect(effectFn, options) {
1024
1032
  try {
1025
1033
  retrack2(ctx.bodyFn, ctx.subscriber);
1026
1034
  if (ctx.rerunPending) drainReruns(ctx);
1035
+ } catch (err) {
1036
+ ctx.disposed = true;
1037
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
1038
+ cleanup2(ctx.subscriber);
1039
+ throw err;
1027
1040
  } finally {
1028
1041
  ctx.running = false;
1029
1042
  ctx.rerunPending = false;
1030
1043
  }
1031
1044
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1032
- if (hook) hook.emit("effect:create", { effectFn });
1045
+ if (hook) emitDevtools(hook, "effect:create", { effectFn });
1033
1046
  return () => disposeEffect(ctx);
1034
1047
  }
1035
1048
 
@@ -1645,13 +1658,19 @@ function colorScheme() {
1645
1658
  }
1646
1659
 
1647
1660
  // src/browser/format.ts
1661
+ var I18N_STATE = /* @__PURE__ */ Symbol.for("sibujs.i18n.v1");
1662
+ function activeI18nLocale() {
1663
+ const state2 = globalThis[I18N_STATE];
1664
+ if (!state2) return void 0;
1665
+ return state2.getLocale ? state2.getLocale() : state2.locale?.[0]();
1666
+ }
1648
1667
  function formatNumber(value, options) {
1649
1668
  const { locale, ...formatOptions } = options ?? {};
1650
- return new Intl.NumberFormat(locale, formatOptions).format(value);
1669
+ return new Intl.NumberFormat(locale ?? activeI18nLocale(), formatOptions).format(value);
1651
1670
  }
1652
1671
  function formatCurrency(value, currency, options) {
1653
1672
  const { locale, ...formatOptions } = options ?? {};
1654
- return new Intl.NumberFormat(locale, {
1673
+ return new Intl.NumberFormat(locale ?? activeI18nLocale(), {
1655
1674
  ...formatOptions,
1656
1675
  style: "currency",
1657
1676
  currency
@@ -2579,6 +2598,36 @@ function textSelection() {
2579
2598
  };
2580
2599
  }
2581
2600
 
2601
+ // src/utils/sanitize.ts
2602
+ function stripControlChars(value) {
2603
+ return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
2604
+ }
2605
+ var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
2606
+ var OUTER_TRIM = /^[\x00-\x20\x7f-\x9f]+|[\x00-\x20\x7f-\x9f]+$/g;
2607
+ function sanitizeUrl(url) {
2608
+ const probe = stripControlChars(url).trim();
2609
+ if (!probe) return "";
2610
+ const output = url.replace(OUTER_TRIM, "");
2611
+ if (probe.length >= 2 && (probe[0] === "\\" || probe[0] === "/") && (probe[1] === "\\" || probe[1] === "/") && (probe[0] === "\\" || probe[1] === "\\")) {
2612
+ return "";
2613
+ }
2614
+ const lower = probe.toLowerCase();
2615
+ let schemeEnd = -1;
2616
+ for (let i = 0; i < lower.length; i++) {
2617
+ const ch = lower.charCodeAt(i);
2618
+ if (ch === 58) {
2619
+ schemeEnd = i;
2620
+ break;
2621
+ }
2622
+ if (ch === 47 || ch === 63 || ch === 35) break;
2623
+ }
2624
+ if (schemeEnd === -1) return output;
2625
+ const scheme = lower.slice(0, schemeEnd + 1);
2626
+ if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return output;
2627
+ if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
2628
+ return output;
2629
+ }
2630
+
2582
2631
  // src/browser/imageLoader.ts
2583
2632
  function imageLoader(src) {
2584
2633
  const [status, setStatus] = signal("pending");
@@ -2620,6 +2669,11 @@ function imageLoader(src) {
2620
2669
  abandonCurrent();
2621
2670
  resetState();
2622
2671
  if (disposed || token !== startToken) return;
2672
+ const safe = sanitizeUrl(String(url));
2673
+ if (!safe) {
2674
+ setStatus("error");
2675
+ return;
2676
+ }
2623
2677
  const img = new Image();
2624
2678
  current = img;
2625
2679
  currentSettled = false;
@@ -2638,7 +2692,7 @@ function imageLoader(src) {
2638
2692
  currentSettled = true;
2639
2693
  setStatus("error");
2640
2694
  };
2641
- img.src = url;
2695
+ img.src = safe;
2642
2696
  }
2643
2697
  let srcEffectTeardown = null;
2644
2698
  if (typeof src === "function") {
@@ -198,6 +198,18 @@ declare function colorScheme(): {
198
198
  /**
199
199
  * Locale-aware number and currency formatting using Intl.NumberFormat.
200
200
  *
201
+ * LOCALE. An explicit `locale` option always wins. Without one, the active i18n
202
+ * locale is used when the i18n plugin is loaded (`setLocale()` / `getLocale()`),
203
+ * and the runtime's default locale otherwise. The i18n read is reactive, so a
204
+ * formatter called inside a binding re-formats in place when the locale
205
+ * switches:
206
+ *
207
+ * ```ts
208
+ * span(() => formatCurrency(price(), "EUR")); // follows setLocale("es")
209
+ * ```
210
+ *
211
+ * On the server the read is request-scoped, exactly as `getLocale()` is.
212
+ *
201
213
  * @example
202
214
  * ```ts
203
215
  * formatNumber(1234567.89); // "1,234,567.89" (locale-dependent)
@@ -792,6 +804,13 @@ declare function vibrate(pattern: number | number[]): boolean;
792
804
  * Ensures a `<link rel="icon">` exists — creates one if missing, updates
793
805
  * the `href` otherwise.
794
806
  *
807
+ * NOT routed through the canonical URL allowlist, deliberately: `data:` icons
808
+ * are this helper's purpose (see `svgFavicon`), and the allowlist refuses
809
+ * `data:`. That is safe here because an icon link only ever fetches an image —
810
+ * the browser never navigates to, executes or renders it as a document, so no
811
+ * scheme turns this sink into script. Do not copy this exception to any sink
812
+ * that navigates, executes or embeds.
813
+ *
795
814
  * @param url Favicon URL or `data:` URI
796
815
  *
797
816
  * @example
@@ -874,6 +893,10 @@ interface ImageLoaderState {
874
893
  * and its value changes, the previous load is abandoned and a new one
875
894
  * starts.
876
895
  *
896
+ * The URL passes the framework's canonical URL policy first (`http:`,
897
+ * `https:`, relative, …). A refused URL — `javascript:`, `data:`, `blob:`, … —
898
+ * requests nothing and reports `status() === "error"`.
899
+ *
877
900
  * @example
878
901
  * ```ts
879
902
  * const img = imageLoader("/hero.jpg");
package/dist/browser.d.ts CHANGED
@@ -198,6 +198,18 @@ declare function colorScheme(): {
198
198
  /**
199
199
  * Locale-aware number and currency formatting using Intl.NumberFormat.
200
200
  *
201
+ * LOCALE. An explicit `locale` option always wins. Without one, the active i18n
202
+ * locale is used when the i18n plugin is loaded (`setLocale()` / `getLocale()`),
203
+ * and the runtime's default locale otherwise. The i18n read is reactive, so a
204
+ * formatter called inside a binding re-formats in place when the locale
205
+ * switches:
206
+ *
207
+ * ```ts
208
+ * span(() => formatCurrency(price(), "EUR")); // follows setLocale("es")
209
+ * ```
210
+ *
211
+ * On the server the read is request-scoped, exactly as `getLocale()` is.
212
+ *
201
213
  * @example
202
214
  * ```ts
203
215
  * formatNumber(1234567.89); // "1,234,567.89" (locale-dependent)
@@ -792,6 +804,13 @@ declare function vibrate(pattern: number | number[]): boolean;
792
804
  * Ensures a `<link rel="icon">` exists — creates one if missing, updates
793
805
  * the `href` otherwise.
794
806
  *
807
+ * NOT routed through the canonical URL allowlist, deliberately: `data:` icons
808
+ * are this helper's purpose (see `svgFavicon`), and the allowlist refuses
809
+ * `data:`. That is safe here because an icon link only ever fetches an image —
810
+ * the browser never navigates to, executes or renders it as a document, so no
811
+ * scheme turns this sink into script. Do not copy this exception to any sink
812
+ * that navigates, executes or embeds.
813
+ *
795
814
  * @param url Favicon URL or `data:` URI
796
815
  *
797
816
  * @example
@@ -874,6 +893,10 @@ interface ImageLoaderState {
874
893
  * and its value changes, the previous load is abandoned and a new one
875
894
  * starts.
876
895
  *
896
+ * The URL passes the framework's canonical URL policy first (`http:`,
897
+ * `https:`, relative, …). A refused URL — `javascript:`, `data:`, `blob:`, … —
898
+ * requests nothing and reports `status() === "error"`.
899
+ *
877
900
  * @example
878
901
  * ```ts
879
902
  * const img = imageLoader("/hero.jpg");
package/dist/browser.js CHANGED
@@ -36,14 +36,15 @@ import {
36
36
  visibility,
37
37
  wakeLock,
38
38
  windowSize
39
- } from "./chunk-OXUY2A6L.js";
40
- import "./chunk-H3SRKIYX.js";
39
+ } from "./chunk-EGUQLBHE.js";
41
40
  import "./chunk-52XFPGSN.js";
41
+ import "./chunk-62BDYGAG.js";
42
42
  import "./chunk-7ZHH77QA.js";
43
- import "./chunk-XC4MEKGA.js";
43
+ import "./chunk-V3LHZSU5.js";
44
+ import "./chunk-EXXSN3BW.js";
44
45
  import "./chunk-7XHATCIH.js";
45
- import "./chunk-D33YTSX5.js";
46
- import "./chunk-5Q4R7HCL.js";
46
+ import "./chunk-DSID757X.js";
47
+ import "./chunk-TQQUN4WR.js";
47
48
  import "./chunk-NYNYSPK7.js";
48
49
  export {
49
50
  __resetSpeechCoordinator,