@devlusoft/devix 0.4.1-beta.8 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/cli/build.js +130 -31
  2. package/dist/cli/build.js.map +4 -4
  3. package/dist/cli/dev-server.js +132 -33
  4. package/dist/cli/dev-server.js.map +4 -4
  5. package/dist/cli/generate.js +130 -31
  6. package/dist/cli/generate.js.map +4 -4
  7. package/dist/cli/index.js +131 -32
  8. package/dist/cli/index.js.map +4 -4
  9. package/dist/cli/start.js +1 -1
  10. package/dist/cli/start.js.map +3 -3
  11. package/dist/runtime/client-router.js +1 -1
  12. package/dist/runtime/client-router.js.map +3 -3
  13. package/dist/runtime/context.d.ts +1 -0
  14. package/dist/runtime/context.js.map +2 -2
  15. package/dist/runtime/fetch.d.ts +4 -35
  16. package/dist/runtime/fetch.js +1 -1
  17. package/dist/runtime/fetch.js.map +3 -3
  18. package/dist/runtime/index.d.ts +32 -4
  19. package/dist/runtime/index.js +1 -1
  20. package/dist/runtime/index.js.map +4 -4
  21. package/dist/runtime/link.d.ts +3 -2
  22. package/dist/runtime/link.js +1 -1
  23. package/dist/runtime/link.js.map +4 -4
  24. package/dist/runtime/router-provider.js +1 -1
  25. package/dist/runtime/router-provider.js.map +3 -3
  26. package/dist/runtime/server-app.js +1 -1
  27. package/dist/runtime/server-app.js.map +3 -3
  28. package/dist/server/api-router.d.ts +0 -1
  29. package/dist/server/api-router.js +1 -1
  30. package/dist/server/api-router.js.map +3 -3
  31. package/dist/server/api.js +1 -1
  32. package/dist/server/api.js.map +3 -3
  33. package/dist/server/index.js +1 -1
  34. package/dist/server/index.js.map +3 -3
  35. package/dist/server/pages-router.d.ts +0 -1
  36. package/dist/server/pages-router.js +1 -1
  37. package/dist/server/pages-router.js.map +3 -3
  38. package/dist/server/render.d.ts +15 -0
  39. package/dist/server/render.js +1 -1
  40. package/dist/server/render.js.map +3 -3
  41. package/dist/server/routes.js +1 -1
  42. package/dist/server/routes.js.map +3 -3
  43. package/dist/server/types.d.ts +4 -2
  44. package/dist/utils/banner.js +1 -1
  45. package/dist/utils/banner.js.map +1 -1
  46. package/dist/utils/load-config.js +1 -1
  47. package/dist/utils/load-config.js.map +3 -3
  48. package/dist/utils/response.d.ts +13 -2
  49. package/dist/utils/response.js +1 -1
  50. package/dist/utils/response.js.map +3 -3
  51. package/dist/vite/codegen/entry-client.js +14 -1
  52. package/dist/vite/codegen/entry-client.js.map +2 -2
  53. package/dist/vite/codegen/page-types.d.ts +5 -0
  54. package/dist/vite/codegen/page-types.js +14 -0
  55. package/dist/vite/codegen/page-types.js.map +7 -0
  56. package/dist/vite/codegen/routes-dts.js +13 -10
  57. package/dist/vite/codegen/routes-dts.js.map +2 -2
  58. package/dist/vite/codegen/scan-api.js +1 -1
  59. package/dist/vite/codegen/scan-api.js.map +1 -1
  60. package/dist/vite/codegen/server-entry.d.ts +9 -0
  61. package/dist/vite/codegen/server-entry.js +73 -0
  62. package/dist/vite/codegen/server-entry.js.map +7 -0
  63. package/dist/vite/index.js +131 -32
  64. package/dist/vite/index.js.map +4 -4
  65. package/package.json +2 -2
package/dist/cli/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- var s=(t,e)=>()=>(t&&(e=t(t=0)),e);var Gt={};import{spawnSync as Vt}from"node:child_process";import{fileURLToPath as Bt}from"node:url";import{dirname as Jt,resolve as Wt}from"node:path";var Xt,Q=s(()=>{"use strict";Xt=Jt(Bt(import.meta.url));for(;Vt(process.execPath,[Wt(Xt,"dev-server.js")],{stdio:"inherit",env:process.env}).status===75;);});function tt({cssUrls:t}){return`
3
- ${t.map(r=>`import '${r}'`).join(`
2
+ var c=(e,t)=>()=>(e&&(t=e(e=0)),t);var lt={};import{spawnSync as nt}from"node:child_process";import{fileURLToPath as it}from"node:url";import{dirname as st,resolve as at}from"node:path";var ct,ne=c(()=>{"use strict";ct=st(it(import.meta.url));for(;nt(process.execPath,[at(ct,"dev-server.js")],{stdio:"inherit",env:process.env}).status===75;);});function ie({cssUrls:e}){return`
3
+ ${e.map(r=>`import '${r}'`).join(`
4
4
  `)}
5
5
  import "@vitejs/plugin-react/preamble"
6
6
  import React from "react"
@@ -20,7 +20,20 @@ if (!window.__DEVIX__) {
20
20
 
21
21
  const matched = matchClientRoute(window.location.pathname)
22
22
 
23
- if (matched) {
23
+ if (window.__LOADER_ERROR__) {
24
+ const {statusCode, message, data} = window.__LOADER_ERROR__
25
+ const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()
26
+ createRoot(root).render(
27
+ React.createElement(RouterProvider, {
28
+ clientEntry,
29
+ initialData: null,
30
+ initialParams: {},
31
+ initialPage: () => null,
32
+ initialError: {statusCode, message, data},
33
+ initialErrorPage: ErrorPage,
34
+ })
35
+ )
36
+ } else if (matched) {
24
37
  const [pageMod, ...layoutMods] = await Promise.all([
25
38
  matched.load(),
26
39
  ...matched.loadLayouts.map(l => l()),
@@ -63,12 +76,12 @@ if (!window.__DEVIX__) {
63
76
  )
64
77
  }
65
78
  }
66
- `}var et=s(()=>{"use strict"});function rt({pagesDir:t,matcherPath:e}){return`
79
+ `}var se=c(()=>{"use strict"});function ae({pagesDir:e,matcherPath:t}){return`
67
80
  import React from 'react'
68
- import { createMatcher } from '${e}'
69
- const pageFiles = import.meta.glob(['/${t}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])
70
- const layoutFiles = import.meta.glob('/${t}/**/layout.tsx')
71
- const errorFiles = import.meta.glob('/${t}/**/error.tsx')
81
+ import { createMatcher } from '${t}'
82
+ const pageFiles = import.meta.glob(['/${e}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])
83
+ const layoutFiles = import.meta.glob('/${e}/**/layout.tsx')
84
+ const errorFiles = import.meta.glob('/${e}/**/error.tsx')
72
85
 
73
86
  export const matchClientRoute = createMatcher(pageFiles, layoutFiles)
74
87
 
@@ -91,16 +104,16 @@ export function getDefaultErrorPage() {
91
104
  )
92
105
  }
93
106
  }
94
- `}var ot=s(()=>{"use strict"});function nt({pagesDir:t,renderPath:e}){return`
95
- import { render as _render, runLoader as _runLoader, getStaticRoutes as _getStaticRoutes } from '${e}'
107
+ `}var ce=c(()=>{"use strict"});function le({pagesDir:e,renderPath:t}){return`
108
+ import { render as _render, runLoader as _runLoader, getStaticRoutes as _getStaticRoutes } from '${t}'
96
109
 
97
- const _pages = import.meta.glob(['/${t}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])
98
- const _layouts = import.meta.glob('/${t}/**/layout.tsx')
110
+ const _pages = import.meta.glob(['/${e}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])
111
+ const _layouts = import.meta.glob('/${e}/**/layout.tsx')
99
112
 
100
113
  const _glob = {
101
114
  pages: _pages,
102
115
  layouts: _layouts,
103
- pagesDir: '/${t}',
116
+ pagesDir: '/${e}',
104
117
  }
105
118
 
106
119
  export function render(url, request, options) {
@@ -114,51 +127,137 @@ export function runLoader(url, request, options) {
114
127
  export function getStaticRoutes() {
115
128
  return _getStaticRoutes(_glob)
116
129
  }
117
- `}var it=s(()=>{"use strict"});function st({apiPath:t,appDir:e}){return`
118
- import { handleApiRequest as _handleApiRequest } from '${t}'
130
+ `}var ue=c(()=>{"use strict"});function de({apiPath:e,appDir:t}){return`
131
+ import { handleApiRequest as _handleApiRequest } from '${e}'
119
132
 
120
- const _routes = import.meta.glob(['/${e}/api/**/*.ts', '!**/middleware.ts'])
121
- const _middlewares = import.meta.glob('/${e}/api/**/middleware.ts')
133
+ const _routes = import.meta.glob(['/${t}/api/**/*.ts', '!**/middleware.ts'])
134
+ const _middlewares = import.meta.glob('/${t}/api/**/middleware.ts')
122
135
 
123
136
  const _glob = {
124
137
  routes: _routes,
125
138
  middlewares: _middlewares,
126
- apiDir: '/${e}/api',
139
+ apiDir: '/${t}/api',
127
140
  }
128
141
 
129
142
  export function handleApiRequest(url, request) {
130
143
  return _handleApiRequest(url, request, _glob)
131
144
  }
132
- `}var at=s(()=>{"use strict"});function $(t){return t.replace(/\.(tsx|ts|jsx|js)$/,"").replace(/\(.*?\)\//g,"").replace(/^index$|\/index$/,"").replace(/\[([^\]]+)]/g,":$1")||"/"}var b=s(()=>{"use strict"});function D(){Yt=null}var Yt,ct=s(()=>{"use strict";b();Yt=null});function lt(t,e){let r=t.slice(e.length+1).replace(/\\/g,"/"),i=$(r);return i==="/"?"/api":`/api/${i}`.replace("/api//","/api/")}function C(){zt=null}var zt,A=s(()=>{"use strict";b();zt=null});function ut(){return`
145
+ `}var pe=c(()=>{"use strict"});function me(){return`
133
146
  export {RouterContext} from '@devlusoft/devix/runtime/context'
134
- `}var pt=s(()=>{"use strict"});function Kt(t){return t.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}function dt(t){let e=new Set;for(let r of Kt(t).matchAll(Zt))e.add(r[1]);return[...e]}var Zt,mt=s(()=>{"use strict";Zt=/export\s+(?:const|async\s+function|function)\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g});function Qt(t,e){return"_api_"+t.slice(`${e}/`.length).replace(/\.(ts|tsx)$/,"").replace(/[^a-zA-Z0-9]/g,"_")}function ft(t,e,r){return{filePath:t,urlPattern:lt(t,e),identifier:Qt(t,e),methods:r}}function O(t,e){if(t.length===0)return`// auto-generado por devix \u2014 no editar
147
+ `}var fe=c(()=>{"use strict"});function dt(e){return e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}function ge(e){let t=new Set;for(let r of dt(e).matchAll(ut))t.add(r[1]);return[...t]}var ut,he=c(()=>{"use strict";ut=/export\s+(?:const|async\s+function|function)\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g});function ve(e){return e.replace(/\.(tsx|ts|jsx|js)$/,"").replace(/\(.*?\)\//g,"").replace(/^index$|\/index$/,"").replace(/\[([^\]]+)]/g,":$1")||"/"}var xe=c(()=>{"use strict"});function ye(e,t){let r=e.slice(t.length+1).replace(/\\/g,"/"),n=ve(r);return n==="/"?"/api":`/api/${n}`.replace("/api//","/api/")}var Re=c(()=>{"use strict";xe()});function pt(e,t){return"_api_"+e.slice(`${t}/`.length).replace(/\.(ts|tsx)$/,"").replace(/[^a-zA-Z0-9]/g,"_")}function we(e,t,r){return{filePath:e,urlPattern:ye(e,t),identifier:pt(e,t),methods:r}}function I(e,t){if(e.length===0)return`// auto-generado por devix \u2014 no editar
148
+ export {}
135
149
  declare module '@devlusoft/devix' {
136
150
  interface ApiRoutes {}
137
151
  }
138
- `;let r=t.map(o=>{let a="../"+o.filePath.replace(/\.(ts|tsx)$/,"");return`import type * as ${o.identifier} from '${a}'`}).join(`
139
- `),i=t.flatMap(o=>o.methods.map(a=>` '${a} ${o.urlPattern}': InferRoute<(typeof ${o.identifier})['${a}']>`)).join(`
152
+ `;let r=e.map(o=>{let a="../"+o.filePath.replace(/\.(ts|tsx)$/,"");return`import type * as ${o.identifier} from '${a}'`}).join(`
153
+ `),n=e.flatMap(o=>o.methods.map(a=>` '${a} ${o.urlPattern}': InferRoute<(typeof ${o.identifier})['${a}']>`)).join(`
140
154
  `);return`// auto-generado por devix \u2014 no editar
141
155
  ${r}
142
156
 
143
- type JsonResponse<T> = Response & { readonly __body: T }
144
- type UnwrapJson<T> = T extends JsonResponse<infer U> ? U : never
145
- type InferFnReturn<T> = T extends (...args: any[]) => any
146
- ? UnwrapJson<Awaited<ReturnType<T>>> | Exclude<Awaited<ReturnType<T>>, JsonResponse<any> | null | void | undefined>
147
- : never
157
+ type JsonResponse<T, S extends number = number> = Response & { readonly __body: T; readonly __status: S }
158
+ type Is2xx<S extends number> = [number] extends [S] ? boolean : S extends 200 | 201 | 202 | 203 | 204 | 205 | 206 ? true : false
159
+ type UnwrapSuccessJson<T> = T extends JsonResponse<infer U, infer S> ? Is2xx<S> extends false ? never : U : never
160
+ type UnwrapErrorJson<T> = T extends JsonResponse<infer U, infer S> ? Is2xx<S> extends true ? never : U : never
161
+ type InferFnSuccess<T> = T extends (...args: any[]) => any ? UnwrapSuccessJson<Awaited<ReturnType<T>>> : never
162
+ type InferFnErrors<T> = T extends (...args: any[]) => any ? UnwrapErrorJson<Awaited<ReturnType<T>>> : never
148
163
  type InferRoute<T> =
149
164
  T extends { readonly __return?: infer TReturn; readonly __body?: infer TBody }
150
165
  ? {
151
166
  __body: [TBody] extends [undefined] ? never : Exclude<TBody, undefined>
152
- __response: InferFnReturn<() => TReturn>
167
+ __response: InferFnSuccess<() => TReturn>
168
+ __errors: InferFnErrors<() => TReturn>
153
169
  }
154
- : InferFnReturn<T>
170
+ : InferFnSuccess<T>
155
171
 
156
172
  declare module '@devlusoft/devix' {
157
173
  interface ApiRoutes {
158
- ${i}
174
+ ${n}
159
175
  }
160
176
  }
161
- `}var M=s(()=>{"use strict";A()});import{readFileSync as te,readdirSync as ee,statSync as re}from"node:fs";import{join as I,relative as oe}from"node:path";function gt(t,e){let r=[];for(let i of ee(t)){let o=I(t,i);re(o).isDirectory()?r.push(...gt(o,e)):/\.(ts|tsx)$/.test(i)&&r.push(oe(e,o).replace(/\\/g,"/"))}return r}function L(t,e){let r=I(e,t,"api"),i;try{i=gt(r,e)}catch{return[]}return i.filter(o=>!o.endsWith("middleware.ts")&&!o.endsWith("middleware.tsx")).flatMap(o=>{try{let a=te(I(e,o),"utf-8"),p=dt(a);return p.length===0?[]:[ft(o,`${t}/api`,p)]}catch{return[]}})}var ht=s(()=>{"use strict";mt();M()});import{mkdirSync as ne,readFileSync as ie,writeFileSync as se,existsSync as ae}from"node:fs";import{join as xt}from"node:path";function j(t,e){let r=xt(e,".devix"),i=xt(r,"routes.d.ts");return ne(r,{recursive:!0}),ae(i)&&ie(i,"utf-8")===t?!1:(se(i,t,"utf-8"),!0)}var yt=s(()=>{"use strict"});import{mergeConfig as ce}from"vite";import le from"@vitejs/plugin-react";import{fileURLToPath as ue}from"node:url";import{dirname as pe,resolve as m}from"node:path";import{parseSync as de}from"oxc-parser";function Rt(t){let e=t.appDir??"app",r=`${e}/pages`,i=(t.css??[]).map(n=>n.startsWith("/")?n:`/${n.replace(/^\.\//,"")}`),o=m(k,"../server/render.js").replace(/\\/g,"/"),a=m(k,"../server/api.js").replace(/\\/g,"/"),p=m(k,"../runtime/client-router.js").replace(/\\/g,"/"),x={name:"devix",enforce:"pre",resolveId(n){if(n===F)return`\0${F}`;if(n===U)return`\0${U}`;if(n===H)return`\0${H}`;if(n===q)return`\0${q}`;if(n===N)return`\0${N}`},load(n){if(n===`\0${F}`)return tt({cssUrls:i});if(n===`\0${U}`)return rt({pagesDir:r,matcherPath:p});if(n===`\0${H}`)return nt({pagesDir:r,renderPath:o});if(n===`\0${q}`)return st({apiPath:a,appDir:e});if(n===`\0${N}`)return ut()},transform(n,l,y){if(y?.ssr)return;let c=m(process.cwd(),r);if(!l.startsWith(c))return;let Nt=de(l,n,{sourceType:"module"}),v=[];for(let u of Nt.program.body){if(u.type!=="ExportNamedDeclaration"||!u.declaration)continue;let d=u.declaration;if(d.type==="FunctionDeclaration"&&d.id&&vt.has(d.id.name)&&v.push({start:u.start,end:u.end,name:d.id.name}),d.type==="VariableDeclaration"){let P=new Set;for(let T of d.declarations)T.id.type==="Identifier"&&vt.has(T.id.name)&&(P.has(u.start)||(P.add(u.start),v.push({start:u.start,end:u.end,name:T.id.name})))}}if(v.length===0)return;v.sort((u,d)=>d.start-u.start);let E=n;for(let{start:u,end:d,name:P}of v)E=E.slice(0,u)+`export const ${P} = undefined`+E.slice(d);return{code:E,map:null}},buildStart(){let n=process.cwd(),l=L(e,n);j(O(l,`${e}/api`),n)},configureServer(n){let l=process.cwd(),y=()=>{let c=L(e,l);j(O(c,`${e}/api`),l)};n.watcher.add(m(l,"devix.config.ts")),n.watcher.on("change",c=>{c===m(l,"devix.config.ts")&&(console.log("[devix] Config changed, restarting..."),process.exit(75))}),n.watcher.on("add",c=>{c.startsWith(m(l,r))&&D(),c.includes(`${e}/api`)&&(C(),y())}),n.watcher.on("unlink",c=>{c.startsWith(m(l,r))&&D(),c.includes(`${e}/api`)&&(C(),y())}),n.watcher.on("change",c=>{c.includes(`${e}/api`)&&!c.endsWith("middleware.ts")&&y()})}},g={plugins:[le(),x],publicDir:m(process.cwd(),t.publicDir??"public"),ssr:{noExternal:["@devlusoft/devix"]},...t.envPrefix?{envPrefix:t.envPrefix}:{}};return ce(g,t.vite??{})}var k,F,U,H,q,N,vt,wt=s(()=>{"use strict";et();ot();it();at();ct();A();pt();ht();M();yt();k=pe(ue(import.meta.url)),F="virtual:devix/entry-client",U="virtual:devix/client-routes",H="virtual:devix/render",q="virtual:devix/api",N="virtual:devix/context",vt=new Set(["loader","guard","generateStaticParams","headers"])});function _t(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}}var Et=s(()=>{"use strict"});import{build as me}from"esbuild";import{join as Pt}from"node:path";import{tmpdir as fe}from"node:os";import{unlinkSync as ge,writeFileSync as he}from"node:fs";import{pathToFileURL as xe}from"node:url";async function S(t){let e=await me({entryPoints:[Pt(t,"devix.config.ts")],bundle:!0,write:!1,format:"esm",platform:"node",packages:"external"}),r=Pt(fe(),`devix-config-${Date.now()}.mjs`);he(r,e.outputFiles[0].text);try{return(await import(xe(r).href)).default}finally{ge(r)}}var V=s(()=>{"use strict"});var $t={};import{writeFileSync as ye}from"node:fs";import{resolve as ve}from"node:path";import{build as St}from"vite";var R,Tt,Re,B=s(async()=>{"use strict";wt();Et();V();R=await S(process.cwd()),Tt=Rt(R);await St({...Tt,configFile:!1,build:{outDir:"dist/client",manifest:!0,rolldownOptions:{input:"virtual:devix/entry-client"}}});await St({...Tt,configFile:!1,build:{ssr:!0,outDir:"dist/server",copyPublicDir:!1,rolldownOptions:{input:{render:"virtual:devix/render",api:"virtual:devix/api"}}}});Re={port:R.port??3e3,host:R.host??!1,loaderTimeout:_t(R.loaderTimeout??1e4),output:R.output??"server"};ye(ve(process.cwd(),"dist/devix.config.json"),JSON.stringify(Re,null,2),"utf-8")});var Se={};import{readFileSync as we,mkdirSync as bt,writeFileSync as Dt,rmSync as _e}from"node:fs";import{resolve as X,join as h}from"node:path";import{pathToFileURL as Ee}from"node:url";var At,Pe,J,Ct,W,Ot=s(async()=>{"use strict";V();At=await S(process.cwd());At.output!=="static"&&console.warn('[devix] Tip: set output: "static" in devix.config.ts to skip the SSR server at runtime.');await B().then(()=>$t);Pe=Date.now(),J=await import(Ee(X(process.cwd(),"dist/server/render.js")).href+`?t=${Pe}`),Ct=JSON.parse(we(X(process.cwd(),"dist/client/.vite/manifest.json"),"utf-8")),W=await J.getStaticRoutes();console.log(`[devix] Generating ${W.length} static page${W.length===1?"":"s"}...`);for(let t of W){let e=`http://localhost${t}`,{html:r,statusCode:i}=await J.render(e,new Request(e),{manifest:Ct});if(i!==200){console.warn(`[devix] Skipping ${t} \u2014 status ${i}`);continue}let o=t==="/"?h(process.cwd(),"dist/client/index.html"):h(process.cwd(),"dist/client",t,"index.html");bt(h(o,".."),{recursive:!0}),Dt(o,`<!DOCTYPE html>${r}`,"utf-8");let a=await J.runLoader(e,new Request(e),{manifest:Ct}),p=t==="/"?h(process.cwd(),"dist/client/_data/index.json"):h(process.cwd(),"dist/client/_data",`${t}.json`);bt(h(p,".."),{recursive:!0}),Dt(p,JSON.stringify(a),"utf-8"),console.log(` \u2713 ${t}`)}console.log("[devix] Generation complete.");At.output==="static"&&(_e(X(process.cwd(),"dist/server"),{recursive:!0,force:!0}),console.log("[devix] Removed dist/server (not needed in static mode)"))});function Mt(t,{apiModule:e,renderModule:r,loaderTimeout:i}){t.all("/api/*",async o=>{try{return await e.handleApiRequest(o.req.url,o.req.raw)}catch(a){return console.error(a),o.json({error:"internal error"},500)}}),t.get("/_data/*",async o=>{try{let{pathname:a,search:p}=new URL(o.req.url,"http://localhost"),x=a.replace(/^\/_data/,"")+p,g=await r.runLoader(x,o.req.raw,{loaderTimeout:i});return g.error?o.json({error:"internal error"},500):o.json(g)}catch(a){return console.error(a),o.json({error:"internal error"},500)}})}function It(t,{renderModule:e,manifest:r,loaderTimeout:i}){t.get("*",async o=>{try{let{html:a,statusCode:p,headers:x}=await e.render(o.req.url,o.req.raw,{manifest:r,loaderTimeout:i}),g=o.html(`<!DOCTYPE html>${a}`,p);for(let[n,l]of Object.entries(x))g.headers.set(n,l);return g}catch(a){return console.error(a),o.text("Internal Server Error",500)}})}var Lt=s(()=>{"use strict"});import{loadEnv as Te}from"vite";function jt(t){let e=Te(t,process.cwd(),"");for(let[r,i]of Object.entries(e))process.env[r]===void 0&&(process.env[r]=i)}var kt=s(()=>{"use strict"});var Oe={};import{readFileSync as G}from"node:fs";import{serve as $e}from"@hono/node-server";import{serveStatic as be}from"@hono/node-server/serve-static";import{Hono as De}from"hono";import{resolve as Ft,join as w}from"node:path";import{pathToFileURL as Ut}from"node:url";var Y,z,Z,f,Ce,Ae,_,K,Ht=s(async()=>{"use strict";Lt();kt();jt("production");try{f=JSON.parse(G(w(process.cwd(),"dist/devix.config.json"),"utf-8")),f.output!=="static"&&(Y=await import(Ut(Ft(process.cwd(),"dist/server/render.js")).href),z=await import(Ut(Ft(process.cwd(),"dist/server/api.js")).href)),Z=JSON.parse(G(w(process.cwd(),"dist/client/.vite/manifest.json"),"utf-8"))}catch{console.error('[devix] Build not found. Run "devix build" first.'),process.exit(1)}Ce=Number(process.env.PORT)||f.port||3e3,Ae=typeof f.host=="string"?f.host:f.host?"0.0.0.0":process.env.HOST||"0.0.0.0",_=new De,K=w(process.cwd(),"dist/client");f.output==="static"&&_.get("/_data/*",t=>{let e=t.req.path.replace(/^\/_data/,"")||"/",r=e==="/"?w(K,"_data/index.json"):w(K,"_data",`${e}.json`);try{let i=G(r,"utf-8");return t.json(JSON.parse(i))}catch{return t.json({error:"not found"},404)}});_.use("/*",be({root:K,onFound:(t,e)=>{e.header("Cache-Control",t.includes("/assets/")?"public, immutable, max-age=31536000":"no-cache")}}));f.output==="static"?console.log("[devix] Static mode \u2014 serving pre-generated files from dist/client"):(Mt(_,{renderModule:Y,apiModule:z,manifest:Z}),It(_,{renderModule:Y,apiModule:z,manifest:Z,loaderTimeout:f.loaderTimeout}));$e({fetch:_.fetch,port:Ce,hostname:Ae},t=>console.log(`http://${t.address}:${t.port}`))});var qt=process.argv[2];switch(qt){case"dev":await Promise.resolve().then(()=>(Q(),Gt));break;case"build":await B().then(()=>$t);break;case"generate":await Ot().then(()=>Se);break;case"start":await Ht().then(()=>Oe);break;case"--version":case"-v":{console.log("0.4.1-beta.8");break}case"--help":case"-h":console.log(`
177
+ `}var L=c(()=>{"use strict";Re()});import{readFileSync as mt,readdirSync as ft,statSync as gt}from"node:fs";import{join as U,relative as ht}from"node:path";function _e(e,t){let r=[];for(let n of ft(e)){let o=U(e,n);gt(o).isDirectory()?r.push(..._e(o,t)):/\.(ts|tsx)$/.test(n)&&r.push(ht(t,o).replace(/\\/g,"/"))}return r}function k(e,t){let r=U(t,e,"api"),n;try{n=_e(r,t)}catch{return[]}return n.filter(o=>!o.endsWith("middleware.ts")&&!o.endsWith("middleware.tsx")).flatMap(o=>{try{let a=mt(U(t,o),"utf-8"),d=ge(a);return d.length===0?[]:[we(o,`${e}/api`,d)]}catch{return[]}})}var Se=c(()=>{"use strict";he();L()});import{mkdirSync as vt,readFileSync as xt,writeFileSync as yt,existsSync as Rt}from"node:fs";import{join as Ee}from"node:path";function N(e,t){let r=Ee(t,".devix"),n=Ee(r,"routes.d.ts");return vt(r,{recursive:!0}),Rt(n)&&xt(n,"utf-8")===e?!1:(yt(n,e,"utf-8"),!0)}var Pe=c(()=>{"use strict"});function Te({routesPath:e,envPath:t,honoServerPath:r,honoServerStaticPath:n,honoPath:o}){return`
178
+ import { readFileSync } from 'node:fs'
179
+ import { serve } from '${r}'
180
+ import { serveStatic } from '${n}'
181
+ import { Hono } from '${o}'
182
+ import { resolve, join, dirname } from 'node:path'
183
+ import { pathToFileURL } from 'node:url'
184
+ import { registerApiRoutes, registerSsrRoute } from '${e}'
185
+ import { loadDotenv } from '${t}'
186
+
187
+ loadDotenv('production')
188
+
189
+ const __dir = dirname(process.argv[1])
190
+
191
+ let renderModule, apiModule, manifest, runtimeConfig
192
+
193
+ try {
194
+ runtimeConfig = JSON.parse(readFileSync(resolve(__dir, '../devix.config.json'), 'utf-8'))
195
+ if (runtimeConfig.output !== 'static') {
196
+ renderModule = await import(pathToFileURL(resolve(__dir, 'render.js')).href)
197
+ apiModule = await import(pathToFileURL(resolve(__dir, 'api.js')).href)
198
+ }
199
+ manifest = JSON.parse(readFileSync(resolve(__dir, '../client/.vite/manifest.json'), 'utf-8'))
200
+ } catch {
201
+ console.error('[devix] Build not found. Run "devix build" first.')
202
+ process.exit(1)
203
+ }
204
+
205
+ const port = Number(process.env.PORT) || runtimeConfig.port || 3000
206
+ const host = typeof runtimeConfig.host === 'string'
207
+ ? runtimeConfig.host
208
+ : runtimeConfig.host ? '0.0.0.0' : (process.env.HOST || '0.0.0.0')
209
+
210
+ const clientRoot = resolve(__dir, '../client')
211
+ const app = new Hono()
212
+
213
+ if (runtimeConfig.output === 'static') {
214
+ app.get('/_data/*', (c) => {
215
+ const pathname = c.req.path.replace(/^\\/_data/, '') || '/'
216
+ const filePath = pathname === '/'
217
+ ? join(clientRoot, '_data/index.json')
218
+ : join(clientRoot, '_data', pathname + '.json')
219
+ try {
220
+ return c.json(JSON.parse(readFileSync(filePath, 'utf-8')))
221
+ } catch {
222
+ return c.json({ error: 'not found' }, 404)
223
+ }
224
+ })
225
+ }
226
+
227
+ app.use('/*', serveStatic({
228
+ root: clientRoot,
229
+ onFound: (_path, c) => {
230
+ c.header('Cache-Control', _path.includes('/assets/')
231
+ ? 'public, immutable, max-age=31536000'
232
+ : 'no-cache')
233
+ }
234
+ }))
235
+
236
+ if (runtimeConfig.output === 'static') {
237
+ console.log('[devix] Static mode \u2014 serving pre-generated files from dist/client')
238
+ } else {
239
+ registerApiRoutes(app, { renderModule, apiModule, manifest })
240
+ registerSsrRoute(app, { renderModule, apiModule, manifest, loaderTimeout: runtimeConfig.loaderTimeout })
241
+ }
242
+
243
+ const server = serve({ fetch: app.fetch, port, hostname: host }, (info) =>
244
+ console.log(\`http://\${info.address}:\${info.port}\`))
245
+
246
+ process.on('SIGTERM', () => server.close())
247
+ process.on('SIGINT', () => server.close())
248
+ `}var $e=c(()=>{"use strict"});import{existsSync as De,mkdirSync as wt,readdirSync as _t,readFileSync as be,rmSync as St,statSync as Et,writeFileSync as Pt}from"node:fs";import{join as y,relative as Ce}from"node:path";import{parseSync as Tt}from"oxc-parser";function Ae(e,t){let r=[];for(let n of _t(e)){let o=y(e,n);Et(o).isDirectory()?r.push(...Ae(o,t)):/\.(ts|tsx)$/.test(n)&&n!=="layout.tsx"&&n!=="error.tsx"&&r.push(Ce(t,o).replace(/\\/g,"/"))}return r}function $t(e,t){let r=Tt(t,e,{sourceType:"module"});for(let n of r.program.body){if(n.type!=="ExportNamedDeclaration")continue;let o=n.declaration;if(o?.type==="FunctionDeclaration"&&o.id?.name==="loader")return!0;if(o?.type==="VariableDeclaration"){for(let a of o.declarations)if(a.id.type==="Identifier"&&a.id.name==="loader")return!0}for(let a of n.specifiers??[])if(a.exported.type==="Identifier"&&a.exported.name==="loader")return!0}return!1}function bt(e,t){return t?`// auto-generado por devix \u2014 no editar
249
+ import type { loader } from "${e}"
250
+ import type { Redirect } from "@devlusoft/devix"
251
+
252
+ export type PageData = Exclude<
253
+ Awaited<ReturnType<NonNullable<typeof loader>>>,
254
+ Redirect | void | undefined
255
+ >
256
+ export type PageParams = NonNullable<Parameters<typeof loader>[0]>["params"]
257
+ `:`// auto-generado por devix - no editar
258
+ export type PageData = undefined
259
+ export type PageParams = Record<string, string>
260
+ `}function O(e,t){let r=y(t,e),n=be(r,"utf-8"),o=$t(n,r),a=y(t,".devix","pages",e.replace(/\.(tsx?|jsx?)$/,"")),d=y(a,"$types.d.ts"),x=r.replace(/\.(tsx?|jsx?)$/,""),m=Ce(a,x).replace(/\\/g,"/"),f=bt(m,o);De(d)&&be(d,"utf-8")===f||(wt(a,{recursive:!0}),Pt(d,f,"utf-8"))}function Oe(e,t){let r=y(t,".devix","pages",e.replace(/\.(tsx?|jsx?)$/,"")),n=y(r,"$types.d.ts");De(n)&&St(n)}function H(e,t){let r=y(t,e,"pages"),n;try{n=Ae(r,t)}catch{return}for(let o of n)try{O(o,t)}catch{}}var je=c(()=>{"use strict"});import{mergeConfig as Dt}from"vite";import Ct from"@vitejs/plugin-react";import{fileURLToPath as At}from"node:url";import{dirname as Ot,relative as jt,resolve as p}from"node:path";import{createRequire as Mt}from"node:module";import{parseSync as Ft}from"oxc-parser";function Fe(e){let t=e.appDir??"app",r=`${t}/pages`,n=(e.css??[]).map(i=>i.startsWith("/")?i:`/${i.replace(/^\.\//,"")}`),o=p(P,"../server/render.js").replace(/\\/g,"/"),a=p(P,"../server/api.js").replace(/\\/g,"/"),d=p(P,"../runtime/client-router.js").replace(/\\/g,"/"),x=p(P,"../server/routes.js").replace(/\\/g,"/"),m=p(P,"../utils/env.js").replace(/\\/g,"/"),f=Mt(import.meta.url),w=f.resolve("@hono/node-server").replace(/\\/g,"/"),M=f.resolve("@hono/node-server/serve-static").replace(/\\/g,"/"),tt=f.resolve("hono").replace(/\\/g,"/"),rt={name:"devix",enforce:"pre",resolveId(i){if(i===q)return`\0${q}`;if(i===V)return`\0${V}`;if(i===T)return`\0${T}`;if(i===$)return`\0${$}`;if(i===J)return`\0${J}`;if(i===W)return`\0${W}`},load(i){if(i===`\0${q}`)return ie({cssUrls:n});if(i===`\0${V}`)return ae({pagesDir:r,matcherPath:d});if(i===`\0${T}`)return le({pagesDir:r,renderPath:o});if(i===`\0${$}`)return de({apiPath:a,appDir:t});if(i===`\0${J}`)return me();if(i===`\0${W}`)return Te({routesPath:x,envPath:m,honoServerPath:w,honoServerStaticPath:M,honoPath:tt})},transform(i,l,_){if(_?.ssr)return;let S=p(process.cwd(),r);if(!l.startsWith(S))return;let E=Ft(l,i,{sourceType:"module"}),g=[];for(let u of E.program.body){if(u.type!=="ExportNamedDeclaration"||!u.declaration)continue;let h=u.declaration;if(h.type==="FunctionDeclaration"&&h.id&&Me.has(h.id.name)&&g.push({start:u.start,end:u.end,name:h.id.name}),h.type==="VariableDeclaration"){let A=new Set;for(let F of h.declarations)F.id.type==="Identifier"&&Me.has(F.id.name)&&(A.has(u.start)||(A.add(u.start),g.push({start:u.start,end:u.end,name:F.id.name})))}}if(g.length===0)return;g.sort((u,h)=>h.start-u.start);let s=i;for(let{start:u,end:h,name:A}of g)s=s.slice(0,u)+`export const ${A} = undefined`+s.slice(h);return{code:s,map:null}},buildStart(){let i=process.cwd(),l=k(t,i);N(I(l,`${t}/api`),i),H(t,i)},configureServer(i){let l=process.cwd();H(t,l);let _=()=>{let s=k(t,l);N(I(s,`${t}/api`),l)},S=s=>s.startsWith(p(l,r))&&!s.endsWith("layout.tsx")&&!s.endsWith("error.tsx"),E=s=>jt(l,s).replace(/\\/g,"/"),g=s=>{let u=i.moduleGraph.getModuleById(`\0${s}`);u&&i.moduleGraph.invalidateModule(u)};i.watcher.add(p(l,"devix.config.ts")),i.watcher.on("change",s=>{s===p(l,"devix.config.ts")&&(console.log("[devix] Config changed, restarting..."),process.exit(75))}),i.watcher.on("add",s=>{s.startsWith(p(l,r))&&g(T),S(s)&&O(E(s),l),s.includes(`${t}/api`)&&(g($),_())}),i.watcher.on("unlink",s=>{s.startsWith(p(l,r))&&g(T),S(s)&&Oe(E(s),l),s.includes(`${t}/api`)&&(g($),_())}),i.watcher.on("change",s=>{S(s)&&O(E(s),l),s.includes(`${t}/api`)&&!s.endsWith("middleware.ts")&&_()})}},ot={plugins:[Ct(),rt],publicDir:p(process.cwd(),e.publicDir??"public"),ssr:{noExternal:["@devlusoft/devix"]},...e.envPrefix?{envPrefix:e.envPrefix}:{}};return Dt(ot,e.vite??{})}var P,q,V,T,$,J,W,Me,Ie=c(()=>{"use strict";se();ce();ue();pe();fe();Se();L();Pe();$e();je();P=Ot(At(import.meta.url)),q="virtual:devix/entry-client",V="virtual:devix/client-routes",T="virtual:devix/render",$="virtual:devix/api",J="virtual:devix/context",W="virtual:devix/server-entry",Me=new Set(["loader","guard","generateStaticParams","headers"])});function Le(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}}var Ue=c(()=>{"use strict"});import{build as It}from"esbuild";import{join as ke}from"node:path";import{unlinkSync as Lt,writeFileSync as Ut}from"node:fs";import{pathToFileURL as kt}from"node:url";async function j(e){let t=await It({entryPoints:[ke(e,"devix.config.ts")],bundle:!0,write:!1,format:"esm",platform:"node",packages:"external"}),r=ke(e,`.devix-config-${Date.now()}.mjs`);Ut(r,t.outputFiles[0].text);try{return(await import(kt(r).href)).default}finally{Lt(r)}}var B=c(()=>{"use strict"});var Ne={};import{writeFileSync as Nt}from"node:fs";import{resolve as Ht}from"node:path";import{build as G}from"vite";var b,X,qt,Y=c(async()=>{"use strict";Ie();Ue();B();b=await j(process.cwd()),X=Fe(b);await G({...X,configFile:!1,build:{outDir:"dist/client",manifest:!0,rolldownOptions:{input:"virtual:devix/entry-client"}}});await G({...X,configFile:!1,build:{ssr:!0,outDir:"dist/server",copyPublicDir:!1,rolldownOptions:{input:{render:"virtual:devix/render",api:"virtual:devix/api"}}}});await G({...X,configFile:!1,build:{ssr:!0,outDir:"dist/server",emptyOutDir:!1,copyPublicDir:!1,rolldownOptions:{input:{index:"virtual:devix/server-entry"}}}});qt={port:b.port??3e3,host:b.host??!1,loaderTimeout:Le(b.loaderTimeout??1e4),output:b.output??"server"};Nt(Ht(process.cwd(),"dist/devix.config.json"),JSON.stringify(qt,null,2),"utf-8")});var Gt={};import{readFileSync as Vt,mkdirSync as He,writeFileSync as qe,rmSync as Jt}from"node:fs";import{resolve as K,join as R}from"node:path";import{pathToFileURL as Wt}from"node:url";var Je,Bt,z,Ve,Z,We=c(async()=>{"use strict";B();Je=await j(process.cwd());Je.output!=="static"&&console.warn('[devix] Tip: set output: "static" in devix.config.ts to skip the SSR server at runtime.');await Y().then(()=>Ne);Bt=Date.now(),z=await import(Wt(K(process.cwd(),"dist/server/render.js")).href+`?t=${Bt}`),Ve=JSON.parse(Vt(K(process.cwd(),"dist/client/.vite/manifest.json"),"utf-8")),Z=await z.getStaticRoutes();console.log(`[devix] Generating ${Z.length} static page${Z.length===1?"":"s"}...`);for(let e of Z){let t=`http://localhost${e}`,{html:r,statusCode:n}=await z.render(t,new Request(t),{manifest:Ve});if(n!==200){console.warn(`[devix] Skipping ${e} \u2014 status ${n}`);continue}let o=e==="/"?R(process.cwd(),"dist/client/index.html"):R(process.cwd(),"dist/client",e,"index.html");He(R(o,".."),{recursive:!0}),qe(o,`<!DOCTYPE html>${r}`,"utf-8");let a=await z.runLoader(t,new Request(t),{manifest:Ve}),d=e==="/"?R(process.cwd(),"dist/client/_data/index.json"):R(process.cwd(),"dist/client/_data",`${e}.json`);He(R(d,".."),{recursive:!0}),qe(d,JSON.stringify(a),"utf-8"),console.log(` \u2713 ${e}`)}console.log("[devix] Generation complete.");Je.output==="static"&&(Jt(K(process.cwd(),"dist/server"),{recursive:!0,force:!0}),console.log("[devix] Removed dist/server (not needed in static mode)"))});function Be(e,{apiModule:t,renderModule:r,loaderTimeout:n}){e.all("/api/*",async o=>{try{return await t.handleApiRequest(o.req.url,o.req.raw)}catch(a){return console.error(a),o.json({error:"internal error"},500)}}),e.get("/_data/*",async o=>{try{let{pathname:a,search:d}=new URL(o.req.url,"http://localhost"),x=a.replace(/^\/_data/,"")+d,m=await r.runLoader(x,o.req.raw,{loaderTimeout:n});if(m.error)return o.json({error:"internal error"},500);if("loaderError"in m){let{statusCode:f,message:w,data:M}=m.loaderError;return o.json({statusCode:f,message:w,data:M},f)}return o.json(m)}catch(a){return console.error(a),o.json({error:"internal error"},500)}})}function Ge(e,{renderModule:t,manifest:r,loaderTimeout:n}){e.get("*",async o=>{try{let{html:a,statusCode:d,headers:x}=await t.render(o.req.url,o.req.raw,{manifest:r,loaderTimeout:n}),m=o.html(`<!DOCTYPE html>${a}`,d);for(let[f,w]of Object.entries(x))m.headers.set(f,w);return m}catch(a){return console.error(a),o.text("Internal Server Error",500)}})}var Xe=c(()=>{"use strict"});import{loadEnv as Xt}from"vite";function Ye(e){let t=Xt(e,process.cwd(),"");for(let[r,n]of Object.entries(t))process.env[r]===void 0&&(process.env[r]=n)}var ze=c(()=>{"use strict"});var er={};import{readFileSync as Q}from"node:fs";import{serve as Yt}from"@hono/node-server";import{serveStatic as zt}from"@hono/node-server/serve-static";import{Hono as Zt}from"hono";import{resolve as Ze,join as D}from"node:path";import{pathToFileURL as Ke}from"node:url";var ee,te,re,v,Kt,Qt,C,oe,Qe=c(async()=>{"use strict";Xe();ze();Ye("production");try{v=JSON.parse(Q(D(process.cwd(),"dist/devix.config.json"),"utf-8")),v.output!=="static"&&(ee=await import(Ke(Ze(process.cwd(),"dist/server/render.js")).href),te=await import(Ke(Ze(process.cwd(),"dist/server/api.js")).href)),re=JSON.parse(Q(D(process.cwd(),"dist/client/.vite/manifest.json"),"utf-8"))}catch{console.error('[devix] Build not found. Run "devix build" first.'),process.exit(1)}Kt=Number(process.env.PORT)||v.port||3e3,Qt=typeof v.host=="string"?v.host:v.host?"0.0.0.0":process.env.HOST||"0.0.0.0",C=new Zt,oe=D(process.cwd(),"dist/client");v.output==="static"&&C.get("/_data/*",e=>{let t=e.req.path.replace(/^\/_data/,"")||"/",r=t==="/"?D(oe,"_data/index.json"):D(oe,"_data",`${t}.json`);try{let n=Q(r,"utf-8");return e.json(JSON.parse(n))}catch{return e.json({error:"not found"},404)}});C.use("/*",zt({root:oe,onFound:(e,t)=>{t.header("Cache-Control",e.includes("/assets/")?"public, immutable, max-age=31536000":"no-cache")}}));v.output==="static"?console.log("[devix] Static mode \u2014 serving pre-generated files from dist/client"):(Be(C,{renderModule:ee,apiModule:te,manifest:re}),Ge(C,{renderModule:ee,apiModule:te,manifest:re,loaderTimeout:v.loaderTimeout}));Yt({fetch:C.fetch,port:Kt,hostname:Qt},e=>console.log(`http://${e.address}:${e.port}`))});var et=process.argv[2];switch(et){case"dev":await Promise.resolve().then(()=>(ne(),lt));break;case"build":await Y().then(()=>Ne);break;case"generate":await We().then(()=>Gt);break;case"start":await Qe().then(()=>er);break;case"--version":case"-v":{console.log("0.4.1");break}case"--help":case"-h":console.log(`
162
261
  devix \u2014 a lightweight SSR framework
163
262
 
164
263
  Usage:
@@ -174,5 +273,5 @@ Options:
174
273
  Output modes (set in devix.config.ts):
175
274
  output: "server" SSR mode \u2014 devix start handles requests dynamically (default)
176
275
  output: "static" SSG mode \u2014 devix generate pre-renders all pages; devix start serves static files only
177
- `.trim());break;default:console.error(`Unknown command: ${qt}`),console.error("Usage: devix <dev|build|generate|start>"),process.exit(1)}
276
+ `.trim());break;default:console.error(`Unknown command: ${et}`),console.error("Usage: devix <dev|build|generate|start>"),process.exit(1)}
178
277
  //# sourceMappingURL=index.js.map