@vertz/ui-server 0.2.42 → 0.2.44

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.
@@ -1535,9 +1535,16 @@ function createPrefetchManifestManager(options) {
1535
1535
  };
1536
1536
  }
1537
1537
 
1538
- // src/ssr-render.ts
1539
- import { compileTheme } from "@vertz/ui";
1540
- import { EntityStore, MemoryCache, QueryEnvelopeStore } from "@vertz/ui/internals";
1538
+ // src/ssr-session.ts
1539
+ function createSessionScript(session, nonce) {
1540
+ const json = JSON.stringify(session);
1541
+ const escaped = json.replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
1542
+ const nonceAttr = nonce ? ` nonce="${escapeAttr2(nonce)}"` : "";
1543
+ return `<script${nonceAttr}>window.__VERTZ_SESSION__=${escaped}</script>`;
1544
+ }
1545
+ function escapeAttr2(s) {
1546
+ return s.replace(/[&"'<>]/g, (c) => `&#${c.charCodeAt(0)};`);
1547
+ }
1541
1548
 
1542
1549
  // src/css-filter.ts
1543
1550
  function extractClassNamesFromHTML(html) {
@@ -2382,14 +2389,14 @@ var RAW_TEXT_ELEMENTS = new Set(["script", "style"]);
2382
2389
  function escapeHtml(text) {
2383
2390
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
2384
2391
  }
2385
- function escapeAttr2(value) {
2392
+ function escapeAttr3(value) {
2386
2393
  const str = typeof value === "string" ? value : String(value);
2387
2394
  return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
2388
2395
  }
2389
2396
  function serializeAttrs(attrs) {
2390
2397
  const parts = [];
2391
2398
  for (const [key, value] of Object.entries(attrs)) {
2392
- parts.push(` ${key}="${escapeAttr2(value)}"`);
2399
+ parts.push(` ${key}="${escapeAttr3(value)}"`);
2393
2400
  }
2394
2401
  return parts.join("");
2395
2402
  }
@@ -2457,7 +2464,7 @@ async function streamToString(stream) {
2457
2464
  function createTemplateChunk(slotId, resolvedHtml, nonce) {
2458
2465
  const tmplId = `v-tmpl-${slotId}`;
2459
2466
  const slotRef = `v-slot-${slotId}`;
2460
- const nonceAttr = nonce != null ? ` nonce="${escapeAttr2(nonce)}"` : "";
2467
+ const nonceAttr = nonce != null ? ` nonce="${escapeAttr3(nonce)}"` : "";
2461
2468
  return `<template id="${tmplId}">${resolvedHtml}</template>` + `<script${nonceAttr}>` + `(function(){` + `var s=document.getElementById("${slotRef}");` + `var t=document.getElementById("${tmplId}");` + `if(s&&t){s.replaceWith(t.content.cloneNode(true));t.remove()}` + `})()` + "</script>";
2462
2469
  }
2463
2470
 
@@ -2487,7 +2494,7 @@ function renderToStream(tree, options) {
2487
2494
  return children.map((child) => walkAndSerialize(child)).join("");
2488
2495
  }
2489
2496
  const isRawText = RAW_TEXT_ELEMENTS.has(tag);
2490
- const attrStr = Object.entries(attrs).map(([k, v]) => ` ${k}="${escapeAttr2(v)}"`).join("");
2497
+ const attrStr = Object.entries(attrs).map(([k, v]) => ` ${k}="${escapeAttr3(v)}"`).join("");
2491
2498
  if (VOID_ELEMENTS.has(tag)) {
2492
2499
  return `<${tag}${attrStr}>`;
2493
2500
  }
@@ -2525,276 +2532,6 @@ function renderToStream(tree, options) {
2525
2532
  });
2526
2533
  }
2527
2534
 
2528
- // src/ssr-streaming-runtime.ts
2529
- function safeSerialize(data) {
2530
- return JSON.stringify(data).replace(/</g, "\\u003c");
2531
- }
2532
-
2533
- // src/ssr-render.ts
2534
- var compiledThemeCache = new WeakMap;
2535
- var compiledThemeWithMetricsCache = new WeakMap;
2536
- function compileThemeCached(theme, fallbackMetrics) {
2537
- const cache = fallbackMetrics ? compiledThemeWithMetricsCache : compiledThemeCache;
2538
- const cached = cache.get(theme);
2539
- if (cached)
2540
- return cached;
2541
- const compiled = compileTheme(theme, { fallbackMetrics });
2542
- cache.set(theme, compiled);
2543
- return compiled;
2544
- }
2545
- function createRequestContext(url) {
2546
- return {
2547
- url,
2548
- adapter: createSSRAdapter(),
2549
- subscriber: null,
2550
- readValueCb: null,
2551
- cleanupStack: [],
2552
- batchDepth: 0,
2553
- pendingEffects: new Map,
2554
- contextScope: null,
2555
- entityStore: new EntityStore,
2556
- envelopeStore: new QueryEnvelopeStore,
2557
- queryCache: new MemoryCache({ maxSize: Infinity }),
2558
- inflight: new Map,
2559
- queries: [],
2560
- errors: [],
2561
- cssTracker: new Set
2562
- };
2563
- }
2564
- var domShimInstalled = false;
2565
- function ensureDomShim() {
2566
- if (domShimInstalled && typeof document !== "undefined")
2567
- return;
2568
- domShimInstalled = true;
2569
- installDomShim();
2570
- }
2571
- function resolveAppFactory(module) {
2572
- const createApp = module.default || module.App;
2573
- if (typeof createApp !== "function") {
2574
- throw new Error("App entry must export a default function or named App function");
2575
- }
2576
- return createApp;
2577
- }
2578
- function collectCSS(themeCss, module, renderedHtml) {
2579
- const alreadyIncluded = new Set;
2580
- if (themeCss)
2581
- alreadyIncluded.add(themeCss);
2582
- if (module.styles) {
2583
- for (const s of module.styles)
2584
- alreadyIncluded.add(s);
2585
- }
2586
- const ssrCtx = ssrStorage.getStore();
2587
- const tracker = ssrCtx?.cssTracker;
2588
- const useTracker = tracker && tracker.size > 0;
2589
- const rawComponentCss = useTracker ? Array.from(tracker) : module.getInjectedCSS?.() ?? [];
2590
- let componentCss = rawComponentCss.filter((s) => !alreadyIncluded.has(s));
2591
- if (!useTracker && componentCss.length > 0 && renderedHtml) {
2592
- componentCss = filterCSSByHTML(renderedHtml, componentCss);
2593
- }
2594
- const themeTag = themeCss ? `<style data-vertz-css>${themeCss}</style>` : "";
2595
- const globalTag = module.styles && module.styles.length > 0 ? `<style data-vertz-css>${module.styles.join(`
2596
- `)}</style>` : "";
2597
- const componentTag = componentCss.length > 0 ? `<style data-vertz-css>${componentCss.join(`
2598
- `)}</style>` : "";
2599
- return [themeTag, globalTag, componentTag].filter(Boolean).join(`
2600
- `);
2601
- }
2602
- async function ssrRenderToString(module, url, options) {
2603
- const normalizedUrl = url.endsWith("/index.html") ? url.slice(0, -"/index.html".length) || "/" : url;
2604
- const ssrTimeout = options?.ssrTimeout ?? 300;
2605
- ensureDomShim();
2606
- const ctx = createRequestContext(normalizedUrl);
2607
- if (options?.ssrAuth) {
2608
- ctx.ssrAuth = options.ssrAuth;
2609
- }
2610
- return ssrStorage.run(ctx, async () => {
2611
- try {
2612
- setGlobalSSRTimeout(ssrTimeout);
2613
- const createApp = resolveAppFactory(module);
2614
- let themeCss = "";
2615
- let themePreloadTags = "";
2616
- if (module.theme) {
2617
- try {
2618
- const compiled = compileThemeCached(module.theme, options?.fallbackMetrics);
2619
- themeCss = compiled.css;
2620
- themePreloadTags = compiled.preloadTags;
2621
- } catch (e) {
2622
- console.error("[vertz] Failed to compile theme export. Ensure your theme is created with defineTheme().", e);
2623
- }
2624
- }
2625
- createApp();
2626
- if (ctx.ssrRedirect) {
2627
- return {
2628
- html: "",
2629
- css: "",
2630
- ssrData: [],
2631
- headTags: "",
2632
- redirect: ctx.ssrRedirect
2633
- };
2634
- }
2635
- const store = ssrStorage.getStore();
2636
- if (store) {
2637
- if (store.pendingRouteComponents?.size) {
2638
- const entries = Array.from(store.pendingRouteComponents.entries());
2639
- const results = await Promise.allSettled(entries.map(([route, promise]) => Promise.race([
2640
- promise.then((mod) => ({ route, factory: mod.default })),
2641
- new Promise((_, reject) => setTimeout(() => reject(new Error("lazy route timeout")), ssrTimeout))
2642
- ])));
2643
- store.resolvedComponents = new Map;
2644
- for (const result of results) {
2645
- if (result.status === "fulfilled") {
2646
- const { route, factory } = result.value;
2647
- store.resolvedComponents.set(route, factory);
2648
- }
2649
- }
2650
- store.pendingRouteComponents = undefined;
2651
- }
2652
- if (!store.resolvedComponents) {
2653
- store.resolvedComponents = new Map;
2654
- }
2655
- }
2656
- const queries = getSSRQueries();
2657
- const resolvedQueries = [];
2658
- if (queries.length > 0) {
2659
- await Promise.allSettled(queries.map(({ promise, timeout, resolve, key }) => Promise.race([
2660
- promise.then((data) => {
2661
- resolve(data);
2662
- resolvedQueries.push({ key, data });
2663
- return "resolved";
2664
- }),
2665
- new Promise((r) => setTimeout(r, timeout || ssrTimeout)).then(() => "timeout")
2666
- ])));
2667
- if (store)
2668
- store.queries = [];
2669
- }
2670
- const app = createApp();
2671
- const vnode = toVNode(app);
2672
- const stream = renderToStream(vnode);
2673
- const html = await streamToString(stream);
2674
- const css = collectCSS(themeCss, module, html);
2675
- const ssrData = resolvedQueries.length > 0 ? resolvedQueries.map(({ key, data }) => ({ key, data })) : [];
2676
- return {
2677
- html,
2678
- css,
2679
- ssrData,
2680
- headTags: themePreloadTags,
2681
- discoveredRoutes: ctx.discoveredRoutes,
2682
- matchedRoutePatterns: ctx.matchedRoutePatterns
2683
- };
2684
- } finally {
2685
- clearGlobalSSRTimeout();
2686
- }
2687
- });
2688
- }
2689
- async function ssrStreamNavQueries(module, url, options) {
2690
- const normalizedUrl = url.endsWith("/index.html") ? url.slice(0, -"/index.html".length) || "/" : url;
2691
- const ssrTimeout = options?.ssrTimeout ?? 300;
2692
- const navTimeout = options?.navSsrTimeout ?? 5000;
2693
- ensureDomShim();
2694
- const ctx = createRequestContext(normalizedUrl);
2695
- const queries = await ssrStorage.run(ctx, async () => {
2696
- try {
2697
- setGlobalSSRTimeout(ssrTimeout);
2698
- const createApp = resolveAppFactory(module);
2699
- createApp();
2700
- const discovered = getSSRQueries();
2701
- return discovered.map((q) => ({
2702
- promise: q.promise,
2703
- timeout: q.timeout || ssrTimeout,
2704
- resolve: q.resolve,
2705
- key: q.key
2706
- }));
2707
- } finally {
2708
- clearGlobalSSRTimeout();
2709
- }
2710
- });
2711
- if (queries.length === 0) {
2712
- const encoder3 = new TextEncoder;
2713
- return new ReadableStream({
2714
- start(controller) {
2715
- controller.enqueue(encoder3.encode(`event: done
2716
- data: {}
2717
-
2718
- `));
2719
- controller.close();
2720
- }
2721
- });
2722
- }
2723
- const encoder2 = new TextEncoder;
2724
- let remaining = queries.length;
2725
- return new ReadableStream({
2726
- start(controller) {
2727
- let closed = false;
2728
- function safeEnqueue(chunk) {
2729
- if (closed)
2730
- return;
2731
- try {
2732
- controller.enqueue(chunk);
2733
- } catch {
2734
- closed = true;
2735
- }
2736
- }
2737
- function safeClose() {
2738
- if (closed)
2739
- return;
2740
- closed = true;
2741
- try {
2742
- controller.close();
2743
- } catch {}
2744
- }
2745
- function checkDone() {
2746
- if (remaining === 0) {
2747
- safeEnqueue(encoder2.encode(`event: done
2748
- data: {}
2749
-
2750
- `));
2751
- safeClose();
2752
- }
2753
- }
2754
- for (const { promise, resolve, key } of queries) {
2755
- let settled = false;
2756
- promise.then((data) => {
2757
- if (settled)
2758
- return;
2759
- settled = true;
2760
- resolve(data);
2761
- const entry = { key, data };
2762
- safeEnqueue(encoder2.encode(`event: data
2763
- data: ${safeSerialize(entry)}
2764
-
2765
- `));
2766
- remaining--;
2767
- checkDone();
2768
- }, () => {
2769
- if (settled)
2770
- return;
2771
- settled = true;
2772
- remaining--;
2773
- checkDone();
2774
- });
2775
- setTimeout(() => {
2776
- if (settled)
2777
- return;
2778
- settled = true;
2779
- remaining--;
2780
- checkDone();
2781
- }, navTimeout);
2782
- }
2783
- }
2784
- });
2785
- }
2786
-
2787
- // src/ssr-session.ts
2788
- function createSessionScript(session, nonce) {
2789
- const json = JSON.stringify(session);
2790
- const escaped = json.replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
2791
- const nonceAttr = nonce ? ` nonce="${escapeAttr3(nonce)}"` : "";
2792
- return `<script${nonceAttr}>window.__VERTZ_SESSION__=${escaped}</script>`;
2793
- }
2794
- function escapeAttr3(s) {
2795
- return s.replace(/[&"'<>]/g, (c) => `&#${c.charCodeAt(0)};`);
2796
- }
2797
-
2798
2535
  // src/ssr-manifest-prefetch.ts
2799
2536
  function reconstructDescriptors(queries, routeParams, apiClient) {
2800
2537
  if (!apiClient)
@@ -2884,6 +2621,40 @@ function resolveQueryBindings(bindings, routeParams) {
2884
2621
  return resolved;
2885
2622
  }
2886
2623
 
2624
+ // src/ssr-shared.ts
2625
+ import { compileTheme } from "@vertz/ui";
2626
+ import { EntityStore, MemoryCache, QueryEnvelopeStore } from "@vertz/ui/internals";
2627
+ var compiledThemeCache = new WeakMap;
2628
+ var compiledThemeWithMetricsCache = new WeakMap;
2629
+ function compileThemeCached(theme, fallbackMetrics) {
2630
+ const cache = fallbackMetrics ? compiledThemeWithMetricsCache : compiledThemeCache;
2631
+ const cached = cache.get(theme);
2632
+ if (cached)
2633
+ return cached;
2634
+ const compiled = compileTheme(theme, { fallbackMetrics });
2635
+ cache.set(theme, compiled);
2636
+ return compiled;
2637
+ }
2638
+ function createRequestContext(url) {
2639
+ return {
2640
+ url,
2641
+ adapter: createSSRAdapter(),
2642
+ subscriber: null,
2643
+ readValueCb: null,
2644
+ cleanupStack: [],
2645
+ batchDepth: 0,
2646
+ pendingEffects: new Map,
2647
+ contextScope: null,
2648
+ entityStore: new EntityStore,
2649
+ envelopeStore: new QueryEnvelopeStore,
2650
+ queryCache: new MemoryCache({ maxSize: Infinity }),
2651
+ inflight: new Map,
2652
+ queries: [],
2653
+ errors: [],
2654
+ cssTracker: new Set
2655
+ };
2656
+ }
2657
+
2887
2658
  // src/ssr-route-matcher.ts
2888
2659
  function matchUrlToPatterns(url, patterns, options) {
2889
2660
  const path = (url.split("?")[0] ?? "").split("#")[0] ?? "";
@@ -2925,14 +2696,16 @@ function matchPattern(path, pattern, exact) {
2925
2696
  return { pattern, params };
2926
2697
  }
2927
2698
 
2699
+ // src/ssr-streaming-runtime.ts
2700
+ function safeSerialize(data) {
2701
+ return JSON.stringify(data).replace(/</g, "\\u003c");
2702
+ }
2703
+
2928
2704
  // src/ssr-single-pass.ts
2929
2705
  async function ssrRenderSinglePass(module, url, options) {
2930
- if (options?.prefetch === false) {
2931
- return ssrRenderToString(module, url, options);
2932
- }
2933
2706
  const normalizedUrl = url.endsWith("/index.html") ? url.slice(0, -"/index.html".length) || "/" : url;
2934
2707
  const ssrTimeout = options?.ssrTimeout ?? 300;
2935
- ensureDomShim2();
2708
+ ensureDomShim();
2936
2709
  const zeroDiscoveryData = attemptZeroDiscovery(normalizedUrl, module, options, ssrTimeout);
2937
2710
  if (zeroDiscoveryData) {
2938
2711
  return renderWithPrefetchedData(module, normalizedUrl, zeroDiscoveryData, options);
@@ -2961,7 +2734,7 @@ async function ssrRenderSinglePass(module, url, options) {
2961
2734
  return ssrStorage.run(renderCtx, async () => {
2962
2735
  try {
2963
2736
  setGlobalSSRTimeout(ssrTimeout);
2964
- const createApp = resolveAppFactory2(module);
2737
+ const createApp = resolveAppFactory(module);
2965
2738
  let themeCss = "";
2966
2739
  let themePreloadTags = "";
2967
2740
  if (module.theme) {
@@ -2977,7 +2750,7 @@ async function ssrRenderSinglePass(module, url, options) {
2977
2750
  const vnode = toVNode(app);
2978
2751
  const stream = renderToStream(vnode);
2979
2752
  const html = await streamToString(stream);
2980
- const css = collectCSS2(themeCss, module, html);
2753
+ const css = collectCSS(themeCss, module, html);
2981
2754
  const ssrData = discoveredData.resolvedQueries.map(({ key, data }) => ({
2982
2755
  key,
2983
2756
  data
@@ -2995,59 +2768,75 @@ async function ssrRenderSinglePass(module, url, options) {
2995
2768
  }
2996
2769
  });
2997
2770
  }
2998
- async function runDiscoveryPhase(normalizedUrl, ssrTimeout, module, options) {
2999
- const discoveryCtx = createRequestContext(normalizedUrl);
2771
+ async function runQueryDiscovery(normalizedUrl, ssrTimeout, module, options) {
2772
+ ensureDomShim();
2773
+ const ctx = createRequestContext(normalizedUrl);
3000
2774
  if (options?.ssrAuth) {
3001
- discoveryCtx.ssrAuth = options.ssrAuth;
2775
+ ctx.ssrAuth = options.ssrAuth;
3002
2776
  }
3003
2777
  if (options?.cookies) {
3004
- discoveryCtx.cookies = options.cookies;
2778
+ ctx.cookies = options.cookies;
3005
2779
  }
3006
- return ssrStorage.run(discoveryCtx, async () => {
2780
+ return ssrStorage.run(ctx, async () => {
3007
2781
  try {
3008
2782
  setGlobalSSRTimeout(ssrTimeout);
3009
- const createApp = resolveAppFactory2(module);
2783
+ const createApp = resolveAppFactory(module);
3010
2784
  createApp();
3011
- if (discoveryCtx.ssrRedirect) {
3012
- return { redirect: discoveryCtx.ssrRedirect };
2785
+ if (ctx.ssrRedirect) {
2786
+ return { redirect: ctx.ssrRedirect, queries: [] };
3013
2787
  }
3014
- if (discoveryCtx.pendingRouteComponents?.size) {
3015
- const entries = Array.from(discoveryCtx.pendingRouteComponents.entries());
2788
+ if (ctx.pendingRouteComponents?.size) {
2789
+ const entries = Array.from(ctx.pendingRouteComponents.entries());
3016
2790
  const results = await Promise.allSettled(entries.map(([route, promise]) => Promise.race([
3017
2791
  promise.then((mod) => ({ route, factory: mod.default })),
3018
2792
  new Promise((_, reject) => setTimeout(() => reject(new Error("lazy route timeout")), ssrTimeout))
3019
2793
  ])));
3020
- discoveryCtx.resolvedComponents = new Map;
2794
+ ctx.resolvedComponents = new Map;
3021
2795
  for (const result of results) {
3022
2796
  if (result.status === "fulfilled") {
3023
2797
  const { route, factory } = result.value;
3024
- discoveryCtx.resolvedComponents.set(route, factory);
2798
+ ctx.resolvedComponents.set(route, factory);
3025
2799
  }
3026
2800
  }
3027
- discoveryCtx.pendingRouteComponents = undefined;
2801
+ ctx.pendingRouteComponents = undefined;
3028
2802
  }
3029
2803
  const queries = getSSRQueries();
3030
- const eligibleQueries = filterByEntityAccess(queries, options?.manifest?.entityAccess, options?.prefetchSession);
3031
- const resolvedQueries = [];
3032
- if (eligibleQueries.length > 0) {
3033
- await Promise.allSettled(eligibleQueries.map(({ promise, timeout, resolve, key }) => Promise.race([
3034
- promise.then((data) => {
3035
- resolve(data);
3036
- resolvedQueries.push({ key, data });
3037
- return "resolved";
3038
- }),
3039
- new Promise((r) => setTimeout(r, timeout || ssrTimeout)).then(() => "timeout")
3040
- ])));
3041
- }
3042
2804
  return {
3043
- resolvedQueries,
3044
- resolvedComponents: discoveryCtx.resolvedComponents
2805
+ queries: queries.map((q) => ({
2806
+ promise: q.promise,
2807
+ timeout: q.timeout || ssrTimeout,
2808
+ resolve: q.resolve,
2809
+ key: q.key
2810
+ })),
2811
+ resolvedComponents: ctx.resolvedComponents
3045
2812
  };
3046
2813
  } finally {
3047
2814
  clearGlobalSSRTimeout();
3048
2815
  }
3049
2816
  });
3050
2817
  }
2818
+ async function runDiscoveryPhase(normalizedUrl, ssrTimeout, module, options) {
2819
+ const discovery = await runQueryDiscovery(normalizedUrl, ssrTimeout, module, options);
2820
+ if ("redirect" in discovery) {
2821
+ return { redirect: discovery.redirect };
2822
+ }
2823
+ const eligibleQueries = filterByEntityAccess(discovery.queries, options?.manifest?.entityAccess, options?.prefetchSession);
2824
+ const resolvedQueries = [];
2825
+ if (eligibleQueries.length > 0) {
2826
+ await Promise.allSettled(eligibleQueries.map(({ promise, timeout, resolve, key }) => Promise.race([
2827
+ promise.then((data) => {
2828
+ resolve(data);
2829
+ resolvedQueries.push({ key, data });
2830
+ return "resolved";
2831
+ }),
2832
+ new Promise((r) => setTimeout(r, timeout)).then(() => "timeout")
2833
+ ])));
2834
+ }
2835
+ return {
2836
+ resolvedQueries,
2837
+ resolvedComponents: discovery.resolvedComponents
2838
+ };
2839
+ }
3051
2840
  function attemptZeroDiscovery(url, module, options, ssrTimeout) {
3052
2841
  const manifest = options?.manifest;
3053
2842
  if (!manifest?.routeEntries || !module.api)
@@ -3108,7 +2897,7 @@ async function renderWithPrefetchedData(module, normalizedUrl, prefetchedData, o
3108
2897
  return ssrStorage.run(renderCtx, async () => {
3109
2898
  try {
3110
2899
  setGlobalSSRTimeout(ssrTimeout);
3111
- const createApp = resolveAppFactory2(module);
2900
+ const createApp = resolveAppFactory(module);
3112
2901
  let themeCss = "";
3113
2902
  let themePreloadTags = "";
3114
2903
  if (module.theme) {
@@ -3135,7 +2924,7 @@ async function renderWithPrefetchedData(module, normalizedUrl, prefetchedData, o
3135
2924
  matchedRoutePatterns: renderCtx.matchedRoutePatterns
3136
2925
  };
3137
2926
  }
3138
- const css = collectCSS2(themeCss, module, html);
2927
+ const css = collectCSS(themeCss, module, html);
3139
2928
  const ssrData = data.resolvedQueries.map(({ key, data: d }) => ({
3140
2929
  key,
3141
2930
  data: d
@@ -3153,14 +2942,95 @@ async function renderWithPrefetchedData(module, normalizedUrl, prefetchedData, o
3153
2942
  }
3154
2943
  });
3155
2944
  }
3156
- var domShimInstalled2 = false;
3157
- function ensureDomShim2() {
3158
- if (domShimInstalled2 && typeof document !== "undefined")
2945
+ async function ssrStreamNavQueries(module, url, options) {
2946
+ const normalizedUrl = url.endsWith("/index.html") ? url.slice(0, -"/index.html".length) || "/" : url;
2947
+ const ssrTimeout = options?.ssrTimeout ?? 300;
2948
+ const navTimeout = options?.navSsrTimeout ?? 5000;
2949
+ const discovery = await runQueryDiscovery(normalizedUrl, ssrTimeout, module);
2950
+ if ("redirect" in discovery || discovery.queries.length === 0) {
2951
+ const encoder3 = new TextEncoder;
2952
+ return new ReadableStream({
2953
+ start(controller) {
2954
+ controller.enqueue(encoder3.encode(`event: done
2955
+ data: {}
2956
+
2957
+ `));
2958
+ controller.close();
2959
+ }
2960
+ });
2961
+ }
2962
+ const queries = discovery.queries;
2963
+ const encoder2 = new TextEncoder;
2964
+ let remaining = queries.length;
2965
+ return new ReadableStream({
2966
+ start(controller) {
2967
+ let closed = false;
2968
+ function safeEnqueue(chunk) {
2969
+ if (closed)
2970
+ return;
2971
+ try {
2972
+ controller.enqueue(chunk);
2973
+ } catch {
2974
+ closed = true;
2975
+ }
2976
+ }
2977
+ function safeClose() {
2978
+ if (closed)
2979
+ return;
2980
+ closed = true;
2981
+ try {
2982
+ controller.close();
2983
+ } catch {}
2984
+ }
2985
+ function checkDone() {
2986
+ if (remaining === 0) {
2987
+ safeEnqueue(encoder2.encode(`event: done
2988
+ data: {}
2989
+
2990
+ `));
2991
+ safeClose();
2992
+ }
2993
+ }
2994
+ for (const { promise, resolve, key } of queries) {
2995
+ let settled = false;
2996
+ promise.then((data) => {
2997
+ if (settled)
2998
+ return;
2999
+ settled = true;
3000
+ resolve(data);
3001
+ const entry = { key, data };
3002
+ safeEnqueue(encoder2.encode(`event: data
3003
+ data: ${safeSerialize(entry)}
3004
+
3005
+ `));
3006
+ remaining--;
3007
+ checkDone();
3008
+ }, () => {
3009
+ if (settled)
3010
+ return;
3011
+ settled = true;
3012
+ remaining--;
3013
+ checkDone();
3014
+ });
3015
+ setTimeout(() => {
3016
+ if (settled)
3017
+ return;
3018
+ settled = true;
3019
+ remaining--;
3020
+ checkDone();
3021
+ }, navTimeout);
3022
+ }
3023
+ }
3024
+ });
3025
+ }
3026
+ var domShimInstalled = false;
3027
+ function ensureDomShim() {
3028
+ if (domShimInstalled && typeof document !== "undefined")
3159
3029
  return;
3160
- domShimInstalled2 = true;
3030
+ domShimInstalled = true;
3161
3031
  installDomShim();
3162
3032
  }
3163
- function resolveAppFactory2(module) {
3033
+ function resolveAppFactory(module) {
3164
3034
  const createApp = module.default || module.App;
3165
3035
  if (typeof createApp !== "function") {
3166
3036
  throw new Error("App entry must export a default function or named App function");
@@ -3208,7 +3078,7 @@ function extractMethodFromKey(key) {
3208
3078
  const segments = cleanPath.split("/").filter(Boolean);
3209
3079
  return segments.length > 1 ? "get" : "list";
3210
3080
  }
3211
- function collectCSS2(themeCss, module, renderedHtml) {
3081
+ function collectCSS(themeCss, module, renderedHtml) {
3212
3082
  const alreadyIncluded = new Set;
3213
3083
  if (themeCss)
3214
3084
  alreadyIncluded.add(themeCss);