@useavalon/avalon 0.3.2-canary.15 → 0.3.2-canary.17

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.
Files changed (61) hide show
  1. package/dist/src/build/island-client-bundler.js +1 -1
  2. package/dist/src/build/island-manifest.d.ts +3 -0
  3. package/dist/src/build/island-manifest.js +1 -1
  4. package/dist/src/build/island-ssr-flag.d.ts +14 -0
  5. package/dist/src/build/island-ssr-flag.js +1 -0
  6. package/dist/src/build/mdx-island-transform.js +2 -2
  7. package/dist/src/build/page-island-transform.js +2 -2
  8. package/dist/src/client/custom-directives.js +1 -1
  9. package/dist/src/client/hydrate-runtime.d.ts +32 -0
  10. package/dist/src/client/hydrate-runtime.js +1 -0
  11. package/dist/src/client/hydration-mode.d.ts +11 -0
  12. package/dist/src/client/hydration-mode.js +1 -0
  13. package/dist/src/client/main-slim.js +1 -0
  14. package/dist/src/client/main.js +2 -15
  15. package/dist/src/client/router/a11y.d.ts +9 -0
  16. package/dist/src/client/router/a11y.js +1 -0
  17. package/dist/src/client/router/eligibility.d.ts +32 -0
  18. package/dist/src/client/router/eligibility.js +1 -0
  19. package/dist/src/client/router/events.d.ts +33 -0
  20. package/dist/src/client/router/events.js +1 -0
  21. package/dist/src/client/router/forms.d.ts +25 -0
  22. package/dist/src/client/router/forms.js +1 -0
  23. package/dist/src/client/router/index.d.ts +20 -0
  24. package/dist/src/client/router/index.js +1 -0
  25. package/dist/src/client/router/opt-out.d.ts +30 -0
  26. package/dist/src/client/router/opt-out.js +1 -0
  27. package/dist/src/client/router/persist.d.ts +21 -0
  28. package/dist/src/client/router/persist.js +1 -0
  29. package/dist/src/client/router/prefetch.d.ts +25 -0
  30. package/dist/src/client/router/prefetch.js +1 -0
  31. package/dist/src/client/router/swap.d.ts +21 -0
  32. package/dist/src/client/router/swap.js +1 -0
  33. package/dist/src/client/router/transitions.d.ts +17 -0
  34. package/dist/src/client/router/transitions.js +1 -0
  35. package/dist/src/client/server-islands-boot.d.ts +12 -0
  36. package/dist/src/client/server-islands-boot.js +1 -0
  37. package/dist/src/client/types/vite-virtual-modules.d.ts +7 -0
  38. package/dist/src/islands/framework-base-css.d.ts +5 -1
  39. package/dist/src/islands/framework-base-css.js +1 -1
  40. package/dist/src/islands/island.d.ts +17 -3
  41. package/dist/src/islands/island.js +1 -1
  42. package/dist/src/islands/per-island-script.js +1 -1
  43. package/dist/src/islands/types.d.ts +4 -0
  44. package/dist/src/nitro/renderer.d.ts +2 -1
  45. package/dist/src/nitro/renderer.js +20 -20
  46. package/dist/src/nitro/types.d.ts +5 -0
  47. package/dist/src/post-build/index.d.ts +6 -0
  48. package/dist/src/post-build/index.js +3 -3
  49. package/dist/src/post-build/isolated-island-builder.js +2 -2
  50. package/dist/src/schemas/routing/index.d.ts +2 -0
  51. package/dist/src/schemas/routing.d.ts +1 -0
  52. package/dist/src/schemas/routing.js +1 -1
  53. package/dist/src/server-islands/renderer.js +6 -5
  54. package/dist/src/types/island-prop.d.ts +25 -5
  55. package/dist/src/types/virtual-modules.d.ts +20 -4
  56. package/dist/src/vite-plugin/config.js +1 -1
  57. package/dist/src/vite-plugin/nitro-integration.js +18 -18
  58. package/dist/src/vite-plugin/plugin.d.ts +2 -0
  59. package/dist/src/vite-plugin/plugin.js +1 -1
  60. package/dist/src/vite-plugin/types.d.ts +12 -0
  61. package/package.json +6 -2
@@ -0,0 +1 @@
1
+ export function prefersReducedMotion(){return!!globalThis.matchMedia?.(`(prefers-reduced-motion: reduce)`)?.matches}export function viewTransitionFromDataset(e){if(!(e==null||e===``))return e===`false`?!1:e===`true`?!0:e}export function resolveViewTransition(e){return e===!1||e===`false`?{enabled:!1}:typeof e==`string`&&e!==``&&e!==`true`?{enabled:!0,type:e}:{enabled:!0}}function r(e,t){let n=document,r=n.startViewTransition?.bind(n);if(r){if(t)try{return r({update:e,types:[t]})}catch{}return r(e)}}export async function withViewTransition(t,i){let{enabled:a,type:o}=resolveViewTransition(i);if(!a||prefersReducedMotion()){await t();return}let s=!1,c=async()=>{s||(s=!0,await t())},l=document.documentElement,u=o?l.dataset.routerTransition:void 0;o&&(l.dataset.routerTransition=o);try{let e=r(c,o);if(!e){await c();return}await e.finished}catch{await c()}finally{o&&(u===void 0?delete l.dataset.routerTransition:l.dataset.routerTransition=u)}}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Boot deferred server islands after first load or a client-navigation swap.
3
+ *
4
+ * Inline fetch scripts in the SSR HTML do not run when the document is swapped
5
+ * via DOMParser. The shared runtime discovers `<avalon-server-island data-p>`
6
+ * nodes and performs the same fetch the inline script would.
7
+ */
8
+ /**
9
+ * Fetch and inject every server island under `root` that has not started yet.
10
+ * Combined islands re-execute module scripts in the injected HTML so they hydrate.
11
+ */
12
+ export declare function bootServerIslands(root?: ParentNode): Promise<void>;
@@ -0,0 +1 @@
1
+ function e(e){if(e.dataset.endpoint)return e.dataset.endpoint;let t=/^si-(.+)-(\d+)$/.exec(e.id);return t?`/_server-islands/${t[1]}`:null}function t(e){let t=[...e.querySelectorAll(`script[type="module"]`)];for(let e of t){if(e.getAttribute(`src`))continue;let t=document.createElement(`script`);t.type=`module`,t.textContent=e.textContent,e.replaceWith(t)}}async function n(e,t,n){let r=e.dataset.p;if(!r)return null;let i=`${t}?p=${encodeURIComponent(r)}`,a=i.length>2048?await fetch(t,{method:`POST`,body:r,headers:{"content-type":`text/plain`},signal:n}):await fetch(i,{signal:n});return a.ok?a.text():null}export async function bootServerIslands(r=document){let i=[...r.querySelectorAll(`avalon-server-island[data-p]`)];await Promise.all(i.map(async r=>{if(r.dataset.siStarted)return;let i=e(r);if(!i)return;r.dataset.siStarted=`1`;let a=Number(r.dataset.timeout)||1e4,o=new AbortController,s=setTimeout(()=>o.abort(),a);try{let e=await n(r,i,o.signal);if(clearTimeout(s),e==null)return;r.innerHTML=e,t(r)}catch{clearTimeout(s)}}))}
@@ -11,6 +11,7 @@ declare module "/@useavalon/preact/client" {
11
11
  component: unknown,
12
12
  props?: Record<string, unknown>,
13
13
  ): void;
14
+ export function unmount(container: Element): void;
14
15
  export function getHydrationScript(): string;
15
16
  }
16
17
 
@@ -20,6 +21,7 @@ declare module "/@useavalon/react/client" {
20
21
  component: unknown,
21
22
  props?: Record<string, unknown>,
22
23
  ): void;
24
+ export function unmount(container: Element): void;
23
25
  export function getHydrationScript(): string;
24
26
  }
25
27
 
@@ -29,6 +31,7 @@ declare module "/@useavalon/vue/client" {
29
31
  component: unknown,
30
32
  props?: Record<string, unknown>,
31
33
  ): void;
34
+ export function unmount(container: Element): void;
32
35
  export function getHydrationScript(): string;
33
36
  }
34
37
 
@@ -38,6 +41,7 @@ declare module "/@useavalon/svelte/client" {
38
41
  component: unknown,
39
42
  props?: Record<string, unknown>,
40
43
  ): void;
44
+ export function unmount(container: Element): void;
41
45
  export function getHydrationScript(): string;
42
46
  }
43
47
 
@@ -47,6 +51,7 @@ declare module "/@useavalon/solid/client" {
47
51
  component: unknown,
48
52
  props?: Record<string, unknown>,
49
53
  ): void;
54
+ export function unmount(container: Element): void;
50
55
  export function getHydrationScript(): string;
51
56
  }
52
57
 
@@ -56,6 +61,7 @@ declare module "/@useavalon/lit/client" {
56
61
  component: unknown,
57
62
  props?: Record<string, unknown>,
58
63
  ): void;
64
+ export function unmount(container: Element): void;
59
65
  export function getHydrationScript(): string;
60
66
  }
61
67
 
@@ -65,6 +71,7 @@ declare module "/@useavalon/qwik/client" {
65
71
  component: unknown,
66
72
  props?: Record<string, unknown>,
67
73
  ): void;
74
+ export function unmount(container: Element): void;
68
75
  export function getHydrationScript(): string;
69
76
  }
70
77
 
@@ -14,6 +14,10 @@
14
14
  * devtools. This mirrors the pattern Astro, Lit, and Elder.js use for
15
15
  * island-style hydration anchors.
16
16
  *
17
+ * Client-only islands have no SSR children, so `display: contents` would
18
+ * leave a host with no box. Those use `display: block` so deferred
19
+ * conditions (`on:visible`, `on:interaction`) can attach to the host.
20
+ *
17
21
  * The CSS is intentionally low-specificity (single-element selectors)
18
22
  * so any user CSS that sets a different `display` value naturally wins.
19
23
  */
@@ -33,4 +37,4 @@
33
37
  */
34
38
  export declare function injectFrameworkBaseCSS(html: string): string;
35
39
  /** Exposed for tests */
36
- export declare const __FRAMEWORK_BASE_CSS = "avalon-island,avalon-page,avalon-page-content,avalon-server-island,[data-server-island-wrapper]{display:contents}";
40
+ export declare const __FRAMEWORK_BASE_CSS = "avalon-island,avalon-page,avalon-page-content,avalon-server-island,[data-server-island-wrapper]{display:contents}avalon-island[data-render-strategy=client-only]{display:block}";
@@ -1 +1 @@
1
- const e=`avalon-island,avalon-page,avalon-page-content,avalon-server-island,[data-server-island-wrapper]{display:contents}`,t=`<style data-avalon-base="true">${e}</style>`;export function injectFrameworkBaseCSS(e){return e.includes(`data-avalon-base="true"`)||!e.includes(`<head>`)&&!e.includes(`<head `)?e:e.replace(/<head(\s[^>]*)?>/i,e=>`${e}${t}`)}export const __FRAMEWORK_BASE_CSS=e;
1
+ const e=`avalon-island,avalon-page,avalon-page-content,avalon-server-island,[data-server-island-wrapper]{display:contents}avalon-island[data-render-strategy=client-only]{display:block}`,t=`<style data-avalon-base="true">${e}</style>`;export function injectFrameworkBaseCSS(e){return e.includes(`data-avalon-base="true"`)||!e.includes(`<head>`)&&!e.includes(`<head `)?e:e.replace(/<head(\s[^>]*)?>/i,e=>`${e}${t}`)}export const __FRAMEWORK_BASE_CSS=e;
@@ -8,6 +8,8 @@ declare global {
8
8
  var __viteDevServer: ViteDevServer | undefined;
9
9
  /** Hydration mode — automatically set: "entry-client" in dev (HMR), "per-island" in production */
10
10
  var __avalonHydrationMode: "entry-client" | "per-island" | undefined;
11
+ /** True when Vite is serving (dev). Independent of hydration mode so production + clientRouter still uses hashed island URLs. */
12
+ var __avalonIsDev: boolean | undefined;
11
13
  /** Compile-time constant set by Vite define — true in production, false in dev */
12
14
  var __AVALON_PER_ISLAND__: boolean;
13
15
  }
@@ -15,6 +17,8 @@ declare global {
15
17
  export type HydrationCondition = "on:visible" | "on:interaction" | "on:idle" | "on:client" | `media:${string}` | `on:${string}`;
16
18
  /** Supported framework identifiers (without "unknown") */
17
19
  export type FrameworkId = Exclude<Framework, "unknown">;
20
+ /** Preact's `ComponentChildren` already includes `undefined`; keep `?` without repeating it. */
21
+ type IslandChildren = Exclude<import("preact").ComponentChildren, undefined>;
18
22
  export interface IslandProps {
19
23
  /** Path to the island component (e.g., "/islands/Counter.tsx") */
20
24
  src: string;
@@ -25,9 +29,11 @@ export interface IslandProps {
25
29
  /** Props to pass to the island component */
26
30
  props?: Record<string, unknown>;
27
31
  /** Children to render inside the island (for SSR) */
28
- children?: import("preact").ComponentChildren;
32
+ children?: IslandChildren;
29
33
  /** Whether to render server-side (default: true unless condition is 'on:client') */
30
34
  ssr?: boolean;
35
+ /** Skip component SSR and mount on the client. Forces `ssr: false`. */
36
+ clientOnly?: boolean;
31
37
  /** Framework hint for client hydration */
32
38
  framework?: FrameworkId;
33
39
  /** Force SSR-only rendering without hydration */
@@ -42,6 +48,13 @@ export interface IslandProps {
42
48
  server?: ServerIslandProp;
43
49
  /** Island directive for combined server + client islands */
44
50
  island?: IslandDirective;
51
+ /** Explicit HTML id for this island instance. Unique per instance when omitted. */
52
+ id?: string;
53
+ /**
54
+ * Persist key for client navigation (`data-router-persist`).
55
+ * `true` uses `src` as the key so layout islands match across pages.
56
+ */
57
+ persist?: string | true;
45
58
  /** React/Preact list key — set on the host VNode, never serialized into props */
46
59
  key?: string | number;
47
60
  }
@@ -56,7 +69,7 @@ export declare function withListKey(key: unknown, vnode: JSX.Element): JSX.Eleme
56
69
  * Uses custom elements instead of div wrappers for cleaner, more semantic markup.
57
70
  * Supports intelligent rendering strategy detection to skip hydration for SSR-only components.
58
71
  */
59
- export default function Island({ src, condition, conditionArg, props, children, ssr, framework, ssrOnly, renderOptions, hydrationData, }: IslandProps): JSX.Element;
72
+ export default function Island({ src, condition, conditionArg, props, children, ssr: ssrProp, clientOnly, framework, ssrOnly, renderOptions, hydrationData, id, persist, }: IslandProps): JSX.Element;
60
73
  /**
61
74
  * Universal renderIsland function – auto-detects framework and handles SSR + hydration.
62
75
  *
@@ -73,4 +86,5 @@ export default function Island({ src, condition, conditionArg, props, children,
73
86
  * Error isolation: If SSR fails, returns an error placeholder instead of throwing,
74
87
  * allowing the page to continue rendering other islands.
75
88
  */
76
- export declare function renderIsland({ src, condition, conditionArg, props, children, ssr, framework, ssrOnly, renderOptions, component: preloadedComponent, server, island, key, }: IslandProps): Promise<JSX.Element>;
89
+ export declare function renderIsland({ src, condition, conditionArg, props, children, ssr: ssrProp, clientOnly, framework, ssrOnly, renderOptions, component: preloadedComponent, server, island, key, id, persist, }: IslandProps): Promise<JSX.Element>;
90
+ export {};
@@ -1 +1 @@
1
- import{getIslandBundlePath as e}from"../build/island-manifest.js";import{shellH as t,shellFragment as n}from"../render/shell-engine.js";import{addToManifest as r,generateComponentId as i}from"../server-islands/manifest.js";import{renderServerIsland as a}from"../server-islands/renderer.js";import{devError as o,devLog as s,devWarn as c,isDev as l,logRenderTiming as u}from"../utils/dev-logger.js";import{analyzeComponentFile as d,renderComponentSSROnly as f}from"./component-analysis.js";import{detectFramework as p}from"./framework-detection.js";import{isCustomDirective as m,serializeDirectiveScript as h}from"./hydration-directives.js";import{detectFrameworkFromPath as g,loadIntegration as _}from"./integration-loader.js";import{addModulepreload as v}from"./modulepreload-collector.js";import{generatePerIslandScript as y}from"./per-island-script.js";import{addUniversalCSS as b}from"./universal-css-collector.js";import{addUniversalHead as x}from"./universal-head-collector.js";function S(e,r){return r==null?e:t(n(),{key:r},e)}export function withListKey(e,t){return S(t,e)}function w(e){return`island-${e.replaceAll(/[^a-zA-Z0-9]/g,`-`)}`}function T(){return globalThis.__avalonHydrationMode===void 0?globalThis.__viteDevServer?!1:typeof __AVALON_PER_ISLAND__<`u`?__AVALON_PER_ISLAND__:!l():globalThis.__avalonHydrationMode===`per-island`}function E(r,i){if(!T()||i.shouldSkipHydration)return r;let a=e(i.src);i.condition===`on:client`&&v(a);let o=m(i.condition),s=o?h(i.condition):void 0,c=y({islandId:i.islandId,componentSrc:a,framework:i.framework,condition:i.condition,conditionArg:i.conditionArg,propsJson:JSON.stringify(i.props),isCustomDirective:o,directiveScript:s??void 0});return t(n(),null,r,t(`div`,{dangerouslySetInnerHTML:{__html:c},"data-island-script":``}))}function D(e){let t={};e.renderId&&(t[`data-solid-render-id`]=e.renderId);let n=e.metadata;return n?.tagName&&(t[`data-tag-name`]=n.tagName),t}function O(t,n,r,i,a){let o={"data-condition":n,"data-src":e(t),"data-props":JSON.stringify(r),"data-render-strategy":`hydrate`,...D(i)};if(m(n)){o[`data-custom-directive`]=n;let e=h(n);e&&(o[`data-directive-script`]=e)}return a&&(o[`data-condition-arg`]=a),o}function k(e){return e.startsWith(`<script`)?`script`:e.startsWith(`<style`)?`style`:e.startsWith(`<meta`)?`meta`:e.startsWith(`<link`)?`link`:e.includes(`window._$HY`)||e.includes(`_$HY=`)?`script`:`other`}function A(e){let t=e.match(/<style[^>]*>([\s\S]*?)<\/style>/i);return t?t[1].trim():null}function j(e,t,n,r){if(e.css&&b(e.css,t,n,e.scopeId),e.head){let i=e.head.trim(),a=k(i);if(a===`style`){let a=A(i);a&&(s(`${r} Extracting CSS from head <style> tag`),b(a,t,n,e.scopeId));return}x(e.head,t,n,a)}}function M(e){let{islandId:n,detectedFramework:r,shouldSkipHydration:i,src:a,condition:o,conditionArg:c,props:l,hydrationData:u,children:d}=e,f={id:n,"data-framework":r},p=i?{"data-render-strategy":`ssr-only`}:O(a,o,l,u,c);r===`lit`&&s(`🔍 [Island Component] ${a} - Lit hydration data:`,{hydrationDataKeys:Object.keys(u),metadata:u.metadata});let m={...f,...p},h;return h=typeof d==`string`?t(`avalon-island`,{...m,dangerouslySetInnerHTML:{__html:d}}):t(`avalon-island`,m,d),E(h,{islandId:n,src:a,condition:o,conditionArg:c,props:l,framework:r,shouldSkipHydration:i})}function N(n){let{islandId:r,detectedFramework:i,shouldSkipHydration:a,src:o,condition:s,props:c,hydrationData:l,conditionArg:u}=n;if(a)return t(`avalon-island`,{id:r,"data-render-strategy":`ssr-only`,"data-framework":i});let d={id:r,"data-condition":s,"data-src":e(o),"data-props":JSON.stringify(c),"data-render-strategy":`hydrate`,"data-framework":i,...D(l)};if(m(s)){d[`data-custom-directive`]=s;let e=h(s);e&&(d[`data-directive-script`]=e)}return u&&(d[`data-condition-arg`]=u),E(t(`avalon-island`,d),{islandId:r,src:o,condition:s,conditionArg:u,props:c,framework:i,shouldSkipHydration:a})}export default function P({src:e,condition:t=`on:client`,conditionArg:n,props:r={},children:i,ssr:a=t!==`on:client`,framework:o,ssrOnly:l=!1,renderOptions:u={},hydrationData:d={}}){let f=w(e),p=l||!!u.forceSSROnly,m=o||g(e),h=i!=null&&i!==``;return s(`🔍 [Island Component] ${e}`,{ssr:a,ssrOnly:l,hasChildren:h,framework:o,condition:t}),a&&h?M({islandId:f,detectedFramework:m,shouldSkipHydration:p,src:e,condition:t,conditionArg:n,props:r,hydrationData:d,children:i}):(a&&!h&&p&&c(`${e}: SSR-only component has no rendered content. This may indicate a rendering error.`),N({islandId:f,detectedFramework:m,shouldSkipHydration:p,src:e,condition:t,props:r,hydrationData:d,conditionArg:n}))}function F(n,r){let i=r instanceof Error?r.message:String(r);return o(`🚨 Island SSR failed for ${n}:`,r),r instanceof Error&&r.stack&&o(`Stack trace:`,r.stack),t(`avalon-island`,{id:w(n),"data-src":e(n),"data-ssr-error":i,"data-render-strategy":`client-only`})}async function I({src:e,condition:t,conditionArg:n,props:r,children:i,ssr:a,framework:s,ssrOnly:c,renderOptions:u,component:d}){let f=`🏝️ [${e}]`;if(!a||i)return P({src:e,condition:t,conditionArg:n,props:r,children:i,ssr:a,framework:s,ssrOnly:c,renderOptions:u});let p;try{p=await _(s)}catch(i){return o(`${f} Failed to load ${s} integration:`,i),P({src:e,condition:t,conditionArg:n,props:r,ssr:!1,framework:s,ssrOnly:c,renderOptions:u})}try{let i=await p.render({component:d??null,props:r,src:e,condition:t,ssrOnly:c,viteServer:globalThis.__viteDevServer,isDev:l()});return j(i,e,s,f),P({src:e,condition:t,conditionArg:n,props:r,children:i.html,ssr:!0,framework:s,ssrOnly:c,renderOptions:u,hydrationData:c?void 0:i.hydrationData})}catch(i){return o(`${f} Fast path SSR failed:`,i),P({src:e,condition:t,conditionArg:n,props:r,ssr:!1,framework:s,ssrOnly:c,renderOptions:u})}}async function L(e,t,n,r){if(t||n.detectScripts===!1)return t;try{let t=await d(e,n);if(t.decision.warnings?.length)for(let e of t.decision.warnings)c(`${r} Analysis warning: ${e}`);return!t.decision.shouldHydrate}catch(e){return c(`${r} Component analysis failed:`,e),t}}async function R(e){return e.endsWith(`.vue`)?`vue`:e.endsWith(`.svelte`)?`svelte`:e.endsWith(`.tsx`)||e.endsWith(`.jsx`)||e.endsWith(`.ts`)||e.endsWith(`.js`)?p(e):`unknown`}async function z(e,t,n,r,i,a,o){let s=await R(e),c=s,u=await(await B(s,a)).render({component:o??null,props:n,src:e,condition:t,ssrOnly:r,viteServer:globalThis.__viteDevServer,isDev:l()});return j(u,e,s,a),P({src:e,condition:t,props:n,children:u.html,ssr:!0,framework:c,ssrOnly:r,renderOptions:i,hydrationData:r?void 0:u.hydrationData})}async function B(e,t){try{s(`${t} Loading integration for framework: ${e}`);let n=await _(e);return s(`${t} ✅ Integration loaded successfully`),n}catch(n){throw o(`${t} Failed to load ${e} integration:`,n),Error(`Failed to load integration for framework '${e}'. Make sure @useavalon/${e} is installed.\nInstall it with: deno add @useavalon/${e}`,{cause:n})}}export async function renderIsland({src:o,condition:s=`on:client`,conditionArg:c,props:d={},children:f,ssr:p=s!==`on:client`,framework:m,ssrOnly:h=!1,renderOptions:_={},component:v,server:y,island:b,key:x}){let C=l()?performance.now():0,w=`🏝️ [${o}]`;try{if(y){let s=i(o);r(s,o);let c=m||g(o),l=a(s,d,y,b,b?e(o):void 0,o,c);return S(t(n(),null,t(`div`,{dangerouslySetInnerHTML:{__html:l},"data-server-island-wrapper":``})),x)}return h&&!p&&(p=!0),S(m?await I({src:o,condition:s,conditionArg:c,props:d,children:f,ssr:p,framework:m,ssrOnly:h,renderOptions:_,component:v}):await V({src:o,condition:s,conditionArg:c,props:d,children:f,ssr:p,ssrOnly:h,renderOptions:_,logPrefix:w,component:v}),x)}catch(e){return S(F(o,e),x)}finally{l()&&u(o,performance.now()-C)}}async function V(e){let{src:t,condition:n,conditionArg:r,props:i,children:a,ssr:c,ssrOnly:l,renderOptions:u,logPrefix:d,component:f}=e;if(s(`🔍 [renderIsland] ${t} - Starting render (slow path)`,{ssr:c,ssrOnly:l,hasChildren:!!a,condition:n}),await L(t,l,u,d))return H(t,n,i,a,c,u,d);if(!c||a)return P({src:t,condition:n,conditionArg:r,props:i,children:a,ssr:c,renderOptions:u});try{return await z(t,n,i,l,u,d,f)}catch(e){let a=await R(t);return o(`${d} Framework rendering failed:`,e),P({src:t,condition:n,conditionArg:r,props:i,ssr:!1,framework:a,renderOptions:u})}}function H(e,t,n,r,i,a,s){return i&&!r?f({src:e,condition:t,props:n,renderOptions:a}).catch(r=>(o(`${s} SSR failed for SSR-only component:`,r),P({src:e,condition:t,props:n,ssr:!1,ssrOnly:!0,renderOptions:a}))):P({src:e,condition:t,props:n,children:r,ssr:i,ssrOnly:!0,renderOptions:a})}
1
+ import{getIslandBundlePath as e}from"../build/island-manifest.js";import{shellH as t,shellFragment as n}from"../render/shell-engine.js";import{addToManifest as r,generateComponentId as i}from"../server-islands/manifest.js";import{renderServerIsland as a}from"../server-islands/renderer.js";import{devError as o,devLog as s,devWarn as c,isDev as l,logRenderTiming as u}from"../utils/dev-logger.js";import{analyzeComponentFile as d,renderComponentSSROnly as f}from"./component-analysis.js";import{detectFramework as p}from"./framework-detection.js";import{isCustomDirective as m,serializeDirectiveScript as h}from"./hydration-directives.js";import{detectFrameworkFromPath as g,loadIntegration as _}from"./integration-loader.js";import{addModulepreload as v}from"./modulepreload-collector.js";import{generatePerIslandScript as y}from"./per-island-script.js";import{addUniversalCSS as b}from"./universal-css-collector.js";import{addUniversalHead as x}from"./universal-head-collector.js";function S(e,r){return r==null?e:t(n(),{key:r},e)}export function withListKey(e,t){return S(t,e)}let w=0;function T(e,t){return t||`island-${e.replaceAll(/[^a-zA-Z0-9]/g,`-`)}-${w++}`}function E(e,t){if(e===void 0)return;if(e===!0)return t;let n=e.trim();return n.length>0?n:void 0}function D(){return globalThis.__avalonHydrationMode===void 0?globalThis.__viteDevServer?!1:typeof __AVALON_PER_ISLAND__<`u`?__AVALON_PER_ISLAND__:!l():globalThis.__avalonHydrationMode===`per-island`}function O(r,i){if(!D()||i.shouldSkipHydration)return r;let a=e(i.src);i.condition===`on:client`&&v(a);let o=m(i.condition),s=o?h(i.condition):void 0,c=y({islandId:i.islandId,componentSrc:a,framework:i.framework,condition:i.condition,conditionArg:i.conditionArg,propsJson:JSON.stringify(i.props),isCustomDirective:o,directiveScript:s??void 0});return t(n(),null,r,t(`div`,{dangerouslySetInnerHTML:{__html:c},"data-island-script":``}))}function k(e){let t={};e.renderId&&(t[`data-solid-render-id`]=e.renderId);let n=e.metadata;return n?.tagName&&(t[`data-tag-name`]=n.tagName),t}function A(e){return JSON.stringify(e)}function j(t,n,r,i,a,o=`hydrate`){let s={"data-condition":n,"data-src":e(t),"data-props":A(r),"data-render-strategy":o,...k(i)};if(m(n)){s[`data-custom-directive`]=n;let e=h(n);e&&(s[`data-directive-script`]=e)}return a&&(s[`data-condition-arg`]=a),s}function M(e){return e.startsWith(`<script`)?`script`:e.startsWith(`<style`)?`style`:e.startsWith(`<meta`)?`meta`:e.startsWith(`<link`)?`link`:e.includes(`window._$HY`)||e.includes(`_$HY=`)?`script`:`other`}function N(e){let t=/<style[^>]*>([\s\S]*?)<\/style>/i.exec(e);return t?t[1].trim():null}function P(e,t,n,r){if(e.css&&b(e.css,t,n,e.scopeId),e.head){let i=e.head.trim(),a=M(i);if(a===`style`){let a=N(i);a&&(s(`${r} Extracting CSS from head <style> tag`),b(a,t,n,e.scopeId));return}x(e.head,t,n,a)}}function F(e){let{islandId:n,detectedFramework:r,shouldSkipHydration:i,src:a,condition:o,conditionArg:c,props:l,hydrationData:u,children:d,persist:f}=e,p={id:n,"data-framework":r},m=E(f,a);m&&(p[`data-router-persist`]=m);let h=i?{"data-render-strategy":`ssr-only`}:j(a,o,l,u,c);r===`lit`&&s(`🔍 [Island Component] ${a} - Lit hydration data:`,{hydrationDataKeys:Object.keys(u),metadata:u.metadata});let g={...p,...h},_;return _=typeof d==`string`?t(`avalon-island`,{...g,dangerouslySetInnerHTML:{__html:d}}):t(`avalon-island`,g,d),O(_,{islandId:n,src:a,condition:o,conditionArg:c,props:l,framework:r,shouldSkipHydration:i})}function I(n){let{islandId:r,detectedFramework:i,shouldSkipHydration:a,src:o,condition:s,props:c,hydrationData:l,conditionArg:u,persist:d,clientOnly:f}=n,p=E(d,o);if(a)return t(`avalon-island`,{id:r,"data-render-strategy":`ssr-only`,"data-framework":i,...p?{"data-router-persist":p}:{}});let g={id:r,"data-condition":s,"data-src":e(o),"data-props":A(c),"data-render-strategy":f?`client-only`:`hydrate`,"data-framework":i,...k(l)};if(p&&(g[`data-router-persist`]=p),m(s)){g[`data-custom-directive`]=s;let e=h(s);e&&(g[`data-directive-script`]=e)}return u&&(g[`data-condition-arg`]=u),O(t(`avalon-island`,g),{islandId:r,src:o,condition:s,conditionArg:u,props:c,framework:i,shouldSkipHydration:a})}export default function L({src:e,condition:t=`on:client`,conditionArg:n,props:r={},children:i,ssr:a,clientOnly:o,framework:l,ssrOnly:u=!1,renderOptions:d={},hydrationData:f={},id:p,persist:m}){let h=o===!0?!1:a??t!==`on:client`,_=T(e,p),v=u||!!d.forceSSROnly,y=l||g(e),b=i!=null&&i!==``;return s(`🔍 [Island Component] ${e}`,{ssr:h,ssrOnly:u,hasChildren:b,framework:l,condition:t}),h&&b?F({islandId:_,detectedFramework:y,shouldSkipHydration:v,src:e,condition:t,conditionArg:n,props:r,hydrationData:f,children:i,persist:m}):(h&&!b&&v&&c(`${e}: SSR-only component has no rendered content. This may indicate a rendering error.`),I({islandId:_,detectedFramework:y,shouldSkipHydration:v,src:e,condition:t,props:r,hydrationData:f,conditionArg:n,persist:m,clientOnly:!h}))}function R(n,r){let i=r instanceof Error?r.message:String(r);return o(`🚨 Island SSR failed for ${n}:`,r),r instanceof Error&&r.stack&&o(`Stack trace:`,r.stack),t(`avalon-island`,{id:T(n),"data-src":e(n),"data-ssr-error":i,"data-render-strategy":`client-only`})}async function z({src:e,condition:t,conditionArg:n,props:r,children:i,ssr:a,framework:s,ssrOnly:c,renderOptions:u,component:d,id:f,persist:p}){let m=`🏝️ [${e}]`;if(!a||i)return L({src:e,condition:t,conditionArg:n,props:r,children:i,ssr:a,framework:s,ssrOnly:c,renderOptions:u,id:f,persist:p});let h;try{h=await _(s)}catch(i){return o(`${m} Failed to load ${s} integration:`,i),L({src:e,condition:t,conditionArg:n,props:r,ssr:!1,framework:s,ssrOnly:c,renderOptions:u,id:f,persist:p})}try{let i=await h.render({component:d??null,props:r,src:e,condition:t,ssrOnly:c,viteServer:globalThis.__viteDevServer,isDev:l()});return P(i,e,s,m),L({src:e,condition:t,conditionArg:n,props:r,children:i.html,ssr:!0,framework:s,ssrOnly:c,renderOptions:u,hydrationData:c?void 0:i.hydrationData,id:f,persist:p})}catch(i){return o(`${m} Fast path SSR failed:`,i),L({src:e,condition:t,conditionArg:n,props:r,ssr:!1,framework:s,ssrOnly:c,renderOptions:u,id:f,persist:p})}}async function B(e,t,n,r){if(t||n.detectScripts===!1)return t;try{let t=await d(e,n);if(t.decision.warnings?.length)for(let e of t.decision.warnings)c(`${r} Analysis warning: ${e}`);return!t.decision.shouldHydrate}catch(e){return c(`${r} Component analysis failed:`,e),t}}async function V(e){return e.endsWith(`.vue`)?`vue`:e.endsWith(`.svelte`)?`svelte`:e.endsWith(`.tsx`)||e.endsWith(`.jsx`)||e.endsWith(`.ts`)||e.endsWith(`.js`)?p(e):`unknown`}async function H(e){let{src:t,condition:n,props:r,ssrOnly:i,renderOptions:a,logPrefix:o,preloadedComponent:s,id:c,persist:u}=e,d=await V(t),f=d,p=await(await U(d,o)).render({component:s??null,props:r,src:t,condition:n,ssrOnly:i,viteServer:globalThis.__viteDevServer,isDev:l()});return P(p,t,d,o),L({src:t,condition:n,props:r,children:p.html,ssr:!0,framework:f,ssrOnly:i,renderOptions:a,hydrationData:i?void 0:p.hydrationData,id:c,persist:u})}async function U(e,t){try{s(`${t} Loading integration for framework: ${e}`);let n=await _(e);return s(`${t} ✅ Integration loaded successfully`),n}catch(n){throw o(`${t} Failed to load ${e} integration:`,n),Error(`Failed to load integration for framework '${e}'. Make sure @useavalon/${e} is installed.\nInstall it with: deno add @useavalon/${e}`,{cause:n})}}export async function renderIsland({src:o,condition:s=`on:client`,conditionArg:c,props:d={},children:f,ssr:p,clientOnly:m,framework:h,ssrOnly:_=!1,renderOptions:v={},component:y,server:b,island:x,key:C,id:w,persist:T}){let E=m===!0?!1:p??s!==`on:client`,D=l()?performance.now():0,O=`🏝️ [${o}]`;try{if(b){let s=i(o);r(s,o);let c=h||g(o),l=a(s,d,b,x,x?e(o):void 0,o,c);return S(t(n(),null,t(`div`,{dangerouslySetInnerHTML:{__html:l},"data-server-island-wrapper":``})),C)}return _&&!E&&m!==!0&&(E=!0),S(h?await z({src:o,condition:s,conditionArg:c,props:d,children:f,ssr:E,framework:h,ssrOnly:_,renderOptions:v,component:y,id:w,persist:T}):await W({src:o,condition:s,conditionArg:c,props:d,children:f,ssr:E,ssrOnly:_,renderOptions:v,logPrefix:O,component:y,id:w,persist:T}),C)}catch(e){return S(R(o,e),C)}finally{l()&&u(o,performance.now()-D)}}async function W(e){let{src:t,condition:n,conditionArg:r,props:i,children:a,ssr:c,ssrOnly:l,renderOptions:u,logPrefix:d,component:f,id:p,persist:m}=e;if(s(`🔍 [renderIsland] ${t} - Starting render (slow path)`,{ssr:c,ssrOnly:l,hasChildren:!!a,condition:n}),await B(t,l,u,d))return G({src:t,condition:n,props:i,children:a,ssr:c,renderOptions:u,logPrefix:d,id:p,persist:m});if(!c||a)return L({src:t,condition:n,conditionArg:r,props:i,children:a,ssr:c,renderOptions:u,id:p,persist:m});try{return await H({src:t,condition:n,props:i,ssrOnly:l,renderOptions:u,logPrefix:d,preloadedComponent:f,id:p,persist:m})}catch(e){let a=await V(t);return o(`${d} Framework rendering failed:`,e),L({src:t,condition:n,conditionArg:r,props:i,ssr:!1,framework:a,renderOptions:u,id:p,persist:m})}}function G(e){let{src:t,condition:n,props:r,children:i,ssr:a,renderOptions:s,logPrefix:c,id:l,persist:u}=e;return a&&!i?f({src:t,condition:n,props:r,renderOptions:s}).catch(e=>(o(`${c} SSR failed for SSR-only component:`,e),L({src:t,condition:n,props:r,ssr:!1,ssrOnly:!0,renderOptions:s,id:l,persist:u}))):L({src:t,condition:n,props:r,children:i,ssr:a,ssrOnly:!0,renderOptions:s,id:l,persist:u})}
@@ -1 +1 @@
1
- export function escapeJsonForScript(e){return e.replaceAll(`<`,String.raw`\u003c`).replaceAll(`>`,String.raw`\u003e`).replaceAll(`&`,String.raw`\u0026`).replaceAll(`\u2028`,String.raw`\u2028`).replaceAll(`\u2029`,String.raw`\u2029`)}export function generatePerIslandScript(e){let{islandId:t,componentSrc:i,framework:a,condition:o,conditionArg:s,propsJson:c,isCustomDirective:l,directiveScript:u}=e;return`<script type="module">${r(t,o,n(t,i,a,c),s,l,u)}<\/script>`}function n(t,n,r,i){return[`async function h(){`,`var e=document.getElementById(${JSON.stringify(t)});`,`if(!e||e.dataset.hydrated)return;`,`try{`,`var p=${escapeJsonForScript(i)};`,`var m=await import(${JSON.stringify(n)});`,`var C=m.default||Object.values(m).find(function(v){return typeof v==="function"&&v.prototype})||m;`,`if(m.__hydrateIsland){await m.__hydrateIsland(e,C,p)}`,`else if(m.loadIntegrationModule){var i=await m.loadIntegrationModule(${JSON.stringify(r)});if(i.hydrate)await i.hydrate(e,C,p)}`,`e.dataset.hydrated="true";`,`}catch(err){console.error("Hydration error:",err)}`,`}`].join(``)}function r(e,t,n,r,i,a){if(t===`on:client`)return`${n}h();`;if(t===`on:visible`)return[n,`var e=document.getElementById(${JSON.stringify(e)});`,`if(e){try{var t=e.firstElementChild||e;var o=new IntersectionObserver(function(n){`,`if(n[0].isIntersecting){h();o.disconnect()}`,`},{rootMargin:"50px",threshold:0});o.observe(t)}catch(_){h()}}`].join(``);if(t===`on:idle`)return[n,`if("requestIdleCallback" in globalThis){`,`globalThis.requestIdleCallback(function(){h()},{timeout:5000})`,`}else if(document.readyState==="complete"){`,`setTimeout(function(){h()},200)`,`}else{globalThis.addEventListener("load",function(){setTimeout(function(){h()},200)},{once:true})}`].join(``);if(t===`on:interaction`)return[n,`var e=document.getElementById(${JSON.stringify(e)});`,`if(e){var t=e.firstElementChild||e;var d=false;var ev=["click","touchstart","mouseenter","focusin"];`,`var fn=function(){if(d)return;d=true;ev.forEach(function(n){t.removeEventListener(n,fn)});h()};`,`ev.forEach(function(n){t.addEventListener(n,fn,{once:true,passive:true})})}`].join(``);if(t.startsWith(`media:`)){let e=t.slice(6);return[n,`try{var mq=globalThis.matchMedia(${JSON.stringify(e)});`,`if(mq.matches){h()}else{mq.addEventListener("change",function x(ev){`,`if(ev.matches){h();mq.removeEventListener("change",x)}},{once:true})}}catch(_){h()}`].join(``)}if(i&&a){let t=r?`,${JSON.stringify(r)}`:``;return[n,`var e=document.getElementById(${JSON.stringify(e)});`,`if(e){var dir=(${a});`,`dir(e,function(){h()}${t})}`].join(``)}return`${n}h();`}
1
+ export function escapeJsonForScript(e){return e.replaceAll(`<`,String.raw`\u003c`).replaceAll(`>`,String.raw`\u003e`).replaceAll(`&`,String.raw`\u0026`).replaceAll(`\u2028`,String.raw`\u2028`).replaceAll(`\u2029`,String.raw`\u2029`)}export function generatePerIslandScript(e){let{islandId:t,componentSrc:i,framework:a,condition:o,conditionArg:s,propsJson:c,isCustomDirective:l,directiveScript:u}=e;return`<script type="module">${r(t,o,n(t,i,a,c),s,l,u)}<\/script>`}function n(t,n,r,i){return[`async function h(){`,`var e=document.getElementById(${JSON.stringify(t)});`,`if(!e||e.dataset.hydrated)return;`,`try{`,`var p=${escapeJsonForScript(i)};`,`var m=await import(${JSON.stringify(n)});`,`var C=m.default||Object.values(m).find(function(v){return typeof v==="function"&&v.prototype})||m;`,`var i;if(!m.__hydrateIsland&&!m.__mountIsland&&m.loadIntegrationModule){i=await m.loadIntegrationModule(${JSON.stringify(r)})}`,`var fn=e.dataset.renderStrategy==="client-only"?(m.__mountIsland||(i&&i.mount)):(m.__hydrateIsland||(i&&i.hydrate));`,`if(!fn)throw new Error("Integration does not export "+(e.dataset.renderStrategy==="client-only"?"mount":"hydrate"));`,`await fn(e,C,p)`,`e.dataset.hydrated="true";`,`}catch(err){console.error("Hydration error:",err)}`,`}`].join(``)}function r(e,t,n,r,i,a){if(t===`on:client`)return`${n}h();`;if(t===`on:visible`)return[n,`var e=document.getElementById(${JSON.stringify(e)});`,`if(e){try{var t=e.firstElementChild||e;var o=new IntersectionObserver(function(n){`,`if(n[0].isIntersecting){h();o.disconnect()}`,`},{rootMargin:"50px",threshold:0});o.observe(t)}catch(_){h()}}`].join(``);if(t===`on:idle`)return[n,`if("requestIdleCallback" in globalThis){`,`globalThis.requestIdleCallback(function(){h()},{timeout:5000})`,`}else if(document.readyState==="complete"){`,`setTimeout(function(){h()},200)`,`}else{globalThis.addEventListener("load",function(){setTimeout(function(){h()},200)},{once:true})}`].join(``);if(t===`on:interaction`)return[n,`var e=document.getElementById(${JSON.stringify(e)});`,`if(e){var t=e.firstElementChild||e;var d=false;var ev=["click","touchstart","mouseenter","focusin"];`,`var fn=function(){if(d)return;d=true;ev.forEach(function(n){t.removeEventListener(n,fn)});h()};`,`ev.forEach(function(n){t.addEventListener(n,fn,{once:true,passive:true})})}`].join(``);if(t.startsWith(`media:`)){let e=t.slice(6);return[n,`try{var mq=globalThis.matchMedia(${JSON.stringify(e)});`,`if(mq.matches){h()}else{mq.addEventListener("change",function x(ev){`,`if(ev.matches){h();mq.removeEventListener("change",x)}},{once:true})}}catch(_){h()}`].join(``)}if(i&&a){let t=r?`,${JSON.stringify(r)}`:``;return[n,`var e=document.getElementById(${JSON.stringify(e)});`,`if(e){var dir=(${a});`,`dir(e,function(){h()}${t})}`].join(``)}return`${n}h();`}
@@ -23,6 +23,8 @@ export interface IslandProps {
23
23
  children?: JSX.Element | JSX.Element[] | string;
24
24
  /** Whether to render server-side (default: true unless condition is 'on:client') */
25
25
  ssr?: boolean;
26
+ /** Skip component SSR and mount on the client. Forces `ssr: false`. */
27
+ clientOnly?: boolean;
26
28
  /** Framework hint for client hydration */
27
29
  framework?: "solid" | "vue" | "preact" | "react" | "svelte" | "lit" | "qwik";
28
30
  /** Force SSR-only rendering without hydration */
@@ -31,6 +33,8 @@ export interface IslandProps {
31
33
  renderOptions?: AnalyzerOptions;
32
34
  /** Server island configuration — defers rendering to a server endpoint after page load */
33
35
  server?: ServerIslandProp;
36
+ /** Explicit HTML id for this island instance. Unique per instance when omitted. */
37
+ id?: string;
34
38
  /** React/Preact list key — set on the host VNode, never serialized into props */
35
39
  key?: string | number;
36
40
  }
@@ -86,6 +86,7 @@ export interface RenderHandlerOptions {
86
86
  */
87
87
  enableCustomErrorPages?: boolean;
88
88
  }
89
+ type WrapWithLayouts = NonNullable<RenderHandlerOptions["wrapWithLayouts"]>;
89
90
  /**
90
91
  * Creates a render context from an H3 event
91
92
  *
@@ -300,7 +301,7 @@ export interface NitroCatchAllOptions {
300
301
  /** Optional layout resolver */
301
302
  resolveLayouts?: (routePath: string, config: AvalonRuntimeConfig) => Promise<string[]>;
302
303
  /** Wrap rendered page HTML with layout components (same as RenderHandlerOptions) */
303
- wrapWithLayouts?: RenderHandlerOptions["wrapWithLayouts"];
304
+ wrapWithLayouts?: WrapWithLayouts;
304
305
  /**
305
306
  * Enable custom error pages (404.tsx, 500.tsx, _error.tsx)
306
307
  * When enabled, the renderer will look for custom error pages in the pages directory
@@ -1,4 +1,4 @@
1
- import{getRequestURL as e}from"h3";import{inlineCriticalCSS as t}from"../islands/critical-css.js";import{injectModulepreloadLinks as n}from"../islands/modulepreload-collector.js";import{discoverScopedMiddleware as r,executeScopedMiddleware as i}from"../middleware/index.js";import{renderShell as a}from"../render/shell-engine.js";import{discoverErrorPages as o,handleRenderError as s}from"./error-handler.js";import{createNotFoundError as c,isHttpError as l}from"./types.js";function u(e,t){return{...e.context.params??{},...t.params}}async function d(e,t,n,r){return e.context.route||(r?r(t,n):A(t,n))}export function createRenderContext(e,t={}){let n=getRequestURL(e);return{url:n,params:t,query:Object.fromEntries(n.searchParams),request:toRequest(e),event:e}}export function createRenderContextFromRequest(e,t={}){let n=new URL(e.url,`http://localhost`),r={method:e.method,path:n.pathname+n.search,context:{params:t}};return{url:n,params:t,query:Object.fromEntries(n.searchParams),request:e,event:r}}export function getRequestURL(t){return new URL(e(t).pathname,`http://localhost`)}export function toRequest(e){let t=getRequestURL(e);return new Request(t,{method:e.req.method,headers:getRequestHeaders(e)})}export function getRequestHeaders(e){return new Headers}export function setResponseHeader(e,t,n){e.context.responseHeaders||(e.context.responseHeaders={}),e.context.responseHeaders[t]=n}export function createErrorResponse(e,t){let n=l(e)?e.statusCode:500;if(t){let t=v(e,n);return new Response(t,{status:n,headers:{"Content-Type":`text/html; charset=utf-8`}})}let r=y(n);return new Response(r,{status:n,headers:{"Content-Type":`text/html; charset=utf-8`}})}function v(e,t){return`<!DOCTYPE html>
1
+ import{getRequestURL as e}from"h3";import{clientNavigationResponseHeaders as t,isClientNavigationDisabled as n,stampClientNavigationOptOut as r}from"../client/router/opt-out.js";import{inlineCriticalCSS as i}from"../islands/critical-css.js";import{injectModulepreloadLinks as a}from"../islands/modulepreload-collector.js";import{discoverScopedMiddleware as o,executeScopedMiddleware as s}from"../middleware/index.js";import{renderShell as c}from"../render/shell-engine.js";import{discoverErrorPages as l,handleRenderError as u}from"./error-handler.js";import{createNotFoundError as d,isHttpError as f}from"./types.js";function p(e,t){return{...e.context.params??{},...t.params}}async function m(e,t,n,r){return e.context.route||(r?r(t,n):L(t,n))}export function createRenderContext(e,t={}){let n=getRequestURL(e);return{url:n,params:t,query:Object.fromEntries(n.searchParams),request:toRequest(e),event:e}}export function createRenderContextFromRequest(e,t={}){let n=new URL(e.url,`http://localhost`),r={method:e.method,path:n.pathname+n.search,context:{params:t}};return{url:n,params:t,query:Object.fromEntries(n.searchParams),request:e,event:r}}export function getRequestURL(t){return new URL(e(t).pathname,`http://localhost`)}export function toRequest(e){let t=getRequestURL(e);return new Request(t,{method:e.req.method,headers:getRequestHeaders(e)})}export function getRequestHeaders(e){return new Headers}export function setResponseHeader(e,t,n){e.context.responseHeaders||(e.context.responseHeaders={}),e.context.responseHeaders[t]=n}function g(e){return{"Content-Type":`text/html; charset=utf-8`,...t(n(e))}}function _(e,t){return a(i(injectHydrationScript(e,t)))}async function v(e,t,n,r){let i=await renderPage(e,t,{},r);return new Response(_(i.html,n),{status:i.statusCode,headers:i.headers})}async function y(e,t,n){let r=await renderPageStream(e,t,{onShellReady:()=>{for(let[t,r]of Object.entries(g(e)))setResponseHeader(n,t,r)}});return new Response(r,{headers:g(e)})}async function b(e,t,n,r,i,a){return i&&a?y(e,t,a):v(e,t,n,r)}async function x(e,t,n,r){try{return await e(t)}catch(i){try{return await e(n)}catch(e){return r&&(console.debug(`[renderer] Page not found: ${t}`,i),console.debug(`[renderer] Index fallback not found: ${n}`,e)),null}}}export function createErrorResponse(e,t){let n=f(e)?e.statusCode:500;if(t){let t=S(e,n);return new Response(t,{status:n,headers:{"Content-Type":`text/html; charset=utf-8`}})}let r=C(n);return new Response(r,{status:n,headers:{"Content-Type":`text/html; charset=utf-8`}})}function S(e,t){return`<!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8">
@@ -56,15 +56,15 @@ import{getRequestURL as e}from"h3";import{inlineCriticalCSS as t}from"../islands
56
56
  <body>
57
57
  <div class="error-container">
58
58
  <div class="status-code">${t}</div>
59
- <h1>${b(t)}</h1>
60
- <p class="message">${x(e.message)}</p>
59
+ <h1>${w(t)}</h1>
60
+ <p class="message">${T(e.message)}</p>
61
61
  ${e.stack?`
62
62
  <div class="stack-title">Stack Trace</div>
63
- <pre>${x(e.stack)}</pre>
63
+ <pre>${T(e.stack)}</pre>
64
64
  `:``}
65
65
  </div>
66
66
  </body>
67
- </html>`}function y(e){return`<!DOCTYPE html>
67
+ </html>`}function C(e){return`<!DOCTYPE html>
68
68
  <html lang="en">
69
69
  <head>
70
70
  <meta charset="utf-8">
@@ -113,47 +113,47 @@ import{getRequestURL as e}from"h3";import{inlineCriticalCSS as t}from"../islands
113
113
  <body>
114
114
  <div class="error-container">
115
115
  <div class="status-code">${e}</div>
116
- <h1>${b(e)}</h1>
116
+ <h1>${w(e)}</h1>
117
117
  <p><a href="/">Return to home</a></p>
118
118
  </div>
119
119
  </body>
120
- </html>`}function b(e){return{400:`Bad Request`,401:`Unauthorized`,403:`Forbidden`,404:`Page Not Found`,405:`Method Not Allowed`,500:`Internal Server Error`,502:`Bad Gateway`,503:`Service Unavailable`}[e]||`Error`}function x(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`>`,`&gt;`).replaceAll(`"`,`&quot;`).replaceAll(`'`,`&#039;`)}export function extractIslandMarkers(e){let t=[],n=/<[^>]*data-framework="([^"]+)"[^>]*>/g,r=n.exec(e);for(;r!==null;){let i=r[0],a=r[1],o=/data-src="([^"]+)"/.exec(i),s=o?o[1]:``,c=/data-props="([^"]*)"/.exec(i),l=c?c[1]:void 0,u=/data-hydrate="([^"]+)"/.exec(i),d=u?u[1]:void 0;t.push({framework:a,src:s,props:l,hydrate:d}),r=n.exec(e)}return t}export function ensureHydrationMarkers(e,t){let n=e;return t.framework&&!n.includes(`data-framework=`)&&(n=n.replace(/>/,` data-framework="${t.framework}">`)),t.src&&!n.includes(`data-src=`)&&(n=n.replace(/>/,` data-src="${t.src}">`)),t.props!==void 0&&!n.includes(`data-props=`)&&(n=n.replace(/>/,` data-props="${t.props}">`)),n}function S(e){return e.replaceAll(/<div[^>]*\bdata-island-script\b[^>]*>(<script[\s\S]*?<\/script>)<\/div>/g,`$1`)}export function injectHydrationScript(e,t,n={}){if(globalThis.__avalonHydrationMode===`per-island`||!t)return S(e);if(!(e.includes(`data-framework=`)||e.includes(`data-src=`))&&!n.forceInject||[`/src/client/main.js`,`/dist/client.js`,`client/main.js`,`entry-client`].some(t=>e.includes(t)))return e;let r=n.scriptPath||(t?`/src/client/main.js`:`/dist/client.js`),i=[];i.push(`<script type="module" src="${r}"><\/script>`),n.additionalScripts&&i.push(...n.additionalScripts);let a=i.join(`
121
- `);return e.includes(`</body>`)?e.replace(`</body>`,`${a}\n</body>`):e+a}export function validateHydrationMarkers(e){let t=extractIslandMarkers(e),n=e.match(/data-framework="[^"]+"/g)||[],r=e.match(/data-src="[^"]+"/g)||[],i=e.match(/data-props="[^"]*"/g)||[],a=e.includes(`/src/client/main.js`)||e.includes(`/dist/client.js`)||e.includes(`client/main.js`),o=t.every(e=>e.framework&&e.src),s=t.length===0||o&&a;return{hasFrameworkAttr:n.length>0,hasSrcAttr:r.length>0,hasPropsAttr:i.length>0,islandCount:n.length,islands:t,hasClientScript:a,isValid:s}}export function processHydrationRequirements(e,t){let n=injectHydrationScript(e,t);return{html:n,validation:validateHydrationMarkers(n)}}export async function renderPage(e,t,n={},r){try{let i={};return e.getServerSideProps&&(i=await e.getServerSideProps(t)),{html:await C(e,i,t,n,r),statusCode:200,headers:{"Content-Type":`text/html; charset=utf-8`}}}catch(e){throw console.error(`[SSR Error]`,e),n.onError&&e instanceof Error&&n.onError(e),e}}async function C(e,t,n,r,i){let o=e.default,s=e.metadata||{},c=process.env.NODE_ENV!==`production`,l,u=!1;try{let e=o(t);l=e instanceof Promise?await e:e}catch(e){console.error(`[renderer] Error calling page component:`,e),u=!0}let d;if(u)d=`<div>Error rendering page</div>`;else try{d=a(l)}catch(e){console.error(`[renderer] Error rendering page shell:`,e),d=`<div>Error rendering page</div>`}if(i)return await i(d,e,n);let f=c?`
120
+ </html>`}function w(e){return{400:`Bad Request`,401:`Unauthorized`,403:`Forbidden`,404:`Page Not Found`,405:`Method Not Allowed`,500:`Internal Server Error`,502:`Bad Gateway`,503:`Service Unavailable`}[e]||`Error`}function T(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`>`,`&gt;`).replaceAll(`"`,`&quot;`).replaceAll(`'`,`&#039;`)}function E(e,t){let n=`${t}="`,r=e.indexOf(n);if(r===-1)return;let i=r+n.length,a=e.indexOf(`"`,i);if(a!==-1)return e.slice(i,a)}export function extractIslandMarkers(e){let t=[],n=0;for(;n<e.length;){let r=e.indexOf(`data-framework="`,n);if(r===-1)break;let i=e.lastIndexOf(`<`,r),a=e.indexOf(`>`,r);if(i===-1||a===-1){n=r+16;continue}let o=e.slice(i,a+1),s=E(o,`data-framework`);if(!s){n=r+16;continue}t.push({framework:s,src:E(o,`data-src`)??``,props:E(o,`data-props`),hydrate:E(o,`data-hydrate`)}),n=a+1}return t}export function ensureHydrationMarkers(e,t){let n=e;return t.framework&&!n.includes(`data-framework=`)&&(n=n.replace(/>/,` data-framework="${t.framework}">`)),t.src&&!n.includes(`data-src=`)&&(n=n.replace(/>/,` data-src="${t.src}">`)),t.props!==void 0&&!n.includes(`data-props=`)&&(n=n.replace(/>/,` data-props="${t.props}">`)),n}function D(e){return e.replaceAll(/<div[^>]*\bdata-island-script\b[^>]*>(<script[\s\S]*?<\/script>)<\/div>/g,`$1`)}export function injectHydrationScript(e,t,n={}){e=D(e);let r=globalThis.__avalonHydrationMode;if(r===`per-island`||r===void 0&&!t||!(e.includes(`data-framework=`)||e.includes(`data-src=`))&&!n.forceInject||[`/src/client/main.js`,`/dist/client.js`,`client/main.js`,`entry-client`].some(t=>e.includes(t)))return e;let i=n.scriptPath||(t?`/src/client/main.js`:`/dist/client.js`),a=[];a.push(`<script type="module" src="${i}"><\/script>`),n.additionalScripts&&a.push(...n.additionalScripts);let o=a.join(`
121
+ `);return e.includes(`</body>`)?e.replace(`</body>`,`${o}\n</body>`):e+o}export function validateHydrationMarkers(e){let t=extractIslandMarkers(e),n=e.match(/data-framework="[^"]+"/g)||[],r=e.match(/data-src="[^"]+"/g)||[],i=e.match(/data-props="[^"]*"/g)||[],a=e.includes(`/src/client/main.js`)||e.includes(`/dist/client.js`)||e.includes(`client/main.js`),o=t.every(e=>e.framework&&e.src),s=t.length===0||o&&a;return{hasFrameworkAttr:n.length>0,hasSrcAttr:r.length>0,hasPropsAttr:i.length>0,islandCount:n.length,islands:t,hasClientScript:a,isValid:s}}export function processHydrationRequirements(e,t){let n=injectHydrationScript(e,t);return{html:n,validation:validateHydrationMarkers(n)}}export async function renderPage(e,t,i={},a){try{let o={};e.getServerSideProps&&(o=await e.getServerSideProps(t));let s=await O(e,o,t,i,a);return n(e)&&(s=r(s)),{html:s,statusCode:200,headers:g(e)}}catch(e){throw console.error(`[SSR Error]`,e),i.onError&&e instanceof Error&&i.onError(e),e}}async function O(e,t,n,r,i){let a=e.default,o=e.metadata||{},s=process.env.NODE_ENV!==`production`,l,u=!1;try{let e=a(t);l=e instanceof Promise?await e:e}catch(e){console.error(`[renderer] Error calling page component:`,e),u=!0}let d;if(u)d=`<div>Error rendering page</div>`;else try{d=c(l)}catch(e){console.error(`[renderer] Error rendering page shell:`,e),d=`<div>Error rendering page</div>`}if(i)return await i(d,e,n);let f=s?`
122
122
  <script type="module" src="/src/client/main.js"><\/script>`:``;return`<!DOCTYPE html>
123
123
  <html lang="en">
124
124
  <head>
125
125
  <meta charset="utf-8">
126
126
  <meta name="viewport" content="width=device-width, initial-scale=1">
127
- <title>${x(String(s.title||`Avalon App`))}</title>
128
- ${s.description?`<meta name="description" content="${x(String(s.description))}">`:``}
127
+ <title>${T(String(o.title||`Avalon App`))}</title>
128
+ ${o.description?`<meta name="description" content="${T(String(o.description))}">`:``}
129
129
  </head>
130
130
  <body>
131
131
  <div id="app">
132
132
  ${d}
133
133
  </div>${f}
134
134
  </body>
135
- </html>`}export async function renderPageStream(e,t,n={}){let r=new TextEncoder,i=null,o={shellSent:!1,contentSent:!1,closed:!1,error:null},s=n.shellReadyTimeout,c=n.allReadyTimeout,l=null,u=null,d=()=>{l&&=(clearTimeout(l),null),u&&=(clearTimeout(u),null)};function f(e,t,n,r,i,a,o){if(n.error=e,a(),console.error(`[Streaming Error]`,{message:e.message,stack:e.stack,shellSent:n.shellSent,isShellError:t,timestamp:new Date().toISOString()}),t&&o.onShellError&&o.onShellError(e),o.onError&&o.onError(e),!n.closed&&r){if(n.shellSent){let t=D(e);r.enqueue(i.encode(t));let n=E();r.enqueue(i.encode(n))}else{let t=v(e,500);r.enqueue(i.encode(t))}n.closed=!0,r.close()}}async function p(s){i=s;let p={};e.getServerSideProps&&(p=await e.getServerSideProps(t));let m=w(e.metadata||{},t);if(o.closed||(s.enqueue(r.encode(m)),o.shellSent=!0,l&&=(clearTimeout(l),null),n.onShellReady&&n.onShellReady()),c&&c>0&&(u=setTimeout(()=>{!o.contentSent&&!o.closed&&f(Error(`All ready timeout after ${c}ms`),!1,o,i,r,d,n)},c)),!o.closed){let t=e.default;if(t&&typeof t==`function`){let n=t(p);if(n&&typeof n.then==`function`)try{let e=a(await n);s.enqueue(r.encode(` <div id="app">${e}</div>\n`))}catch(t){console.error(`[streaming] Async component error:`,t);let n=T(e,p);s.enqueue(r.encode(n))}else{let t=T(e,p);s.enqueue(r.encode(t))}}else{let t=T(e,p);s.enqueue(r.encode(t))}o.contentSent=!0}if(!o.closed){let e=E();s.enqueue(r.encode(e))}d(),n.onAllReady&&!o.closed&&n.onAllReady(),o.closed||(o.closed=!0,s.close())}return new ReadableStream({async start(e){i=e,s&&s>0&&(l=setTimeout(()=>{!o.shellSent&&!o.closed&&f(Error(`Shell ready timeout after ${s}ms`),!0,o,i,r,d,n)},s));try{await p(e)}catch(e){f(e instanceof Error?e:Error(String(e)),!o.shellSent,o,i,r,d,n)}},cancel(){if(d(),!o.closed&&i){o.closed=!0;try{i.close()}catch{}}}})}function w(e,t){return`<!DOCTYPE html>
135
+ </html>`}function k(e,t,i,a,o,s,c){let l=j(i.metadata||{},a),u=n(i)?r(l):l;e.enqueue(t.encode(u)),o.shellSent=!0,s(),c?.()}async function A(e,t,n,r){let i=n.default;if(typeof i!=`function`){e.enqueue(t.encode(M(n,r)));return}let a=i(r);if(a&&typeof a.then==`function`)try{let n=c(await a);e.enqueue(t.encode(` <div id="app">${n}</div>\n`));return}catch(e){console.error(`[streaming] Async component error:`,e)}e.enqueue(t.encode(M(n,r)))}export async function renderPageStream(e,t,n={}){let r=new TextEncoder,i=null,a={shellSent:!1,contentSent:!1,closed:!1,error:null},o=n.shellReadyTimeout,s=n.allReadyTimeout,c=null,l=null,u=()=>{c&&=(clearTimeout(c),null),l&&=(clearTimeout(l),null)};function d(e,t,n,r,i,a,o){if(n.error=e,a(),console.error(`[Streaming Error]`,{message:e.message,stack:e.stack,shellSent:n.shellSent,isShellError:t,timestamp:new Date().toISOString()}),t&&o.onShellError&&o.onShellError(e),o.onError&&o.onError(e),!n.closed&&r){if(n.shellSent){let t=P(e);r.enqueue(i.encode(t));let n=N();r.enqueue(i.encode(n))}else{let t=S(e,500);r.enqueue(i.encode(t))}n.closed=!0,r.close()}}async function f(o){i=o;let f={};e.getServerSideProps&&(f=await e.getServerSideProps(t)),a.closed||k(o,r,e,t,a,()=>{c&&=(clearTimeout(c),null)},n.onShellReady),s&&s>0&&(l=setTimeout(()=>{!a.contentSent&&!a.closed&&d(Error(`All ready timeout after ${s}ms`),!1,a,i,r,u,n)},s)),a.closed||(await A(o,r,e,f),a.contentSent=!0),a.closed||o.enqueue(r.encode(N())),u(),n.onAllReady&&!a.closed&&n.onAllReady(),a.closed||(a.closed=!0,o.close())}return new ReadableStream({async start(e){i=e,o&&o>0&&(c=setTimeout(()=>{!a.shellSent&&!a.closed&&d(Error(`Shell ready timeout after ${o}ms`),!0,a,i,r,u,n)},o));try{await f(e)}catch(e){d(e instanceof Error?e:Error(String(e)),!a.shellSent,a,i,r,u,n)}},cancel(){if(u(),!a.closed&&i){a.closed=!0;try{i.close()}catch{}}}})}function j(e,t){return`<!DOCTYPE html>
136
136
  <html lang="en">
137
137
  <head>
138
138
  <meta charset="utf-8">
139
139
  <meta name="viewport" content="width=device-width, initial-scale=1">
140
- <title>${x(String(e.title||`Avalon App`))}</title>
141
- ${e.description?`<meta name="description" content="${x(String(e.description))}">`:``}
140
+ <title>${T(String(e.title||`Avalon App`))}</title>
141
+ ${e.description?`<meta name="description" content="${T(String(e.description))}">`:``}
142
142
  </head>
143
143
  <body>
144
- `}function T(e,t){let n=e.default;if(n&&typeof n==`function`)try{let e=n(t);if(e&&typeof e.then==`function`){let e=n.name||`Page`;return` <div id="app" data-page="${x(String(e))}" data-props='${x(JSON.stringify(t))}'>
144
+ `}function M(e,t){let n=e.default;if(n&&typeof n==`function`)try{let e=n(t);if(e&&typeof e.then==`function`){let e=n.name||`Page`;return` <div id="app" data-page="${T(String(e))}" data-props='${T(JSON.stringify(t))}'>
145
145
  <!-- Async component — awaiting hydration -->
146
- </div>\n`}return` <div id="app">${a(e)}</div>\n`}catch(e){console.error(`[streaming] Error rendering page component:`,e)}let r=e.default?.name||`Page`;return` <div id="app" data-page="${x(String(r))}" data-props='${x(JSON.stringify(t))}'>
146
+ </div>\n`}return` <div id="app">${c(e)}</div>\n`}catch(e){console.error(`[streaming] Error rendering page component:`,e)}let r=e.default?.name||`Page`;return` <div id="app" data-page="${T(String(r))}" data-props='${T(JSON.stringify(t))}'>
147
147
  <!-- Component render fallback -->
148
- </div>\n`}function E(){return` </body>
149
- </html>`}function D(e){let t=process.env.NODE_ENV!==`production`,n=e.stack?`<pre style="
148
+ </div>\n`}function N(){return` </body>
149
+ </html>`}function P(e){let t=process.env.NODE_ENV!==`production`,n=e.stack?`<pre style="
150
150
  background: #f5f5f5;
151
151
  padding: 10px;
152
152
  border-radius: 4px;
153
153
  overflow-x: auto;
154
154
  font-size: 12px;
155
155
  margin-top: 10px;
156
- ">${x(e.stack)}</pre>`:``;return`
156
+ ">${T(e.stack)}</pre>`:``;return`
157
157
  <div class="streaming-error-boundary" data-error-boundary="true" style="
158
158
  background: #fff3cd;
159
159
  border: 2px solid #ffc107;
@@ -175,10 +175,10 @@ import{getRequestURL as e}from"h3";import{inlineCriticalCSS as t}from"../islands
175
175
  Error Details (Development Mode)
176
176
  </summary>
177
177
  <div style="margin-top: 10px;">
178
- <p><strong>Error:</strong> ${x(e.message)}</p>
178
+ <p><strong>Error:</strong> ${T(e.message)}</p>
179
179
  ${n}
180
180
  </div>
181
181
  </details>
182
182
  `:``}
183
183
  </div>
184
- `}export function createStreamingResponse(e,t={}){let n=new Headers({"Content-Type":`text/html; charset=utf-8`,"Transfer-Encoding":`chunked`,...t.headers});return new Response(e,{status:t.status||200,headers:n})}function O(e,t,n){return async()=>(e.value??=await r({baseDir:t,devMode:n}),e.value)}function k(e,t,n){return async(r,i)=>e?s(r,i,t):createErrorResponse(r,n)}export function createNitroRenderer(e){let{avalonConfig:r,isDev:a=!1,enableCustomErrorPages:s=!0}=e,l={isDev:a,avalonConfig:r,loadPageModule:e.loadPageModule,pagesDir:r.pagesDir};s&&o(l).catch(e=>{console.warn(`[renderer] Failed to discover error pages:`,e)});let h=O({value:null},r.srcDir||`src`,a),g=k(s,l,a);async function v(o){let s=getRequestURL(o).pathname;if(s.startsWith(`/_server-islands/`))return new Response(`Not handled by renderer`,{status:404});try{let l=await i(o,await h(),{devMode:a});if(l)return a&&console.log(`[renderer] Middleware terminated request for ${s}`),l;let p=await d(o,s,r.pagesDir,e.resolvePageRoute);if(!p)return g(c(`Page not found: ${s}`),o);let m=e.loadPageModule?await e.loadPageModule(p.filePath):await j(p.filePath),_=createRenderContext(o,u(o,p));if(e.resolveLayouts&&(_.layoutContext={layouts:await e.resolveLayouts(s,r)}),r.streaming&&!e.wrapWithLayouts){let e=await renderPageStream(m,_,{onShellReady:()=>{setResponseHeader(o,`Content-Type`,`text/html; charset=utf-8`)}});return new Response(e,{headers:{"Content-Type":`text/html; charset=utf-8`}})}else{let r=await renderPage(m,_,{},e.wrapWithLayouts),i=injectHydrationScript(r.html,a);return i=t(i),i=n(i),new Response(i,{status:r.statusCode,headers:r.headers})}}catch(e){return console.error(`[Nitro Renderer Error]`,e),g(e instanceof Error?e:Error(String(e)),o)}}return Object.assign(v,{async fetch(i){let o=new URL(i.url,`http://localhost`).pathname;if(o.startsWith(`/_server-islands/`))return new Response(`Not handled by renderer`,{status:404});try{let s=null;if(s=e.resolvePageRoute?await e.resolvePageRoute(o,r.pagesDir):await A(o,r.pagesDir),!s)return createErrorResponse(c(`Page not found: ${o}`),a);let l=await renderPage(e.loadPageModule?await e.loadPageModule(s.filePath):await j(s.filePath),createRenderContextFromRequest(i,s.params),{},e.wrapWithLayouts),u=injectHydrationScript(l.html,a);return u=t(u),u=n(u),new Response(u,{status:l.statusCode,headers:l.headers})}catch(e){return console.error(`[Nitro Renderer .fetch() Error]`,e),createErrorResponse(e instanceof Error?e:Error(String(e)),a)}}})}async function A(e,t){return e===`/`||e===``?{filePath:`src/pages/index.tsx`,pattern:`/`,params:{}}:{filePath:`src/pages/${e.replace(/^\//,``).replace(/\/$/,``)}.tsx`,pattern:e,params:{}}}async function j(e){return{default:()=>null,metadata:{title:`Avalon Page`}}}export function createNitroCatchAllRenderer(e){let{avalonConfig:r,isDev:a=!1,loadPageModule:s,resolveLayouts:l,enableCustomErrorPages:u=!0}=e,d={isDev:a,avalonConfig:r,loadPageModule:s,pagesDir:r.pagesDir};u&&o(d).catch(e=>{console.warn(`[renderer] Failed to discover error pages:`,e)});let h=O({value:null},r.srcDir||`src`,a),g=k(u,d,a);async function v(o){let u=getRequestURL(o).pathname;if(u.startsWith(`/_server-islands/`))return new Response(`Not handled by renderer`,{status:404});try{let d=await i(o,await h(),{devMode:a});if(d)return a&&console.log(`[renderer] Middleware terminated request for ${u}`),d;let p=o.context.params||{},m=p.slug||u.replace(/^\//,``)||`index`,_=`${r.pagesDir}/${m}.tsx`,v;try{v=await s(_)}catch(e){try{v=await s(`${r.pagesDir}/${m}/index.tsx`)}catch(t){return a&&(console.debug(`[renderer] Page not found: ${_}`,e),console.debug(`[renderer] Index fallback not found: ${r.pagesDir}/${m}/index.tsx`,t)),g(c(`Page not found: ${u}`),o)}}let y=createRenderContext(o,p);if(l&&(y.layoutContext={layouts:await l(u,r)}),r.streaming&&!e.wrapWithLayouts){let e=await renderPageStream(v,y,{onShellReady:()=>{setResponseHeader(o,`Content-Type`,`text/html; charset=utf-8`)}});return new Response(e,{headers:{"Content-Type":`text/html; charset=utf-8`}})}else{let r=await renderPage(v,y,{},e.wrapWithLayouts),i=injectHydrationScript(r.html,a);return i=t(i),i=n(i),new Response(i,{status:r.statusCode,headers:r.headers})}}catch(e){return console.error(`[Nitro Catch-All Renderer Error]`,e),g(e instanceof Error?e:Error(String(e)),o)}}return Object.assign(v,{async fetch(i){let o=new URL(i.url,`http://localhost`).pathname;if(o.startsWith(`/_server-islands/`))return new Response(`Not handled by renderer`,{status:404});try{let l=o.replace(/^\//,``)||`index`,u=`${r.pagesDir}/${l}.tsx`,d;try{d=await s(u)}catch{try{d=await s(`${r.pagesDir}/${l}/index.tsx`)}catch{return createErrorResponse(c(`Page not found: ${o}`),a)}}let f=createRenderContextFromRequest(i),m=await renderPage(d,f,{},e.wrapWithLayouts),h=injectHydrationScript(m.html,a);return h=t(h),h=n(h),new Response(h,{status:m.statusCode,headers:m.headers})}catch(e){return console.error(`[Nitro CatchAll .fetch() Error]`,e),createErrorResponse(e instanceof Error?e:Error(String(e)),a)}}})}export{clearMiddlewareCache as clearRendererMiddlewareCache}from"../middleware/index.js";
184
+ `}export function createStreamingResponse(e,t={}){let n=new Headers({"Content-Type":`text/html; charset=utf-8`,"Transfer-Encoding":`chunked`,...t.headers});return new Response(e,{status:t.status||200,headers:n})}function F(e,t,n){return async()=>(e.value??=await o({baseDir:t,devMode:n}),e.value)}function I(e,t,n){return async(r,i)=>e?u(r,i,t):createErrorResponse(r,n)}export function createNitroRenderer(e){let{avalonConfig:t,isDev:n=!1,enableCustomErrorPages:r=!0}=e,i={isDev:n,avalonConfig:t,loadPageModule:e.loadPageModule,pagesDir:t.pagesDir};r&&l(i).catch(e=>{console.warn(`[renderer] Failed to discover error pages:`,e)});let a=F({value:null},t.srcDir||`src`,n),o=I(r,i,n);async function c(r){let i=getRequestURL(r).pathname;if(i.startsWith(`/_server-islands/`))return new Response(`Not handled by renderer`,{status:404});try{let c=await s(r,await a(),{devMode:n});if(c)return n&&console.log(`[renderer] Middleware terminated request for ${i}`),c;let l=await m(r,i,t.pagesDir,e.resolvePageRoute);if(!l)return o(d(`Page not found: ${i}`),r);let u=e.loadPageModule?await e.loadPageModule(l.filePath):await R(l.filePath),f=createRenderContext(r,p(r,l));return e.resolveLayouts&&(f.layoutContext={layouts:await e.resolveLayouts(i,t)}),b(u,f,n,e.wrapWithLayouts,!!(t.streaming&&!e.wrapWithLayouts),r)}catch(e){return console.error(`[Nitro Renderer Error]`,e),o(e instanceof Error?e:Error(String(e)),r)}}return Object.assign(c,{async fetch(r){let i=new URL(r.url,`http://localhost`).pathname;if(i.startsWith(`/_server-islands/`))return new Response(`Not handled by renderer`,{status:404});try{let a=null;return a=e.resolvePageRoute?await e.resolvePageRoute(i,t.pagesDir):await L(i,t.pagesDir),a?v(e.loadPageModule?await e.loadPageModule(a.filePath):await R(a.filePath),createRenderContextFromRequest(r,a.params),n,e.wrapWithLayouts):createErrorResponse(d(`Page not found: ${i}`),n)}catch(e){return console.error(`[Nitro Renderer .fetch() Error]`,e),createErrorResponse(e instanceof Error?e:Error(String(e)),n)}}})}async function L(e,t){return e===`/`||e===``?{filePath:`src/pages/index.tsx`,pattern:`/`,params:{}}:{filePath:`src/pages/${e.replace(/^\//,``).replace(/\/$/,``)}.tsx`,pattern:e,params:{}}}async function R(e){return{default:()=>null,metadata:{title:`Avalon Page`}}}export function createNitroCatchAllRenderer(e){let{avalonConfig:t,isDev:n=!1,loadPageModule:r,resolveLayouts:i,enableCustomErrorPages:a=!0}=e,o={isDev:n,avalonConfig:t,loadPageModule:r,pagesDir:t.pagesDir};a&&l(o).catch(e=>{console.warn(`[renderer] Failed to discover error pages:`,e)});let c=F({value:null},t.srcDir||`src`,n),u=I(a,o,n);async function f(a){let o=getRequestURL(a).pathname;if(o.startsWith(`/_server-islands/`))return new Response(`Not handled by renderer`,{status:404});try{let l=await s(a,await c(),{devMode:n});if(l)return n&&console.log(`[renderer] Middleware terminated request for ${o}`),l;let f=a.context.params||{},p=f.slug||o.replace(/^\//,``)||`index`,m=await x(r,`${t.pagesDir}/${p}.tsx`,`${t.pagesDir}/${p}/index.tsx`,n);if(!m)return u(d(`Page not found: ${o}`),a);let h=createRenderContext(a,f);return i&&(h.layoutContext={layouts:await i(o,t)}),b(m,h,n,e.wrapWithLayouts,!!(t.streaming&&!e.wrapWithLayouts),a)}catch(e){return console.error(`[Nitro Catch-All Renderer Error]`,e),u(e instanceof Error?e:Error(String(e)),a)}}return Object.assign(f,{async fetch(i){let a=new URL(i.url,`http://localhost`).pathname;if(a.startsWith(`/_server-islands/`))return new Response(`Not handled by renderer`,{status:404});try{let o=a.replace(/^\//,``)||`index`,s=await x(r,`${t.pagesDir}/${o}.tsx`,`${t.pagesDir}/${o}/index.tsx`,!1);return s?v(s,createRenderContextFromRequest(i),n,e.wrapWithLayouts):createErrorResponse(d(`Page not found: ${a}`),n)}catch(e){return console.error(`[Nitro CatchAll .fetch() Error]`,e),createErrorResponse(e instanceof Error?e:Error(String(e)),n)}}})}export{clearMiddlewareCache as clearRendererMiddlewareCache}from"../middleware/index.js";
@@ -178,6 +178,11 @@ export interface PageModule {
178
178
  getStaticProps?: () => Promise<Record<string, unknown>>;
179
179
  /** Optional getServerSideProps for SSR */
180
180
  getServerSideProps?: (context: NitroRenderContext) => Promise<Record<string, unknown>>;
181
+ /**
182
+ * When `false`, client navigation falls back to a full load for this route.
183
+ * MDX can set the same flag via frontmatter.
184
+ */
185
+ clientNavigation?: boolean;
181
186
  }
182
187
  /**
183
188
  * Page metadata for SEO and configuration
@@ -41,6 +41,12 @@ export interface PostBuildOptions {
41
41
  prerender?: PrerenderConfig | false;
42
42
  /** Port for prerender server (default: 13172) */
43
43
  prerenderPort?: number;
44
+ /**
45
+ * Keep the shared `entry-client` script (and its modulepreload) in
46
+ * prerendered HTML. Required when `clientRouter` is enabled so client
47
+ * navigation can rescan islands after a swap.
48
+ */
49
+ clientRouter?: boolean;
44
50
  }
45
51
  /**
46
52
  * Ensure the SSR client-assets `css` array lists global stylesheets (`index-*.css`
@@ -1,7 +1,7 @@
1
1
  import{copyFileSync as e,cpSync as t,existsSync as n,mkdirSync as r,readdirSync as i,readFileSync as a,statSync as o,unlinkSync as s,writeFileSync as c}from"node:fs";import{basename as l,dirname as u,join as d,relative as f}from"node:path";import{patchCloudflareWorkerOutput as p}from"./cloudflare-worker-patch.js";import{fetchHandlerWrapperSource as m}from"./fetch-handler-wrapper.js";function h(e,t,r=[]){if(!n(e))return r;for(let n of i(e,{withFileTypes:!0})){let i=d(e,n.name);n.isDirectory()?h(i,t,r):t(n.name)&&r.push(i)}return r}function g(e){try{return o(e).isFile()}catch{return!1}}function _(e){let t=d(e,`dist`,`_worker.js`);if(g(t))return t;if(!n(t))return null;for(let e of[`index.js`,`index.mjs`]){let n=d(t,e);if(g(n))return n}return null}function v(e){let t=d(e,`dist`,`_worker.js`,`_ssr`,`ssr.mjs`);return g(t)?t:null}function y(e){if(!n(e))return!1;let t=a(e,`utf-8`);return t.length<500&&!t.includes(`data-framework`)&&!t.includes(`avalon`)}function b(e){for(let t of[`dist/index.html`,`.netlify/functions-internal/server/public/index.html`,`.output/public/index.html`]){let r=d(e,t);y(r)?(s(r),console.log(`[cleanup] Removed stale Vite template ${t}`)):n(r)&&console.log(`[cleanup] Kept ${t} (not a Vite template)`)}}function x(e){return e.replaceAll(/\/\*[\s\S]*?\*\//g,``).replaceAll(/\s+/g,` `).replaceAll(/\s*([{}:;,])\s*/g,`$1`).trim()}export function patchSSRBundleCSS(e,t,r){if(!g(e))return!1;let i=[d(t,`assets`),d(r,`.netlify`,`functions-internal`,`server`,`public`,`assets`),d(r,`.output`,`public`,`assets`)].find(e=>n(e));if(!i)return!1;let o=h(i,e=>e.endsWith(`.css`)).filter(e=>{let t=(e.split(`/`).pop()||``).toLowerCase();return t.includes(`_isolated-island-entry`)?!1:!!(t.startsWith(`entry-client`)||t.startsWith(`index-`))}).map(e=>`/assets${e.substring(i.length).replaceAll(`\\`,`/`)}`);if(!o.some(e=>/\/index-[^/]+\.css$/.test(e))){let e=h(i,e=>e.endsWith(`.css`)).filter(e=>(e.split(`/`).pop()||``).toLowerCase().startsWith(`ssr-index`)).map(e=>`/assets${e.substring(i.length).replaceAll(`\\`,`/`)}`);o.push(...e)}console.log(`[patch] Found ${o.length} CSS files in ${i}`);let s=a(e,`utf-8`),l=[{re:/"css"\s*:\s*\[((?:\s*\{\s*"href"\s*:\s*"[^"]+"\s*\}\s*,?)*)\]/,hrefRe:/"href"\s*:\s*"([^"]+)"/g,formatEntry:e=>`{ "href": "${e}" }`,rebuild:(e,t)=>{let n=e.trim().replace(/,\s*$/,``);return`"css": [${[...n?[n]:[],...t].join(`, `)}]`}},{re:/css:\[(\{href:`[^`]+`\}(?:,\{href:`[^`]+`\})*)\]/,hrefRe:/href:`([^`]+)`/g,formatEntry:e=>`{href:\`${e}\`}`,rebuild:(e,t)=>`css:[${e},${t.join(`,`)}]`},{re:/css:\[(\{href:"[^"]+"\}(?:,\{href:"[^"]+"\})*)\]/,hrefRe:/href:"([^"]+)"/g,formatEntry:e=>`{href:"${e}"}`,rebuild:(e,t)=>`css:[${e},${t.join(`,`)}]`}];for(let{re:t,hrefRe:n,formatEntry:r,rebuild:i}of l){let a=t.exec(s);if(!a)continue;let l=new Set([...a[1].matchAll(n)].map(e=>e[1])),u=o.filter(e=>!l.has(e));if(u.length===0)return console.log(`[patch] All CSS already included`),!0;let d=u.map(r);return s=s.replace(a[0],i(a[1],d)),c(e,s),console.log(`[patch] ✅ Added ${u.length} CSS files to SSR bundle`),!0}return console.warn(`[patch] Could not find CSS array in SSR bundle`),!1}function C(e,t){let o=d(t,`assets`);if(n(o)&&i(o).some(e=>e.startsWith(`entry-client`)&&e.endsWith(`.css`))){console.log(`[ssr-css] Skipped — client build already includes entry-client CSS`);return}let s=[d(e,`node_modules`,`.nitro`,`vite`,`services`,`ssr`,`assets`)];for(let o of s){if(!n(o))continue;let s=i(o).filter(e=>e.endsWith(`.css`));if(s.length===0)continue;let l=[d(t,`assets`),d(e,`.output`,`public`,`assets`),d(e,`.netlify`,`functions-internal`,`server`,`public`,`assets`)];for(let e of l){r(e,{recursive:!0});for(let t of s){let n=a(d(o,t),`utf-8`);n=x(n),c(d(e,`ssr-${t}`),n)}}let u=`ssr-${s[0]}`,f=d(l.find(e=>n(e))||l[0],u),p=n(f)?a(f).length:0;console.log(`[ssr-css] Copied SSR CSS → /assets/${u} (${p} bytes, minified)`);let m=[d(e,`.output`,`server`,`index.mjs`),d(e,`.netlify`,`functions-internal`,`server`,`main.mjs`)];for(let e of m){if(!n(e))continue;let t=a(e,`utf-8`),r=`/assets/${u}`;if(t.includes(r))continue;let i=/"\/assets\/[^"]+\.css":\{type:`text\/css[^}]+\}/.exec(t);if(i){let n=new Date().toISOString(),a=`,"${r}":{type:\`text/css; charset=utf-8\`,etag:\`${`"${p.toString(16)}-ssr"`}\`,mtime:\`${n}\`,size:${p},path:\`../public/assets/${u}\`}`;t=t.replace(i[0],i[0]+a),c(e,t),console.log(`[ssr-css] ✅ Patched asset manifest in ${e}`)}}return}console.log(`[ssr-css] No SSR CSS files found`)}async function w(e,t){let r=d(t,`islands`);if(!n(r)){console.log(`[islands] No islands directory found, skipping isolation`);return}let i=h(r,e=>e.endsWith(`.js`)&&!e.endsWith(`.js.map`));if(!i.some(e=>{let t=a(e,`utf-8`);return t.includes(`from"../`)||t.includes(`from'../`)})){console.log(`[islands] All islands are self-contained`);return}try{let{buildIsolatedIslands:r}=await import(`./isolated-island-builder.js`),o=new Map;for(let r of i){let i=f(t,r).replaceAll(`\\`,`/`).replace(/^islands\//,``).replace(/\.js$/,``),s=a(r,`utf-8`),c=`preact`;i.includes(`.solid`)?c=`solid`:i.includes(`.vue`)||i.endsWith(`.vue`)?c=`vue`:i.includes(`.svelte`)||i.endsWith(`.svelte`)?c=`svelte`:i.includes(`.lit`)?c=`lit`:i.includes(`.qwik`)?c=`qwik`:i.includes(`.react`)?c=`react`:i.includes(`.preact`)&&(c=`preact`);let l=/from["']((?:\/|\.\/)[^"']+\.(tsx|ts|jsx|js|vue|svelte))["']/i.exec(s),u;if(l&&!l[1].includes(`/assets/`)&&!l[1].startsWith(`../`))u=l[1];else{let t=i;u=[`${t}.tsx`,`${t}.ts`,`${t}.jsx`,`${t}.js`,`${t}`].find(t=>n(d(e,t)))??`${t}.tsx`}u.startsWith(`src/islands/`)&&(u=u.slice(12)),u.startsWith(`/`)||(u=`/${u}`),o.set(i,{filePath:u,bundleKey:i,framework:c})}await r(e,t,o,[],{})}catch{console.warn(`[islands] Isolated rebuild failed, falling back to inline-islands`);try{let{inlineIslandChunks:e}=await import(`./inline-islands.js`);await e(t,{verbose:!0})}catch(e){console.error(`[islands] Inline fallback also failed:`,e)}}}function T(e,r){let i=d(r,`islands`);if(!n(i))return;let a=[d(e,`.output`,`public`),d(e,`.netlify`,`functions-internal`,`server`,`public`)];for(let e of a)n(e)&&t(i,d(e,`islands`),{recursive:!0,force:!0});console.log(`[islands] Synced isolated islands to output directories`)}function E(e){let t=d(e,`islands`);if(!n(t))return;let r=h(t,e=>e.endsWith(`.js`)&&!e.endsWith(`.js.map`));if(r.length===0)return;let i=[];for(let t of r){let n=t.substring(e.length).replaceAll(`\\`,`/`);i.push(`${n} ${n} 200`)}let o=d(e,`_redirects`),s=n(o)?a(o,`utf-8`):``;c(o,s?`${s}\n${i.join(`
2
2
  `)}`:i.join(`
3
- `)),console.log(`[redirects] Generated ${i.length} island redirect(s)`)}function D(e,a){let o=d(e,`node_modules`,`@useavalon`);if(!n(o))return;let s=[d(a,`adapters`),d(e,`.output`,`public`,`adapters`),d(e,`.netlify`,`functions-internal`,`server`,`public`,`adapters`)];for(let e of s){if(!n(u(e)))continue;let a=i(o).map(e=>d(o,e,`client`)).filter(e=>n(e));for(let n of a){let i=d(e,n.split(`/`).at(-2)||``);r(i,{recursive:!0}),t(n,i,{recursive:!0,force:!0})}}console.log(`[adapters] Copied framework adapters to output directories`)}function O(e){let i=d(e,`.netlify`,`functions-internal`),a=d(e,`.netlify`,`v1`,`functions`);n(i)&&(r(a,{recursive:!0}),t(i,a,{recursive:!0,force:!0}),console.log(`[netlify] Copied server function to v1 API paths`))}function k(e){if(!n(e))return!1;let t=a(e,`utf-8`);return t.includes(`netlify`)||t.includes(`lambda`)}function A(e,t){let n=d(u(e),`_prerender-server.mjs`);return c(n,m(`./${l(e)}`,t)),n}function j(e){let t=/<a\s+[^>]*href=["']([^"']+)["'][^>]*>/gi,n=[],r;for(r=t.exec(e);r!==null;r=t.exec(e)){let e=r[1],t=e.indexOf(`#`);t!==-1&&(e=e.substring(0,t));let i=e.indexOf(`?`);i!==-1&&(e=e.substring(0,i)),e&&e.startsWith(`/`)&&!e.startsWith(`//`)&&!e.includes(`.`)&&n.push(e)}return n}async function M(t,i,o,l){let p=_(t),m=[d(t,`.netlify`,`functions-internal`,`server`,`server.mjs`),d(t,`.netlify`,`v1`,`functions`,`server`,`server.mjs`),d(t,`.output`,`server`,`index.mjs`),...p?[p]:[]].find(e=>n(e));if(!m){console.log(`[prerender] No server entry found, skipping prerender`);return}let h=[d(t,`.output`,`public`),i].find(e=>n(e));if(!h){console.log(`[prerender] No output directory found, skipping prerender`);return}let v={routes:o.routes??[`/`],crawlLinks:o.crawlLinks??!0,ignore:o.ignore??[],failOnError:o.failOnError??!1,concurrency:o.concurrency??4,autoSubfolderIndex:o.autoSubfolderIndex??!0,retry:o.retry??3,retryDelay:o.retryDelay??500},y=`http://localhost:${l}`,b=k(m),x=p!==null&&m===p,S=m;if(b){let e=d(u(m),`main.mjs`);if(!n(e)){console.error(`[prerender] Netlify handler detected but main.mjs not found`);return}S=A(e,l),console.log(`[prerender] Netlify handler detected — using wrapper`)}else x&&(S=A(m,l),console.log(`[prerender] Cloudflare worker detected — using wrapper`));{let e=[m,d(u(m),`main.mjs`)].filter(e=>g(e));for(let n of e){let e=a(n,`utf-8`),r=/"\/[^"]*\.html":\{[^}]+\},?/g,i=e.length;e=e.replaceAll(r,``),i!==e.length&&(c(n,e),console.log(`[prerender] Patched ${f(t,n)}: removed HTML asset entries`))}}console.log(`[prerender] Starting prerender with server: ${f(t,S)}`);let{spawn:C}=await import(`node:child_process`),w;try{w=C(`node`,[S],{env:{...process.env,PORT:String(l),NITRO_PORT:String(l),HOST:`127.0.0.1`,NITRO_HOST:`127.0.0.1`,NODE_ENV:`production`},stdio:[`ignore`,`pipe`,`pipe`]}),w.stdout?.on(`data`,e=>{let t=e.toString().trim();t&&console.log(`[prerender:server] ${t}`)}),w.stderr?.on(`data`,e=>{let t=e.toString().trim();t&&console.error(`[prerender:server:err] ${t}`)});let e=Date.now(),t=!1;for(;Date.now()-e<15e3;){try{let e=await fetch(`${y}/`);if(e.ok||e.status<500){t=!0;break}}catch{}await new Promise(e=>setTimeout(e,200))}if(!t)throw Error(`Server did not become ready within 15s`);console.log(`[prerender] Server ready at ${y}`)}catch(e){w?.kill(`SIGKILL`),console.error(`[prerender] Failed to start server:`,e.message);return}let T=new Set,E=[...v.routes],D=[],O=[];function M(e){for(let t of v.ignore)if(typeof t==`string`&&e===t||typeof t==`string`&&t.endsWith(`/**`)&&e.startsWith(t.slice(0,-2)))return!0;return!1}try{for(;E.length>0;){let e=E.splice(0,v.concurrency);await Promise.all(e.map(async e=>{let t=e.endsWith(`/`)&&e!==`/`?e.slice(0,-1):e;if(T.has(t)||(T.add(t),M(t)))return;let n=null;for(let e=1;e<=v.retry;e++)try{let e=await fetch(`${y}${t}`);n={html:await e.text(),status:e.status};break}catch{e<v.retry&&await new Promise(e=>setTimeout(e,v.retryDelay))}if(!n){O.push({route:t,error:`Failed after ${v.retry} attempts`});return}if(n.status>=400){O.push({route:t,error:`Returned ${n.status}`});return}let i=v.autoSubfolderIndex?d(t,`index.html`):`${t}.html`,a=d(h,i);r(u(a),{recursive:!0});let o=n.html.replace(`<!DOCTYPE html>`,`<!DOCTYPE html>
4
- <!-- SSG: prerendered at build time -->`).replaceAll(/<link rel="stylesheet" href="\/assets\/[^"]*\.css">\n?/g,e=>e.includes(`_isolated-island-entry`)?``:e);if(o=o.replaceAll(/<script type="module" src="\/assets\/entry-client[^"]*\.js"><\/script>\n?/g,``),(/\/assets\/(?:ssr-)?index-[^"]+\.css/.test(o)||/<style data-inlined-from="\/assets\/(?:ssr-)?index-/.test(o))&&(o=o.replaceAll(/<link rel="stylesheet" href="\/assets\/entry-client[^"]*\.css">\n?/g,``)),o=o.replaceAll(/<link rel="modulepreload" href="\/assets\/entry-client[^"]*\.js">\n?/g,``),c(a,o),D.push(t),console.log(`[prerender] ✅ ${t} → ${i}`),v.crawlLinks)for(let e of j(n.html)){let t=e.endsWith(`/`)&&e!==`/`?e.slice(0,-1):e;!T.has(t)&&!M(t)&&E.push(t)}}))}}finally{console.log(`[prerender] Shutting down server...`),w?.kill(`SIGKILL`)}if(console.log(`[prerender] Done: ${D.length} page(s) prerendered`+(O.length>0?`, ${O.length} error(s)`:``)),b||x){let e=d(u(m),`_prerender-server.mjs`);n(e)&&(s(e),console.log(`[prerender] Cleaned up wrapper script`))}if(D.length>0){let a=[i,d(t,`.netlify`,`functions-internal`,`server`,`public`),d(t,`.netlify`,`v1`,`functions`,`server`,`public`)].filter(e=>e!==h&&n(u(e)));for(let t of a)for(let i of D){let a=d(i,`index.html`),o=d(h,a),s=d(t,a);n(o)&&(r(u(s),{recursive:!0}),e(o,s))}a.length>0&&console.log(`[prerender] Copied prerendered HTML to ${a.length} additional output dir(s)`)}}function N(e,t){let r={},i=d(t,`island-deps.json`);if(n(i))try{r=JSON.parse(a(i,`utf-8`))}catch{}let o=d(e,`.output`,`public`);if(Object.keys(r).length===0&&n(o)){let e=h(d(o,`islands`),e=>e.endsWith(`.js`)&&!e.endsWith(`.js.map`));for(let t of e){let e=`/${t.substring(o.length+1).replaceAll(`\\`,`/`)}`,n=a(t,`utf-8`),i=/\bfrom\s*["']([^"']+)["']|import\s*["']([^"']+)["']/g,s=[],c;for(c=i.exec(n);c!==null;c=i.exec(n)){let t=c[1]||c[2];if(t&&(t.includes(`/assets/`)||t.startsWith(`.`))){let n=(t.startsWith(`.`)?`/${d(u(e.slice(1)),t).replaceAll(`\\`,`/`).replace(/^\/+/,``)}`:t).split(`/`).filter(Boolean),r=[];for(let e of n)e===`..`?r.pop():e!==`.`&&r.push(e);s.push(`/${r.join(`/`)}`)}}s.length>0&&(r[e]=s)}}if(Object.keys(r).length===0)return;let s=[d(e,`.output`,`public`),t],l=0;for(let e of s){if(!n(e))continue;let t=h(e,e=>e===`index.html`);for(let e of t){let t=a(e,`utf-8`),n=new Set;for(let[e,i]of Object.entries(r))if(t.includes(e))for(let e of i)t.includes(`href="${e}"`)||n.add(e);if(n.size===0)continue;let i=Array.from(n).map(e=>`<link rel="modulepreload" href="${e}">`).join(`
3
+ `)),console.log(`[redirects] Generated ${i.length} island redirect(s)`)}function D(e,a){let o=d(e,`node_modules`,`@useavalon`);if(!n(o))return;let s=[d(a,`adapters`),d(e,`.output`,`public`,`adapters`),d(e,`.netlify`,`functions-internal`,`server`,`public`,`adapters`)];for(let e of s){if(!n(u(e)))continue;let a=i(o).map(e=>d(o,e,`client`)).filter(e=>n(e));for(let n of a){let i=d(e,n.split(`/`).at(-2)||``);r(i,{recursive:!0}),t(n,i,{recursive:!0,force:!0})}}console.log(`[adapters] Copied framework adapters to output directories`)}function O(e){let i=d(e,`.netlify`,`functions-internal`),a=d(e,`.netlify`,`v1`,`functions`);n(i)&&(r(a,{recursive:!0}),t(i,a,{recursive:!0,force:!0}),console.log(`[netlify] Copied server function to v1 API paths`))}function k(e){if(!n(e))return!1;let t=a(e,`utf-8`);return t.includes(`netlify`)||t.includes(`lambda`)}function A(e,t){let n=d(u(e),`_prerender-server.mjs`);return c(n,m(`./${l(e)}`,t)),n}function j(e){let t=/<a\s+[^>]*href=["']([^"']+)["'][^>]*>/gi,n=[],r;for(r=t.exec(e);r!==null;r=t.exec(e)){let e=r[1],t=e.indexOf(`#`);t!==-1&&(e=e.substring(0,t));let i=e.indexOf(`?`);i!==-1&&(e=e.substring(0,i)),e&&e.startsWith(`/`)&&!e.startsWith(`//`)&&!e.includes(`.`)&&n.push(e)}return n}async function M(t,i,o,l,p=!1){let m=_(t),h=[d(t,`.netlify`,`functions-internal`,`server`,`server.mjs`),d(t,`.netlify`,`v1`,`functions`,`server`,`server.mjs`),d(t,`.output`,`server`,`index.mjs`),...m?[m]:[]].find(e=>n(e));if(!h){console.log(`[prerender] No server entry found, skipping prerender`);return}let v=[d(t,`.output`,`public`),i].find(e=>n(e));if(!v){console.log(`[prerender] No output directory found, skipping prerender`);return}let y={routes:o.routes??[`/`],crawlLinks:o.crawlLinks??!0,ignore:o.ignore??[],failOnError:o.failOnError??!1,concurrency:o.concurrency??4,autoSubfolderIndex:o.autoSubfolderIndex??!0,retry:o.retry??3,retryDelay:o.retryDelay??500},b=`http://localhost:${l}`,x=k(h),S=m!==null&&h===m,C=h;if(x){let e=d(u(h),`main.mjs`);if(!n(e)){console.error(`[prerender] Netlify handler detected but main.mjs not found`);return}C=A(e,l),console.log(`[prerender] Netlify handler detected — using wrapper`)}else S&&(C=A(h,l),console.log(`[prerender] Cloudflare worker detected — using wrapper`));{let e=[h,d(u(h),`main.mjs`)].filter(e=>g(e));for(let n of e){let e=a(n,`utf-8`),r=/"\/[^"]*\.html":\{[^}]+\},?/g,i=e.length;e=e.replaceAll(r,``),i!==e.length&&(c(n,e),console.log(`[prerender] Patched ${f(t,n)}: removed HTML asset entries`))}}console.log(`[prerender] Starting prerender with server: ${f(t,C)}`);let{spawn:w}=await import(`node:child_process`),T;try{T=w(`node`,[C],{env:{...process.env,PORT:String(l),NITRO_PORT:String(l),HOST:`127.0.0.1`,NITRO_HOST:`127.0.0.1`,NODE_ENV:`production`},stdio:[`ignore`,`pipe`,`pipe`]}),T.stdout?.on(`data`,e=>{let t=e.toString().trim();t&&console.log(`[prerender:server] ${t}`)}),T.stderr?.on(`data`,e=>{let t=e.toString().trim();t&&console.error(`[prerender:server:err] ${t}`)});let e=Date.now(),t=!1;for(;Date.now()-e<15e3;){try{let e=await fetch(`${b}/`);if(e.ok||e.status<500){t=!0;break}}catch{}await new Promise(e=>setTimeout(e,200))}if(!t)throw Error(`Server did not become ready within 15s`);console.log(`[prerender] Server ready at ${b}`)}catch(e){T?.kill(`SIGKILL`),console.error(`[prerender] Failed to start server:`,e.message);return}let E=new Set,D=[...y.routes],O=[],M=[];function N(e){for(let t of y.ignore)if(typeof t==`string`&&e===t||typeof t==`string`&&t.endsWith(`/**`)&&e.startsWith(t.slice(0,-2)))return!0;return!1}try{for(;D.length>0;){let e=D.splice(0,y.concurrency);await Promise.all(e.map(async e=>{let t=e.endsWith(`/`)&&e!==`/`?e.slice(0,-1):e;if(E.has(t)||(E.add(t),N(t)))return;let n=null;for(let e=1;e<=y.retry;e++)try{let e=await fetch(`${b}${t}`);n={html:await e.text(),status:e.status};break}catch{e<y.retry&&await new Promise(e=>setTimeout(e,y.retryDelay))}if(!n){M.push({route:t,error:`Failed after ${y.retry} attempts`});return}if(n.status>=400){M.push({route:t,error:`Returned ${n.status}`});return}let i=y.autoSubfolderIndex?d(t,`index.html`):`${t}.html`,a=d(v,i);r(u(a),{recursive:!0});let o=n.html.replace(`<!DOCTYPE html>`,`<!DOCTYPE html>
4
+ <!-- SSG: prerendered at build time -->`).replaceAll(/<link rel="stylesheet" href="\/assets\/[^"]*\.css">\n?/g,e=>e.includes(`_isolated-island-entry`)?``:e);if(p||(o=o.replaceAll(/<script type="module" src="\/assets\/entry-client[^"]*\.js"><\/script>\n?/g,``)),(/\/assets\/(?:ssr-)?index-[^"]+\.css/.test(o)||/<style data-inlined-from="\/assets\/(?:ssr-)?index-/.test(o))&&(o=o.replaceAll(/<link rel="stylesheet" href="\/assets\/entry-client[^"]*\.css">\n?/g,``)),p||(o=o.replaceAll(/<link rel="modulepreload" href="\/assets\/entry-client[^"]*\.js">\n?/g,``)),c(a,o),O.push(t),console.log(`[prerender] ✅ ${t} → ${i}`),y.crawlLinks)for(let e of j(n.html)){let t=e.endsWith(`/`)&&e!==`/`?e.slice(0,-1):e;!E.has(t)&&!N(t)&&D.push(t)}}))}}finally{console.log(`[prerender] Shutting down server...`),T?.kill(`SIGKILL`)}if(console.log(`[prerender] Done: ${O.length} page(s) prerendered`+(M.length>0?`, ${M.length} error(s)`:``)),x||S){let e=d(u(h),`_prerender-server.mjs`);n(e)&&(s(e),console.log(`[prerender] Cleaned up wrapper script`))}if(O.length>0){let a=[i,d(t,`.netlify`,`functions-internal`,`server`,`public`),d(t,`.netlify`,`v1`,`functions`,`server`,`public`)].filter(e=>e!==v&&n(u(e)));for(let t of a)for(let i of O){let a=d(i,`index.html`),o=d(v,a),s=d(t,a);n(o)&&(r(u(s),{recursive:!0}),e(o,s))}a.length>0&&console.log(`[prerender] Copied prerendered HTML to ${a.length} additional output dir(s)`)}}function N(e,t){let r={},i=d(t,`island-deps.json`);if(n(i))try{r=JSON.parse(a(i,`utf-8`))}catch{}let o=d(e,`.output`,`public`);if(Object.keys(r).length===0&&n(o)){let e=h(d(o,`islands`),e=>e.endsWith(`.js`)&&!e.endsWith(`.js.map`));for(let t of e){let e=`/${t.substring(o.length+1).replaceAll(`\\`,`/`)}`,n=a(t,`utf-8`),i=/\bfrom\s*["']([^"']+)["']|import\s*["']([^"']+)["']/g,s=[],c;for(c=i.exec(n);c!==null;c=i.exec(n)){let t=c[1]||c[2];if(t&&(t.includes(`/assets/`)||t.startsWith(`.`))){let n=(t.startsWith(`.`)?`/${d(u(e.slice(1)),t).replaceAll(`\\`,`/`).replace(/^\/+/,``)}`:t).split(`/`).filter(Boolean),r=[];for(let e of n)e===`..`?r.pop():e!==`.`&&r.push(e);s.push(`/${r.join(`/`)}`)}}s.length>0&&(r[e]=s)}}if(Object.keys(r).length===0)return;let s=[d(e,`.output`,`public`),t],l=0;for(let e of s){if(!n(e))continue;let t=h(e,e=>e===`index.html`);for(let e of t){let t=a(e,`utf-8`),n=new Set;for(let[e,i]of Object.entries(r))if(t.includes(e))for(let e of i)t.includes(`href="${e}"`)||n.add(e);if(n.size===0)continue;let i=Array.from(n).map(e=>`<link rel="modulepreload" href="${e}">`).join(`
5
5
  `);t.includes(`</head>`)&&(t=t.replace(`</head>`,`${i}\n</head>`),c(e,t),l++)}}l>0&&console.log(`[modulepreload] ✅ Injected dependency preloads into ${l} HTML file(s)`)}const P=[/syntax-highlight/i,/hljs/i,/prism/i,/highlight\.js/i];function F(e,t){let r=[d(e,`.output`,`public`),t],i=L(r),o=0;for(let e of r){if(!n(e))continue;let t=h(e,e=>e===`index.html`);for(let e of t){let t=a(e,`utf-8`),n=t;t=R(t,i),t=I(t),t=z(t),t=B(t),t!==n&&(c(e,t),o++)}}o>0&&console.log(`[post-build] Optimized ${o} HTML file(s) — deferred non-critical CSS, added font preload hints`)}function I(e){if(!e.includes(`</head>`)||!e.includes(`<body`))return e;let t=e.indexOf(`</head>`),n=e.indexOf(`<body`);if(t===-1||n===-1||n<t)return e;let r=e.substring(n),i=new Set,a=[],o=``,s=0,c=0;for(;c<r.length;){if(r[c]===`<`){if(r.startsWith(`<template`,c)){s++;let e=r.indexOf(`>`,c);if(e===-1)break;o+=r.substring(c,e+1),c=e+1;continue}if(r.startsWith(`</template>`,c)){s=Math.max(0,s-1),o+=`</template>`,c+=11;continue}if(s===0&&r.startsWith(`<style`,c)){let e=r.indexOf(`</style>`,c);if(e===-1)break;let t=r.substring(c,e+8),n=/<style[^>]*>([\s\S]*?)<\/style>/.exec(t);if(n){let e=n[1].replaceAll(/\s+/g,` `).trim();e&&!i.has(e)&&(i.add(e),a.push(`<style>${e}</style>`))}c=e+8;continue}}o+=r[c],c++}return a.length===0?e:`${e.substring(0,t)}\n${a.join(`
6
6
  `)}\n</head>${o}`}function L(e){let t=new Map;for(let r of e){let e=d(r,`assets`);if(n(e))for(let n of i(e))n.endsWith(`.css`)&&t.set(`/assets/${n}`,a(d(e,n),`utf-8`))}return t}function R(e,t){let n=/<link\s+rel="stylesheet"\s+href="(\/assets\/(?:ssr-)?index-[^"]+\.css)">/i.exec(e);if(!n)return e;let r=n[1],i=t.get(r);if(!i)return e;if(Buffer.byteLength(i,`utf-8`)<=14336){let t=`<style data-inlined-from="${r}">${i}</style>`;return e.replace(n[0],t)}let a=`<link rel="preload" href="${r}" as="style">`;return e.includes(`</title>`)&&!e.includes(`preload" href="${r}"`)&&(e=e.replace(`</title>`,`</title>\n${a}`)),e}function z(e){return e.replaceAll(/<link\s+([^>]*rel=["']stylesheet["'][^>]*)>/gi,(t,n,r)=>{if(e.slice(Math.max(0,r-32),r).toLowerCase().includes(`<noscript`))return t;let i=n.replace(/\s*\/\s*$/,``).trim();if(/\bmedia\s*=/i.test(i)||/data-critical/i.test(i))return t;let a=/href=["']([^"']+)["']/i.exec(i);if(!a)return t;let o=a[1],s=o.startsWith(`https://`)||o.startsWith(`http://`),c=!s&&P.some(e=>e.test(o));return!s&&!c?t:`<link ${i} media="print" onload="this.media='all'">\n<noscript><link ${i}></noscript>`})}function B(e){let t=/href=["'](https:\/\/fonts\.googleapis\.com\/css2[^"']+)["']/gi,n=new Set,r;for(r=t.exec(e);r!==null;r=t.exec(e))n.add(r[1]);if(n.size===0)return e;let i=[];for(let t of n){let n=t.replaceAll(/[.*+?^${}()|[\]\\]/g,String.raw`\$&`);new RegExp(String.raw`<link\s+[^>]*rel=["']preload["'][^>]*href=["']${n}["'][^>]*>`,`i`).test(e)||i.push(`<link rel="preload" href="${t}" as="style">`)}if(i.length===0)return e;let a=i.join(`
7
- `);return e.includes(`</title>`)?e.replace(`</title>`,`</title>\n${a}`):e}async function V(e){let{promisify:t}=await import(`node:util`),r=await import(`node:zlib`),i=t(r.brotliCompress),o=t(r.gzip),s=[d(e,`.output`,`public`),d(e,`.netlify`,`functions-internal`,`server`,`public`)],l=e=>e.endsWith(`.js`)||e.endsWith(`.css`)||e.endsWith(`.html`)||e.endsWith(`.svg`)||e.endsWith(`.txt`)||e.endsWith(`.xml`)||e.endsWith(`.json`),u=0;for(let e of s){if(!n(e))continue;let t=h(e,e=>l(e)&&!e.endsWith(`.map`));for(let e of t){let t=a(e);if(!(t.length<256))try{let[n,a]=await Promise.all([i(t,{params:{[r.constants.BROTLI_PARAM_QUALITY]:11}}),o(t,{level:9})]);c(`${e}.br`,n),c(`${e}.gz`,a),u++}catch{}}}u>0&&console.log(`[compress] ✅ Compressed ${u} public asset(s) (brotli + gzip)`)}function H(e){let t=[d(e,`.output`,`server`,`index.mjs`),d(e,`.netlify`,`functions-internal`,`server`,`index.mjs`)],r=d(e,`.output`,`public`);if(!n(r))return;let i=U(r);if(i.length===0)return;let a=0;for(let e of t)W(e,i,r)&&a++;a>0&&console.log(`[manifest] ✅ Registered ${i.length} prerendered HTML file(s) in Nitro asset manifest`)}function U(e){let t=h(e,e=>e===`index.html`||e===`index.html.br`||e===`index.html.gz`||e===`index.html.zst`),n=[],r=new Date().toISOString();for(let i of t){let t=`/${i.substring(e.length+1).replaceAll(`\\`,`/`)}`,o=a(i).length,s=`"${o.toString(16)}-prerender"`,c=``;t.endsWith(`.br`)?c=`br`:t.endsWith(`.gz`)?c=`gzip`:t.endsWith(`.zst`)&&(c=`zstd`);let l=`"${t}":{type:\`text/html; charset=utf-8\``;c&&(l+=`,encoding:\`${c}\``),l+=`,etag:\`${s}\`,mtime:\`${r}\`,size:${o},path:\`../public${t}\`}`,n.push(l)}return n}function W(e,t,r){if(!n(e))return!1;let i=a(e,`utf-8`),o=/("\/favicon\.ico":\{[^}]+\})/.exec(i);if(!o)return!1;let s=t.filter(e=>{let t=/^"([^"]+)"/.exec(e);return t&&!i.includes(`"${t[1]}":{`)});s.length>0&&(i=i.replace(o[0],`${o[0]},${s.join(`,`)}`));let l=G(r),u="u===`/favicon.ico`&&d.unshift({data:e})";for(let e of l){if(i.includes(`route:\`${e}\``))continue;let t=`[{name:\`headers\`,route:\`${e}\`,handler:x,options:{"Cache-Control":\`public, max-age=0, must-revalidate\`}}]`;i=i.replace(u,`${u};u===\`${e}\`&&d.unshift({data:${t}})`)}return c(e,i),s.length>0||l.length>0}function G(e){let t=[];if(!n(e))return t;for(let r of i(e,{withFileTypes:!0}))!r.isDirectory()&&r.name===`index.html`?t.push(`/`):r.isDirectory()&&n(d(e,r.name,`index.html`))&&t.push(`/${r.name}`);return t}export async function runPostBuild(e={}){let t=e.cwd??process.cwd(),n=d(t,`dist`),r=e.prerenderPort??13172;b(t),C(t,n);for(let e of[d(t,`.netlify`,`functions-internal`,`server`,`_ssr`,`ssr.mjs`),d(t,`.netlify`,`v1`,`functions`,`server`,`_ssr`,`ssr.mjs`),d(t,`.output`,`server`,`_ssr`,`ssr.mjs`),v(t)])e&&g(e)&&(console.log(`[patch] Patching ${e}`),patchSSRBundleCSS(e,n,t));await w(t,n),T(t,n),E(n),D(t,n),O(t),p(t),e.prerender!==!1&&await M(t,n,e.prerender??{},r),N(t,n),F(t,n),await V(t),H(t),console.log(`[post-build] ✅ Complete`)}
7
+ `);return e.includes(`</title>`)?e.replace(`</title>`,`</title>\n${a}`):e}async function V(e){let{promisify:t}=await import(`node:util`),r=await import(`node:zlib`),i=t(r.brotliCompress),o=t(r.gzip),s=[d(e,`.output`,`public`),d(e,`.netlify`,`functions-internal`,`server`,`public`)],l=e=>e.endsWith(`.js`)||e.endsWith(`.css`)||e.endsWith(`.html`)||e.endsWith(`.svg`)||e.endsWith(`.txt`)||e.endsWith(`.xml`)||e.endsWith(`.json`),u=0;for(let e of s){if(!n(e))continue;let t=h(e,e=>l(e)&&!e.endsWith(`.map`));for(let e of t){let t=a(e);if(!(t.length<256))try{let[n,a]=await Promise.all([i(t,{params:{[r.constants.BROTLI_PARAM_QUALITY]:11}}),o(t,{level:9})]);c(`${e}.br`,n),c(`${e}.gz`,a),u++}catch{}}}u>0&&console.log(`[compress] ✅ Compressed ${u} public asset(s) (brotli + gzip)`)}function H(e){let t=[d(e,`.output`,`server`,`index.mjs`),d(e,`.netlify`,`functions-internal`,`server`,`index.mjs`)],r=d(e,`.output`,`public`);if(!n(r))return;let i=U(r);if(i.length===0)return;let a=0;for(let e of t)W(e,i,r)&&a++;a>0&&console.log(`[manifest] ✅ Registered ${i.length} prerendered HTML file(s) in Nitro asset manifest`)}function U(e){let t=h(e,e=>e===`index.html`||e===`index.html.br`||e===`index.html.gz`||e===`index.html.zst`),n=[],r=new Date().toISOString();for(let i of t){let t=`/${i.substring(e.length+1).replaceAll(`\\`,`/`)}`,o=a(i).length,s=`"${o.toString(16)}-prerender"`,c=``;t.endsWith(`.br`)?c=`br`:t.endsWith(`.gz`)?c=`gzip`:t.endsWith(`.zst`)&&(c=`zstd`);let l=`"${t}":{type:\`text/html; charset=utf-8\``;c&&(l+=`,encoding:\`${c}\``),l+=`,etag:\`${s}\`,mtime:\`${r}\`,size:${o},path:\`../public${t}\`}`,n.push(l)}return n}function W(e,t,r){if(!n(e))return!1;let i=a(e,`utf-8`),o=/("\/favicon\.ico":\{[^}]+\})/.exec(i);if(!o)return!1;let s=t.filter(e=>{let t=/^"([^"]+)"/.exec(e);return t&&!i.includes(`"${t[1]}":{`)});s.length>0&&(i=i.replace(o[0],`${o[0]},${s.join(`,`)}`));let l=G(r),u="u===`/favicon.ico`&&d.unshift({data:e})";for(let e of l){if(i.includes(`route:\`${e}\``))continue;let t=`[{name:\`headers\`,route:\`${e}\`,handler:x,options:{"Cache-Control":\`public, max-age=0, must-revalidate\`}}]`;i=i.replace(u,`${u};u===\`${e}\`&&d.unshift({data:${t}})`)}return c(e,i),s.length>0||l.length>0}function G(e){let t=[];if(!n(e))return t;for(let r of i(e,{withFileTypes:!0}))!r.isDirectory()&&r.name===`index.html`?t.push(`/`):r.isDirectory()&&n(d(e,r.name,`index.html`))&&t.push(`/${r.name}`);return t}export async function runPostBuild(e={}){let t=e.cwd??process.cwd(),n=d(t,`dist`),r=e.prerenderPort??13172;b(t),C(t,n);for(let e of[d(t,`.netlify`,`functions-internal`,`server`,`_ssr`,`ssr.mjs`),d(t,`.netlify`,`v1`,`functions`,`server`,`_ssr`,`ssr.mjs`),d(t,`.output`,`server`,`_ssr`,`ssr.mjs`),v(t)])e&&g(e)&&(console.log(`[patch] Patching ${e}`),patchSSRBundleCSS(e,n,t));await w(t,n),T(t,n),E(n),D(t,n),O(t),p(t),e.prerender!==!1&&await M(t,n,e.prerender??{},r,e.clientRouter),N(t,n),F(t,n),await V(t),H(t),console.log(`[post-build] ✅ Complete`)}
@@ -1,3 +1,3 @@
1
1
  import{existsSync as e,statSync as t}from"node:fs";import{resolve as n}from"node:path";export const DEFAULT_TREESHAKE_CONFIG={annotations:!0,moduleSideEffects:!0,propertyReadSideEffects:!1,unknownGlobalSideEffects:!1,manualPureFunctions:[]};export function mergeTreeshakeConfig(e,t){return{annotations:t.annotations??e.annotations,moduleSideEffects:t.moduleSideEffects??e.moduleSideEffects,propertyReadSideEffects:t.propertyReadSideEffects??e.propertyReadSideEffects,unknownGlobalSideEffects:t.unknownGlobalSideEffects??e.unknownGlobalSideEffects,manualPureFunctions:[...e.manualPureFunctions,...t.manualPureFunctions??[]]}}const a={solid:`@useavalon/solid/client`,preact:`@useavalon/preact/client`,react:`@useavalon/react/client`,vue:`@useavalon/vue/client`,svelte:`@useavalon/svelte/client`};export function generateWrapperCode(e,t){let n=JSON.stringify(e);if(t===`qwik`)return[`export * from ${n};`,`export { _hW } from "@builder.io/qwik";`].join(`
2
- `);let r=a[t],i=[`import __C from ${n};`,`var Component = __C;`,`export { Component as default, Component };`,`if(typeof globalThis<"u")globalThis.__avalonIsland=Component;`];return r&&i.push(`export { hydrate as __hydrateIsland } from ${JSON.stringify(r)};`),i.join(`
3
- `)}export function generateIntegrationLoaderForFramework(e){let t=a[e];return t?`export { hydrate } from ${JSON.stringify(t)};`:`export {};`}async function c(e,t){let n=[],{resolve:r}=await import(`node:path`),{existsSync:i}=await import(`node:fs`),{pathToFileURL:a}=await import(`node:url`),o={solid:{pkg:`vite-plugin-solid`,esmEntry:`dist/esm/index.mjs`},vue:{pkg:`@vitejs/plugin-vue`,esmEntry:`dist/index.mjs`},svelte:{pkg:`@sveltejs/vite-plugin-svelte`,esmEntry:`src/index.js`}}[e];if(!o)return n;try{let s=null,c=t;for(let e=0;e<8;e++){let e=r(c,`node_modules`,o.pkg,o.esmEntry);if(i(e)){s=e;break}for(let e of[`solid`,`vue`,`svelte`,`preact`,`react`,`lit`]){let t=r(c,`packages`,`integrations`,e,`node_modules`,o.pkg,o.esmEntry);if(i(t)){s=t;break}}if(s)break;c=r(c,`..`)}if(!s)throw Error(`Cannot find package '${o.pkg}'`);let l=await import(a(s).href);switch(e){case`solid`:n.push((l.default??l)({ssr:!1,hot:!1}));break;case`vue`:n.push((l.default??l)());break;case`svelte`:n.push((l.svelte??l.default)());break}}catch(t){console.warn(` ⚠ Could not load ${e} plugin: ${t instanceof Error?t.message:t}`)}return n}async function l(e){let{createRequire:t}=await import(`node:module`),{existsSync:n}=await import(`node:fs`),r=t(`${e}/package.json`),i=e=>{try{let t=r.resolve(e);return t.endsWith(`.js`)&&n(t.replace(/\.js$/,`.mjs`))?t.replace(/\.js$/,`.mjs`):t}catch{return null}},a={preact:i(`preact`),"preact/hooks":i(`preact/hooks`),"preact/compat":i(`preact/compat`),"preact/compat/client":i(`preact/compat/client`),"preact/compat/server":i(`preact/compat/server`),"preact/jsx-runtime":i(`preact/jsx-runtime`),react:i(`preact/compat`),"react/jsx-runtime":i(`preact/jsx-runtime`),"react/jsx-dev-runtime":i(`preact/jsx-runtime`),"react-dom":i(`preact/compat`),"react-dom/client":i(`preact/compat/client`),"react-dom/server":i(`preact/compat/server`)};return{name:`avalon:isolated-preact-compat`,enforce:`pre`,resolveId(e){return a[e]??null}}}export async function buildIsolatedIslands(a,u,d,f,p,m){if(d.size===0)return[];let{build:h}=await import(`vite`),g=new Set([`qwik`,`lit`,`preact`,`react`]),_=[...d.values()].filter(e=>!g.has(e.framework));console.log(`🏝️ Building ${_.length} island(s) in isolation (${d.size-_.length} skipped)...`);let v=performance.now(),y=m?.treeshake?mergeTreeshakeConfig(DEFAULT_TREESHAKE_CONFIG,m.treeshake):DEFAULT_TREESHAKE_CONFIG,b=[];for(let[,r]of d){let{filePath:i,bundleKey:d,framework:m}=r,g=`islands/${d}.js`;if(m===`qwik`||m===`lit`||m===`preact`||m===`react`){b.push({island:g,success:!0,skipped:!0});continue}let _=generateWrapperCode(i,m),v=`\0isolated-island-entry`,x=`\0virtual:avalon/integration-loader`;try{let r=await c(m,a),i=await l(a),o=performance.now(),S=await h({configFile:!1,root:a,logLevel:`silent`,plugins:[{name:`avalon:isolated-island-virtual`,resolveId(e){return e===v?e:e===`virtual:avalon/integration-loader`||e===x?x:null},load(e){return e===v?_:e===x?generateIntegrationLoaderForFramework(m):null}},i,...r],build:{write:!0,outDir:n(a,u),emptyOutDir:!1,minify:`oxc`,target:`es2022`,rollupOptions:{input:v,output:{format:`es`,entryFileNames:g},preserveEntrySignatures:`exports-only`,treeshake:y}},resolve:{alias:f},define:{...p,__DEV__:`false`,__PROD__:`true`,"process.env.NODE_ENV":`"production"`}}),C=performance.now()-o,w=n(a,u,g),T=e(w)?t(w).size:0,E=[],D=Array.isArray(S)?S:[S];for(let e of D)if(e&&`output`in e)for(let t of e.output)t.type===`chunk`&&t.fileName!==g&&E.push(`/${t.fileName}`);b.push({island:g,success:!0,size:T,elapsedMs:C,deps:E}),console.log(` ✅ ${d} (${m}): ${(T/1024).toFixed(1)} KiB`),C>2e3&&console.warn(` ⚠ ${d} (${m}): build took ${C.toFixed(0)}ms (>2s)`)}catch(e){let t=e instanceof Error?e.message:String(e);console.error(` ❌ ${d} (${m}): ${t}`),b.push({island:g,success:!1,error:t})}}let x=((performance.now()-v)/1e3).toFixed(1),S=b.filter(e=>e.success&&!e.skipped).length,C=b.filter(e=>e.skipped).length,w=b.filter(e=>!e.success).length,T=`🏝️ Done in ${x}s: ${S} built`;C&&(T+=`, ${C} skipped`),w&&(T+=`, ${w} failed`),console.log(T);let E={};for(let e of b)e.success&&e.deps&&e.deps.length>0&&(E[`/${e.island}`]=e.deps);if(Object.keys(E).length>0){let e=n(a,u,`island-deps.json`),{writeFileSync:t}=await import(`node:fs`);t(e,JSON.stringify(E))}return b}
2
+ `);let r=a[t],i=[`import __C from ${n};`,`var Component = __C;`,`export { Component as default, Component };`,`if(typeof globalThis<"u")globalThis.__avalonIsland=Component;`];return r&&i.push(`export { hydrate as __hydrateIsland, mount as __mountIsland } from ${JSON.stringify(r)};`),i.join(`
3
+ `)}export function generateIntegrationLoaderForFramework(e){let t=a[e];return t?`export { hydrate, mount } from ${JSON.stringify(t)};`:`export {};`}async function c(e,t){let n=[],{resolve:r}=await import(`node:path`),{existsSync:i}=await import(`node:fs`),{pathToFileURL:a}=await import(`node:url`),o={solid:{pkg:`vite-plugin-solid`,esmEntry:`dist/esm/index.mjs`},vue:{pkg:`@vitejs/plugin-vue`,esmEntry:`dist/index.mjs`},svelte:{pkg:`@sveltejs/vite-plugin-svelte`,esmEntry:`src/index.js`}}[e];if(!o)return n;try{let s=null,c=t;for(let e=0;e<8;e++){let e=r(c,`node_modules`,o.pkg,o.esmEntry);if(i(e)){s=e;break}for(let e of[`solid`,`vue`,`svelte`,`preact`,`react`,`lit`]){let t=r(c,`packages`,`integrations`,e,`node_modules`,o.pkg,o.esmEntry);if(i(t)){s=t;break}}if(s)break;c=r(c,`..`)}if(!s)throw Error(`Cannot find package '${o.pkg}'`);let l=await import(a(s).href);switch(e){case`solid`:n.push((l.default??l)({ssr:!1,hot:!1}));break;case`vue`:n.push((l.default??l)());break;case`svelte`:n.push((l.svelte??l.default)());break}}catch(t){console.warn(` ⚠ Could not load ${e} plugin: ${t instanceof Error?t.message:t}`)}return n}async function l(e){let{createRequire:t}=await import(`node:module`),{existsSync:n}=await import(`node:fs`),r=t(`${e}/package.json`),i=e=>{try{let t=r.resolve(e);return t.endsWith(`.js`)&&n(t.replace(/\.js$/,`.mjs`))?t.replace(/\.js$/,`.mjs`):t}catch{return null}},a={preact:i(`preact`),"preact/hooks":i(`preact/hooks`),"preact/compat":i(`preact/compat`),"preact/compat/client":i(`preact/compat/client`),"preact/compat/server":i(`preact/compat/server`),"preact/jsx-runtime":i(`preact/jsx-runtime`),react:i(`preact/compat`),"react/jsx-runtime":i(`preact/jsx-runtime`),"react/jsx-dev-runtime":i(`preact/jsx-runtime`),"react-dom":i(`preact/compat`),"react-dom/client":i(`preact/compat/client`),"react-dom/server":i(`preact/compat/server`)};return{name:`avalon:isolated-preact-compat`,enforce:`pre`,resolveId(e){return a[e]??null}}}export async function buildIsolatedIslands(a,u,d,f,p,m){if(d.size===0)return[];let{build:h}=await import(`vite`),g=new Set([`qwik`,`lit`,`preact`,`react`]),_=[...d.values()].filter(e=>!g.has(e.framework));console.log(`🏝️ Building ${_.length} island(s) in isolation (${d.size-_.length} skipped)...`);let v=performance.now(),y=m?.treeshake?mergeTreeshakeConfig(DEFAULT_TREESHAKE_CONFIG,m.treeshake):DEFAULT_TREESHAKE_CONFIG,b=[];for(let[,r]of d){let{filePath:i,bundleKey:d,framework:m}=r,g=`islands/${d}.js`;if(m===`qwik`||m===`lit`||m===`preact`||m===`react`){b.push({island:g,success:!0,skipped:!0});continue}let _=generateWrapperCode(i,m),v=`\0isolated-island-entry`,x=`\0virtual:avalon/integration-loader`;try{let r=await c(m,a),i=await l(a),o=performance.now(),S=await h({configFile:!1,root:a,logLevel:`silent`,plugins:[{name:`avalon:isolated-island-virtual`,resolveId(e){return e===v?e:e===`virtual:avalon/integration-loader`||e===x?x:null},load(e){return e===v?_:e===x?generateIntegrationLoaderForFramework(m):null}},i,...r],build:{write:!0,outDir:n(a,u),emptyOutDir:!1,minify:`oxc`,target:`es2022`,rollupOptions:{input:v,output:{format:`es`,entryFileNames:g},preserveEntrySignatures:`exports-only`,treeshake:y}},resolve:{alias:f},define:{...p,__DEV__:`false`,__PROD__:`true`,"process.env.NODE_ENV":`"production"`}}),C=performance.now()-o,w=n(a,u,g),T=e(w)?t(w).size:0,E=[],D=Array.isArray(S)?S:[S];for(let e of D)if(e&&`output`in e)for(let t of e.output)t.type===`chunk`&&t.fileName!==g&&E.push(`/${t.fileName}`);b.push({island:g,success:!0,size:T,elapsedMs:C,deps:E}),console.log(` ✅ ${d} (${m}): ${(T/1024).toFixed(1)} KiB`),C>2e3&&console.warn(` ⚠ ${d} (${m}): build took ${C.toFixed(0)}ms (>2s)`)}catch(e){let t=e instanceof Error?e.message:String(e);console.error(` ❌ ${d} (${m}): ${t}`),b.push({island:g,success:!1,error:t})}}let x=((performance.now()-v)/1e3).toFixed(1),S=b.filter(e=>e.success&&!e.skipped).length,C=b.filter(e=>e.skipped).length,w=b.filter(e=>!e.success).length,T=`🏝️ Done in ${x}s: ${S} built`;C&&(T+=`, ${C} skipped`),w&&(T+=`, ${w} failed`),console.log(T);let E={};for(let e of b)e.success&&e.deps&&e.deps.length>0&&(E[`/${e.island}`]=e.deps);if(Object.keys(E).length>0){let e=n(a,u,`island-deps.json`),{writeFileSync:t}=await import(`node:fs`);t(e,JSON.stringify(E))}return b}
@@ -15,6 +15,7 @@ export declare const routingValidators: {
15
15
  generateMetadata?: any;
16
16
  loader?: any;
17
17
  frontmatter?: Record<string, any>;
18
+ clientNavigation?: boolean;
18
19
  };
19
20
  readonly routeDiscoveryOptions: (data: unknown) => {
20
21
  pagesDirectory: string;
@@ -105,6 +106,7 @@ export declare const safeRoutingValidators: {
105
106
  generateMetadata?: any;
106
107
  loader?: any;
107
108
  frontmatter?: Record<string, any>;
109
+ clientNavigation?: boolean;
108
110
  }>;
109
111
  readonly routeDiscoveryOptions: (data: unknown) => import("../index.ts").ValidationResult<{
110
112
  pagesDirectory: string;