@voltro/web 0.8.0 → 0.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.
- package/CHANGELOG.md +19 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +34 -34
- package/dist/{mount-D3k8Ozdm.js → mount-Gsn3ouYx.js} +1 -1
- package/dist/mount.js +1 -1
- package/dist/{routerState-ga64vk2B.js → routerState-DpUqogK8.js} +2 -0
- package/dist/{serverContext-BW0GF8fv.js → serverContext-COzippNt.js} +103 -98
- package/dist/ssr.d.ts +21 -0
- package/dist/ssr.js +32 -32
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -39,6 +39,25 @@ _Changes staged for the next release accumulate here (rolled up from
|
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
|
|
42
|
+
## [0.9.0] — 2026-07-21
|
|
43
|
+
|
|
44
|
+
### ⚠ BREAKING
|
|
45
|
+
|
|
46
|
+
- **@voltro/web, @voltro/cli** — A `renderMode: 'spa'` page whose route has an SSR layout chain now renders that LAYOUT on the server — an SSR shell — instead of rendering nothing server-side. This decouples layout SSR from page render mode: the layout (nav shell, sidebar, auth gate) is server-rendered for an instant first paint and SEO, while the page itself stays client-only. Concretely, on both `voltro dev` and `voltro start`, a spa page under a layout used to ship the empty client shell (`<div id="root"></div>`) and mount the whole tree — layout included — in the browser. Now the server renders the layout chain around an empty page slot (`<div data-voltro-page-slot>`), runs the LAYOUT loaders, and inlines their data + a `pageClientOnly` flag; the browser hydrates that shell and mounts the client-only page into the slot after hydration. The page's OWN loader still runs in the browser, exactly as before. A spa page with NO layout is unchanged (still a pure client mount); `static`/`ssr`/`isr` pages are unchanged. Why this is BREAKING: a layout component AND its `loader` now execute during the server render for spa routes. Layouts shared with any `static`/`ssr`/`isr` page already ran server-side (and `static` is the default), so they are unaffected — the only newly-server-rendered layout is one whose ENTIRE page subtree is `'spa'`. Such a layout must be SSR-safe: no unguarded `window`/`document` at render time or in its `loader`. The `voltro update` codemod (`0.9.0/01`) prints this review step, and only for projects that actually have both a spa page and a layout. Out of scope this release (follow-ups): build-time prerender of the spa layout shell (`voltro build` still skips spa pages, so `voltro start` renders the shell on demand rather than from a prerendered file), `defer()`/streaming inside a spa-shell layout (the shell is buffered), and Fast-Refresh coverage of the new shell path.
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- **@voltro/protocol** — `jwtBearerStrategy` (and `extractBearerOrCookie`) accept an optional `cookieToToken` hook (`CookieTokenExtractor`) that transforms the request's cookie transport into the JWT to verify. It receives a `getCookie(name)` accessor (so a strategy can read sibling / chunked cookies) plus the configured cookie name. Applied to the cookie path only — the Bearer header stays a raw token — and defaulting to a verbatim read, so the raw-JWT cookie path for WorkOS / Kinde / Clerk / Auth0 / OIDC is byte-identical. `supabaseStrategy` supplies one to unwrap the `@supabase/ssr` session envelope. Additive: existing `jwtBearerStrategy` configs and 2-arg `extractBearerOrCookie` calls are unaffected.
|
|
51
|
+
- **@voltro/cli** — `voltro doctor` now flags pages that are safe `renderMode:'spa'` candidates. A page is listed when ALL hold: it is a page file (not `layout`/`loading`/`error`/`not-found`), it exports no `loader`, its `renderMode` is `'ssr'` or unset/default (not already `'spa'`/`'static'`/`'isr'`), AND a `layout.tsx` sits somewhere in its directory chain (root, an ancestor, or the page's own dir). That last condition is load-bearing: only with a layout does switching to `'spa'` keep a server-rendered shell (the layout SSRs while the page body goes client-only) — a page with no layout would, as `'spa'`, ship no server HTML at all, so it is never flagged. The hint is ADVISORY and names the tradeoff: `renderMode:'spa'` skips the page's per-page SSR compile while its layout shell still renders server-side — adopt it for internal/authenticated pages whose body needs no SSR; keep `'ssr'` when the page content needs SEO or server first-paint. We deliberately ship NO codemod to auto-flip pages, because dropping a page body's server render is a per-page product decision, not a mechanically-safe transform. The scan reuses the framework's own page discovery (`walkPagesTree`), so it can't drift from what dev/build classify as a page. The full list is retrievable via `voltro doctor --json` (a new `spaCandidates` array); the human view caps at 10 with a "+N more" pointer.
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- **@voltro/cli** — `voltro dev` no longer OOM-kills itself when many `renderMode:'ssr'` pages compile at once. The dev SSR renderer compiles each page (and every layout in its chain) on demand via Vite's `ssrLoadModule`, and that call was unbounded: two browser tabs on the same cold route, or a health-check sweep hitting hundreds of distinct routes, each started its OWN esbuild module tree with no dedupe and no concurrency cap, so the transient heaps added up and the process was killed (a downstream app with ~224 SSR pages reached >14 GB in seconds; `--max-old-space-size=8192` died after ~5 concurrent cold pages). The fix is a cold-compile gate (`coldCompileGate.ts`) around every `ssrLoadModule` in the dev SSR handler — the page, each layout/error/loading segment, and the shared `@voltro/web/ssr` helpers, so a sweep can't fan out on layouts either. It does two things: (1) DEDUPES concurrent requests for the same module — N tabs on one cold route trigger ONE compile they all await; (2) BOUNDS how many DISTINCT cold compiles run at once (default 4). A WARM module (already in Vite's graph) bypasses the gate entirely, so a hot app stays fully concurrent — the gate only tames the cold stampede, it never serializes warm serving. Verified: a concurrent sweep of 100 distinct cold routes runs exactly 4 concurrent esbuild trees under the default instead of 100, and 8 concurrent requests to one cold route compile the page once. The bound is overridable with `VOLTRO_DEV_SSR_COMPILE_CONCURRENCY` — drop it to `1`/`2` on a low-memory box, raise it on a beefy one. Default 4 balances memory against cold-sweep throughput (a lower value is safer but serializes first-paint of freshly-hit routes). Production `voltro start` is unaffected: it renders from a precompiled bundle and refuses to boot without one, so it never compiles on demand. The dev-like `voltro start` middleware FALLBACK (used only when `NODE_ENV!=='production'` and no bundle exists) shares the same `ssrLoadModule` path and now goes through the same gate. Covered by `coldCompileGate.test.ts` (dedupe, bound, warm bypass, failure-clears-and-retries, env parsing); the heavy end-to-end reproduction is a scratchpad (`scripts/measure-ssr-compile-oom.mjs`), not a CI gate.
|
|
56
|
+
- **@voltro/cli** — `voltro update` (and `voltro update --codemods-only`) no longer aborts with `ELOOP: too many symbolic links` when the app tree contains a circular symlink. The codemod file scan built its ts-morph `Project` with `addSourceFilesAtPaths([...globs])`, whose underlying glob FOLLOWS symbolic links and applies the `!**/node_modules/**` negations only to the RESULTS — so a self-referential symlink anywhere under the app root (pnpm's package layout inside `node_modules`, or any stray symlinked scratch dir) made the walk descend forever and throw before any negation could apply. The scan now enumerates source files itself with `followSymbolicLinks: false` and prunes heavy directories (`node_modules`, `.git`, `dist`, `build`, `.framework`, `.turbo`, `.next`, `.cache`, `.output`, `.voltro-*`, …) at the traversal level rather than by post-filtering — the crawler never descends into them, and no symlink is followed, so a cycle put there by anything is harmless. App source a codemod rewrites is always real files on disk, so files reachable only through a symlink are deliberately not scanned (and never rewritten). A codemod's explicit `scope` still narrows the file set exactly as before.
|
|
57
|
+
- **@voltro/plugin-auth-supabase** — `supabaseStrategy({ cookieName: 'sb-<ref>-auth-token' })` now reads `@supabase/ssr` session cookies. Those cookies do not hold a raw JWT — the SDK stores the GoTrue session as a JSON envelope, optionally `base64-`-encoded and split across `sb-<ref>-auth-token.0`, `.1`, … chunk cookies. The strategy previously handed that envelope straight to the JWT verifier, so every cookie-mode request failed with `malformed jwt` and fell back to anonymous (including `ctx.query` from a `type:'web'` loader, which forwards the browser cookie to the api). The strategy now unwraps the envelope — URL-decode, strip the `base64-` prefix and base64url-decode when present, concatenate chunks in order, then lift the inner `access_token` — before verification. The `Authorization: Bearer` path is unchanged (always a raw token). Hostile / malformed / oversized cookies resolve to anonymous (skip), never throw. Auth strategies belong on the `type:'api'` app, not the web app — the api verifies the forwarded cookie.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
42
61
|
## [0.8.0] — 2026-07-20
|
|
43
62
|
|
|
44
63
|
### ⚠ BREAKING
|
package/dist/index.d.ts
CHANGED
|
@@ -615,6 +615,8 @@ export declare class NotFoundError extends Error {
|
|
|
615
615
|
constructor(detail?: string);
|
|
616
616
|
}
|
|
617
617
|
|
|
618
|
+
export declare const PAGE_SLOT_ATTR = "data-voltro-page-slot";
|
|
619
|
+
|
|
618
620
|
export declare interface PageDescriptor<TLoaderData = unknown> {
|
|
619
621
|
/** URL pattern, e.g. `/`, `/about`, `/users/[id]`, `/docs/[...slug]`. */
|
|
620
622
|
readonly pattern: string;
|
|
@@ -705,6 +707,11 @@ export declare const pageRoute: (pattern: string, mod: Record<string, unknown>,
|
|
|
705
707
|
readonly chain?: ReadonlyArray<RouteSegment>;
|
|
706
708
|
}) => PageDescriptor;
|
|
707
709
|
|
|
710
|
+
/** The empty page slot the SSR-layout-shell path renders at the leaf, on BOTH
|
|
711
|
+
* the server (`renderPageToHtml` with `pageSlot`) and the client Router's
|
|
712
|
+
* first render — identical markup, so hydration matches. */
|
|
713
|
+
export declare const PageSlot: () => ReactNode;
|
|
714
|
+
|
|
708
715
|
export declare const parseCookieHeader: (raw: string | undefined) => Record<string, string>;
|
|
709
716
|
|
|
710
717
|
/** A caller may override any subtree, not the whole object — deep-partial per
|
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-C_d7E8Fj.js";
|
|
4
4
|
import { a as d, c as f, i as p, l as m, o as h, s as g } from "./defaultFallbacks-CGs2z5qv.js";
|
|
5
|
-
import { i as _, n as ee, r as te, t as ne } from "./mount-
|
|
6
|
-
import { c as re, d as ie, h as ae, l as oe, p as se, u as ce } from "./routerState-
|
|
7
|
-
import { A as le, B as ue, C as de, D as fe, E as pe, F as me,
|
|
8
|
-
import { Component as
|
|
5
|
+
import { i as _, n as ee, r as te, t as ne } from "./mount-Gsn3ouYx.js";
|
|
6
|
+
import { c as re, d as ie, h as ae, l as oe, p as se, u as ce } from "./routerState-DpUqogK8.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, _ as A, a as j, b as M, c as N, d as P, f as F, g as I, h as L, i as R, j as z, k as he, l as ge, m as _e, n as ve, o as ye, p as be, r as xe, s as Se, t as Ce, u as we, v as Te, w as Ee, x as De, y as Oe, z as ke } from "./serverContext-COzippNt.js";
|
|
8
|
+
import { Component as Ae, Suspense as je, createElement as B, use as Me, useCallback as Ne, useContext as Pe, useSyncExternalStore as Fe } from "react";
|
|
9
9
|
import { Fragment as V, jsx as H, jsxs as U } from "react/jsx-runtime";
|
|
10
10
|
export * from "@voltro/client";
|
|
11
11
|
export * from "@voltro/ui";
|
|
12
12
|
//#region src/await.tsx
|
|
13
|
-
var
|
|
13
|
+
var Ie = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PURE__ */ H(je, {
|
|
14
14
|
fallback: t,
|
|
15
|
-
children: /* @__PURE__ */ H(
|
|
15
|
+
children: /* @__PURE__ */ H(Re, {
|
|
16
16
|
errorFallback: r,
|
|
17
|
-
children: /* @__PURE__ */ H(
|
|
17
|
+
children: /* @__PURE__ */ H(Le, {
|
|
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 } }),
|
|
24
|
-
let r =
|
|
23
|
+
}), W = ({ body: e }) => /* @__PURE__ */ H("script", { dangerouslySetInnerHTML: { __html: e } }), Le = ({ value: e, errorFallback: t, children: n }) => {
|
|
24
|
+
let r = Me(e), i = ce(e), a = ae(r);
|
|
25
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
|
-
},
|
|
26
|
+
}, Re = class extends Ae {
|
|
27
27
|
state = { error: void 0 };
|
|
28
28
|
static getDerivedStateFromError(e) {
|
|
29
29
|
return { error: e };
|
|
@@ -31,7 +31,7 @@ var Pe = ({ 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 }),
|
|
34
|
+
}, G = ({ src: e }) => e, K = e("imageConfig", { loader: G }), ze = ({ loader: e, children: t }) => B(K.Provider, { value: { loader: e } }, t), q = [
|
|
35
35
|
640,
|
|
36
36
|
750,
|
|
37
37
|
828,
|
|
@@ -40,7 +40,7 @@ var Pe = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
|
|
|
40
40
|
1920,
|
|
41
41
|
2048,
|
|
42
42
|
3840
|
|
43
|
-
],
|
|
43
|
+
], Be = (e, t, n, r) => {
|
|
44
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];
|
|
45
45
|
return {
|
|
46
46
|
srcSet: i.map((n) => `${e({
|
|
@@ -52,10 +52,10 @@ var Pe = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
|
|
|
52
52
|
width: i[i.length - 1]
|
|
53
53
|
})
|
|
54
54
|
};
|
|
55
|
-
},
|
|
56
|
-
let f =
|
|
55
|
+
}, Ve = ({ 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 = Pe(K).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 } =
|
|
58
|
+
let { srcSet: m, fallback: h } = Be(p, e, n, i), g = c === "blur" && l ? {
|
|
59
59
|
backgroundImage: `url(${l})`,
|
|
60
60
|
backgroundSize: "cover",
|
|
61
61
|
backgroundPosition: "center"
|
|
@@ -85,10 +85,10 @@ var Pe = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
|
|
|
85
85
|
},
|
|
86
86
|
...d
|
|
87
87
|
});
|
|
88
|
-
},
|
|
88
|
+
}, He = ({ to: e, children: t, className: n }) => B("a", {
|
|
89
89
|
href: e,
|
|
90
90
|
className: n
|
|
91
|
-
}, t),
|
|
91
|
+
}, t), Ue = {
|
|
92
92
|
position: "sticky",
|
|
93
93
|
top: 0,
|
|
94
94
|
zIndex: 10,
|
|
@@ -99,13 +99,13 @@ var Pe = ({ 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
|
-
},
|
|
102
|
+
}, We = {
|
|
103
103
|
maxWidth: "48rem",
|
|
104
104
|
margin: "0 auto",
|
|
105
105
|
padding: "2rem 1.5rem",
|
|
106
106
|
width: "100%"
|
|
107
|
-
},
|
|
108
|
-
let { brand: t, topNav: n, children: r, pathname: i, footer: a, breadcrumbs: o, headerRight: s } = e, c = e.Link ??
|
|
107
|
+
}, Ge = (e) => {
|
|
108
|
+
let { brand: t, topNav: n, children: r, pathname: i, footer: a, breadcrumbs: o, headerRight: s } = e, c = e.Link ?? He, l = B("nav", {
|
|
109
109
|
className: "voltro-blog-nav",
|
|
110
110
|
style: {
|
|
111
111
|
display: "flex",
|
|
@@ -122,7 +122,7 @@ var Pe = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
|
|
|
122
122
|
});
|
|
123
123
|
})), u = B("header", {
|
|
124
124
|
className: "voltro-blog-header",
|
|
125
|
-
style:
|
|
125
|
+
style: Ue
|
|
126
126
|
}, B("div", { className: "voltro-blog-brand" }, t), s ? B("div", { style: {
|
|
127
127
|
display: "flex",
|
|
128
128
|
gap: "1rem",
|
|
@@ -150,7 +150,7 @@ var Pe = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
|
|
|
150
150
|
})) : null;
|
|
151
151
|
return B("div", { className: "voltro-blog-layout" }, u, B("main", {
|
|
152
152
|
className: "voltro-blog-main",
|
|
153
|
-
style:
|
|
153
|
+
style: We
|
|
154
154
|
}, d, r), a ? B("footer", {
|
|
155
155
|
className: "voltro-blog-footer",
|
|
156
156
|
style: {
|
|
@@ -160,7 +160,7 @@ var Pe = ({ 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",
|
|
163
|
+
}, J = "voltro:theme", Y = 31536e3, Ke = () => {
|
|
164
164
|
if (typeof document > "u") return "system";
|
|
165
165
|
try {
|
|
166
166
|
let e = document.cookie.match(/(?:^|;\s*)voltro:theme=([^;]*)/), t = e?.[1] === void 0 ? "" : decodeURIComponent(e[1]);
|
|
@@ -168,17 +168,17 @@ var Pe = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
|
|
|
168
168
|
} catch {
|
|
169
169
|
return "system";
|
|
170
170
|
}
|
|
171
|
-
},
|
|
171
|
+
}, qe = () => {
|
|
172
172
|
if (typeof window > "u" || !window.matchMedia) return !1;
|
|
173
173
|
try {
|
|
174
174
|
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
175
175
|
} catch {
|
|
176
176
|
return !1;
|
|
177
177
|
}
|
|
178
|
-
}, X = (e) => e === "system" ?
|
|
178
|
+
}, X = (e) => e === "system" ? qe() ? "dark" : "light" : e, Z = 0, Q = /* @__PURE__ */ new Set(), $ = () => {
|
|
179
179
|
Z++;
|
|
180
180
|
for (let e of Q) e();
|
|
181
|
-
},
|
|
181
|
+
}, Je = (e) => {
|
|
182
182
|
Q.add(e);
|
|
183
183
|
let t, n = () => $();
|
|
184
184
|
if (typeof window < "u" && window.matchMedia) try {
|
|
@@ -190,21 +190,21 @@ var Pe = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
|
|
|
190
190
|
t?.removeEventListener("change", n);
|
|
191
191
|
} catch {}
|
|
192
192
|
};
|
|
193
|
-
},
|
|
194
|
-
let e =
|
|
193
|
+
}, Ye = () => {
|
|
194
|
+
let e = Ke();
|
|
195
195
|
return `${Z}:${e}:${X(e)}`;
|
|
196
|
-
},
|
|
197
|
-
let [, e, t] =
|
|
196
|
+
}, Xe = () => "0:system:light", Ze = () => {
|
|
197
|
+
let [, e, t] = Fe(Je, Ye, Xe).split(":");
|
|
198
198
|
return {
|
|
199
199
|
theme: e,
|
|
200
200
|
resolvedTheme: t,
|
|
201
|
-
setTheme:
|
|
201
|
+
setTheme: Ne((e) => {
|
|
202
202
|
if (typeof document < "u") try {
|
|
203
|
-
document.cookie = e === "system" ? `${J}=; path=/; max-age=0; SameSite=Lax` : `${J}=${e}; path=/; max-age=${
|
|
203
|
+
document.cookie = e === "system" ? `${J}=; path=/; max-age=0; SameSite=Lax` : `${J}=${e}; path=/; max-age=${Y}; SameSite=Lax`, document.documentElement.classList.toggle("dark", X(e) === "dark");
|
|
204
204
|
} catch {}
|
|
205
205
|
$();
|
|
206
206
|
}, [])
|
|
207
207
|
};
|
|
208
|
-
},
|
|
208
|
+
}, Qe = "framework-web";
|
|
209
209
|
//#endregion
|
|
210
|
-
export { t as AppClientsContext,
|
|
210
|
+
export { t as AppClientsContext, Ie as Await, Ge as BlogLayout, p as FallbackStringsProvider, Ve as Image, ze as ImageConfigProvider, ye as Link, Se as LoaderCache, N as LoaderDataContext, i as NavigationIndicator, me as NotFoundError, ge as PAGE_SLOT_ATTR, we as PageSlot, P as PlainLink, o as ReconnectContext, y as RedirectError, F as Router, be as RouterContext, Ce as ServerRequestContext, ve as ServerRequestProvider, J as THEME_COOKIE, Qe as WEB_NAME, _e as compileRoute, d as defaultFallbackStrings, re as defer, L as externalUrl, I 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, b as isNotFound, T as isRedirect, _ as island, A as lazyPageRoute, Te as loaderCacheKey, Oe as matchRoute, ne as mount, ke as notFound, M as pageRoute, xe as parseCookieHeader, G as passthroughImageLoader, De as preloadRouteModule, f as pushStatus, ue as redirect, s as registerClientTrace, E as resolveAnchorNavigation, de as resolveMeta, Ee as segmentLoaderKey, v as setRouteSnapshot, D as sortRoutesByPriority, O as subscribeRouteSnapshot, m as subscribeStatuses, l as subscribeTraceErrors, n as useAppClient, pe as useBlocker, h as useFallbackStrings, fe as useLoaderData, C as useLocation, he as useNavigate, le as useParams, z as usePrefetch, u as useReconnect, R as useSearchParams, j as useServerRequest, x as useSetSearchParams, Ze as useTheme, S as withHash, w as withQuery };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as e } from "./frameworkBoot-C_d7E8Fj.js";
|
|
2
|
-
import { o as t, r as n, t as r } from "./routerState-
|
|
2
|
+
import { o as t, r as n, t as r } from "./routerState-DpUqogK8.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
5
|
import { jsx as c } from "react/jsx-runtime";
|
package/dist/mount.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as e } from "./mount-
|
|
1
|
+
import { t as e } from "./mount-Gsn3ouYx.js";
|
|
2
2
|
export { e as mount };
|
|
@@ -65,6 +65,7 @@ var e = /* @__PURE__ */ RegExp("\\u2028", "g"), t = /* @__PURE__ */ RegExp("\\u2
|
|
|
65
65
|
...e.pageLoaderRan ? { page: !0 } : {},
|
|
66
66
|
...t.length > 0 ? { segments: t } : {}
|
|
67
67
|
},
|
|
68
|
+
...e.pageClientOnly ? { pageClientOnly: !0 } : {},
|
|
68
69
|
...n || r ? { deferred: {
|
|
69
70
|
...n ? { page: e.deferredPageIds } : {},
|
|
70
71
|
...r ? { segments: e.deferredSegmentIds } : {}
|
|
@@ -85,6 +86,7 @@ var e = /* @__PURE__ */ RegExp("\\u2028", "g"), t = /* @__PURE__ */ RegExp("\\u2
|
|
|
85
86
|
page: D(r.page, r.deferred?.page),
|
|
86
87
|
pageRan: r.ran?.page === !0,
|
|
87
88
|
segments: a.size > 0 ? a : T,
|
|
89
|
+
pageClientOnly: r.pageClientOnly === !0,
|
|
88
90
|
pathname: t
|
|
89
91
|
};
|
|
90
92
|
}, D = (e, t) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as e } from "./globalContext-d4A-ugDg.js";
|
|
2
2
|
import { c as t, n, t as r } from "./defaultFallbacks-CGs2z5qv.js";
|
|
3
|
-
import { f as i, i as a } from "./routerState-
|
|
3
|
+
import { f as i, i as a } from "./routerState-DpUqogK8.js";
|
|
4
4
|
import { Component as o, useCallback as s, useContext as c, useEffect as l, useMemo as u, useRef as d, useState as f } from "react";
|
|
5
5
|
import { jsx as p, jsxs as ee } from "react/jsx-runtime";
|
|
6
6
|
//#region src/routeEventBus.ts
|
|
@@ -286,7 +286,7 @@ var m = {
|
|
|
286
286
|
}
|
|
287
287
|
return this.props.children;
|
|
288
288
|
}
|
|
289
|
-
}, ve = ({ routes: e, notFounds: i = [], notFound: o = n, errorFallback: c = r }) => {
|
|
289
|
+
}, B = "data-voltro-page-slot", ve = () => /* @__PURE__ */ p("div", { [B]: "" }), ye = ({ routes: e, notFounds: i = [], notFound: o = n, errorFallback: c = r }) => {
|
|
290
290
|
let [m, h] = f(() => window.location.pathname), [g, _] = f(() => window.location.pathname), [v, y] = f(() => window.location.search + window.location.hash), b = d(new le()), x = d(/* @__PURE__ */ new Map()), [C, w] = f(null), T = s((e, t) => (x.current.set(e, t), () => {
|
|
291
291
|
x.current.delete(e);
|
|
292
292
|
}), []), E = d(/* @__PURE__ */ new Map()), D = d(null), j = u(() => ie(e.map(re)), [e]);
|
|
@@ -351,7 +351,7 @@ var m = {
|
|
|
351
351
|
};
|
|
352
352
|
return document.addEventListener("click", e), () => document.removeEventListener("click", e);
|
|
353
353
|
}, [P]);
|
|
354
|
-
let I = u(() => O(j, m), [j, m]), R = d(/* @__PURE__ */ new Map()), [
|
|
354
|
+
let I = u(() => O(j, m), [j, m]), R = d(/* @__PURE__ */ new Map()), [B, ye] = f(0);
|
|
355
355
|
l(() => {
|
|
356
356
|
let e = I?.route;
|
|
357
357
|
if (!e?.load || R.current.has(e.pattern)) return;
|
|
@@ -362,27 +362,27 @@ var m = {
|
|
|
362
362
|
t = !0;
|
|
363
363
|
};
|
|
364
364
|
}, [I?.route.load ? I.route.pattern : null]);
|
|
365
|
-
let
|
|
365
|
+
let V = u(() => {
|
|
366
366
|
if (!I) return null;
|
|
367
367
|
let e = I.route;
|
|
368
368
|
if (!e.load) return e;
|
|
369
369
|
let t = R.current.get(e.pattern);
|
|
370
370
|
return t ? {
|
|
371
371
|
...e,
|
|
372
|
-
...
|
|
372
|
+
...De(t),
|
|
373
373
|
load: void 0
|
|
374
374
|
} : null;
|
|
375
|
-
}, [I,
|
|
376
|
-
if (!
|
|
377
|
-
let e =
|
|
375
|
+
}, [I, B]), H = u(() => O(j, g), [j, g]), U = u(() => {
|
|
376
|
+
if (!H) return null;
|
|
377
|
+
let e = H.route;
|
|
378
378
|
if (!e.load) return e;
|
|
379
379
|
let t = R.current.get(e.pattern);
|
|
380
380
|
return t ? {
|
|
381
381
|
...e,
|
|
382
|
-
...
|
|
382
|
+
...De(t),
|
|
383
383
|
load: void 0
|
|
384
384
|
} : null;
|
|
385
|
-
}, [
|
|
385
|
+
}, [H, B]), W = s((e) => {
|
|
386
386
|
let t = new URL(e, window.location.origin), n = O(j, t.pathname);
|
|
387
387
|
if (!n) return;
|
|
388
388
|
let r = (e, r) => {
|
|
@@ -395,33 +395,37 @@ var m = {
|
|
|
395
395
|
n.route.loader && r(k(n.route.pattern, n.params), n.route.loader), n.route.chain?.forEach((e, t) => {
|
|
396
396
|
e.loader && r(ae(n.route.pattern, t, n.params), e.loader);
|
|
397
397
|
});
|
|
398
|
-
}, [j]), [
|
|
399
|
-
|
|
400
|
-
let
|
|
398
|
+
}, [j]), [G, K] = f({ status: "idle" }), q = d(void 0);
|
|
399
|
+
q.current === void 0 && (q.current = a());
|
|
400
|
+
let Se = d(!1), [Ce, we] = f(() => q.current?.pageClientOnly === !0 && q.current.pathname === m);
|
|
401
|
+
l(() => {
|
|
402
|
+
we(!1);
|
|
403
|
+
}, []);
|
|
404
|
+
let [J, Te] = f(() => ({
|
|
401
405
|
pathname: m,
|
|
402
|
-
data: me(
|
|
406
|
+
data: me(q.current ?? null, m),
|
|
403
407
|
chain: I?.route.chain
|
|
404
408
|
}));
|
|
405
409
|
l(() => {
|
|
406
410
|
let e = (e) => {
|
|
407
|
-
_(m),
|
|
411
|
+
_(m), Te((t) => t.pathname === m && he(t.data, e) ? t : {
|
|
408
412
|
pathname: m,
|
|
409
413
|
data: e,
|
|
410
414
|
chain: I?.route.chain
|
|
411
415
|
});
|
|
412
416
|
};
|
|
413
417
|
if (!I) {
|
|
414
|
-
|
|
418
|
+
K({ status: "idle" }), e(void 0);
|
|
415
419
|
return;
|
|
416
420
|
}
|
|
417
|
-
if (!
|
|
418
|
-
|
|
421
|
+
if (!V) {
|
|
422
|
+
K({
|
|
419
423
|
status: "pending",
|
|
420
424
|
key: k(I.route.pattern, I.params)
|
|
421
425
|
});
|
|
422
426
|
return;
|
|
423
427
|
}
|
|
424
|
-
let t =
|
|
428
|
+
let t = V, { params: n } = I, r = t.chain, i = (t.Pending ?? A(r, "Pending", r ? r.length - 1 : -1)) !== void 0, a = [];
|
|
425
429
|
if (t.loader) {
|
|
426
430
|
let e = t.loader;
|
|
427
431
|
a.push({
|
|
@@ -448,12 +452,12 @@ var m = {
|
|
|
448
452
|
});
|
|
449
453
|
}
|
|
450
454
|
}), a.length === 0) {
|
|
451
|
-
|
|
455
|
+
K({ status: "idle" }), e(void 0);
|
|
452
456
|
return;
|
|
453
457
|
}
|
|
454
|
-
let o = k(t.pattern, n), s =
|
|
455
|
-
if (s && !
|
|
456
|
-
|
|
458
|
+
let o = k(t.pattern, n), s = q.current;
|
|
459
|
+
if (s && !Se.current && m === s.pathname) {
|
|
460
|
+
Se.current = !0;
|
|
457
461
|
for (let e of a) e.target === "page" ? s.pageRan && b.current.seed(e.cacheKey, s.page) : s.segments.has(e.target) && b.current.seed(e.cacheKey, s.segments.get(e.target));
|
|
458
462
|
}
|
|
459
463
|
let c = a.map((e) => ({
|
|
@@ -479,18 +483,18 @@ var m = {
|
|
|
479
483
|
};
|
|
480
484
|
}, u = l();
|
|
481
485
|
if (u) {
|
|
482
|
-
u.ok ? (
|
|
486
|
+
u.ok ? (K({
|
|
483
487
|
status: "success",
|
|
484
488
|
key: o,
|
|
485
489
|
data: u.data
|
|
486
|
-
}), e(u.data)) : (
|
|
490
|
+
}), e(u.data)) : (K({
|
|
487
491
|
status: "error",
|
|
488
492
|
key: o,
|
|
489
493
|
error: u.error
|
|
490
494
|
}), S(u.error) || e(void 0));
|
|
491
495
|
return;
|
|
492
496
|
}
|
|
493
|
-
|
|
497
|
+
K({
|
|
494
498
|
status: "pending",
|
|
495
499
|
key: o
|
|
496
500
|
}), i && _(m);
|
|
@@ -498,11 +502,11 @@ var m = {
|
|
|
498
502
|
return Promise.all(f).then(() => {
|
|
499
503
|
if (d) return;
|
|
500
504
|
let t = l();
|
|
501
|
-
t && (t.ok ? (
|
|
505
|
+
t && (t.ok ? (K({
|
|
502
506
|
status: "success",
|
|
503
507
|
key: o,
|
|
504
508
|
data: t.data
|
|
505
|
-
}), e(t.data)) : (
|
|
509
|
+
}), e(t.data)) : (K({
|
|
506
510
|
status: "error",
|
|
507
511
|
key: o,
|
|
508
512
|
error: t.error
|
|
@@ -512,48 +516,48 @@ var m = {
|
|
|
512
516
|
};
|
|
513
517
|
}, [
|
|
514
518
|
I,
|
|
515
|
-
|
|
519
|
+
V,
|
|
516
520
|
m
|
|
517
521
|
]);
|
|
518
|
-
let
|
|
519
|
-
if (!
|
|
520
|
-
let e =
|
|
521
|
-
return se(
|
|
522
|
+
let Y = J.data?.page, X = g === m, Ee = J.pathname === g, Oe = Ee ? J.data?.page : void 0, ke = ge(), Z = u(() => {
|
|
523
|
+
if (!H) return null;
|
|
524
|
+
let e = H.params.locale ?? ke;
|
|
525
|
+
return se(U?.meta, H.params, Y, e);
|
|
522
526
|
}, [
|
|
523
|
-
V,
|
|
524
527
|
H,
|
|
525
|
-
|
|
526
|
-
|
|
528
|
+
U,
|
|
529
|
+
Y,
|
|
530
|
+
ke
|
|
527
531
|
]);
|
|
528
|
-
l(() => _e(
|
|
529
|
-
let [
|
|
532
|
+
l(() => _e(Z), [Z]);
|
|
533
|
+
let [Q, Ae] = f(""), je = d(!1), [Me, Ne] = f(!1);
|
|
530
534
|
l(() => {
|
|
531
|
-
if (!
|
|
532
|
-
|
|
535
|
+
if (!je.current) {
|
|
536
|
+
je.current = !0, Ne(!0);
|
|
533
537
|
return;
|
|
534
538
|
}
|
|
535
|
-
let e =
|
|
536
|
-
|
|
537
|
-
}, [g,
|
|
539
|
+
let e = Z?.title ?? (typeof document < "u" ? document.title : "");
|
|
540
|
+
Ae(e && e.length > 0 ? e : g);
|
|
541
|
+
}, [g, Z]), l(() => {
|
|
538
542
|
let e = D.current;
|
|
539
543
|
e && (D.current = null, de(() => window.scrollTo(e.x, e.y)));
|
|
540
544
|
}, [g]);
|
|
541
|
-
let
|
|
545
|
+
let Pe = u(() => ({
|
|
542
546
|
pathname: g,
|
|
543
547
|
search: v,
|
|
544
548
|
navigate: P,
|
|
545
|
-
params:
|
|
546
|
-
prefetch:
|
|
547
|
-
loaderData:
|
|
549
|
+
params: H?.params ?? {},
|
|
550
|
+
prefetch: W,
|
|
551
|
+
loaderData: Y,
|
|
548
552
|
registerBlocker: T,
|
|
549
553
|
blocked: C
|
|
550
554
|
}), [
|
|
551
555
|
g,
|
|
552
556
|
v,
|
|
553
557
|
P,
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
558
|
+
H,
|
|
559
|
+
W,
|
|
560
|
+
Y,
|
|
557
561
|
T,
|
|
558
562
|
C
|
|
559
563
|
]);
|
|
@@ -571,82 +575,83 @@ var m = {
|
|
|
571
575
|
}, []), l(() => {
|
|
572
576
|
te({
|
|
573
577
|
pathname: g,
|
|
574
|
-
params:
|
|
575
|
-
loaderData:
|
|
578
|
+
params: H?.params ?? {},
|
|
579
|
+
loaderData: Y
|
|
576
580
|
});
|
|
577
581
|
}, [
|
|
578
582
|
g,
|
|
579
|
-
|
|
580
|
-
|
|
583
|
+
H,
|
|
584
|
+
Y
|
|
581
585
|
]), l(() => {
|
|
582
|
-
if (
|
|
586
|
+
if (G.status === "pending") return t({
|
|
583
587
|
id: "voltro:router:loader",
|
|
584
588
|
kind: "loading",
|
|
585
589
|
label: "Loading…"
|
|
586
590
|
});
|
|
587
|
-
}, [
|
|
588
|
-
if (
|
|
591
|
+
}, [G.status]), l(() => {
|
|
592
|
+
if (G.status === "error") return t({
|
|
589
593
|
id: "voltro:router:loader-error",
|
|
590
594
|
kind: "error",
|
|
591
595
|
label: "Loader failed"
|
|
592
596
|
});
|
|
593
|
-
}, [
|
|
594
|
-
|
|
595
|
-
}, [
|
|
596
|
-
let
|
|
597
|
+
}, [G.status]), l(() => {
|
|
598
|
+
G.status === "error" && S(G.error) && P(G.error.location, { replace: !0 });
|
|
599
|
+
}, [G, P]);
|
|
600
|
+
let Fe = () => {
|
|
597
601
|
let e = ce(i, g);
|
|
598
602
|
if (e) {
|
|
599
603
|
let { Component: t, chain: n } = e;
|
|
600
604
|
return xe(n, /* @__PURE__ */ p(t, {}), g, c);
|
|
601
605
|
}
|
|
602
606
|
return /* @__PURE__ */ p(o, {});
|
|
603
|
-
},
|
|
604
|
-
if (!
|
|
605
|
-
else if (ne(
|
|
607
|
+
}, Ie = X && H && G.status === "error" ? G.error : void 0, $;
|
|
608
|
+
if (!H) $ = Fe();
|
|
609
|
+
else if (ne(Ie)) $ = Fe();
|
|
606
610
|
else {
|
|
607
|
-
let e =
|
|
608
|
-
if (
|
|
609
|
-
|
|
611
|
+
let e = H.route.chain, t = e ? e.length - 1 : -1, n = U?.ErrorBoundary ?? A(e, "Error", t) ?? c, r;
|
|
612
|
+
if (Ce) r = /* @__PURE__ */ p(ve, {});
|
|
613
|
+
else if (X && G.status === "error" && !S(G.error)) r = /* @__PURE__ */ p(n, {
|
|
614
|
+
error: G.error,
|
|
610
615
|
reset: () => {
|
|
611
|
-
b.current.invalidate(
|
|
616
|
+
b.current.invalidate(H.route.pattern), h((e) => e), K({ status: "idle" });
|
|
612
617
|
}
|
|
613
618
|
});
|
|
614
|
-
else if (
|
|
615
|
-
let i =
|
|
619
|
+
else if (X && G.status === "pending") {
|
|
620
|
+
let i = U?.Pending ?? A(e, "Pending", t);
|
|
616
621
|
if (i) r = /* @__PURE__ */ p(i, {});
|
|
617
|
-
else if (
|
|
618
|
-
let e =
|
|
622
|
+
else if (U?.Component) {
|
|
623
|
+
let e = U.Component;
|
|
619
624
|
r = /* @__PURE__ */ p(z, {
|
|
620
625
|
resetKey: g,
|
|
621
626
|
Fallback: n,
|
|
622
627
|
children: /* @__PURE__ */ p(L.Provider, {
|
|
623
|
-
value:
|
|
628
|
+
value: Oe,
|
|
624
629
|
children: /* @__PURE__ */ p(e, {})
|
|
625
630
|
})
|
|
626
631
|
});
|
|
627
632
|
} else r = null;
|
|
628
633
|
} else {
|
|
629
|
-
let e =
|
|
634
|
+
let e = U?.Component;
|
|
630
635
|
r = e ? /* @__PURE__ */ p(z, {
|
|
631
636
|
resetKey: g,
|
|
632
637
|
Fallback: n,
|
|
633
638
|
children: /* @__PURE__ */ p(L.Provider, {
|
|
634
|
-
value:
|
|
639
|
+
value: Oe,
|
|
635
640
|
children: /* @__PURE__ */ p(e, {})
|
|
636
641
|
})
|
|
637
642
|
}) : null;
|
|
638
643
|
}
|
|
639
644
|
$ = xe(e, r, g, c, (t) => {
|
|
640
|
-
if (
|
|
645
|
+
if (Ee) return J.data?.segments[t];
|
|
641
646
|
let n = e?.[t]?.Layout;
|
|
642
|
-
return n !== void 0 && n ===
|
|
647
|
+
return n !== void 0 && n === J.chain?.[t]?.Layout ? J.data?.segments[t] : void 0;
|
|
643
648
|
});
|
|
644
649
|
}
|
|
645
650
|
return /* @__PURE__ */ ee(F.Provider, {
|
|
646
|
-
value:
|
|
647
|
-
children: [$,
|
|
651
|
+
value: Pe,
|
|
652
|
+
children: [$, Me ? /* @__PURE__ */ p(be, { message: Q }) : null]
|
|
648
653
|
});
|
|
649
|
-
},
|
|
654
|
+
}, V = {
|
|
650
655
|
position: "absolute",
|
|
651
656
|
width: 1,
|
|
652
657
|
height: 1,
|
|
@@ -661,7 +666,7 @@ var m = {
|
|
|
661
666
|
role: "status",
|
|
662
667
|
"aria-live": "assertive",
|
|
663
668
|
"aria-atomic": "true",
|
|
664
|
-
style:
|
|
669
|
+
style: V,
|
|
665
670
|
children: e
|
|
666
671
|
}), xe = (e, t, n, r, i) => {
|
|
667
672
|
if (!e || e.length === 0) return t;
|
|
@@ -685,7 +690,7 @@ var m = {
|
|
|
685
690
|
}
|
|
686
691
|
}
|
|
687
692
|
return a;
|
|
688
|
-
},
|
|
693
|
+
}, H = () => I().pathname, U = () => I().navigate, W = () => I().params, G = () => c(L), K = () => I().prefetch, q = (e) => {
|
|
689
694
|
let { registerBlocker: t, blocked: n } = I(), r = d(Symbol("voltro:blocker")), i = d(e);
|
|
690
695
|
return i.current = e, l(() => {
|
|
691
696
|
let e = r.current;
|
|
@@ -699,22 +704,22 @@ var m = {
|
|
|
699
704
|
retry: n.retry,
|
|
700
705
|
reset: n.reset
|
|
701
706
|
} : { blocked: !1 };
|
|
702
|
-
},
|
|
707
|
+
}, Se = (e) => e instanceof URLSearchParams ? e : new URLSearchParams(e), Ce = () => {
|
|
703
708
|
let { navigate: e } = I();
|
|
704
709
|
return s((t, n) => {
|
|
705
|
-
let r = new URLSearchParams(typeof window < "u" ? window.location.search : ""), i =
|
|
710
|
+
let r = new URLSearchParams(typeof window < "u" ? window.location.search : ""), i = Se(typeof t == "function" ? t(r) : t).toString(), a = typeof window < "u" ? window.location.pathname : "/", o = i ? `${a}?${i}` : a;
|
|
706
711
|
e(o, {
|
|
707
712
|
replace: !n?.push,
|
|
708
713
|
...n?.scroll === void 0 ? {} : { scroll: n.scroll }
|
|
709
714
|
});
|
|
710
715
|
}, [e]);
|
|
711
|
-
},
|
|
716
|
+
}, we = (e) => e, J = (e, t) => {
|
|
712
717
|
let n = new URLSearchParams();
|
|
713
718
|
for (let [e, r] of Object.entries(t)) r !== void 0 && n.append(e, String(r));
|
|
714
719
|
let r = n.toString();
|
|
715
720
|
return r ? `${e}?${r}` : e;
|
|
716
|
-
},
|
|
717
|
-
let c =
|
|
721
|
+
}, Te = (e, t) => `${e}#${t.replace(/^#/, "")}`, Y = (e) => /^([a-z][a-z0-9+.-]*:|\/\/|#)/i.test(e), X = ({ to: e, children: t, onClick: n, prefetch: r = !1, replace: i = !1, onMouseEnter: a, onFocus: o, ...s }) => {
|
|
722
|
+
let c = U(), l = K(), u = Y(e), d = (t) => {
|
|
718
723
|
u || t.metaKey || t.ctrlKey || t.shiftKey || t.altKey || t.button !== 0 || (t.preventDefault(), n?.(t), c(e, i ? { replace: i } : void 0));
|
|
719
724
|
}, f = (t) => {
|
|
720
725
|
r && !u && l(e), a?.(t);
|
|
@@ -729,10 +734,10 @@ var m = {
|
|
|
729
734
|
onFocus: ee,
|
|
730
735
|
children: t
|
|
731
736
|
});
|
|
732
|
-
},
|
|
737
|
+
}, Ee = (e) => X({
|
|
733
738
|
...e,
|
|
734
739
|
to: e.to
|
|
735
|
-
}),
|
|
740
|
+
}), De = (e) => ({
|
|
736
741
|
Component: e.default,
|
|
737
742
|
meta: e.meta,
|
|
738
743
|
loader: e.loader,
|
|
@@ -740,30 +745,30 @@ var m = {
|
|
|
740
745
|
Pending: e.Pending,
|
|
741
746
|
renderMode: e.renderMode,
|
|
742
747
|
interactive: e.interactive
|
|
743
|
-
}),
|
|
748
|
+
}), Oe = (e, t, n = {}) => ({
|
|
744
749
|
pattern: e,
|
|
745
|
-
...
|
|
750
|
+
...De(t),
|
|
746
751
|
chain: n.chain
|
|
747
|
-
}),
|
|
752
|
+
}), ke = (e, t, n = {}) => ({
|
|
748
753
|
pattern: e,
|
|
749
754
|
load: t,
|
|
750
755
|
chain: n.chain
|
|
751
|
-
}),
|
|
756
|
+
}), Z = async (e, t) => {
|
|
752
757
|
let n = O(e.map(re), t)?.route.load;
|
|
753
758
|
if (n) try {
|
|
754
759
|
await n();
|
|
755
760
|
} catch {}
|
|
756
|
-
},
|
|
757
|
-
let e =
|
|
761
|
+
}, Q = e("serverRequest", null), Ae = () => c(Q), je = () => {
|
|
762
|
+
let e = Ae();
|
|
758
763
|
if (e !== null) {
|
|
759
764
|
let t = e.url.indexOf("?");
|
|
760
765
|
return new URLSearchParams(t >= 0 ? e.url.slice(t + 1) : "");
|
|
761
766
|
}
|
|
762
767
|
return typeof window < "u" ? new URLSearchParams(window.location.search) : new URLSearchParams();
|
|
763
|
-
},
|
|
768
|
+
}, Me = ({ value: e, children: t }) => /* @__PURE__ */ p(Q.Provider, {
|
|
764
769
|
value: e,
|
|
765
770
|
children: t
|
|
766
|
-
}),
|
|
771
|
+
}), Ne = (e) => {
|
|
767
772
|
let t = {};
|
|
768
773
|
if (!e) return t;
|
|
769
774
|
for (let n of e.split(";")) {
|
|
@@ -781,4 +786,4 @@ var m = {
|
|
|
781
786
|
return t;
|
|
782
787
|
};
|
|
783
788
|
//#endregion
|
|
784
|
-
export {
|
|
789
|
+
export { W as A, x as B, se as C, G as D, q as E, v as F, te as H, y as I, ne as L, Ce as M, Te as N, H as O, J as P, S as R, ue as S, ie as T, _ as U, g as V, ke as _, Ae as a, Oe as b, L as c, Ee as d, ye as f, ce as g, we as h, je as i, K as j, U as k, B as l, re as m, Me as n, X as o, F as p, Ne as r, le as s, Q as t, ve as u, k as v, ae as w, Z as x, O as y, b as z };
|
package/dist/ssr.d.ts
CHANGED
|
@@ -77,6 +77,13 @@ export declare interface InlinedRouterState {
|
|
|
77
77
|
readonly page?: boolean;
|
|
78
78
|
readonly segments?: ReadonlyArray<number>;
|
|
79
79
|
};
|
|
80
|
+
/** True when the server rendered the layout chain but left the page leaf as
|
|
81
|
+
* an EMPTY slot — the `renderMode:'spa'`-under-an-SSR-layout case. The
|
|
82
|
+
* server ran only the layout loaders; the page is client-only. The client's
|
|
83
|
+
* FIRST render must reproduce the identical empty slot so the layout chain
|
|
84
|
+
* hydrates without a mismatch, then mount the real page after commit. Absent
|
|
85
|
+
* (falsy) for every full-page SSR/ISR/static document. */
|
|
86
|
+
readonly pageClientOnly?: boolean;
|
|
80
87
|
/** Deferred (streamed) loader fields: field name -> client-registry id, for
|
|
81
88
|
* the page loader and per chain index. The VALUES are not here — they
|
|
82
89
|
* arrive later, published by the settle `<script>` each `<Await>` boundary
|
|
@@ -319,6 +326,14 @@ export declare interface RenderPageOptions {
|
|
|
319
326
|
* catalog at meta-resolve time. Optional: when absent, page
|
|
320
327
|
* `meta(ctx)` callbacks see `ctx.locale = 'en'` as a safe default. */
|
|
321
328
|
readonly locale?: string;
|
|
329
|
+
/** Render the LAYOUT CHAIN ONLY, with an empty page slot at the leaf
|
|
330
|
+
* ({@link PageSlot}) instead of the page Component — the
|
|
331
|
+
* `renderMode:'spa'`-under-an-SSR-layout case. The caller runs only the
|
|
332
|
+
* layout loaders (not the page loader) and pairs this with a state script
|
|
333
|
+
* carrying `pageClientOnly: true`, so the client reproduces the empty slot
|
|
334
|
+
* on its first render and mounts the page after hydration. When set, the
|
|
335
|
+
* descriptor need not carry a `Component`. */
|
|
336
|
+
readonly pageSlot?: boolean;
|
|
322
337
|
}
|
|
323
338
|
|
|
324
339
|
export declare interface RenderPageResult {
|
|
@@ -415,6 +430,12 @@ export declare interface RouterStateInput {
|
|
|
415
430
|
* `loaderData` (a loader may legitimately resolve to `undefined`/`null`,
|
|
416
431
|
* and the SSR paths default the field to `null` when there is no loader). */
|
|
417
432
|
readonly pageLoaderRan: boolean;
|
|
433
|
+
/** Set by the SSR-layout-shell path (a `renderMode:'spa'` page under an SSR
|
|
434
|
+
* layout chain): the server rendered the layouts + an empty page slot and
|
|
435
|
+
* ran only the layout loaders. Tells the client to reproduce the empty slot
|
|
436
|
+
* on its first render, then mount the page after hydration. Omit for every
|
|
437
|
+
* full-page render. */
|
|
438
|
+
readonly pageClientOnly?: boolean | undefined;
|
|
418
439
|
/** Page-loader deferred fields: name -> registry id. Produced by
|
|
419
440
|
* `prepareDeferredLoaderData` in the SSR pipeline; omit when nothing
|
|
420
441
|
* deferred (which is every non-streaming emitter). */
|
package/dist/ssr.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { _ as e, a as t, g as n, m as r, n as i, p as a, s as o, t as s } from "./routerState-
|
|
2
|
-
import { c,
|
|
3
|
-
import { createElement as
|
|
4
|
-
import { renderToPipeableStream as
|
|
1
|
+
import { _ as e, a as t, g as n, m as r, n as i, p as a, s as o, t as s } from "./routerState-DpUqogK8.js";
|
|
2
|
+
import { C as c, c as l, p as u, r as d, t as f, u as p } from "./serverContext-COzippNt.js";
|
|
3
|
+
import { createElement as m } from "react";
|
|
4
|
+
import { renderToPipeableStream as h, renderToString as g } from "react-dom/server";
|
|
5
5
|
//#region src/ssr.tsx
|
|
6
|
-
var
|
|
7
|
-
let i =
|
|
6
|
+
var _ = (e, t, n, r) => {
|
|
7
|
+
let i = m(l.Provider, { value: n }, m(e));
|
|
8
8
|
if (!t) return i;
|
|
9
9
|
for (let e = t.length - 1; e >= 0; e--) {
|
|
10
10
|
let n = t[e];
|
|
11
11
|
if (n.Layout) {
|
|
12
12
|
let t = n.Layout;
|
|
13
|
-
i =
|
|
13
|
+
i = m(l.Provider, { value: r(e) }, m(t, { children: i }));
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
return i;
|
|
17
|
-
},
|
|
18
|
-
let { descriptor: t, params: n, pathname: r, loaderData: i, segmentLoaderData: a, requestContext: o, outerWrap: s, locale:
|
|
17
|
+
}, v = (e) => {
|
|
18
|
+
let { descriptor: t, params: n, pathname: r, loaderData: i, segmentLoaderData: a, requestContext: o, outerWrap: s, locale: l, pageSlot: d } = e, h = c(t.meta, n, i, l), g = {
|
|
19
19
|
pathname: r,
|
|
20
20
|
search: "",
|
|
21
21
|
params: n,
|
|
@@ -26,23 +26,23 @@ var g = (e, t, n, r) => {
|
|
|
26
26
|
prefetch: () => {},
|
|
27
27
|
registerBlocker: () => () => {},
|
|
28
28
|
blocked: null
|
|
29
|
-
},
|
|
30
|
-
if (!
|
|
31
|
-
let
|
|
32
|
-
return o && (
|
|
33
|
-
tree:
|
|
34
|
-
meta:
|
|
29
|
+
}, v = d ? p : t.Component;
|
|
30
|
+
if (!v) throw Error(`SSR received a descriptor with no Component for "${r}". Lazy page routes are a client-only optimization and must not be used on the server.`);
|
|
31
|
+
let y = m(u.Provider, { value: g }, _(v, t.chain, d ? void 0 : i, (e) => a?.[e]));
|
|
32
|
+
return o && (y = m(f.Provider, { value: o }, y)), s && (y = s(y)), {
|
|
33
|
+
tree: y,
|
|
34
|
+
meta: h
|
|
35
35
|
};
|
|
36
|
-
},
|
|
37
|
-
let { tree: t, meta: n } =
|
|
36
|
+
}, y = (e) => {
|
|
37
|
+
let { tree: t, meta: n } = v(e);
|
|
38
38
|
return {
|
|
39
|
-
html:
|
|
39
|
+
html: g(t),
|
|
40
40
|
meta: n
|
|
41
41
|
};
|
|
42
|
-
},
|
|
43
|
-
let { tree: t, meta: n } =
|
|
42
|
+
}, b = (e) => {
|
|
43
|
+
let { tree: t, meta: n } = v(e);
|
|
44
44
|
return {
|
|
45
|
-
stream:
|
|
45
|
+
stream: h(t, {
|
|
46
46
|
...e.bootstrapModules ? { bootstrapModules: [...e.bootstrapModules] } : {},
|
|
47
47
|
...e.onShellReady ? { onShellReady: e.onShellReady } : {},
|
|
48
48
|
...e.onShellError ? { onShellError: e.onShellError } : {},
|
|
@@ -50,20 +50,20 @@ var g = (e, t, n, r) => {
|
|
|
50
50
|
}),
|
|
51
51
|
meta: n
|
|
52
52
|
};
|
|
53
|
-
},
|
|
53
|
+
}, x = (e) => {
|
|
54
54
|
if (!e) return "";
|
|
55
55
|
let t = [];
|
|
56
|
-
if (typeof e.title == "string" && t.push(`<title>${
|
|
57
|
-
let e = n.name ? `name="${
|
|
58
|
-
e && t.push(`<meta ${e} content="${
|
|
56
|
+
if (typeof e.title == "string" && t.push(`<title>${S(e.title)}</title>`), e.description && t.push(`<meta name="description" content="${C(e.description)}" />`), e.canonical && t.push(`<link rel="canonical" href="${C(e.canonical)}" />`), e.tags) for (let n of e.tags) {
|
|
57
|
+
let e = n.name ? `name="${C(n.name)}"` : n.property ? `property="${C(n.property)}"` : "";
|
|
58
|
+
e && t.push(`<meta ${e} content="${C(n.content)}" />`);
|
|
59
59
|
}
|
|
60
60
|
if (e.links) for (let n of e.links) {
|
|
61
61
|
let e = [
|
|
62
|
-
`rel="${
|
|
63
|
-
`href="${
|
|
64
|
-
n.hreflang ? `hreflang="${
|
|
65
|
-
n.type ? `type="${
|
|
66
|
-
n.title ? `title="${
|
|
62
|
+
`rel="${C(n.rel)}"`,
|
|
63
|
+
`href="${C(n.href)}"`,
|
|
64
|
+
n.hreflang ? `hreflang="${C(n.hreflang)}"` : "",
|
|
65
|
+
n.type ? `type="${C(n.type)}"` : "",
|
|
66
|
+
n.title ? `title="${C(n.title)}"` : ""
|
|
67
67
|
].filter(Boolean).join(" ");
|
|
68
68
|
t.push(`<link ${e} />`);
|
|
69
69
|
}
|
|
@@ -72,6 +72,6 @@ var g = (e, t, n, r) => {
|
|
|
72
72
|
t.push(`<script type="application/ld+json" data-voltro-page-jsonld>${e}<\/script>`);
|
|
73
73
|
}
|
|
74
74
|
return t.join("\n ");
|
|
75
|
-
},
|
|
75
|
+
}, S = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"), C = (e) => e.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
76
76
|
//#endregion
|
|
77
|
-
export { s as ROUTER_STATE_SCRIPT_ID, o as assertDeferralSupported, i as encodeRouterState, a as isDeferredLoaderResult,
|
|
77
|
+
export { s as ROUTER_STATE_SCRIPT_ID, o as assertDeferralSupported, i as encodeRouterState, a as isDeferredLoaderResult, d as parseCookieHeader, r as prepareDeferredLoaderData, n as renderDeferredRegistryScript, x as renderMetaToHtml, y as renderPageToHtml, b as renderPageToStream, t as renderRouterStateScript, e as serialiseStateForInlining };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "The Voltro web framework — file-based routing, render modes (SSR / SSG / islands), the page-export contract, data hooks, and the browser mount.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
"node": ">=24.0.0"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@voltro/client": "0.
|
|
56
|
-
"@voltro/ui": "0.
|
|
55
|
+
"@voltro/client": "0.9.0",
|
|
56
|
+
"@voltro/ui": "0.9.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@effect/platform": "^0.96.2",
|