@voltro/web 0.27.0 → 0.29.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.
package/dist/index.d.ts CHANGED
@@ -135,6 +135,12 @@ export declare interface BrowserConsoleBridgeOptions {
135
135
  readonly flushAfterMs?: number;
136
136
  }
137
137
 
138
+ /** Absolute canonical URL for a page. Relative paths are also valid in a
139
+ * `<link rel="canonical">` (crawlers resolve them against the document base),
140
+ * but an absolute one is unambiguous across environments — pass the production
141
+ * `siteUrl` and the page's root-relative `path`. */
142
+ export declare const canonicalUrl: (siteUrl: string, path: string) => string;
143
+
138
144
  /**
139
145
  * Structured result of running a route's loaders: the page (leaf) loader's
140
146
  * data plus each chain segment's loader data, keyed by segment index.
@@ -425,6 +431,10 @@ export declare const isNotFound: (e: unknown) => e is NotFoundError;
425
431
  /** Brand guard — true for any `RedirectError`, even cross-bundle. */
426
432
  export declare const isRedirect: (e: unknown) => e is RedirectError;
427
433
 
434
+ /** Join an origin (`https://example.com`, optionally with a trailing slash) to a
435
+ * root-relative path, collapsing the slash seam so exactly one separates them. */
436
+ export declare const joinUrl: (siteUrl: string, path: string) => string;
437
+
428
438
  /** Lazy variant of `pageRoute`: takes a thunk that dynamically imports the page
429
439
  * instead of an already-imported module. The chunk loads only when the route
430
440
  * first matches — the initial bundle no longer pulls in every page. */
@@ -560,6 +570,11 @@ declare type LoaderEntry<T = unknown> = {
560
570
 
561
571
  export declare type LoaderFn<T = unknown> = (ctx: LoaderContext) => Promise<T> | T;
562
572
 
573
+ /** The URL path a logical page takes for a given locale under URL-prefix
574
+ * routing: the default locale keeps the bare path, every other locale gets a
575
+ * `/<locale>` prefix. `/about` @ `de` → `/de/about`; @ the default → `/about`. */
576
+ export declare const localizedPath: (path: string, locale: string, defaultLocale: string) => string;
577
+
563
578
  export declare const matchRoute: (compiled: ReadonlyArray<CompiledRoute>, pathname: string) => RouteMatch | null;
564
579
 
565
580
  /**
@@ -628,6 +643,12 @@ export declare interface NavigateOptions {
628
643
 
629
644
  export declare const NavigationIndicator: () => ReactNode;
630
645
 
646
+ /* Excluded from this release type: NO_LOADER_DATA */
647
+
648
+ /** Strip a trailing slash from a path, except the root, and guarantee a leading
649
+ * slash. `''` and `'/'` both normalise to `'/'`. */
650
+ export declare const normalizePath: (path: string) => string;
651
+
631
652
  /** Construct-and-throw sugar for `NotFoundError`. Typed `: never` so
632
653
  * control-flow narrows at the call site (`const x = row ?? notFound()`). */
633
654
  export declare const notFound: (detail?: string) => never;
@@ -737,6 +758,11 @@ export declare interface PageMeta {
737
758
  * JSON-serialisable is accepted; `@context` + `@type` are
738
759
  * authored, not synthesised. */
739
760
  readonly jsonLd?: ReadonlyArray<Record<string, unknown>>;
761
+ /** Keep this page out of the index. Emits
762
+ * `<meta name="robots" content="noindex, nofollow">`, and the build's
763
+ * `sitemap.xml` generator EXCLUDES the route. Use for utility pages
764
+ * (checkout steps, previews, thank-you pages) that should not rank. */
765
+ readonly noIndex?: boolean;
740
766
  }
741
767
 
742
768
  export declare const pageRoute: (pattern: string, mod: Record<string, unknown>, extras?: {
@@ -991,6 +1017,56 @@ export declare type SearchParamsInit = URLSearchParams | Readonly<Record<string,
991
1017
  */
992
1018
  export declare const segmentLoaderKey: (pattern: string, index: number, params: Readonly<Record<string, string>>) => string;
993
1019
 
1020
+ /**
1021
+ * Compute the canonical URL + the full set of `hreflang` alternates for a
1022
+ * localized page. Spread the result straight into a `PageMeta`:
1023
+ *
1024
+ * export const meta = ({ locale }) => ({
1025
+ * title: t('about.title'),
1026
+ * ...seoAlternates({
1027
+ * siteUrl: 'https://example.com', path: '/about',
1028
+ * locale, locales: ['en', 'de'], defaultLocale: 'en',
1029
+ * }),
1030
+ * })
1031
+ *
1032
+ * `canonical` is the current locale's absolute URL; `links` carries one
1033
+ * `rel="alternate"` per locale (each an ABSOLUTE URL — Google ignores relative
1034
+ * hreflang hrefs) plus the `x-default`. Every page in a locale set should point
1035
+ * its alternates at the SAME set of URLs, including a self-referential one, per
1036
+ * Google's reciprocity rule — which is exactly what iterating `locales` here
1037
+ * produces.
1038
+ */
1039
+ export declare const seoAlternates: (input: SeoAlternatesInput) => {
1040
+ readonly canonical: string;
1041
+ readonly links: ReadonlyArray<SeoLink>;
1042
+ };
1043
+
1044
+ export declare interface SeoAlternatesInput {
1045
+ /** Production origin, e.g. `'https://voltro.dev'`. Absolute URLs are required
1046
+ * for `hreflang` alternates to be valid, so this is not optional. */
1047
+ readonly siteUrl: string;
1048
+ /** The page's LOGICAL path WITHOUT any locale prefix — the path as the default
1049
+ * locale serves it (`/plugins/foo`, `/about`, `/`). The current locale's
1050
+ * prefix is applied by this function, not by the caller. */
1051
+ readonly path: string;
1052
+ /** The locale THIS render is for — drives which URL is `canonical`. */
1053
+ readonly locale: string;
1054
+ /** Every locale the site publishes this page under. */
1055
+ readonly locales: ReadonlyArray<string>;
1056
+ /** The locale served at the bare (un-prefixed) path. */
1057
+ readonly defaultLocale: string;
1058
+ /** Emit an `hreflang="x-default"` alternate pointing at the default-locale URL
1059
+ * (the recommended fallback for an unmatched language). Default `true`. */
1060
+ readonly xDefault?: boolean;
1061
+ }
1062
+
1063
+ /** A `<link>` descriptor, structurally the entries `PageMeta.links` accepts. */
1064
+ export declare interface SeoLink {
1065
+ readonly rel: string;
1066
+ readonly href: string;
1067
+ readonly hreflang?: string;
1068
+ }
1069
+
994
1070
  export declare interface ServerLogRelay {
995
1071
  readonly dispose: () => void;
996
1072
  }
@@ -1142,6 +1218,23 @@ export declare const useLocation: () => string;
1142
1218
 
1143
1219
  export declare const useNavigate: () => RouterContextValue["navigate"];
1144
1220
 
1221
+ /**
1222
+ * `useLoaderData()` for a component that may render at a level with no
1223
+ * `loader` — returns `undefined` there instead of throwing.
1224
+ *
1225
+ * This exists for ONE case, and it is worth stating so it is not reached for
1226
+ * casually: a component genuinely shared between routes that declare a loader
1227
+ * and routes that do not. On a page that declares its own `loader`, the router
1228
+ * never renders it without its data, so reaching for the optional read there
1229
+ * only hides a real mistake behind a `?.`.
1230
+ *
1231
+ * Note what it does NOT mean: an empty RESULT is a value, not an absence. A
1232
+ * loader returning `{ items: [] }` returns exactly that through both hooks —
1233
+ * `undefined` here says "there is no loader at this level", never "the query
1234
+ * found nothing".
1235
+ */
1236
+ export declare const useOptionalLoaderData: <T>() => LoaderData<T> | undefined;
1237
+
1145
1238
  export declare const useParams: <T extends Record<string, string> = Record<string, string>>() => T;
1146
1239
 
1147
1240
  /** Imperatively pre-warm a route's loader. No-op if the route has no loader. */
package/dist/index.js CHANGED
@@ -2,28 +2,28 @@ import { t as e } from "./globalContext-d4A-ugDg.js";
2
2
  import { AppClientsContext as t, useAppClient as n } from "./hooks.js";
3
3
  import { a as r, c as i, i as a, l as o, o as s, r as c, s as l, u } from "./frameworkBoot-DHdoAwd9.js";
4
4
  import { a as d, c as f, i as p, l as m, o as h, s as g } from "./defaultFallbacks-Fik_Gcjh.js";
5
- import { i as _, n as ee, r as te, t as ne } from "./mount-DfyG67bY.js";
6
- import { c as re, d as ie, h as ae, l as oe, p as se, u as ce } from "./routerState-DDDBYFrI.js";
7
- import { A as le, B as ue, C as de, D as fe, E as pe, F as me, H as v, I as y, L as b, M as x, N as S, O as C, P as w, R as T, S as E, T as D, U as O, V as k, W as A, _ as j, a as M, b as N, c as P, d as F, f as I, g as L, h as R, i as z, j as he, k as ge, l as _e, m as ve, n as ye, o as be, p as xe, r as Se, s as Ce, t as we, u as Te, v as Ee, w as De, x as Oe, y as ke, z as Ae } from "./serverContext-BASpdhXG.js";
8
- import { Component as je, Suspense as Me, createElement as B, use as Ne, useCallback as Pe, useContext as Fe, useSyncExternalStore as Ie } from "react";
9
- import { Fragment as V, jsx as H, jsxs as U } from "react/jsx-runtime";
5
+ import { i as _, n as ee, r as te, t as ne } from "./mount-B9DPjlEf.js";
6
+ import { c as re, d as ie, h as ae, l as oe, p as se, u as ce } from "./routerState-DAT472IC.js";
7
+ import { A as le, B as ue, C as de, D as fe, E as pe, F as me, G as he, H as ge, I as _e, K as v, L as y, M as b, N as x, O as S, P as C, R as w, S as T, T as E, U as D, V as O, W as k, _ as A, a as j, b as M, c as N, d as P, f as F, g as I, h as ve, i as ye, j as be, k as xe, l as Se, m as Ce, n as we, o as Te, p as Ee, r as De, s as Oe, t as ke, u as L, v as Ae, w as je, x as Me, y as Ne, z as Pe } from "./serverContext-B1Pivair.js";
8
+ import { Component as Fe, Suspense as Ie, createElement as R, use as Le, useCallback as Re, useContext as ze, useSyncExternalStore as Be } from "react";
9
+ import { Fragment as z, jsx as B, jsxs as V } from "react/jsx-runtime";
10
10
  export * from "@voltro/client";
11
11
  export * from "@voltro/ui";
12
12
  //#region src/await.tsx
13
- var Le = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PURE__ */ H(Me, {
13
+ var Ve = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PURE__ */ B(Ie, {
14
14
  fallback: t,
15
- children: /* @__PURE__ */ H(ze, {
15
+ children: /* @__PURE__ */ B(Ue, {
16
16
  errorFallback: r,
17
- children: /* @__PURE__ */ H(Re, {
17
+ children: /* @__PURE__ */ B(He, {
18
18
  value: e,
19
19
  errorFallback: r ?? null,
20
20
  children: n
21
21
  })
22
22
  })
23
- }), W = ({ body: e }) => /* @__PURE__ */ H("script", { dangerouslySetInnerHTML: { __html: e } }), Re = ({ value: e, errorFallback: t, children: n }) => {
24
- let r = Ne(e), i = ce(e), a = ae(r);
25
- return a === void 0 ? /* @__PURE__ */ U(V, { children: [i === void 0 ? null : /* @__PURE__ */ H(W, { body: ie(i, r) }), n(r)] }) : /* @__PURE__ */ U(V, { children: [i === void 0 ? null : /* @__PURE__ */ H(W, { body: oe(i, a) }), t] });
26
- }, ze = class extends je {
23
+ }), H = ({ body: e }) => /* @__PURE__ */ B("script", { dangerouslySetInnerHTML: { __html: e } }), He = ({ value: e, errorFallback: t, children: n }) => {
24
+ let r = Le(e), i = ce(e), a = ae(r);
25
+ return a === void 0 ? /* @__PURE__ */ V(z, { children: [i === void 0 ? null : /* @__PURE__ */ B(H, { body: ie(i, r) }), n(r)] }) : /* @__PURE__ */ V(z, { children: [i === void 0 ? null : /* @__PURE__ */ B(H, { body: oe(i, a) }), t] });
26
+ }, Ue = class extends Fe {
27
27
  state = { error: void 0 };
28
28
  static getDerivedStateFromError(e) {
29
29
  return { error: e };
@@ -31,7 +31,7 @@ var Le = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
31
31
  render() {
32
32
  return this.state.error === void 0 ? this.props.children : this.props.errorFallback ?? null;
33
33
  }
34
- }, G = ({ src: e }) => e, K = e("imageConfig", { loader: G }), Be = ({ loader: e, children: t }) => B(K.Provider, { value: { loader: e } }, t), q = [
34
+ }, U = ({ src: e }) => e, W = e("imageConfig", { loader: U }), We = ({ loader: e, children: t }) => R(W.Provider, { value: { loader: e } }, t), G = [
35
35
  640,
36
36
  750,
37
37
  828,
@@ -40,8 +40,8 @@ var Le = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
40
40
  1920,
41
41
  2048,
42
42
  3840
43
- ], Ve = (e, t, n, r) => {
44
- let i = n !== void 0 && !r ? Array.from(new Set(q.filter((e) => e <= n * 2).concat(n))).sort((e, t) => e - t) : [...q];
43
+ ], Ge = (e, t, n, r) => {
44
+ let i = n !== void 0 && !r ? Array.from(new Set(G.filter((e) => e <= n * 2).concat(n))).sort((e, t) => e - t) : [...G];
45
45
  return {
46
46
  srcSet: i.map((n) => `${e({
47
47
  src: t,
@@ -52,10 +52,10 @@ var Le = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
52
52
  width: i[i.length - 1]
53
53
  })
54
54
  };
55
- }, He = ({ src: e, alt: t, width: n, height: r, fill: i = !1, sizes: a, priority: o = !1, loader: s, placeholder: c = "empty", blurDataURL: l, style: u, ...d }) => {
56
- let f = Fe(K).loader, p = s ?? f;
55
+ }, Ke = ({ src: e, alt: t, width: n, height: r, fill: i = !1, sizes: a, priority: o = !1, loader: s, placeholder: c = "empty", blurDataURL: l, style: u, ...d }) => {
56
+ let f = ze(W).loader, p = s ?? f;
57
57
  !i && (n === void 0 || r === void 0) && typeof console < "u" && console.warn(`<Image src="${e}"> needs both width and height (or fill) to reserve layout space and avoid CLS.`);
58
- let { srcSet: m, fallback: h } = Ve(p, e, n, i), g = c === "blur" && l ? {
58
+ let { srcSet: m, fallback: h } = Ge(p, e, n, i), g = c === "blur" && l ? {
59
59
  backgroundImage: `url(${l})`,
60
60
  backgroundSize: "cover",
61
61
  backgroundPosition: "center"
@@ -66,7 +66,7 @@ var Le = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
66
66
  width: "100%",
67
67
  objectFit: "cover"
68
68
  } : {};
69
- return B("img", {
69
+ return R("img", {
70
70
  src: h,
71
71
  srcSet: m,
72
72
  sizes: a ?? (i ? "100vw" : void 0),
@@ -85,10 +85,10 @@ var Le = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
85
85
  },
86
86
  ...d
87
87
  });
88
- }, Ue = ({ to: e, children: t, className: n }) => B("a", {
88
+ }, qe = ({ to: e, children: t, className: n }) => R("a", {
89
89
  href: e,
90
90
  className: n
91
- }, t), We = {
91
+ }, t), Je = {
92
92
  position: "sticky",
93
93
  top: 0,
94
94
  zIndex: 10,
@@ -99,13 +99,13 @@ var Le = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
99
99
  padding: "1rem 1.5rem",
100
100
  borderBottom: "1px solid var(--voltro-blog-border, rgba(127,127,127,0.2))",
101
101
  backdropFilter: "blur(8px)"
102
- }, Ge = {
102
+ }, Ye = {
103
103
  maxWidth: "48rem",
104
104
  margin: "0 auto",
105
105
  padding: "2rem 1.5rem",
106
106
  width: "100%"
107
- }, Ke = (e) => {
108
- let { brand: t, topNav: n, children: r, pathname: i, footer: a, breadcrumbs: o, headerRight: s } = e, c = e.Link ?? Ue, l = B("nav", {
107
+ }, Xe = (e) => {
108
+ let { brand: t, topNav: n, children: r, pathname: i, footer: a, breadcrumbs: o, headerRight: s } = e, c = e.Link ?? qe, l = R("nav", {
109
109
  className: "voltro-blog-nav",
110
110
  style: {
111
111
  display: "flex",
@@ -114,20 +114,20 @@ var Le = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
114
114
  }
115
115
  }, ...n.map((e) => {
116
116
  let t = i === e.href;
117
- return B(c, {
117
+ return R(c, {
118
118
  key: e.href,
119
119
  to: e.href,
120
120
  className: t ? "voltro-blog-nav-link is-active" : "voltro-blog-nav-link",
121
121
  children: e.label
122
122
  });
123
- })), u = B("header", {
123
+ })), u = R("header", {
124
124
  className: "voltro-blog-header",
125
- style: We
126
- }, B("div", { className: "voltro-blog-brand" }, t), s ? B("div", { style: {
125
+ style: Je
126
+ }, R("div", { className: "voltro-blog-brand" }, t), s ? R("div", { style: {
127
127
  display: "flex",
128
128
  gap: "1rem",
129
129
  alignItems: "center"
130
- } }, l, s) : l), d = o && o.length > 0 ? B("nav", {
130
+ } }, l, s) : l), d = o && o.length > 0 ? R("nav", {
131
131
  className: "voltro-blog-breadcrumbs",
132
132
  "aria-label": "Breadcrumb",
133
133
  style: {
@@ -138,20 +138,20 @@ var Le = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
138
138
  gap: "0.5rem"
139
139
  }
140
140
  }, ...o.flatMap((e, t) => {
141
- let n = t === o.length - 1, r = e.href && !n ? B(c, {
141
+ let n = t === o.length - 1, r = e.href && !n ? R(c, {
142
142
  key: `c${t}`,
143
143
  to: e.href,
144
144
  children: e.label
145
- }) : B("span", {
145
+ }) : R("span", {
146
146
  key: `c${t}`,
147
147
  "aria-current": n ? "page" : void 0
148
148
  }, e.label);
149
- return n ? [r] : [r, B("span", { key: `s${t}` }, "/")];
149
+ return n ? [r] : [r, R("span", { key: `s${t}` }, "/")];
150
150
  })) : null;
151
- return B("div", { className: "voltro-blog-layout" }, u, B("main", {
151
+ return R("div", { className: "voltro-blog-layout" }, u, R("main", {
152
152
  className: "voltro-blog-main",
153
- style: Ge
154
- }, d, r), a ? B("footer", {
153
+ style: Ye
154
+ }, d, r), a ? R("footer", {
155
155
  className: "voltro-blog-footer",
156
156
  style: {
157
157
  maxWidth: "48rem",
@@ -160,7 +160,31 @@ var Le = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
160
160
  borderTop: "1px solid var(--voltro-blog-border, rgba(127,127,127,0.2))"
161
161
  }
162
162
  }, a) : null);
163
- }, J = "voltro:theme", qe = 31536e3, Je = () => {
163
+ }, K = (e) => {
164
+ if (e === "" || e === "/") return "/";
165
+ let t = e.startsWith("/") ? e : `/${e}`;
166
+ return t.endsWith("/") ? t.slice(0, -1) : t;
167
+ }, q = (e, t) => {
168
+ let n = e.endsWith("/") ? e.slice(0, -1) : e, r = K(t);
169
+ return r === "/" ? `${n}/` : `${n}${r}`;
170
+ }, J = (e, t, n) => {
171
+ let r = K(e);
172
+ return t === n ? r : r === "/" ? `/${t}` : `/${t}${r}`;
173
+ }, Ze = (e, t) => q(e, t), Qe = (e) => {
174
+ let { siteUrl: t, path: n, locale: r, locales: i, defaultLocale: a, xDefault: o = !0 } = e, s = q(t, J(n, r, a)), c = i.map((e) => ({
175
+ rel: "alternate",
176
+ hreflang: e,
177
+ href: q(t, J(n, e, a))
178
+ }));
179
+ return o && c.push({
180
+ rel: "alternate",
181
+ hreflang: "x-default",
182
+ href: q(t, J(n, a, a))
183
+ }), {
184
+ canonical: s,
185
+ links: c
186
+ };
187
+ }, Y = "voltro:theme", $e = 31536e3, et = () => {
164
188
  if (typeof document > "u") return "system";
165
189
  try {
166
190
  let e = document.cookie.match(/(?:^|;\s*)voltro:theme=([^;]*)/), t = e?.[1] === void 0 ? "" : decodeURIComponent(e[1]);
@@ -168,17 +192,17 @@ var Le = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
168
192
  } catch {
169
193
  return "system";
170
194
  }
171
- }, Y = () => {
195
+ }, tt = () => {
172
196
  if (typeof window > "u" || !window.matchMedia) return !1;
173
197
  try {
174
198
  return window.matchMedia("(prefers-color-scheme: dark)").matches;
175
199
  } catch {
176
200
  return !1;
177
201
  }
178
- }, X = (e) => e === "system" ? Y() ? "dark" : "light" : e, Z = 0, Q = /* @__PURE__ */ new Set(), $ = () => {
202
+ }, X = (e) => e === "system" ? tt() ? "dark" : "light" : e, Z = 0, Q = /* @__PURE__ */ new Set(), $ = () => {
179
203
  Z++;
180
204
  for (let e of Q) e();
181
- }, Ye = (e) => {
205
+ }, nt = (e) => {
182
206
  Q.add(e);
183
207
  let t, n = () => $();
184
208
  if (typeof window < "u" && window.matchMedia) try {
@@ -190,21 +214,21 @@ var Le = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
190
214
  t?.removeEventListener("change", n);
191
215
  } catch {}
192
216
  };
193
- }, Xe = () => {
194
- let e = Je();
217
+ }, rt = () => {
218
+ let e = et();
195
219
  return `${Z}:${e}:${X(e)}`;
196
- }, Ze = () => "0:system:light", Qe = () => {
197
- let [, e, t] = Ie(Ye, Xe, Ze).split(":");
220
+ }, it = () => "0:system:light", at = () => {
221
+ let [, e, t] = Be(nt, rt, it).split(":");
198
222
  return {
199
223
  theme: e,
200
224
  resolvedTheme: t,
201
- setTheme: Pe((e) => {
225
+ setTheme: Re((e) => {
202
226
  if (typeof document < "u") try {
203
- document.cookie = e === "system" ? `${J}=; path=/; max-age=0; SameSite=Lax` : `${J}=${e}; path=/; max-age=${qe}; SameSite=Lax`, document.documentElement.classList.toggle("dark", X(e) === "dark");
227
+ document.cookie = e === "system" ? `${Y}=; path=/; max-age=0; SameSite=Lax` : `${Y}=${e}; path=/; max-age=${$e}; SameSite=Lax`, document.documentElement.classList.toggle("dark", X(e) === "dark");
204
228
  } catch {}
205
229
  $();
206
230
  }, [])
207
231
  };
208
- }, $e = "framework-web";
232
+ }, ot = "framework-web";
209
233
  //#endregion
210
- export { t as AppClientsContext, Le as Await, Ke as BlogLayout, p as FallbackStringsProvider, He as Image, Be as ImageConfigProvider, be as Link, Ce as LoaderCache, P as LoaderDataContext, i as NavigationIndicator, y as NotFoundError, _e as PAGE_SLOT_ATTR, Te as PageSlot, F as PlainLink, I as RENDER_MODES, o as ReconnectContext, b as RedirectError, xe as Router, ve as RouterContext, we as ServerRequestContext, ye as ServerRequestProvider, J as THEME_COOKIE, $e as WEB_NAME, R as compileRoute, d as defaultFallbackStrings, re as defer, L as externalUrl, j as findNotFound, c as formatPrintf, ee as getIslandComponent, v as getRouteSnapshot, g as getStatuses, te as hydrateIslandsOnPage, a as installBrowserConsoleBridge, r as installServerLogRelay, se as isDeferredLoaderResult, T as isNotFound, Ae as isRedirect, _ as island, Ee as lazyPageRoute, ke as loaderCacheKey, N as matchRoute, ne as mount, ue as notFound, Oe as pageRoute, Se as parseCookieHeader, G as passthroughImageLoader, E as preloadRouteModule, f as pushStatus, k as redirect, s as registerClientTrace, de as resolveAnchorNavigation, De as resolveMeta, D as segmentLoaderKey, O as setRouteSnapshot, pe as sortRoutesByPriority, A as subscribeRouteSnapshot, m as subscribeStatuses, l as subscribeTraceErrors, n as useAppClient, fe as useBlocker, h as useFallbackStrings, C as useLoaderData, ge as useLocation, le as useNavigate, he as useParams, x as usePrefetch, u as useReconnect, z as useSearchParams, M as useServerRequest, S as useSetSearchParams, Qe as useTheme, w as withHash, me as withQuery };
234
+ export { t as AppClientsContext, Ve as Await, Xe as BlogLayout, p as FallbackStringsProvider, Ke as Image, We as ImageConfigProvider, Te as Link, Oe as LoaderCache, N as LoaderDataContext, Se as NO_LOADER_DATA, i as NavigationIndicator, w as NotFoundError, L as PAGE_SLOT_ATTR, P as PageSlot, F as PlainLink, Ee as RENDER_MODES, o as ReconnectContext, Pe as RedirectError, Ce as Router, ve as RouterContext, ke as ServerRequestContext, we as ServerRequestProvider, Y as THEME_COOKIE, ot as WEB_NAME, Ze as canonicalUrl, I as compileRoute, d as defaultFallbackStrings, re as defer, A as externalUrl, Ae as findNotFound, c as formatPrintf, ee as getIslandComponent, k as getRouteSnapshot, g as getStatuses, te as hydrateIslandsOnPage, a as installBrowserConsoleBridge, r as installServerLogRelay, se as isDeferredLoaderResult, ue as isNotFound, O as isRedirect, _ as island, q as joinUrl, Ne as lazyPageRoute, M as loaderCacheKey, J as localizedPath, Me as matchRoute, ne as mount, K as normalizePath, ge as notFound, T as pageRoute, De as parseCookieHeader, U as passthroughImageLoader, de as preloadRouteModule, f as pushStatus, D as redirect, s as registerClientTrace, je as resolveAnchorNavigation, E as resolveMeta, pe as segmentLoaderKey, Qe as seoAlternates, he as setRouteSnapshot, fe as sortRoutesByPriority, v as subscribeRouteSnapshot, m as subscribeStatuses, l as subscribeTraceErrors, n as useAppClient, S as useBlocker, h as useFallbackStrings, xe as useLoaderData, le as useLocation, be as useNavigate, b as useOptionalLoaderData, x as useParams, C as usePrefetch, u as useReconnect, ye as useSearchParams, j as useServerRequest, me as useSetSearchParams, at as useTheme, _e as withHash, y as withQuery };
@@ -1,35 +1,35 @@
1
1
  import { t as e } from "./frameworkBoot-DHdoAwd9.js";
2
- import { o as t, r as n, t as r } from "./routerState-DDDBYFrI.js";
2
+ import { o as t, r as n, t as r } from "./routerState-DAT472IC.js";
3
3
  import { StrictMode as i, createElement as a } from "react";
4
4
  import { createRoot as o, hydrateRoot as s } from "react-dom/client";
5
- import { applyStoreSeeds as c } from "@voltro/client";
6
- import { jsx as l } from "react/jsx-runtime";
5
+ import { applyPreloadSeeds as c, applyStoreSeeds as l } from "@voltro/client";
6
+ import { jsx as u } from "react/jsx-runtime";
7
7
  //#region src/islands.tsx
8
- var u = /* @__PURE__ */ new Map(), d = (e, t) => {
9
- u.set(t.name, e);
8
+ var d = /* @__PURE__ */ new Map(), f = (e, t) => {
9
+ d.set(t.name, e);
10
10
  let n = t.hydrate ?? "visible", r = (r) => a("div", {
11
11
  "data-voltro-island": "",
12
12
  "data-island-name": t.name,
13
13
  "data-island-hydrate": n,
14
- "data-island-props": p(r)
14
+ "data-island-props": m(r)
15
15
  }, a(e, r));
16
16
  return r.displayName = `Island(${t.name})`, r;
17
- }, f = (e) => u.get(e), p = (e) => JSON.stringify(e ?? {}).replace(/</g, "\\u003c"), m = (e) => {
17
+ }, p = (e) => d.get(e), m = (e) => JSON.stringify(e ?? {}).replace(/</g, "\\u003c"), h = (e) => {
18
18
  if (!e) return {};
19
19
  try {
20
20
  return JSON.parse(e);
21
21
  } catch {
22
22
  return {};
23
23
  }
24
- }, h = () => {
24
+ }, g = () => {
25
25
  let e = document.querySelectorAll("[data-voltro-island]:not([data-voltro-hydrated])");
26
26
  for (let t of e) {
27
- let e = t.dataset.islandName ?? "", n = u.get(e);
27
+ let e = t.dataset.islandName ?? "", n = d.get(e);
28
28
  if (!n) {
29
29
  console.warn(`[voltro] island "${e}" referenced in DOM but not registered. Did the island file get imported in this bundle?`);
30
30
  continue;
31
31
  }
32
- let r = m(t.dataset.islandProps ?? null), i = t.dataset.islandHydrate ?? "visible";
32
+ let r = h(t.dataset.islandProps ?? null), i = t.dataset.islandHydrate ?? "visible";
33
33
  t.setAttribute("data-voltro-hydrated", "pending");
34
34
  let o = () => {
35
35
  t.getAttribute("data-voltro-hydrated") !== "done" && (t.setAttribute("data-voltro-hydrated", "done"), s(t, a(n, r)));
@@ -50,28 +50,28 @@ var u = /* @__PURE__ */ new Map(), d = (e, t) => {
50
50
  t.addEventListener("pointerdown", e, { passive: !0 }), t.addEventListener("keydown", e);
51
51
  }
52
52
  }
53
- }, g = (e) => `${window.location.protocol === "https:" ? "wss:" : "ws:"}//${window.location.host}/ws/${e}`, _ = (a, u) => {
54
- let d = document.getElementById(u.rootId ?? "root");
55
- if (!d) throw Error(`@voltro/web: no #${u.rootId ?? "root"} element in the document`);
56
- let f = Object.entries(u.apis).map(([e, t]) => ({
53
+ }, _ = (e) => `${window.location.protocol === "https:" ? "wss:" : "ws:"}//${window.location.host}/ws/${e}`, v = (a, d) => {
54
+ let f = document.getElementById(d.rootId ?? "root");
55
+ if (!f) throw Error(`@voltro/web: no #${d.rootId ?? "root"} element in the document`);
56
+ let p = Object.entries(d.apis).map(([e, t]) => ({
57
57
  name: e,
58
58
  group: t.group,
59
59
  descriptors: t.descriptors ?? {},
60
- wsUrl: t.wsUrl ?? g(e),
60
+ wsUrl: t.wsUrl ?? _(e),
61
61
  headers: t.headers
62
- })), p = n(document.getElementById(r)?.textContent, window.location.pathname), m = p !== null && d.children.length > 0, _ = document.querySelector("meta[name=\"voltro-interactive\"]")?.getAttribute("content") ?? "full";
63
- if (_ === "none") return;
64
- if (_ === "islands") {
65
- h();
62
+ })), m = n(document.getElementById(r)?.textContent, window.location.pathname), h = m !== null && f.children.length > 0, v = document.querySelector("meta[name=\"voltro-interactive\"]")?.getAttribute("content") ?? "full";
63
+ if (v === "none") return;
64
+ if (v === "islands") {
65
+ g();
66
66
  return;
67
67
  }
68
- m && t(p), c(p?.storeSeeds);
69
- let v = /* @__PURE__ */ l(i, { children: /* @__PURE__ */ l(e, {
68
+ h && t(m), l(m?.storeSeeds), c(m?.preloadSeeds);
69
+ let y = /* @__PURE__ */ u(i, { children: /* @__PURE__ */ u(e, {
70
70
  App: a,
71
- apis: f,
72
- ...u.Devtools ? { Devtools: u.Devtools } : {}
71
+ apis: p,
72
+ ...d.Devtools ? { Devtools: d.Devtools } : {}
73
73
  }) });
74
- m ? s(d, v) : o(d).render(v);
74
+ h ? s(f, y) : o(f).render(y);
75
75
  };
76
76
  //#endregion
77
- export { d as i, f as n, h as r, _ as t };
77
+ export { f as i, p as n, g as r, v as t };
package/dist/mount.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as e } from "./mount-DfyG67bY.js";
1
+ import { t as e } from "./mount-B9DPjlEf.js";
2
2
  export { e as mount };
@@ -69,6 +69,7 @@ var e = /* @__PURE__ */ RegExp("\\u2028", "g"), t = /* @__PURE__ */ RegExp("\\u2
69
69
  },
70
70
  ...e.pageClientOnly ? { pageClientOnly: !0 } : {},
71
71
  ...e.storeSeeds !== void 0 && e.storeSeeds.length > 0 ? { storeSeeds: e.storeSeeds } : {},
72
+ ...e.preloadSeeds !== void 0 && e.preloadSeeds.length > 0 ? { preloadSeeds: e.preloadSeeds } : {},
72
73
  ...n || r ? { deferred: {
73
74
  ...n ? { page: e.deferredPageIds } : {},
74
75
  ...r ? { segments: e.deferredSegmentIds } : {}
@@ -99,7 +100,8 @@ var e = /* @__PURE__ */ RegExp("\\u2028", "g"), t = /* @__PURE__ */ RegExp("\\u2
99
100
  segments: a.size > 0 ? a : T,
100
101
  pageClientOnly: r.pageClientOnly === !0,
101
102
  pathname: t,
102
- storeSeeds: Array.isArray(r.storeSeeds) ? r.storeSeeds : []
103
+ storeSeeds: Array.isArray(r.storeSeeds) ? r.storeSeeds : [],
104
+ preloadSeeds: Array.isArray(r.preloadSeeds) ? r.preloadSeeds : []
103
105
  };
104
106
  }, O = (e, t) => {
105
107
  if (!t) return e;