@voltro/web 0.9.0 → 0.10.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/ssr.d.ts CHANGED
@@ -22,6 +22,11 @@ import { ReactNode } from 'react';
22
22
  * and never hydrates the root, so nothing ever consumes the registry
23
23
  * promises. Islands take their props from their own serialised payload, not
24
24
  * from loader data, so there is no value in wiring them in.
25
+ *
26
+ * The one place `renderMode` is NOT the deciding input is the SSR layout shell
27
+ * (`layoutShell` above): a `renderMode:'spa'` page under an SSR layout chain is
28
+ * streamed per request by dev/serve — so a LAYOUT loader may defer there — and
29
+ * written to a file by the build, where it may not.
25
30
  */
26
31
  export declare const assertDeferralSupported: (target: DeferralTarget) => void;
27
32
 
@@ -31,6 +36,23 @@ export declare interface DeferralTarget {
31
36
  readonly page: string;
32
37
  readonly renderMode: string;
33
38
  readonly interactive: string;
39
+ /**
40
+ * Set ONLY on the SSR-layout-shell path — a `renderMode:'spa'` page under an
41
+ * SSR layout chain, where the server renders the LAYOUTS around an empty page
42
+ * slot and runs only the layout loaders. `renderMode` is `'spa'` there, so
43
+ * without this the shell would be rejected by the rule below; the thing that
44
+ * actually decides whether it can stream is HOW the shell is delivered:
45
+ *
46
+ * - `'stream'` — a per-request response (`voltro dev` / `voltro serve`). It
47
+ * goes out through `renderPageToStream`, so a LAYOUT loader may `defer()`:
48
+ * the chain + empty slot flush immediately and the deferred value streams
49
+ * in behind its `<Await>` boundary, exactly as on an `ssr` page.
50
+ * - `'artefact'` — the build-time prerender, which writes an HTML FILE. A
51
+ * file has no "after", so `defer()` is refused there by name.
52
+ *
53
+ * Absent for every full-page render, where `renderMode` alone decides.
54
+ */
55
+ readonly layoutShell?: 'stream' | 'artefact' | undefined;
34
56
  }
35
57
 
36
58
  /** Brand key on the object `defer()` returns. A single explicit container
@@ -64,6 +86,13 @@ declare interface ErrorBoundaryProps {
64
86
  * re-run it on hydration (the flash this whole payload exists to remove).
65
87
  */
66
88
  export declare interface InlinedRouterState {
89
+ /** The pathname the server rendered THIS document for.
90
+ *
91
+ * Present so the client can tell "the server rendered my route" from "a
92
+ * static host handed me some other route's document as its SPA fallback".
93
+ * Without it the two are indistinguishable — the payload parses either way,
94
+ * and `mount()` would adopt markup for a route it is not on. */
95
+ readonly path?: string;
67
96
  /** The page (leaf) loader's result — exactly the value the server render
68
97
  * provided to the page's `LoaderDataContext`. */
69
98
  readonly page?: unknown;
@@ -250,20 +279,6 @@ export declare interface PreparedLoaderData {
250
279
  readonly deferredIds: Readonly<Record<string, string>> | undefined;
251
280
  }
252
281
 
253
- /**
254
- * The `<script>` every streaming SSR emitter puts in `<head>`, before the
255
- * shell. Must precede any settle script — which is automatic, since settle
256
- * scripts ride in the body.
257
- */
258
- export declare const renderDeferredRegistryScript: () => string;
259
-
260
- /**
261
- * Helper for the build pipeline: stringify the resolved meta into a
262
- * `<head>`-ready HTML fragment. Returns an empty string when no meta
263
- * is set so the caller can blindly inject the result.
264
- */
265
- export declare const renderMetaToHtml: (meta: PageMeta | null) => string;
266
-
267
282
  /**
268
283
  * How a page's HTML is produced.
269
284
  *
@@ -286,8 +301,33 @@ export declare const renderMetaToHtml: (meta: PageMeta | null) => string;
286
301
  * tenant-scoped first paint.
287
302
  * - 'isr' — Like 'ssr' on the first request, then cached and
288
303
  * revalidated in the background on a TTL.
304
+ *
305
+ * The value set is single-sourced from {@link RENDER_MODES} so the type and
306
+ * every runtime check derive from ONE literal list. There are no aliases — an
307
+ * unrecognised value is rejected at codegen/discovery time by the CLI, not
308
+ * silently passed through.
309
+ */
310
+ declare const RENDER_MODES: readonly ["static", "spa", "ssr", "isr"];
311
+
312
+ /**
313
+ * The `<script>` every streaming SSR emitter puts in `<head>`, before the
314
+ * shell. Must precede any settle script — which is automatic, since settle
315
+ * scripts ride in the body.
316
+ */
317
+ export declare const renderDeferredRegistryScript: () => string;
318
+
319
+ /**
320
+ * Helper for the build pipeline: stringify the resolved meta into a
321
+ * `<head>`-ready HTML fragment. Returns an empty string when no meta
322
+ * is set so the caller can blindly inject the result.
323
+ */
324
+ export declare const renderMetaToHtml: (meta: PageMeta | null) => string;
325
+
326
+ /**
327
+ * A page's render mode — one of {@link RENDER_MODES}, from which this type is
328
+ * derived. Closed set: an unrecognised value is rejected at codegen time.
289
329
  */
290
- declare type RenderMode = 'static' | 'spa' | 'ssr' | 'isr';
330
+ declare type RenderMode = (typeof RENDER_MODES)[number];
291
331
 
292
332
  export declare interface RenderPageOptions {
293
333
  /** Descriptor produced by codegen (`pageRoute(...)`). */
@@ -421,6 +461,12 @@ export declare const renderRouterStateScript: (input: RouterStateInput) => strin
421
461
  export declare const ROUTER_STATE_SCRIPT_ID = "__voltro_state__";
422
462
 
423
463
  export declare interface RouterStateInput {
464
+ /** The pathname this render is FOR. Every emitter has it — it is the same
465
+ * value handed to the renderer as `pathname` — and passing it is required
466
+ * rather than optional on purpose: a payload without it cannot be matched
467
+ * against the document it lands in, which is the whole point of carrying
468
+ * it (see {@link parseRouterState}). */
469
+ readonly path: string;
424
470
  /** Page loader result passed to `renderPageToHtml` / `renderPageToStream`. */
425
471
  readonly loaderData: unknown;
426
472
  /** Layout loader results, keyed by chain index — the same object passed to
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-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";
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-cjTiUIum.js";
2
+ import { c, m as l, r as u, t as d, u as f, w as p } from "./serverContext-BP0ywwLZ.js";
3
3
  import { createElement as m } from "react";
4
4
  import { renderToPipeableStream as h, renderToString as g } from "react-dom/server";
5
5
  //#region src/ssr.tsx
6
6
  var _ = (e, t, n, r) => {
7
- let i = m(l.Provider, { value: n }, m(e));
7
+ let i = m(c.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 = m(l.Provider, { value: r(e) }, m(t, { children: i }));
13
+ i = m(c.Provider, { value: r(e) }, m(t, { children: i }));
14
14
  }
15
15
  }
16
16
  return i;
17
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 = {
18
+ let { descriptor: t, params: n, pathname: r, loaderData: i, segmentLoaderData: a, requestContext: o, outerWrap: s, locale: c, pageSlot: u } = e, h = p(t.meta, n, i, c), g = {
19
19
  pathname: r,
20
20
  search: "",
21
21
  params: n,
@@ -26,10 +26,10 @@ var _ = (e, t, n, r) => {
26
26
  prefetch: () => {},
27
27
  registerBlocker: () => () => {},
28
28
  blocked: null
29
- }, v = d ? p : t.Component;
29
+ }, v = u ? f : t.Component;
30
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)), {
31
+ let y = m(l.Provider, { value: g }, _(v, t.chain, u ? void 0 : i, (e) => a?.[e]));
32
+ return o && (y = m(d.Provider, { value: o }, y)), s && (y = s(y)), {
33
33
  tree: y,
34
34
  meta: h
35
35
  };
@@ -74,4 +74,4 @@ var _ = (e, t, n, r) => {
74
74
  return t.join("\n ");
75
75
  }, S = (e) => e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"), C = (e) => e.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
76
76
  //#endregion
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 };
77
+ export { s as ROUTER_STATE_SCRIPT_ID, o as assertDeferralSupported, i as encodeRouterState, a as isDeferredLoaderResult, u 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.9.0",
3
+ "version": "0.10.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.9.0",
56
- "@voltro/ui": "0.9.0"
55
+ "@voltro/client": "0.10.0",
56
+ "@voltro/ui": "0.10.0"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "@effect/platform": "^0.96.2",