@devlusoft/devix 0.4.1-beta.11 → 0.4.1-beta.13

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.
package/dist/cli/build.js CHANGED
@@ -1,4 +1,4 @@
1
- import{writeFileSync as wt}from"node:fs";import{resolve as Tt}from"node:path";import{build as O}from"vite";import{mergeConfig as gt}from"vite";import ht from"@vitejs/plugin-react";import{fileURLToPath as xt}from"node:url";import{dirname as yt,resolve as l}from"node:path";function I({cssUrls:t}){return`
1
+ import{writeFileSync as Ct}from"node:fs";import{resolve as At}from"node:path";import{build as F}from"vite";import{mergeConfig as vt}from"vite";import Rt from"@vitejs/plugin-react";import{fileURLToPath as _t}from"node:url";import{dirname as Pt,resolve as l}from"node:path";import{createRequire as Et}from"node:module";function L({cssUrls:t}){return`
2
2
  ${t.map(r=>`import '${r}'`).join(`
3
3
  `)}
4
4
  import "@vitejs/plugin-react/preamble"
@@ -62,7 +62,7 @@ if (!window.__DEVIX__) {
62
62
  )
63
63
  }
64
64
  }
65
- `}function L({pagesDir:t,matcherPath:e}){return`
65
+ `}function j({pagesDir:t,matcherPath:e}){return`
66
66
  import React from 'react'
67
67
  import { createMatcher } from '${e}'
68
68
  const pageFiles = import.meta.glob(['/${t}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])
@@ -113,7 +113,7 @@ export function runLoader(url, request, options) {
113
113
  export function getStaticRoutes() {
114
114
  return _getStaticRoutes(_glob)
115
115
  }
116
- `}function j({apiPath:t,appDir:e}){return`
116
+ `}function H({apiPath:t,appDir:e}){return`
117
117
  import { handleApiRequest as _handleApiRequest } from '${t}'
118
118
 
119
119
  const _routes = import.meta.glob(['/${e}/api/**/*.ts', '!**/middleware.ts'])
@@ -128,14 +128,14 @@ const _glob = {
128
128
  export function handleApiRequest(url, request) {
129
129
  return _handleApiRequest(url, request, _glob)
130
130
  }
131
- `}function v(t){return t.replace(/\.(tsx|ts|jsx|js)$/,"").replace(/\(.*?\)\//g,"").replace(/^index$|\/index$/,"").replace(/\[([^\]]+)]/g,":$1")||"/"}var rt=null;function _(){rt=null}function H(t,e){let r=t.slice(e.length+1).replace(/\\/g,"/"),i=v(r);return i==="/"?"/api":`/api/${i}`.replace("/api//","/api/")}var nt=null;function E(){nt=null}function k(){return`
131
+ `}function _(t){return t.replace(/\.(tsx|ts|jsx|js)$/,"").replace(/\(.*?\)\//g,"").replace(/^index$|\/index$/,"").replace(/\[([^\]]+)]/g,":$1")||"/"}var st=null;function P(){st=null}function k(t,e){let r=t.slice(e.length+1).replace(/\\/g,"/"),i=_(r);return i==="/"?"/api":`/api/${i}`.replace("/api//","/api/")}var at=null;function E(){at=null}function N(){return`
132
132
  export {RouterContext} from '@devlusoft/devix/runtime/context'
133
- `}import{readFileSync as at,readdirSync as ct,statSync as lt}from"node:fs";import{join as w,relative as ut}from"node:path";var ot=/export\s+(?:const|async\s+function|function)\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g;function it(t){return t.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}function N(t){let e=new Set;for(let r of it(t).matchAll(ot))e.add(r[1]);return[...e]}function st(t,e){return"_api_"+t.slice(`${e}/`.length).replace(/\.(ts|tsx)$/,"").replace(/[^a-zA-Z0-9]/g,"_")}function V(t,e,r){return{filePath:t,urlPattern:H(t,e),identifier:st(t,e),methods:r}}function P(t,e){if(t.length===0)return`// auto-generado por devix \u2014 no editar
133
+ `}import{readFileSync as pt,readdirSync as dt,statSync as mt}from"node:fs";import{join as T,relative as ft}from"node:path";var ct=/export\s+(?:const|async\s+function|function)\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g;function lt(t){return t.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}function q(t){let e=new Set;for(let r of lt(t).matchAll(ct))e.add(r[1]);return[...e]}function ut(t,e){return"_api_"+t.slice(`${e}/`.length).replace(/\.(ts|tsx)$/,"").replace(/[^a-zA-Z0-9]/g,"_")}function V(t,e,r){return{filePath:t,urlPattern:k(t,e),identifier:ut(t,e),methods:r}}function w(t,e){if(t.length===0)return`// auto-generado por devix \u2014 no editar
134
134
  declare module '@devlusoft/devix' {
135
135
  interface ApiRoutes {}
136
136
  }
137
- `;let r=t.map(o=>{let p="../"+o.filePath.replace(/\.(ts|tsx)$/,"");return`import type * as ${o.identifier} from '${p}'`}).join(`
138
- `),i=t.flatMap(o=>o.methods.map(p=>` '${p} ${o.urlPattern}': InferRoute<(typeof ${o.identifier})['${p}']>`)).join(`
137
+ `;let r=t.map(n=>{let p="../"+n.filePath.replace(/\.(ts|tsx)$/,"");return`import type * as ${n.identifier} from '${p}'`}).join(`
138
+ `),i=t.flatMap(n=>n.methods.map(p=>` '${p} ${n.urlPattern}': InferRoute<(typeof ${n.identifier})['${p}']>`)).join(`
139
139
  `);return`// auto-generado por devix \u2014 no editar
140
140
  ${r}
141
141
 
@@ -157,19 +157,19 @@ declare module '@devlusoft/devix' {
157
157
  ${i}
158
158
  }
159
159
  }
160
- `}function q(t,e){let r=[];for(let i of ct(t)){let o=w(t,i);lt(o).isDirectory()?r.push(...q(o,e)):/\.(ts|tsx)$/.test(i)&&r.push(ut(e,o).replace(/\\/g,"/"))}return r}function T(t,e){let r=w(e,t,"api"),i;try{i=q(r,e)}catch{return[]}return i.filter(o=>!o.endsWith("middleware.ts")&&!o.endsWith("middleware.tsx")).flatMap(o=>{try{let p=at(w(e,o),"utf-8"),h=N(p);return h.length===0?[]:[V(o,`${t}/api`,h)]}catch{return[]}})}import{mkdirSync as pt,readFileSync as dt,writeFileSync as mt,existsSync as ft}from"node:fs";import{join as W}from"node:path";function $(t,e){let r=W(e,".devix"),i=W(r,"routes.d.ts");return pt(r,{recursive:!0}),ft(i)&&dt(i,"utf-8")===t?!1:(mt(i,t,"utf-8"),!0)}import{parseSync as Rt}from"oxc-parser";function B({routesPath:t,envPath:e}){return`
160
+ `}function W(t,e){let r=[];for(let i of dt(t)){let n=T(t,i);mt(n).isDirectory()?r.push(...W(n,e)):/\.(ts|tsx)$/.test(i)&&r.push(ft(e,n).replace(/\\/g,"/"))}return r}function S(t,e){let r=T(e,t,"api"),i;try{i=W(r,e)}catch{return[]}return i.filter(n=>!n.endsWith("middleware.ts")&&!n.endsWith("middleware.tsx")).flatMap(n=>{try{let p=pt(T(e,n),"utf-8"),h=q(p);return h.length===0?[]:[V(n,`${t}/api`,h)]}catch{return[]}})}import{mkdirSync as gt,readFileSync as ht,writeFileSync as xt,existsSync as yt}from"node:fs";import{join as B}from"node:path";function $(t,e){let r=B(e,".devix"),i=B(r,"routes.d.ts");return gt(r,{recursive:!0}),yt(i)&&ht(i,"utf-8")===t?!1:(xt(i,t,"utf-8"),!0)}import{parseSync as wt}from"oxc-parser";function J({routesPath:t,envPath:e,honoServerPath:r,honoServerStaticPath:i,honoPath:n}){return`
161
161
  import { readFileSync } from 'node:fs'
162
- import { serve } from '@hono/node-server'
163
- import { serveStatic } from '@hono/node-server/serve-static'
164
- import { Hono } from 'hono'
165
- import { resolve, join, dirname } from 'node:path'
166
- import { fileURLToPath, pathToFileURL } from 'node:url'
162
+ import { serve } from '${r}'
163
+ import { serveStatic } from '${i}'
164
+ import { Hono } from '${n}'
165
+ import { resolve, join, dirname } from 'node:path'
166
+ import { pathToFileURL } from 'node:url'
167
167
  import { registerApiRoutes, registerSsrRoute } from '${t}'
168
168
  import { loadDotenv } from '${e}'
169
169
 
170
170
  loadDotenv('production')
171
171
 
172
- const __dir = dirname(fileURLToPath(import.meta.url))
172
+ const __dir = dirname(process.argv[1])
173
173
 
174
174
  let renderModule, apiModule, manifest, runtimeConfig
175
175
 
@@ -228,5 +228,5 @@ import { readFileSync } from 'node:fs'
228
228
 
229
229
  process.on('SIGTERM', () => server.close())
230
230
  process.on('SIGINT', () => server.close())
231
- `}var f=yt(xt(import.meta.url)),S="virtual:devix/entry-client",D="virtual:devix/client-routes",C="virtual:devix/render",A="virtual:devix/api",b="virtual:devix/context",M="virtual:devix/server-entry",J=new Set(["loader","guard","generateStaticParams","headers"]);function X(t){let e=t.appDir??"app",r=`${e}/pages`,i=(t.css??[]).map(n=>n.startsWith("/")?n:`/${n.replace(/^\.\//,"")}`),o=l(f,"../server/render.js").replace(/\\/g,"/"),p=l(f,"../server/api.js").replace(/\\/g,"/"),h=l(f,"../runtime/client-router.js").replace(/\\/g,"/"),Z=l(f,"../server/routes.js").replace(/\\/g,"/"),K=l(f,"../utils/env.js").replace(/\\/g,"/"),Q={name:"devix",enforce:"pre",resolveId(n){if(n===S)return`\0${S}`;if(n===D)return`\0${D}`;if(n===C)return`\0${C}`;if(n===A)return`\0${A}`;if(n===b)return`\0${b}`;if(n===M)return`\0${M}`},load(n){if(n===`\0${S}`)return I({cssUrls:i});if(n===`\0${D}`)return L({pagesDir:r,matcherPath:h});if(n===`\0${C}`)return U({pagesDir:r,renderPath:o});if(n===`\0${A}`)return j({apiPath:p,appDir:e});if(n===`\0${b}`)return k();if(n===`\0${M}`)return B({routesPath:Z,envPath:K})},transform(n,c,d){if(d?.ssr)return;let s=l(process.cwd(),r);if(!c.startsWith(s))return;let et=Rt(c,n,{sourceType:"module"}),m=[];for(let a of et.program.body){if(a.type!=="ExportNamedDeclaration"||!a.declaration)continue;let u=a.declaration;if(u.type==="FunctionDeclaration"&&u.id&&J.has(u.id.name)&&m.push({start:a.start,end:a.end,name:u.id.name}),u.type==="VariableDeclaration"){let y=new Set;for(let R of u.declarations)R.id.type==="Identifier"&&J.has(R.id.name)&&(y.has(a.start)||(y.add(a.start),m.push({start:a.start,end:a.end,name:R.id.name})))}}if(m.length===0)return;m.sort((a,u)=>u.start-a.start);let x=n;for(let{start:a,end:u,name:y}of m)x=x.slice(0,a)+`export const ${y} = undefined`+x.slice(u);return{code:x,map:null}},buildStart(){let n=process.cwd(),c=T(e,n);$(P(c,`${e}/api`),n)},configureServer(n){let c=process.cwd(),d=()=>{let s=T(e,c);$(P(s,`${e}/api`),c)};n.watcher.add(l(c,"devix.config.ts")),n.watcher.on("change",s=>{s===l(c,"devix.config.ts")&&(console.log("[devix] Config changed, restarting..."),process.exit(75))}),n.watcher.on("add",s=>{s.startsWith(l(c,r))&&_(),s.includes(`${e}/api`)&&(E(),d())}),n.watcher.on("unlink",s=>{s.startsWith(l(c,r))&&_(),s.includes(`${e}/api`)&&(E(),d())}),n.watcher.on("change",s=>{s.includes(`${e}/api`)&&!s.endsWith("middleware.ts")&&d()})}},tt={plugins:[ht(),Q],publicDir:l(process.cwd(),t.publicDir??"public"),ssr:{noExternal:["@devlusoft/devix"]},...t.envPrefix?{envPrefix:t.envPrefix}:{}};return gt(tt,t.vite??{})}function G(t){if(typeof t=="number")return t;let e=t.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h)?$/);if(!e)throw new Error(`[devix] Invalid duration: "${t}". Use a number (ms) or a string like "5s", "2m", "500ms".`);let r=parseFloat(e[1]);switch(e[2]){case"h":return r*36e5;case"m":return r*6e4;case"s":return r*1e3;default:return r}}import{build as vt}from"esbuild";import{join as Y}from"node:path";import{unlinkSync as _t,writeFileSync as Et}from"node:fs";import{pathToFileURL as Pt}from"node:url";async function z(t){let e=await vt({entryPoints:[Y(t,"devix.config.ts")],bundle:!0,write:!1,format:"esm",platform:"node",packages:"external"}),r=Y(t,`.devix-config-${Date.now()}.mjs`);Et(r,e.outputFiles[0].text);try{return(await import(Pt(r).href)).default}finally{_t(r)}}var g=await z(process.cwd()),F=X(g);await O({...F,configFile:!1,build:{outDir:"dist/client",manifest:!0,rolldownOptions:{input:"virtual:devix/entry-client"}}});await O({...F,configFile:!1,build:{ssr:!0,outDir:"dist/server",copyPublicDir:!1,rolldownOptions:{input:{render:"virtual:devix/render",api:"virtual:devix/api"}}}});await O({...F,configFile:!1,ssr:{noExternal:["hono","@hono/node-server","@devlusoft/devix"]},build:{ssr:!0,outDir:"dist/server",copyPublicDir:!1,rolldownOptions:{input:{index:"virtual:devix/server-entry"}}}});var $t={port:g.port??3e3,host:g.host??!1,loaderTimeout:G(g.loaderTimeout??1e4),output:g.output??"server"};wt(Tt(process.cwd(),"dist/devix.config.json"),JSON.stringify($t,null,2),"utf-8");
231
+ `}var f=Pt(_t(import.meta.url)),D="virtual:devix/entry-client",C="virtual:devix/client-routes",A="virtual:devix/render",b="virtual:devix/api",O="virtual:devix/context",M="virtual:devix/server-entry",X=new Set(["loader","guard","generateStaticParams","headers"]);function G(t){let e=t.appDir??"app",r=`${e}/pages`,i=(t.css??[]).map(o=>o.startsWith("/")?o:`/${o.replace(/^\.\//,"")}`),n=l(f,"../server/render.js").replace(/\\/g,"/"),p=l(f,"../server/api.js").replace(/\\/g,"/"),h=l(f,"../runtime/client-router.js").replace(/\\/g,"/"),K=l(f,"../server/routes.js").replace(/\\/g,"/"),Q=l(f,"../utils/env.js").replace(/\\/g,"/"),v=Et(import.meta.url),tt=v.resolve("@hono/node-server").replace(/\\/g,"/"),et=v.resolve("@hono/node-server/serve-static").replace(/\\/g,"/"),rt=v.resolve("hono").replace(/\\/g,"/"),ot={name:"devix",enforce:"pre",resolveId(o){if(o===D)return`\0${D}`;if(o===C)return`\0${C}`;if(o===A)return`\0${A}`;if(o===b)return`\0${b}`;if(o===O)return`\0${O}`;if(o===M)return`\0${M}`},load(o){if(o===`\0${D}`)return L({cssUrls:i});if(o===`\0${C}`)return j({pagesDir:r,matcherPath:h});if(o===`\0${A}`)return U({pagesDir:r,renderPath:n});if(o===`\0${b}`)return H({apiPath:p,appDir:e});if(o===`\0${O}`)return N();if(o===`\0${M}`)return J({routesPath:K,envPath:Q,honoServerPath:tt,honoServerStaticPath:et,honoPath:rt})},transform(o,c,d){if(d?.ssr)return;let s=l(process.cwd(),r);if(!c.startsWith(s))return;let it=wt(c,o,{sourceType:"module"}),m=[];for(let a of it.program.body){if(a.type!=="ExportNamedDeclaration"||!a.declaration)continue;let u=a.declaration;if(u.type==="FunctionDeclaration"&&u.id&&X.has(u.id.name)&&m.push({start:a.start,end:a.end,name:u.id.name}),u.type==="VariableDeclaration"){let y=new Set;for(let R of u.declarations)R.id.type==="Identifier"&&X.has(R.id.name)&&(y.has(a.start)||(y.add(a.start),m.push({start:a.start,end:a.end,name:R.id.name})))}}if(m.length===0)return;m.sort((a,u)=>u.start-a.start);let x=o;for(let{start:a,end:u,name:y}of m)x=x.slice(0,a)+`export const ${y} = undefined`+x.slice(u);return{code:x,map:null}},buildStart(){let o=process.cwd(),c=S(e,o);$(w(c,`${e}/api`),o)},configureServer(o){let c=process.cwd(),d=()=>{let s=S(e,c);$(w(s,`${e}/api`),c)};o.watcher.add(l(c,"devix.config.ts")),o.watcher.on("change",s=>{s===l(c,"devix.config.ts")&&(console.log("[devix] Config changed, restarting..."),process.exit(75))}),o.watcher.on("add",s=>{s.startsWith(l(c,r))&&P(),s.includes(`${e}/api`)&&(E(),d())}),o.watcher.on("unlink",s=>{s.startsWith(l(c,r))&&P(),s.includes(`${e}/api`)&&(E(),d())}),o.watcher.on("change",s=>{s.includes(`${e}/api`)&&!s.endsWith("middleware.ts")&&d()})}},nt={plugins:[Rt(),ot],publicDir:l(process.cwd(),t.publicDir??"public"),ssr:{noExternal:["@devlusoft/devix"]},...t.envPrefix?{envPrefix:t.envPrefix}:{}};return vt(nt,t.vite??{})}function Y(t){if(typeof t=="number")return t;let e=t.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h)?$/);if(!e)throw new Error(`[devix] Invalid duration: "${t}". Use a number (ms) or a string like "5s", "2m", "500ms".`);let r=parseFloat(e[1]);switch(e[2]){case"h":return r*36e5;case"m":return r*6e4;case"s":return r*1e3;default:return r}}import{build as Tt}from"esbuild";import{join as z}from"node:path";import{unlinkSync as St,writeFileSync as $t}from"node:fs";import{pathToFileURL as Dt}from"node:url";async function Z(t){let e=await Tt({entryPoints:[z(t,"devix.config.ts")],bundle:!0,write:!1,format:"esm",platform:"node",packages:"external"}),r=z(t,`.devix-config-${Date.now()}.mjs`);$t(r,e.outputFiles[0].text);try{return(await import(Dt(r).href)).default}finally{St(r)}}var g=await Z(process.cwd()),I=G(g);await F({...I,configFile:!1,build:{outDir:"dist/client",manifest:!0,rolldownOptions:{input:"virtual:devix/entry-client"}}});await F({...I,configFile:!1,build:{ssr:!0,outDir:"dist/server",copyPublicDir:!1,rolldownOptions:{input:{render:"virtual:devix/render",api:"virtual:devix/api"}}}});await F({...I,configFile:!1,build:{ssr:!0,outDir:"dist/server",emptyOutDir:!1,copyPublicDir:!1,rolldownOptions:{input:{index:"virtual:devix/server-entry"}}}});var bt={port:g.port??3e3,host:g.host??!1,loaderTimeout:Y(g.loaderTimeout??1e4),output:g.output??"server"};Ct(At(process.cwd(),"dist/devix.config.json"),JSON.stringify(bt,null,2),"utf-8");
232
232
  //# sourceMappingURL=build.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cli/build.ts", "../../src/vite/index.ts", "../../src/vite/codegen/entry-client.ts", "../../src/vite/codegen/client-routes.ts", "../../src/vite/codegen/render.ts", "../../src/vite/codegen/api.ts", "../../src/utils/patterns.ts", "../../src/server/pages-router.ts", "../../src/server/api-router.ts", "../../src/vite/codegen/context.ts", "../../src/vite/codegen/scan-api.ts", "../../src/vite/codegen/extract-methods.ts", "../../src/vite/codegen/routes-dts.ts", "../../src/vite/codegen/write-routes-dts.ts", "../../src/vite/codegen/server-entry.ts", "../../src/utils/duration.ts", "../../src/utils/load-config.ts"],
4
- "sourcesContent": ["import {writeFileSync} from 'node:fs'\nimport {resolve} from 'node:path'\nimport {build} from 'vite'\nimport {devix} from '../vite'\nimport {parseDuration} from '../utils/duration'\nimport {loadConfig} from \"../utils/load-config\";\n\nconst config = await loadConfig(process.cwd())\nconst baseConfig = devix(config)\n\nawait build({\n ...baseConfig,\n configFile: false,\n build: {\n outDir: 'dist/client',\n manifest: true,\n rolldownOptions: {\n input: 'virtual:devix/entry-client',\n },\n },\n})\n\nawait build({\n ...baseConfig,\n configFile: false,\n build: {\n ssr: true,\n outDir: 'dist/server',\n copyPublicDir: false,\n rolldownOptions: {\n input: {\n render: 'virtual:devix/render',\n api: 'virtual:devix/api',\n },\n },\n },\n})\n\nawait build({\n ...baseConfig,\n configFile: false,\n ssr: {\n noExternal: ['hono', '@hono/node-server', '@devlusoft/devix'],\n },\n build: {\n ssr: true,\n outDir: 'dist/server',\n copyPublicDir: false,\n rolldownOptions: {\n input: {index: 'virtual:devix/server-entry'},\n },\n },\n})\n\nconst runtimeConfig = {\n port: config.port ?? 3000,\n host: config.host ?? false,\n loaderTimeout: parseDuration(config.loaderTimeout ?? 10_000),\n output: config.output ?? 'server',\n}\n\nwriteFileSync(\n resolve(process.cwd(), 'dist/devix.config.json'),\n JSON.stringify(runtimeConfig, null, 2),\n 'utf-8'\n)\n\n\nexport {}", "import { UserConfig, Plugin, mergeConfig } from 'vite'\nimport type { DevixConfig } from '../config'\nimport react from '@vitejs/plugin-react'\nimport { fileURLToPath } from 'node:url'\nimport { dirname, resolve } from 'node:path'\nimport { generateEntryClient } from './codegen/entry-client'\nimport { generateClientRoutes } from './codegen/client-routes'\nimport { generateRender } from './codegen/render'\nimport { generateApi } from './codegen/api'\nimport { invalidatePagesCache } from \"../server/pages-router\";\nimport { invalidateApiCache } from \"../server/api-router\";\nimport { generateContext } from \"./codegen/context\";\nimport { scanApiFiles } from \"./codegen/scan-api\";\nimport { generateRoutesDts } from \"./codegen/routes-dts\";\nimport { writeRoutesDts } from \"./codegen/write-routes-dts\";\nimport { parseSync } from 'oxc-parser'\nimport {generateServerEntry} from \"./codegen/server-entry\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nconst VIRTUAL_ENTRY_CLIENT = 'virtual:devix/entry-client'\nconst VIRTUAL_CLIENT_ROUTES = 'virtual:devix/client-routes'\nconst VIRTUAL_RENDER = 'virtual:devix/render'\nconst VIRTUAL_API = 'virtual:devix/api'\nconst VIRTUAL_CONTEXT = 'virtual:devix/context'\nconst VIRTUAL_SERVER_ENTRY = 'virtual:devix/server-entry'\n\nconst SERVER_EXPORTS = new Set(['loader', 'guard', 'generateStaticParams', 'headers'])\n\nexport function devix(config: DevixConfig): UserConfig {\n const appDir = config.appDir ?? 'app'\n const pagesDir = `${appDir}/pages`\n const cssUrls = (config.css ?? []).map(u => u.startsWith('/') ? u : `/${u.replace(/^\\.\\//, '')}`)\n\n const renderPath = resolve(__dirname, '../server/render.js').replace(/\\\\/g, '/')\n const apiPath = resolve(__dirname, '../server/api.js').replace(/\\\\/g, '/')\n const matcherPath = resolve(__dirname, '../runtime/client-router.js').replace(/\\\\/g, '/')\n const routesPath = resolve(__dirname, '../server/routes.js').replace(/\\\\/g, '/')\n const envPath = resolve(__dirname, '../utils/env.js').replace(/\\\\/g, '/')\n\n const virtualPlugin: Plugin = {\n name: 'devix',\n enforce: 'pre',\n\n resolveId(id) {\n if (id === VIRTUAL_ENTRY_CLIENT) return `\\0${VIRTUAL_ENTRY_CLIENT}`\n if (id === VIRTUAL_CLIENT_ROUTES) return `\\0${VIRTUAL_CLIENT_ROUTES}`\n if (id === VIRTUAL_RENDER) return `\\0${VIRTUAL_RENDER}`\n if (id === VIRTUAL_API) return `\\0${VIRTUAL_API}`\n if (id === VIRTUAL_CONTEXT) return `\\0${VIRTUAL_CONTEXT}`\n if (id === VIRTUAL_SERVER_ENTRY) return `\\0${VIRTUAL_SERVER_ENTRY}`\n },\n\n load(id) {\n if (id === `\\0${VIRTUAL_ENTRY_CLIENT}`)\n return generateEntryClient({ cssUrls })\n if (id === `\\0${VIRTUAL_CLIENT_ROUTES}`)\n return generateClientRoutes({ pagesDir, matcherPath })\n if (id === `\\0${VIRTUAL_RENDER}`)\n return generateRender({ pagesDir, renderPath })\n if (id === `\\0${VIRTUAL_API}`)\n return generateApi({ apiPath, appDir })\n if (id === `\\0${VIRTUAL_CONTEXT}`)\n return generateContext()\n if (id === `\\0${VIRTUAL_SERVER_ENTRY}`)\n return generateServerEntry({ routesPath, envPath })\n },\n\n\n transform(code, id, options) {\n if (options?.ssr) return\n\n const resolvedPagesDir = resolve(process.cwd(), pagesDir)\n if (!id.startsWith(resolvedPagesDir)) return\n\n const ast = parseSync(id, code, { sourceType: 'module' })\n\n const replacements: { start: number; end: number; name: string }[] = []\n\n for (const node of ast.program.body) {\n if (node.type !== 'ExportNamedDeclaration' || !node.declaration) continue\n\n const decl = node.declaration\n\n if (decl.type === 'FunctionDeclaration' && decl.id && SERVER_EXPORTS.has(decl.id.name)) {\n replacements.push({ start: node.start, end: node.end, name: decl.id.name })\n }\n\n if (decl.type === 'VariableDeclaration') {\n const seen = new Set<number>()\n for (const declarator of decl.declarations) {\n if (declarator.id.type === 'Identifier' && SERVER_EXPORTS.has(declarator.id.name)) {\n if (!seen.has(node.start)) {\n seen.add(node.start)\n replacements.push({ start: node.start, end: node.end, name: declarator.id.name })\n }\n }\n }\n }\n }\n\n if (replacements.length === 0) return\n\n replacements.sort((a, b) => b.start - a.start)\n\n let result = code\n for (const { start, end, name } of replacements) {\n result = result.slice(0, start) + `export const ${name} = undefined` + result.slice(end)\n }\n\n return { code: result, map: null }\n },\n\n buildStart() {\n const root = process.cwd()\n const entries = scanApiFiles(appDir, root)\n writeRoutesDts(generateRoutesDts(entries, `${appDir}/api`), root)\n },\n\n configureServer(server) {\n const root = process.cwd()\n\n const regenerateDts = () => {\n const entries = scanApiFiles(appDir, root)\n writeRoutesDts(generateRoutesDts(entries, `${appDir}/api`), root)\n }\n\n server.watcher.add(resolve(root, 'devix.config.ts'))\n server.watcher.on('change', (file) => {\n if (file === resolve(root, 'devix.config.ts')) {\n console.log('[devix] Config changed, restarting...')\n process.exit(75)\n }\n })\n\n server.watcher.on('add', (file) => {\n if (file.startsWith(resolve(root, pagesDir))) invalidatePagesCache()\n if (file.includes(`${appDir}/api`)) { invalidateApiCache(); regenerateDts() }\n })\n server.watcher.on('unlink', (file) => {\n if (file.startsWith(resolve(root, pagesDir))) invalidatePagesCache()\n if (file.includes(`${appDir}/api`)) { invalidateApiCache(); regenerateDts() }\n })\n server.watcher.on('change', (file) => {\n if (file.includes(`${appDir}/api`) && !file.endsWith('middleware.ts')) {\n regenerateDts()\n }\n })\n },\n }\n\n const base: UserConfig = {\n plugins: [react(), virtualPlugin],\n publicDir: resolve(process.cwd(), config.publicDir ?? 'public'),\n ssr: { noExternal: ['@devlusoft/devix'] },\n ...(config.envPrefix ? { envPrefix: config.envPrefix } : {}),\n }\n\n return mergeConfig(base, config.vite ?? {})\n}", "interface EntryClientOptions {\n cssUrls: string[]\n}\n\nexport function generateEntryClient({ cssUrls }: EntryClientOptions): string {\n const cssImports = cssUrls.map(u => `import '${u}'`).join('\\n')\n\n return `\n${cssImports}\nimport \"@vitejs/plugin-react/preamble\"\nimport React from \"react\"\nimport {hydrateRoot, createRoot} from 'react-dom/client'\nimport {matchClientRoute, loadErrorPage, getDefaultErrorPage} from 'virtual:devix/client-routes'\nimport {RouterProvider} from '@devlusoft/devix'\n\nconst root = document.getElementById('devix-root')\n\nif (!window.__DEVIX__) {\n const ErrorPage = getDefaultErrorPage()\n createRoot(root).render(React.createElement(ErrorPage, {statusCode: 500, message: 'Server error'}))\n} else {\n const {metadata, viewport, clientEntry} = window.__DEVIX__\n const loaderData = window.__LOADER_DATA__\n const layoutsData = window.__LAYOUTS_DATA__ ?? []\n\n const matched = matchClientRoute(window.location.pathname)\n\n if (matched) {\n const [pageMod, ...layoutMods] = await Promise.all([\n matched.load(),\n ...matched.loadLayouts.map(l => l()),\n ])\n hydrateRoot(\n root,\n React.createElement(RouterProvider, {\n clientEntry,\n initialData: loaderData,\n initialParams: matched.params,\n initialPage: pageMod.default,\n initialLayouts: layoutMods.map(m => m.default),\n initialLayoutsData: layoutsData,\n initialMeta: metadata,\n initialViewport: viewport,\n })\n )\n\n if (window.location.hash) { \n const id = window.location.hash.slice(1) \n const scrollBehavior = getComputedStyle(document.documentElement).scrollBehavior \n requestAnimationFrame(() => { \n document.getElementById(id)?.scrollIntoView({ behavior: scrollBehavior }) \n }) \n } \n } else {\n const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()\n createRoot(root).render(\n React.createElement(RouterProvider, {\n clientEntry,\n initialData: null,\n initialParams: {},\n initialPage: () => null,\n initialLayouts: [],\n initialLayoutsData: [],\n initialMeta: null,\n initialError: {statusCode: 404, message: 'Not found'},\n initialErrorPage: ErrorPage,\n })\n )\n }\n}\n`\n}", "interface ClientRoutesOptions {\n pagesDir: string\n matcherPath: string\n}\n\nexport function generateClientRoutes({pagesDir, matcherPath}: ClientRoutesOptions) {\n return `\nimport React from 'react'\nimport { createMatcher } from '${matcherPath}'\nconst pageFiles = import.meta.glob(['/${pagesDir}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])\nconst layoutFiles = import.meta.glob('/${pagesDir}/**/layout.tsx')\nconst errorFiles = import.meta.glob('/${pagesDir}/**/error.tsx')\n\nexport const matchClientRoute = createMatcher(pageFiles, layoutFiles)\n\nexport async function loadErrorPage() {\n const key = Object.keys(errorFiles)[0]\n if (!key) return null\n const mod = await errorFiles[key]()\n return mod?.default ?? null\n}\n\nexport function getDefaultErrorPage() {\n return function DefaultError({ statusCode, message }) {\n return React.createElement('main', {\n style: { minHeight: '100dvh', display: 'flex', flexDirection: 'column', \n alignItems: 'center', justifyContent: 'center', gap: '8px',\n fontFamily: 'system-ui, sans-serif' }\n },\n React.createElement('h1', {style: {fontSize: '4rem', fontWeight: 700}}, statusCode),\n React.createElement('p', {style: {color: '#666'}}, message ?? 'An unexpected error occurred'),\n )\n }\n}\n`\n}", "interface RenderOptions {\n pagesDir: string\n renderPath: string\n}\n\nexport function generateRender({pagesDir, renderPath}: RenderOptions): string {\n return `\nimport { render as _render, runLoader as _runLoader, getStaticRoutes as _getStaticRoutes } from '${renderPath}'\n\nconst _pages = import.meta.glob(['/${pagesDir}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])\nconst _layouts = import.meta.glob('/${pagesDir}/**/layout.tsx')\n\nconst _glob = {\n pages: _pages,\n layouts: _layouts,\n pagesDir: '/${pagesDir}',\n}\n\nexport function render(url, request, options) {\n return _render(url, request, _glob, options)\n}\n\nexport function runLoader(url, request, options) {\n return _runLoader(url, request, _glob, options)\n}\n\nexport function getStaticRoutes() {\n return _getStaticRoutes(_glob)\n}\n`\n}\n", "interface ApiOptions {\n apiPath: string\n appDir: string\n}\n\nexport function generateApi({apiPath, appDir}: ApiOptions): string {\n return `\nimport { handleApiRequest as _handleApiRequest } from '${apiPath}'\n\nconst _routes = import.meta.glob(['/${appDir}/api/**/*.ts', '!**/middleware.ts'])\nconst _middlewares = import.meta.glob('/${appDir}/api/**/middleware.ts')\n\nconst _glob = {\n routes: _routes,\n middlewares: _middlewares,\n apiDir: '/${appDir}/api',\n}\n\nexport function handleApiRequest(url, request) {\n return _handleApiRequest(url, request, _glob)\n}\n`\n}\n", "export function routePattern(rel: string): string {\n return rel\n .replace(/\\.(tsx|ts|jsx|js)$/, '')\n .replace(/\\(.*?\\)\\//g, '')\n .replace(/^index$|\\/index$/, '')\n .replace(/\\[([^\\]]+)]/g, ':$1')\n || '/'\n}", "import {routePattern} from \"../utils/patterns\";\n\nexport interface Page {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface Layout {\n dir: string\n key: string\n}\n\nexport interface PagesResult {\n pages: Page[]\n layouts: Layout[]\n}\n\nfunction keyToRoutePattern(key: string, pagesDir: string): string {\n const rel = key.slice(pagesDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === \"/\" ? \"/\" : `/${pattern}`\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: PagesResult | null = null\n\nexport function invalidatePagesCache() {\n cache = null\n}\n\nexport function buildPages(pageKeys: string[], layoutKeys: string[], pagesDir: string): PagesResult {\n if (cache) return cache\n\n const pages: Page[] = []\n const layouts: Layout[] = []\n\n for (const key of layoutKeys) {\n layouts.push({dir: keyToDir(key), key})\n }\n\n for (const key of pageKeys) {\n const pattern = keyToRoutePattern(key, pagesDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n pages.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n\n pages.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {pages, layouts}\n return cache\n}\n\nexport function collectLayoutChain(pageKey: string, layouts: Layout[]): Layout[] {\n const pageDir = keyToDir(pageKey)\n\n return layouts\n .filter(layout => pageDir.startsWith(layout.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchPage(pathname: string, pages: Page[]): {\n page: Page\n params: Record<string, string>\n} | null {\n for (const page of pages) {\n const match = pathname.match(page.regex)\n if (match) {\n const params: Record<string, string> = {}\n page.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {page, params}\n }\n }\n return null\n}\n", "import {routePattern} from \"../utils/patterns\";\n\nexport interface ApiRoute {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface ApiMiddleware {\n dir: string\n key: string\n}\n\nexport interface ApiResult {\n routes: ApiRoute[]\n middlewares: ApiMiddleware[]\n}\n\nexport function keyToRoutePattern(key: string, apiDir: string): string {\n const rel = key.slice(apiDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === '/' ? '/api' : `/api/${pattern}`.replace('/api//', '/api/')\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: ApiResult | null = null\n\nexport function invalidateApiCache() {\n cache = null\n}\n\nexport function buildRoutes(routeKeys: string[], middlewareKeys: string[], apiDir: string): ApiResult {\n if (cache) return cache\n\n const routes: ApiRoute[] = []\n const middlewares: ApiMiddleware[] = []\n\n for (const key of middlewareKeys) {\n middlewares.push({dir: keyToDir(key), key})\n }\n\n for (const key of routeKeys) {\n const pattern = keyToRoutePattern(key, apiDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n routes.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n routes.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {routes, middlewares}\n return cache\n}\n\nexport function collectMiddlewareChain(routeKey: string, middlewares: ApiMiddleware[]): ApiMiddleware[] {\n const routeDir = keyToDir(routeKey)\n\n return middlewares\n .filter(mw => routeDir.startsWith(mw.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchRoute(\n pathname: string,\n routes: ApiRoute[]\n): {route: ApiRoute; params: Record<string, string>} | null {\n for (const route of routes) {\n const match = pathname.match(route.regex)\n if (match) {\n const params: Record<string, string> = {}\n route.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {route, params}\n }\n }\n return null\n}\n", "export function generateContext(): string {\n return `\nexport {RouterContext} from '@devlusoft/devix/runtime/context'\n`\n}", "import {readFileSync, readdirSync, statSync} from 'node:fs'\nimport {join, relative} from 'node:path'\nimport {extractHttpMethods} from './extract-methods'\nimport {buildRouteEntry} from './routes-dts'\nimport type {RouteEntry} from './routes-dts'\n\nfunction walkDir(dir: string, root: string): string[] {\n const entries: string[] = []\n for (const name of readdirSync(dir)) {\n const full = join(dir, name)\n if (statSync(full).isDirectory()) {\n entries.push(...walkDir(full, root))\n } else if (/\\.(ts|tsx)$/.test(name)) {\n entries.push(relative(root, full).replace(/\\\\/g, '/'))\n }\n }\n return entries\n}\n\nexport function scanApiFiles(appDir: string, projectRoot: string): RouteEntry[] {\n const apiDir = join(projectRoot, appDir, 'api')\n\n let files: string[]\n try {\n files = walkDir(apiDir, projectRoot)\n } catch {\n return []\n }\n\n return files\n .filter(f => !f.endsWith('middleware.ts') && !f.endsWith('middleware.tsx'))\n .flatMap(filePath => {\n try {\n const content = readFileSync(join(projectRoot, filePath), 'utf-8')\n const methods = extractHttpMethods(content)\n if (methods.length === 0) return []\n return [buildRouteEntry(filePath, `${appDir}/api`, methods)]\n } catch {\n return []\n }\n })\n}\n", "const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'] as const\nexport type HttpMethod = (typeof HTTP_METHODS)[number]\n\nconst METHOD_EXPORT_RE = /export\\s+(?:const|async\\s+function|function)\\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b/g\n\nfunction stripComments(content: string): string {\n return content\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .replace(/\\/\\/.*$/gm, '')\n}\n\nexport function extractHttpMethods(content: string): HttpMethod[] {\n const found = new Set<HttpMethod>()\n for (const match of stripComments(content).matchAll(METHOD_EXPORT_RE)) {\n found.add(match[1] as HttpMethod)\n }\n return [...found]\n}\n", "import { keyToRoutePattern } from '../../server/api-router'\nimport type { HttpMethod } from './extract-methods'\n\nexport interface RouteEntry {\n filePath: string\n urlPattern: string\n identifier: string\n methods: HttpMethod[]\n}\n\nexport function filePathToIdentifier(filePath: string, apiDir: string): string {\n return '_api_' + filePath\n .slice(`${apiDir}/`.length)\n .replace(/\\.(ts|tsx)$/, '')\n .replace(/[^a-zA-Z0-9]/g, '_')\n}\n\nexport function buildRouteEntry(filePath: string, apiDir: string, methods: HttpMethod[]): RouteEntry {\n return {\n filePath,\n urlPattern: keyToRoutePattern(filePath, apiDir),\n identifier: filePathToIdentifier(filePath, apiDir),\n methods,\n }\n}\n\nexport function generateRoutesDts(entries: RouteEntry[], apiDir: string): string {\n if (entries.length === 0) {\n return `// auto-generado por devix \u2014 no editar\\ndeclare module '@devlusoft/devix' {\\n interface ApiRoutes {}\\n}\\n`\n }\n\n const imports = entries\n .map(e => {\n const importPath = '../' + e.filePath.replace(/\\.(ts|tsx)$/, '')\n return `import type * as ${e.identifier} from '${importPath}'`\n })\n .join('\\n')\n\n const routeLines = entries.flatMap(e =>\n e.methods.map(m =>\n ` '${m} ${e.urlPattern}': InferRoute<(typeof ${e.identifier})['${m}']>`\n )\n ).join('\\n')\n\n return `// auto-generado por devix \u2014 no editar\n${imports}\n\ntype JsonResponse<T> = Response & { readonly __body: T }\ntype UnwrapJson<T> = T extends JsonResponse<infer U> ? U : never\ntype InferFnReturn<T> = T extends (...args: any[]) => any\n ? UnwrapJson<Awaited<ReturnType<T>>> | Exclude<Awaited<ReturnType<T>>, JsonResponse<any> | null | void | undefined>\n : never\ntype InferRoute<T> =\n T extends { readonly __return?: infer TReturn; readonly __body?: infer TBody }\n ? {\n __body: [TBody] extends [undefined] ? never : Exclude<TBody, undefined>\n __response: InferFnReturn<() => TReturn>\n }\n : InferFnReturn<T>\n\ndeclare module '@devlusoft/devix' {\n interface ApiRoutes {\n${routeLines}\n }\n}\n`\n}\n", "import {mkdirSync, readFileSync, writeFileSync, existsSync} from 'node:fs'\nimport {join} from 'node:path'\n\nexport function writeRoutesDts(content: string, projectRoot: string): boolean {\n const devixDir = join(projectRoot, '.devix')\n const outPath = join(devixDir, 'routes.d.ts')\n\n mkdirSync(devixDir, {recursive: true})\n\n if (existsSync(outPath) && readFileSync(outPath, 'utf-8') === content) {\n return false\n }\n\n writeFileSync(outPath, content, 'utf-8')\n return true\n}\n", "interface ServerEntryOptions {\n routesPath: string\n envPath: string\n}\n\nexport function generateServerEntry({ routesPath, envPath }: ServerEntryOptions): string {\n return `\nimport { readFileSync } from 'node:fs'\n import { serve } from '@hono/node-server' \n import { serveStatic } from '@hono/node-server/serve-static'\n import { Hono } from 'hono' \n import { resolve, join, dirname } from 'node:path' \n import { fileURLToPath, pathToFileURL } from 'node:url'\n import { registerApiRoutes, registerSsrRoute } from '${routesPath}' \n import { loadDotenv } from '${envPath}'\n \n loadDotenv('production')\n \n const __dir = dirname(fileURLToPath(import.meta.url))\n\n let renderModule, apiModule, manifest, runtimeConfig \n \n try { \n runtimeConfig = JSON.parse(readFileSync(resolve(__dir, '../devix.config.json'), 'utf-8'))\n if (runtimeConfig.output !== 'static') { \n renderModule = await import(pathToFileURL(resolve(__dir, 'render.js')).href)\n apiModule = await import(pathToFileURL(resolve(__dir, 'api.js')).href) \n } \n manifest = JSON.parse(readFileSync(resolve(__dir, '../client/.vite/manifest.json'), 'utf-8')) \n } catch { \n console.error('[devix] Build not found. Run \"devix build\" first.')\n process.exit(1) \n } \n \n const port = Number(process.env.PORT) || runtimeConfig.port || 3000 \n const host = typeof runtimeConfig.host === 'string'\n ? runtimeConfig.host \n : runtimeConfig.host ? '0.0.0.0' : (process.env.HOST || '0.0.0.0') \n \n const clientRoot = resolve(__dir, '../client') \n const app = new Hono()\n \n if (runtimeConfig.output === 'static') {\n app.get('/_data/*', (c) => {\n const pathname = c.req.path.replace(/^\\\\/_data/, '') || '/' \n const filePath = pathname === '/' \n ? join(clientRoot, '_data/index.json') \n : join(clientRoot, '_data', pathname + '.json') \n try { \n return c.json(JSON.parse(readFileSync(filePath, 'utf-8')))\n } catch { \n return c.json({ error: 'not found' }, 404)\n } \n }) \n }\n\n app.use('/*', serveStatic({ \n root: clientRoot,\n onFound: (_path, c) => { \n c.header('Cache-Control', _path.includes('/assets/') \n ? 'public, immutable, max-age=31536000'\n : 'no-cache') \n } \n })) \n \n if (runtimeConfig.output === 'static') {\n console.log('[devix] Static mode \u2014 serving pre-generated files from dist/client')\n } else { \n registerApiRoutes(app, { renderModule, apiModule, manifest })\n registerSsrRoute(app, { renderModule, apiModule, manifest, loaderTimeout: runtimeConfig.loaderTimeout })\n } \n \n const server = serve({ fetch: app.fetch, port, hostname: host }, (info) => \n console.log(\\`http://\\${info.address}:\\${info.port}\\`))\n\nprocess.on('SIGTERM', () => server.close())\nprocess.on('SIGINT', () => server.close())\n`\n}", "export function parseDuration(value: number | string): number {\n if (typeof value === 'number') return value\n const match = value.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h)?$/)\n if (!match) throw new Error(`[devix] Invalid duration: \"${value}\". Use a number (ms) or a string like \"5s\", \"2m\", \"500ms\".`)\n const n = parseFloat(match[1])\n switch (match[2]) {\n case 'h': return n * 3_600_000\n case 'm': return n * 60_000\n case 's': return n * 1_000\n case 'ms':\n default: return n\n }\n}\n", "import {build} from 'esbuild'\nimport type {DevixConfig} from \"../config\"\nimport {join} from \"node:path\"\nimport {unlinkSync, writeFileSync} from \"node:fs\";\nimport {pathToFileURL} from \"node:url\";\n\nexport async function loadConfig(cwd: string): Promise<DevixConfig> {\n const result = await build({\n entryPoints: [join(cwd, 'devix.config.ts')],\n bundle: true,\n write: false,\n format: 'esm',\n platform: 'node',\n packages: 'external',\n })\n\n const tmpFile = join(cwd, `.devix-config-${Date.now()}.mjs`)\n writeFileSync(tmpFile, result.outputFiles[0].text)\n\n try {\n const mod = await import(pathToFileURL(tmpFile).href)\n return mod.default\n } finally {\n unlinkSync(tmpFile)\n }\n}"],
5
- "mappings": "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",
6
- "names": ["writeFileSync", "resolve", "build", "mergeConfig", "react", "fileURLToPath", "dirname", "resolve", "generateEntryClient", "cssUrls", "u", "generateClientRoutes", "pagesDir", "matcherPath", "generateRender", "pagesDir", "renderPath", "generateApi", "apiPath", "appDir", "routePattern", "rel", "cache", "invalidatePagesCache", "keyToRoutePattern", "key", "apiDir", "rel", "pattern", "routePattern", "cache", "invalidateApiCache", "generateContext", "readFileSync", "readdirSync", "statSync", "join", "relative", "METHOD_EXPORT_RE", "stripComments", "content", "extractHttpMethods", "found", "match", "filePathToIdentifier", "filePath", "apiDir", "buildRouteEntry", "methods", "keyToRoutePattern", "generateRoutesDts", "entries", "imports", "e", "importPath", "routeLines", "m", "walkDir", "dir", "root", "entries", "name", "readdirSync", "full", "join", "statSync", "relative", "scanApiFiles", "appDir", "projectRoot", "apiDir", "files", "f", "filePath", "content", "readFileSync", "methods", "extractHttpMethods", "buildRouteEntry", "mkdirSync", "readFileSync", "writeFileSync", "existsSync", "join", "writeRoutesDts", "content", "projectRoot", "devixDir", "outPath", "parseSync", "generateServerEntry", "routesPath", "envPath", "__dirname", "dirname", "fileURLToPath", "VIRTUAL_ENTRY_CLIENT", "VIRTUAL_CLIENT_ROUTES", "VIRTUAL_RENDER", "VIRTUAL_API", "VIRTUAL_CONTEXT", "VIRTUAL_SERVER_ENTRY", "SERVER_EXPORTS", "devix", "config", "appDir", "pagesDir", "cssUrls", "u", "renderPath", "resolve", "apiPath", "matcherPath", "routesPath", "envPath", "virtualPlugin", "id", "generateEntryClient", "generateClientRoutes", "generateRender", "generateApi", "generateContext", "generateServerEntry", "code", "options", "resolvedPagesDir", "ast", "parseSync", "replacements", "node", "decl", "seen", "declarator", "b", "result", "start", "end", "name", "root", "entries", "scanApiFiles", "writeRoutesDts", "generateRoutesDts", "server", "regenerateDts", "file", "invalidatePagesCache", "invalidateApiCache", "base", "react", "mergeConfig", "parseDuration", "value", "match", "n", "build", "join", "unlinkSync", "writeFileSync", "pathToFileURL", "loadConfig", "cwd", "result", "tmpFile", "config", "loadConfig", "baseConfig", "devix", "build", "runtimeConfig", "parseDuration", "writeFileSync", "resolve"]
4
+ "sourcesContent": ["import {writeFileSync} from 'node:fs'\nimport {resolve} from 'node:path'\nimport {build} from 'vite'\nimport {devix} from '../vite'\nimport {parseDuration} from '../utils/duration'\nimport {loadConfig} from \"../utils/load-config\";\n\nconst config = await loadConfig(process.cwd())\nconst baseConfig = devix(config)\n\nawait build({\n ...baseConfig,\n configFile: false,\n build: {\n outDir: 'dist/client',\n manifest: true,\n rolldownOptions: {\n input: 'virtual:devix/entry-client',\n },\n },\n})\n\nawait build({\n ...baseConfig,\n configFile: false,\n build: {\n ssr: true,\n outDir: 'dist/server',\n copyPublicDir: false,\n rolldownOptions: {\n input: {\n render: 'virtual:devix/render',\n api: 'virtual:devix/api',\n },\n },\n },\n})\n\nawait build({\n ...baseConfig,\n configFile: false,\n build: {\n ssr: true,\n outDir: 'dist/server',\n emptyOutDir: false,\n copyPublicDir: false,\n rolldownOptions: {\n input: { index: 'virtual:devix/server-entry' },\n },\n },\n})\n\nconst runtimeConfig = {\n port: config.port ?? 3000,\n host: config.host ?? false,\n loaderTimeout: parseDuration(config.loaderTimeout ?? 10_000),\n output: config.output ?? 'server',\n}\n\nwriteFileSync(\n resolve(process.cwd(), 'dist/devix.config.json'),\n JSON.stringify(runtimeConfig, null, 2),\n 'utf-8'\n)\n\n\nexport {}", "import { UserConfig, Plugin, mergeConfig } from 'vite'\nimport type { DevixConfig } from '../config'\nimport react from '@vitejs/plugin-react'\nimport { fileURLToPath } from 'node:url'\nimport { dirname, resolve } from 'node:path'\nimport { createRequire } from 'node:module'\nimport { generateEntryClient } from './codegen/entry-client'\nimport { generateClientRoutes } from './codegen/client-routes'\nimport { generateRender } from './codegen/render'\nimport { generateApi } from './codegen/api'\nimport { invalidatePagesCache } from \"../server/pages-router\";\nimport { invalidateApiCache } from \"../server/api-router\";\nimport { generateContext } from \"./codegen/context\";\nimport { scanApiFiles } from \"./codegen/scan-api\";\nimport { generateRoutesDts } from \"./codegen/routes-dts\";\nimport { writeRoutesDts } from \"./codegen/write-routes-dts\";\nimport { parseSync } from 'oxc-parser'\nimport {generateServerEntry} from \"./codegen/server-entry\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nconst VIRTUAL_ENTRY_CLIENT = 'virtual:devix/entry-client'\nconst VIRTUAL_CLIENT_ROUTES = 'virtual:devix/client-routes'\nconst VIRTUAL_RENDER = 'virtual:devix/render'\nconst VIRTUAL_API = 'virtual:devix/api'\nconst VIRTUAL_CONTEXT = 'virtual:devix/context'\nconst VIRTUAL_SERVER_ENTRY = 'virtual:devix/server-entry'\n\nconst SERVER_EXPORTS = new Set(['loader', 'guard', 'generateStaticParams', 'headers'])\n\nexport function devix(config: DevixConfig): UserConfig {\n const appDir = config.appDir ?? 'app'\n const pagesDir = `${appDir}/pages`\n const cssUrls = (config.css ?? []).map(u => u.startsWith('/') ? u : `/${u.replace(/^\\.\\//, '')}`)\n\n const renderPath = resolve(__dirname, '../server/render.js').replace(/\\\\/g, '/')\n const apiPath = resolve(__dirname, '../server/api.js').replace(/\\\\/g, '/')\n const matcherPath = resolve(__dirname, '../runtime/client-router.js').replace(/\\\\/g, '/')\n const routesPath = resolve(__dirname, '../server/routes.js').replace(/\\\\/g, '/')\n const envPath = resolve(__dirname, '../utils/env.js').replace(/\\\\/g, '/')\n\n const _require = createRequire(import.meta.url)\n const honoServerPath = _require.resolve('@hono/node-server').replace(/\\\\/g, '/')\n const honoServerStaticPath = _require.resolve('@hono/node-server/serve-static').replace(/\\\\/g, '/')\n const honoPath = _require.resolve('hono').replace(/\\\\/g, '/')\n\n const virtualPlugin: Plugin = {\n name: 'devix',\n enforce: 'pre',\n\n resolveId(id) {\n if (id === VIRTUAL_ENTRY_CLIENT) return `\\0${VIRTUAL_ENTRY_CLIENT}`\n if (id === VIRTUAL_CLIENT_ROUTES) return `\\0${VIRTUAL_CLIENT_ROUTES}`\n if (id === VIRTUAL_RENDER) return `\\0${VIRTUAL_RENDER}`\n if (id === VIRTUAL_API) return `\\0${VIRTUAL_API}`\n if (id === VIRTUAL_CONTEXT) return `\\0${VIRTUAL_CONTEXT}`\n if (id === VIRTUAL_SERVER_ENTRY) return `\\0${VIRTUAL_SERVER_ENTRY}`\n },\n\n load(id) {\n if (id === `\\0${VIRTUAL_ENTRY_CLIENT}`)\n return generateEntryClient({ cssUrls })\n if (id === `\\0${VIRTUAL_CLIENT_ROUTES}`)\n return generateClientRoutes({ pagesDir, matcherPath })\n if (id === `\\0${VIRTUAL_RENDER}`)\n return generateRender({ pagesDir, renderPath })\n if (id === `\\0${VIRTUAL_API}`)\n return generateApi({ apiPath, appDir })\n if (id === `\\0${VIRTUAL_CONTEXT}`)\n return generateContext()\n if (id === `\\0${VIRTUAL_SERVER_ENTRY}`)\n return generateServerEntry({ routesPath, envPath, honoServerPath, honoServerStaticPath, honoPath })\n },\n\n\n transform(code, id, options) {\n if (options?.ssr) return\n\n const resolvedPagesDir = resolve(process.cwd(), pagesDir)\n if (!id.startsWith(resolvedPagesDir)) return\n\n const ast = parseSync(id, code, { sourceType: 'module' })\n\n const replacements: { start: number; end: number; name: string }[] = []\n\n for (const node of ast.program.body) {\n if (node.type !== 'ExportNamedDeclaration' || !node.declaration) continue\n\n const decl = node.declaration\n\n if (decl.type === 'FunctionDeclaration' && decl.id && SERVER_EXPORTS.has(decl.id.name)) {\n replacements.push({ start: node.start, end: node.end, name: decl.id.name })\n }\n\n if (decl.type === 'VariableDeclaration') {\n const seen = new Set<number>()\n for (const declarator of decl.declarations) {\n if (declarator.id.type === 'Identifier' && SERVER_EXPORTS.has(declarator.id.name)) {\n if (!seen.has(node.start)) {\n seen.add(node.start)\n replacements.push({ start: node.start, end: node.end, name: declarator.id.name })\n }\n }\n }\n }\n }\n\n if (replacements.length === 0) return\n\n replacements.sort((a, b) => b.start - a.start)\n\n let result = code\n for (const { start, end, name } of replacements) {\n result = result.slice(0, start) + `export const ${name} = undefined` + result.slice(end)\n }\n\n return { code: result, map: null }\n },\n\n buildStart() {\n const root = process.cwd()\n const entries = scanApiFiles(appDir, root)\n writeRoutesDts(generateRoutesDts(entries, `${appDir}/api`), root)\n },\n\n configureServer(server) {\n const root = process.cwd()\n\n const regenerateDts = () => {\n const entries = scanApiFiles(appDir, root)\n writeRoutesDts(generateRoutesDts(entries, `${appDir}/api`), root)\n }\n\n server.watcher.add(resolve(root, 'devix.config.ts'))\n server.watcher.on('change', (file) => {\n if (file === resolve(root, 'devix.config.ts')) {\n console.log('[devix] Config changed, restarting...')\n process.exit(75)\n }\n })\n\n server.watcher.on('add', (file) => {\n if (file.startsWith(resolve(root, pagesDir))) invalidatePagesCache()\n if (file.includes(`${appDir}/api`)) { invalidateApiCache(); regenerateDts() }\n })\n server.watcher.on('unlink', (file) => {\n if (file.startsWith(resolve(root, pagesDir))) invalidatePagesCache()\n if (file.includes(`${appDir}/api`)) { invalidateApiCache(); regenerateDts() }\n })\n server.watcher.on('change', (file) => {\n if (file.includes(`${appDir}/api`) && !file.endsWith('middleware.ts')) {\n regenerateDts()\n }\n })\n },\n }\n\n const base: UserConfig = {\n plugins: [react(), virtualPlugin],\n publicDir: resolve(process.cwd(), config.publicDir ?? 'public'),\n ssr: { noExternal: ['@devlusoft/devix'] },\n ...(config.envPrefix ? { envPrefix: config.envPrefix } : {}),\n }\n\n return mergeConfig(base, config.vite ?? {})\n}", "interface EntryClientOptions {\n cssUrls: string[]\n}\n\nexport function generateEntryClient({ cssUrls }: EntryClientOptions): string {\n const cssImports = cssUrls.map(u => `import '${u}'`).join('\\n')\n\n return `\n${cssImports}\nimport \"@vitejs/plugin-react/preamble\"\nimport React from \"react\"\nimport {hydrateRoot, createRoot} from 'react-dom/client'\nimport {matchClientRoute, loadErrorPage, getDefaultErrorPage} from 'virtual:devix/client-routes'\nimport {RouterProvider} from '@devlusoft/devix'\n\nconst root = document.getElementById('devix-root')\n\nif (!window.__DEVIX__) {\n const ErrorPage = getDefaultErrorPage()\n createRoot(root).render(React.createElement(ErrorPage, {statusCode: 500, message: 'Server error'}))\n} else {\n const {metadata, viewport, clientEntry} = window.__DEVIX__\n const loaderData = window.__LOADER_DATA__\n const layoutsData = window.__LAYOUTS_DATA__ ?? []\n\n const matched = matchClientRoute(window.location.pathname)\n\n if (matched) {\n const [pageMod, ...layoutMods] = await Promise.all([\n matched.load(),\n ...matched.loadLayouts.map(l => l()),\n ])\n hydrateRoot(\n root,\n React.createElement(RouterProvider, {\n clientEntry,\n initialData: loaderData,\n initialParams: matched.params,\n initialPage: pageMod.default,\n initialLayouts: layoutMods.map(m => m.default),\n initialLayoutsData: layoutsData,\n initialMeta: metadata,\n initialViewport: viewport,\n })\n )\n\n if (window.location.hash) { \n const id = window.location.hash.slice(1) \n const scrollBehavior = getComputedStyle(document.documentElement).scrollBehavior \n requestAnimationFrame(() => { \n document.getElementById(id)?.scrollIntoView({ behavior: scrollBehavior }) \n }) \n } \n } else {\n const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()\n createRoot(root).render(\n React.createElement(RouterProvider, {\n clientEntry,\n initialData: null,\n initialParams: {},\n initialPage: () => null,\n initialLayouts: [],\n initialLayoutsData: [],\n initialMeta: null,\n initialError: {statusCode: 404, message: 'Not found'},\n initialErrorPage: ErrorPage,\n })\n )\n }\n}\n`\n}", "interface ClientRoutesOptions {\n pagesDir: string\n matcherPath: string\n}\n\nexport function generateClientRoutes({pagesDir, matcherPath}: ClientRoutesOptions) {\n return `\nimport React from 'react'\nimport { createMatcher } from '${matcherPath}'\nconst pageFiles = import.meta.glob(['/${pagesDir}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])\nconst layoutFiles = import.meta.glob('/${pagesDir}/**/layout.tsx')\nconst errorFiles = import.meta.glob('/${pagesDir}/**/error.tsx')\n\nexport const matchClientRoute = createMatcher(pageFiles, layoutFiles)\n\nexport async function loadErrorPage() {\n const key = Object.keys(errorFiles)[0]\n if (!key) return null\n const mod = await errorFiles[key]()\n return mod?.default ?? null\n}\n\nexport function getDefaultErrorPage() {\n return function DefaultError({ statusCode, message }) {\n return React.createElement('main', {\n style: { minHeight: '100dvh', display: 'flex', flexDirection: 'column', \n alignItems: 'center', justifyContent: 'center', gap: '8px',\n fontFamily: 'system-ui, sans-serif' }\n },\n React.createElement('h1', {style: {fontSize: '4rem', fontWeight: 700}}, statusCode),\n React.createElement('p', {style: {color: '#666'}}, message ?? 'An unexpected error occurred'),\n )\n }\n}\n`\n}", "interface RenderOptions {\n pagesDir: string\n renderPath: string\n}\n\nexport function generateRender({pagesDir, renderPath}: RenderOptions): string {\n return `\nimport { render as _render, runLoader as _runLoader, getStaticRoutes as _getStaticRoutes } from '${renderPath}'\n\nconst _pages = import.meta.glob(['/${pagesDir}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])\nconst _layouts = import.meta.glob('/${pagesDir}/**/layout.tsx')\n\nconst _glob = {\n pages: _pages,\n layouts: _layouts,\n pagesDir: '/${pagesDir}',\n}\n\nexport function render(url, request, options) {\n return _render(url, request, _glob, options)\n}\n\nexport function runLoader(url, request, options) {\n return _runLoader(url, request, _glob, options)\n}\n\nexport function getStaticRoutes() {\n return _getStaticRoutes(_glob)\n}\n`\n}\n", "interface ApiOptions {\n apiPath: string\n appDir: string\n}\n\nexport function generateApi({apiPath, appDir}: ApiOptions): string {\n return `\nimport { handleApiRequest as _handleApiRequest } from '${apiPath}'\n\nconst _routes = import.meta.glob(['/${appDir}/api/**/*.ts', '!**/middleware.ts'])\nconst _middlewares = import.meta.glob('/${appDir}/api/**/middleware.ts')\n\nconst _glob = {\n routes: _routes,\n middlewares: _middlewares,\n apiDir: '/${appDir}/api',\n}\n\nexport function handleApiRequest(url, request) {\n return _handleApiRequest(url, request, _glob)\n}\n`\n}\n", "export function routePattern(rel: string): string {\n return rel\n .replace(/\\.(tsx|ts|jsx|js)$/, '')\n .replace(/\\(.*?\\)\\//g, '')\n .replace(/^index$|\\/index$/, '')\n .replace(/\\[([^\\]]+)]/g, ':$1')\n || '/'\n}", "import {routePattern} from \"../utils/patterns\";\n\nexport interface Page {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface Layout {\n dir: string\n key: string\n}\n\nexport interface PagesResult {\n pages: Page[]\n layouts: Layout[]\n}\n\nfunction keyToRoutePattern(key: string, pagesDir: string): string {\n const rel = key.slice(pagesDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === \"/\" ? \"/\" : `/${pattern}`\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: PagesResult | null = null\n\nexport function invalidatePagesCache() {\n cache = null\n}\n\nexport function buildPages(pageKeys: string[], layoutKeys: string[], pagesDir: string): PagesResult {\n if (cache) return cache\n\n const pages: Page[] = []\n const layouts: Layout[] = []\n\n for (const key of layoutKeys) {\n layouts.push({dir: keyToDir(key), key})\n }\n\n for (const key of pageKeys) {\n const pattern = keyToRoutePattern(key, pagesDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n pages.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n\n pages.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {pages, layouts}\n return cache\n}\n\nexport function collectLayoutChain(pageKey: string, layouts: Layout[]): Layout[] {\n const pageDir = keyToDir(pageKey)\n\n return layouts\n .filter(layout => pageDir.startsWith(layout.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchPage(pathname: string, pages: Page[]): {\n page: Page\n params: Record<string, string>\n} | null {\n for (const page of pages) {\n const match = pathname.match(page.regex)\n if (match) {\n const params: Record<string, string> = {}\n page.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {page, params}\n }\n }\n return null\n}\n", "import {routePattern} from \"../utils/patterns\";\n\nexport interface ApiRoute {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface ApiMiddleware {\n dir: string\n key: string\n}\n\nexport interface ApiResult {\n routes: ApiRoute[]\n middlewares: ApiMiddleware[]\n}\n\nexport function keyToRoutePattern(key: string, apiDir: string): string {\n const rel = key.slice(apiDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === '/' ? '/api' : `/api/${pattern}`.replace('/api//', '/api/')\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: ApiResult | null = null\n\nexport function invalidateApiCache() {\n cache = null\n}\n\nexport function buildRoutes(routeKeys: string[], middlewareKeys: string[], apiDir: string): ApiResult {\n if (cache) return cache\n\n const routes: ApiRoute[] = []\n const middlewares: ApiMiddleware[] = []\n\n for (const key of middlewareKeys) {\n middlewares.push({dir: keyToDir(key), key})\n }\n\n for (const key of routeKeys) {\n const pattern = keyToRoutePattern(key, apiDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n routes.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n routes.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {routes, middlewares}\n return cache\n}\n\nexport function collectMiddlewareChain(routeKey: string, middlewares: ApiMiddleware[]): ApiMiddleware[] {\n const routeDir = keyToDir(routeKey)\n\n return middlewares\n .filter(mw => routeDir.startsWith(mw.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchRoute(\n pathname: string,\n routes: ApiRoute[]\n): {route: ApiRoute; params: Record<string, string>} | null {\n for (const route of routes) {\n const match = pathname.match(route.regex)\n if (match) {\n const params: Record<string, string> = {}\n route.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {route, params}\n }\n }\n return null\n}\n", "export function generateContext(): string {\n return `\nexport {RouterContext} from '@devlusoft/devix/runtime/context'\n`\n}", "import {readFileSync, readdirSync, statSync} from 'node:fs'\nimport {join, relative} from 'node:path'\nimport {extractHttpMethods} from './extract-methods'\nimport {buildRouteEntry} from './routes-dts'\nimport type {RouteEntry} from './routes-dts'\n\nfunction walkDir(dir: string, root: string): string[] {\n const entries: string[] = []\n for (const name of readdirSync(dir)) {\n const full = join(dir, name)\n if (statSync(full).isDirectory()) {\n entries.push(...walkDir(full, root))\n } else if (/\\.(ts|tsx)$/.test(name)) {\n entries.push(relative(root, full).replace(/\\\\/g, '/'))\n }\n }\n return entries\n}\n\nexport function scanApiFiles(appDir: string, projectRoot: string): RouteEntry[] {\n const apiDir = join(projectRoot, appDir, 'api')\n\n let files: string[]\n try {\n files = walkDir(apiDir, projectRoot)\n } catch {\n return []\n }\n\n return files\n .filter(f => !f.endsWith('middleware.ts') && !f.endsWith('middleware.tsx'))\n .flatMap(filePath => {\n try {\n const content = readFileSync(join(projectRoot, filePath), 'utf-8')\n const methods = extractHttpMethods(content)\n if (methods.length === 0) return []\n return [buildRouteEntry(filePath, `${appDir}/api`, methods)]\n } catch {\n return []\n }\n })\n}\n", "const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'] as const\nexport type HttpMethod = (typeof HTTP_METHODS)[number]\n\nconst METHOD_EXPORT_RE = /export\\s+(?:const|async\\s+function|function)\\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b/g\n\nfunction stripComments(content: string): string {\n return content\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .replace(/\\/\\/.*$/gm, '')\n}\n\nexport function extractHttpMethods(content: string): HttpMethod[] {\n const found = new Set<HttpMethod>()\n for (const match of stripComments(content).matchAll(METHOD_EXPORT_RE)) {\n found.add(match[1] as HttpMethod)\n }\n return [...found]\n}\n", "import { keyToRoutePattern } from '../../server/api-router'\nimport type { HttpMethod } from './extract-methods'\n\nexport interface RouteEntry {\n filePath: string\n urlPattern: string\n identifier: string\n methods: HttpMethod[]\n}\n\nexport function filePathToIdentifier(filePath: string, apiDir: string): string {\n return '_api_' + filePath\n .slice(`${apiDir}/`.length)\n .replace(/\\.(ts|tsx)$/, '')\n .replace(/[^a-zA-Z0-9]/g, '_')\n}\n\nexport function buildRouteEntry(filePath: string, apiDir: string, methods: HttpMethod[]): RouteEntry {\n return {\n filePath,\n urlPattern: keyToRoutePattern(filePath, apiDir),\n identifier: filePathToIdentifier(filePath, apiDir),\n methods,\n }\n}\n\nexport function generateRoutesDts(entries: RouteEntry[], apiDir: string): string {\n if (entries.length === 0) {\n return `// auto-generado por devix \u2014 no editar\\ndeclare module '@devlusoft/devix' {\\n interface ApiRoutes {}\\n}\\n`\n }\n\n const imports = entries\n .map(e => {\n const importPath = '../' + e.filePath.replace(/\\.(ts|tsx)$/, '')\n return `import type * as ${e.identifier} from '${importPath}'`\n })\n .join('\\n')\n\n const routeLines = entries.flatMap(e =>\n e.methods.map(m =>\n ` '${m} ${e.urlPattern}': InferRoute<(typeof ${e.identifier})['${m}']>`\n )\n ).join('\\n')\n\n return `// auto-generado por devix \u2014 no editar\n${imports}\n\ntype JsonResponse<T> = Response & { readonly __body: T }\ntype UnwrapJson<T> = T extends JsonResponse<infer U> ? U : never\ntype InferFnReturn<T> = T extends (...args: any[]) => any\n ? UnwrapJson<Awaited<ReturnType<T>>> | Exclude<Awaited<ReturnType<T>>, JsonResponse<any> | null | void | undefined>\n : never\ntype InferRoute<T> =\n T extends { readonly __return?: infer TReturn; readonly __body?: infer TBody }\n ? {\n __body: [TBody] extends [undefined] ? never : Exclude<TBody, undefined>\n __response: InferFnReturn<() => TReturn>\n }\n : InferFnReturn<T>\n\ndeclare module '@devlusoft/devix' {\n interface ApiRoutes {\n${routeLines}\n }\n}\n`\n}\n", "import {mkdirSync, readFileSync, writeFileSync, existsSync} from 'node:fs'\nimport {join} from 'node:path'\n\nexport function writeRoutesDts(content: string, projectRoot: string): boolean {\n const devixDir = join(projectRoot, '.devix')\n const outPath = join(devixDir, 'routes.d.ts')\n\n mkdirSync(devixDir, {recursive: true})\n\n if (existsSync(outPath) && readFileSync(outPath, 'utf-8') === content) {\n return false\n }\n\n writeFileSync(outPath, content, 'utf-8')\n return true\n}\n", "interface ServerEntryOptions {\n routesPath: string\n envPath: string\n honoServerPath: string\n honoServerStaticPath: string\n honoPath: string\n}\n\nexport function generateServerEntry({ routesPath, envPath, honoServerPath, honoServerStaticPath, honoPath }: ServerEntryOptions): string {\n return `\nimport { readFileSync } from 'node:fs'\n import { serve } from '${honoServerPath}'\n import { serveStatic } from '${honoServerStaticPath}'\n import { Hono } from '${honoPath}'\n import { resolve, join, dirname } from 'node:path'\n import { pathToFileURL } from 'node:url'\n import { registerApiRoutes, registerSsrRoute } from '${routesPath}' \n import { loadDotenv } from '${envPath}'\n \n loadDotenv('production')\n \n const __dir = dirname(process.argv[1])\n\n let renderModule, apiModule, manifest, runtimeConfig \n \n try { \n runtimeConfig = JSON.parse(readFileSync(resolve(__dir, '../devix.config.json'), 'utf-8'))\n if (runtimeConfig.output !== 'static') { \n renderModule = await import(pathToFileURL(resolve(__dir, 'render.js')).href)\n apiModule = await import(pathToFileURL(resolve(__dir, 'api.js')).href) \n } \n manifest = JSON.parse(readFileSync(resolve(__dir, '../client/.vite/manifest.json'), 'utf-8')) \n } catch { \n console.error('[devix] Build not found. Run \"devix build\" first.')\n process.exit(1) \n } \n \n const port = Number(process.env.PORT) || runtimeConfig.port || 3000 \n const host = typeof runtimeConfig.host === 'string'\n ? runtimeConfig.host \n : runtimeConfig.host ? '0.0.0.0' : (process.env.HOST || '0.0.0.0') \n \n const clientRoot = resolve(__dir, '../client') \n const app = new Hono()\n \n if (runtimeConfig.output === 'static') {\n app.get('/_data/*', (c) => {\n const pathname = c.req.path.replace(/^\\\\/_data/, '') || '/' \n const filePath = pathname === '/' \n ? join(clientRoot, '_data/index.json') \n : join(clientRoot, '_data', pathname + '.json') \n try { \n return c.json(JSON.parse(readFileSync(filePath, 'utf-8')))\n } catch { \n return c.json({ error: 'not found' }, 404)\n } \n }) \n }\n\n app.use('/*', serveStatic({ \n root: clientRoot,\n onFound: (_path, c) => { \n c.header('Cache-Control', _path.includes('/assets/') \n ? 'public, immutable, max-age=31536000'\n : 'no-cache') \n } \n })) \n \n if (runtimeConfig.output === 'static') {\n console.log('[devix] Static mode \u2014 serving pre-generated files from dist/client')\n } else { \n registerApiRoutes(app, { renderModule, apiModule, manifest })\n registerSsrRoute(app, { renderModule, apiModule, manifest, loaderTimeout: runtimeConfig.loaderTimeout })\n } \n \n const server = serve({ fetch: app.fetch, port, hostname: host }, (info) => \n console.log(\\`http://\\${info.address}:\\${info.port}\\`))\n\nprocess.on('SIGTERM', () => server.close())\nprocess.on('SIGINT', () => server.close())\n`\n}", "export function parseDuration(value: number | string): number {\n if (typeof value === 'number') return value\n const match = value.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h)?$/)\n if (!match) throw new Error(`[devix] Invalid duration: \"${value}\". Use a number (ms) or a string like \"5s\", \"2m\", \"500ms\".`)\n const n = parseFloat(match[1])\n switch (match[2]) {\n case 'h': return n * 3_600_000\n case 'm': return n * 60_000\n case 's': return n * 1_000\n case 'ms':\n default: return n\n }\n}\n", "import {build} from 'esbuild'\nimport type {DevixConfig} from \"../config\"\nimport {join} from \"node:path\"\nimport {unlinkSync, writeFileSync} from \"node:fs\";\nimport {pathToFileURL} from \"node:url\";\n\nexport async function loadConfig(cwd: string): Promise<DevixConfig> {\n const result = await build({\n entryPoints: [join(cwd, 'devix.config.ts')],\n bundle: true,\n write: false,\n format: 'esm',\n platform: 'node',\n packages: 'external',\n })\n\n const tmpFile = join(cwd, `.devix-config-${Date.now()}.mjs`)\n writeFileSync(tmpFile, result.outputFiles[0].text)\n\n try {\n const mod = await import(pathToFileURL(tmpFile).href)\n return mod.default\n } finally {\n unlinkSync(tmpFile)\n }\n}"],
5
+ "mappings": "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",
6
+ "names": ["writeFileSync", "resolve", "build", "mergeConfig", "react", "fileURLToPath", "dirname", "resolve", "createRequire", "generateEntryClient", "cssUrls", "u", "generateClientRoutes", "pagesDir", "matcherPath", "generateRender", "pagesDir", "renderPath", "generateApi", "apiPath", "appDir", "routePattern", "rel", "cache", "invalidatePagesCache", "keyToRoutePattern", "key", "apiDir", "rel", "pattern", "routePattern", "cache", "invalidateApiCache", "generateContext", "readFileSync", "readdirSync", "statSync", "join", "relative", "METHOD_EXPORT_RE", "stripComments", "content", "extractHttpMethods", "found", "match", "filePathToIdentifier", "filePath", "apiDir", "buildRouteEntry", "methods", "keyToRoutePattern", "generateRoutesDts", "entries", "imports", "e", "importPath", "routeLines", "m", "walkDir", "dir", "root", "entries", "name", "readdirSync", "full", "join", "statSync", "relative", "scanApiFiles", "appDir", "projectRoot", "apiDir", "files", "f", "filePath", "content", "readFileSync", "methods", "extractHttpMethods", "buildRouteEntry", "mkdirSync", "readFileSync", "writeFileSync", "existsSync", "join", "writeRoutesDts", "content", "projectRoot", "devixDir", "outPath", "parseSync", "generateServerEntry", "routesPath", "envPath", "honoServerPath", "honoServerStaticPath", "honoPath", "__dirname", "dirname", "fileURLToPath", "VIRTUAL_ENTRY_CLIENT", "VIRTUAL_CLIENT_ROUTES", "VIRTUAL_RENDER", "VIRTUAL_API", "VIRTUAL_CONTEXT", "VIRTUAL_SERVER_ENTRY", "SERVER_EXPORTS", "devix", "config", "appDir", "pagesDir", "cssUrls", "u", "renderPath", "resolve", "apiPath", "matcherPath", "routesPath", "envPath", "_require", "createRequire", "honoServerPath", "honoServerStaticPath", "honoPath", "virtualPlugin", "id", "generateEntryClient", "generateClientRoutes", "generateRender", "generateApi", "generateContext", "generateServerEntry", "code", "options", "resolvedPagesDir", "ast", "parseSync", "replacements", "node", "decl", "seen", "declarator", "b", "result", "start", "end", "name", "root", "entries", "scanApiFiles", "writeRoutesDts", "generateRoutesDts", "server", "regenerateDts", "file", "invalidatePagesCache", "invalidateApiCache", "base", "react", "mergeConfig", "parseDuration", "value", "match", "n", "build", "join", "unlinkSync", "writeFileSync", "pathToFileURL", "loadConfig", "cwd", "result", "tmpFile", "config", "loadConfig", "baseConfig", "devix", "build", "runtimeConfig", "parseDuration", "writeFileSync", "resolve"]
7
7
  }
@@ -1,4 +1,4 @@
1
- import{createServer as Oe}from"node:http";import{createServer as Ue}from"vite";import{getRequestListener as je}from"@hono/node-server";import{Hono as Fe}from"hono";import{mergeConfig as Ee}from"vite";import Pe from"@vitejs/plugin-react";import{fileURLToPath as Te}from"node:url";import{dirname as $e,resolve as p}from"node:path";function H({cssUrls:e}){return`
1
+ import{createServer as He}from"node:http";import{createServer as qe}from"vite";import{getRequestListener as Ne}from"@hono/node-server";import{Hono as Ve}from"hono";import{mergeConfig as Se}from"vite";import De from"@vitejs/plugin-react";import{fileURLToPath as Ce}from"node:url";import{dirname as Ae,resolve as p}from"node:path";import{createRequire as be}from"node:module";function H({cssUrls:e}){return`
2
2
  ${e.map(r=>`import '${r}'`).join(`
3
3
  `)}
4
4
  import "@vitejs/plugin-react/preamble"
@@ -128,14 +128,14 @@ const _glob = {
128
128
  export function handleApiRequest(url, request) {
129
129
  return _handleApiRequest(url, request, _glob)
130
130
  }
131
- `}function $(e){return e.replace(/\.(tsx|ts|jsx|js)$/,"").replace(/\(.*?\)\//g,"").replace(/^index$|\/index$/,"").replace(/\[([^\]]+)]/g,":$1")||"/"}var ue=null;function S(){ue=null}function W(e,t){let r=e.slice(t.length+1).replace(/\\/g,"/"),i=$(r);return i==="/"?"/api":`/api/${i}`.replace("/api//","/api/")}var pe=null;function D(){pe=null}function B(){return`
131
+ `}function T(e){return e.replace(/\.(tsx|ts|jsx|js)$/,"").replace(/\(.*?\)\//g,"").replace(/^index$|\/index$/,"").replace(/\[([^\]]+)]/g,":$1")||"/"}var fe=null;function S(){fe=null}function W(e,t){let r=e.slice(t.length+1).replace(/\\/g,"/"),n=T(r);return n==="/"?"/api":`/api/${n}`.replace("/api//","/api/")}var ge=null;function D(){ge=null}function B(){return`
132
132
  export {RouterContext} from '@devlusoft/devix/runtime/context'
133
- `}import{readFileSync as ge,readdirSync as he,statSync as ye}from"node:fs";import{join as A,relative as xe}from"node:path";var de=/export\s+(?:const|async\s+function|function)\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g;function me(e){return e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}function J(e){let t=new Set;for(let r of me(e).matchAll(de))t.add(r[1]);return[...t]}function fe(e,t){return"_api_"+e.slice(`${t}/`.length).replace(/\.(ts|tsx)$/,"").replace(/[^a-zA-Z0-9]/g,"_")}function X(e,t,r){return{filePath:e,urlPattern:W(e,t),identifier:fe(e,t),methods:r}}function C(e,t){if(e.length===0)return`// auto-generado por devix \u2014 no editar
133
+ `}import{readFileSync as ve,readdirSync as Re,statSync as _e}from"node:fs";import{join as A,relative as we}from"node:path";var he=/export\s+(?:const|async\s+function|function)\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g;function ye(e){return e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}function J(e){let t=new Set;for(let r of ye(e).matchAll(he))t.add(r[1]);return[...t]}function xe(e,t){return"_api_"+e.slice(`${t}/`.length).replace(/\.(ts|tsx)$/,"").replace(/[^a-zA-Z0-9]/g,"_")}function X(e,t,r){return{filePath:e,urlPattern:W(e,t),identifier:xe(e,t),methods:r}}function C(e,t){if(e.length===0)return`// auto-generado por devix \u2014 no editar
134
134
  declare module '@devlusoft/devix' {
135
135
  interface ApiRoutes {}
136
136
  }
137
137
  `;let r=e.map(o=>{let s="../"+o.filePath.replace(/\.(ts|tsx)$/,"");return`import type * as ${o.identifier} from '${s}'`}).join(`
138
- `),i=e.flatMap(o=>o.methods.map(s=>` '${s} ${o.urlPattern}': InferRoute<(typeof ${o.identifier})['${s}']>`)).join(`
138
+ `),n=e.flatMap(o=>o.methods.map(s=>` '${s} ${o.urlPattern}': InferRoute<(typeof ${o.identifier})['${s}']>`)).join(`
139
139
  `);return`// auto-generado por devix \u2014 no editar
140
140
  ${r}
141
141
 
@@ -154,22 +154,22 @@ type InferRoute<T> =
154
154
 
155
155
  declare module '@devlusoft/devix' {
156
156
  interface ApiRoutes {
157
- ${i}
157
+ ${n}
158
158
  }
159
159
  }
160
- `}function G(e,t){let r=[];for(let i of he(e)){let o=A(e,i);ye(o).isDirectory()?r.push(...G(o,t)):/\.(ts|tsx)$/.test(i)&&r.push(xe(t,o).replace(/\\/g,"/"))}return r}function b(e,t){let r=A(t,e,"api"),i;try{i=G(r,t)}catch{return[]}return i.filter(o=>!o.endsWith("middleware.ts")&&!o.endsWith("middleware.tsx")).flatMap(o=>{try{let s=ge(A(t,o),"utf-8"),m=J(s);return m.length===0?[]:[X(o,`${e}/api`,m)]}catch{return[]}})}import{mkdirSync as ve,readFileSync as Re,writeFileSync as _e,existsSync as we}from"node:fs";import{join as Y}from"node:path";function M(e,t){let r=Y(t,".devix"),i=Y(r,"routes.d.ts");return ve(r,{recursive:!0}),we(i)&&Re(i,"utf-8")===e?!1:(_e(i,e,"utf-8"),!0)}import{parseSync as Se}from"oxc-parser";function z({routesPath:e,envPath:t}){return`
160
+ `}function G(e,t){let r=[];for(let n of Re(e)){let o=A(e,n);_e(o).isDirectory()?r.push(...G(o,t)):/\.(ts|tsx)$/.test(n)&&r.push(we(t,o).replace(/\\/g,"/"))}return r}function b(e,t){let r=A(t,e,"api"),n;try{n=G(r,t)}catch{return[]}return n.filter(o=>!o.endsWith("middleware.ts")&&!o.endsWith("middleware.tsx")).flatMap(o=>{try{let s=ve(A(t,o),"utf-8"),m=J(s);return m.length===0?[]:[X(o,`${e}/api`,m)]}catch{return[]}})}import{mkdirSync as Ee,readFileSync as Pe,writeFileSync as $e,existsSync as Te}from"node:fs";import{join as Y}from"node:path";function M(e,t){let r=Y(t,".devix"),n=Y(r,"routes.d.ts");return Ee(r,{recursive:!0}),Te(n)&&Pe(n,"utf-8")===e?!1:($e(n,e,"utf-8"),!0)}import{parseSync as Me}from"oxc-parser";function z({routesPath:e,envPath:t,honoServerPath:r,honoServerStaticPath:n,honoPath:o}){return`
161
161
  import { readFileSync } from 'node:fs'
162
- import { serve } from '@hono/node-server'
163
- import { serveStatic } from '@hono/node-server/serve-static'
164
- import { Hono } from 'hono'
165
- import { resolve, join, dirname } from 'node:path'
166
- import { fileURLToPath, pathToFileURL } from 'node:url'
162
+ import { serve } from '${r}'
163
+ import { serveStatic } from '${n}'
164
+ import { Hono } from '${o}'
165
+ import { resolve, join, dirname } from 'node:path'
166
+ import { pathToFileURL } from 'node:url'
167
167
  import { registerApiRoutes, registerSsrRoute } from '${e}'
168
168
  import { loadDotenv } from '${t}'
169
169
 
170
170
  loadDotenv('production')
171
171
 
172
- const __dir = dirname(fileURLToPath(import.meta.url))
172
+ const __dir = dirname(process.argv[1])
173
173
 
174
174
  let renderModule, apiModule, manifest, runtimeConfig
175
175
 
@@ -228,7 +228,7 @@ import { readFileSync } from 'node:fs'
228
228
 
229
229
  process.on('SIGTERM', () => server.close())
230
230
  process.on('SIGINT', () => server.close())
231
- `}var _=$e(Te(import.meta.url)),I="virtual:devix/entry-client",L="virtual:devix/client-routes",O="virtual:devix/render",U="virtual:devix/api",j="virtual:devix/context",F="virtual:devix/server-entry",Z=new Set(["loader","guard","generateStaticParams","headers"]);function K(e){let t=e.appDir??"app",r=`${t}/pages`,i=(e.css??[]).map(n=>n.startsWith("/")?n:`/${n.replace(/^\.\//,"")}`),o=p(_,"../server/render.js").replace(/\\/g,"/"),s=p(_,"../server/api.js").replace(/\\/g,"/"),m=p(_,"../runtime/client-router.js").replace(/\\/g,"/"),y=p(_,"../server/routes.js").replace(/\\/g,"/"),f=p(_,"../utils/env.js").replace(/\\/g,"/"),x={name:"devix",enforce:"pre",resolveId(n){if(n===I)return`\0${I}`;if(n===L)return`\0${L}`;if(n===O)return`\0${O}`;if(n===U)return`\0${U}`;if(n===j)return`\0${j}`;if(n===F)return`\0${F}`},load(n){if(n===`\0${I}`)return H({cssUrls:i});if(n===`\0${L}`)return q({pagesDir:r,matcherPath:m});if(n===`\0${O}`)return N({pagesDir:r,renderPath:o});if(n===`\0${U}`)return V({apiPath:s,appDir:t});if(n===`\0${j}`)return B();if(n===`\0${F}`)return z({routesPath:y,envPath:f})},transform(n,u,v){if(v?.ssr)return;let a=p(process.cwd(),r);if(!u.startsWith(a))return;let le=Se(u,n,{sourceType:"module"}),R=[];for(let c of le.program.body){if(c.type!=="ExportNamedDeclaration"||!c.declaration)continue;let d=c.declaration;if(d.type==="FunctionDeclaration"&&d.id&&Z.has(d.id.name)&&R.push({start:c.start,end:c.end,name:d.id.name}),d.type==="VariableDeclaration"){let E=new Set;for(let T of d.declarations)T.id.type==="Identifier"&&Z.has(T.id.name)&&(E.has(c.start)||(E.add(c.start),R.push({start:c.start,end:c.end,name:T.id.name})))}}if(R.length===0)return;R.sort((c,d)=>d.start-c.start);let w=n;for(let{start:c,end:d,name:E}of R)w=w.slice(0,c)+`export const ${E} = undefined`+w.slice(d);return{code:w,map:null}},buildStart(){let n=process.cwd(),u=b(t,n);M(C(u,`${t}/api`),n)},configureServer(n){let u=process.cwd(),v=()=>{let a=b(t,u);M(C(a,`${t}/api`),u)};n.watcher.add(p(u,"devix.config.ts")),n.watcher.on("change",a=>{a===p(u,"devix.config.ts")&&(console.log("[devix] Config changed, restarting..."),process.exit(75))}),n.watcher.on("add",a=>{a.startsWith(p(u,r))&&S(),a.includes(`${t}/api`)&&(D(),v())}),n.watcher.on("unlink",a=>{a.startsWith(p(u,r))&&S(),a.includes(`${t}/api`)&&(D(),v())}),n.watcher.on("change",a=>{a.includes(`${t}/api`)&&!a.endsWith("middleware.ts")&&v()})}},P={plugins:[Pe(),x],publicDir:p(process.cwd(),e.publicDir??"public"),ssr:{noExternal:["@devlusoft/devix"]},...e.envPrefix?{envPrefix:e.envPrefix}:{}};return Ee(P,e.vite??{})}function Q(e,{apiModule:t,renderModule:r,loaderTimeout:i}){e.all("/api/*",async o=>{try{return await t.handleApiRequest(o.req.url,o.req.raw)}catch(s){return console.error(s),o.json({error:"internal error"},500)}}),e.get("/_data/*",async o=>{try{let{pathname:s,search:m}=new URL(o.req.url,"http://localhost"),y=s.replace(/^\/_data/,"")+m,f=await r.runLoader(y,o.req.raw,{loaderTimeout:i});return f.error?o.json({error:"internal error"},500):o.json(f)}catch(s){return console.error(s),o.json({error:"internal error"},500)}})}import l from"picocolors";import{networkInterfaces as De}from"node:os";function Ce(e){let t=De();for(let r of Object.values(t))for(let i of r??[])if(i.family==="IPv4"&&!i.internal)return`http://${i.address}:${e}/`;return null}function ee(e){let t="0.4.1-beta.11",r=Ce(e);console.log(),console.log(` ${l.bold(l.yellow("devix"))} ${l.dim(`v${t}`)}`),console.log(),console.log(` ${l.green("\u279C")} ${l.bold("Local:")} ${l.cyan(`http://localhost:${e}/`)}`),console.log(r?` ${l.green("\u279C")} ${l.bold("Network:")} ${l.cyan(r)}`:` ${l.green("\u279C")} ${l.bold("Network:")} ${l.dim("use --host to expose")}`),console.log()}async function te(e){let t=new Set;for(let[,r]of e.moduleGraph.idToModuleMap)r.id&&(r.id.endsWith(".css")||r.id.includes(".css?"))&&r.url.startsWith("/")&&t.add(r.url);return[...t]}function re(e){if(typeof e=="number")return e;let t=e.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h)?$/);if(!t)throw new Error(`[devix] Invalid duration: "${e}". Use a number (ms) or a string like "5s", "2m", "500ms".`);let r=parseFloat(t[1]);switch(t[2]){case"h":return r*36e5;case"m":return r*6e4;case"s":return r*1e3;default:return r}}import{loadEnv as Ae}from"vite";function oe(e){let t=Ae(e,process.cwd(),"");for(let[r,i]of Object.entries(t))process.env[r]===void 0&&(process.env[r]=i)}import{build as be}from"esbuild";import{join as ne}from"node:path";import{unlinkSync as Me,writeFileSync as Ie}from"node:fs";import{pathToFileURL as Le}from"node:url";async function ie(e){let t=await be({entryPoints:[ne(e,"devix.config.ts")],bundle:!0,write:!1,format:"esm",platform:"node",packages:"external"}),r=ne(e,`.devix-config-${Date.now()}.mjs`);Ie(r,t.outputFiles[0].text);try{return(await import(Le(r).href)).default}finally{Me(r)}}oe("development");var se="virtual:devix/render",ke="virtual:devix/api",h=await ie(process.cwd()),ae=Number(process.env.PORT)||h.port||3e3,He=typeof h.host=="string"?h.host:h.host?"0.0.0.0":"localhost",g=await Ue({...K(h),configFile:!1,appType:"custom",server:{middlewareMode:!0}}),ce={render:async(...e)=>(await g.ssrLoadModule(se)).render(...e),runLoader:async(...e)=>(await g.ssrLoadModule(se)).runLoader(...e)},qe={handleApiRequest:async(...e)=>(await g.ssrLoadModule(ke)).handleApiRequest(...e)},k=new Fe;Q(k,{renderModule:ce,apiModule:qe});k.get("*",async e=>{try{let{html:t,statusCode:r,headers:i}=await ce.render(e.req.url,e.req.raw,{loaderTimeout:re(h.loaderTimeout??1e4)}),s=(await te(g)).map(x=>`<link rel="stylesheet" href="${x}">`).join(`
231
+ `}var _=Ae(Ce(import.meta.url)),I="virtual:devix/entry-client",L="virtual:devix/client-routes",O="virtual:devix/render",j="virtual:devix/api",U="virtual:devix/context",F="virtual:devix/server-entry",Z=new Set(["loader","guard","generateStaticParams","headers"]);function K(e){let t=e.appDir??"app",r=`${t}/pages`,n=(e.css??[]).map(i=>i.startsWith("/")?i:`/${i.replace(/^\.\//,"")}`),o=p(_,"../server/render.js").replace(/\\/g,"/"),s=p(_,"../server/api.js").replace(/\\/g,"/"),m=p(_,"../runtime/client-router.js").replace(/\\/g,"/"),x=p(_,"../server/routes.js").replace(/\\/g,"/"),f=p(_,"../utils/env.js").replace(/\\/g,"/"),g=be(import.meta.url),P=g.resolve("@hono/node-server").replace(/\\/g,"/"),le=g.resolve("@hono/node-server/serve-static").replace(/\\/g,"/"),ue=g.resolve("hono").replace(/\\/g,"/"),pe={name:"devix",enforce:"pre",resolveId(i){if(i===I)return`\0${I}`;if(i===L)return`\0${L}`;if(i===O)return`\0${O}`;if(i===j)return`\0${j}`;if(i===U)return`\0${U}`;if(i===F)return`\0${F}`},load(i){if(i===`\0${I}`)return H({cssUrls:n});if(i===`\0${L}`)return q({pagesDir:r,matcherPath:m});if(i===`\0${O}`)return N({pagesDir:r,renderPath:o});if(i===`\0${j}`)return V({apiPath:s,appDir:t});if(i===`\0${U}`)return B();if(i===`\0${F}`)return z({routesPath:x,envPath:f,honoServerPath:P,honoServerStaticPath:le,honoPath:ue})},transform(i,u,v){if(v?.ssr)return;let a=p(process.cwd(),r);if(!u.startsWith(a))return;let me=Me(u,i,{sourceType:"module"}),R=[];for(let c of me.program.body){if(c.type!=="ExportNamedDeclaration"||!c.declaration)continue;let d=c.declaration;if(d.type==="FunctionDeclaration"&&d.id&&Z.has(d.id.name)&&R.push({start:c.start,end:c.end,name:d.id.name}),d.type==="VariableDeclaration"){let E=new Set;for(let $ of d.declarations)$.id.type==="Identifier"&&Z.has($.id.name)&&(E.has(c.start)||(E.add(c.start),R.push({start:c.start,end:c.end,name:$.id.name})))}}if(R.length===0)return;R.sort((c,d)=>d.start-c.start);let w=i;for(let{start:c,end:d,name:E}of R)w=w.slice(0,c)+`export const ${E} = undefined`+w.slice(d);return{code:w,map:null}},buildStart(){let i=process.cwd(),u=b(t,i);M(C(u,`${t}/api`),i)},configureServer(i){let u=process.cwd(),v=()=>{let a=b(t,u);M(C(a,`${t}/api`),u)};i.watcher.add(p(u,"devix.config.ts")),i.watcher.on("change",a=>{a===p(u,"devix.config.ts")&&(console.log("[devix] Config changed, restarting..."),process.exit(75))}),i.watcher.on("add",a=>{a.startsWith(p(u,r))&&S(),a.includes(`${t}/api`)&&(D(),v())}),i.watcher.on("unlink",a=>{a.startsWith(p(u,r))&&S(),a.includes(`${t}/api`)&&(D(),v())}),i.watcher.on("change",a=>{a.includes(`${t}/api`)&&!a.endsWith("middleware.ts")&&v()})}},de={plugins:[De(),pe],publicDir:p(process.cwd(),e.publicDir??"public"),ssr:{noExternal:["@devlusoft/devix"]},...e.envPrefix?{envPrefix:e.envPrefix}:{}};return Se(de,e.vite??{})}function Q(e,{apiModule:t,renderModule:r,loaderTimeout:n}){e.all("/api/*",async o=>{try{return await t.handleApiRequest(o.req.url,o.req.raw)}catch(s){return console.error(s),o.json({error:"internal error"},500)}}),e.get("/_data/*",async o=>{try{let{pathname:s,search:m}=new URL(o.req.url,"http://localhost"),x=s.replace(/^\/_data/,"")+m,f=await r.runLoader(x,o.req.raw,{loaderTimeout:n});return f.error?o.json({error:"internal error"},500):o.json(f)}catch(s){return console.error(s),o.json({error:"internal error"},500)}})}import l from"picocolors";import{networkInterfaces as Ie}from"node:os";function Le(e){let t=Ie();for(let r of Object.values(t))for(let n of r??[])if(n.family==="IPv4"&&!n.internal)return`http://${n.address}:${e}/`;return null}function ee(e){let t="0.4.1-beta.13",r=Le(e);console.log(),console.log(` ${l.bold(l.yellow("devix"))} ${l.dim(`v${t}`)}`),console.log(),console.log(` ${l.green("\u279C")} ${l.bold("Local:")} ${l.cyan(`http://localhost:${e}/`)}`),console.log(r?` ${l.green("\u279C")} ${l.bold("Network:")} ${l.cyan(r)}`:` ${l.green("\u279C")} ${l.bold("Network:")} ${l.dim("use --host to expose")}`),console.log()}async function te(e){let t=new Set;for(let[,r]of e.moduleGraph.idToModuleMap)r.id&&(r.id.endsWith(".css")||r.id.includes(".css?"))&&r.url.startsWith("/")&&t.add(r.url);return[...t]}function re(e){if(typeof e=="number")return e;let t=e.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h)?$/);if(!t)throw new Error(`[devix] Invalid duration: "${e}". Use a number (ms) or a string like "5s", "2m", "500ms".`);let r=parseFloat(t[1]);switch(t[2]){case"h":return r*36e5;case"m":return r*6e4;case"s":return r*1e3;default:return r}}import{loadEnv as Oe}from"vite";function oe(e){let t=Oe(e,process.cwd(),"");for(let[r,n]of Object.entries(t))process.env[r]===void 0&&(process.env[r]=n)}import{build as je}from"esbuild";import{join as ne}from"node:path";import{unlinkSync as Ue,writeFileSync as Fe}from"node:fs";import{pathToFileURL as ke}from"node:url";async function ie(e){let t=await je({entryPoints:[ne(e,"devix.config.ts")],bundle:!0,write:!1,format:"esm",platform:"node",packages:"external"}),r=ne(e,`.devix-config-${Date.now()}.mjs`);Fe(r,t.outputFiles[0].text);try{return(await import(ke(r).href)).default}finally{Ue(r)}}oe("development");var se="virtual:devix/render",We="virtual:devix/api",y=await ie(process.cwd()),ae=Number(process.env.PORT)||y.port||3e3,Be=typeof y.host=="string"?y.host:y.host?"0.0.0.0":"localhost",h=await qe({...K(y),configFile:!1,appType:"custom",server:{middlewareMode:!0}}),ce={render:async(...e)=>(await h.ssrLoadModule(se)).render(...e),runLoader:async(...e)=>(await h.ssrLoadModule(se)).runLoader(...e)},Je={handleApiRequest:async(...e)=>(await h.ssrLoadModule(We)).handleApiRequest(...e)},k=new Ve;Q(k,{renderModule:ce,apiModule:Je});k.get("*",async e=>{try{let{html:t,statusCode:r,headers:n}=await ce.render(e.req.url,e.req.raw,{loaderTimeout:re(y.loaderTimeout??1e4)}),s=(await te(h)).map(g=>`<link rel="stylesheet" href="${g}">`).join(`
232
232
  `),m=s?t.replace("</head>",`${s}
233
- </head>`):t,y=await g.transformIndexHtml(e.req.url,`<!DOCTYPE html>${m}`),f=e.html(y,r);for(let[x,P]of Object.entries(i))f.headers.set(x,P);return f}catch(t){return g.ssrFixStacktrace(t),console.error(t),e.text("Internal Server Error",500)}});var Ne=je(k.fetch);Oe(async(e,t)=>{await new Promise(r=>g.middlewares(e,t,r)),t.writableEnded||await Ne(e,t)}).listen(ae,He,()=>{ee(ae)});
233
+ </head>`):t,x=await h.transformIndexHtml(e.req.url,`<!DOCTYPE html>${m}`),f=e.html(x,r);for(let[g,P]of Object.entries(n))f.headers.set(g,P);return f}catch(t){return h.ssrFixStacktrace(t),console.error(t),e.text("Internal Server Error",500)}});var Xe=Ne(k.fetch);He(async(e,t)=>{await new Promise(r=>h.middlewares(e,t,r)),t.writableEnded||await Xe(e,t)}).listen(ae,Be,()=>{ee(ae)});
234
234
  //# sourceMappingURL=dev-server.js.map