@devlusoft/devix 0.5.3 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- function y(r){if(r&&typeof r=="object"&&"message"in r){let e=r.message;if(typeof e=="string"&&e.length>0)return e}return null}var c=class extends Error{constructor(n,o,t,s){super(y(s)??`HTTP ${n}: ${o}`);this.status=n;this.statusText=o;this.response=t;this.body=s;this.name="FetchError"}get code(){if(this.body&&typeof this.body=="object"&&"code"in this.body){let n=this.body.code;return typeof n=="string"?n:void 0}}};function T(r,e){return x(e).test(r)}function g(r,e){if(!e||e.length===0)return!1;for(let n of e)if(T(r,n))return!0;return!1}function x(r){let e="",n=0;for(;n<r.length;){let o=r[n];if(o==="*"&&r[n+1]==="*")e+=".*",n+=2;else if(o==="*")e+="[^/]*",n+=1;else if(o===":"){for(n+=1;n<r.length&&/[a-zA-Z0-9_]/.test(r[n]);)n+=1;e+="[^/]+"}else".+?^$()|[]{}\\".includes(o)?(e+="\\"+o,n+=1):(e+=o,n+=1)}return new RegExp(`^${e}$`)}function v(r,e){if(!e)return new Proxy({},{get(o,t){throw new Error(`[devix] ctx.$server.${String(t)} called but no 'server' config is defined in devix.config.ts`)}});let n=new Map;return new Proxy({},{get(o,t){if(typeof t!="string")return;let s=e[t];if(!s)throw new Error(`[devix] ctx.$server.${t} \u2014 namespace "${t}" not configured in devix.config.ts`);let i=n.get(t);return i||(i=C(t,s,r),n.set(t,i)),i}})}function C(r,e,n){async function o(t,s,i,p){if(!g(s,e.allowedPaths))throw new c(403,"Path not allowed",new Response(null,{status:403}),{statusCode:403,message:"Path not allowed",code:"PATH_NOT_ALLOWED"});if(g(s,e.deniedPaths))throw new c(403,"Path denied",new Response(null,{status:403}),{statusCode:403,message:"Path denied",code:"PATH_DENIED"});let h=new URL(s,e.url),l=new Headers(p?.headers);if(e.prepare){let f={request:n,headers:l,url:h},u=await e.prepare(f);if(u instanceof Response)throw new c(u.status,u.statusText,u,await E(u))}let d;i!=null&&t!=="GET"&&t!=="HEAD"&&(i instanceof FormData||i instanceof Blob||i instanceof ArrayBuffer?d=i:(d=JSON.stringify(i),l.has("Content-Type")||l.set("Content-Type","application/json")));let a=await fetch(h,{method:t,headers:l,body:d,signal:p?.signal}),w=a.status===204||a.headers.get("Content-Length")==="0";if(!a.ok){let f=a.headers.get("Content-Type")??"",u;if(!w&&f.includes("application/json"))try{u=await a.json()}catch{}throw new c(a.status,a.statusText,a,u)}return w?null:(a.headers.get("Content-Type")??"").includes("application/json")?await a.json():await a.text()}return{get:((t,s)=>o("GET",t,void 0,s)),post:((t,s,i)=>o("POST",t,s,i)),put:((t,s,i)=>o("PUT",t,s,i)),patch:((t,s,i)=>o("PATCH",t,s,i)),delete:((t,s)=>o("DELETE",t,void 0,s))}}async function E(r){if((r.headers.get("Content-Type")??"").includes("application/json"))try{return await r.json()}catch{return}}export{v as makeBoundServer};
1
+ function T(r){if(r&&typeof r=="object"&&"message"in r){let n=r.message;if(typeof n=="string"&&n.length>0)return n}return null}var w=Symbol.for("@devlusoft/devix.FetchError"),u=class extends Error{constructor(e,i,t,s){super(T(s)??`HTTP ${e}: ${i}`);this.status=e;this.statusText=i;this.response=t;this.body=s;this.name="FetchError",this[w]=!0}static[Symbol.hasInstance](e){return e!==null&&typeof e=="object"&&e[w]===!0}get code(){if(this.body&&typeof this.body=="object"&&"code"in this.body){let e=this.body.code;return typeof e=="string"?e:void 0}}};function x(r,n){return E(n).test(r)}function g(r,n){if(!n||n.length===0)return!1;for(let e of n)if(x(r,e))return!0;return!1}function E(r){let n="",e=0;for(;e<r.length;){let i=r[e];if(i==="*"&&r[e+1]==="*")n+=".*",e+=2;else if(i==="*")n+="[^/]*",e+=1;else if(i===":"){for(e+=1;e<r.length&&/[a-zA-Z0-9_]/.test(r[e]);)e+=1;n+="[^/]+"}else".+?^$()|[]{}\\".includes(i)?(n+="\\"+i,e+=1):(n+=i,e+=1)}return new RegExp(`^${n}$`)}function A(r,n){if(!n)return new Proxy({},{get(i,t){throw new Error(`[devix] ctx.$server.${String(t)} called but no 'server' config is defined in devix.config.ts`)}});let e=new Map;return new Proxy({},{get(i,t){if(typeof t!="string")return;let s=n[t];if(!s)throw new Error(`[devix] ctx.$server.${t} \u2014 namespace "${t}" not configured in devix.config.ts`);let o=e.get(t);return o||(o=C(t,s,r),e.set(t,o)),o}})}function C(r,n,e){async function i(t,s,o,p){if(!g(s,n.allowedPaths))throw new u(403,"Path not allowed",new Response(null,{status:403}),{statusCode:403,message:"Path not allowed",code:"PATH_NOT_ALLOWED"});if(g(s,n.deniedPaths))throw new u(403,"Path denied",new Response(null,{status:403}),{statusCode:403,message:"Path denied",code:"PATH_DENIED"});let h=new URL(s,n.url),l=new Headers(p?.headers);if(n.prepare){let f={request:e,headers:l,url:h},c=await n.prepare(f);if(c instanceof Response)throw new u(c.status,c.statusText,c,await P(c))}let d;o!=null&&t!=="GET"&&t!=="HEAD"&&(o instanceof FormData||o instanceof Blob||o instanceof ArrayBuffer?d=o:(d=JSON.stringify(o),l.has("Content-Type")||l.set("Content-Type","application/json")));let a=await fetch(h,{method:t,headers:l,body:d,signal:p?.signal}),y=a.status===204||a.headers.get("Content-Length")==="0";if(!a.ok){let f=a.headers.get("Content-Type")??"",c;if(!y&&f.includes("application/json"))try{c=await a.json()}catch{}throw new u(a.status,a.statusText,a,c)}return y?null:(a.headers.get("Content-Type")??"").includes("application/json")?await a.json():await a.text()}return{get:((t,s)=>i("GET",t,void 0,s)),post:((t,s,o)=>i("POST",t,s,o)),put:((t,s,o)=>i("PUT",t,s,o)),patch:((t,s,o)=>i("PATCH",t,s,o)),delete:((t,s)=>i("DELETE",t,void 0,s))}}async function P(r){if((r.headers.get("Content-Type")??"").includes("application/json"))try{return await r.json()}catch{return}}export{A as makeBoundServer};
2
2
  //# sourceMappingURL=server-bound.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/runtime/fetch.ts", "../../src/utils/glob.ts", "../../src/server/server-bound.ts"],
4
- "sourcesContent": ["export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS'\n\nfunction extractMessage(body: unknown): string | null {\n if (body && typeof body === 'object' && 'message' in body) {\n const m = (body as {message: unknown}).message\n if (typeof m === 'string' && m.length > 0) return m\n }\n return null\n}\n\nexport class FetchError<E = unknown> extends Error {\n constructor(\n public readonly status: number,\n public readonly statusText: string,\n public readonly response: Response,\n public readonly body?: E,\n ) {\n super(extractMessage(body) ?? `HTTP ${status}: ${statusText}`)\n this.name = 'FetchError'\n }\n\n get code(): string | undefined {\n if (this.body && typeof this.body === 'object' && 'code' in this.body) {\n const c = (this.body as {code: unknown}).code\n return typeof c === 'string' ? c : undefined\n }\n return undefined\n }\n}\n", "/**\n * Match simple de path contra un glob estilo `'/v1/**'`, `'/v1/users/*'`, `'/v1/users/:id'`.\n *\n * Reglas:\n * - `**` matchea cualquier subpath (incluye `/`).\n * - `*` matchea un \u00FAnico segmento (sin `/`).\n * - `:param` matchea un \u00FAnico segmento.\n * - Cualquier otro caracter es literal.\n */\nexport function matchPathGlob(path: string, pattern: string): boolean {\n const regex = globToRegex(pattern)\n return regex.test(path)\n}\n\nexport function matchesAnyGlob(path: string, patterns: readonly string[] | undefined): boolean {\n if (!patterns || patterns.length === 0) return false\n for (const pattern of patterns) {\n if (matchPathGlob(path, pattern)) return true\n }\n return false\n}\n\nfunction globToRegex(pattern: string): RegExp {\n let regex = ''\n let i = 0\n while (i < pattern.length) {\n const c = pattern[i]\n if (c === '*' && pattern[i + 1] === '*') {\n regex += '.*'\n i += 2\n } else if (c === '*') {\n regex += '[^/]*'\n i += 1\n } else if (c === ':') {\n i += 1\n while (i < pattern.length && /[a-zA-Z0-9_]/.test(pattern[i])) i += 1\n regex += '[^/]+'\n } else if ('.+?^$()|[]{}\\\\'.includes(c)) {\n regex += '\\\\' + c\n i += 1\n } else {\n regex += c\n i += 1\n }\n }\n return new RegExp(`^${regex}$`)\n}\n", "import {FetchError, type HttpMethod} from '../runtime/fetch'\nimport {matchesAnyGlob} from '../utils/glob'\nimport type {ServerBackendConfig, PrepareContext} from '../config'\nimport type {BackendClient} from '../runtime/server-client'\n\n/**\n * Construye un `$server` server-side bound al request del usuario.\n *\n * Diferencias clave vs el `$server` cliente:\n * - Hace fetch directo a `backend.url + path` (sin pasar por el proxy interno).\n * - Aplica `prepare` con el `Request` del loader/handler para que pueda leer cookies.\n * - Aplica allowlist/denylist por simetr\u00EDa con el proxy cliente.\n */\nexport function makeBoundServer(\n request: Request,\n config: Record<string, ServerBackendConfig> | undefined,\n): Record<string, BackendClient> {\n if (!config) return new Proxy({} as any, {\n get(_t, namespace: string) {\n throw new Error(`[devix] ctx.$server.${String(namespace)} called but no 'server' config is defined in devix.config.ts`)\n },\n })\n\n const cache = new Map<string, BackendClient>()\n return new Proxy({} as any, {\n get(_t, namespace: string) {\n if (typeof namespace !== 'string') return undefined\n const backend = config[namespace]\n if (!backend) {\n throw new Error(`[devix] ctx.$server.${namespace} \u2014 namespace \"${namespace}\" not configured in devix.config.ts`)\n }\n let client = cache.get(namespace)\n if (!client) {\n client = makeBackendClientBound(namespace, backend, request)\n cache.set(namespace, client)\n }\n return client\n },\n })\n}\n\nfunction makeBackendClientBound(\n _namespace: string,\n backend: ServerBackendConfig,\n userRequest: Request,\n): BackendClient {\n async function call<TResult>(method: HttpMethod, path: string, body?: unknown, options?: {headers?: HeadersInit; signal?: AbortSignal}): Promise<TResult> {\n if (!matchesAnyGlob(path, backend.allowedPaths)) {\n throw new FetchError(403, 'Path not allowed', new Response(null, {status: 403}), {\n statusCode: 403, message: 'Path not allowed', code: 'PATH_NOT_ALLOWED',\n })\n }\n if (matchesAnyGlob(path, backend.deniedPaths)) {\n throw new FetchError(403, 'Path denied', new Response(null, {status: 403}), {\n statusCode: 403, message: 'Path denied', code: 'PATH_DENIED',\n })\n }\n\n const targetUrl = new URL(path, backend.url)\n const headers = new Headers(options?.headers)\n if (backend.prepare) {\n const ctx: PrepareContext = {request: userRequest, headers, url: targetUrl}\n const result = await backend.prepare(ctx)\n if (result instanceof Response) {\n throw new FetchError(\n result.status,\n result.statusText,\n result,\n await readErrorBody(result),\n )\n }\n }\n\n let sendBody: BodyInit | undefined\n if (body !== undefined && body !== null && method !== 'GET' && method !== 'HEAD') {\n if (body instanceof FormData || body instanceof Blob || body instanceof ArrayBuffer) {\n sendBody = body\n } else {\n sendBody = JSON.stringify(body)\n if (!headers.has('Content-Type')) headers.set('Content-Type', 'application/json')\n }\n }\n\n const response = await fetch(targetUrl, {method, headers, body: sendBody, signal: options?.signal})\n const isEmpty = response.status === 204 || response.headers.get('Content-Length') === '0'\n\n if (!response.ok) {\n const ct = response.headers.get('Content-Type') ?? ''\n let errorBody: unknown\n if (!isEmpty && ct.includes('application/json')) {\n try { errorBody = await response.json() } catch { /* body inv\u00E1lido */ }\n }\n throw new FetchError(response.status, response.statusText, response, errorBody)\n }\n\n if (isEmpty) return null as TResult\n\n const ct = response.headers.get('Content-Type') ?? ''\n if (ct.includes('application/json')) return await response.json() as TResult\n return await response.text() as unknown as TResult\n }\n\n return {\n get: ((path: string, options?: any) => call('GET', path, undefined, options)) as BackendClient['get'],\n post: ((path: string, body?: any, options?: any) => call('POST', path, body, options)) as BackendClient['post'],\n put: ((path: string, body?: any, options?: any) => call('PUT', path, body, options)) as BackendClient['put'],\n patch: ((path: string, body?: any, options?: any) => call('PATCH', path, body, options)) as BackendClient['patch'],\n delete: ((path: string, options?: any) => call('DELETE', path, undefined, options)) as BackendClient['delete'],\n }\n}\n\nasync function readErrorBody(res: Response): Promise<unknown> {\n const ct = res.headers.get('Content-Type') ?? ''\n if (ct.includes('application/json')) {\n try { return await res.json() } catch { return undefined }\n }\n return undefined\n}\n"],
5
- "mappings": "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",
6
- "names": ["extractMessage", "body", "m", "FetchError", "status", "statusText", "response", "c", "matchPathGlob", "path", "pattern", "globToRegex", "matchesAnyGlob", "patterns", "regex", "i", "c", "makeBoundServer", "request", "config", "_t", "namespace", "cache", "backend", "client", "makeBackendClientBound", "_namespace", "userRequest", "call", "method", "path", "body", "options", "matchesAnyGlob", "FetchError", "targetUrl", "headers", "ctx", "result", "readErrorBody", "sendBody", "response", "isEmpty", "ct", "errorBody", "res"]
4
+ "sourcesContent": ["export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS'\n\nfunction extractMessage(body: unknown): string | null {\n if (body && typeof body === 'object' && 'message' in body) {\n const m = (body as {message: unknown}).message\n if (typeof m === 'string' && m.length > 0) return m\n }\n return null\n}\n\nconst FETCH_ERROR_BRAND = Symbol.for('@devlusoft/devix.FetchError')\n\nexport class FetchError<E = unknown> extends Error {\n static [Symbol.hasInstance](value: unknown): boolean {\n return value !== null && typeof value === 'object' && (value as any)[FETCH_ERROR_BRAND] === true\n }\n\n constructor(\n public readonly status: number,\n public readonly statusText: string,\n public readonly response: Response,\n public readonly body?: E,\n ) {\n super(extractMessage(body) ?? `HTTP ${status}: ${statusText}`)\n this.name = 'FetchError'\n ;(this as any)[FETCH_ERROR_BRAND] = true\n }\n\n get code(): string | undefined {\n if (this.body && typeof this.body === 'object' && 'code' in this.body) {\n const c = (this.body as {code: unknown}).code\n return typeof c === 'string' ? c : undefined\n }\n return undefined\n }\n}\n", "/**\n * Match simple de path contra un glob estilo `'/v1/**'`, `'/v1/users/*'`, `'/v1/users/:id'`.\n *\n * Reglas:\n * - `**` matchea cualquier subpath (incluye `/`).\n * - `*` matchea un \u00FAnico segmento (sin `/`).\n * - `:param` matchea un \u00FAnico segmento.\n * - Cualquier otro caracter es literal.\n */\nexport function matchPathGlob(path: string, pattern: string): boolean {\n const regex = globToRegex(pattern)\n return regex.test(path)\n}\n\nexport function matchesAnyGlob(path: string, patterns: readonly string[] | undefined): boolean {\n if (!patterns || patterns.length === 0) return false\n for (const pattern of patterns) {\n if (matchPathGlob(path, pattern)) return true\n }\n return false\n}\n\nfunction globToRegex(pattern: string): RegExp {\n let regex = ''\n let i = 0\n while (i < pattern.length) {\n const c = pattern[i]\n if (c === '*' && pattern[i + 1] === '*') {\n regex += '.*'\n i += 2\n } else if (c === '*') {\n regex += '[^/]*'\n i += 1\n } else if (c === ':') {\n i += 1\n while (i < pattern.length && /[a-zA-Z0-9_]/.test(pattern[i])) i += 1\n regex += '[^/]+'\n } else if ('.+?^$()|[]{}\\\\'.includes(c)) {\n regex += '\\\\' + c\n i += 1\n } else {\n regex += c\n i += 1\n }\n }\n return new RegExp(`^${regex}$`)\n}\n", "import {FetchError, type HttpMethod} from '../runtime/fetch'\nimport {matchesAnyGlob} from '../utils/glob'\nimport type {ServerBackendConfig, PrepareContext} from '../config'\nimport type {BackendClient} from '../runtime/server-client'\n\n/**\n * Construye un `$server` server-side bound al request del usuario.\n *\n * Diferencias clave vs el `$server` cliente:\n * - Hace fetch directo a `backend.url + path` (sin pasar por el proxy interno).\n * - Aplica `prepare` con el `Request` del loader/handler para que pueda leer cookies.\n * - Aplica allowlist/denylist por simetr\u00EDa con el proxy cliente.\n */\nexport function makeBoundServer(\n request: Request,\n config: Record<string, ServerBackendConfig> | undefined,\n): Record<string, BackendClient> {\n if (!config) return new Proxy({} as any, {\n get(_t, namespace: string) {\n throw new Error(`[devix] ctx.$server.${String(namespace)} called but no 'server' config is defined in devix.config.ts`)\n },\n })\n\n const cache = new Map<string, BackendClient>()\n return new Proxy({} as any, {\n get(_t, namespace: string) {\n if (typeof namespace !== 'string') return undefined\n const backend = config[namespace]\n if (!backend) {\n throw new Error(`[devix] ctx.$server.${namespace} \u2014 namespace \"${namespace}\" not configured in devix.config.ts`)\n }\n let client = cache.get(namespace)\n if (!client) {\n client = makeBackendClientBound(namespace, backend, request)\n cache.set(namespace, client)\n }\n return client\n },\n })\n}\n\nfunction makeBackendClientBound(\n _namespace: string,\n backend: ServerBackendConfig,\n userRequest: Request,\n): BackendClient {\n async function call<TResult>(method: HttpMethod, path: string, body?: unknown, options?: {headers?: HeadersInit; signal?: AbortSignal}): Promise<TResult> {\n if (!matchesAnyGlob(path, backend.allowedPaths)) {\n throw new FetchError(403, 'Path not allowed', new Response(null, {status: 403}), {\n statusCode: 403, message: 'Path not allowed', code: 'PATH_NOT_ALLOWED',\n })\n }\n if (matchesAnyGlob(path, backend.deniedPaths)) {\n throw new FetchError(403, 'Path denied', new Response(null, {status: 403}), {\n statusCode: 403, message: 'Path denied', code: 'PATH_DENIED',\n })\n }\n\n const targetUrl = new URL(path, backend.url)\n const headers = new Headers(options?.headers)\n if (backend.prepare) {\n const ctx: PrepareContext = {request: userRequest, headers, url: targetUrl}\n const result = await backend.prepare(ctx)\n if (result instanceof Response) {\n throw new FetchError(\n result.status,\n result.statusText,\n result,\n await readErrorBody(result),\n )\n }\n }\n\n let sendBody: BodyInit | undefined\n if (body !== undefined && body !== null && method !== 'GET' && method !== 'HEAD') {\n if (body instanceof FormData || body instanceof Blob || body instanceof ArrayBuffer) {\n sendBody = body\n } else {\n sendBody = JSON.stringify(body)\n if (!headers.has('Content-Type')) headers.set('Content-Type', 'application/json')\n }\n }\n\n const response = await fetch(targetUrl, {method, headers, body: sendBody, signal: options?.signal})\n const isEmpty = response.status === 204 || response.headers.get('Content-Length') === '0'\n\n if (!response.ok) {\n const ct = response.headers.get('Content-Type') ?? ''\n let errorBody: unknown\n if (!isEmpty && ct.includes('application/json')) {\n try { errorBody = await response.json() } catch { /* body inv\u00E1lido */ }\n }\n throw new FetchError(response.status, response.statusText, response, errorBody)\n }\n\n if (isEmpty) return null as TResult\n\n const ct = response.headers.get('Content-Type') ?? ''\n if (ct.includes('application/json')) return await response.json() as TResult\n return await response.text() as unknown as TResult\n }\n\n return {\n get: ((path: string, options?: any) => call('GET', path, undefined, options)) as BackendClient['get'],\n post: ((path: string, body?: any, options?: any) => call('POST', path, body, options)) as BackendClient['post'],\n put: ((path: string, body?: any, options?: any) => call('PUT', path, body, options)) as BackendClient['put'],\n patch: ((path: string, body?: any, options?: any) => call('PATCH', path, body, options)) as BackendClient['patch'],\n delete: ((path: string, options?: any) => call('DELETE', path, undefined, options)) as BackendClient['delete'],\n }\n}\n\nasync function readErrorBody(res: Response): Promise<unknown> {\n const ct = res.headers.get('Content-Type') ?? ''\n if (ct.includes('application/json')) {\n try { return await res.json() } catch { return undefined }\n }\n return undefined\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["extractMessage", "body", "m", "FETCH_ERROR_BRAND", "FetchError", "status", "statusText", "response", "value", "c", "matchPathGlob", "path", "pattern", "globToRegex", "matchesAnyGlob", "patterns", "regex", "i", "c", "makeBoundServer", "request", "config", "_t", "namespace", "cache", "backend", "client", "makeBackendClientBound", "_namespace", "userRequest", "call", "method", "path", "body", "options", "matchesAnyGlob", "FetchError", "targetUrl", "headers", "ctx", "result", "readErrorBody", "sendBody", "response", "isEmpty", "ct", "errorBody", "res"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import o from"picocolors";import{networkInterfaces as r}from"node:os";function s(e){let l=r();for(let n of Object.values(l))for(let t of n??[])if(t.family==="IPv4"&&!t.internal)return`http://${t.address}:${e}/`;return null}function $(e){let l="0.5.3",n=s(e);console.log(),console.log(` ${o.bold(o.yellow("devix"))} ${o.dim(`v${l}`)}`),console.log(),console.log(` ${o.green("\u279C")} ${o.bold("Local:")} ${o.cyan(`http://localhost:${e}/`)}`),console.log(n?` ${o.green("\u279C")} ${o.bold("Network:")} ${o.cyan(n)}`:` ${o.green("\u279C")} ${o.bold("Network:")} ${o.dim("use --host to expose")}`),console.log()}export{$ as printDevBanner};
1
+ import o from"picocolors";import{networkInterfaces as r}from"node:os";function s(e){let l=r();for(let n of Object.values(l))for(let t of n??[])if(t.family==="IPv4"&&!t.internal)return`http://${t.address}:${e}/`;return null}function $(e){let l="0.5.5",n=s(e);console.log(),console.log(` ${o.bold(o.yellow("devix"))} ${o.dim(`v${l}`)}`),console.log(),console.log(` ${o.green("\u279C")} ${o.bold("Local:")} ${o.cyan(`http://localhost:${e}/`)}`),console.log(n?` ${o.green("\u279C")} ${o.bold("Network:")} ${o.cyan(n)}`:` ${o.green("\u279C")} ${o.bold("Network:")} ${o.dim("use --host to expose")}`),console.log()}export{$ as printDevBanner};
2
2
  //# sourceMappingURL=banner.js.map
@@ -1,5 +1,5 @@
1
- function o({cssUrls:t}){return`
2
- ${t.map(a=>`import '${a}'`).join(`
1
+ function r({cssUrls:t}){return`
2
+ ${t.map(e=>`import '${e}'`).join(`
3
3
  `)}
4
4
  import "@vitejs/plugin-react/preamble"
5
5
  import React from "react"
@@ -25,6 +25,9 @@ if (!window.__DEVIX__) {
25
25
  const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()
26
26
  createRoot(root).render(
27
27
  React.createElement(RouterProvider, {
28
+ matchClientRoute,
29
+ loadErrorPage,
30
+ getDefaultErrorPage,
28
31
  clientEntry,
29
32
  initialData: null,
30
33
  initialParams: {},
@@ -41,6 +44,9 @@ if (!window.__DEVIX__) {
41
44
  hydrateRoot(
42
45
  root,
43
46
  React.createElement(RouterProvider, {
47
+ matchClientRoute,
48
+ loadErrorPage,
49
+ getDefaultErrorPage,
44
50
  clientEntry,
45
51
  initialData: loaderData,
46
52
  initialParams: matched.params,
@@ -64,6 +70,9 @@ if (!window.__DEVIX__) {
64
70
  const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()
65
71
  createRoot(root).render(
66
72
  React.createElement(RouterProvider, {
73
+ matchClientRoute,
74
+ loadErrorPage,
75
+ getDefaultErrorPage,
67
76
  clientEntry,
68
77
  initialData: null,
69
78
  initialParams: {},
@@ -77,5 +86,5 @@ if (!window.__DEVIX__) {
77
86
  )
78
87
  }
79
88
  }
80
- `}export{o as generateEntryClient};
89
+ `}export{r as generateEntryClient};
81
90
  //# sourceMappingURL=entry-client.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/vite/codegen/entry-client.ts"],
4
- "sourcesContent": ["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 const guardData = window.__GUARD_DATA__ ?? null\n\n const matched = matchClientRoute(window.location.pathname)\n\n if (window.__LOADER_ERROR__) {\n const {statusCode, message, code, data} = window.__LOADER_ERROR__\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 initialError: {statusCode, message, code, data},\n initialErrorPage: ErrorPage,\n })\n )\n } else 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 initialGuardData: guardData,\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}"],
5
- "mappings": "AAIO,SAASA,EAAoB,CAAE,QAAAC,CAAQ,EAA+B,CAGzE,MAAO;AAAA,EAFYA,EAAQ,IAAIC,GAAK,WAAWA,CAAC,GAAG,EAAE,KAAK;AAAA,CAAI,CAGtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CA8EZ",
4
+ "sourcesContent": ["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 const guardData = window.__GUARD_DATA__ ?? null\n\n const matched = matchClientRoute(window.location.pathname)\n\n if (window.__LOADER_ERROR__) {\n const {statusCode, message, code, data} = window.__LOADER_ERROR__\n const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()\n createRoot(root).render(\n React.createElement(RouterProvider, {\n matchClientRoute,\n loadErrorPage,\n getDefaultErrorPage,\n clientEntry,\n initialData: null,\n initialParams: {},\n initialPage: () => null,\n initialError: {statusCode, message, code, data},\n initialErrorPage: ErrorPage,\n })\n )\n } else 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 matchClientRoute,\n loadErrorPage,\n getDefaultErrorPage,\n clientEntry,\n initialData: loaderData,\n initialParams: matched.params,\n initialPage: pageMod.default,\n initialLayouts: layoutMods.map(m => m.default),\n initialLayoutsData: layoutsData,\n initialGuardData: guardData,\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 matchClientRoute,\n loadErrorPage,\n getDefaultErrorPage,\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}"],
5
+ "mappings": "AAIO,SAASA,EAAoB,CAAE,QAAAC,CAAQ,EAA+B,CAGzE,MAAO;AAAA,EAFYA,EAAQ,IAAIC,GAAK,WAAWA,CAAC,GAAG,EAAE,KAAK;AAAA,CAAI,CAGtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAuFZ",
6
6
  "names": ["generateEntryClient", "cssUrls", "u"]
7
7
  }
@@ -1,4 +1,4 @@
1
- import{mergeConfig as we}from"vite";import Te from"@vitejs/plugin-react";import{fileURLToPath as Se}from"node:url";import{dirname as $e,relative as Ae,resolve as u}from"node:path";import{createRequire as De}from"node:module";function U({cssUrls:e}){return`
1
+ import{mergeConfig as we}from"vite";import Te from"@vitejs/plugin-react";import{fileURLToPath as Se}from"node:url";import{dirname as De,relative as $e,resolve as p}from"node:path";import{createRequire as Ae}from"node:module";function U({cssUrls:e}){return`
2
2
  ${e.map(r=>`import '${r}'`).join(`
3
3
  `)}
4
4
  import "@vitejs/plugin-react/preamble"
@@ -25,6 +25,9 @@ if (!window.__DEVIX__) {
25
25
  const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()
26
26
  createRoot(root).render(
27
27
  React.createElement(RouterProvider, {
28
+ matchClientRoute,
29
+ loadErrorPage,
30
+ getDefaultErrorPage,
28
31
  clientEntry,
29
32
  initialData: null,
30
33
  initialParams: {},
@@ -41,6 +44,9 @@ if (!window.__DEVIX__) {
41
44
  hydrateRoot(
42
45
  root,
43
46
  React.createElement(RouterProvider, {
47
+ matchClientRoute,
48
+ loadErrorPage,
49
+ getDefaultErrorPage,
44
50
  clientEntry,
45
51
  initialData: loaderData,
46
52
  initialParams: matched.params,
@@ -64,6 +70,9 @@ if (!window.__DEVIX__) {
64
70
  const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()
65
71
  createRoot(root).render(
66
72
  React.createElement(RouterProvider, {
73
+ matchClientRoute,
74
+ loadErrorPage,
75
+ getDefaultErrorPage,
67
76
  clientEntry,
68
77
  initialData: null,
69
78
  initialParams: {},
@@ -145,7 +154,7 @@ export function handleApiRequest(url, request) {
145
154
  }
146
155
  `}function W(){return`
147
156
  export {RouterContext} from '@devlusoft/devix/runtime/context'
148
- `}import{readFileSync as ce,readdirSync as le,statSync as pe}from"node:fs";import{join as A,relative as ue}from"node:path";var ie=/export\s+(?:const|async\s+function|function)\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g;function se(e){return e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}function k(e){let t=new Set;for(let r of se(e).matchAll(ie))t.add(r[1]);return[...t]}function V(e){return e.replace(/\.(tsx|ts|jsx|js)$/,"").replace(/\(.*?\)\//g,"").replace(/^index$|\/index$/,"").replace(/\[([^\]]+)]/g,":$1")||"/"}function q(e,t){let r=e.slice(t.length+1).replace(/\\/g,"/"),i=V(r);return i==="/"?"/api":`/api/${i}`.replace("/api//","/api/")}function ae(e,t){return"_api_"+e.slice(`${t}/`.length).replace(/\.(ts|tsx)$/,"").replace(/[^a-zA-Z0-9]/g,"_")}function B(e,t,r){return{filePath:e,urlPattern:q(e,t),identifier:ae(e,t),methods:r}}function $(e,t){if(e.length===0)return`// auto-generado por devix \u2014 no editar
157
+ `}import{readFileSync as ce,readdirSync as le,statSync as ue}from"node:fs";import{join as $,relative as pe}from"node:path";var ie=/export\s+(?:const|async\s+function|function)\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g;function se(e){return e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}function k(e){let t=new Set;for(let r of se(e).matchAll(ie))t.add(r[1]);return[...t]}function V(e){return e.replace(/\.(tsx|ts|jsx|js)$/,"").replace(/\(.*?\)\//g,"").replace(/^index$|\/index$/,"").replace(/\[([^\]]+)]/g,":$1")||"/"}function q(e,t){let r=e.slice(t.length+1).replace(/\\/g,"/"),i=V(r);return i==="/"?"/api":`/api/${i}`.replace("/api//","/api/")}function ae(e,t){return"_api_"+e.slice(`${t}/`.length).replace(/\.(ts|tsx)$/,"").replace(/[^a-zA-Z0-9]/g,"_")}function B(e,t,r){return{filePath:e,urlPattern:q(e,t),identifier:ae(e,t),methods:r}}function D(e,t){if(e.length===0)return`// auto-generado por devix \u2014 no editar
149
158
  export {}
150
159
  declare module '@devlusoft/devix' {
151
160
  interface ApiRoutes {}
@@ -175,7 +184,7 @@ declare module '@devlusoft/devix' {
175
184
  ${i}
176
185
  }
177
186
  }
178
- `}function J(e,t){let r=[];for(let i of le(e)){let o=A(e,i);pe(o).isDirectory()?r.push(...J(o,t)):/\.(ts|tsx)$/.test(i)&&r.push(ue(t,o).replace(/\\/g,"/"))}return r}function D(e,t){let r=A(t,e,"api"),i;try{i=J(r,t)}catch{return[]}return i.filter(o=>!o.endsWith("middleware.ts")&&!o.endsWith("middleware.tsx")).flatMap(o=>{try{let a=ce(A(t,o),"utf-8"),p=k(a);return p.length===0?[]:[B(o,`${e}/api`,p)]}catch{return[]}})}import{mkdirSync as de,readFileSync as fe,writeFileSync as ge,existsSync as me}from"node:fs";import{join as G}from"node:path";function b(e,t){let r=G(t,".devix"),i=G(r,"routes.d.ts");return de(r,{recursive:!0}),me(i)&&fe(i,"utf-8")===e?!1:(ge(i,e,"utf-8"),!0)}import{parseSync as be}from"oxc-parser";function X({routesPath:e,envPath:t,honoServerPath:r,honoServerStaticPath:i,honoPath:o}){return`
187
+ `}function J(e,t){let r=[];for(let i of le(e)){let o=$(e,i);ue(o).isDirectory()?r.push(...J(o,t)):/\.(ts|tsx)$/.test(i)&&r.push(pe(t,o).replace(/\\/g,"/"))}return r}function A(e,t){let r=$(t,e,"api"),i;try{i=J(r,t)}catch{return[]}return i.filter(o=>!o.endsWith("middleware.ts")&&!o.endsWith("middleware.tsx")).flatMap(o=>{try{let a=ce($(t,o),"utf-8"),u=k(a);return u.length===0?[]:[B(o,`${e}/api`,u)]}catch{return[]}})}import{mkdirSync as de,readFileSync as fe,writeFileSync as ge,existsSync as me}from"node:fs";import{join as G}from"node:path";function C(e,t){let r=G(t,".devix"),i=G(r,"routes.d.ts");return de(r,{recursive:!0}),me(i)&&fe(i,"utf-8")===e?!1:(ge(i,e,"utf-8"),!0)}import{parseSync as Ce}from"oxc-parser";function X({routesPath:e,envPath:t,honoServerPath:r,honoServerStaticPath:i,honoPath:o}){return`
179
188
  import { readFileSync } from 'node:fs'
180
189
  import { serve } from '${r}'
181
190
  import { serveStatic } from '${i}'
@@ -254,7 +263,7 @@ import { readFileSync } from 'node:fs'
254
263
 
255
264
  process.on('SIGTERM', () => server.close())
256
265
  process.on('SIGINT', () => server.close())
257
- `}import{existsSync as z,mkdirSync as xe,readdirSync as ye,readFileSync as Y,rmSync as he,statSync as Re,writeFileSync as ve}from"node:fs";import{join as x,relative as Z}from"node:path";import{parseSync as Ee}from"oxc-parser";function K(e,t){let r=[];for(let i of ye(e)){let o=x(e,i);Re(o).isDirectory()?r.push(...K(o,t)):/\.(ts|tsx)$/.test(i)&&i!=="layout.tsx"&&i!=="error.tsx"&&r.push(Z(t,o).replace(/\\/g,"/"))}return r}function _e(e,t){let r=Ee(t,e,{sourceType:"module"});for(let i of r.program.body){if(i.type!=="ExportNamedDeclaration")continue;let o=i.declaration;if(o?.type==="FunctionDeclaration"&&o.id?.name==="loader")return{exists:!0,isAsync:o.async,isReExport:!1};if(o?.type==="VariableDeclaration"){for(let a of o.declarations)if(a.id.type==="Identifier"&&a.id.name==="loader"){let p=a.init;return{exists:!0,isAsync:p?.type==="ArrowFunctionExpression"&&p.async||p?.type==="FunctionExpression"&&p.async,isReExport:!1}}}for(let a of i.specifiers??[])if(a.exported.type==="Identifier"&&a.exported.name==="loader")return{exists:!0,isAsync:!1,isReExport:!0}}return{exists:!1,isAsync:!1,isReExport:!1}}function Pe(e,t){return t?`// auto-generado por devix \u2014 no editar
266
+ `}import{existsSync as z,mkdirSync as xe,readdirSync as he,readFileSync as Y,rmSync as ye,statSync as Re,writeFileSync as ve}from"node:fs";import{join as x,relative as Z}from"node:path";import{parseSync as Ee}from"oxc-parser";function K(e,t){let r=[];for(let i of he(e)){let o=x(e,i);Re(o).isDirectory()?r.push(...K(o,t)):/\.(ts|tsx)$/.test(i)&&i!=="layout.tsx"&&i!=="error.tsx"&&r.push(Z(t,o).replace(/\\/g,"/"))}return r}function Pe(e,t){let r=Ee(t,e,{sourceType:"module"});for(let i of r.program.body){if(i.type!=="ExportNamedDeclaration")continue;let o=i.declaration;if(o?.type==="FunctionDeclaration"&&o.id?.name==="loader")return{exists:!0,isAsync:o.async,isReExport:!1};if(o?.type==="VariableDeclaration"){for(let a of o.declarations)if(a.id.type==="Identifier"&&a.id.name==="loader"){let u=a.init;return{exists:!0,isAsync:u?.type==="ArrowFunctionExpression"&&u.async||u?.type==="FunctionExpression"&&u.async,isReExport:!1}}}for(let a of i.specifiers??[])if(a.exported.type==="Identifier"&&a.exported.name==="loader")return{exists:!0,isAsync:!1,isReExport:!0}}return{exists:!1,isAsync:!1,isReExport:!1}}function _e(e,t){return t?`// auto-generado por devix \u2014 no editar
258
267
  import type { loader } from "${e}"
259
268
  import type { Redirect } from "@devlusoft/devix"
260
269
 
@@ -266,5 +275,5 @@ export type PageParams = NonNullable<Parameters<typeof loader>[0]>["params"]
266
275
  `:`// auto-generado por devix - no editar
267
276
  export type PageData = undefined
268
277
  export type PageParams = Record<string, string>
269
- `}function C(e,t){let r=x(t,e),i=Y(r,"utf-8"),o=_e(i,r),a=[];o.exists&&!o.isAsync&&!o.isReExport&&a.push(`[devix] ${e}: 'loader' must be async. Use 'export async function loader' or 'export const loader = async (...) => ...'.`);let p=x(t,".devix","pages",e.replace(/\.(tsx?|jsx?)$/,"")),y=x(p,"$types.d.ts"),S=r.replace(/\.(tsx?|jsx?)$/,""),h=Z(p,S).replace(/\\/g,"/"),T=Pe(h,o.exists);return z(y)&&Y(y,"utf-8")===T?{warnings:a}:(xe(p,{recursive:!0}),ve(y,T,"utf-8"),{warnings:a})}function Q(e,t){let r=x(t,".devix","pages",e.replace(/\.(tsx?|jsx?)$/,"")),i=x(r,"$types.d.ts");z(i)&&he(i)}function I(e,t){let r=x(t,e,"pages"),i=[],o;try{o=K(r,t)}catch{return{warnings:i}}for(let a of o)try{let p=C(a,t);i.push(...p.warnings)}catch{}return{warnings:i}}var _=$e(Se(import.meta.url)),M="virtual:devix/entry-client",F="virtual:devix/client-routes",P="virtual:devix/render",w="virtual:devix/api",O="virtual:devix/context",L="virtual:devix/server-entry",ee=new Set(["loader","guard","generateStaticParams","headers"]);function Rt(e){let t=e.appDir??"app",r=`${t}/pages`,i=(e.css??[]).map(s=>s.startsWith("/")?s:`/${s.replace(/^\.\//,"")}`),o=u(_,"../server/render.js").replace(/\\/g,"/"),a=u(_,"../server/api.js").replace(/\\/g,"/"),p=u(_,"../runtime/client-router.js").replace(/\\/g,"/"),y=u(_,"../server/routes.js").replace(/\\/g,"/"),S=u(_,"../utils/env.js").replace(/\\/g,"/"),h=De(import.meta.url),T=h.resolve("@hono/node-server").replace(/\\/g,"/"),te=h.resolve("@hono/node-server/serve-static").replace(/\\/g,"/"),re=h.resolve("hono").replace(/\\/g,"/"),ne={name:"devix",enforce:"pre",resolveId(s){if(s===M)return`\0${M}`;if(s===F)return`\0${F}`;if(s===P)return`\0${P}`;if(s===w)return`\0${w}`;if(s===O)return`\0${O}`;if(s===L)return`\0${L}`},load(s){if(s===`\0${M}`)return U({cssUrls:i});if(s===`\0${F}`)return j({pagesDir:r,matcherPath:p});if(s===`\0${P}`)return H({pagesDir:r,renderPath:o});if(s===`\0${w}`)return N({apiPath:a,appDir:t});if(s===`\0${O}`)return W();if(s===`\0${L}`)return X({routesPath:y,envPath:S,honoServerPath:T,honoServerStaticPath:te,honoPath:re})},transform(s,c,R){if(R?.ssr)return;let m=u(process.cwd(),r);if(!c.startsWith(m))return;let v=be(c,s,{sourceType:"module"}),g=[];for(let l of v.program.body){if(l.type!=="ExportNamedDeclaration"||!l.declaration)continue;let n=l.declaration;if(n.type==="FunctionDeclaration"&&n.id&&ee.has(n.id.name)&&g.push({start:l.start,end:l.end,name:n.id.name}),n.type==="VariableDeclaration"){let f=new Set;for(let E of n.declarations)E.id.type==="Identifier"&&ee.has(E.id.name)&&(f.has(l.start)||(f.add(l.start),g.push({start:l.start,end:l.end,name:E.id.name})))}}if(g.length===0)return;g.sort((l,n)=>n.start-l.start);let d=s;for(let{start:l,end:n,name:f}of g)d=d.slice(0,l)+`export const ${f} = undefined`+d.slice(n);return{code:d,map:null}},buildStart(){let s=process.cwd(),c=D(t,s);b($(c,`${t}/api`),s);let{warnings:R}=I(t,s);for(let m of R)console.warn(m)},configureServer(s){let c=process.cwd(),R=I(t,c);for(let n of R.warnings)console.warn(n);let m=()=>{let n=D(t,c);b($(n,`${t}/api`),c)},v=n=>n.startsWith(u(c,r))&&!n.endsWith("layout.tsx")&&!n.endsWith("error.tsx"),g=n=>Ae(c,n).replace(/\\/g,"/"),d=n=>{let f=s.moduleGraph.getModuleById(`\0${n}`);f&&s.moduleGraph.invalidateModule(f)};s.watcher.add(u(c,"devix.config.ts")),s.watcher.on("change",n=>{n===u(c,"devix.config.ts")&&(console.log("[devix] Config changed, restarting..."),process.exit(75))});let l=n=>{try{let{warnings:f}=C(g(n),c);for(let E of f)console.warn(E)}catch{}};s.watcher.on("add",n=>{n.startsWith(u(c,r))&&d(P),v(n)&&l(n),n.includes(`${t}/api`)&&(d(w),m())}),s.watcher.on("unlink",n=>{n.startsWith(u(c,r))&&d(P),v(n)&&Q(g(n),c),n.includes(`${t}/api`)&&(d(w),m())}),s.watcher.on("change",n=>{v(n)&&l(n),n.includes(`${t}/api`)&&!n.endsWith("middleware.ts")&&m()})}},oe={plugins:[Te(),ne],publicDir:u(process.cwd(),e.publicDir??"public"),ssr:{noExternal:["@devlusoft/devix"]},...e.envPrefix?{envPrefix:e.envPrefix}:{}};return we(oe,e.vite??{})}export{Rt as devix};
278
+ `}function b(e,t){let r=x(t,e),i=Y(r,"utf-8"),o=Pe(i,r),a=[];o.exists&&!o.isAsync&&!o.isReExport&&a.push(`[devix] ${e}: 'loader' must be async. Use 'export async function loader' or 'export const loader = async (...) => ...'.`);let u=x(t,".devix","pages",e.replace(/\.(tsx?|jsx?)$/,"")),h=x(u,"$types.d.ts"),S=r.replace(/\.(tsx?|jsx?)$/,""),y=Z(u,S).replace(/\\/g,"/"),T=_e(y,o.exists);return z(h)&&Y(h,"utf-8")===T?{warnings:a}:(xe(u,{recursive:!0}),ve(h,T,"utf-8"),{warnings:a})}function Q(e,t){let r=x(t,".devix","pages",e.replace(/\.(tsx?|jsx?)$/,"")),i=x(r,"$types.d.ts");z(i)&&ye(i)}function I(e,t){let r=x(t,e,"pages"),i=[],o;try{o=K(r,t)}catch{return{warnings:i}}for(let a of o)try{let u=b(a,t);i.push(...u.warnings)}catch{}return{warnings:i}}var P=De(Se(import.meta.url)),M="virtual:devix/entry-client",F="virtual:devix/client-routes",_="virtual:devix/render",w="virtual:devix/api",O="virtual:devix/context",L="virtual:devix/server-entry",ee=new Set(["loader","guard","generateStaticParams","headers"]);function Rt(e){let t=e.appDir??"app",r=`${t}/pages`,i=(e.css??[]).map(s=>s.startsWith("/")?s:`/${s.replace(/^\.\//,"")}`),o=p(P,"../server/render.js").replace(/\\/g,"/"),a=p(P,"../server/api.js").replace(/\\/g,"/"),u=p(P,"../runtime/client-router.js").replace(/\\/g,"/"),h=p(P,"../server/routes.js").replace(/\\/g,"/"),S=p(P,"../utils/env.js").replace(/\\/g,"/"),y=Ae(import.meta.url),T=y.resolve("@hono/node-server").replace(/\\/g,"/"),te=y.resolve("@hono/node-server/serve-static").replace(/\\/g,"/"),re=y.resolve("hono").replace(/\\/g,"/"),ne={name:"devix",enforce:"pre",resolveId(s){if(s===M)return`\0${M}`;if(s===F)return`\0${F}`;if(s===_)return`\0${_}`;if(s===w)return`\0${w}`;if(s===O)return`\0${O}`;if(s===L)return`\0${L}`},load(s){if(s===`\0${M}`)return U({cssUrls:i});if(s===`\0${F}`)return j({pagesDir:r,matcherPath:u});if(s===`\0${_}`)return H({pagesDir:r,renderPath:o});if(s===`\0${w}`)return N({apiPath:a,appDir:t});if(s===`\0${O}`)return W();if(s===`\0${L}`)return X({routesPath:h,envPath:S,honoServerPath:T,honoServerStaticPath:te,honoPath:re})},transform(s,c,R){if(R?.ssr)return;let m=p(process.cwd(),r);if(!c.startsWith(m))return;let v=Ce(c,s,{sourceType:"module"}),g=[];for(let l of v.program.body){if(l.type!=="ExportNamedDeclaration"||!l.declaration)continue;let n=l.declaration;if(n.type==="FunctionDeclaration"&&n.id&&ee.has(n.id.name)&&g.push({start:l.start,end:l.end,name:n.id.name}),n.type==="VariableDeclaration"){let f=new Set;for(let E of n.declarations)E.id.type==="Identifier"&&ee.has(E.id.name)&&(f.has(l.start)||(f.add(l.start),g.push({start:l.start,end:l.end,name:E.id.name})))}}if(g.length===0)return;g.sort((l,n)=>n.start-l.start);let d=s;for(let{start:l,end:n,name:f}of g)d=d.slice(0,l)+`export const ${f} = undefined`+d.slice(n);return{code:d,map:null}},buildStart(){let s=process.cwd(),c=A(t,s);C(D(c,`${t}/api`),s);let{warnings:R}=I(t,s);for(let m of R)console.warn(m)},configureServer(s){let c=process.cwd(),R=I(t,c);for(let n of R.warnings)console.warn(n);let m=()=>{let n=A(t,c);C(D(n,`${t}/api`),c)},v=n=>n.startsWith(p(c,r))&&!n.endsWith("layout.tsx")&&!n.endsWith("error.tsx"),g=n=>$e(c,n).replace(/\\/g,"/"),d=n=>{let f=s.moduleGraph.getModuleById(`\0${n}`);f&&s.moduleGraph.invalidateModule(f)};s.watcher.add(p(c,"devix.config.ts")),s.watcher.on("change",n=>{n===p(c,"devix.config.ts")&&(console.log("[devix] Config changed, restarting..."),process.exit(75))});let l=n=>{try{let{warnings:f}=b(g(n),c);for(let E of f)console.warn(E)}catch{}};s.watcher.on("add",n=>{n.startsWith(p(c,r))&&d(_),v(n)&&l(n),n.includes(`${t}/api`)&&(d(w),m())}),s.watcher.on("unlink",n=>{n.startsWith(p(c,r))&&d(_),v(n)&&Q(g(n),c),n.includes(`${t}/api`)&&(d(w),m())}),s.watcher.on("change",n=>{v(n)&&l(n),n.includes(`${t}/api`)&&!n.endsWith("middleware.ts")&&m()})}},oe={plugins:[Te(),ne],publicDir:p(process.cwd(),e.publicDir??"public"),ssr:{noExternal:["@devlusoft/devix"]},...e.envPrefix?{envPrefix:e.envPrefix}:{}};return we(oe,e.vite??{})}export{Rt as devix};
270
279
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../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/vite/codegen/context.ts", "../../src/vite/codegen/scan-api.ts", "../../src/vite/codegen/extract-methods.ts", "../../src/utils/patterns.ts", "../../src/server/api-router.ts", "../../src/vite/codegen/routes-dts.ts", "../../src/vite/codegen/write-routes-dts.ts", "../../src/vite/codegen/server-entry.ts", "../../src/vite/codegen/page-types.ts"],
4
- "sourcesContent": ["import {UserConfig, Plugin, mergeConfig} from 'vite'\nimport type {DevixConfig} from '../config'\nimport react from '@vitejs/plugin-react'\nimport {fileURLToPath} from 'node:url'\nimport {dirname, relative, 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 {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\";\nimport {deletePageTypes, scanAndWritePageTypes, writePageTypes} from \"./codegen/page-types\";\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 const {warnings} = scanAndWritePageTypes(appDir, root)\n for (const w of warnings) console.warn(w)\n },\n\n configureServer(server) {\n const root = process.cwd()\n\n const initial = scanAndWritePageTypes(appDir, root)\n for (const w of initial.warnings) console.warn(w)\n\n const regenerateDts = () => {\n const entries = scanApiFiles(appDir, root)\n writeRoutesDts(generateRoutesDts(entries, `${appDir}/api`), root)\n }\n\n const isPageFile = (file: string) => file.startsWith(resolve(root, pagesDir)) && !file.endsWith('layout.tsx') && !file.endsWith('error.tsx')\n\n const pageRelPath = (file: string) => relative(root, file).replace(/\\\\/g, '/')\n\n const invalidateVirtualModule = (id: string) => {\n const mod = server.moduleGraph.getModuleById(`\\0${id}`)\n if (mod) server.moduleGraph.invalidateModule(mod)\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 const writePageTypesAndLog = (file: string) => {\n try {\n const {warnings} = writePageTypes(pageRelPath(file), root)\n for (const w of warnings) console.warn(w)\n } catch {\n /* ignorar archivos no procesables */\n }\n }\n\n server.watcher.on('add', (file) => {\n if (file.startsWith(resolve(root, pagesDir))) invalidateVirtualModule(VIRTUAL_RENDER)\n if (isPageFile(file)) writePageTypesAndLog(file)\n if (file.includes(`${appDir}/api`)) {\n invalidateVirtualModule(VIRTUAL_API)\n regenerateDts()\n }\n })\n server.watcher.on('unlink', (file) => {\n if (file.startsWith(resolve(root, pagesDir))) invalidateVirtualModule(VIRTUAL_RENDER)\n if (isPageFile(file)) deletePageTypes(pageRelPath(file), root)\n if (file.includes(`${appDir}/api`)) {\n invalidateVirtualModule(VIRTUAL_API)\n regenerateDts()\n }\n })\n server.watcher.on('change', (file) => {\n if (isPageFile(file)) writePageTypesAndLog(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 const guardData = window.__GUARD_DATA__ ?? null\n\n const matched = matchClientRoute(window.location.pathname)\n\n if (window.__LOADER_ERROR__) {\n const {statusCode, message, code, data} = window.__LOADER_ERROR__\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 initialError: {statusCode, message, code, data},\n initialErrorPage: ErrorPage,\n })\n )\n } else 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 initialGuardData: guardData,\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 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", "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 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\nexport function buildRoutes(routeKeys: string[], middlewareKeys: string[], apiDir: string): ApiResult {\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 return {routes, middlewares}\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", "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\\nexport {}\\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, S extends number = number> = Response & { readonly __body: T; readonly __status: S }\ntype Is2xx<S extends number> = [number] extends [S] ? boolean : S extends 200 | 201 | 202 | 203 | 204 | 205 | 206 ? true : false\ntype UnwrapSuccessJson<T> = T extends JsonResponse<infer U, infer S> ? Is2xx<S> extends false ? never : U : never\ntype UnwrapErrorJson<T> = T extends JsonResponse<infer U, infer S> ? Is2xx<S> extends true ? never : U : never\ntype InferFnSuccess<T> = T extends (...args: any[]) => any ? UnwrapSuccessJson<Awaited<ReturnType<T>>> : never\ntype InferFnErrors<T> = T extends (...args: any[]) => any ? UnwrapErrorJson<Awaited<ReturnType<T>>> : 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: InferFnSuccess<() => TReturn>\n __errors: InferFnErrors<() => TReturn>\n }\n : InferFnSuccess<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 let userServerConfig\n try {\n const userConfigMod = await import(pathToFileURL(resolve(process.cwd(), 'devix.config.ts')).href).catch(() =>\n import(pathToFileURL(resolve(process.cwd(), 'devix.config.js')).href))\n userServerConfig = userConfigMod?.default?.server\n } catch {\n /* config sin server \u2014 sigue normal */\n }\n registerApiRoutes(app, { renderModule, apiModule, manifest, server: userServerConfig })\n registerSsrRoute(app, { renderModule, apiModule, manifest, loaderTimeout: runtimeConfig.loaderTimeout, server: userServerConfig })\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}", "import {existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync} from \"node:fs\";\nimport {join, relative} from \"node:path\";\nimport {parseSync} from \"oxc-parser\";\n\nfunction walkPages(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(...walkPages(full, root))\n } else if (/\\.(ts|tsx)$/.test(name) && name !== 'layout.tsx' && name !== 'error.tsx') {\n entries.push(relative(root, full).replace(/\\\\/g, '/'))\n }\n }\n return entries\n}\n\nexport interface LoaderExportInfo {\n exists: boolean\n isAsync: boolean\n isReExport: boolean\n}\n\nexport function inspectLoaderExport(code: string, filePath: string): LoaderExportInfo {\n const ast = parseSync(filePath, code, {sourceType: 'module'})\n for (const node of ast.program.body) {\n if (node.type !== 'ExportNamedDeclaration') continue\n const decl = node.declaration\n if (decl?.type === 'FunctionDeclaration' && decl.id?.name === 'loader') {\n return {exists: true, isAsync: decl.async, isReExport: false}\n }\n if (decl?.type === 'VariableDeclaration') {\n for (const d of decl.declarations) {\n if (d.id.type === 'Identifier' && d.id.name === 'loader') {\n const init = d.init\n const isAsync =\n (init?.type === 'ArrowFunctionExpression' && init.async) ||\n (init?.type === 'FunctionExpression' && init.async)\n return {exists: true, isAsync, isReExport: false}\n }\n }\n }\n for (const spec of (node.specifiers ?? [])) {\n if (spec.exported.type === 'Identifier' && spec.exported.name === 'loader') {\n return {exists: true, isAsync: false, isReExport: true}\n }\n }\n }\n return {exists: false, isAsync: false, isReExport: false}\n}\n\nexport function hasLoaderExport(code: string, filePath: string): boolean {\n return inspectLoaderExport(code, filePath).exists\n}\n\nexport function generatePageTypesDts(importPath: string, withLoader: boolean): string {\n if (!withLoader) {\n return '// auto-generado por devix - no editar\\nexport type PageData = undefined\\nexport type PageParams = Record<string, string>\\n'\n }\n return `// auto-generado por devix \u2014 no editar\\nimport type { loader } from \"${importPath}\"\\nimport type { Redirect } from \"@devlusoft/devix\"\\n\\nexport type PageData = Exclude<\\n Awaited<ReturnType<NonNullable<typeof loader>>>,\\n Redirect | void | undefined\\n>\\nexport type PageParams = NonNullable<Parameters<typeof loader>[0]>[\"params\"]\\n`\n}\n\nexport interface WritePageTypesResult {\n warnings: string[]\n}\n\nexport function writePageTypes(pageRelPath: string, root: string): WritePageTypesResult {\n const fullPath = join(root, pageRelPath)\n const code = readFileSync(fullPath, 'utf-8')\n const loaderInfo = inspectLoaderExport(code, fullPath)\n const warnings: string[] = []\n\n if (loaderInfo.exists && !loaderInfo.isAsync && !loaderInfo.isReExport) {\n warnings.push(\n `[devix] ${pageRelPath}: 'loader' must be async. ` +\n `Use 'export async function loader' or 'export const loader = async (...) => ...'.`\n )\n }\n\n const typesDir = join(root, '.devix', 'pages', pageRelPath.replace(/\\.(tsx?|jsx?)$/, ''))\n const outPath = join(typesDir, '$types.d.ts')\n\n const pageAbsNoExt = fullPath.replace(/\\.(tsx?|jsx?)$/, '')\n const importPath = relative(typesDir, pageAbsNoExt).replace(/\\\\/g, '/')\n\n const content = generatePageTypesDts(importPath, loaderInfo.exists)\n\n if (existsSync(outPath) && readFileSync(outPath, 'utf-8') === content) return {warnings}\n\n mkdirSync(typesDir, {recursive: true})\n writeFileSync(outPath, content, 'utf-8')\n return {warnings}\n}\n\nexport function deletePageTypes(pageRelPath: string, root: string): void {\n const typesDir = join(root, '.devix', 'pages', pageRelPath.replace(/\\.(tsx?|jsx?)$/, ''))\n const outPath = join(typesDir, '$types.d.ts')\n if (existsSync(outPath)) rmSync(outPath)\n}\n\nexport function scanAndWritePageTypes(appDir: string, root: string): WritePageTypesResult {\n const pagesDir = join(root, appDir, 'pages')\n const warnings: string[] = []\n let files: string[]\n try {\n files = walkPages(pagesDir, root)\n } catch {\n return {warnings}\n }\n for (const file of files) {\n try {\n const result = writePageTypes(file, root)\n warnings.push(...result.warnings)\n } catch {\n /* ignorar archivos no procesables */\n }\n }\n return {warnings}\n}"],
5
- "mappings": "AAAA,OAA4B,eAAAA,OAAkB,OAE9C,OAAOC,OAAW,uBAClB,OAAQ,iBAAAC,OAAoB,WAC5B,OAAQ,WAAAC,GAAS,YAAAC,GAAU,WAAAC,MAAc,YACzC,OAAQ,iBAAAC,OAAoB,cCDrB,SAASC,EAAoB,CAAE,QAAAC,CAAQ,EAA+B,CAGzE,MAAO;AAAA,EAFYA,EAAQ,IAAIC,GAAK,WAAWA,CAAC,GAAG,EAAE,KAAK;AAAA,CAAI,CAGtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CA8EZ,CCjFO,SAASC,EAAqB,CAAC,SAAAC,EAAU,YAAAC,CAAW,EAAwB,CAC/E,MAAO;AAAA;AAAA,iCAEsBA,CAAW;AAAA,wCACJD,CAAQ;AAAA,yCACPA,CAAQ;AAAA,wCACTA,CAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAwBhD,CC9BO,SAASE,EAAe,CAAC,SAAAC,EAAU,WAAAC,CAAU,EAA0B,CAC1E,MAAO;AAAA,mGACwFA,CAAU;AAAA;AAAA,qCAExED,CAAQ;AAAA,sCACPA,CAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,kBAK5BA,CAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAe1B,CCzBO,SAASE,EAAY,CAAC,QAAAC,EAAS,OAAAC,CAAM,EAAuB,CAC/D,MAAO;AAAA,yDAC8CD,CAAO;AAAA;AAAA,sCAE1BC,CAAM;AAAA,0CACFA,CAAM;AAAA;AAAA;AAAA;AAAA;AAAA,gBAKhCA,CAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAOtB,CCtBO,SAASC,GAA0B,CACtC,MAAO;AAAA;AAAA,CAGX,CCJA,OAAQ,gBAAAC,GAAc,eAAAC,GAAa,YAAAC,OAAe,UAClD,OAAQ,QAAAC,EAAM,YAAAC,OAAe,YCE7B,IAAMC,GAAmB,6FAEzB,SAASC,GAAcC,EAAyB,CAC5C,OAAOA,EACF,QAAQ,oBAAqB,EAAE,EAC/B,QAAQ,YAAa,EAAE,CAChC,CAEO,SAASC,EAAmBD,EAA+B,CAC9D,IAAME,EAAQ,IAAI,IAClB,QAAWC,KAASJ,GAAcC,CAAO,EAAE,SAASF,EAAgB,EAChEI,EAAM,IAAIC,EAAM,CAAC,CAAe,EAEpC,MAAO,CAAC,GAAGD,CAAK,CACpB,CCjBO,SAASE,EAAaC,EAAqB,CAC9C,OAAOA,EACE,QAAQ,qBAAsB,EAAE,EAChC,QAAQ,aAAc,EAAE,EACxB,QAAQ,mBAAoB,EAAE,EAC9B,QAAQ,eAAgB,KAAK,GAC/B,GACX,CCYO,SAASC,EAAkBC,EAAaC,EAAwB,CACnE,IAAMC,EAAMF,EAAI,MAAMC,EAAO,OAAS,CAAC,EAAE,QAAQ,MAAO,GAAG,EACrDE,EAAUC,EAAaF,CAAG,EAChC,OAAOC,IAAY,IAAM,OAAS,QAAQA,CAAO,GAAG,QAAQ,SAAU,OAAO,CACjF,CCbO,SAASE,GAAqBC,EAAkBC,EAAwB,CAC3E,MAAO,QAAUD,EACZ,MAAM,GAAGC,CAAM,IAAI,MAAM,EACzB,QAAQ,cAAe,EAAE,EACzB,QAAQ,gBAAiB,GAAG,CACrC,CAEO,SAASC,EAAgBF,EAAkBC,EAAgBE,EAAmC,CACjG,MAAO,CACH,SAAAH,EACA,WAAYI,EAAkBJ,EAAUC,CAAM,EAC9C,WAAYF,GAAqBC,EAAUC,CAAM,EACjD,QAAAE,CACJ,CACJ,CAEO,SAASE,EAAkBC,EAAuBL,EAAwB,CAC7E,GAAIK,EAAQ,SAAW,EACnB,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAGX,IAAMC,EAAUD,EACX,IAAIE,GAAK,CACN,IAAMC,EAAa,MAAQD,EAAE,SAAS,QAAQ,cAAe,EAAE,EAC/D,MAAO,oBAAoBA,EAAE,UAAU,UAAUC,CAAU,GAC/D,CAAC,EACA,KAAK;AAAA,CAAI,EAERC,EAAaJ,EAAQ,QAAQE,GAC/BA,EAAE,QAAQ,IAAIG,GACV,QAAQA,CAAC,IAAIH,EAAE,UAAU,yBAAyBA,EAAE,UAAU,MAAMG,CAAC,KACzE,CACJ,EAAE,KAAK;AAAA,CAAI,EAEX,MAAO;AAAA,EACTJ,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBPG,CAAU;AAAA;AAAA;AAAA,CAIZ,CJ9DA,SAASE,EAAQC,EAAaC,EAAwB,CAClD,IAAMC,EAAoB,CAAC,EAC3B,QAAWC,KAAQC,GAAYJ,CAAG,EAAG,CACjC,IAAMK,EAAOC,EAAKN,EAAKG,CAAI,EACvBI,GAASF,CAAI,EAAE,YAAY,EAC3BH,EAAQ,KAAK,GAAGH,EAAQM,EAAMJ,CAAI,CAAC,EAC5B,cAAc,KAAKE,CAAI,GAC9BD,EAAQ,KAAKM,GAASP,EAAMI,CAAI,EAAE,QAAQ,MAAO,GAAG,CAAC,CAE7D,CACA,OAAOH,CACX,CAEO,SAASO,EAAaC,EAAgBC,EAAmC,CAC5E,IAAMC,EAASN,EAAKK,EAAaD,EAAQ,KAAK,EAE1CG,EACJ,GAAI,CACAA,EAAQd,EAAQa,EAAQD,CAAW,CACvC,MAAQ,CACJ,MAAO,CAAC,CACZ,CAEA,OAAOE,EACF,OAAOC,GAAK,CAACA,EAAE,SAAS,eAAe,GAAK,CAACA,EAAE,SAAS,gBAAgB,CAAC,EACzE,QAAQC,GAAY,CACjB,GAAI,CACA,IAAMC,EAAUC,GAAaX,EAAKK,EAAaI,CAAQ,EAAG,OAAO,EAC3DG,EAAUC,EAAmBH,CAAO,EAC1C,OAAIE,EAAQ,SAAW,EAAU,CAAC,EAC3B,CAACE,EAAgBL,EAAU,GAAGL,CAAM,OAAQQ,CAAO,CAAC,CAC/D,MAAQ,CACJ,MAAO,CAAC,CACZ,CACJ,CAAC,CACT,CKzCA,OAAQ,aAAAG,GAAW,gBAAAC,GAAc,iBAAAC,GAAe,cAAAC,OAAiB,UACjE,OAAQ,QAAAC,MAAW,YAEZ,SAASC,EAAeC,EAAiBC,EAA8B,CAC1E,IAAMC,EAAWJ,EAAKG,EAAa,QAAQ,EACrCE,EAAUL,EAAKI,EAAU,aAAa,EAI5C,OAFAR,GAAUQ,EAAU,CAAC,UAAW,EAAI,CAAC,EAEjCL,GAAWM,CAAO,GAAKR,GAAaQ,EAAS,OAAO,IAAMH,EACnD,IAGXJ,GAAcO,EAASH,EAAS,OAAO,EAChC,GACX,CXDA,OAAQ,aAAAI,OAAgB,aYNjB,SAASC,EAAoB,CAAE,WAAAC,EAAY,QAAAC,EAAS,eAAAC,EAAgB,qBAAAC,EAAsB,SAAAC,CAAS,EAA+B,CACrI,MAAO;AAAA;AAAA,2BAEgBF,CAAc;AAAA,iCACRC,CAAoB;AAAA,0BAC3BC,CAAQ;AAAA;AAAA;AAAA,yDAGuBJ,CAAU;AAAA,gCACnCC,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAwEvC,CCzFA,OAAQ,cAAAI,EAAY,aAAAC,GAAW,eAAAC,GAAa,gBAAAC,EAAc,UAAAC,GAAQ,YAAAC,GAAU,iBAAAC,OAAoB,UAChG,OAAQ,QAAAC,EAAM,YAAAC,MAAe,YAC7B,OAAQ,aAAAC,OAAgB,aAExB,SAASC,EAAUC,EAAaC,EAAwB,CACpD,IAAMC,EAAoB,CAAC,EAC3B,QAAWC,KAAQZ,GAAYS,CAAG,EAAG,CACjC,IAAMI,EAAOR,EAAKI,EAAKG,CAAI,EACvBT,GAASU,CAAI,EAAE,YAAY,EAC3BF,EAAQ,KAAK,GAAGH,EAAUK,EAAMH,CAAI,CAAC,EAC9B,cAAc,KAAKE,CAAI,GAAKA,IAAS,cAAgBA,IAAS,aACrED,EAAQ,KAAKL,EAASI,EAAMG,CAAI,EAAE,QAAQ,MAAO,GAAG,CAAC,CAE7D,CACA,OAAOF,CACX,CAQO,SAASG,GAAoBC,EAAcC,EAAoC,CAClF,IAAMC,EAAMV,GAAUS,EAAUD,EAAM,CAAC,WAAY,QAAQ,CAAC,EAC5D,QAAWG,KAAQD,EAAI,QAAQ,KAAM,CACjC,GAAIC,EAAK,OAAS,yBAA0B,SAC5C,IAAMC,EAAOD,EAAK,YAClB,GAAIC,GAAM,OAAS,uBAAyBA,EAAK,IAAI,OAAS,SAC1D,MAAO,CAAC,OAAQ,GAAM,QAASA,EAAK,MAAO,WAAY,EAAK,EAEhE,GAAIA,GAAM,OAAS,uBACf,QAAWC,KAAKD,EAAK,aACjB,GAAIC,EAAE,GAAG,OAAS,cAAgBA,EAAE,GAAG,OAAS,SAAU,CACtD,IAAMC,EAAOD,EAAE,KAIf,MAAO,CAAC,OAAQ,GAAM,QAFjBC,GAAM,OAAS,2BAA6BA,EAAK,OACjDA,GAAM,OAAS,sBAAwBA,EAAK,MAClB,WAAY,EAAK,CACpD,EAGR,QAAWC,KAASJ,EAAK,YAAc,CAAC,EACpC,GAAII,EAAK,SAAS,OAAS,cAAgBA,EAAK,SAAS,OAAS,SAC9D,MAAO,CAAC,OAAQ,GAAM,QAAS,GAAO,WAAY,EAAI,CAGlE,CACA,MAAO,CAAC,OAAQ,GAAO,QAAS,GAAO,WAAY,EAAK,CAC5D,CAMO,SAASC,GAAqBC,EAAoBC,EAA6B,CAClF,OAAKA,EAGE;AAAA,+BAAwED,CAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAF9E;AAAA;AAAA;AAAA,CAGf,CAMO,SAASE,EAAeC,EAAqBC,EAAoC,CACpF,IAAMC,EAAWC,EAAKF,EAAMD,CAAW,EACjCI,EAAOC,EAAaH,EAAU,OAAO,EACrCI,EAAaC,GAAoBH,EAAMF,CAAQ,EAC/CM,EAAqB,CAAC,EAExBF,EAAW,QAAU,CAACA,EAAW,SAAW,CAACA,EAAW,YACxDE,EAAS,KACL,WAAWR,CAAW,6GAE1B,EAGJ,IAAMS,EAAWN,EAAKF,EAAM,SAAU,QAASD,EAAY,QAAQ,iBAAkB,EAAE,CAAC,EAClFU,EAAUP,EAAKM,EAAU,aAAa,EAEtCE,EAAeT,EAAS,QAAQ,iBAAkB,EAAE,EACpDL,EAAae,EAASH,EAAUE,CAAY,EAAE,QAAQ,MAAO,GAAG,EAEhEE,EAAUjB,GAAqBC,EAAYS,EAAW,MAAM,EAElE,OAAIQ,EAAWJ,CAAO,GAAKL,EAAaK,EAAS,OAAO,IAAMG,EAAgB,CAAC,SAAAL,CAAQ,GAEvFO,GAAUN,EAAU,CAAC,UAAW,EAAI,CAAC,EACrCO,GAAcN,EAASG,EAAS,OAAO,EAChC,CAAC,SAAAL,CAAQ,EACpB,CAEO,SAASS,EAAgBjB,EAAqBC,EAAoB,CACrE,IAAMQ,EAAWN,EAAKF,EAAM,SAAU,QAASD,EAAY,QAAQ,iBAAkB,EAAE,CAAC,EAClFU,EAAUP,EAAKM,EAAU,aAAa,EACxCK,EAAWJ,CAAO,GAAGQ,GAAOR,CAAO,CAC3C,CAEO,SAASS,EAAsBC,EAAgBnB,EAAoC,CACtF,IAAMoB,EAAWlB,EAAKF,EAAMmB,EAAQ,OAAO,EACrCZ,EAAqB,CAAC,EACxBc,EACJ,GAAI,CACAA,EAAQC,EAAUF,EAAUpB,CAAI,CACpC,MAAQ,CACJ,MAAO,CAAC,SAAAO,CAAQ,CACpB,CACA,QAAWgB,KAAQF,EACf,GAAI,CACA,IAAMG,EAAS1B,EAAeyB,EAAMvB,CAAI,EACxCO,EAAS,KAAK,GAAGiB,EAAO,QAAQ,CACpC,MAAQ,CAER,CAEJ,MAAO,CAAC,SAAAjB,CAAQ,CACpB,CbpGA,IAAMkB,EAAYC,GAAQC,GAAc,YAAY,GAAG,CAAC,EAElDC,EAAuB,6BACvBC,EAAwB,8BACxBC,EAAiB,uBACjBC,EAAc,oBACdC,EAAkB,wBAClBC,EAAuB,6BAEvBC,GAAiB,IAAI,IAAI,CAAC,SAAU,QAAS,uBAAwB,SAAS,CAAC,EAE9E,SAASC,GAAMC,EAAiC,CACnD,IAAMC,EAASD,EAAO,QAAU,MAC1BE,EAAW,GAAGD,CAAM,SACpBE,GAAWH,EAAO,KAAO,CAAC,GAAG,IAAII,GAAKA,EAAE,WAAW,GAAG,EAAIA,EAAI,IAAIA,EAAE,QAAQ,QAAS,EAAE,CAAC,EAAE,EAE1FC,EAAaC,EAAQjB,EAAW,qBAAqB,EAAE,QAAQ,MAAO,GAAG,EACzEkB,EAAUD,EAAQjB,EAAW,kBAAkB,EAAE,QAAQ,MAAO,GAAG,EACnEmB,EAAcF,EAAQjB,EAAW,6BAA6B,EAAE,QAAQ,MAAO,GAAG,EAClFoB,EAAaH,EAAQjB,EAAW,qBAAqB,EAAE,QAAQ,MAAO,GAAG,EACzEqB,EAAUJ,EAAQjB,EAAW,iBAAiB,EAAE,QAAQ,MAAO,GAAG,EAElEsB,EAAWC,GAAc,YAAY,GAAG,EACxCC,EAAiBF,EAAS,QAAQ,mBAAmB,EAAE,QAAQ,MAAO,GAAG,EACzEG,GAAuBH,EAAS,QAAQ,gCAAgC,EAAE,QAAQ,MAAO,GAAG,EAC5FI,GAAWJ,EAAS,QAAQ,MAAM,EAAE,QAAQ,MAAO,GAAG,EAEtDK,GAAwB,CAC1B,KAAM,QACN,QAAS,MAET,UAAUC,EAAI,CACV,GAAIA,IAAOzB,EAAsB,MAAO,KAAKA,CAAoB,GACjE,GAAIyB,IAAOxB,EAAuB,MAAO,KAAKA,CAAqB,GACnE,GAAIwB,IAAOvB,EAAgB,MAAO,KAAKA,CAAc,GACrD,GAAIuB,IAAOtB,EAAa,MAAO,KAAKA,CAAW,GAC/C,GAAIsB,IAAOrB,EAAiB,MAAO,KAAKA,CAAe,GACvD,GAAIqB,IAAOpB,EAAsB,MAAO,KAAKA,CAAoB,EACrE,EAEA,KAAKoB,EAAI,CACL,GAAIA,IAAO,KAAKzB,CAAoB,GAChC,OAAO0B,EAAoB,CAAC,QAAAf,CAAO,CAAC,EACxC,GAAIc,IAAO,KAAKxB,CAAqB,GACjC,OAAO0B,EAAqB,CAAC,SAAAjB,EAAU,YAAAM,CAAW,CAAC,EACvD,GAAIS,IAAO,KAAKvB,CAAc,GAC1B,OAAO0B,EAAe,CAAC,SAAAlB,EAAU,WAAAG,CAAU,CAAC,EAChD,GAAIY,IAAO,KAAKtB,CAAW,GACvB,OAAO0B,EAAY,CAAC,QAAAd,EAAS,OAAAN,CAAM,CAAC,EACxC,GAAIgB,IAAO,KAAKrB,CAAe,GAC3B,OAAO0B,EAAgB,EAC3B,GAAIL,IAAO,KAAKpB,CAAoB,GAChC,OAAO0B,EAAoB,CAAC,WAAAd,EAAY,QAAAC,EAAS,eAAAG,EAAgB,qBAAAC,GAAsB,SAAAC,EAAQ,CAAC,CACxG,EAGA,UAAUS,EAAMP,EAAIQ,EAAS,CACzB,GAAIA,GAAS,IAAK,OAElB,IAAMC,EAAmBpB,EAAQ,QAAQ,IAAI,EAAGJ,CAAQ,EACxD,GAAI,CAACe,EAAG,WAAWS,CAAgB,EAAG,OAEtC,IAAMC,EAAMC,GAAUX,EAAIO,EAAM,CAAC,WAAY,QAAQ,CAAC,EAEhDK,EAA+D,CAAC,EAEtE,QAAWC,KAAQH,EAAI,QAAQ,KAAM,CACjC,GAAIG,EAAK,OAAS,0BAA4B,CAACA,EAAK,YAAa,SAEjE,IAAMC,EAAOD,EAAK,YAMlB,GAJIC,EAAK,OAAS,uBAAyBA,EAAK,IAAMjC,GAAe,IAAIiC,EAAK,GAAG,IAAI,GACjFF,EAAa,KAAK,CAAC,MAAOC,EAAK,MAAO,IAAKA,EAAK,IAAK,KAAMC,EAAK,GAAG,IAAI,CAAC,EAGxEA,EAAK,OAAS,sBAAuB,CACrC,IAAMC,EAAO,IAAI,IACjB,QAAWC,KAAcF,EAAK,aACtBE,EAAW,GAAG,OAAS,cAAgBnC,GAAe,IAAImC,EAAW,GAAG,IAAI,IACvED,EAAK,IAAIF,EAAK,KAAK,IACpBE,EAAK,IAAIF,EAAK,KAAK,EACnBD,EAAa,KAAK,CAAC,MAAOC,EAAK,MAAO,IAAKA,EAAK,IAAK,KAAMG,EAAW,GAAG,IAAI,CAAC,GAI9F,CACJ,CAEA,GAAIJ,EAAa,SAAW,EAAG,OAE/BA,EAAa,KAAK,CAACK,EAAGC,IAAMA,EAAE,MAAQD,EAAE,KAAK,EAE7C,IAAIE,EAASZ,EACb,OAAW,CAAC,MAAAa,EAAO,IAAAC,EAAK,KAAAC,CAAI,IAAKV,EAC7BO,EAASA,EAAO,MAAM,EAAGC,CAAK,EAAI,gBAAgBE,CAAI,eAAiBH,EAAO,MAAME,CAAG,EAG3F,MAAO,CAAC,KAAMF,EAAQ,IAAK,IAAI,CACnC,EAEA,YAAa,CACT,IAAMI,EAAO,QAAQ,IAAI,EACnBC,EAAUC,EAAazC,EAAQuC,CAAI,EACzCG,EAAeC,EAAkBH,EAAS,GAAGxC,CAAM,MAAM,EAAGuC,CAAI,EAChE,GAAM,CAAC,SAAAK,CAAQ,EAAIC,EAAsB7C,EAAQuC,CAAI,EACrD,QAAWO,KAAKF,EAAU,QAAQ,KAAKE,CAAC,CAC5C,EAEA,gBAAgBC,EAAQ,CACpB,IAAMR,EAAO,QAAQ,IAAI,EAEnBS,EAAUH,EAAsB7C,EAAQuC,CAAI,EAClD,QAAWO,KAAKE,EAAQ,SAAU,QAAQ,KAAKF,CAAC,EAEhD,IAAMG,EAAgB,IAAM,CACxB,IAAMT,EAAUC,EAAazC,EAAQuC,CAAI,EACzCG,EAAeC,EAAkBH,EAAS,GAAGxC,CAAM,MAAM,EAAGuC,CAAI,CACpE,EAEMW,EAAcC,GAAiBA,EAAK,WAAW9C,EAAQkC,EAAMtC,CAAQ,CAAC,GAAK,CAACkD,EAAK,SAAS,YAAY,GAAK,CAACA,EAAK,SAAS,WAAW,EAErIC,EAAeD,GAAiBE,GAASd,EAAMY,CAAI,EAAE,QAAQ,MAAO,GAAG,EAEvEG,EAA2BtC,GAAe,CAC5C,IAAMuC,EAAMR,EAAO,YAAY,cAAc,KAAK/B,CAAE,EAAE,EAClDuC,GAAKR,EAAO,YAAY,iBAAiBQ,CAAG,CACpD,EAEAR,EAAO,QAAQ,IAAI1C,EAAQkC,EAAM,iBAAiB,CAAC,EACnDQ,EAAO,QAAQ,GAAG,SAAWI,GAAS,CAC9BA,IAAS9C,EAAQkC,EAAM,iBAAiB,IACxC,QAAQ,IAAI,uCAAuC,EACnD,QAAQ,KAAK,EAAE,EAEvB,CAAC,EAED,IAAMiB,EAAwBL,GAAiB,CAC3C,GAAI,CACA,GAAM,CAAC,SAAAP,CAAQ,EAAIa,EAAeL,EAAYD,CAAI,EAAGZ,CAAI,EACzD,QAAWO,KAAKF,EAAU,QAAQ,KAAKE,CAAC,CAC5C,MAAQ,CAER,CACJ,EAEAC,EAAO,QAAQ,GAAG,MAAQI,GAAS,CAC3BA,EAAK,WAAW9C,EAAQkC,EAAMtC,CAAQ,CAAC,GAAGqD,EAAwB7D,CAAc,EAChFyD,EAAWC,CAAI,GAAGK,EAAqBL,CAAI,EAC3CA,EAAK,SAAS,GAAGnD,CAAM,MAAM,IAC7BsD,EAAwB5D,CAAW,EACnCuD,EAAc,EAEtB,CAAC,EACDF,EAAO,QAAQ,GAAG,SAAWI,GAAS,CAC9BA,EAAK,WAAW9C,EAAQkC,EAAMtC,CAAQ,CAAC,GAAGqD,EAAwB7D,CAAc,EAChFyD,EAAWC,CAAI,GAAGO,EAAgBN,EAAYD,CAAI,EAAGZ,CAAI,EACzDY,EAAK,SAAS,GAAGnD,CAAM,MAAM,IAC7BsD,EAAwB5D,CAAW,EACnCuD,EAAc,EAEtB,CAAC,EACDF,EAAO,QAAQ,GAAG,SAAWI,GAAS,CAC9BD,EAAWC,CAAI,GAAGK,EAAqBL,CAAI,EAC3CA,EAAK,SAAS,GAAGnD,CAAM,MAAM,GAAK,CAACmD,EAAK,SAAS,eAAe,GAChEF,EAAc,CAEtB,CAAC,CACL,CACJ,EAEMU,GAAmB,CACrB,QAAS,CAACC,GAAM,EAAG7C,EAAa,EAChC,UAAWV,EAAQ,QAAQ,IAAI,EAAGN,EAAO,WAAa,QAAQ,EAC9D,IAAK,CAAC,WAAY,CAAC,kBAAkB,CAAC,EACtC,GAAIA,EAAO,UAAY,CAAC,UAAWA,EAAO,SAAS,EAAI,CAAC,CAC5D,EAEA,OAAO8D,GAAYF,GAAM5D,EAAO,MAAQ,CAAC,CAAC,CAC9C",
4
+ "sourcesContent": ["import {UserConfig, Plugin, mergeConfig} from 'vite'\nimport type {DevixConfig} from '../config'\nimport react from '@vitejs/plugin-react'\nimport {fileURLToPath} from 'node:url'\nimport {dirname, relative, 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 {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\";\nimport {deletePageTypes, scanAndWritePageTypes, writePageTypes} from \"./codegen/page-types\";\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 const {warnings} = scanAndWritePageTypes(appDir, root)\n for (const w of warnings) console.warn(w)\n },\n\n configureServer(server) {\n const root = process.cwd()\n\n const initial = scanAndWritePageTypes(appDir, root)\n for (const w of initial.warnings) console.warn(w)\n\n const regenerateDts = () => {\n const entries = scanApiFiles(appDir, root)\n writeRoutesDts(generateRoutesDts(entries, `${appDir}/api`), root)\n }\n\n const isPageFile = (file: string) => file.startsWith(resolve(root, pagesDir)) && !file.endsWith('layout.tsx') && !file.endsWith('error.tsx')\n\n const pageRelPath = (file: string) => relative(root, file).replace(/\\\\/g, '/')\n\n const invalidateVirtualModule = (id: string) => {\n const mod = server.moduleGraph.getModuleById(`\\0${id}`)\n if (mod) server.moduleGraph.invalidateModule(mod)\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 const writePageTypesAndLog = (file: string) => {\n try {\n const {warnings} = writePageTypes(pageRelPath(file), root)\n for (const w of warnings) console.warn(w)\n } catch {\n /* ignorar archivos no procesables */\n }\n }\n\n server.watcher.on('add', (file) => {\n if (file.startsWith(resolve(root, pagesDir))) invalidateVirtualModule(VIRTUAL_RENDER)\n if (isPageFile(file)) writePageTypesAndLog(file)\n if (file.includes(`${appDir}/api`)) {\n invalidateVirtualModule(VIRTUAL_API)\n regenerateDts()\n }\n })\n server.watcher.on('unlink', (file) => {\n if (file.startsWith(resolve(root, pagesDir))) invalidateVirtualModule(VIRTUAL_RENDER)\n if (isPageFile(file)) deletePageTypes(pageRelPath(file), root)\n if (file.includes(`${appDir}/api`)) {\n invalidateVirtualModule(VIRTUAL_API)\n regenerateDts()\n }\n })\n server.watcher.on('change', (file) => {\n if (isPageFile(file)) writePageTypesAndLog(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 const guardData = window.__GUARD_DATA__ ?? null\n\n const matched = matchClientRoute(window.location.pathname)\n\n if (window.__LOADER_ERROR__) {\n const {statusCode, message, code, data} = window.__LOADER_ERROR__\n const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()\n createRoot(root).render(\n React.createElement(RouterProvider, {\n matchClientRoute,\n loadErrorPage,\n getDefaultErrorPage,\n clientEntry,\n initialData: null,\n initialParams: {},\n initialPage: () => null,\n initialError: {statusCode, message, code, data},\n initialErrorPage: ErrorPage,\n })\n )\n } else 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 matchClientRoute,\n loadErrorPage,\n getDefaultErrorPage,\n clientEntry,\n initialData: loaderData,\n initialParams: matched.params,\n initialPage: pageMod.default,\n initialLayouts: layoutMods.map(m => m.default),\n initialLayoutsData: layoutsData,\n initialGuardData: guardData,\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 matchClientRoute,\n loadErrorPage,\n getDefaultErrorPage,\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 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", "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 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\nexport function buildRoutes(routeKeys: string[], middlewareKeys: string[], apiDir: string): ApiResult {\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 return {routes, middlewares}\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", "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\\nexport {}\\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, S extends number = number> = Response & { readonly __body: T; readonly __status: S }\ntype Is2xx<S extends number> = [number] extends [S] ? boolean : S extends 200 | 201 | 202 | 203 | 204 | 205 | 206 ? true : false\ntype UnwrapSuccessJson<T> = T extends JsonResponse<infer U, infer S> ? Is2xx<S> extends false ? never : U : never\ntype UnwrapErrorJson<T> = T extends JsonResponse<infer U, infer S> ? Is2xx<S> extends true ? never : U : never\ntype InferFnSuccess<T> = T extends (...args: any[]) => any ? UnwrapSuccessJson<Awaited<ReturnType<T>>> : never\ntype InferFnErrors<T> = T extends (...args: any[]) => any ? UnwrapErrorJson<Awaited<ReturnType<T>>> : 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: InferFnSuccess<() => TReturn>\n __errors: InferFnErrors<() => TReturn>\n }\n : InferFnSuccess<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 let userServerConfig\n try {\n const userConfigMod = await import(pathToFileURL(resolve(process.cwd(), 'devix.config.ts')).href).catch(() =>\n import(pathToFileURL(resolve(process.cwd(), 'devix.config.js')).href))\n userServerConfig = userConfigMod?.default?.server\n } catch {\n /* config sin server \u2014 sigue normal */\n }\n registerApiRoutes(app, { renderModule, apiModule, manifest, server: userServerConfig })\n registerSsrRoute(app, { renderModule, apiModule, manifest, loaderTimeout: runtimeConfig.loaderTimeout, server: userServerConfig })\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}", "import {existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync} from \"node:fs\";\nimport {join, relative} from \"node:path\";\nimport {parseSync} from \"oxc-parser\";\n\nfunction walkPages(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(...walkPages(full, root))\n } else if (/\\.(ts|tsx)$/.test(name) && name !== 'layout.tsx' && name !== 'error.tsx') {\n entries.push(relative(root, full).replace(/\\\\/g, '/'))\n }\n }\n return entries\n}\n\nexport interface LoaderExportInfo {\n exists: boolean\n isAsync: boolean\n isReExport: boolean\n}\n\nexport function inspectLoaderExport(code: string, filePath: string): LoaderExportInfo {\n const ast = parseSync(filePath, code, {sourceType: 'module'})\n for (const node of ast.program.body) {\n if (node.type !== 'ExportNamedDeclaration') continue\n const decl = node.declaration\n if (decl?.type === 'FunctionDeclaration' && decl.id?.name === 'loader') {\n return {exists: true, isAsync: decl.async, isReExport: false}\n }\n if (decl?.type === 'VariableDeclaration') {\n for (const d of decl.declarations) {\n if (d.id.type === 'Identifier' && d.id.name === 'loader') {\n const init = d.init\n const isAsync =\n (init?.type === 'ArrowFunctionExpression' && init.async) ||\n (init?.type === 'FunctionExpression' && init.async)\n return {exists: true, isAsync, isReExport: false}\n }\n }\n }\n for (const spec of (node.specifiers ?? [])) {\n if (spec.exported.type === 'Identifier' && spec.exported.name === 'loader') {\n return {exists: true, isAsync: false, isReExport: true}\n }\n }\n }\n return {exists: false, isAsync: false, isReExport: false}\n}\n\nexport function hasLoaderExport(code: string, filePath: string): boolean {\n return inspectLoaderExport(code, filePath).exists\n}\n\nexport function generatePageTypesDts(importPath: string, withLoader: boolean): string {\n if (!withLoader) {\n return '// auto-generado por devix - no editar\\nexport type PageData = undefined\\nexport type PageParams = Record<string, string>\\n'\n }\n return `// auto-generado por devix \u2014 no editar\\nimport type { loader } from \"${importPath}\"\\nimport type { Redirect } from \"@devlusoft/devix\"\\n\\nexport type PageData = Exclude<\\n Awaited<ReturnType<NonNullable<typeof loader>>>,\\n Redirect | void | undefined\\n>\\nexport type PageParams = NonNullable<Parameters<typeof loader>[0]>[\"params\"]\\n`\n}\n\nexport interface WritePageTypesResult {\n warnings: string[]\n}\n\nexport function writePageTypes(pageRelPath: string, root: string): WritePageTypesResult {\n const fullPath = join(root, pageRelPath)\n const code = readFileSync(fullPath, 'utf-8')\n const loaderInfo = inspectLoaderExport(code, fullPath)\n const warnings: string[] = []\n\n if (loaderInfo.exists && !loaderInfo.isAsync && !loaderInfo.isReExport) {\n warnings.push(\n `[devix] ${pageRelPath}: 'loader' must be async. ` +\n `Use 'export async function loader' or 'export const loader = async (...) => ...'.`\n )\n }\n\n const typesDir = join(root, '.devix', 'pages', pageRelPath.replace(/\\.(tsx?|jsx?)$/, ''))\n const outPath = join(typesDir, '$types.d.ts')\n\n const pageAbsNoExt = fullPath.replace(/\\.(tsx?|jsx?)$/, '')\n const importPath = relative(typesDir, pageAbsNoExt).replace(/\\\\/g, '/')\n\n const content = generatePageTypesDts(importPath, loaderInfo.exists)\n\n if (existsSync(outPath) && readFileSync(outPath, 'utf-8') === content) return {warnings}\n\n mkdirSync(typesDir, {recursive: true})\n writeFileSync(outPath, content, 'utf-8')\n return {warnings}\n}\n\nexport function deletePageTypes(pageRelPath: string, root: string): void {\n const typesDir = join(root, '.devix', 'pages', pageRelPath.replace(/\\.(tsx?|jsx?)$/, ''))\n const outPath = join(typesDir, '$types.d.ts')\n if (existsSync(outPath)) rmSync(outPath)\n}\n\nexport function scanAndWritePageTypes(appDir: string, root: string): WritePageTypesResult {\n const pagesDir = join(root, appDir, 'pages')\n const warnings: string[] = []\n let files: string[]\n try {\n files = walkPages(pagesDir, root)\n } catch {\n return {warnings}\n }\n for (const file of files) {\n try {\n const result = writePageTypes(file, root)\n warnings.push(...result.warnings)\n } catch {\n /* ignorar archivos no procesables */\n }\n }\n return {warnings}\n}"],
5
+ "mappings": "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",
6
6
  "names": ["mergeConfig", "react", "fileURLToPath", "dirname", "relative", "resolve", "createRequire", "generateEntryClient", "cssUrls", "u", "generateClientRoutes", "pagesDir", "matcherPath", "generateRender", "pagesDir", "renderPath", "generateApi", "apiPath", "appDir", "generateContext", "readFileSync", "readdirSync", "statSync", "join", "relative", "METHOD_EXPORT_RE", "stripComments", "content", "extractHttpMethods", "found", "match", "routePattern", "rel", "keyToRoutePattern", "key", "apiDir", "rel", "pattern", "routePattern", "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", "existsSync", "mkdirSync", "readdirSync", "readFileSync", "rmSync", "statSync", "writeFileSync", "join", "relative", "parseSync", "walkPages", "dir", "root", "entries", "name", "full", "inspectLoaderExport", "code", "filePath", "ast", "node", "decl", "d", "init", "spec", "generatePageTypesDts", "importPath", "withLoader", "writePageTypes", "pageRelPath", "root", "fullPath", "join", "code", "readFileSync", "loaderInfo", "inspectLoaderExport", "warnings", "typesDir", "outPath", "pageAbsNoExt", "relative", "content", "existsSync", "mkdirSync", "writeFileSync", "deletePageTypes", "rmSync", "scanAndWritePageTypes", "appDir", "pagesDir", "files", "walkPages", "file", "result", "__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", "a", "b", "result", "start", "end", "name", "root", "entries", "scanApiFiles", "writeRoutesDts", "generateRoutesDts", "warnings", "scanAndWritePageTypes", "w", "server", "initial", "regenerateDts", "isPageFile", "file", "pageRelPath", "relative", "invalidateVirtualModule", "mod", "writePageTypesAndLog", "writePageTypes", "deletePageTypes", "base", "react", "mergeConfig"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devlusoft/devix",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
4
4
  "type": "module",
5
5
  "description": "A lightweight React SSR meta-framework — devix",
6
6
  "author": "devlusoft",
@@ -68,6 +68,11 @@
68
68
  "oxc-parser": "0.121.0"
69
69
  },
70
70
  "packageManager": "pnpm@10.31.0",
71
+ "pnpm": {
72
+ "overrides": {
73
+ "picomatch": ">=4.0.4"
74
+ }
75
+ },
71
76
  "devDependencies": {
72
77
  "@types/node": "25.5.0",
73
78
  "@types/react": "19.2.14",