@useavalon/avalon 0.3.1-canary.3 → 0.3.1
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.
|
@@ -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";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=
|
|
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>
|
|
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>${
|
|
60
|
-
<p class="message">${
|
|
59
|
+
<h1>${b(t)}</h1>
|
|
60
|
+
<p class="message">${x(e.message)}</p>
|
|
61
61
|
${e.stack?`
|
|
62
62
|
<div class="stack-title">Stack Trace</div>
|
|
63
|
-
<pre>${
|
|
63
|
+
<pre>${x(e.stack)}</pre>
|
|
64
64
|
`:``}
|
|
65
65
|
</div>
|
|
66
66
|
</body>
|
|
67
|
-
</html>`}function
|
|
67
|
+
</html>`}function y(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>${
|
|
116
|
+
<h1>${b(e)}</h1>
|
|
117
117
|
<p><a href="/">Return to home</a></p>
|
|
118
118
|
</div>
|
|
119
119
|
</body>
|
|
120
|
-
</html>`}function
|
|
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
|
|
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(`&`,`&`).replaceAll(`<`,`<`).replaceAll(`>`,`>`).replaceAll(`"`,`"`).replaceAll(`'`,`'`)}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?`
|
|
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>${
|
|
128
|
-
${s.description?`<meta name="description" content="${
|
|
127
|
+
<title>${x(String(s.title||`Avalon App`))}</title>
|
|
128
|
+
${s.description?`<meta name="description" content="${x(String(s.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=
|
|
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>
|
|
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>${
|
|
141
|
-
${e.description?`<meta name="description" content="${
|
|
140
|
+
<title>${x(String(e.title||`Avalon App`))}</title>
|
|
141
|
+
${e.description?`<meta name="description" content="${x(String(e.description))}">`:``}
|
|
142
142
|
</head>
|
|
143
143
|
<body>
|
|
144
|
-
`}function
|
|
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))}'>
|
|
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="${
|
|
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))}'>
|
|
147
147
|
<!-- Component render fallback -->
|
|
148
|
-
</div>\n`}function
|
|
149
|
-
</html>`}function
|
|
148
|
+
</div>\n`}function E(){return` </body>
|
|
149
|
+
</html>`}function D(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
|
-
">${
|
|
156
|
+
">${x(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> ${
|
|
178
|
+
<p><strong>Error:</strong> ${x(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
|
|
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";
|
|
@@ -10,7 +10,7 @@ hydrateServerIsland(${JSON.stringify(a)},${JSON.stringify(o)},${s},${JSON.string
|
|
|
10
10
|
`)}\n`}export function createNitroIntegration(e,t={}){let n=b(t,e),r=process.cwd(),i=P(`src/server-islands/route.ts`),a=P(`src/actions/route.ts`),o={preset:n.preset,serverDir:t.serverDir??n.serverDir??`./server`,routeRules:n.routeRules,runtimeConfig:n.runtimeConfig,compatibilityDate:n.compatibilityDate,scanDirs:[`.`],noExternals:[`estree-walker`,/^@useavalon\//,/^estree-util/,/^preact/,...fe(e.core),/^vue/,/^@vue\//],handlers:[{route:`/_server-islands/**`,handler:i},{route:`/_actions/**`,handler:a}],virtual:{"virtual:server-island-manifest":()=>te(r),"virtual:avalon-actions-manifest":()=>se(r),"virtual:server-island-key":()=>{let e=process.env.AVALON_KEY??``;return`export const serverIslandKey = ${JSON.stringify(e)};\n`},"virtual:server-island-integrations":()=>ge(e.integrations)}};t.renderer===!1?o.renderer=!1:n.renderer&&(o.renderer=n.renderer),n.publicRuntimeConfig&&(o.publicRuntimeConfig=n.publicRuntimeConfig),n.publicAssets&&(o.publicAssets=n.publicAssets),n.compressPublicAssets&&(o.compressPublicAssets=n.compressPublicAssets),n.serverEntry&&(o.serverEntry=n.serverEntry);let s=process.argv.includes(`build`)||process.env.NODE_ENV===`production`;n.experimentalTasks&&s&&(o.experimental={...o.experimental,tasks:!0},n.tasks&&Object.keys(n.tasks).length>0&&(o.tasks=n.tasks),n.scheduledTasks&&Object.keys(n.scheduledTasks).length>0&&(o.scheduledTasks=n.scheduledTasks));let c=n.traceDeps??[];o.traceDeps=[...new Set([`undici`,...c])],n.prerender&&(o.prerender={routes:[],crawlLinks:!1});let l=u(o),d=createNitroCoordinationPlugin({avalonConfig:e,nitroConfig:t,verbose:e.verbose}),f=createVirtualModulesPlugin({avalonConfig:e,nitroConfig:t,verbose:e.verbose}),m=S(e,t),h=x(e,{verbose:e.verbose,generatePreloadHints:!0}),g=w(C(t.preset??`node_server`,e.isDev)),_=p(t.cron,e.verbose);return{nitroOptions:n,plugins:[...Array.isArray(l)?l:[l],d,f,m,h,g,_]}}export function createNitroCoordinationPlugin(e){let{avalonConfig:t,verbose:n}=e;return{name:`avalon:nitro-coordination`,enforce:`pre`,config(e,{command:t}){if(t===`serve`)return{server:{watch:{ignored:[`**/.output/**`,`**/dist/**`,`**/.netlify/**`,`**/.vercel/**`,`**/.cloudflare/**`,`**/.wrangler/**`,`**/.firebase/**`,`**/.amplify-hosting/**`]},fs:{deny:[`.output`,`dist`,`.netlify`,`.vercel`,`.cloudflare`,`.wrangler`,`.firebase`,`.amplify-hosting`]}}}},configResolved(e){globalThis.__avalonHydrationMode=e.command===`serve`?`entry-client`:`per-island`;try{f(e.root||process.cwd())}catch{}},configureServer(e){globalThis.__viteDevServer=e;let i=e.config.root||process.cwd(),a=e=>{if(e.includes(`/actions/`))try{f(i)}catch{}};e.watcher.on(`add`,a),e.watcher.on(`unlink`,a);let o=e.config.root||process.cwd(),c=e.config.build?.outDir?s(o,e.config.build.outDir):s(o,`dist`);try{r(c,{recursive:!0,force:!0})}catch{}try{r(s(o,`.output`),{recursive:!0,force:!0})}catch{}let l=!1,u=new Promise(t=>{let n=()=>{(e.environments?.nitro)?.devServer?.entry||l?(l=!0,t()):setTimeout(n,50)};setTimeout(n,100),setTimeout(()=>{l=!0,t()},15e3)});e.middlewares.use(async(e,t,n)=>{if(l)return n();let r=e.url||`/`;if(r.startsWith(`/@`)||r.startsWith(`/__`)||/\/[^/]+\.[a-z0-9]+(\?|$)/i.test(r))return n();await u,n()});let p=null;async function m(){return p||=await v({baseDir:`${e.config.root||process.cwd()}/src`,devMode:!1}),p}function h(){p=null}ye(e,t,n,h),m().catch(e=>{console.warn(`[middleware] Failed to discover middleware:`,e)});let g=e.environments?.ssr,_=!!g&&d(g);_&&L(e,t.integrations,n).catch(e=>{console.error(`[prewarm] Core modules pre-warm failed:`,e)}),e.middlewares.use(async(n,r,i)=>{let a=n.url||`/`;if(!a.startsWith(`/_server-islands/`)||!_)return i();try{let{decrypt:i}=await e.ssrLoadModule(P(`src/server-islands/encryption.ts`)),{h:o,renderToString:s}=await H(e,t.core),c=new URL(a,`http://${n.headers.host||`localhost`}`).searchParams.get(`p`)||``;if(!c&&n.method===`POST`&&(c=await A(n,`Timed out reading server island request body`)),!c){r.statusCode=400,r.setHeader(`Content-Type`,`text/plain`),r.end(`Missing encrypted props`);return}let l=le(c,i);if(!l.ok){r.statusCode=400,r.setHeader(`Content-Type`,`text/plain`),r.end(`Bad Request: decryption failed`);return}let{props:u,srcPath:d,islandMeta:f}=l;if(!d){r.statusCode=404,r.setHeader(`Content-Type`,`text/plain`),r.end(`Component not found (no __src in payload)`);return}let p=(await e.ssrLoadModule(d)).default;if(typeof p!=`function`){r.statusCode=500,r.setHeader(`Content-Type`,`text/plain`),r.end(`Module "${d}" does not export a default component function`);return}let m=s(o(p,u));f&&(m+=ue(a,f,d,u)),r.statusCode=200,r.setHeader(`Content-Type`,`text/html`),r.setHeader(`Cache-Control`,`private, no-store`),r.end(m)}catch(e){console.error(`[server-islands] Dev handler error:`,e),r.statusCode=500,r.setHeader(`Content-Type`,`text/plain`),r.end(`Server island render failed: ${e instanceof Error?e.message:String(e)}`)}}),e.middlewares.use(async(t,n,r)=>{let i=t.url||`/`;if(!i.startsWith(`/_actions/`)||!_)return r();try{let r=N(e.config.root||process.cwd()),[a,o,s]=await Promise.all([e.ssrLoadModule(P(`src/actions/endpoint.ts`)),e.ssrLoadModule(P(`src/actions/registry.ts`)),r?e.ssrLoadModule(r):Promise.resolve({server:{}})]),c=o.flattenActions(s.server),l=a.defineActionHandler({registry:c,isDev:!0}),u=new URL(i,`http://${t.headers.host||`localhost`}`),d=(t.method||`GET`).toUpperCase(),f;d===`POST`&&(f=await A(t,`Timed out reading action request body`));let p=await l({url:u,web:{request:new Request(u,{method:d,headers:t.headers,body:f})},context:{}});n.statusCode=p.status,p.headers.forEach((e,t)=>{n.setHeader(t,e)}),n.end(await p.text())}catch(e){console.error(`[actions] Dev handler error:`,e),n.statusCode=500,n.setHeader(`Content-Type`,`application/json`),n.end(JSON.stringify({error:{code:`INTERNAL_SERVER_ERROR`,message:e instanceof Error?e.message:String(e)}}))}}),e.middlewares.use(async(r,i,a)=>{if(!_)return a();let o=r.url||`/`;if(o.endsWith(`.html`)&&(o=o.slice(0,-5)||`/`),o===`/index`&&(o=`/`),o.startsWith(`/@`)||o.startsWith(`/__`)||o.startsWith(`/node_modules/`)||o.startsWith(`/src/client/`)||o.startsWith(`/packages/`)||o.includes(`.`)&&!o.endsWith(`/`)||o.startsWith(`/api/`))return a();try{if(await F(e,o,r,i,m,n)||await Le(e,o,t,i))return;let a=await Re(e,o,t);if(a){i.statusCode=200,i.setHeader(`Content-Type`,`text/html`),i.end(a);return}await I(e,o,i,t)}catch(e){console.error(`[SSR Error]`,e),i.statusCode=500,i.setHeader(`Content-Type`,`text/html`),i.end(D(e))}})},buildStart(){}}}async function F(e,t,n,r,i,a){let o=performance.now(),s=await i();if(s.length===0)return!1;let c={};for(let[e,t]of Object.entries(n.headers))typeof t==`string`?c[e]=t:Array.isArray(t)&&(c[e]=t.join(`, `));let l=`http://${n.headers.host||`localhost`}${t}`,u=await y({url:l,method:n.method||`GET`,path:t,node:{req:n,res:r},req:new Request(l,{method:n.method||`GET`,headers:c}),context:{}},s,{devMode:!1}),d=performance.now()-o;return d>100&&console.warn(`⚠️ Slow middleware: ${d.toFixed(0)}ms for ${t}`),u?(r.statusCode=u.status,u.headers.forEach((e,t)=>{r.setHeader(t,e)}),r.end(await u.text()),!0):!1}async function I(e,t,n,r){try{let{discoverErrorPages:i,getErrorPageModule:a,generateDefaultErrorPage:o}=await import(`../nitro/error-handler.js`),s=a(404,await i({isDev:r.isDev,pagesDir:r.pagesDir,loadPageModule:async t=>await e.ssrLoadModule(t)}));if(s?.default&&typeof s.default==`function`){let{renderToHtml:e}=await import(`../render/ssr.js`),r=s.default,i=await e({component:()=>r({statusCode:404,message:`Page not found: ${t}`,url:t})},{});n.statusCode=404,n.setHeader(`Content-Type`,`text/html`),n.end(i);return}let c=o(404,`Page not found: ${t}`,r.isDev);n.statusCode=404,n.setHeader(`Content-Type`,`text/html`),n.end(c)}catch{n.statusCode=404,n.setHeader(`Content-Type`,`text/html`),n.end(O(t))}}async function L(e,t,n){let r=performance.now(),i=[{path:P(`src/render/ssr.ts`),assignTo:`ssr`},{path:P(`src/core/layout/enhanced-layout-resolver.ts`),assignTo:`layout`},{path:P(`src/middleware/index.ts`),assignTo:null},...t.map(e=>({path:de(e,`server/renderer.ts`),assignTo:null}))],a=(await Promise.allSettled(i.map(async({path:t,assignTo:n})=>{let r=await e.ssrLoadModule(t);n===`ssr`&&(B=r),n===`layout`&&(V=r)}))).filter(e=>e.status===`fulfilled`).length,o=performance.now()-r;n&&a>0&&console.log(`🔥 SSR ready in ${o.toFixed(0)}ms (${a}/${i.length} core modules)`)}export function createVirtualModulesPlugin(e){let{avalonConfig:n,nitroConfig:r,verbose:i}=e,a=null,o=s,u=c,d=l,f=process.cwd(),p=[];function m(e){try{let n=t(e,{withFileTypes:!0});for(let t of n){let n=o(e,t.name);if(t.isDirectory()&&t.name!==`node_modules`&&!t.name.startsWith(`.`))m(n);else if(t.isFile()&&t.name.endsWith(`.css`)){let e=u(f,n).replaceAll(`\\`,`/`);p.push(e.startsWith(`/`)?e:`/${e}`)}}}catch{}}function h(){p.length=0;for(let e of r.globalCSS??[])p.push(e.startsWith(`/`)?e:`/${e}`);n.modules&&m(d(f,n.modules.dir)),m(d(f,n.layoutsDir));let e=d(f,n.layoutsDir,`..`);e!==f&&e!==d(f,n.layoutsDir)&&e.startsWith(f)&&m(e)}return n.isDev&&h(),{name:`avalon:nitro-virtual-modules`,enforce:`pre`,resolveId(e){return e===VIRTUAL_MODULE_IDS.PAGE_ROUTES?RESOLVED_VIRTUAL_IDS.PAGE_ROUTES:e===VIRTUAL_MODULE_IDS.PAGE_LOADER?RESOLVED_VIRTUAL_IDS.PAGE_LOADER:e===VIRTUAL_MODULE_IDS.ISLAND_MANIFEST?RESOLVED_VIRTUAL_IDS.ISLAND_MANIFEST:e===VIRTUAL_MODULE_IDS.RUNTIME_CONFIG?RESOLVED_VIRTUAL_IDS.RUNTIME_CONFIG:e===VIRTUAL_MODULE_IDS.CONFIG?RESOLVED_VIRTUAL_IDS.CONFIG:e===VIRTUAL_MODULE_IDS.LAYOUTS?RESOLVED_VIRTUAL_IDS.LAYOUTS:e===VIRTUAL_MODULE_IDS.ASSETS?RESOLVED_VIRTUAL_IDS.ASSETS:e===VIRTUAL_MODULE_IDS.RENDERER?RESOLVED_VIRTUAL_IDS.RENDERER:e===VIRTUAL_MODULE_IDS.CLIENT_ENTRY?RESOLVED_VIRTUAL_IDS.CLIENT_ENTRY:e===VIRTUAL_MODULE_IDS.INTEGRATION_LOADER?RESOLVED_VIRTUAL_IDS.INTEGRATION_LOADER:e===VIRTUAL_MODULE_IDS.ACTIONS?RESOLVED_VIRTUAL_IDS.ACTIONS:null},async load(e){return e===RESOLVED_VIRTUAL_IDS.PAGE_ROUTES?await be(n,i):e===RESOLVED_VIRTUAL_IDS.PAGE_LOADER?await xe(n,i):e===RESOLVED_VIRTUAL_IDS.ISLAND_MANIFEST?Se():e===RESOLVED_VIRTUAL_IDS.RUNTIME_CONFIG?Ce(n,r):e===RESOLVED_VIRTUAL_IDS.CONFIG?generateConfigModule(n,r):e===RESOLVED_VIRTUAL_IDS.LAYOUTS?(a||=await we(n,r,p),a):e===RESOLVED_VIRTUAL_IDS.ASSETS?Te(r):e===RESOLVED_VIRTUAL_IDS.RENDERER?Ee(n):e===RESOLVED_VIRTUAL_IDS.CLIENT_ENTRY?await ke(n,r):e===RESOLVED_VIRTUAL_IDS.INTEGRATION_LOADER?generateIntegrationLoaderModule(n):e===RESOLVED_VIRTUAL_IDS.ACTIONS?ce():null},handleHotUpdate({file:e,server:t}){let{isPage:n,isComponent:r,isLayout:i,isCss:o}=_e(e);(n||r||i||o)&&(n&&(R(t,RESOLVED_VIRTUAL_IDS.PAGE_ROUTES),R(t,RESOLVED_VIRTUAL_IDS.PAGE_LOADER)),i&&(a=null,h(),R(t,RESOLVED_VIRTUAL_IDS.LAYOUTS),R(t,RESOLVED_VIRTUAL_IDS.CLIENT_ENTRY)),setTimeout(()=>{t.ws.send({type:`full-reload`,path:`*`})},500)),ve(e)&&R(t,RESOLVED_VIRTUAL_IDS.CONFIG)}}}function R(e,t){let n=e.moduleGraph.getModuleById(t);n&&e.moduleGraph.invalidateModule(n)}function _e(e){let t=e.endsWith(`.css`);return{isPage:e.includes(`/pages/`)&&!t,isComponent:e.includes(`/components/`)&&/\.[tj]sx?$/.test(e),isLayout:(e.includes(`/layouts/`)||e.includes(`_layout`))&&/\.[tj]sx?$/.test(e),isCss:t}}function ve(e){return e.includes(`vite.config`)||e.includes(`avalon.config`)||e.includes(`nitro.config`)}function ye(e,t,n,r){e.watcher.on(`change`,e=>{e.includes(`_middleware`)&&(_(),r?.()),(e.includes(`/render/`)||e.includes(`/layout/`)||e.includes(`/islands/`))&&(B=null,V=null),(e.includes(`/layouts/`)||e.includes(`_layout`))&&globalThis.__avalonLayoutResolver?.clearCache?.()}),e.watcher.on(`add`,e=>{e.includes(`_middleware`)&&(_(),r?.())}),e.watcher.on(`unlink`,e=>{e.includes(`_middleware`)&&(_(),r?.())})}async function be(e,t){try{let{getAllPageDirs:t}=await import(`./module-discovery.js`),{discoverPageRoutesFromMultipleDirs:n}=await import(`../nitro/route-discovery.js`),r=await n(await t(e.pagesDir,e.modules,process.cwd()),{developmentMode:e.isDev});return`export const pageRoutes = ${JSON.stringify(r,null,2)};\nexport default pageRoutes;\n`}catch{return`export const pageRoutes = [];
|
|
11
11
|
export default pageRoutes;
|
|
12
12
|
`}}async function xe(e,t){try{let{getAllPageDirs:t}=await import(`./module-discovery.js`),{discoverPageRoutesFromMultipleDirs:n}=await import(`../nitro/route-discovery.js`),{relative:r}=await import(`node:path`),i=process.cwd(),a=await n(await t(e.pagesDir,e.modules,i),{developmentMode:e.isDev}),o=[],s=[];for(let e=0;e<a.length;e++){let t=a[e],n=`page_${e}`,c=r(i,t.filePath).replaceAll(`\\`,`/`),l=c.startsWith(`/`)?c:`/${c}`;o.push(`import * as ${n} from '${l}';`),s.push(` { pattern: ${JSON.stringify(t.pattern)}, params: ${JSON.stringify(t.params)}, module: ${n} }`)}return[...o,``,`const routes = [`,s.join(`,
|
|
13
|
-
`),`];`,``,`/**`,` * Match a pathname against discovered routes and return the page module.`,` * Uses the same pattern matching as Avalon's route discovery.`,` */`,`export function loadPage(pathname) {`,` const cleanPath = pathname.split('?')[0];`,` for (const route of routes) {`,`
|
|
13
|
+
`),`];`,``,`/**`,` * Match a pathname against discovered routes and return the page module.`,` * Uses the same pattern matching as Avalon's route discovery.`,` */`,`/**`,` * Match a pathname against discovered routes, returning the matched`,` * page module AND the extracted dynamic route params (e.g. { id: "123" }).`,` */`,`export function loadPage(pathname) {`,` const cleanPath = pathname.split('?')[0];`,` for (const route of routes) {`,` const m = matchRoute(cleanPath, route.pattern);`,` if (m.matched) return { module: route.module, params: m.params };`,` }`,` return null;`,`}`,``,`/**`,` * Match one pattern and capture dynamic segments:`,` * /users/:id vs /users/123 -> { id: "123" }`,` * /blog/** vs /blog/a/b -> { slug: "a/b" }`,` */`,`function matchRoute(pathname, pattern) {`,String.raw` const normPath = pathname === '/' ? '/' : pathname.replace(/\/$/, '');`,String.raw` const normPattern = pattern === '/' ? '/' : pattern.replace(/\/$/, '');`,` if (normPath === normPattern) return { matched: true, params: {} };`,` const patternParts = normPattern.split('/');`,` const pathParts = normPath.split('/');`,` const params = {};`,` for (let i = 0; i < patternParts.length; i++) {`,` const seg = patternParts[i];`,` if (seg === '**') {`,` params.slug = pathParts.slice(i).join('/');`,` return { matched: true, params };`,` }`,` if (i >= pathParts.length) return { matched: false, params: {} };`,` if (seg.startsWith(':')) params[seg.slice(1)] = pathParts[i];`,` else if (seg !== pathParts[i]) return { matched: false, params: {} };`,` }`,` if (pathParts.length > patternParts.length) return { matched: false, params: {} };`,` return { matched: true, params };`,`}`,``,`export default { loadPage, routes };`,``].join(`
|
|
14
14
|
`)}catch(e){return console.error(`[page-loader] Failed to generate page loader:`,e),`export function loadPage() { return null; }
|
|
15
15
|
export default { loadPage, routes: [] };
|
|
16
16
|
`}}function Se(){return`export const islandManifest = { islands: {}, clientEntry: "", css: [] };
|
|
@@ -18,7 +18,7 @@ export default islandManifest;
|
|
|
18
18
|
`}function Ce(e,t){let n={avalon:{streaming:t.streaming??!0,pagesDir:e.pagesDir,layoutsDir:e.layoutsDir,isDev:e.isDev},...t.runtimeConfig};return`export const runtimeConfig = ${JSON.stringify(n,null,2)};\nexport function useRuntimeConfig() { return runtimeConfig; }\nexport default runtimeConfig;\n`}export function generateConfigModule(e,t){let n=globalThis.__avalonConfig?.isDev??e.isDev,r={streaming:t.streaming??!0,pagesDir:e.pagesDir,layoutsDir:e.layoutsDir,isDev:n,...t.runtimeConfig};return`globalThis.__avalonHydrationMode = "${n?`entry-client`:`per-island`}";\nconst config = ${JSON.stringify(r,null,2)};\nexport function useAvalonConfig() { return config; }\nexport default config;\n`}async function we(e,t,n){let{getAllLayoutDirs:r}=await import(`./module-discovery.js`),{relative:i,resolve:a}=await import(`node:path`),{stat:o,readFile:c}=await import(`node:fs/promises`),l=process.cwd(),u=await r(e.layoutsDir,e.modules,l),d=[],f=0,p=a(l,e.layoutsDir);for(let{dir:t,prefix:n}of u){let r=s(t,`_layout.tsx`);try{if(!(await o(r)).isFile())continue}catch{continue}let a=i(l,r).replaceAll(`\\`,`/`),c=a.startsWith(`/`)?a:`/${a}`,u=t.startsWith(p),m=u&&!e.modules?`RootLayout`:`Layout_${f}`;d.push({prefix:n,importPath:c,varName:m,isShared:u,filePath:r}),f++}let m=d.filter(e=>e.isShared),h=d.filter(e=>!e.isShared),g=new Map;for(let e of h)try{let t=(await c(e.filePath,`utf8`)).match(/layoutConfig\s*=\s*{[\s\S]*?skipLayouts\s*:\s*\[([^\]]*)\]/)?.[1]??``,n=/['"`]_layout['"`]/.test(t);g.set(e.importPath,n)}catch{g.set(e.importPath,!1)}let _=d.map(e=>`import ${e.varName} from '${e.importPath}';`),v=h.toSorted((e,t)=>t.prefix.length-e.prefix.length).map(e=>{let t=e.prefix===`/`,n=g.get(e.importPath)??!1,r=t||n;return` { prefix: ${JSON.stringify(e.prefix)}, Layout: ${e.varName}, skipRoot: ${r} }`}),y=m.length>0?m[0].varName:`null`,b=JSON.stringify(n);return[`// Auto-generated by Avalon — do not edit`,...pe(e.core),`import { getUniversalCSSForHead } from '@useavalon/avalon/islands/universal-css-collector';`,`import { getUniversalHeadForInjection, injectSolidHydrationScriptIfNeeded } from '@useavalon/avalon/islands/universal-head-collector';`,..._,``,`const RootLayoutComponent = ${y};`,`const _cssLinks = ${b};`,``,`const moduleLayouts = [`,v.join(`,
|
|
19
19
|
`),`];`,``,`function getLayoutsForPath(pathname) {`,` for (const entry of moduleLayouts) {`,` if (entry.prefix === '/' ? pathname === '/' : pathname.startsWith(entry.prefix)) {`,` return entry;`,` }`,` }`,` return null;`,`}`,``,`function injectUniversalAssets(html) {`,` // In dev, inject <link> tags for all discovered CSS files.`,` // The ?direct suffix makes Vite return raw CSS (text/css) instead`,` // of a JS module wrapper, so <link rel="stylesheet"> works.`,` if (process.env.NODE_ENV !== 'production' && _cssLinks.length > 0) {`,` var links = _cssLinks.map(function(href) {`,` return '<link rel="stylesheet" href="' + href + '?direct">';`,String.raw` }).join('\n');`,` if (html.includes('</head>')) {`,String.raw` html = html.replace('</head>', links + '\n</head>');`,` }`,` }`,` const universalCSS = getUniversalCSSForHead(true);`,` if (universalCSS && html.includes('</head>')) {`,String.raw` html = html.replace('</head>', universalCSS + '\n</head>');`,` }`,` const universalHead = getUniversalHeadForInjection(true);`,` if (universalHead && html.includes('</head>')) {`,String.raw` html = html.replace('</head>', universalHead + '\n</head>');`,` }`,` html = injectSolidHydrationScriptIfNeeded(html);`,` return html;`,`}`,``,`export async function wrapWithLayouts(pageHtml, pageModule, context, injectAssets) {`,` const pathname = context.url.pathname;`,` const frontmatter = {`,` ...(pageModule.frontmatter || {}),`,` ...(pageModule.metadata || {}),`,` currentPath: pathname,`,` };`,` const pageLayoutConfig = pageModule.layoutConfig;`,` const skipAll = pageLayoutConfig?.skipLayouts?.includes('_layout');`,``,` const layoutEntry = getLayoutsForPath(pathname);`,` const routeInfo = { path: pathname, params: context.params, query: context.url.searchParams };`,` let html;`,``,` if (!layoutEntry || skipAll) {`,` if (RootLayoutComponent && !skipAll) {`,` const rootProps = {`,` children: h('avalon-page', { id: 'app', dangerouslySetInnerHTML: { __html: pageHtml } }),`,` frontmatter,`,` data: {},`,` route: routeInfo,`,` };`,` const rootResult = RootLayoutComponent(rootProps);`,` const resolvedRoot = rootResult instanceof Promise ? await rootResult : rootResult;`,String.raw` html = '<!DOCTYPE html>\n' + preactRenderToString(resolvedRoot);`,` } else {`,` // skipAll is true — page provides its own HTML shell or needs a minimal one`,` if (pageHtml.trimStart().startsWith('<html')) {`,String.raw` html = '<!DOCTYPE html>\n' + pageHtml;`,` } else {`,` const title = String(frontmatter.title || 'Avalon');`,` html = [`,` '<!DOCTYPE html>',`,` '<html lang="en">',`,` '<head>',`,` '<meta charset="utf-8">',`,` '<meta name="viewport" content="width=device-width, initial-scale=1">',`,` '<title>' + title + '</title>',`,` '</head>',`,` '<body>',`,` '<div id="app">' + pageHtml + '</div>',`,` '</body>',`,` '</html>',`,String.raw` ].join('\n');`,` }`,` }`,` } else {`,` const layoutProps = {`,` children: h('avalon-page', { dangerouslySetInnerHTML: { __html: pageHtml } }),`,` frontmatter,`,` data: {},`,` route: routeInfo,`,` };`,` const layoutResult = layoutEntry.Layout(layoutProps);`,` const resolvedLayout = layoutResult instanceof Promise ? await layoutResult : layoutResult;`,` let wrappedHtml = preactRenderToString(resolvedLayout);`,``,` // If the layout provides its own HTML shell (starts with <html),`,` // skip root wrapping regardless of skipRoot flag — the layout IS the document.`,` const layoutProvidesShell = wrappedHtml.trimStart().startsWith('<html');`,``,` if (!layoutProvidesShell && !layoutEntry.skipRoot && RootLayoutComponent) {`,` const rootProps = {`,` children: h('avalon-page', { dangerouslySetInnerHTML: { __html: wrappedHtml } }),`,` frontmatter,`,` data: {},`,` route: routeInfo,`,` };`,` const rootResult = RootLayoutComponent(rootProps);`,` const resolvedRoot = rootResult instanceof Promise ? await rootResult : rootResult;`,` wrappedHtml = preactRenderToString(resolvedRoot);`,` }`,``,String.raw` html = '<!DOCTYPE html>\n' + wrappedHtml;`,` }`,``,` if (injectAssets) {`,` html = injectAssets(html);`,` }`,` return injectUniversalAssets(html);`,`}`,``,`export default { wrapWithLayouts };`,``].join(`
|
|
20
20
|
`)}function Te(e){let t=e.clientEntry??`app/entry-client`;return[`// Auto-generated by Avalon — do not edit`,`// @ts-ignore — virtual import resolved by Nitro's Vite assets plugin at build time`,`import clientAssets from '${t.startsWith(`/`)?t:`/${t}`}?assets=client';`,``,`function buildAssetTags() {`,` const cssLinks = (clientAssets?.css ?? [])`,` .filter(attr => {`,` const href = attr.href || '';`,` // The SSR build produces ssr-index-*.css containing all global, reset,`,` // token, and layout CSS module styles. The client build may also emit`,` // entry-client-*.css (a subset) and index-*.css. To avoid duplicates,`,` // prefer ssr-index when it exists; otherwise fall back to the others.`,` var hasSsrIndex = (clientAssets?.css ?? []).some(function(a) { return (a.href || '').includes('ssr-index'); });`,` if (hasSsrIndex) return href.includes('ssr-index');`,` if (href.includes('entry-client') && href.endsWith('.css')) return true;`,String.raw` if (/\/index-[^/]+\.css$/.test(href)) return true;`,` return false;`,` })`,` .map(attr => '<link rel="stylesheet" href="' + attr.href + '">')`,String.raw` .join('\n');`,` const jsPreloads = (clientAssets?.js ?? [])`,` .map(attr => '<link rel="modulepreload" href="' + attr.href + '">')`,String.raw` .join('\n');`,` const entryScript = clientAssets?.entry`,` ? '<script type="module" src="' + clientAssets.entry + '"><\/script>'`,` : '';`,` return { cssLinks, jsPreloads, entryScript };`,`}`,``,`export function injectAssets(html) {`,` const { cssLinks, jsPreloads, entryScript } = buildAssetTags();`,` if (html.includes('</head>')) {`,String.raw` html = html.replace('</head>', cssLinks + '\n' + jsPreloads + '\n</head>');`,` }`,` if (html.includes('</body>')) {`,String.raw` html = html.replace('</body>', entryScript + '\n</body>');`,` }`,` return html;`,`}`,``,`export { clientAssets };`,`export default { injectAssets, clientAssets };`,``].join(`
|
|
21
|
-
`)}function Ee(e){let t=Array.isArray(e.integrations)?e.integrations:[],n=[],r=[];for(let e of t){let t=`${e}Integration`;n.push(`import { ${t} } from '@useavalon/${e}';`),r.push(`registry.register(${t});`)}let i=me(e.core);return[`// Auto-generated by Avalon — do not edit`,`import { createNitroRenderer } from '@useavalon/avalon/nitro/renderer';`,`import { registerBuiltinDirectives } from '@useavalon/avalon';`,`import { registry } from '@useavalon/avalon/islands/integration-registry';`,`import avalonConfig from 'virtual:avalon/config';`,`import { loadPage } from 'virtual:avalon/page-loader';`,`import { wrapWithLayouts } from 'virtual:avalon/layouts';`,`import { injectAssets } from 'virtual:avalon/assets';`,...n,``,...i,``,`// Pre-register framework integrations for SSR`,...r,``,`// Register built-in custom hydration directives (on:delay, on:scroll, etc.)`,`registerBuiltinDirectives();`,``,`// Set hydration mode flag — intentionally duplicated from virtual:avalon/config`,`// for module-load-order resilience (config import may be tree-shaken or deferred).`,`globalThis.__avalonHydrationMode = avalonConfig.isDev ? "entry-client" : "per-island";`,``,`export default createNitroRenderer({`,` avalonConfig,`,` isDev: avalonConfig.isDev,`,` resolvePageRoute: async (pathname) => {`,` const
|
|
21
|
+
`)}function Ee(e){let t=Array.isArray(e.integrations)?e.integrations:[],n=[],r=[];for(let e of t){let t=`${e}Integration`;n.push(`import { ${t} } from '@useavalon/${e}';`),r.push(`registry.register(${t});`)}let i=me(e.core);return[`// Auto-generated by Avalon — do not edit`,`import { createNitroRenderer } from '@useavalon/avalon/nitro/renderer';`,`import { registerBuiltinDirectives } from '@useavalon/avalon';`,`import { registry } from '@useavalon/avalon/islands/integration-registry';`,`import avalonConfig from 'virtual:avalon/config';`,`import { loadPage } from 'virtual:avalon/page-loader';`,`import { wrapWithLayouts } from 'virtual:avalon/layouts';`,`import { injectAssets } from 'virtual:avalon/assets';`,...n,``,...i,``,`// Pre-register framework integrations for SSR`,...r,``,`// Register built-in custom hydration directives (on:delay, on:scroll, etc.)`,`registerBuiltinDirectives();`,``,`// Set hydration mode flag — intentionally duplicated from virtual:avalon/config`,`// for module-load-order resilience (config import may be tree-shaken or deferred).`,`globalThis.__avalonHydrationMode = avalonConfig.isDev ? "entry-client" : "per-island";`,``,`export default createNitroRenderer({`,` avalonConfig,`,` isDev: avalonConfig.isDev,`,` resolvePageRoute: async (pathname) => {`,` const match = loadPage(pathname);`,` if (!match || !('default' in match.module)) return null;`,` return { filePath: '[virtual:' + pathname + ']', pattern: pathname, params: match.params };`,` },`,` loadPageModule: async (filePath) => {`,String.raw` const m = filePath.match(/^\[virtual:(.+)\]$/);`,` const pathname = m ? m[1] : filePath;`,` const match = loadPage(pathname);`,` if (match) return match.module;`,` return { default: () => null, metadata: { title: 'Avalon' } };`,` },`,` wrapWithLayouts: (pageHtml, pageModule, context) =>`,` wrapWithLayouts(pageHtml, pageModule, context, injectAssets),`,`});`,``].join(`
|
|
22
22
|
`)}async function De(e,t){let{readdir:n}=await import(`node:fs/promises`),{relative:r,join:i}=await import(`node:path`),a=[];for(let{dir:o}of e){let e;try{e=await n(o,{withFileTypes:!0})}catch{continue}for(let n of e){if(!n.isFile()||!n.name.endsWith(`.css`))continue;let e=r(t,i(o,n.name)).replaceAll(`\\`,`/`);a.push(e.startsWith(`/`)?e:`/${e}`)}}return a}function Oe(e){if(e.length===0)return[];let t=[`// Layout CSS (auto-discovered)`],n=0;for(let r of e)r.includes(`.module.`)?(t.push(`import _lcss${n} from '${r}';`),n++):t.push(`import '${r}';`);return t}async function ke(e,t){let{getAllLayoutDirs:n}=await import(`./module-discovery.js`),r=process.cwd(),i=await De(await n(e.layoutsDir,e.modules,r),r),a=globalThis.__avalonConfig?.isDev??e.isDev?`@useavalon/avalon/client/main`:`@useavalon/avalon/client/main-slim`,o=[`// Auto-generated by Avalon — do not edit`,`// Island hydration runtime`];(globalThis.__avalonHydrationMode??`entry-client`)===`entry-client`?o.push(`import '${a}';`):o.push(`// Per-island hydration mode — no shared runtime needed`),o.push(``);let s=t.globalCSS??[];for(let e of s){let t=e.startsWith(`/`)?e:`/${e}`;o.push(`// Global CSS`,`import '${t}';`)}return s.length>0&&o.push(``),o.push(...Oe(i),``),o.join(`
|
|
23
23
|
`)}function Ae(){return[`// --- Inlined Solid adapter (production) ---`,`// Eliminates a separate chunk + network request for the Solid client adapter.`,`// Only imports hydrate/createComponent — no render() fallback (saves ~1-2 KiB).`,`function _ensureHydrationContext() {`,` if (!globalThis._$HY) {`,` globalThis._$HY = { events: [], completed: new WeakSet(), r: {}, fe() {} };`,` }`,`}`,``,`async function _solidHydrate(container, Component, props) {`,` if (!container) throw new Error("Container element is required for hydration");`,` if (!Component || typeof Component !== "function") {`,` throw new Error("Invalid Solid component: expected function, got " + typeof Component);`,` }`,` var el = container;`,` var renderId = el.dataset.solidRenderId || el.dataset.renderId;`,` var { hydrate: solidHydrate, createComponent } = await import("solid-js/web");`,` _ensureHydrationContext();`,` solidHydrate(function() { return createComponent(Component, props || {}); }, el, { renderId: renderId || "" });`,`}`,``,`var _solidModule = { hydrate: _solidHydrate };`,``]}function je(e,t,n){let r=[];for(let i of e){let e=t[i];e&&(i===`solid`&&!n?r.push(` case "solid":`,` return _solidModule;`):i===`react`?r.push(` case "react":`):r.push(` case "${i}":`,` return import("${e}");`))}return e.includes(`react`)&&!e.includes(`preact`)&&r.push(` return import("${t.react}");`),r}function Me(e,t){let n=[];for(let r of e){let e=t[r];e&&n.push(` case "${r}":`,` return import("${e}").then(m => m.${r}Adapter);`)}return n}export function generateIntegrationLoaderModule(e){let t=(e.integrations??[]).map(e=>typeof e==`string`?e:e.name),n={preact:`@useavalon/preact/client`,react:he(e.core),vue:`@useavalon/vue/client`,svelte:`@useavalon/svelte/client`,solid:`@useavalon/solid/client`,lit:`@useavalon/lit/client`,qwik:`@useavalon/qwik/client`},r={preact:`@useavalon/preact/client/hmr`,react:`@useavalon/react/client/hmr`,vue:`@useavalon/vue/client/hmr`,svelte:`@useavalon/svelte/client/hmr`,solid:`@useavalon/solid/client/hmr`,lit:`@useavalon/lit/client/hmr`,qwik:`@useavalon/qwik/client/hmr`},i=t.includes(`lit`),a=t.includes(`solid`),o=(globalThis.__avalonConfig?.isDev??e.isDev)===!0,s=[`// Auto-generated by Avalon — only includes configured integrations`,``];return a&&!o&&s.push(...Ae()),s.push(`// --- loadIntegrationModule ---`,`export async function loadIntegrationModule(framework) {`,` switch (framework) {`,...je(t,n,o),` default:`," throw new Error(`Unknown or unconfigured framework: ${framework}`);",` }`,`}`,``,`// --- Lit hydration pre-load (only if Lit is configured) ---`),i?s.push(`export async function preLitHydration() {`,` await import("@useavalon/lit/client");`,`}`):s.push(`export async function preLitHydration() {}`),s.push(``,`// --- HMR adapter loader ---`,`export async function loadHMRAdapter(framework) {`,` switch (framework) {`,...Me(t,r),` default: return null;`,` }`,`}`),s.join(`
|
|
24
24
|
`)}export function getViteDevServer(){return globalThis.__viteDevServer}export function getAvalonConfig(){return globalThis.__avalonConfig}export function isDevelopmentMode(){return globalThis.__avalonConfig?.isDev??!0}const z=`<!--AVALON_STREAM_BOUNDARY-->`;let B=null,V=null;async function H(e,t){if(t===`react`){let e=await import(`react`),t=await import(`react-dom/server`),n=e.default??e,r=t.default??t;return{h:e.createElement??n.createElement,renderToString:t.renderToString??r.renderToString}}let n=await e.ssrLoadModule(`preact`),r=await e.ssrLoadModule(`preact-render-to-string`);return{h:n.h,renderToString:r.render??r.default}}function U(e){return e.split(`/`).pop()?.replace(/\.[^.]+$/,``)||``}async function W(e,t,n){let r=[];for(let n of t){let t=await e.ssrLoadModule(n);r.push({file:n,module:t})}for(let r of t){let t=await T(e,r);n.push(...t)}return r}async function G(e,t,n,r){let i=[],a=[];for(let o of e){let e=o.module.default;if(!(!e||typeof e!=`function`))try{let s=e({...t,children:n(`div`,null,`test`)}),c=r(s instanceof Promise?await s:s);c.trim().startsWith(`<html`)||c.includes(`<!DOCTYPE`)?i.push(o):a.push(o)}catch{a.push(o)}}return{shellLayouts:i,wrapperLayouts:a}}async function Ne(e,t,n,r){try{let i=e({...t,children:n(`div`,{dangerouslySetInnerHTML:{__html:z}})});return r(i instanceof Promise?await i:i)}catch{return null}}function Pe(e,t){let n=e;if(t.length>0){let e=`<style data-avalon-ssr-css>${t.join(`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useavalon/avalon",
|
|
3
|
-
"version": "0.3.1
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Multi-framework islands architecture for the modern web",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
}
|
|
160
160
|
},
|
|
161
161
|
"dependencies": {
|
|
162
|
-
"@useavalon/core": "^0.3.1
|
|
162
|
+
"@useavalon/core": "^0.3.1",
|
|
163
163
|
"@mdx-js/rollup": "^3.0.0",
|
|
164
164
|
"h3": "^2.0.1-rc.16",
|
|
165
165
|
"marked": "^17.0.4",
|