@vertz/ui-server 0.2.30 → 0.2.32

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
@@ -1,751 +1,925 @@
1
- import { FallbackFontName as FallbackFontName2, FontFallbackMetrics as FontFallbackMetrics7 } from "@vertz/ui";
2
- interface AotBuildComponentEntry {
3
- tier: "static" | "data-driven" | "conditional" | "runtime-fallback";
4
- holes: string[];
5
- }
6
- interface AotBuildManifest {
7
- components: Record<string, AotBuildComponentEntry>;
8
- classificationLog: string[];
9
- }
10
- /**
11
- * Scan all TSX files in srcDir and generate an AOT build manifest.
12
- */
13
- declare function generateAotBuildManifest(srcDir: string): AotBuildManifest;
14
- /** A raw HTML string that bypasses escaping during serialization. */
15
- interface RawHtml {
16
- __raw: true;
17
- html: string;
18
- }
1
+ import { IncomingMessage, ServerResponse } from "node:http";
2
+ import { FontFallbackMetrics as FontFallbackMetrics4 } from "@vertz/ui";
3
+ import { FontFallbackMetrics as FontFallbackMetrics3 } from "@vertz/ui";
4
+ import { SSRAuth as SSRAuth2 } from "@vertz/ui/internals";
19
5
  /**
20
- * Create a raw HTML string that will NOT be escaped during SSR serialization.
21
- *
22
- * **WARNING: XSS RISK** — This function bypasses all HTML escaping. Never pass
23
- * user-controlled input directly. Always sanitize with a trusted library (e.g.
24
- * DOMPurify) before wrapping in `rawHtml()`.
6
+ * SSR prefetch access rule evaluator.
25
7
  *
26
- * @example Safe usage
27
- * ```ts
28
- * rawHtml('<svg>...</svg>') // static markup — OK
29
- * rawHtml(DOMPurify.sanitize(userInput)) // sanitized — OK
30
- * ```
8
+ * Evaluates serialized entity access rules against the current session
9
+ * to determine whether a query should be prefetched during SSR.
31
10
  *
32
- * @example Unsafe usage NEVER do this
33
- * ```ts
34
- * rawHtml(userInput) // XSS vulnerability
35
- * rawHtml(`<div>${userInput}</div>`) // XSS via interpolation
36
- * ```
11
+ * The serialized rules come from the prefetch manifest (generated at build time).
12
+ * The session comes from the JWT decoded at request time.
37
13
  */
38
- declare function rawHtml(html: string): RawHtml;
39
- /** Virtual node representing an HTML element for SSR serialization. */
40
- interface VNode {
41
- tag: string;
42
- attrs: Record<string, string>;
43
- children: (VNode | string | RawHtml)[];
44
- }
45
- /** Options for hydration marker generation. */
46
- interface HydrationOptions {
47
- /** Component name for `data-v-id`. */
48
- componentName: string;
49
- /** Unique key for `data-v-key`. */
50
- key: string;
51
- /** Serialized props to embed as JSON. */
52
- props?: Record<string, unknown>;
53
- }
54
- /** Metadata collected by the Head component during rendering. */
55
- interface HeadEntry {
56
- tag: "title" | "meta" | "link";
57
- attrs?: Record<string, string>;
58
- textContent?: string;
59
- }
60
- /** Options for {@link renderToStream}. */
61
- interface RenderToStreamOptions {
62
- /**
63
- * CSP nonce to inject on all inline `<script>` tags emitted during SSR.
64
- *
65
- * When set, every inline script (e.g. Suspense replacement scripts) will
66
- * include `nonce="<value>"` so that strict Content-Security-Policy headers
67
- * do not block them.
68
- */
69
- nonce?: string;
70
- }
71
- /** Asset descriptor for script/stylesheet injection. */
72
- interface AssetDescriptor {
73
- type: "script" | "stylesheet";
74
- src: string;
75
- /** Whether to add `async` attribute (scripts only). */
76
- async?: boolean;
77
- /** Whether to add `defer` attribute (scripts only). */
78
- defer?: boolean;
79
- }
80
14
  /**
81
- * Render asset descriptors to HTML tags for script/stylesheet injection.
82
- *
83
- * - Scripts: `<script src="..." [async] [defer]><\/script>`
84
- * - Stylesheets: `<link rel="stylesheet" href="...">`
15
+ * Serialized access rule the JSON-friendly format stored in the manifest.
16
+ * Mirrors SerializedRule from @vertz/server/auth/rules but defined here
17
+ * to avoid importing the server package into the SSR pipeline.
85
18
  */
86
- declare function renderAssetTags(assets: AssetDescriptor[]): string;
19
+ type SerializedAccessRule = {
20
+ type: "public";
21
+ } | {
22
+ type: "authenticated";
23
+ } | {
24
+ type: "role";
25
+ roles: string[];
26
+ } | {
27
+ type: "entitlement";
28
+ value: string;
29
+ } | {
30
+ type: "where";
31
+ conditions: Record<string, unknown>;
32
+ } | {
33
+ type: "all";
34
+ rules: SerializedAccessRule[];
35
+ } | {
36
+ type: "any";
37
+ rules: SerializedAccessRule[];
38
+ } | {
39
+ type: "fva";
40
+ maxAge: number;
41
+ } | {
42
+ type: "deny";
43
+ };
87
44
  /**
88
- * Inline critical CSS as a `<style>` tag.
89
- *
90
- * Wraps the provided CSS in `<style>...</style>` for embedding in the HTML head.
91
- * Escapes any `</style>` sequences in the CSS content to prevent injection.
92
- *
93
- * Returns an empty string if the CSS is empty.
45
+ * Minimal session shape needed for prefetch access evaluation.
46
+ * Extracted from the JWT at SSR request time.
94
47
  */
95
- declare function inlineCriticalCss(css: string): string;
96
- import { FallbackFontName, FontDescriptor, FontFallbackMetrics } from "@vertz/ui";
48
+ type PrefetchSession = {
49
+ status: "authenticated";
50
+ roles?: string[];
51
+ entitlements?: Record<string, boolean>;
52
+ tenantId?: string;
53
+ } | {
54
+ status: "unauthenticated";
55
+ };
97
56
  /**
98
- * Auto-detect which system font to use as fallback base.
99
- *
100
- * Scans the `fallback` array for generic CSS font family keywords:
101
- * - 'sans-serif' or 'system-ui' → Arial
102
- * - 'serif' → Times New Roman
103
- * - 'monospace' → Courier New
104
- *
105
- * Skips non-generic entries (e.g., 'Georgia', 'Helvetica').
106
- * If no generic keyword found, defaults to Arial.
57
+ * Minimal shape of an AccessSet for entitlement extraction.
58
+ * Avoids importing @vertz/server types into the SSR pipeline.
107
59
  */
108
- declare function detectFallbackFont(fallback: readonly string[]): FallbackFontName;
60
+ interface AccessSetLike {
61
+ entitlements: Record<string, {
62
+ allowed: boolean;
63
+ }>;
64
+ }
109
65
  /**
110
- * Extract font metrics from .woff2 files and compute CSS fallback overrides.
66
+ * Convert SSRAuth (from the JWT/session resolver) to PrefetchSession
67
+ * for entity access evaluation during SSR prefetching.
111
68
  *
112
- * @param fonts - Font descriptors from theme definition.
113
- * @param rootDir - Project root directory for resolving font file paths.
114
- * @returns Map of font key → computed fallback metrics.
69
+ * @param ssrAuth - Auth state from session resolver
70
+ * @param accessSet - Access set from JWT acl claim (null = overflow, undefined = not configured)
115
71
  */
116
- declare function extractFontMetrics(fonts: Record<string, FontDescriptor>, rootDir: string): Promise<Record<string, FontFallbackMetrics>>;
72
+ declare function toPrefetchSession(ssrAuth: {
73
+ status: string;
74
+ user?: {
75
+ role?: string;
76
+ [key: string]: unknown;
77
+ };
78
+ } | undefined, accessSet?: AccessSetLike | null): PrefetchSession;
117
79
  /**
118
- * Collector for `<head>` metadata during SSR.
80
+ * Evaluate a serialized access rule against the current session.
119
81
  *
120
- * Components call `addTitle`, `addMeta`, or `addLink` during render,
121
- * and the collected entries are serialized into the HTML `<head>` section.
122
- */
123
- declare class HeadCollector {
124
- private entries;
125
- /** Add a `<title>` entry. */
126
- addTitle(text: string): void;
127
- /** Add a `<meta>` entry. */
128
- addMeta(attrs: Record<string, string>): void;
129
- /** Add a `<link>` entry. */
130
- addLink(attrs: Record<string, string>): void;
131
- /** Get all collected entries. */
132
- getEntries(): HeadEntry[];
133
- /** Clear all collected entries. */
134
- clear(): void;
135
- }
136
- /**
137
- * Render head entries to an HTML string.
82
+ * Returns true if the query is eligible for prefetch (the user
83
+ * likely has access), false if it should be skipped.
138
84
  *
139
- * - `<title>` renders as `<title>text</title>`
140
- * - `<meta>` and `<link>` render as void elements
85
+ * Design rationale for specific rule types:
86
+ * - `where` true: row-level filter, not an access gate. The query
87
+ * always executes; it just returns fewer rows for non-owners.
88
+ * - `fva` → optimistic for authenticated users: MFA freshness is
89
+ * enforced on the actual API call. If the check fails server-side,
90
+ * the query returns an error result.
91
+ * - `deny` → false: explicitly denied operations are never prefetched.
92
+ * - Unknown types → false: fail-secure. Don't prefetch if we can't
93
+ * evaluate the rule.
141
94
  */
142
- declare function renderHeadToHtml(entries: HeadEntry[]): string;
95
+ declare function evaluateAccessRule(rule: SerializedAccessRule, session: PrefetchSession): boolean;
143
96
  /**
144
- * Serialize a VNode tree (or plain string) to an HTML string.
145
- *
146
- * This is the core serialization function for SSR. It walks the virtual tree
147
- * recursively and produces an HTML string without requiring a real DOM.
97
+ * AOT SSR Diagnostics
148
98
  *
149
- * - Text content inside `<script>` and `<style>` tags is not escaped.
150
- * - `RawHtml` values bypass escaping entirely.
99
+ * Tracks AOT compilation results and provides a JSON snapshot
100
+ * for the `/__vertz_ssr_aot` dev endpoint.
151
101
  */
152
- declare function serializeToHtml(node: VNode | string | RawHtml): string;
102
+ /** AOT tier classification (mirrored from @vertz/ui-compiler to avoid cross-package dependency). */
103
+ type AotTier = "static" | "data-driven" | "conditional" | "runtime-fallback";
104
+ /** Per-component diagnostic entry in the snapshot. */
105
+ interface AotComponentDiagnostic {
106
+ tier: AotTier;
107
+ holes: string[];
108
+ }
109
+ /** A recorded divergence between AOT and DOM shim output. */
110
+ interface AotDivergenceEntry {
111
+ component: string;
112
+ aotHtml: string;
113
+ domHtml: string;
114
+ timestamp: string;
115
+ }
116
+ /** JSON snapshot returned by the `/__vertz_ssr_aot` endpoint. */
117
+ interface AotDiagnosticsSnapshot {
118
+ components: Record<string, AotComponentDiagnostic>;
119
+ coverage: {
120
+ total: number;
121
+ aot: number;
122
+ runtime: number;
123
+ percentage: number;
124
+ };
125
+ divergences: AotDivergenceEntry[];
126
+ }
127
+ /** Input shape matching AotComponentInfo from @vertz/ui-compiler. */
128
+ interface ComponentInput {
129
+ name: string;
130
+ tier: AotTier;
131
+ holes: string[];
132
+ }
153
133
  /**
154
- * Wrap a VNode with hydration markers for interactive components.
155
- *
156
- * Adds `data-v-id` and `data-v-key` attributes to the root element,
157
- * and optionally embeds serialized props as a `<script type="application/json">` child.
134
+ * Collects AOT compilation diagnostics and produces JSON snapshots.
158
135
  *
159
- * Returns a new VNode; the original is not mutated.
136
+ * Used by the dev server to power the `/__vertz_ssr_aot` endpoint
137
+ * and by the build pipeline for classification logging.
160
138
  */
161
- declare function wrapWithHydrationMarkers(node: VNode, options: HydrationOptions): VNode;
162
- interface PageOptions {
163
- /** HTTP status code (default: 200) */
164
- status?: number;
165
- /** Page title */
166
- title?: string;
167
- /** Meta description */
168
- description?: string;
169
- /** Language attribute (default: 'en') */
170
- lang?: string;
171
- /** Favicon URL */
172
- favicon?: string;
173
- /** Open Graph meta tags */
174
- og?: {
175
- /** OG title (falls back to title) */
176
- title?: string;
177
- /** OG description (falls back to description) */
178
- description?: string;
179
- /** OG image URL */
180
- image?: string;
181
- /** OG canonical URL */
182
- url?: string;
183
- /** OG type (default: 'website') */
184
- type?: string;
185
- };
186
- /** Twitter card meta tags */
187
- twitter?: {
188
- /** Twitter card type */
189
- card?: string;
190
- /** Twitter @username */
191
- site?: string;
192
- };
193
- /** Array of script URLs to include at end of body */
194
- scripts?: string[];
195
- /** Array of stylesheet URLs to include in head */
139
+ declare class AotDiagnostics {
140
+ private _components;
141
+ private _divergences;
142
+ /**
143
+ * Record components from an AOT compilation result.
144
+ * Called once per file during compilation or hot rebuild.
145
+ */
146
+ recordCompilation(components: ComponentInput[]): void;
147
+ /** Record a divergence between AOT and DOM shim HTML output. */
148
+ recordDivergence(component: string, aotHtml: string, domHtml: string): void;
149
+ /** Clear all recorded data (used during full rebuild). */
150
+ clear(): void;
151
+ /** Clear only component classifications (preserves divergences). */
152
+ clearComponents(): void;
153
+ /**
154
+ * Generate per-component classification log lines.
155
+ * Used by the build pipeline and VERTZ_DEBUG=aot logging.
156
+ *
157
+ * Returns lines like:
158
+ * - "Header: static"
159
+ * - "Dashboard: conditional, 1 hole (SidePanel)"
160
+ * - "Coverage: 3/4 components (75%)"
161
+ */
162
+ getClassificationLog(): string[];
163
+ /** Produce a JSON-serializable snapshot for the diagnostic endpoint. */
164
+ getSnapshot(): AotDiagnosticsSnapshot;
165
+ }
166
+ import { CompiledRoute, FontFallbackMetrics, Theme } from "@vertz/ui";
167
+ import { SSRAuth as SSRAuth_jq1nwm } from "@vertz/ui/internals";
168
+ interface SSRModule {
169
+ default?: () => unknown;
170
+ App?: () => unknown;
171
+ theme?: Theme;
172
+ /** Global CSS strings to include in every SSR response (e.g. resets, body styles). */
196
173
  styles?: string[];
197
- /** Raw HTML escape hatch for head */
198
- head?: string;
174
+ /**
175
+ * Return all CSS tracked by the bundled @vertz/ui instance.
176
+ * The Vite SSR build inlines @vertz/ui into the server bundle, creating
177
+ * a separate module instance from @vertz/ui-server's dependency. Without
178
+ * this, component CSS from module-level css() calls is invisible to the
179
+ * SSR renderer. Export `getInjectedCSS` from @vertz/ui in the app entry.
180
+ */
181
+ getInjectedCSS?: () => string[];
182
+ /** Compiled routes exported from the app for build-time SSG with generateParams. */
183
+ routes?: CompiledRoute[];
184
+ /** Code-generated API client for manifest-driven zero-discovery prefetching. */
185
+ api?: Record<string, Record<string, (...args: unknown[]) => unknown>>;
186
+ }
187
+ interface SSRRenderResult {
188
+ html: string;
189
+ css: string;
190
+ ssrData: Array<{
191
+ key: string;
192
+ data: unknown;
193
+ }>;
194
+ /** Font preload link tags for injection into <head>. */
195
+ headTags: string;
196
+ /** Route patterns discovered by createRouter() during SSR (for build-time pre-rendering). */
197
+ discoveredRoutes?: string[];
198
+ /** Route patterns that matched the current URL (for per-route modulepreload). */
199
+ matchedRoutePatterns?: string[];
200
+ /** Set when ProtectedRoute writes a redirect during SSR. Server should return 302. */
201
+ redirect?: {
202
+ to: string;
203
+ };
204
+ }
205
+ interface SSRDiscoverResult {
206
+ resolved: Array<{
207
+ key: string;
208
+ data: unknown;
209
+ }>;
210
+ pending: string[];
199
211
  }
200
212
  /**
201
- * Render a VNode to a full HTML Response with common page structure.
202
- *
203
- * This is the main entry point for zero-boilerplate SSR. It wraps the component
204
- * in a complete HTML document with doctype, head (meta, OG, Twitter, favicon,
205
- * styles), and body (component content + scripts).
206
- *
207
- * @param vnode - The root VNode to render
208
- * @param options - Optional page configuration
209
- * @returns A Response with text/html content-type
210
- *
211
- * @example
212
- * ```ts
213
- * // Minimal usage
214
- * return renderPage(App)
213
+ * Render an SSR module to an HTML string with CSS and pre-fetched query data.
215
214
  *
216
- * // Full options
217
- * return renderPage(App, {
218
- * title: 'My App',
219
- * description: 'Built with vertz',
220
- * og: { image: '/og.png' },
221
- * scripts: ['/app.js'],
222
- * styles: ['/app.css'],
223
- * })
224
- * ```
215
+ * Performs a two-pass render:
216
+ * - Pass 1: Discovery — calls the app to trigger query() registrations, awaits them
217
+ * - Pass 2: Render — calls the app again with data populated, renders to HTML
225
218
  */
226
- declare function renderPage(vnode: VNode, options?: PageOptions): Response;
227
- import { FontFallbackMetrics as FontFallbackMetrics2, Theme } from "@vertz/ui";
228
- interface RenderToHTMLOptions<AppFn extends () => VNode> {
229
- /** The app component function */
230
- app: AppFn;
231
- /** Request URL for SSR */
232
- url: string;
233
- /** Theme definition for CSS vars */
234
- theme?: Theme;
235
- /** Global CSS strings to inject */
236
- styles?: string[];
237
- /** HTML head configuration */
238
- head?: {
239
- title?: string;
240
- meta?: Array<{
241
- name?: string;
242
- property?: string;
243
- content: string;
244
- }>;
245
- links?: Array<{
246
- rel: string;
247
- href: string;
248
- }>;
249
- };
250
- /** Container selector (default '#app') */
251
- container?: string;
219
+ declare function ssrRenderToString(module: SSRModule, url: string, options?: {
220
+ ssrTimeout?: number;
252
221
  /** Pre-computed font fallback metrics (computed at server startup). */
253
- fallbackMetrics?: Record<string, FontFallbackMetrics2>;
222
+ fallbackMetrics?: Record<string, FontFallbackMetrics>;
223
+ /** Auth state resolved from session cookie. Passed to SSRRenderContext for AuthProvider. */
224
+ ssrAuth?: SSRAuth_jq1nwm;
225
+ }): Promise<SSRRenderResult>;
226
+ /**
227
+ * Discover queries for a given URL without rendering.
228
+ * Runs only Pass 1 (query registration + resolution), no Pass 2 render.
229
+ * Used by the production handler to pre-fetch query data for client-side navigations.
230
+ */
231
+ declare function ssrDiscoverQueries(module: SSRModule, url: string, options?: {
232
+ ssrTimeout?: number;
233
+ }): Promise<SSRDiscoverResult>;
234
+ import { FontFallbackMetrics as FontFallbackMetrics2 } from "@vertz/ui";
235
+ import { SSRAuth } from "@vertz/ui/internals";
236
+ import { ExtractedQuery } from "@vertz/ui-compiler";
237
+ /** Serialized entity access rules from the prefetch manifest. */
238
+ type EntityAccessMap = Record<string, Partial<Record<string, SerializedAccessRule>>>;
239
+ interface SSRPrefetchManifest {
240
+ /** Route patterns present in the manifest. */
241
+ routePatterns: string[];
242
+ /** Entity access rules keyed by entity name → operation → serialized rule. */
243
+ entityAccess?: EntityAccessMap;
244
+ /** Route entries with query binding metadata for zero-discovery prefetch. */
245
+ routeEntries?: Record<string, {
246
+ queries: ExtractedQuery[];
247
+ }>;
254
248
  }
255
- interface RenderToHTMLStreamOptions<AppFn extends () => VNode> extends RenderToHTMLOptions<AppFn> {
256
- /** CSP nonce for inline scripts */
257
- nonce?: string;
258
- /** Global default for per-query ssrTimeout (ms) */
249
+ interface SSRSinglePassOptions {
259
250
  ssrTimeout?: number;
260
- /** Hard timeout for entire stream (ms, default 30000) */
261
- streamTimeout?: number;
251
+ /** Pre-computed font fallback metrics (computed at server startup). */
252
+ fallbackMetrics?: Record<string, FontFallbackMetrics2>;
253
+ /** Auth state resolved from session cookie. */
254
+ ssrAuth?: SSRAuth;
255
+ /** Set to false to fall back to two-pass rendering. Default: true. */
256
+ prefetch?: boolean;
257
+ /** Prefetch manifest for entity access filtering. */
258
+ manifest?: SSRPrefetchManifest;
259
+ /** Session data for access rule evaluation. */
260
+ prefetchSession?: PrefetchSession;
262
261
  }
263
262
  /**
264
- * Render a component to a streaming HTML Response.
263
+ * Render an SSR module in a single pass via discovery-only execution.
265
264
  *
266
- * The initial HTML is sent immediately. For slow queries that timed out
267
- * during SSR, their resolved data is streamed as inline `<script>` chunks
268
- * that push data to the client's reactive system.
265
+ * 1. Discovery: Run the app factory to capture query registrations (no stream render)
266
+ * 2. Prefetch: Await all discovered queries with timeout
267
+ * 3. Render: Create a fresh context with pre-populated cache, render once
269
268
  *
270
- * @returns Promise<Response> - A streaming Response with text/html content
269
+ * Falls back to two-pass (`ssrRenderToString`) when:
270
+ * - `prefetch: false` is set
271
+ * - A redirect is detected during discovery
271
272
  */
272
- declare function renderToHTMLStream<AppFn extends () => VNode>(options: RenderToHTMLStreamOptions<AppFn>): Promise<Response>;
273
+ declare function ssrRenderSinglePass(module: SSRModule, url: string, options?: SSRSinglePassOptions): Promise<SSRRenderResult>;
274
+ /** Context passed to AOT render functions for accessing data and runtime holes. */
275
+ interface SSRAotContext {
276
+ /** Pre-generated closures for runtime-rendered components. */
277
+ holes: Record<string, () => string>;
278
+ /** Access query data by cache key. */
279
+ getData(key: string): unknown;
280
+ /** Auth session for conditional rendering. */
281
+ session: PrefetchSession | undefined;
282
+ /** Route params for the current request. */
283
+ params: Record<string, string>;
284
+ }
285
+ /** An AOT render function: takes props/data and context, returns HTML string. */
286
+ type AotRenderFn = (data: Record<string, unknown>, ctx: SSRAotContext) => string;
287
+ /** Per-route AOT entry in the manifest. */
288
+ interface AotRouteEntry {
289
+ /** The pre-compiled render function. */
290
+ render: AotRenderFn;
291
+ /** Component names that need runtime fallback (holes). */
292
+ holes: string[];
293
+ /** Query cache keys this route reads via ctx.getData(). */
294
+ queryKeys?: string[];
295
+ }
273
296
  /**
274
- * Render a VNode to a full HTML string.
275
- *
276
- * This is a wrapper around renderPage() that provides a simpler API for
277
- * theme and style injection.
278
- *
279
- * @param options - Render options including app, url, theme, styles, head
280
- * @returns Promise<string> - The rendered HTML string
281
- *
282
- * @example
283
- * ```ts
284
- * import { renderToHTML, defineTheme } from '@vertz/ui-server';
285
- *
286
- * const theme = defineTheme({
287
- * colors: { primary: { DEFAULT: '#3b82f6' } }
288
- * });
297
+ * AOT manifest maps route patterns to pre-compiled render functions.
289
298
  *
290
- * const html = await renderToHTML({
291
- * app: App,
292
- * url: '/',
293
- * theme,
294
- * styles: ['body { margin: 0; }'],
295
- * head: { title: 'My App' }
296
- * });
297
- * ```
299
+ * Generated at build time by the AOT compiler pipeline.
298
300
  */
299
- declare function renderToHTML<AppFn extends () => VNode>(options: RenderToHTMLOptions<AppFn>): Promise<string>;
300
- /**
301
- * @deprecated Use the options-object overload: `renderToHTML({ app, url, ... })`
302
- */
303
- declare function renderToHTML<AppFn extends () => VNode>(app: AppFn, options: RenderToHTMLOptions<AppFn>): Promise<string>;
301
+ interface AotManifest {
302
+ /** Route pattern → AOT entry. */
303
+ routes: Record<string, AotRouteEntry>;
304
+ }
305
+ /** Options for `ssrRenderAot()`. */
306
+ interface SSRRenderAotOptions {
307
+ /** AOT manifest with pre-compiled render functions. */
308
+ aotManifest: AotManifest;
309
+ /** Prefetch manifest for route matching and data fetching. */
310
+ manifest?: SSRPrefetchManifest;
311
+ /** SSR timeout in ms. */
312
+ ssrTimeout?: number;
313
+ /** Pre-computed font fallback metrics. */
314
+ fallbackMetrics?: Record<string, FontFallbackMetrics3>;
315
+ /** Auth state resolved from session cookie. */
316
+ ssrAuth?: SSRAuth2;
317
+ /** Session data for access rule evaluation. */
318
+ prefetchSession?: PrefetchSession;
319
+ /** AOT diagnostics collector (dev mode). When provided with VERTZ_DEBUG=aot, enables dual rendering and divergence detection. */
320
+ diagnostics?: AotDiagnostics;
321
+ }
304
322
  /**
305
- * Render a VNode tree to a `ReadableStream` of HTML chunks.
306
- *
307
- * This is the main SSR entry point. It walks the virtual tree, serializing
308
- * synchronous content immediately and deferring Suspense boundaries.
323
+ * Create closure-based runtime fallback renderers for components
324
+ * that cannot be AOT-compiled.
309
325
  *
310
- * Suspense boundaries emit:
311
- * 1. A `<div id="v-slot-N">fallback</div>` placeholder inline
312
- * 2. A `<template id="v-tmpl-N">resolved</template><script>...<\/script>` chunk
313
- * appended after the main content once the async content resolves
326
+ * Each hole closure:
327
+ * 1. Runs inside `ssrStorage.run()` to provide SSRRenderContext
328
+ * 2. Calls the component factory via the SSR module
329
+ * 3. Converts the result to VNode and serializes to HTML string
330
+ * 4. Shares the query cache with the AOT function
314
331
  *
315
- * This enables out-of-order streaming: the browser can paint the fallback
316
- * immediately and swap in the resolved content when it arrives.
332
+ * @param holeNames - Component names that need runtime rendering
333
+ * @param module - SSR module with component factories
334
+ * @param url - Request URL for context
335
+ * @param queryCache - Pre-populated query cache (shared with AOT)
336
+ * @param ssrAuth - Auth state for the request
317
337
  */
318
- declare function renderToStream(tree: VNode | string | RawHtml, options?: RenderToStreamOptions): ReadableStream<Uint8Array>;
319
- /** Reset the slot counter (for testing). */
320
- declare function resetSlotCounter(): void;
338
+ declare function createHoles(holeNames: string[], module: SSRModule, url: string, queryCache: Map<string, unknown>, ssrAuth?: SSRAuth2): Record<string, () => string>;
321
339
  /**
322
- * Create a Suspense slot placeholder.
340
+ * Render a page using pre-compiled AOT string-builder functions.
323
341
  *
324
- * Wraps fallback content in a `<div id="v-slot-N">` so it can later
325
- * be replaced by the resolved async content via a template chunk.
342
+ * Falls back to `ssrRenderSinglePass()` when:
343
+ * - No route match in the AOT manifest
344
+ * - No prefetch manifest for route matching
326
345
  *
327
- * Returns the placeholder VNode and the assigned slot ID.
346
+ * Pipeline:
347
+ * 1. Match URL to route pattern
348
+ * 2. Look up AOT entry in manifest
349
+ * 3. Prefetch query data (reuses single-pass prefetch logic)
350
+ * 4. Create runtime holes (closures for non-AOT components)
351
+ * 5. Call AOT render function with data + context
352
+ * 6. Collect CSS, ssrData, headTags
353
+ * 7. Return SSRRenderResult
328
354
  */
329
- declare function createSlotPlaceholder(fallback: VNode | string): VNode & {
330
- _slotId: number;
331
- };
355
+ declare function ssrRenderAot(module: SSRModule, url: string, options: SSRRenderAotOptions): Promise<SSRRenderResult>;
356
+ /** Check if VERTZ_DEBUG includes the 'aot' category. */
357
+ declare function isAotDebugEnabled(): boolean;
358
+ import { AccessSet } from "@vertz/ui/auth";
359
+ interface SessionData {
360
+ user: {
361
+ id: string;
362
+ email: string;
363
+ role: string;
364
+ [key: string]: unknown;
365
+ };
366
+ /** Unix timestamp in milliseconds (JWT exp * 1000). */
367
+ expiresAt: number;
368
+ }
369
+ /** Resolved session data for SSR injection. */
370
+ interface SSRSessionInfo {
371
+ session: SessionData;
372
+ /**
373
+ * Access set from JWT acl claim.
374
+ * - Present (object): inline access set (no overflow)
375
+ * - null: access control is configured but the set overflowed the JWT
376
+ * - undefined: access control is not configured
377
+ */
378
+ accessSet?: AccessSet | null;
379
+ }
332
380
  /**
333
- * SSR prefetch access rule evaluator.
334
- *
335
- * Evaluates serialized entity access rules against the current session
336
- * to determine whether a query should be prefetched during SSR.
337
- *
338
- * The serialized rules come from the prefetch manifest (generated at build time).
339
- * The session comes from the JWT decoded at request time.
381
+ * Callback that extracts session data from a request.
382
+ * Returns null when no valid session exists (expired, missing, or invalid cookie).
340
383
  */
384
+ type SessionResolver = (request: Request) => Promise<SSRSessionInfo | null>;
341
385
  /**
342
- * Serialized access rule the JSON-friendly format stored in the manifest.
343
- * Mirrors SerializedRule from @vertz/server/auth/rules but defined here
344
- * to avoid importing the server package into the SSR pipeline.
386
+ * Serialize a session into a `<script>` tag that sets
387
+ * `window.__VERTZ_SESSION__`.
388
+ *
389
+ * @param session - The session data to serialize
390
+ * @param nonce - Optional CSP nonce for the script tag
345
391
  */
346
- type SerializedAccessRule = {
347
- type: "public";
348
- } | {
349
- type: "authenticated";
350
- } | {
351
- type: "role";
352
- roles: string[];
353
- } | {
354
- type: "entitlement";
355
- value: string;
356
- } | {
357
- type: "where";
358
- conditions: Record<string, unknown>;
359
- } | {
360
- type: "all";
361
- rules: SerializedAccessRule[];
362
- } | {
363
- type: "any";
364
- rules: SerializedAccessRule[];
365
- } | {
366
- type: "fva";
367
- maxAge: number;
368
- } | {
369
- type: "deny";
370
- };
392
+ declare function createSessionScript(session: SessionData, nonce?: string): string;
393
+ interface SSRHandlerOptions {
394
+ /** The loaded SSR module (import('./dist/server/index.js')) */
395
+ module: SSRModule;
396
+ /** HTML template string (contents of dist/client/index.html) */
397
+ template: string;
398
+ /** SSR timeout for queries (default: 300ms) */
399
+ ssrTimeout?: number;
400
+ /**
401
+ * Map of CSS asset URLs to their content for inlining.
402
+ * Replaces `<link rel="stylesheet" href="...">` tags with inline `<style>` tags.
403
+ * Eliminates extra network requests, preventing FOUC on slow connections.
404
+ *
405
+ * @example
406
+ * ```ts
407
+ * inlineCSS: { '/assets/vertz.css': await Bun.file('./dist/client/assets/vertz.css').text() }
408
+ * ```
409
+ */
410
+ inlineCSS?: Record<string, string>;
411
+ /**
412
+ * CSP nonce to inject on all inline `<script>` tags emitted during SSR.
413
+ *
414
+ * When set, the SSR data hydration script will include `nonce="<value>"`
415
+ * so that strict Content-Security-Policy headers do not block it.
416
+ */
417
+ nonce?: string;
418
+ /** Pre-computed font fallback metrics (computed at server startup). */
419
+ fallbackMetrics?: Record<string, FontFallbackMetrics4>;
420
+ /** Paths to inject as `<link rel="modulepreload">` in `<head>`. */
421
+ modulepreload?: string[];
422
+ /**
423
+ * Route chunk manifest for per-route modulepreload injection.
424
+ * When provided, only chunks for the matched route are preloaded instead of all chunks.
425
+ */
426
+ routeChunkManifest?: {
427
+ routes: Record<string, string[]>;
428
+ };
429
+ /** Cache-Control header for HTML responses. Omit or undefined = no header (safe default). */
430
+ cacheControl?: string;
431
+ /**
432
+ * Resolves session data from request cookies for SSR injection.
433
+ * When provided, SSR HTML includes `window.__VERTZ_SESSION__` and
434
+ * optionally `window.__VERTZ_ACCESS_SET__` for instant auth hydration.
435
+ */
436
+ sessionResolver?: SessionResolver;
437
+ /**
438
+ * Prefetch manifest for single-pass SSR optimization.
439
+ *
440
+ * When provided with route entries and an API client export, enables
441
+ * zero-discovery rendering — queries are prefetched from the manifest
442
+ * without executing the component tree, then a single render pass
443
+ * produces the HTML. Without a manifest, SSR still uses the single-pass
444
+ * discovery-then-render approach (cheaper than two-pass).
445
+ */
446
+ manifest?: SSRPrefetchManifest;
447
+ /**
448
+ * Enable progressive HTML streaming. Default: false.
449
+ *
450
+ * When true, the Response body is a ReadableStream that sends `<head>`
451
+ * content (CSS, preloads, fonts) before `<body>` rendering is complete.
452
+ * This improves TTFB and FCP.
453
+ *
454
+ * Has no effect on zero-discovery routes (manifest with routeEntries),
455
+ * which always use buffered rendering.
456
+ */
457
+ progressiveHTML?: boolean;
458
+ /**
459
+ * AOT manifest with pre-compiled render functions.
460
+ *
461
+ * When provided, routes matching AOT entries are rendered via string-builder
462
+ * functions (no DOM shim), bypassing the reactive runtime for 4-6x speedup.
463
+ * Routes not in the manifest fall back to `ssrRenderSinglePass()`.
464
+ *
465
+ * Load via `loadAotManifest(serverDir)` at startup.
466
+ */
467
+ aotManifest?: AotManifest;
468
+ }
469
+ declare function createSSRHandler(options: SSRHandlerOptions): (request: Request) => Promise<Response>;
470
+ type NodeHandlerOptions = SSRHandlerOptions;
471
+ declare function createNodeHandler(options: NodeHandlerOptions): (req: IncomingMessage, res: ServerResponse) => void;
472
+ import { FallbackFontName as FallbackFontName2, FontFallbackMetrics as FontFallbackMetrics7 } from "@vertz/ui";
473
+ import { ExtractedRoute } from "@vertz/ui-compiler";
474
+ import { extractRoutes } from "@vertz/ui-compiler";
475
+ import { AotComponentInfo } from "@vertz/ui-compiler";
476
+ interface AotBuildComponentEntry {
477
+ tier: "static" | "data-driven" | "conditional" | "runtime-fallback";
478
+ holes: string[];
479
+ queryKeys: string[];
480
+ }
481
+ /** Compiled file output from AOT compilation. */
482
+ interface AotCompiledFile {
483
+ /** Transformed source code containing __ssr_* functions. */
484
+ code: string;
485
+ /** Per-component AOT info from the compilation. */
486
+ components: AotComponentInfo[];
487
+ }
488
+ /** Route map entry for the AOT manifest JSON. */
489
+ interface AotRouteMapEntry {
490
+ /** Name of the __ssr_* render function (e.g., '__ssr_HomePage'). */
491
+ renderFn: string;
492
+ /** Component names that need runtime fallback rendering. */
493
+ holes: string[];
494
+ /** Query cache keys this route reads via ctx.getData(). */
495
+ queryKeys: string[];
496
+ }
497
+ interface AotBuildManifest {
498
+ components: Record<string, AotBuildComponentEntry>;
499
+ /** Compiled files keyed by source file path. */
500
+ compiledFiles: Record<string, AotCompiledFile>;
501
+ classificationLog: string[];
502
+ }
371
503
  /**
372
- * Minimal session shape needed for prefetch access evaluation.
373
- * Extracted from the JWT at SSR request time.
504
+ * Scan all TSX files in srcDir and generate an AOT build manifest.
374
505
  */
375
- type PrefetchSession = {
376
- status: "authenticated";
377
- roles?: string[];
378
- entitlements?: Record<string, boolean>;
379
- tenantId?: string;
380
- } | {
381
- status: "unauthenticated";
382
- };
506
+ declare function generateAotBuildManifest(srcDir: string): AotBuildManifest;
383
507
  /**
384
- * Minimal shape of an AccessSet for entitlement extraction.
385
- * Avoids importing @vertz/server types into the SSR pipeline.
508
+ * Build AOT route map maps route patterns to render function names.
509
+ *
510
+ * Skips routes for runtime-fallback components (they can't be AOT-rendered)
511
+ * and routes for unknown components (not found in AOT manifest).
386
512
  */
387
- interface AccessSetLike {
388
- entitlements: Record<string, {
389
- allowed: boolean;
390
- }>;
513
+ declare function buildAotRouteMap(components: Record<string, AotBuildComponentEntry>, routes: Array<{
514
+ pattern: string;
515
+ componentName: string;
516
+ }>): Record<string, AotRouteMapEntry>;
517
+ /** Result of barrel generation — barrel source + file mapping for temp dir. */
518
+ interface AotBarrelResult {
519
+ /** Barrel module source code (import/re-statements). */
520
+ barrelSource: string;
521
+ /**
522
+ * Mapping of temp file names → compiled source code.
523
+ * Write each entry as `<tempDir>/<filename>.ts` alongside the barrel.
524
+ */
525
+ files: Record<string, string>;
391
526
  }
392
527
  /**
393
- * Convert SSRAuth (from the JWT/session resolver) to PrefetchSession
394
- * for entity access evaluation during SSR prefetching.
528
+ * Generate a barrel module that re-exports __ssr_* functions from compiled files.
395
529
  *
396
- * @param ssrAuth - Auth state from session resolver
397
- * @param accessSet - Access set from JWT acl claim (null = overflow, undefined = not configured)
530
+ * Returns the barrel source code and a mapping of temp filenames → compiled code
531
+ * that must be written alongside the barrel for bundling.
398
532
  */
399
- declare function toPrefetchSession(ssrAuth: {
400
- status: string;
401
- user?: {
402
- role?: string;
403
- [key: string]: unknown;
404
- };
405
- } | undefined, accessSet?: AccessSetLike | null): PrefetchSession;
533
+ declare function generateAotBarrel(compiledFiles: Record<string, AotCompiledFile>, routeMap: Record<string, AotRouteMapEntry>): AotBarrelResult;
406
534
  /**
407
- * Evaluate a serialized access rule against the current session.
535
+ * Load AOT manifest and routes module from a server build directory.
408
536
  *
409
- * Returns true if the query is eligible for prefetch (the user
410
- * likely has access), false if it should be skipped.
537
+ * Returns `null` if either `aot-manifest.json` or `aot-routes.js` is missing,
538
+ * or if no routes can be wired to render functions.
411
539
  *
412
- * Design rationale for specific rule types:
413
- * - `where` → true: row-level filter, not an access gate. The query
414
- * always executes; it just returns fewer rows for non-owners.
415
- * - `fva` → optimistic for authenticated users: MFA freshness is
416
- * enforced on the actual API call. If the check fails server-side,
417
- * the query returns an error result.
418
- * - `deny` → false: explicitly denied operations are never prefetched.
419
- * - Unknown types → false: fail-secure. Don't prefetch if we can't
420
- * evaluate the rule.
540
+ * @param serverDir - Path to `dist/server/` directory
421
541
  */
422
- declare function evaluateAccessRule(rule: SerializedAccessRule, session: PrefetchSession): boolean;
423
- import { AccessSet } from "@vertz/ui/auth";
542
+ declare function loadAotManifest(serverDir: string): Promise<AotManifest | null>;
543
+ /** A raw HTML string that bypasses escaping during serialization. */
544
+ interface RawHtml {
545
+ __raw: true;
546
+ html: string;
547
+ }
424
548
  /**
425
- * Extract an AccessSet from a decoded JWT payload for SSR injection.
549
+ * Create a raw HTML string that will NOT be escaped during SSR serialization.
426
550
  *
427
- * - If the JWT has an inline `acl.set` (no overflow), returns the decoded AccessSet.
428
- * - If `acl.overflow` is true, returns `null` caller should re-compute from live stores.
429
- * - If no `acl` claim exists, returns `null`.
551
+ * **WARNING: XSS RISK** This function bypasses all HTML escaping. Never pass
552
+ * user-controlled input directly. Always sanitize with a trusted library (e.g.
553
+ * DOMPurify) before wrapping in `rawHtml()`.
430
554
  *
431
- * @param jwtPayload - The decoded JWT payload (from verifyJWT)
432
- * @returns The AccessSet for SSR injection, or null
555
+ * @example Safe usage
556
+ * ```ts
557
+ * rawHtml('<svg>...</svg>') // static markup — OK
558
+ * rawHtml(DOMPurify.sanitize(userInput)) // sanitized — OK
559
+ * ```
560
+ *
561
+ * @example Unsafe usage — NEVER do this
562
+ * ```ts
563
+ * rawHtml(userInput) // XSS vulnerability
564
+ * rawHtml(`<div>${userInput}</div>`) // XSS via interpolation
565
+ * ```
433
566
  */
434
- declare function getAccessSetForSSR(jwtPayload: Record<string, unknown> | null): AccessSet | null;
567
+ declare function rawHtml(html: string): RawHtml;
568
+ /** Virtual node representing an HTML element for SSR serialization. */
569
+ interface VNode {
570
+ tag: string;
571
+ attrs: Record<string, string>;
572
+ children: (VNode | string | RawHtml)[];
573
+ }
574
+ /** Options for hydration marker generation. */
575
+ interface HydrationOptions {
576
+ /** Component name for `data-v-id`. */
577
+ componentName: string;
578
+ /** Unique key for `data-v-key`. */
579
+ key: string;
580
+ /** Serialized props to embed as JSON. */
581
+ props?: Record<string, unknown>;
582
+ }
583
+ /** Metadata collected by the Head component during rendering. */
584
+ interface HeadEntry {
585
+ tag: "title" | "meta" | "link";
586
+ attrs?: Record<string, string>;
587
+ textContent?: string;
588
+ }
589
+ /** Options for {@link renderToStream}. */
590
+ interface RenderToStreamOptions {
591
+ /**
592
+ * CSP nonce to inject on all inline `<script>` tags emitted during SSR.
593
+ *
594
+ * When set, every inline script (e.g. Suspense replacement scripts) will
595
+ * include `nonce="<value>"` so that strict Content-Security-Policy headers
596
+ * do not block them.
597
+ */
598
+ nonce?: string;
599
+ }
600
+ /** Asset descriptor for script/stylesheet injection. */
601
+ interface AssetDescriptor {
602
+ type: "script" | "stylesheet";
603
+ src: string;
604
+ /** Whether to add `async` attribute (scripts only). */
605
+ async?: boolean;
606
+ /** Whether to add `defer` attribute (scripts only). */
607
+ defer?: boolean;
608
+ }
435
609
  /**
436
- * Serialize an AccessSet into a `<script>` tag that sets
437
- * `window.__VERTZ_ACCESS_SET__`.
610
+ * Render asset descriptors to HTML tags for script/stylesheet injection.
438
611
  *
439
- * @param accessSet - The access set to serialize
440
- * @param nonce - Optional CSP nonce for the script tag
612
+ * - Scripts: `<script src="..." [async] [defer]><\/script>`
613
+ * - Stylesheets: `<link rel="stylesheet" href="...">`
441
614
  */
442
- declare function createAccessSetScript(accessSet: AccessSet, nonce?: string): string;
443
- import { RenderAdapter } from "@vertz/ui/internals";
615
+ declare function renderAssetTags(assets: AssetDescriptor[]): string;
444
616
  /**
445
- * Create an SSR adapter that uses in-memory SSR node classes.
446
- * Replaces `installDomShim()` — no global mutation needed.
617
+ * Inline critical CSS as a `<style>` tag.
618
+ *
619
+ * Wraps the provided CSS in `<style>...</style>` for embedding in the HTML head.
620
+ * Escapes any `</style>` sequences in the CSS content to prevent injection.
621
+ *
622
+ * Returns an empty string if the CSS is empty.
447
623
  */
448
- declare function createSSRAdapter(): RenderAdapter;
624
+ declare function inlineCriticalCss(css: string): string;
625
+ import { FallbackFontName, FontDescriptor, FontFallbackMetrics as FontFallbackMetrics5 } from "@vertz/ui";
449
626
  /**
450
- * AOT SSR Diagnostics
627
+ * Auto-detect which system font to use as fallback base.
451
628
  *
452
- * Tracks AOT compilation results and provides a JSON snapshot
453
- * for the `/__vertz_ssr_aot` dev endpoint.
629
+ * Scans the `fallback` array for generic CSS font family keywords:
630
+ * - 'sans-serif' or 'system-ui' → Arial
631
+ * - 'serif' → Times New Roman
632
+ * - 'monospace' → Courier New
633
+ *
634
+ * Skips non-generic entries (e.g., 'Georgia', 'Helvetica').
635
+ * If no generic keyword found, defaults to Arial.
454
636
  */
455
- /** AOT tier classification (mirrored from @vertz/ui-compiler to avoid cross-package dependency). */
456
- type AotTier = "static" | "data-driven" | "conditional" | "runtime-fallback";
457
- /** Per-component diagnostic entry in the snapshot. */
458
- interface AotComponentDiagnostic {
459
- tier: AotTier;
460
- holes: string[];
461
- }
462
- /** A recorded divergence between AOT and DOM shim output. */
463
- interface AotDivergenceEntry {
464
- component: string;
465
- aotHtml: string;
466
- domHtml: string;
467
- timestamp: string;
468
- }
469
- /** JSON snapshot returned by the `/__vertz_ssr_aot` endpoint. */
470
- interface AotDiagnosticsSnapshot {
471
- components: Record<string, AotComponentDiagnostic>;
472
- coverage: {
473
- total: number;
474
- aot: number;
475
- runtime: number;
476
- percentage: number;
477
- };
478
- divergences: AotDivergenceEntry[];
479
- }
480
- /** Input shape matching AotComponentInfo from @vertz/ui-compiler. */
481
- interface ComponentInput {
482
- name: string;
483
- tier: AotTier;
484
- holes: string[];
485
- }
637
+ declare function detectFallbackFont(fallback: readonly string[]): FallbackFontName;
486
638
  /**
487
- * Collects AOT compilation diagnostics and produces JSON snapshots.
639
+ * Extract font metrics from .woff2 files and compute CSS fallback overrides.
488
640
  *
489
- * Used by the dev server to power the `/__vertz_ssr_aot` endpoint
490
- * and by the build pipeline for classification logging.
641
+ * @param fonts - Font descriptors from theme definition.
642
+ * @param rootDir - Project root directory for resolving font file paths.
643
+ * @returns Map of font key → computed fallback metrics.
491
644
  */
492
- declare class AotDiagnostics {
493
- private _components;
494
- private _divergences;
495
- /**
496
- * Record components from an AOT compilation result.
497
- * Called once per file during compilation or hot rebuild.
498
- */
499
- recordCompilation(components: ComponentInput[]): void;
500
- /** Record a divergence between AOT and DOM shim HTML output. */
501
- recordDivergence(component: string, aotHtml: string, domHtml: string): void;
502
- /** Clear all recorded data (used during full rebuild). */
645
+ declare function extractFontMetrics(fonts: Record<string, FontDescriptor>, rootDir: string): Promise<Record<string, FontFallbackMetrics5>>;
646
+ /**
647
+ * Collector for `<head>` metadata during SSR.
648
+ *
649
+ * Components call `addTitle`, `addMeta`, or `addLink` during render,
650
+ * and the collected entries are serialized into the HTML `<head>` section.
651
+ */
652
+ declare class HeadCollector {
653
+ private entries;
654
+ /** Add a `<title>` entry. */
655
+ addTitle(text: string): void;
656
+ /** Add a `<meta>` entry. */
657
+ addMeta(attrs: Record<string, string>): void;
658
+ /** Add a `<link>` entry. */
659
+ addLink(attrs: Record<string, string>): void;
660
+ /** Get all collected entries. */
661
+ getEntries(): HeadEntry[];
662
+ /** Clear all collected entries. */
503
663
  clear(): void;
504
- /** Clear only component classifications (preserves divergences). */
505
- clearComponents(): void;
506
- /**
507
- * Generate per-component classification log lines.
508
- * Used by the build pipeline and VERTZ_DEBUG=aot logging.
509
- *
510
- * Returns lines like:
511
- * - "Header: static"
512
- * - "Dashboard: conditional, 1 hole (SidePanel)"
513
- * - "Coverage: 3/4 components (75%)"
514
- */
515
- getClassificationLog(): string[];
516
- /** Produce a JSON-serializable snapshot for the diagnostic endpoint. */
517
- getSnapshot(): AotDiagnosticsSnapshot;
518
664
  }
519
- /** Per-component entry in the dev AOT manifest. */
520
- interface AotDevComponentEntry {
521
- tier: "static" | "data-driven" | "conditional" | "runtime-fallback";
522
- holes: string[];
523
- /** The file this component was compiled from. */
524
- file: string;
525
- }
526
- /** Dev-mode AOT manifest — tracks all components across all files. */
527
- interface AotDevManifest {
528
- components: Record<string, AotDevComponentEntry>;
529
- }
530
- interface AotManifestSnapshot {
531
- manifest: AotDevManifest | null;
532
- rebuildCount: number;
533
- lastRebuildMs: number | null;
534
- lastRebuildAt: string | null;
535
- }
536
- interface AotManifestManagerOptions {
537
- /** Read a file's contents. Returns undefined if file doesn't exist. */
538
- readFile: (path: string) => string | undefined;
539
- /** List all files in the source directory (absolute paths). */
540
- listFiles: () => string[];
541
- }
542
- interface AotManifestManager {
543
- /** Initial full build — compile all TSX files. */
544
- build(): void;
545
- /** Handle a file change — recompile a single file. */
546
- onFileChange(filePath: string, sourceText: string): void;
547
- /** Get the current manifest (atomic read). */
548
- getManifest(): AotDevManifest | null;
549
- /** Get diagnostic snapshot for endpoints. */
550
- getSnapshot(): AotManifestSnapshot;
551
- /** Get AotDiagnostics instance for the diagnostics endpoint. */
552
- getDiagnostics(): AotDiagnostics;
665
+ /**
666
+ * Render head entries to an HTML string.
667
+ *
668
+ * - `<title>` renders as `<title>text</title>`
669
+ * - `<meta>` and `<link>` render as void elements
670
+ */
671
+ declare function renderHeadToHtml(entries: HeadEntry[]): string;
672
+ /**
673
+ * Serialize a VNode tree (or plain string) to an HTML string.
674
+ *
675
+ * This is the core serialization function for SSR. It walks the virtual tree
676
+ * recursively and produces an HTML string without requiring a real DOM.
677
+ *
678
+ * - Text content inside `<script>` and `<style>` tags is not escaped.
679
+ * - `RawHtml` values bypass escaping entirely.
680
+ */
681
+ declare function serializeToHtml(node: VNode | string | RawHtml): string;
682
+ /**
683
+ * Wrap a VNode with hydration markers for interactive components.
684
+ *
685
+ * Adds `data-v-id` and `data-v-key` attributes to the root element,
686
+ * and optionally embeds serialized props as a `<script type="application/json">` child.
687
+ *
688
+ * Returns a new VNode; the original is not mutated.
689
+ */
690
+ declare function wrapWithHydrationMarkers(node: VNode, options: HydrationOptions): VNode;
691
+ interface PageOptions {
692
+ /** HTTP status code (default: 200) */
693
+ status?: number;
694
+ /** Page title */
695
+ title?: string;
696
+ /** Meta description */
697
+ description?: string;
698
+ /** Language attribute (default: 'en') */
699
+ lang?: string;
700
+ /** Favicon URL */
701
+ favicon?: string;
702
+ /** Open Graph meta tags */
703
+ og?: {
704
+ /** OG title (falls back to title) */
705
+ title?: string;
706
+ /** OG description (falls back to description) */
707
+ description?: string;
708
+ /** OG image URL */
709
+ image?: string;
710
+ /** OG canonical URL */
711
+ url?: string;
712
+ /** OG type (default: 'website') */
713
+ type?: string;
714
+ };
715
+ /** Twitter card meta tags */
716
+ twitter?: {
717
+ /** Twitter card type */
718
+ card?: string;
719
+ /** Twitter @username */
720
+ site?: string;
721
+ };
722
+ /** Array of script URLs to include at end of body */
723
+ scripts?: string[];
724
+ /** Array of stylesheet URLs to include in head */
725
+ styles?: string[];
726
+ /** Raw HTML escape hatch for head */
727
+ head?: string;
553
728
  }
554
- declare function createAotManifestManager(options: AotManifestManagerOptions): AotManifestManager;
555
- import { FontFallbackMetrics as FontFallbackMetrics5 } from "@vertz/ui";
556
- import { SSRAuth as SSRAuth2 } from "@vertz/ui/internals";
557
- import { CompiledRoute, FontFallbackMetrics as FontFallbackMetrics3, Theme as Theme2 } from "@vertz/ui";
558
- import { SSRAuth as SSRAuth_jq1nwm } from "@vertz/ui/internals";
559
- interface SSRModule {
560
- default?: () => unknown;
561
- App?: () => unknown;
729
+ /**
730
+ * Render a VNode to a full HTML Response with common page structure.
731
+ *
732
+ * This is the main entry point for zero-boilerplate SSR. It wraps the component
733
+ * in a complete HTML document with doctype, head (meta, OG, Twitter, favicon,
734
+ * styles), and body (component content + scripts).
735
+ *
736
+ * @param vnode - The root VNode to render
737
+ * @param options - Optional page configuration
738
+ * @returns A Response with text/html content-type
739
+ *
740
+ * @example
741
+ * ```ts
742
+ * // Minimal usage
743
+ * return renderPage(App)
744
+ *
745
+ * // Full options
746
+ * return renderPage(App, {
747
+ * title: 'My App',
748
+ * description: 'Built with vertz',
749
+ * og: { image: '/og.png' },
750
+ * scripts: ['/app.js'],
751
+ * styles: ['/app.css'],
752
+ * })
753
+ * ```
754
+ */
755
+ declare function renderPage(vnode: VNode, options?: PageOptions): Response;
756
+ import { FontFallbackMetrics as FontFallbackMetrics6, Theme as Theme2 } from "@vertz/ui";
757
+ interface RenderToHTMLOptions<AppFn extends () => VNode> {
758
+ /** The app component function */
759
+ app: AppFn;
760
+ /** Request URL for SSR */
761
+ url: string;
762
+ /** Theme definition for CSS vars */
562
763
  theme?: Theme2;
563
- /** Global CSS strings to include in every SSR response (e.g. resets, body styles). */
764
+ /** Global CSS strings to inject */
564
765
  styles?: string[];
565
- /**
566
- * Return all CSS tracked by the bundled @vertz/ui instance.
567
- * The Vite SSR build inlines @vertz/ui into the server bundle, creating
568
- * a separate module instance from @vertz/ui-server's dependency. Without
569
- * this, component CSS from module-level css() calls is invisible to the
570
- * SSR renderer. Export `getInjectedCSS` from @vertz/ui in the app entry.
571
- */
572
- getInjectedCSS?: () => string[];
573
- /** Compiled routes exported from the app for build-time SSG with generateParams. */
574
- routes?: CompiledRoute[];
575
- /** Code-generated API client for manifest-driven zero-discovery prefetching. */
576
- api?: Record<string, Record<string, (...args: unknown[]) => unknown>>;
577
- }
578
- interface SSRRenderResult {
579
- html: string;
580
- css: string;
581
- ssrData: Array<{
582
- key: string;
583
- data: unknown;
584
- }>;
585
- /** Font preload link tags for injection into <head>. */
586
- headTags: string;
587
- /** Route patterns discovered by createRouter() during SSR (for build-time pre-rendering). */
588
- discoveredRoutes?: string[];
589
- /** Route patterns that matched the current URL (for per-route modulepreload). */
590
- matchedRoutePatterns?: string[];
591
- /** Set when ProtectedRoute writes a redirect during SSR. Server should return 302. */
592
- redirect?: {
593
- to: string;
766
+ /** HTML head configuration */
767
+ head?: {
768
+ title?: string;
769
+ meta?: Array<{
770
+ name?: string;
771
+ property?: string;
772
+ content: string;
773
+ }>;
774
+ links?: Array<{
775
+ rel: string;
776
+ href: string;
777
+ }>;
594
778
  };
779
+ /** Container selector (default '#app') */
780
+ container?: string;
781
+ /** Pre-computed font fallback metrics (computed at server startup). */
782
+ fallbackMetrics?: Record<string, FontFallbackMetrics6>;
595
783
  }
596
- interface SSRDiscoverResult {
597
- resolved: Array<{
598
- key: string;
599
- data: unknown;
600
- }>;
601
- pending: string[];
784
+ interface RenderToHTMLStreamOptions<AppFn extends () => VNode> extends RenderToHTMLOptions<AppFn> {
785
+ /** CSP nonce for inline scripts */
786
+ nonce?: string;
787
+ /** Global default for per-query ssrTimeout (ms) */
788
+ ssrTimeout?: number;
789
+ /** Hard timeout for entire stream (ms, default 30000) */
790
+ streamTimeout?: number;
602
791
  }
603
792
  /**
604
- * Render an SSR module to an HTML string with CSS and pre-fetched query data.
793
+ * Render a component to a streaming HTML Response.
605
794
  *
606
- * Performs a two-pass render:
607
- * - Pass 1: Discovery calls the app to trigger query() registrations, awaits them
608
- * - Pass 2: Render — calls the app again with data populated, renders to HTML
795
+ * The initial HTML is sent immediately. For slow queries that timed out
796
+ * during SSR, their resolved data is streamed as inline `<script>` chunks
797
+ * that push data to the client's reactive system.
798
+ *
799
+ * @returns Promise<Response> - A streaming Response with text/html content
609
800
  */
610
- declare function ssrRenderToString(module: SSRModule, url: string, options?: {
611
- ssrTimeout?: number;
612
- /** Pre-computed font fallback metrics (computed at server startup). */
613
- fallbackMetrics?: Record<string, FontFallbackMetrics3>;
614
- /** Auth state resolved from session cookie. Passed to SSRRenderContext for AuthProvider. */
615
- ssrAuth?: SSRAuth_jq1nwm;
616
- }): Promise<SSRRenderResult>;
801
+ declare function renderToHTMLStream<AppFn extends () => VNode>(options: RenderToHTMLStreamOptions<AppFn>): Promise<Response>;
617
802
  /**
618
- * Discover queries for a given URL without rendering.
619
- * Runs only Pass 1 (query registration + resolution), no Pass 2 render.
620
- * Used by the production handler to pre-fetch query data for client-side navigations.
803
+ * Render a VNode to a full HTML string.
804
+ *
805
+ * This is a wrapper around renderPage() that provides a simpler API for
806
+ * theme and style injection.
807
+ *
808
+ * @param options - Render options including app, url, theme, styles, head
809
+ * @returns Promise<string> - The rendered HTML string
810
+ *
811
+ * @example
812
+ * ```ts
813
+ * import { renderToHTML, defineTheme } from '@vertz/ui-server';
814
+ *
815
+ * const theme = defineTheme({
816
+ * colors: { primary: { DEFAULT: '#3b82f6' } }
817
+ * });
818
+ *
819
+ * const html = await renderToHTML({
820
+ * app: App,
821
+ * url: '/',
822
+ * theme,
823
+ * styles: ['body { margin: 0; }'],
824
+ * head: { title: 'My App' }
825
+ * });
826
+ * ```
621
827
  */
622
- declare function ssrDiscoverQueries(module: SSRModule, url: string, options?: {
623
- ssrTimeout?: number;
624
- }): Promise<SSRDiscoverResult>;
625
- import { FontFallbackMetrics as FontFallbackMetrics4 } from "@vertz/ui";
626
- import { SSRAuth } from "@vertz/ui/internals";
627
- import { ExtractedQuery } from "@vertz/ui-compiler";
628
- /** Serialized entity access rules from the prefetch manifest. */
629
- type EntityAccessMap = Record<string, Partial<Record<string, SerializedAccessRule>>>;
630
- interface SSRPrefetchManifest {
631
- /** Route patterns present in the manifest. */
632
- routePatterns: string[];
633
- /** Entity access rules keyed by entity name → operation → serialized rule. */
634
- entityAccess?: EntityAccessMap;
635
- /** Route entries with query binding metadata for zero-discovery prefetch. */
636
- routeEntries?: Record<string, {
637
- queries: ExtractedQuery[];
638
- }>;
639
- }
640
- interface SSRSinglePassOptions {
641
- ssrTimeout?: number;
642
- /** Pre-computed font fallback metrics (computed at server startup). */
643
- fallbackMetrics?: Record<string, FontFallbackMetrics4>;
644
- /** Auth state resolved from session cookie. */
645
- ssrAuth?: SSRAuth;
646
- /** Set to false to fall back to two-pass rendering. Default: true. */
647
- prefetch?: boolean;
648
- /** Prefetch manifest for entity access filtering. */
649
- manifest?: SSRPrefetchManifest;
650
- /** Session data for access rule evaluation. */
651
- prefetchSession?: PrefetchSession;
652
- }
828
+ declare function renderToHTML<AppFn extends () => VNode>(options: RenderToHTMLOptions<AppFn>): Promise<string>;
829
+ /**
830
+ * @deprecated Use the options-object overload: `renderToHTML({ app, url, ... })`
831
+ */
832
+ declare function renderToHTML<AppFn extends () => VNode>(app: AppFn, options: RenderToHTMLOptions<AppFn>): Promise<string>;
653
833
  /**
654
- * Render an SSR module in a single pass via discovery-only execution.
834
+ * Render a VNode tree to a `ReadableStream` of HTML chunks.
655
835
  *
656
- * 1. Discovery: Run the app factory to capture query registrations (no stream render)
657
- * 2. Prefetch: Await all discovered queries with timeout
658
- * 3. Render: Create a fresh context with pre-populated cache, render once
836
+ * This is the main SSR entry point. It walks the virtual tree, serializing
837
+ * synchronous content immediately and deferring Suspense boundaries.
659
838
  *
660
- * Falls back to two-pass (`ssrRenderToString`) when:
661
- * - `prefetch: false` is set
662
- * - A redirect is detected during discovery
839
+ * Suspense boundaries emit:
840
+ * 1. A `<div id="v-slot-N">fallback</div>` placeholder inline
841
+ * 2. A `<template id="v-tmpl-N">resolved</template><script>...<\/script>` chunk
842
+ * appended after the main content once the async content resolves
843
+ *
844
+ * This enables out-of-order streaming: the browser can paint the fallback
845
+ * immediately and swap in the resolved content when it arrives.
663
846
  */
664
- declare function ssrRenderSinglePass(module: SSRModule, url: string, options?: SSRSinglePassOptions): Promise<SSRRenderResult>;
665
- /** Context passed to AOT render functions for accessing data and runtime holes. */
666
- interface SSRAotContext {
667
- /** Pre-generated closures for runtime-rendered components. */
668
- holes: Record<string, () => string>;
669
- /** Access query data by cache key. */
670
- getData(key: string): unknown;
671
- /** Auth session for conditional rendering. */
672
- session: PrefetchSession | undefined;
673
- /** Route params for the current request. */
674
- params: Record<string, string>;
675
- }
676
- /** An AOT render function: takes props/data and context, returns HTML string. */
677
- type AotRenderFn = (data: Record<string, unknown>, ctx: SSRAotContext) => string;
678
- /** Per-route AOT entry in the manifest. */
679
- interface AotRouteEntry {
680
- /** The pre-compiled render function. */
681
- render: AotRenderFn;
682
- /** Component names that need runtime fallback (holes). */
683
- holes: string[];
684
- /** Query cache keys this route reads via ctx.getData(). */
685
- queryKeys?: string[];
686
- }
847
+ declare function renderToStream(tree: VNode | string | RawHtml, options?: RenderToStreamOptions): ReadableStream<Uint8Array>;
848
+ /** Reset the slot counter (for testing). */
849
+ declare function resetSlotCounter(): void;
687
850
  /**
688
- * AOT manifest maps route patterns to pre-compiled render functions.
851
+ * Create a Suspense slot placeholder.
689
852
  *
690
- * Generated at build time by the AOT compiler pipeline.
853
+ * Wraps fallback content in a `<div id="v-slot-N">` so it can later
854
+ * be replaced by the resolved async content via a template chunk.
855
+ *
856
+ * Returns the placeholder VNode and the assigned slot ID.
691
857
  */
692
- interface AotManifest {
693
- /** Route pattern → AOT entry. */
694
- routes: Record<string, AotRouteEntry>;
695
- }
696
- /** Options for `ssrRenderAot()`. */
697
- interface SSRRenderAotOptions {
698
- /** AOT manifest with pre-compiled render functions. */
699
- aotManifest: AotManifest;
700
- /** Prefetch manifest for route matching and data fetching. */
701
- manifest?: SSRPrefetchManifest;
702
- /** SSR timeout in ms. */
703
- ssrTimeout?: number;
704
- /** Pre-computed font fallback metrics. */
705
- fallbackMetrics?: Record<string, FontFallbackMetrics5>;
706
- /** Auth state resolved from session cookie. */
707
- ssrAuth?: SSRAuth2;
708
- /** Session data for access rule evaluation. */
709
- prefetchSession?: PrefetchSession;
710
- /** AOT diagnostics collector (dev mode). When provided with VERTZ_DEBUG=aot, enables dual rendering and divergence detection. */
711
- diagnostics?: AotDiagnostics;
712
- }
858
+ declare function createSlotPlaceholder(fallback: VNode | string): VNode & {
859
+ _slotId: number;
860
+ };
861
+ import { AccessSet as AccessSet2 } from "@vertz/ui/auth";
713
862
  /**
714
- * Create closure-based runtime fallback renderers for components
715
- * that cannot be AOT-compiled.
863
+ * Extract an AccessSet from a decoded JWT payload for SSR injection.
716
864
  *
717
- * Each hole closure:
718
- * 1. Runs inside `ssrStorage.run()` to provide SSRRenderContext
719
- * 2. Calls the component factory via the SSR module
720
- * 3. Converts the result to VNode and serializes to HTML string
721
- * 4. Shares the query cache with the AOT function
865
+ * - If the JWT has an inline `acl.set` (no overflow), returns the decoded AccessSet.
866
+ * - If `acl.overflow` is true, returns `null` caller should re-compute from live stores.
867
+ * - If no `acl` claim exists, returns `null`.
722
868
  *
723
- * @param holeNames - Component names that need runtime rendering
724
- * @param module - SSR module with component factories
725
- * @param url - Request URL for context
726
- * @param queryCache - Pre-populated query cache (shared with AOT)
727
- * @param ssrAuth - Auth state for the request
869
+ * @param jwtPayload - The decoded JWT payload (from verifyJWT)
870
+ * @returns The AccessSet for SSR injection, or null
728
871
  */
729
- declare function createHoles(holeNames: string[], module: SSRModule, url: string, queryCache: Map<string, unknown>, ssrAuth?: SSRAuth2): Record<string, () => string>;
872
+ declare function getAccessSetForSSR(jwtPayload: Record<string, unknown> | null): AccessSet2 | null;
730
873
  /**
731
- * Render a page using pre-compiled AOT string-builder functions.
732
- *
733
- * Falls back to `ssrRenderSinglePass()` when:
734
- * - No route match in the AOT manifest
735
- * - No prefetch manifest for route matching
874
+ * Serialize an AccessSet into a `<script>` tag that sets
875
+ * `window.__VERTZ_ACCESS_SET__`.
736
876
  *
737
- * Pipeline:
738
- * 1. Match URL to route pattern
739
- * 2. Look up AOT entry in manifest
740
- * 3. Prefetch query data (reuses single-pass prefetch logic)
741
- * 4. Create runtime holes (closures for non-AOT components)
742
- * 5. Call AOT render function with data + context
743
- * 6. Collect CSS, ssrData, headTags
744
- * 7. Return SSRRenderResult
877
+ * @param accessSet - The access set to serialize
878
+ * @param nonce - Optional CSP nonce for the script tag
745
879
  */
746
- declare function ssrRenderAot(module: SSRModule, url: string, options: SSRRenderAotOptions): Promise<SSRRenderResult>;
747
- /** Check if VERTZ_DEBUG includes the 'aot' category. */
748
- declare function isAotDebugEnabled(): boolean;
880
+ declare function createAccessSetScript(accessSet: AccessSet2, nonce?: string): string;
881
+ import { RenderAdapter } from "@vertz/ui/internals";
882
+ /**
883
+ * Create an SSR adapter that uses in-memory SSR node classes.
884
+ * Replaces `installDomShim()` — no global mutation needed.
885
+ */
886
+ declare function createSSRAdapter(): RenderAdapter;
887
+ /** Per-component entry in the dev AOT manifest. */
888
+ interface AotDevComponentEntry {
889
+ tier: "static" | "data-driven" | "conditional" | "runtime-fallback";
890
+ holes: string[];
891
+ /** The file this component was compiled from. */
892
+ file: string;
893
+ }
894
+ /** Dev-mode AOT manifest — tracks all components across all files. */
895
+ interface AotDevManifest {
896
+ components: Record<string, AotDevComponentEntry>;
897
+ }
898
+ interface AotManifestSnapshot {
899
+ manifest: AotDevManifest | null;
900
+ rebuildCount: number;
901
+ lastRebuildMs: number | null;
902
+ lastRebuildAt: string | null;
903
+ }
904
+ interface AotManifestManagerOptions {
905
+ /** Read a file's contents. Returns undefined if file doesn't exist. */
906
+ readFile: (path: string) => string | undefined;
907
+ /** List all files in the source directory (absolute paths). */
908
+ listFiles: () => string[];
909
+ }
910
+ interface AotManifestManager {
911
+ /** Initial full build — compile all TSX files. */
912
+ build(): void;
913
+ /** Handle a file change — recompile a single file. */
914
+ onFileChange(filePath: string, sourceText: string): void;
915
+ /** Get the current manifest (atomic read). */
916
+ getManifest(): AotDevManifest | null;
917
+ /** Get diagnostic snapshot for endpoints. */
918
+ getSnapshot(): AotManifestSnapshot;
919
+ /** Get AotDiagnostics instance for the diagnostics endpoint. */
920
+ getDiagnostics(): AotDiagnostics;
921
+ }
922
+ declare function createAotManifestManager(options: AotManifestManagerOptions): AotManifestManager;
749
923
  /**
750
924
  * SSR AOT Runtime Helpers
751
925
  *
@@ -821,109 +995,6 @@ declare function clearGlobalSSRTimeout(): void;
821
995
  * Returns undefined if not set or outside SSR context.
822
996
  */
823
997
  declare function getGlobalSSRTimeout(): number | undefined;
824
- import { FontFallbackMetrics as FontFallbackMetrics6 } from "@vertz/ui";
825
- import { AccessSet as AccessSet2 } from "@vertz/ui/auth";
826
- interface SessionData {
827
- user: {
828
- id: string;
829
- email: string;
830
- role: string;
831
- [key: string]: unknown;
832
- };
833
- /** Unix timestamp in milliseconds (JWT exp * 1000). */
834
- expiresAt: number;
835
- }
836
- /** Resolved session data for SSR injection. */
837
- interface SSRSessionInfo {
838
- session: SessionData;
839
- /**
840
- * Access set from JWT acl claim.
841
- * - Present (object): inline access set (no overflow)
842
- * - null: access control is configured but the set overflowed the JWT
843
- * - undefined: access control is not configured
844
- */
845
- accessSet?: AccessSet2 | null;
846
- }
847
- /**
848
- * Callback that extracts session data from a request.
849
- * Returns null when no valid session exists (expired, missing, or invalid cookie).
850
- */
851
- type SessionResolver = (request: Request) => Promise<SSRSessionInfo | null>;
852
- /**
853
- * Serialize a session into a `<script>` tag that sets
854
- * `window.__VERTZ_SESSION__`.
855
- *
856
- * @param session - The session data to serialize
857
- * @param nonce - Optional CSP nonce for the script tag
858
- */
859
- declare function createSessionScript(session: SessionData, nonce?: string): string;
860
- interface SSRHandlerOptions {
861
- /** The loaded SSR module (import('./dist/server/index.js')) */
862
- module: SSRModule;
863
- /** HTML template string (contents of dist/client/index.html) */
864
- template: string;
865
- /** SSR timeout for queries (default: 300ms) */
866
- ssrTimeout?: number;
867
- /**
868
- * Map of CSS asset URLs to their content for inlining.
869
- * Replaces `<link rel="stylesheet" href="...">` tags with inline `<style>` tags.
870
- * Eliminates extra network requests, preventing FOUC on slow connections.
871
- *
872
- * @example
873
- * ```ts
874
- * inlineCSS: { '/assets/vertz.css': await Bun.file('./dist/client/assets/vertz.css').text() }
875
- * ```
876
- */
877
- inlineCSS?: Record<string, string>;
878
- /**
879
- * CSP nonce to inject on all inline `<script>` tags emitted during SSR.
880
- *
881
- * When set, the SSR data hydration script will include `nonce="<value>"`
882
- * so that strict Content-Security-Policy headers do not block it.
883
- */
884
- nonce?: string;
885
- /** Pre-computed font fallback metrics (computed at server startup). */
886
- fallbackMetrics?: Record<string, FontFallbackMetrics6>;
887
- /** Paths to inject as `<link rel="modulepreload">` in `<head>`. */
888
- modulepreload?: string[];
889
- /**
890
- * Route chunk manifest for per-route modulepreload injection.
891
- * When provided, only chunks for the matched route are preloaded instead of all chunks.
892
- */
893
- routeChunkManifest?: {
894
- routes: Record<string, string[]>;
895
- };
896
- /** Cache-Control header for HTML responses. Omit or undefined = no header (safe default). */
897
- cacheControl?: string;
898
- /**
899
- * Resolves session data from request cookies for SSR injection.
900
- * When provided, SSR HTML includes `window.__VERTZ_SESSION__` and
901
- * optionally `window.__VERTZ_ACCESS_SET__` for instant auth hydration.
902
- */
903
- sessionResolver?: SessionResolver;
904
- /**
905
- * Prefetch manifest for single-pass SSR optimization.
906
- *
907
- * When provided with route entries and an API client export, enables
908
- * zero-discovery rendering — queries are prefetched from the manifest
909
- * without executing the component tree, then a single render pass
910
- * produces the HTML. Without a manifest, SSR still uses the single-pass
911
- * discovery-then-render approach (cheaper than two-pass).
912
- */
913
- manifest?: SSRPrefetchManifest;
914
- /**
915
- * Enable progressive HTML streaming. Default: false.
916
- *
917
- * When true, the Response body is a ReadableStream that sends `<head>`
918
- * content (CSS, preloads, fonts) before `<body>` rendering is complete.
919
- * This improves TTFB and FCP.
920
- *
921
- * Has no effect on zero-discovery routes (manifest with routeEntries),
922
- * which always use buffered rendering.
923
- */
924
- progressiveHTML?: boolean;
925
- }
926
- declare function createSSRHandler(options: SSRHandlerOptions): (request: Request) => Promise<Response>;
927
998
  interface GenerateSSRHtmlOptions {
928
999
  appHtml: string;
929
1000
  css: string;
@@ -1055,4 +1126,4 @@ declare function collectStreamChunks(stream: ReadableStream<Uint8Array>): Promis
1055
1126
  * @param nonce - Optional CSP nonce to add to the inline script tag.
1056
1127
  */
1057
1128
  declare function createTemplateChunk(slotId: number, resolvedHtml: string, nonce?: string): string;
1058
- export { wrapWithHydrationMarkers, toPrefetchSession, streamToString, ssrStorage, ssrRenderToString, ssrRenderSinglePass, ssrRenderAot, ssrDiscoverQueries, setGlobalSSRTimeout, serializeToHtml, safeSerialize, resetSlotCounter, renderToStream, renderToHTMLStream, renderToHTML, renderPage, renderHeadToHtml, renderAssetTags, registerSSRQuery, reconstructDescriptors, rawHtml, matchUrlToPatterns, isInSSR, isAotDebugEnabled, inlineCriticalCss, getStreamingRuntimeScript, getSSRUrl, getSSRQueries, getGlobalSSRTimeout, getAccessSetForSSR, generateSSRHtml, generateAotBuildManifest, extractFontMetrics, evaluateAccessRule, encodeChunk, detectFallbackFont, createTemplateChunk, createSlotPlaceholder, createSessionScript, createSSRHandler, createSSRDataChunk, createSSRAdapter, createPrefetchManifestManager, createHoles, createAotManifestManager, createAccessSetScript, collectStreamChunks, clearGlobalSSRTimeout, __ssr_style_object, __ssr_spread, __esc_attr, __esc, VNode, SessionResolver, SessionData, SerializedAccessRule, SSRSinglePassOptions, SSRSessionInfo, SSRRenderResult, SSRRenderAotOptions, SSRQueryEntry2 as SSRQueryEntry, SSRPrefetchManifest, SSRModule, SSRHandlerOptions, SSRDiscoverResult, SSRAotContext, RenderToStreamOptions, RenderToHTMLStreamOptions, RenderToHTMLOptions, ReconstructedDescriptor, RawHtml, PrefetchSession, PrefetchManifestSnapshot, PrefetchManifestManagerOptions, PrefetchManifestManager, PageOptions, MatchedRoute, HydrationOptions, HeadEntry, HeadCollector, GenerateSSRHtmlOptions, FontFallbackMetrics7 as FontFallbackMetrics, FallbackFontName2 as FallbackFontName, EntityAccessMap, AssetDescriptor, AotTier, AotRouteEntry, AotRenderFn, AotManifestSnapshot, AotManifestManagerOptions, AotManifestManager, AotManifest, AotDivergenceEntry, AotDiagnosticsSnapshot, AotDiagnostics, AotDevManifest, AotDevComponentEntry, AotComponentDiagnostic, AotBuildManifest, AotBuildComponentEntry };
1129
+ export { wrapWithHydrationMarkers, toPrefetchSession, streamToString, ssrStorage, ssrRenderToString, ssrRenderSinglePass, ssrRenderAot, ssrDiscoverQueries, setGlobalSSRTimeout, serializeToHtml, safeSerialize, resetSlotCounter, renderToStream, renderToHTMLStream, renderToHTML, renderPage, renderHeadToHtml, renderAssetTags, registerSSRQuery, reconstructDescriptors, rawHtml, matchUrlToPatterns, loadAotManifest, isInSSR, isAotDebugEnabled, inlineCriticalCss, getStreamingRuntimeScript, getSSRUrl, getSSRQueries, getGlobalSSRTimeout, getAccessSetForSSR, generateSSRHtml, generateAotBuildManifest, generateAotBarrel, extractRoutes, extractFontMetrics, evaluateAccessRule, encodeChunk, detectFallbackFont, createTemplateChunk, createSlotPlaceholder, createSessionScript, createSSRHandler, createSSRDataChunk, createSSRAdapter, createPrefetchManifestManager, createNodeHandler, createHoles, createAotManifestManager, createAccessSetScript, collectStreamChunks, clearGlobalSSRTimeout, buildAotRouteMap, __ssr_style_object, __ssr_spread, __esc_attr, __esc, VNode, SessionResolver, SessionData, SerializedAccessRule, SSRSinglePassOptions, SSRSessionInfo, SSRRenderResult, SSRRenderAotOptions, SSRQueryEntry2 as SSRQueryEntry, SSRPrefetchManifest, SSRModule, SSRHandlerOptions, SSRDiscoverResult, SSRAotContext, RenderToStreamOptions, RenderToHTMLStreamOptions, RenderToHTMLOptions, ReconstructedDescriptor, RawHtml, PrefetchSession, PrefetchManifestSnapshot, PrefetchManifestManagerOptions, PrefetchManifestManager, PageOptions, NodeHandlerOptions, MatchedRoute, HydrationOptions, HeadEntry, HeadCollector, GenerateSSRHtmlOptions, FontFallbackMetrics7 as FontFallbackMetrics, FallbackFontName2 as FallbackFontName, ExtractedRoute, EntityAccessMap, AssetDescriptor, AotTier, AotRouteMapEntry, AotRouteEntry, AotRenderFn, AotManifestSnapshot, AotManifestManagerOptions, AotManifestManager, AotManifest, AotDivergenceEntry, AotDiagnosticsSnapshot, AotDiagnostics, AotDevManifest, AotDevComponentEntry, AotComponentDiagnostic, AotCompiledFile, AotBuildManifest, AotBuildComponentEntry, AotBarrelResult };