@useavalon/avalon 0.1.50 → 0.1.52

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.
@@ -181,4 +181,4 @@ import{getRequestURL as e}from"h3";import{h as t}from"preact";import n from"prea
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 T(e,t,n){return async()=>(e.value??=await r({baseDir:t,devMode:n}),e.value)}function E(e,t,n){return async(r,i)=>e?o(r,i,t):createErrorResponse(r,n)}export function createNitroRenderer(e){let{avalonConfig:t,isDev:n=!1,enableCustomErrorPages:r=!0}=e,o={isDev:n,avalonConfig:t,loadPageModule:e.loadPageModule,pagesDir:t.pagesDir};r&&a(o).catch(e=>{console.warn(`[renderer] Failed to discover error pages:`,e)});let c=T({value:null},t.srcDir||`src`,n),f=E(r,o,n);async function p(r){let a=getRequestURL(r).pathname;try{let o=await i(r,await c(),{devMode:n});if(o)return n&&console.log(`[renderer] Middleware terminated request for ${a}`),o;let u=r.context.route,d=null;if(d=u||(e.resolvePageRoute?await e.resolvePageRoute(a,t.pagesDir):await D(a,t.pagesDir)),!d)return f(s(`Page not found: ${a}`),r);let p=e.loadPageModule?await e.loadPageModule(d.filePath):await O(d.filePath),h=createRenderContext(r,r.context.params||d.params);if(e.resolveLayouts&&(h.layoutContext={layouts:await e.resolveLayouts(a,t)}),t.streaming){let e=await renderPageStream(p,h,{onShellReady:()=>{setResponseHeader(r,`Content-Type`,`text/html; charset=utf-8`)}});return new Response(e,{headers:{"Content-Type":`text/html; charset=utf-8`}})}else{let t=await renderPage(p,h,{},e.wrapWithLayouts),r=injectHydrationScript(t.html,n);return new Response(r,{status:t.statusCode,headers:t.headers})}}catch(e){return console.error(`[Nitro Renderer Error]`,e),f(e instanceof Error?e:Error(String(e)),r)}}return Object.assign(p,{async fetch(r){let i=new URL(r.url,`http://localhost`).pathname;try{let a=null;if(a=e.resolvePageRoute?await e.resolvePageRoute(i,t.pagesDir):await D(i,t.pagesDir),!a)return createErrorResponse(s(`Page not found: ${i}`),n);let o=await renderPage(e.loadPageModule?await e.loadPageModule(a.filePath):await O(a.filePath),createRenderContextFromRequest(r,a.params),{},e.wrapWithLayouts),c=injectHydrationScript(o.html,n);return new Response(c,{status:o.statusCode,headers:o.headers})}catch(e){return console.error(`[Nitro Renderer .fetch() Error]`,e),createErrorResponse(e instanceof Error?e:Error(String(e)),n)}}})}async function D(e,t){return e===`/`||e===``?{filePath:`src/pages/index.tsx`,pattern:`/`,params:{}}:{filePath:`src/pages/${e.replace(/^\//,``).replace(/\/$/,``)}.tsx`,pattern:e,params:{}}}async function O(e){return{default:()=>null,metadata:{title:`Avalon Page`}}}export function createNitroCatchAllRenderer(e){let{avalonConfig:t,isDev:n=!1,loadPageModule:r,resolveLayouts:o,enableCustomErrorPages:c=!0}=e,f={isDev:n,avalonConfig:t,loadPageModule:r,pagesDir:t.pagesDir};c&&a(f).catch(e=>{console.warn(`[renderer] Failed to discover error pages:`,e)});let p=T({value:null},t.srcDir||`src`,n),g=E(c,f,n);async function _(a){let c=getRequestURL(a).pathname;try{let u=await i(a,await p(),{devMode:n});if(u)return n&&console.log(`[renderer] Middleware terminated request for ${c}`),u;let d=a.context.params||{},f=d.slug||c.replace(/^\//,``)||`index`,h=`${t.pagesDir}/${f}.tsx`,_;try{_=await r(h)}catch(e){try{_=await r(`${t.pagesDir}/${f}/index.tsx`)}catch(r){return n&&(console.debug(`[renderer] Page not found: ${h}`,e),console.debug(`[renderer] Index fallback not found: ${t.pagesDir}/${f}/index.tsx`,r)),g(s(`Page not found: ${c}`),a)}}let v=createRenderContext(a,d);if(o&&(v.layoutContext={layouts:await o(c,t)}),t.streaming){let e=await renderPageStream(_,v,{onShellReady:()=>{setResponseHeader(a,`Content-Type`,`text/html; charset=utf-8`)}});return new Response(e,{headers:{"Content-Type":`text/html; charset=utf-8`}})}else{let t=await renderPage(_,v,{},e.wrapWithLayouts),r=injectHydrationScript(t.html,n);return new Response(r,{status:t.statusCode,headers:t.headers})}}catch(e){return console.error(`[Nitro Catch-All Renderer Error]`,e),g(e instanceof Error?e:Error(String(e)),a)}}return Object.assign(_,{async fetch(i){let a=new URL(i.url,`http://localhost`).pathname;try{let o=a.replace(/^\//,``)||`index`,c=`${t.pagesDir}/${o}.tsx`,l;try{l=await r(c)}catch{try{l=await r(`${t.pagesDir}/${o}/index.tsx`)}catch{return createErrorResponse(s(`Page not found: ${a}`),n)}}let d=createRenderContextFromRequest(i),f=await renderPage(l,d,{},e.wrapWithLayouts),p=injectHydrationScript(f.html,n);return new Response(p,{status:f.statusCode,headers:f.headers})}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";
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 T(e,t,n){return async()=>(e.value??=await r({baseDir:t,devMode:n}),e.value)}function E(e,t,n){return async(r,i)=>e?o(r,i,t):createErrorResponse(r,n)}export function createNitroRenderer(e){let{avalonConfig:t,isDev:n=!1,enableCustomErrorPages:r=!0}=e,o={isDev:n,avalonConfig:t,loadPageModule:e.loadPageModule,pagesDir:t.pagesDir};r&&a(o).catch(e=>{console.warn(`[renderer] Failed to discover error pages:`,e)});let c=T({value:null},t.srcDir||`src`,n),f=E(r,o,n);async function p(r){let a=getRequestURL(r).pathname;try{let o=await i(r,await c(),{devMode:n});if(o)return n&&console.log(`[renderer] Middleware terminated request for ${a}`),o;let u=r.context.route,d=null;if(d=u||(e.resolvePageRoute?await e.resolvePageRoute(a,t.pagesDir):await D(a,t.pagesDir)),!d)return f(s(`Page not found: ${a}`),r);let p=e.loadPageModule?await e.loadPageModule(d.filePath):await O(d.filePath),h=createRenderContext(r,r.context.params||d.params);if(e.resolveLayouts&&(h.layoutContext={layouts:await e.resolveLayouts(a,t)}),t.streaming&&!e.wrapWithLayouts){let e=await renderPageStream(p,h,{onShellReady:()=>{setResponseHeader(r,`Content-Type`,`text/html; charset=utf-8`)}});return new Response(e,{headers:{"Content-Type":`text/html; charset=utf-8`}})}else{let t=await renderPage(p,h,{},e.wrapWithLayouts),r=injectHydrationScript(t.html,n);return new Response(r,{status:t.statusCode,headers:t.headers})}}catch(e){return console.error(`[Nitro Renderer Error]`,e),f(e instanceof Error?e:Error(String(e)),r)}}return Object.assign(p,{async fetch(r){let i=new URL(r.url,`http://localhost`).pathname;try{let a=null;if(a=e.resolvePageRoute?await e.resolvePageRoute(i,t.pagesDir):await D(i,t.pagesDir),!a)return createErrorResponse(s(`Page not found: ${i}`),n);let o=await renderPage(e.loadPageModule?await e.loadPageModule(a.filePath):await O(a.filePath),createRenderContextFromRequest(r,a.params),{},e.wrapWithLayouts),c=injectHydrationScript(o.html,n);return new Response(c,{status:o.statusCode,headers:o.headers})}catch(e){return console.error(`[Nitro Renderer .fetch() Error]`,e),createErrorResponse(e instanceof Error?e:Error(String(e)),n)}}})}async function D(e,t){return e===`/`||e===``?{filePath:`src/pages/index.tsx`,pattern:`/`,params:{}}:{filePath:`src/pages/${e.replace(/^\//,``).replace(/\/$/,``)}.tsx`,pattern:e,params:{}}}async function O(e){return{default:()=>null,metadata:{title:`Avalon Page`}}}export function createNitroCatchAllRenderer(e){let{avalonConfig:t,isDev:n=!1,loadPageModule:r,resolveLayouts:o,enableCustomErrorPages:c=!0}=e,f={isDev:n,avalonConfig:t,loadPageModule:r,pagesDir:t.pagesDir};c&&a(f).catch(e=>{console.warn(`[renderer] Failed to discover error pages:`,e)});let p=T({value:null},t.srcDir||`src`,n),g=E(c,f,n);async function _(a){let c=getRequestURL(a).pathname;try{let u=await i(a,await p(),{devMode:n});if(u)return n&&console.log(`[renderer] Middleware terminated request for ${c}`),u;let d=a.context.params||{},f=d.slug||c.replace(/^\//,``)||`index`,h=`${t.pagesDir}/${f}.tsx`,_;try{_=await r(h)}catch(e){try{_=await r(`${t.pagesDir}/${f}/index.tsx`)}catch(r){return n&&(console.debug(`[renderer] Page not found: ${h}`,e),console.debug(`[renderer] Index fallback not found: ${t.pagesDir}/${f}/index.tsx`,r)),g(s(`Page not found: ${c}`),a)}}let v=createRenderContext(a,d);if(o&&(v.layoutContext={layouts:await o(c,t)}),t.streaming&&!e.wrapWithLayouts){let e=await renderPageStream(_,v,{onShellReady:()=>{setResponseHeader(a,`Content-Type`,`text/html; charset=utf-8`)}});return new Response(e,{headers:{"Content-Type":`text/html; charset=utf-8`}})}else{let t=await renderPage(_,v,{},e.wrapWithLayouts),r=injectHydrationScript(t.html,n);return new Response(r,{status:t.statusCode,headers:t.headers})}}catch(e){return console.error(`[Nitro Catch-All Renderer Error]`,e),g(e instanceof Error?e:Error(String(e)),a)}}return Object.assign(_,{async fetch(i){let a=new URL(i.url,`http://localhost`).pathname;try{let o=a.replace(/^\//,``)||`index`,c=`${t.pagesDir}/${o}.tsx`,l;try{l=await r(c)}catch{try{l=await r(`${t.pagesDir}/${o}/index.tsx`)}catch{return createErrorResponse(s(`Page not found: ${a}`),n)}}let d=createRenderContextFromRequest(i),f=await renderPage(l,d,{},e.wrapWithLayouts),p=injectHydrationScript(f.html,n);return new Response(p,{status:f.statusCode,headers:f.headers})}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";
@@ -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,unlinkSync as o,writeFileSync as s}from"node:fs";import{dirname as c,join as l,relative as u}from"node:path";function d(e,t,r=[]){if(!n(e))return r;for(let n of i(e,{withFileTypes:!0})){let i=l(e,n.name);n.isDirectory()?d(i,t,r):t(n.name)&&r.push(i)}return r}function f(e){if(!n(e))return!1;let t=a(e,`utf-8`);return t.length<500&&!t.includes(`data-framework`)&&!t.includes(`avalon`)}function p(e){for(let t of[`dist/index.html`,`.netlify/functions-internal/server/public/index.html`]){let r=l(e,t);f(r)?(o(r),console.log(`[cleanup] Removed stale Vite template ${t}`)):n(r)&&console.log(`[cleanup] Preserved prerendered ${t}`)}}function m(e,t,r){if(!n(e))return;let i=[l(t,`assets`),l(r,`.netlify`,`functions-internal`,`server`,`public`,`assets`),l(r,`.output`,`public`,`assets`)].find(e=>n(e));if(!i)return;let o=d(i,e=>e.endsWith(`.css`)).map(e=>`/assets${e.substring(i.length).replaceAll(`\\`,`/`)}`);console.log(`[patch] Found ${o.length} CSS files in ${i}`);let c=a(e,`utf-8`);for(let{re:t,hrefRe:n,q:r}of[{re:/css:\[(\{href:`[^`]+`\}(?:,\{href:`[^`]+`\})*)\]/,hrefRe:/href:`([^`]+)`/g,q:"`"},{re:/css:\[(\{href:"[^"]+"\}(?:,\{href:"[^"]+"\})*)\]/,hrefRe:/href:"([^"]+)"/g,q:`"`}]){let i=t.exec(c);if(!i)continue;let a=new Set([...i[1].matchAll(n)].map(e=>e[1])),l=o.filter(e=>!a.has(e));if(l.length===0){console.log(`[patch] All CSS already included`);return}let u=l.map(e=>`{href:${r}${e}${r}}`).join(`,`);c=c.replace(i[0],`css:[${i[1]},${u}]`),s(e,c),console.log(`[patch] ✅ Added ${l.length} CSS files to SSR bundle`);return}console.warn(`[patch] Could not find CSS array in SSR bundle`)}function h(t,o){let c=[l(t,`node_modules`,`.nitro`,`vite`,`services`,`ssr`,`assets`)];for(let u of c){if(!n(u))continue;let c=i(u).filter(e=>e.endsWith(`.css`));if(c.length===0)continue;let d=[l(o,`assets`),l(t,`.output`,`public`,`assets`),l(t,`.netlify`,`functions-internal`,`server`,`public`,`assets`)];for(let t of d){r(t,{recursive:!0});for(let n of c)e(l(u,n),l(t,`ssr-${n}`))}let f=c[0],p=a(l(u,f)).length,m=`ssr-${f}`;console.log(`[ssr-css] Copied SSR CSS → /assets/${m} (${p} bytes)`);let h=[l(t,`.output`,`server`,`index.mjs`),l(t,`.netlify`,`functions-internal`,`server`,`main.mjs`)];for(let e of h){if(!n(e))continue;let t=a(e,`utf-8`),r=`/assets/${m}`;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/${m}\`}`;t=t.replace(i[0],i[0]+a),s(e,t),console.log(`[ssr-css] ✅ Patched asset manifest in ${e}`)}}return}console.log(`[ssr-css] No SSR CSS files found`)}function g(t){let i=[l(t,`assets`,`islands`),l(t,`islands`)].find(e=>n(e));if(!i)return;let o=d(i,e=>e.endsWith(`.js`)&&!e.endsWith(`.js.map`));if(o.length===0)return;let f=o.filter(e=>/-[A-Za-z0-9_-]{6,12}\.js$/.test(e));if(f.length===0){console.log(`[redirects] ${o.length} island(s) found with clean paths — no redirects needed`);return}let p=[];for(let n of f){let i=`/${u(t,n).replaceAll(`\\`,`/`)}`,a=i.replace(`/assets/`,`/`).replace(/-[A-Za-z0-9_-]{6,12}\.js$/,`.js`);p.push(`${a} ${i} 200`);let o=l(t,a.slice(1));r(c(o),{recursive:!0}),e(n,o)}let m=l(t,`_redirects`),h=n(m)?a(m,`utf-8`):``;h=h.replaceAll(/# Island JS path rewrites[^\n]*\n(?:\/islands\/[^\n]*\n)*/g,``).trim();let g=`# Island JS path rewrites (generated by Avalon post-build)
2
2
  `;s(m,h?`${h}\n\n${g}${p.join(`
3
3
  `)}\n`:`${g+p.join(`
4
- `)}\n`),console.log(`[redirects] ✅ Wrote ${p.length} island redirects + local copies`)}function _(t,a){let o=[l(t,`.output`,`public`,`_adapters`),l(a,`_adapters`)];for(let t of o){if(!n(t))continue;let o=i(t).filter(e=>e.endsWith(`.js`));if(o.length===0)continue;let s=l(a,`_adapters`);r(s,{recursive:!0});for(let n of o){let r=l(t,n),i=l(s,n);r!==i&&e(r,i)}console.log(`[adapters] ✅ Copied ${o.length} framework adapters`);return}console.log(`[adapters] No _adapters/ directory found`)}function v(e){let r=l(e,`.netlify`,`functions-internal`,`server`);if(!n(r))return;let i=[l(e,`.netlify`,`v1`,`functions`,`server`),l(e,`netlify`,`functions`,`server`)];for(let n of i){t(r,n,{recursive:!0,force:!0});let i=n.substring(e.length).replaceAll(`\\`,`/`);console.log(`[netlify-fn] ✅ Copied server function to ${i}/`)}}function y(e){let t=a(e,`utf-8`);return t.includes(`path: "/*"`)||t.includes("path:`/*`")}function b(e,t,r){let i=l(c(e),`_prerender-server.mjs`),a=``,o=[l(r,`node_modules`,`urlpattern-polyfill`,`index.js`),l(r,`node_modules`,`urlpattern-polyfill`,`dist`,`urlpattern.js`)].find(e=>n(e));return o&&(a=`import '${o.replaceAll(`\\`,`/`)}';`),s(i,`
4
+ `)}\n`),console.log(`[redirects] ✅ Wrote ${p.length} island redirects + local copies`)}function _(t,a){let o=[l(t,`.output`,`public`,`_adapters`),l(a,`_adapters`)];for(let t of o){if(!n(t))continue;let o=i(t).filter(e=>e.endsWith(`.js`));if(o.length===0)continue;let s=l(a,`_adapters`);r(s,{recursive:!0});for(let n of o){let r=l(t,n),i=l(s,n);r!==i&&e(r,i)}console.log(`[adapters] ✅ Copied ${o.length} framework adapters`);return}console.log(`[adapters] No _adapters/ directory found`)}function v(e){let r=l(e,`.netlify`,`functions-internal`,`server`);if(!n(r))return;let i=[l(e,`.netlify`,`v1`,`functions`,`server`)];for(let n of i){t(r,n,{recursive:!0,force:!0});let i=n.substring(e.length).replaceAll(`\\`,`/`);console.log(`[netlify-fn] ✅ Copied server function to ${i}/`)}}function y(e){let t=a(e,`utf-8`);return t.includes(`path: "/*"`)||t.includes("path:`/*`")}function b(e,t,r){let i=l(c(e),`_prerender-server.mjs`),a=``,o=[l(r,`node_modules`,`urlpattern-polyfill`,`index.js`),l(r,`node_modules`,`urlpattern-polyfill`,`dist`,`urlpattern.js`)].find(e=>n(e));return o&&(a=`import '${o.replaceAll(`\\`,`/`)}';`),s(i,`
5
5
  ${a}
6
6
  import { createServer } from 'node:http';
7
7
  import handler from './main.mjs';
@@ -27,5 +27,5 @@ const server = createServer(async (req, res) => {
27
27
  server.listen(PORT, '127.0.0.1', () => {
28
28
  console.log('[prerender-wrapper] Listening on http://127.0.0.1:' + PORT);
29
29
  });
30
- `),i}function x(e){let t=[],n=/<a\s[^>]*href=["']([^"'#?]+)/gi,r=null;for(r=n.exec(e);r!==null;r=n.exec(e)){let e=r[1];e.startsWith(`/`)&&!e.startsWith(`//`)&&!e.startsWith(`/assets/`)&&!e.startsWith(`/islands/`)&&!e.startsWith(`/chunks/`)&&!e.startsWith(`/_`)&&!e.match(/\.\w{2,5}$/)&&t.push(e)}return[...new Set(t)]}async function S(t,i,d,f){let p=[l(t,`.output`,`server`,`index.mjs`),l(t,`.netlify`,`functions-internal`,`server`,`server.mjs`),l(t,`.netlify`,`v1`,`functions`,`server`,`server.mjs`)].find(e=>n(e));if(!p){console.log(`[prerender] No server entry found, skipping prerender`);return}let m=[l(t,`.output`,`public`),i].find(e=>n(e));if(!m){console.log(`[prerender] No output directory found, skipping prerender`);return}let h={routes:d.routes??[`/`],crawlLinks:d.crawlLinks??!0,ignore:d.ignore??[],failOnError:d.failOnError??!1,concurrency:d.concurrency??4,autoSubfolderIndex:d.autoSubfolderIndex??!0,retry:d.retry??3,retryDelay:d.retryDelay??500},g=`http://localhost:${f}`,_=y(p),v=p;if(_){let e=l(c(p),`main.mjs`);if(!n(e)){console.error(`[prerender] Netlify handler detected but main.mjs not found`);return}v=b(e,f,t),console.log(`[prerender] Netlify handler detected — using wrapper`)}{let e=[p,l(c(p),`main.mjs`)].filter(e=>n(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&&(s(n,e),console.log(`[prerender] Patched ${u(t,n)}: removed HTML asset entries`))}}console.log(`[prerender] Starting prerender with server: ${u(t,v)}`);let{spawn:S}=await import(`node:child_process`),C;try{C=S(`node`,[v],{env:{...process.env,PORT:String(f),NITRO_PORT:String(f),HOST:`127.0.0.1`,NITRO_HOST:`127.0.0.1`,NODE_ENV:`production`},stdio:[`ignore`,`pipe`,`pipe`]}),C.stdout?.on(`data`,e=>{let t=e.toString().trim();t&&console.log(`[prerender:server] ${t}`)}),C.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(`${g}/`);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 ${g}`)}catch(e){C?.kill(`SIGKILL`),console.error(`[prerender] Failed to start server:`,e.message);return}let w=new Set,T=[...h.routes],E=[],D=[];function O(e){for(let t of h.ignore)if(typeof t==`string`&&e===t||typeof t==`string`&&t.endsWith(`/**`)&&e.startsWith(t.slice(0,-2)))return!0;return!1}try{for(;T.length>0;){let e=T.splice(0,h.concurrency);await Promise.all(e.map(async e=>{let t=e.endsWith(`/`)&&e!==`/`?e.slice(0,-1):e;if(w.has(t)||(w.add(t),O(t)))return;let n=null;for(let e=1;e<=h.retry;e++)try{let e=await fetch(`${g}${t}`);n={html:await e.text(),status:e.status};break}catch{e<h.retry&&await new Promise(e=>setTimeout(e,h.retryDelay))}if(!n){D.push({route:t,error:`Failed after ${h.retry} attempts`});return}if(n.status>=400){D.push({route:t,error:`Returned ${n.status}`});return}let i=h.autoSubfolderIndex?l(t,`index.html`):`${t}.html`,a=l(m,i);if(r(c(a),{recursive:!0}),s(a,n.html.replace(`<!DOCTYPE html>`,`<!DOCTYPE html>
30
+ `),i}function x(e){let t=[],n=/<a\s[^>]*href=["']([^"'#?]+)/gi,r=null;for(r=n.exec(e);r!==null;r=n.exec(e)){let e=r[1];e.startsWith(`/`)&&!e.startsWith(`//`)&&!e.startsWith(`/assets/`)&&!e.startsWith(`/islands/`)&&!e.startsWith(`/chunks/`)&&!e.startsWith(`/_`)&&!e.match(/\.\w{2,5}$/)&&t.push(e)}return[...new Set(t)]}async function S(t,i,d,f){let p=[l(t,`.netlify`,`functions-internal`,`server`,`server.mjs`),l(t,`.netlify`,`v1`,`functions`,`server`,`server.mjs`),l(t,`.output`,`server`,`index.mjs`)].find(e=>n(e));if(!p){console.log(`[prerender] No server entry found, skipping prerender`);return}let m=[l(t,`.output`,`public`),i].find(e=>n(e));if(!m){console.log(`[prerender] No output directory found, skipping prerender`);return}let h={routes:d.routes??[`/`],crawlLinks:d.crawlLinks??!0,ignore:d.ignore??[],failOnError:d.failOnError??!1,concurrency:d.concurrency??4,autoSubfolderIndex:d.autoSubfolderIndex??!0,retry:d.retry??3,retryDelay:d.retryDelay??500},g=`http://localhost:${f}`,_=y(p),v=p;if(_){let e=l(c(p),`main.mjs`);if(!n(e)){console.error(`[prerender] Netlify handler detected but main.mjs not found`);return}v=b(e,f,t),console.log(`[prerender] Netlify handler detected — using wrapper`)}{let e=[p,l(c(p),`main.mjs`)].filter(e=>n(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&&(s(n,e),console.log(`[prerender] Patched ${u(t,n)}: removed HTML asset entries`))}}console.log(`[prerender] Starting prerender with server: ${u(t,v)}`);let{spawn:S}=await import(`node:child_process`),C;try{C=S(`node`,[v],{env:{...process.env,PORT:String(f),NITRO_PORT:String(f),HOST:`127.0.0.1`,NITRO_HOST:`127.0.0.1`,NODE_ENV:`production`},stdio:[`ignore`,`pipe`,`pipe`]}),C.stdout?.on(`data`,e=>{let t=e.toString().trim();t&&console.log(`[prerender:server] ${t}`)}),C.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(`${g}/`);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 ${g}`)}catch(e){C?.kill(`SIGKILL`),console.error(`[prerender] Failed to start server:`,e.message);return}let w=new Set,T=[...h.routes],E=[],D=[];function O(e){for(let t of h.ignore)if(typeof t==`string`&&e===t||typeof t==`string`&&t.endsWith(`/**`)&&e.startsWith(t.slice(0,-2)))return!0;return!1}try{for(;T.length>0;){let e=T.splice(0,h.concurrency);await Promise.all(e.map(async e=>{let t=e.endsWith(`/`)&&e!==`/`?e.slice(0,-1):e;if(w.has(t)||(w.add(t),O(t)))return;let n=null;for(let e=1;e<=h.retry;e++)try{let e=await fetch(`${g}${t}`);n={html:await e.text(),status:e.status};break}catch{e<h.retry&&await new Promise(e=>setTimeout(e,h.retryDelay))}if(!n){D.push({route:t,error:`Failed after ${h.retry} attempts`});return}if(n.status>=400){D.push({route:t,error:`Returned ${n.status}`});return}let i=h.autoSubfolderIndex?l(t,`index.html`):`${t}.html`,a=l(m,i);if(r(c(a),{recursive:!0}),s(a,n.html.replace(`<!DOCTYPE html>`,`<!DOCTYPE html>
31
31
  <!-- SSG: prerendered at build time -->`)),E.push(t),console.log(`[prerender] ✅ ${t} → ${i}`),h.crawlLinks)for(let e of x(n.html)){let t=e.endsWith(`/`)&&e!==`/`?e.slice(0,-1):e;!w.has(t)&&!O(t)&&T.push(t)}}))}}finally{console.log(`[prerender] Shutting down server...`),C?.kill(`SIGKILL`)}if(console.log(`[prerender] Done: ${E.length} page(s) prerendered`+(D.length>0?`, ${D.length} error(s)`:``)),_){let e=l(c(p),`_prerender-server.mjs`);n(e)&&(o(e),console.log(`[prerender] Cleaned up wrapper script`))}if(E.length>0){let a=[i,l(t,`.netlify`,`functions-internal`,`server`,`public`),l(t,`.netlify`,`v1`,`functions`,`server`,`public`)].filter(e=>e!==m&&n(c(e)));for(let t of a)for(let i of E){let a=l(i,`index.html`),o=l(m,a),s=l(t,a);n(o)&&(r(c(s),{recursive:!0}),e(o,s))}a.length>0&&console.log(`[prerender] Copied prerendered HTML to ${a.length} additional output dir(s)`)}}export async function runPostBuild(e={}){let t=e.cwd??process.cwd(),r=l(t,`dist`),i=e.prerenderPort??13172;p(t),h(t,r);for(let e of[l(t,`.netlify`,`functions-internal`,`server`,`_ssr`,`ssr.mjs`),l(t,`.netlify`,`v1`,`functions`,`server`,`_ssr`,`ssr.mjs`),l(t,`.output`,`server`,`_ssr`,`ssr.mjs`)])n(e)&&(console.log(`[patch] Patching ${e}`),m(e,r,t));g(r),_(t,r),v(t),e.prerender!==!1&&await S(t,r,e.prerender??{},i),console.log(`[post-build] ✅ Complete`)}
@@ -6,7 +6,7 @@ export default pageRoutes;
6
6
  export default { loadPage, routes: [] };
7
7
  `}}function P(){return`export const islandManifest = { islands: {}, clientEntry: "", css: [] };
8
8
  export default islandManifest;
9
- `}function F(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={streaming:t.streaming??!0,pagesDir:e.pagesDir,layoutsDir:e.layoutsDir,isDev:e.isDev,...t.runtimeConfig};return`const config = ${JSON.stringify(n,null,2)};\nexport function useAvalonConfig() { return config; }\nexport default config;\n`}async function I(e){let{getAllLayoutDirs:t}=await import(`./module-discovery.js`),{relative:n}=await import(`node:path`),{stat:r}=await import(`node:fs/promises`),a=process.cwd(),o=await t(e.layoutsDir,e.modules,a),s=[],c=0;for(let{dir:t,prefix:l}of o){let o=i(t,`_layout.tsx`);try{if(!(await r(o)).isFile())continue}catch{continue}let u=n(a,o).replaceAll(`\\`,`/`),d=u.startsWith(`/`)?u:`/`+u,f=t.includes(`/shared/`)||l===`/`,p=f&&!e.modules?`RootLayout`:`Layout_${c}`;s.push({prefix:l,importPath:d,varName:p,isShared:f}),c++}let l=s.filter(e=>e.isShared),u=s.filter(e=>!e.isShared),d=s.map(e=>`import ${e.varName} from '${e.importPath}';`),f=u.sort((e,t)=>t.prefix.length-e.prefix.length).map(e=>{let t=e.prefix===`/`;return` { prefix: ${JSON.stringify(e.prefix)}, Layout: ${e.varName}, skipRoot: ${t} }`}),p=l.length>0?l[0].varName:`null`;return[`// Auto-generated by Avalon — do not edit`,`import { h } from 'preact';`,`import preactRenderToString from 'preact-render-to-string';`,`import { getUniversalCSSForHead } from '@useavalon/avalon/islands/universal-css-collector';`,`import { getUniversalHeadForInjection } from '@useavalon/avalon/islands/universal-head-collector';`,...d,``,`const RootLayoutComponent = ${p};`,``,`const moduleLayouts = [`,f.join(`,
9
+ `}function F(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={streaming:t.streaming??!0,pagesDir:e.pagesDir,layoutsDir:e.layoutsDir,isDev:e.isDev,...t.runtimeConfig};return`const config = ${JSON.stringify(n,null,2)};\nexport function useAvalonConfig() { return config; }\nexport default config;\n`}async function I(e){let{getAllLayoutDirs:t}=await import(`./module-discovery.js`),{relative:n,resolve:r}=await import(`node:path`),{stat:a}=await import(`node:fs/promises`),o=process.cwd(),s=await t(e.layoutsDir,e.modules,o),c=[],l=0,u=r(o,e.layoutsDir);for(let{dir:t,prefix:r}of s){let s=i(t,`_layout.tsx`);try{if(!(await a(s)).isFile())continue}catch{continue}let d=n(o,s).replaceAll(`\\`,`/`),f=d.startsWith(`/`)?d:`/`+d,p=t.startsWith(u),m=p&&!e.modules?`RootLayout`:`Layout_${l}`;c.push({prefix:r,importPath:f,varName:m,isShared:p}),l++}let d=c.filter(e=>e.isShared),f=c.filter(e=>!e.isShared),p=c.map(e=>`import ${e.varName} from '${e.importPath}';`),m=f.sort((e,t)=>t.prefix.length-e.prefix.length).map(e=>{let t=e.prefix===`/`;return` { prefix: ${JSON.stringify(e.prefix)}, Layout: ${e.varName}, skipRoot: ${t} }`}),h=d.length>0?d[0].varName:`null`;return[`// Auto-generated by Avalon — do not edit`,`import { h } from 'preact';`,`import preactRenderToString from 'preact-render-to-string';`,`import { getUniversalCSSForHead } from '@useavalon/avalon/islands/universal-css-collector';`,`import { getUniversalHeadForInjection } from '@useavalon/avalon/islands/universal-head-collector';`,...p,``,`const RootLayoutComponent = ${h};`,``,`const moduleLayouts = [`,m.join(`,
10
10
  `),`];`,``,`function getLayoutsForPath(pathname) {`,` for (const entry of moduleLayouts) {`,` if (entry.prefix === '/' ? pathname === '/' : pathname.startsWith(entry.prefix)) {`,` return entry;`,` }`,` }`,` return null;`,`}`,``,`function injectUniversalAssets(html) {`,` const universalCSS = getUniversalCSSForHead(true);`,` if (universalCSS && html.includes('</head>')) {`,` html = html.replace('</head>', universalCSS + '\\n</head>');`,` }`,` const universalHead = getUniversalHeadForInjection(true);`,` if (universalHead && html.includes('</head>')) {`,` html = html.replace('</head>', universalHead + '\\n</head>');`,` }`,` 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) {`,` 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>',`,` ].join('\\n');`,` } else {`,` const layoutProps = {`,` children: h('div', { 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 (!layoutEntry.skipRoot && RootLayoutComponent) {`,` const rootProps = {`,` children: h('div', { dangerouslySetInnerHTML: { __html: wrappedHtml } }),`,` frontmatter,`,` data: {},`,` route: routeInfo,`,` };`,` const rootResult = RootLayoutComponent(rootProps);`,` const resolvedRoot = rootResult instanceof Promise ? await rootResult : rootResult;`,` wrappedHtml = preactRenderToString(resolvedRoot);`,` }`,``,` html = '<!DOCTYPE html>\\n' + wrappedHtml;`,` }`,``,` if (injectAssets) {`,` html = injectAssets(html);`,` }`,` return injectUniversalAssets(html);`,`}`,``,`export default { wrapWithLayouts };`,``].join(`
11
11
  `)}function L(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 ?? [])`,` .map(attr => '<link rel="stylesheet" href="' + attr.href + '">')`,` .join('\\n');`,` const jsPreloads = (clientAssets?.js ?? [])`,` .map(attr => '<link rel="modulepreload" href="' + attr.href + '">')`,` .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>')) {`,` html = html.replace('</head>', cssLinks + '\\n' + jsPreloads + '\\n</head>');`,` }`,` if (html.includes('</body>')) {`,` html = html.replace('</body>', entryScript + '\\n</body>');`,` }`,` return html;`,`}`,``,`export { clientAssets };`,`export default { injectAssets, clientAssets };`,``].join(`
12
12
  `)}function R(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});`)}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,``,`// Pre-register framework integrations for SSR`,...r,``,`// Register built-in custom hydration directives (on:delay, on:scroll, etc.)`,`registerBuiltinDirectives();`,``,`export default createNitroRenderer({`,` avalonConfig,`,` isDev: avalonConfig.isDev,`,` resolvePageRoute: async (pathname) => {`,` const mod = loadPage(pathname);`,` if (!mod || !('default' in mod)) return null;`,` return { filePath: '[virtual:' + pathname + ']', pattern: pathname, params: {} };`,` },`,` loadPageModule: async (filePath) => {`,` const match = filePath.match(/^\\[virtual:(.+)\\]$/);`,` const pathname = match ? match[1] : filePath;`,` const mod = loadPage(pathname);`,` if (mod) return mod;`,` return { default: () => null, metadata: { title: 'Avalon' } };`,` },`,` wrapWithLayouts: (pageHtml, pageModule, context) =>`,` wrapWithLayouts(pageHtml, pageModule, context, injectAssets),`,`});`,``].join(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useavalon/avalon",
3
- "version": "0.1.50",
3
+ "version": "0.1.52",
4
4
  "description": "Multi-framework islands architecture for the modern web",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -132,7 +132,7 @@
132
132
  }
133
133
  },
134
134
  "dependencies": {
135
- "@useavalon/core": "workspace:^",
135
+ "@useavalon/core": "^0.1.7",
136
136
  "@mdx-js/rollup": "^3.0.0",
137
137
  "h3": "^2.0.1-rc.16",
138
138
  "marked": "^17.0.4",