@vertz/ui-server 0.2.37 → 0.2.41

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.
@@ -335,13 +335,102 @@ function createSSRDataChunk(key, data, nonce) {
335
335
  // src/ssr-render.ts
336
336
  import { compileTheme } from "@vertz/ui";
337
337
  import { EntityStore, MemoryCache, QueryEnvelopeStore } from "@vertz/ui/internals";
338
+
339
+ // src/css-filter.ts
340
+ function extractClassNamesFromHTML(html) {
341
+ const classes = new Set;
342
+ const attrRegex = /\bclass(?:Name)?="([^"]*)"/g;
343
+ let match;
344
+ while ((match = attrRegex.exec(html)) !== null) {
345
+ const value = match[1];
346
+ for (const cls of value.split(/\s+/)) {
347
+ if (cls)
348
+ classes.add(cls);
349
+ }
350
+ }
351
+ return classes;
352
+ }
353
+ function extractClassSelectorsFromCSS(css) {
354
+ const selectors = new Set;
355
+ const selectorRegex = /\.([\w-]+)/g;
356
+ let match;
357
+ while ((match = selectorRegex.exec(css)) !== null) {
358
+ selectors.add(match[1]);
359
+ }
360
+ return selectors;
361
+ }
362
+ function isKeyframesBlock(css) {
363
+ return /^\s*@keyframes\s/.test(css);
364
+ }
365
+ function hasOnlyClassSelectors(css) {
366
+ let stripped = css.replace(/\/\*[\s\S]*?\*\//g, "");
367
+ stripped = stripped.replace(/@keyframes\s+[\w-]+\s*\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}/g, "");
368
+ stripped = stripped.replace(/@[\w-]+\s*\([^)]*\)\s*\{/g, "").replace(/^\s*\}/gm, "");
369
+ const ruleRegex = /([^{}]+)\{/g;
370
+ let match;
371
+ let foundAnySelector = false;
372
+ while ((match = ruleRegex.exec(stripped)) !== null) {
373
+ const selector = match[1].trim();
374
+ if (!selector)
375
+ continue;
376
+ foundAnySelector = true;
377
+ if (!selector.startsWith(".")) {
378
+ return false;
379
+ }
380
+ }
381
+ return foundAnySelector;
382
+ }
383
+ function filterCSSByHTML(html, cssStrings) {
384
+ if (cssStrings.length === 0 || !html)
385
+ return [];
386
+ const htmlClasses = extractClassNamesFromHTML(html);
387
+ const kept = [];
388
+ const pendingKeyframes = [];
389
+ for (const css of cssStrings) {
390
+ if (isKeyframesBlock(css)) {
391
+ const nameMatch = /@keyframes\s+([\w-]+)/.exec(css);
392
+ if (nameMatch) {
393
+ pendingKeyframes.push({ css, name: nameMatch[1] });
394
+ }
395
+ continue;
396
+ }
397
+ if (!hasOnlyClassSelectors(css)) {
398
+ kept.push(css);
399
+ continue;
400
+ }
401
+ const cssClasses = extractClassSelectorsFromCSS(css);
402
+ let used = false;
403
+ for (const cls of cssClasses) {
404
+ if (htmlClasses.has(cls)) {
405
+ used = true;
406
+ break;
407
+ }
408
+ }
409
+ if (used)
410
+ kept.push(css);
411
+ }
412
+ if (pendingKeyframes.length > 0) {
413
+ const survivingCss = kept.join(`
414
+ `);
415
+ for (const kf of pendingKeyframes) {
416
+ if (survivingCss.includes(kf.name)) {
417
+ kept.push(kf.css);
418
+ }
419
+ }
420
+ }
421
+ return kept;
422
+ }
423
+
424
+ // src/ssr-render.ts
338
425
  var compiledThemeCache = new WeakMap;
426
+ var compiledThemeWithMetricsCache = new WeakMap;
339
427
  function compileThemeCached(theme, fallbackMetrics) {
340
- const cached = compiledThemeCache.get(theme);
428
+ const cache = fallbackMetrics ? compiledThemeWithMetricsCache : compiledThemeCache;
429
+ const cached = cache.get(theme);
341
430
  if (cached)
342
431
  return cached;
343
432
  const compiled = compileTheme(theme, { fallbackMetrics });
344
- compiledThemeCache.set(theme, compiled);
433
+ cache.set(theme, compiled);
345
434
  return compiled;
346
435
  }
347
436
  function createRequestContext(url) {
@@ -377,7 +466,7 @@ function resolveAppFactory(module) {
377
466
  }
378
467
  return createApp;
379
468
  }
380
- function collectCSS(themeCss, module) {
469
+ function collectCSS(themeCss, module, renderedHtml) {
381
470
  const alreadyIncluded = new Set;
382
471
  if (themeCss)
383
472
  alreadyIncluded.add(themeCss);
@@ -386,8 +475,13 @@ function collectCSS(themeCss, module) {
386
475
  alreadyIncluded.add(s);
387
476
  }
388
477
  const ssrCtx = ssrStorage.getStore();
389
- const rawComponentCss = ssrCtx?.cssTracker?.size ? Array.from(ssrCtx.cssTracker) : module.getInjectedCSS?.() ?? [];
390
- const componentCss = rawComponentCss.filter((s) => !alreadyIncluded.has(s));
478
+ const tracker = ssrCtx?.cssTracker;
479
+ const useTracker = tracker && tracker.size > 0;
480
+ const rawComponentCss = useTracker ? Array.from(tracker) : module.getInjectedCSS?.() ?? [];
481
+ let componentCss = rawComponentCss.filter((s) => !alreadyIncluded.has(s));
482
+ if (!useTracker && componentCss.length > 0 && renderedHtml) {
483
+ componentCss = filterCSSByHTML(renderedHtml, componentCss);
484
+ }
391
485
  const themeTag = themeCss ? `<style data-vertz-css>${themeCss}</style>` : "";
392
486
  const globalTag = module.styles && module.styles.length > 0 ? `<style data-vertz-css>${module.styles.join(`
393
487
  `)}</style>` : "";
@@ -468,7 +562,7 @@ async function ssrRenderToString(module, url, options) {
468
562
  const vnode = toVNode(app);
469
563
  const stream = renderToStream(vnode);
470
564
  const html = await streamToString(stream);
471
- const css = collectCSS(themeCss, module);
565
+ const css = collectCSS(themeCss, module, html);
472
566
  const ssrData = resolvedQueries.length > 0 ? resolvedQueries.map(({ key, data }) => ({ key, data })) : [];
473
567
  return {
474
568
  html,
@@ -718,7 +812,7 @@ async function ssrRenderSinglePass(module, url, options) {
718
812
  const vnode = toVNode(app);
719
813
  const stream = renderToStream(vnode);
720
814
  const html = await streamToString(stream);
721
- const css = collectCSS2(themeCss, module);
815
+ const css = collectCSS2(themeCss, module, html);
722
816
  const ssrData = discoveredData.resolvedQueries.map(({ key, data }) => ({
723
817
  key,
724
818
  data
@@ -775,7 +869,7 @@ async function ssrRenderProgressive(module, url, options) {
775
869
  const app = createApp();
776
870
  const vnode = toVNode(app);
777
871
  const renderStream = renderToStream(vnode);
778
- const css = collectCSS2(themeCss, module);
872
+ const css = collectCSS2(themeCss, module, "");
779
873
  const ssrData = discoveryResult.resolvedQueries.map(({ key, data }) => ({
780
874
  key,
781
875
  data
@@ -926,7 +1020,7 @@ async function renderWithPrefetchedData(module, normalizedUrl, prefetchedData, o
926
1020
  matchedRoutePatterns: renderCtx.matchedRoutePatterns
927
1021
  };
928
1022
  }
929
- const css = collectCSS2(themeCss, module);
1023
+ const css = collectCSS2(themeCss, module, html);
930
1024
  const ssrData = data.resolvedQueries.map(({ key, data: d }) => ({
931
1025
  key,
932
1026
  data: d
@@ -999,7 +1093,7 @@ function extractMethodFromKey(key) {
999
1093
  const segments = cleanPath.split("/").filter(Boolean);
1000
1094
  return segments.length > 1 ? "get" : "list";
1001
1095
  }
1002
- function collectCSS2(themeCss, module) {
1096
+ function collectCSS2(themeCss, module, renderedHtml) {
1003
1097
  const alreadyIncluded = new Set;
1004
1098
  if (themeCss)
1005
1099
  alreadyIncluded.add(themeCss);
@@ -1008,8 +1102,13 @@ function collectCSS2(themeCss, module) {
1008
1102
  alreadyIncluded.add(s);
1009
1103
  }
1010
1104
  const ssrCtx = ssrStorage.getStore();
1011
- const rawComponentCss = ssrCtx?.cssTracker?.size ? Array.from(ssrCtx.cssTracker) : module.getInjectedCSS?.() ?? [];
1012
- const componentCss = rawComponentCss.filter((s) => !alreadyIncluded.has(s));
1105
+ const tracker = ssrCtx?.cssTracker;
1106
+ const useTracker = tracker && tracker.size > 0;
1107
+ const rawComponentCss = useTracker ? Array.from(tracker) : module.getInjectedCSS?.() ?? [];
1108
+ let componentCss = rawComponentCss.filter((s) => !alreadyIncluded.has(s));
1109
+ if (!useTracker && componentCss.length > 0 && renderedHtml) {
1110
+ componentCss = filterCSSByHTML(renderedHtml, componentCss);
1111
+ }
1013
1112
  const themeTag = themeCss ? `<style data-vertz-css>${themeCss}</style>` : "";
1014
1113
  const globalTag = module.styles && module.styles.length > 0 ? `<style data-vertz-css>${module.styles.join(`
1015
1114
  `)}</style>` : "";
@@ -1081,7 +1180,8 @@ async function ssrRenderAot(module, url, options) {
1081
1180
  return ssrRenderSinglePass(module, normalizedUrl, fallbackOptions);
1082
1181
  }
1083
1182
  const queryCache = new Map;
1084
- const resolvedQueryKeys = aotEntry.queryKeys ? resolveParamQueryKeys(aotEntry.queryKeys, match.params) : undefined;
1183
+ const searchParams = extractSearchParams(normalizedUrl);
1184
+ const resolvedQueryKeys = aotEntry.queryKeys ? resolveParamQueryKeys(aotEntry.queryKeys, match.params, searchParams) : undefined;
1085
1185
  if (resolvedQueryKeys && resolvedQueryKeys.length > 0 && manifest?.routeEntries) {
1086
1186
  const apiClient = module.api;
1087
1187
  if (apiClient) {
@@ -1092,7 +1192,7 @@ async function ssrRenderAot(module, url, options) {
1092
1192
  const unresolvedKeys = resolvedQueryKeys.filter((k) => !queryCache.has(k));
1093
1193
  if (unresolvedKeys.length > 0) {
1094
1194
  try {
1095
- const resolved = await options.aotDataResolver(match.pattern, match.params, unresolvedKeys);
1195
+ const resolved = await options.aotDataResolver(match.pattern, match.params, unresolvedKeys, searchParams);
1096
1196
  for (const [key, value] of resolved) {
1097
1197
  queryCache.set(key, value);
1098
1198
  }
@@ -1114,13 +1214,37 @@ async function ssrRenderAot(module, url, options) {
1114
1214
  holes,
1115
1215
  getData: (key) => queryCache.get(key),
1116
1216
  session: options.prefetchSession,
1117
- params: match.params
1217
+ params: match.params,
1218
+ searchParams
1118
1219
  };
1119
1220
  const data = {};
1120
1221
  for (const [key, value] of queryCache) {
1121
1222
  data[key] = value;
1122
1223
  }
1123
- const html = aotEntry.render(data, ctx);
1224
+ let html;
1225
+ try {
1226
+ html = aotEntry.render(data, ctx);
1227
+ } catch (renderErr) {
1228
+ console.error("[SSR] AOT render failed for", match.pattern, "— falling back to single-pass:", renderErr instanceof Error ? renderErr.message : renderErr);
1229
+ return ssrRenderSinglePass(module, normalizedUrl, fallbackOptions);
1230
+ }
1231
+ if (aotManifest.app) {
1232
+ try {
1233
+ const appHoleNames = aotManifest.app.holes.filter((h) => h !== "RouterView");
1234
+ const appHoles = createHoles(appHoleNames, module, normalizedUrl, queryCache, options.ssrAuth);
1235
+ appHoles.RouterView = () => html;
1236
+ const appCtx = {
1237
+ holes: appHoles,
1238
+ getData: (key) => queryCache.get(key),
1239
+ session: options.prefetchSession,
1240
+ params: match.params,
1241
+ searchParams
1242
+ };
1243
+ html = aotManifest.app.render(data, appCtx);
1244
+ } catch (appErr) {
1245
+ console.error("[SSR] AOT app shell render failed — serving page without layout:", appErr instanceof Error ? appErr.message : appErr);
1246
+ }
1247
+ }
1124
1248
  if (options.diagnostics && isAotDebugEnabled()) {
1125
1249
  try {
1126
1250
  const domResult = await ssrRenderSinglePass(module, normalizedUrl, fallbackOptions);
@@ -1129,7 +1253,8 @@ async function ssrRenderAot(module, url, options) {
1129
1253
  }
1130
1254
  } catch {}
1131
1255
  }
1132
- const css = collectCSSFromModule(module, options.fallbackMetrics);
1256
+ const routeCss = mergeRouteCss(aotEntry.css, aotManifest.app?.css);
1257
+ const css = collectCSSFromModule(module, html, options.fallbackMetrics, routeCss, match.pattern);
1133
1258
  const ssrData = [];
1134
1259
  for (const [key, data2] of queryCache) {
1135
1260
  ssrData.push({ key, data: data2 });
@@ -1186,8 +1311,20 @@ function unwrapResult2(result) {
1186
1311
  }
1187
1312
  return result;
1188
1313
  }
1189
- function resolveParamQueryKeys(queryKeys, params) {
1190
- return queryKeys.map((key) => key.replace(/\$\{(\w+)\}/g, (_, paramName) => params[paramName] ?? ""));
1314
+ function resolveParamQueryKeys(queryKeys, params, searchParams) {
1315
+ return queryKeys.map((key) => key.replace(/\$\{sp:(\w+)(?:\|([^}]*))?\}/g, (_, spName, defaultVal) => {
1316
+ const value = searchParams?.get(spName);
1317
+ if (defaultVal !== undefined) {
1318
+ return value || defaultVal;
1319
+ }
1320
+ return value ?? "";
1321
+ }).replace(/\$\{(\w+)\}/g, (_, paramName) => params[paramName] ?? ""));
1322
+ }
1323
+ function extractSearchParams(url) {
1324
+ const qIdx = url.indexOf("?");
1325
+ if (qIdx === -1)
1326
+ return;
1327
+ return new URLSearchParams(url.slice(qIdx));
1191
1328
  }
1192
1329
  function isAotDebugEnabled() {
1193
1330
  const env = process.env.VERTZ_DEBUG;
@@ -1202,7 +1339,32 @@ function ensureDomShim3() {
1202
1339
  domShimInstalled3 = true;
1203
1340
  installDomShim();
1204
1341
  }
1205
- function collectCSSFromModule(module, fallbackMetrics) {
1342
+ function mergeRouteCss(routeCss, appCss) {
1343
+ if (!routeCss && !appCss)
1344
+ return;
1345
+ if (!appCss)
1346
+ return routeCss;
1347
+ if (!routeCss)
1348
+ return appCss;
1349
+ const seen = new Set(appCss);
1350
+ const merged = [...appCss];
1351
+ for (const rule of routeCss) {
1352
+ if (!seen.has(rule))
1353
+ merged.push(rule);
1354
+ }
1355
+ return merged;
1356
+ }
1357
+ var routeCssCache = new Map;
1358
+ function clearRouteCssCache() {
1359
+ routeCssCache.clear();
1360
+ }
1361
+ function collectCSSFromModule(module, renderedHtml, fallbackMetrics, routeCss, routePattern) {
1362
+ if (routePattern && routeCss) {
1363
+ const cached = routeCssCache.get(routePattern);
1364
+ if (cached) {
1365
+ return cached;
1366
+ }
1367
+ }
1206
1368
  let themeCss = "";
1207
1369
  let preloadTags = "";
1208
1370
  if (module.theme) {
@@ -1221,9 +1383,19 @@ function collectCSSFromModule(module, fallbackMetrics) {
1221
1383
  for (const s of module.styles)
1222
1384
  alreadyIncluded.add(s);
1223
1385
  }
1224
- const ssrCtx = ssrStorage.getStore();
1225
- const rawComponentCss = ssrCtx?.cssTracker?.size ? Array.from(ssrCtx.cssTracker) : module.getInjectedCSS?.() ?? [];
1226
- const componentCss = rawComponentCss.filter((s) => !alreadyIncluded.has(s));
1386
+ let componentCss;
1387
+ if (routeCss && routeCss.length > 0) {
1388
+ componentCss = routeCss.filter((s) => !alreadyIncluded.has(s));
1389
+ } else {
1390
+ const ssrCtx = ssrStorage.getStore();
1391
+ const tracker = ssrCtx?.cssTracker;
1392
+ const useTracker = tracker && tracker.size > 0;
1393
+ const rawComponentCss = useTracker ? Array.from(tracker) : module.getInjectedCSS?.() ?? [];
1394
+ componentCss = rawComponentCss.filter((s) => !alreadyIncluded.has(s));
1395
+ if (!useTracker && componentCss.length > 0 && renderedHtml) {
1396
+ componentCss = filterCSSByHTML(renderedHtml, componentCss);
1397
+ }
1398
+ }
1227
1399
  const themeTag = themeCss ? `<style data-vertz-css>${themeCss}</style>` : "";
1228
1400
  const globalTag = module.styles && module.styles.length > 0 ? `<style data-vertz-css>${module.styles.join(`
1229
1401
  `)}</style>` : "";
@@ -1231,7 +1403,11 @@ function collectCSSFromModule(module, fallbackMetrics) {
1231
1403
  `)}</style>` : "";
1232
1404
  const cssString = [themeTag, globalTag, componentTag].filter(Boolean).join(`
1233
1405
  `);
1234
- return { cssString, preloadTags };
1406
+ const result = { cssString, preloadTags };
1407
+ if (routePattern && routeCss) {
1408
+ routeCssCache.set(routePattern, result);
1409
+ }
1410
+ return result;
1235
1411
  }
1236
1412
 
1237
1413
  // src/ssr-access-set.ts
@@ -1507,4 +1683,4 @@ function replaceAppDivContent(template, appHtml) {
1507
1683
  return template.slice(0, contentStart) + appHtml + template.slice(i);
1508
1684
  }
1509
1685
 
1510
- export { escapeHtml, escapeAttr, serializeToHtml, toPrefetchSession, evaluateAccessRule, reconstructDescriptors, resetSlotCounter, createSlotPlaceholder, encodeChunk, streamToString, collectStreamChunks, createTemplateChunk, renderToStream, safeSerialize, getStreamingRuntimeScript, createSSRDataChunk, compileThemeCached, createRequestContext, ssrRenderToString, ssrDiscoverQueries, ssrStreamNavQueries, matchUrlToPatterns, ssrRenderSinglePass, ssrRenderProgressive, createHoles, ssrRenderAot, isAotDebugEnabled, getAccessSetForSSR, createAccessSetScript, createSessionScript, resolveRouteModulepreload, precomputeHandlerState, resolveSession, injectIntoTemplate };
1686
+ export { escapeHtml, escapeAttr, serializeToHtml, toPrefetchSession, evaluateAccessRule, reconstructDescriptors, resetSlotCounter, createSlotPlaceholder, encodeChunk, streamToString, collectStreamChunks, createTemplateChunk, renderToStream, safeSerialize, getStreamingRuntimeScript, createSSRDataChunk, compileThemeCached, createRequestContext, ssrRenderToString, ssrDiscoverQueries, ssrStreamNavQueries, matchUrlToPatterns, ssrRenderSinglePass, ssrRenderProgressive, createHoles, ssrRenderAot, isAotDebugEnabled, clearRouteCssCache, getAccessSetForSSR, createAccessSetScript, createSessionScript, resolveRouteModulepreload, precomputeHandlerState, resolveSession, injectIntoTemplate };
@@ -10,7 +10,7 @@ import {
10
10
  ssrRenderSinglePass,
11
11
  ssrStreamNavQueries,
12
12
  toPrefetchSession
13
- } from "./chunk-vcpk8fs6.js";
13
+ } from "./chunk-15kac8x8.js";
14
14
 
15
15
  // src/node-handler.ts
16
16
  function createNodeHandler(options) {
@@ -24,7 +24,8 @@ function createNodeHandler(options) {
24
24
  sessionResolver,
25
25
  manifest,
26
26
  progressiveHTML,
27
- aotManifest
27
+ aotManifest,
28
+ aotDataResolver
28
29
  } = options;
29
30
  const { template, linkHeader, modulepreloadTags, splitResult } = precomputeHandlerState(options);
30
31
  const useProgressive = progressiveHTML && splitResult && !(manifest?.routeEntries && Object.keys(manifest.routeEntries).length > 0);
@@ -60,7 +61,8 @@ function createNodeHandler(options) {
60
61
  ssrTimeout,
61
62
  fallbackMetrics,
62
63
  ssrAuth,
63
- prefetchSession
64
+ prefetchSession,
65
+ aotDataResolver
64
66
  }) : await ssrRenderSinglePass(module, url, {
65
67
  ssrTimeout,
66
68
  fallbackMetrics,
@@ -11,14 +11,16 @@ import {
11
11
  ssrRenderSinglePass,
12
12
  ssrStreamNavQueries,
13
13
  toPrefetchSession
14
- } from "./chunk-vcpk8fs6.js";
14
+ } from "./chunk-15kac8x8.js";
15
15
 
16
16
  // src/aot-manifest-loader.ts
17
17
  import { existsSync, readFileSync } from "node:fs";
18
18
  import { join } from "node:path";
19
19
  async function loadAotManifest(serverDir) {
20
20
  const manifestPath = join(serverDir, "aot-manifest.json");
21
- const routesModulePath = join(serverDir, "aot-routes.js");
21
+ const routesModuleTs = join(serverDir, "aot-routes.ts");
22
+ const routesModuleJs = join(serverDir, "aot-routes.js");
23
+ const routesModulePath = existsSync(routesModuleTs) ? routesModuleTs : routesModuleJs;
22
24
  if (!existsSync(manifestPath) || !existsSync(routesModulePath)) {
23
25
  return null;
24
26
  }
@@ -46,13 +48,26 @@ async function loadAotManifest(serverDir) {
46
48
  routes[pattern] = {
47
49
  render: renderFn,
48
50
  holes: entry.holes,
49
- queryKeys: entry.queryKeys
51
+ queryKeys: entry.queryKeys,
52
+ css: entry.css
50
53
  };
51
54
  }
52
55
  if (Object.keys(routes).length === 0) {
53
56
  return null;
54
57
  }
55
- return { routes };
58
+ let app;
59
+ if (manifestJson.app) {
60
+ const appRenderFn = routesModule[manifestJson.app.renderFn];
61
+ if (typeof appRenderFn === "function") {
62
+ app = {
63
+ render: appRenderFn,
64
+ holes: manifestJson.app.holes,
65
+ queryKeys: manifestJson.app.queryKeys,
66
+ css: manifestJson.app.css
67
+ };
68
+ }
69
+ }
70
+ return { routes, app };
56
71
  }
57
72
 
58
73
  // src/ssr-progressive-response.ts
@@ -140,6 +140,8 @@ interface SSRAotContext {
140
140
  session: PrefetchSession | undefined;
141
141
  /** Route params for the current request. */
142
142
  params: Record<string, string>;
143
+ /** URL search params for the current request (used by AOT functions with ${sp:name} keys). */
144
+ searchParams: URLSearchParams | undefined;
143
145
  }
144
146
  /** An AOT render function: takes props/data and context, returns HTML string. */
145
147
  type AotRenderFn = (data: Record<string, unknown>, ctx: SSRAotContext) => string;
@@ -151,6 +153,8 @@ interface AotRouteEntry {
151
153
  holes: string[];
152
154
  /** Query cache keys this route reads via ctx.getData(). */
153
155
  queryKeys?: string[];
156
+ /** Pre-filtered CSS rules for this route, determined at build time (#1988). */
157
+ css?: string[];
154
158
  }
155
159
  /**
156
160
  * AOT manifest — maps route patterns to pre-compiled render functions.
@@ -160,6 +164,8 @@ interface AotRouteEntry {
160
164
  interface AotManifest {
161
165
  /** Route pattern → AOT entry. */
162
166
  routes: Record<string, AotRouteEntry>;
167
+ /** Root layout (App) entry — wraps page content via its RouterView hole. */
168
+ app?: AotRouteEntry;
163
169
  }
164
170
  /**
165
171
  * Resolves custom data for AOT-rendered routes.
@@ -172,7 +178,7 @@ interface AotManifest {
172
178
  * @param unresolvedKeys - Query keys not yet populated by entity prefetch
173
179
  * @returns Map of cache key → data, or empty Map to skip
174
180
  */
175
- type AotDataResolver = (pattern: string, params: Record<string, string>, unresolvedKeys: string[]) => Promise<Map<string, unknown>> | Map<string, unknown>;
181
+ type AotDataResolver = (pattern: string, params: Record<string, string>, unresolvedKeys: string[], searchParams?: URLSearchParams) => Promise<Map<string, unknown>> | Map<string, unknown>;
176
182
  /**
177
183
  * Load AOT manifest and routes module from a server build directory.
178
184
  *
package/dist/ssr/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  createSSRHandler,
3
3
  loadAotManifest
4
- } from "../shared/chunk-rwa95knv.js";
4
+ } from "../shared/chunk-j18fewkf.js";
5
5
  import {
6
6
  injectIntoTemplate,
7
7
  ssrDiscoverQueries,
8
8
  ssrRenderToString
9
- } from "../shared/chunk-vcpk8fs6.js";
9
+ } from "../shared/chunk-15kac8x8.js";
10
10
  import"../shared/chunk-ybftdw1r.js";
11
11
  // src/prerender.ts
12
12
  async function discoverRoutes(module) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertz/ui-server",
3
- "version": "0.2.37",
3
+ "version": "0.2.41",
4
4
  "description": "Vertz UI server-side rendering runtime",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -58,7 +58,7 @@
58
58
  },
59
59
  "scripts": {
60
60
  "build": "bunup",
61
- "test": "bun test src/",
61
+ "test": "bun test --timeout 60000 src/",
62
62
  "test:integration": "bun test src/__tests__/bun-dev-server.integration.local.ts",
63
63
  "test:e2e": "bunx playwright test",
64
64
  "typecheck": "tsc --noEmit"
@@ -67,9 +67,9 @@
67
67
  "@ampproject/remapping": "^2.3.0",
68
68
  "@capsizecss/unpack": "^4.0.0",
69
69
  "@jridgewell/trace-mapping": "^0.3.31",
70
- "@vertz/core": "^0.2.35",
71
- "@vertz/ui": "^0.2.35",
72
- "@vertz/ui-compiler": "^0.2.35",
70
+ "@vertz/core": "^0.2.39",
71
+ "@vertz/ui": "^0.2.39",
72
+ "@vertz/ui-compiler": "^0.2.39",
73
73
  "magic-string": "^0.30.0",
74
74
  "sharp": "^0.34.5",
75
75
  "ts-morph": "^27.0.2"
@@ -77,7 +77,7 @@
77
77
  "devDependencies": {
78
78
  "@happy-dom/global-registrator": "^20.8.3",
79
79
  "@playwright/test": "^1.58.2",
80
- "@vertz/codegen": "^0.2.35",
80
+ "@vertz/codegen": "^0.2.39",
81
81
  "@vertz/ui-auth": "^0.2.19",
82
82
  "bun-types": "^1.3.10",
83
83
  "bunup": "^0.16.31",