@devlusoft/devix 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +216 -0
  3. package/bin/devix.js +2 -0
  4. package/dist/cli/build.d.ts +1 -0
  5. package/dist/cli/build.js +286 -0
  6. package/dist/cli/build.js.map +7 -0
  7. package/dist/cli/dev.d.ts +1 -0
  8. package/dist/cli/dev.js +361 -0
  9. package/dist/cli/dev.js.map +7 -0
  10. package/dist/cli/generate.d.ts +1 -0
  11. package/dist/cli/generate.js +389 -0
  12. package/dist/cli/generate.js.map +7 -0
  13. package/dist/cli/index.d.ts +2 -0
  14. package/dist/cli/index.js +649 -0
  15. package/dist/cli/index.js.map +7 -0
  16. package/dist/cli/start.d.ts +1 -0
  17. package/dist/cli/start.js +78 -0
  18. package/dist/cli/start.js.map +7 -0
  19. package/dist/config.d.ts +21 -0
  20. package/dist/config.js +17 -0
  21. package/dist/config.js.map +7 -0
  22. package/dist/runtime/api-context.d.ts +20 -0
  23. package/dist/runtime/api-context.js +18 -0
  24. package/dist/runtime/api-context.js.map +7 -0
  25. package/dist/runtime/client-router.d.ts +13 -0
  26. package/dist/runtime/client-router.js +59 -0
  27. package/dist/runtime/client-router.js.map +7 -0
  28. package/dist/runtime/context.d.ts +27 -0
  29. package/dist/runtime/context.js +15 -0
  30. package/dist/runtime/context.js.map +7 -0
  31. package/dist/runtime/error-boundary.d.ts +19 -0
  32. package/dist/runtime/error-boundary.js +37 -0
  33. package/dist/runtime/error-boundary.js.map +7 -0
  34. package/dist/runtime/head.d.ts +3 -0
  35. package/dist/runtime/head.js +69 -0
  36. package/dist/runtime/head.js.map +7 -0
  37. package/dist/runtime/index.d.ts +5 -0
  38. package/dist/runtime/index.js +300 -0
  39. package/dist/runtime/index.js.map +7 -0
  40. package/dist/runtime/link.d.ts +8 -0
  41. package/dist/runtime/link.js +43 -0
  42. package/dist/runtime/link.js.map +7 -0
  43. package/dist/runtime/metadata.d.ts +10 -0
  44. package/dist/runtime/metadata.js +22 -0
  45. package/dist/runtime/metadata.js.map +7 -0
  46. package/dist/runtime/router-provider.d.ts +22 -0
  47. package/dist/runtime/router-provider.js +259 -0
  48. package/dist/runtime/router-provider.js.map +7 -0
  49. package/dist/server/api-router.d.ts +21 -0
  50. package/dist/server/api-router.js +64 -0
  51. package/dist/server/api-router.js.map +7 -0
  52. package/dist/server/api.d.ts +2 -0
  53. package/dist/server/api.js +123 -0
  54. package/dist/server/api.js.map +7 -0
  55. package/dist/server/collect-css.d.ts +2 -0
  56. package/dist/server/collect-css.js +15 -0
  57. package/dist/server/collect-css.js.map +7 -0
  58. package/dist/server/index.d.ts +6 -0
  59. package/dist/server/index.js +133 -0
  60. package/dist/server/index.js.map +7 -0
  61. package/dist/server/pages-router.d.ts +21 -0
  62. package/dist/server/pages-router.js +64 -0
  63. package/dist/server/pages-router.js.map +7 -0
  64. package/dist/server/render.d.ts +34 -0
  65. package/dist/server/render.js +306 -0
  66. package/dist/server/render.js.map +7 -0
  67. package/dist/server/routes.d.ts +11 -0
  68. package/dist/server/routes.js +42 -0
  69. package/dist/server/routes.js.map +7 -0
  70. package/dist/server/types.d.ts +49 -0
  71. package/dist/server/types.js +1 -0
  72. package/dist/server/types.js.map +7 -0
  73. package/dist/types.d.ts +35 -0
  74. package/dist/types.js +1 -0
  75. package/dist/types.js.map +7 -0
  76. package/dist/utils/async.d.ts +1 -0
  77. package/dist/utils/async.js +14 -0
  78. package/dist/utils/async.js.map +7 -0
  79. package/dist/utils/banner.d.ts +1 -0
  80. package/dist/utils/banner.js +34 -0
  81. package/dist/utils/banner.js.map +7 -0
  82. package/dist/utils/duration.d.ts +1 -0
  83. package/dist/utils/duration.js +22 -0
  84. package/dist/utils/duration.js.map +7 -0
  85. package/dist/utils/html.d.ts +2 -0
  86. package/dist/utils/html.js +12 -0
  87. package/dist/utils/html.js.map +7 -0
  88. package/dist/utils/patterns.d.ts +1 -0
  89. package/dist/utils/patterns.js +8 -0
  90. package/dist/utils/patterns.js.map +7 -0
  91. package/dist/vite/codegen/api.d.ts +6 -0
  92. package/dist/vite/codegen/api.js +23 -0
  93. package/dist/vite/codegen/api.js.map +7 -0
  94. package/dist/vite/codegen/client-routes.d.ts +6 -0
  95. package/dist/vite/codegen/client-routes.js +36 -0
  96. package/dist/vite/codegen/client-routes.js.map +7 -0
  97. package/dist/vite/codegen/context.d.ts +1 -0
  98. package/dist/vite/codegen/context.js +10 -0
  99. package/dist/vite/codegen/context.js.map +7 -0
  100. package/dist/vite/codegen/entry-client.d.ts +5 -0
  101. package/dist/vite/codegen/entry-client.js +64 -0
  102. package/dist/vite/codegen/entry-client.js.map +7 -0
  103. package/dist/vite/codegen/render.d.ts +6 -0
  104. package/dist/vite/codegen/render.js +31 -0
  105. package/dist/vite/codegen/render.js.map +7 -0
  106. package/dist/vite/index.d.ts +3 -0
  107. package/dist/vite/index.js +225 -0
  108. package/dist/vite/index.js.map +7 -0
  109. package/package.json +77 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 devlusoft
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,216 @@
1
+ # devix
2
+
3
+ Un meta-framework ligero de React 19 con SSR, impulsado por Vite 8 + Hono.
4
+
5
+ Construye aplicaciones React full-stack con enrutamiento basado en archivos, renderizado del lado del servidor, generación estática de sitios y rutas API — configuración mínima, control máximo.
6
+
7
+ > **⚠️ En desarrollo activo** — devix está en evolución constante. Las API's pueden cambiar entre versiones sin período de deprecación. No se recomienda para uso en producción todavía.
8
+
9
+ ## Características
10
+
11
+ - **Vite 8** — HMR instantáneo y builds rápidos con Rolldown
12
+ - **React 19** — SSR con `renderToString` e `hydrateRoot`
13
+ - **Enrutamiento basado en archivos** — páginas, layouts anidados y rutas API desde el sistema de archivos
14
+ - **SSR por defecto** — cada página se renderiza en el servidor
15
+ - **SSG** — genera HTML estático con `generateStaticParams`
16
+ - **Rutas API** — basadas en archivos, potenciadas por Hono
17
+ - **Carga de datos** — funciones `loader` con hidratación automática en el cliente
18
+ - **Guards de ruta** — redirecciones del lado del servidor antes del renderizado
19
+ - **SEO** — `metadata` y `generateMetadata` por página, con soporte de Open Graph y Twitter
20
+ - **TypeScript primero** — inferencia de tipos completa en todo el framework
21
+
22
+ ## Instalación
23
+
24
+ ```bash
25
+ npm install @devlusoft/devix react react-dom
26
+ ```
27
+
28
+ Requiere React 19+, Vite 8+, Node 20+.
29
+
30
+ ## Inicio rápido
31
+
32
+ ```bash
33
+ npx devix dev
34
+ ```
35
+
36
+ **1. Crea `devix.config.ts`:**
37
+
38
+ ```ts
39
+ import { defineConfig } from '@devlusoft/devix/config'
40
+
41
+ export default defineConfig({
42
+ port: 3000,
43
+ })
44
+ ```
45
+
46
+ **2. Crea tu primera página en `app/pages/index.tsx`:**
47
+
48
+ ```tsx
49
+ export default function Home() {
50
+ return <h1>¡Hola devix!</h1>
51
+ }
52
+ ```
53
+
54
+ **3. Ejecuta el servidor de desarrollo:**
55
+
56
+ ```bash
57
+ npx devix dev
58
+ ```
59
+
60
+ ## Convenciones de archivos
61
+
62
+ ```
63
+ app/
64
+ ├── pages/
65
+ │ ├── layout.tsx # Layout raíz (envuelve todas las páginas)
66
+ │ ├── index.tsx # → /
67
+ │ ├── about.tsx # → /about
68
+ │ └── blog/
69
+ │ ├── layout.tsx # Layout anidado (envuelve páginas de blog)
70
+ │ ├── index.tsx # → /blog
71
+ │ └── [slug].tsx # → /blog/:slug
72
+ └── api/
73
+ ├── middleware.ts # Middleware global de la API
74
+ └── posts/
75
+ └── [id].ts # → GET/POST /api/posts/:id
76
+ ```
77
+
78
+ ## Conceptos principales
79
+
80
+ ### Loader y datos
81
+
82
+ ```tsx
83
+ import { useLoaderData } from '@devlusoft/devix'
84
+ import type { PageProps, LoaderContext } from '@devlusoft/devix'
85
+
86
+ export async function loader({ params, request }: LoaderContext) {
87
+ const post = await db.posts.findBySlug(params.slug)
88
+ return post
89
+ }
90
+
91
+ export default function BlogPost({ data, params }: PageProps<typeof loader>) {
92
+ return <article>{data.title}</article>
93
+ }
94
+ ```
95
+
96
+ ### Guard de ruta
97
+
98
+ ```ts
99
+ export async function guard({ request }: LoaderContext) {
100
+ const user = await getSession(request)
101
+ if (!user) return '/login'
102
+ return null
103
+ }
104
+ ```
105
+
106
+ ### Metadata
107
+
108
+ ```ts
109
+ export const metadata = {
110
+ title: 'Inicio',
111
+ description: 'Bienvenido a mi sitio',
112
+ og: { image: '/og.png', type: 'website' },
113
+ twitter: { card: 'summary_large_image' },
114
+ }
115
+
116
+ // o dinámica:
117
+ export async function generateMetadata({ loaderData }) {
118
+ return { title: loaderData.title }
119
+ }
120
+ ```
121
+
122
+ ### Layouts
123
+
124
+ ```tsx
125
+ import type { LayoutProps } from '@devlusoft/devix'
126
+
127
+ export default function RootLayout({ children }: LayoutProps) {
128
+ return (
129
+ <div>
130
+ <nav>...</nav>
131
+ {children}
132
+ </div>
133
+ )
134
+ }
135
+ ```
136
+
137
+ ### Rutas API
138
+
139
+ ```ts
140
+ import type { RouteHandler } from '@devlusoft/devix'
141
+
142
+ export const GET: RouteHandler = async (ctx, req) => {
143
+ return Response.json({ hello: 'world' })
144
+ }
145
+
146
+ export const POST: RouteHandler = async (ctx, req) => {
147
+ const body = await req.json()
148
+ return Response.json(body, { status: 201 })
149
+ }
150
+ ```
151
+
152
+ ### Generación estática (SSG)
153
+
154
+ Configura `output: 'static'` y exporta `generateStaticParams` desde cualquier página dinámica:
155
+
156
+ ```ts
157
+ // devix.config.ts
158
+ export default defineConfig({ output: 'static' })
159
+ ```
160
+
161
+ ```ts
162
+ // app/pages/blog/[slug].tsx
163
+ export async function generateStaticParams() {
164
+ const posts = await db.posts.all()
165
+ return posts.map(p => ({ slug: p.slug }))
166
+ }
167
+ ```
168
+
169
+ ```bash
170
+ npx devix generate # compila y pre-renderiza todas las páginas en dist/client/
171
+ npx devix start # sirve los archivos estáticos (sin SSR en runtime)
172
+ ```
173
+
174
+ ## Comandos
175
+
176
+ | Comando | Descripción |
177
+ |------------------|-------------------------------------------------|
178
+ | `devix dev` | Inicia el servidor de desarrollo con HMR |
179
+ | `devix build` | Compila para producción |
180
+ | `devix start` | Inicia el servidor de producción |
181
+ | `devix generate` | Compila y pre-renderiza todas las páginas (SSG) |
182
+
183
+ ## Configuración
184
+
185
+ ```ts
186
+ // devix.config.ts
187
+ import { defineConfig } from '@devlusoft/devix/config'
188
+
189
+ export default defineConfig({
190
+ port: 3000, // puerto del servidor dev y producción (default: 3000)
191
+ host: false, // bind a 0.0.0.0 (default: false)
192
+ appDir: 'app', // directorio de la app (default: 'app')
193
+ output: 'server', // 'server' | 'static' (default: 'server')
194
+ loaderTimeout: 10_000, // timeout de los loaders en ms (default: 10000)
195
+ css: ['./app/styles/global.css'], // archivos CSS globales
196
+ envPrefix: 'PUBLIC_', // expone variables de entorno con este prefijo al cliente
197
+ vite: {}, // extiende la configuración de Vite
198
+ })
199
+ ```
200
+
201
+ ## Documentación
202
+
203
+ La documentación completa está en la carpeta [`docs/`](./docs):
204
+
205
+ - [Primeros pasos](./docs/getting-started.md)
206
+ - [Enrutamiento](./docs/routing.md)
207
+ - [Layouts](./docs/layouts.md)
208
+ - [Carga de datos](./docs/data-loading.md)
209
+ - [Rutas API](./docs/api-routes.md)
210
+ - [Metadata y SEO](./docs/metadata.md)
211
+ - [Generación estática (SSG)](./docs/ssg.md)
212
+ - [Configuración](./docs/configuration.md)
213
+
214
+ ## Licencia
215
+
216
+ MIT — devix es un proyecto de [devlusoft](https://www.devlusoft.com).
package/bin/devix.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../dist/cli/index.js'
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,286 @@
1
+ // src/cli/build.ts
2
+ import { writeFileSync } from "node:fs";
3
+ import { resolve as resolve2 } from "node:path";
4
+ import { build } from "vite";
5
+
6
+ // src/vite/index.ts
7
+ import { mergeConfig } from "vite";
8
+ import react from "@vitejs/plugin-react";
9
+ import { fileURLToPath } from "node:url";
10
+ import { dirname, resolve } from "node:path";
11
+
12
+ // src/vite/codegen/entry-client.ts
13
+ function generateEntryClient({ cssUrls }) {
14
+ const cssImports = cssUrls.map((u) => `import '${u}'`).join("\n");
15
+ return `
16
+ ${cssImports}
17
+ import "@vitejs/plugin-react/preamble"
18
+ import React from "react"
19
+ import {hydrateRoot, createRoot} from 'react-dom/client'
20
+ import {matchClientRoute, loadErrorPage, getDefaultErrorPage} from 'virtual:devix/client-routes'
21
+ import {RouterProvider} from '@devlusoft/devix'
22
+
23
+ const root = document.getElementById('devix-root')
24
+
25
+ if (!window.__DEVIX__) {
26
+ const ErrorPage = getDefaultErrorPage()
27
+ createRoot(root).render(React.createElement(ErrorPage, {statusCode: 500, message: 'Server error'}))
28
+ } else {
29
+ const {metadata, viewport, clientEntry} = window.__DEVIX__
30
+ const loaderData = window.__LOADER_DATA__
31
+ const layoutsData = window.__LAYOUTS_DATA__ ?? []
32
+
33
+ const matched = matchClientRoute(window.location.pathname)
34
+
35
+ if (matched) {
36
+ const [pageMod, ...layoutMods] = await Promise.all([
37
+ matched.load(),
38
+ ...matched.loadLayouts.map(l => l()),
39
+ ])
40
+ hydrateRoot(
41
+ root,
42
+ React.createElement(RouterProvider, {
43
+ clientEntry,
44
+ initialData: loaderData,
45
+ initialParams: matched.params,
46
+ initialPage: pageMod.default,
47
+ initialLayouts: layoutMods.map(m => m.default),
48
+ initialLayoutsData: layoutsData,
49
+ initialMeta: metadata,
50
+ initialViewport: viewport,
51
+ })
52
+ )
53
+ } else {
54
+ const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()
55
+ createRoot(root).render(
56
+ React.createElement(RouterProvider, {
57
+ clientEntry,
58
+ initialData: null,
59
+ initialParams: {},
60
+ initialPage: () => null,
61
+ initialLayouts: [],
62
+ initialLayoutsData: [],
63
+ initialMeta: null,
64
+ initialError: {statusCode: 404, message: 'Not found'},
65
+ initialErrorPage: ErrorPage,
66
+ })
67
+ )
68
+ }
69
+ }
70
+ `;
71
+ }
72
+
73
+ // src/vite/codegen/client-routes.ts
74
+ function generateClientRoutes({ pagesDir, matcherPath }) {
75
+ return `
76
+ import React from 'react'
77
+ import { createMatcher } from '${matcherPath}'
78
+ const pageFiles = import.meta.glob(['/${pagesDir}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])
79
+ const layoutFiles = import.meta.glob('/${pagesDir}/**/layout.tsx')
80
+ const errorFiles = import.meta.glob('/${pagesDir}/**/error.tsx')
81
+
82
+ export const matchClientRoute = createMatcher(pageFiles, layoutFiles)
83
+
84
+ export async function loadErrorPage() {
85
+ const key = Object.keys(errorFiles)[0]
86
+ if (!key) return null
87
+ const mod = await errorFiles[key]()
88
+ return mod?.default ?? null
89
+ }
90
+
91
+ export function getDefaultErrorPage() {
92
+ return function DefaultError({ statusCode, message }) {
93
+ return React.createElement('main', {
94
+ style: { minHeight: '100dvh', display: 'flex', flexDirection: 'column',
95
+ alignItems: 'center', justifyContent: 'center', gap: '8px',
96
+ fontFamily: 'system-ui, sans-serif' }
97
+ },
98
+ React.createElement('h1', {style: {fontSize: '4rem', fontWeight: 700}}, statusCode),
99
+ React.createElement('p', {style: {color: '#666'}}, message ?? 'An unexpected error occurred'),
100
+ )
101
+ }
102
+ }
103
+ `;
104
+ }
105
+
106
+ // src/vite/codegen/render.ts
107
+ function generateRender({ pagesDir, renderPath }) {
108
+ return `
109
+ import { render as _render, runLoader as _runLoader, getStaticRoutes as _getStaticRoutes } from '${renderPath}'
110
+
111
+ const _pages = import.meta.glob(['/${pagesDir}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])
112
+ const _layouts = import.meta.glob('/${pagesDir}/**/layout.tsx')
113
+
114
+ const _glob = {
115
+ pages: _pages,
116
+ layouts: _layouts,
117
+ pagesDir: '/${pagesDir}',
118
+ }
119
+
120
+ export function render(url, request, options) {
121
+ return _render(url, request, _glob, options)
122
+ }
123
+
124
+ export function runLoader(url, request, options) {
125
+ return _runLoader(url, request, _glob, options)
126
+ }
127
+
128
+ export function getStaticRoutes() {
129
+ return _getStaticRoutes(_glob)
130
+ }
131
+ `;
132
+ }
133
+
134
+ // src/vite/codegen/api.ts
135
+ function generateApi({ apiPath, appDir }) {
136
+ return `
137
+ import { handleApiRequest as _handleApiRequest } from '${apiPath}'
138
+
139
+ const _routes = import.meta.glob(['/${appDir}/api/**/*.ts', '!**/middleware.ts'])
140
+ const _middlewares = import.meta.glob('/${appDir}/api/**/middleware.ts')
141
+
142
+ const _glob = {
143
+ routes: _routes,
144
+ middlewares: _middlewares,
145
+ apiDir: '/${appDir}/api',
146
+ }
147
+
148
+ export function handleApiRequest(url, request) {
149
+ return _handleApiRequest(url, request, _glob)
150
+ }
151
+ `;
152
+ }
153
+
154
+ // src/server/pages-router.ts
155
+ var cache = null;
156
+ function invalidatePagesCache() {
157
+ cache = null;
158
+ }
159
+
160
+ // src/server/api-router.ts
161
+ var cache2 = null;
162
+ function invalidateApiCache() {
163
+ cache2 = null;
164
+ }
165
+
166
+ // src/vite/codegen/context.ts
167
+ function generateContext() {
168
+ return `
169
+ export {RouterContext} from '@devlusoft/devix/runtime/context'
170
+ `;
171
+ }
172
+
173
+ // src/vite/index.ts
174
+ var __dirname = dirname(fileURLToPath(import.meta.url));
175
+ var VIRTUAL_ENTRY_CLIENT = "virtual:devix/entry-client";
176
+ var VIRTUAL_CLIENT_ROUTES = "virtual:devix/client-routes";
177
+ var VIRTUAL_RENDER = "virtual:devix/render";
178
+ var VIRTUAL_API = "virtual:devix/api";
179
+ var VIRTUAL_CONTEXT = "virtual:devix/context";
180
+ function devix(config2) {
181
+ const appDir = config2.appDir ?? "app";
182
+ const pagesDir = `${appDir}/pages`;
183
+ const cssUrls = (config2.css ?? []).map((u) => u.startsWith("/") ? u : `/${u.replace(/^\.\//, "")}`);
184
+ const renderPath = resolve(__dirname, "../server/render.js").replace(/\\/g, "/");
185
+ const apiPath = resolve(__dirname, "../server/api.js").replace(/\\/g, "/");
186
+ const matcherPath = resolve(__dirname, "../runtime/client-router.js").replace(/\\/g, "/");
187
+ const virtualPlugin = {
188
+ name: "devix",
189
+ enforce: "pre",
190
+ resolveId(id) {
191
+ if (id === VIRTUAL_ENTRY_CLIENT) return `\0${VIRTUAL_ENTRY_CLIENT}`;
192
+ if (id === VIRTUAL_CLIENT_ROUTES) return `\0${VIRTUAL_CLIENT_ROUTES}`;
193
+ if (id === VIRTUAL_RENDER) return `\0${VIRTUAL_RENDER}`;
194
+ if (id === VIRTUAL_API) return `\0${VIRTUAL_API}`;
195
+ if (id === VIRTUAL_CONTEXT) return `\0${VIRTUAL_CONTEXT}`;
196
+ },
197
+ load(id) {
198
+ if (id === `\0${VIRTUAL_ENTRY_CLIENT}`)
199
+ return generateEntryClient({ cssUrls });
200
+ if (id === `\0${VIRTUAL_CLIENT_ROUTES}`)
201
+ return generateClientRoutes({ pagesDir, matcherPath });
202
+ if (id === `\0${VIRTUAL_RENDER}`)
203
+ return generateRender({ pagesDir, renderPath });
204
+ if (id === `\0${VIRTUAL_API}`)
205
+ return generateApi({ apiPath, appDir });
206
+ if (id === `\0${VIRTUAL_CONTEXT}`)
207
+ return generateContext();
208
+ },
209
+ configureServer(server) {
210
+ server.watcher.on("add", (file) => {
211
+ if (file.startsWith(resolve(process.cwd(), pagesDir))) invalidatePagesCache();
212
+ if (file.includes(`${appDir}/api`)) invalidateApiCache();
213
+ });
214
+ server.watcher.on("unlink", (file) => {
215
+ if (file.startsWith(resolve(process.cwd(), pagesDir))) invalidatePagesCache();
216
+ if (file.includes(`${appDir}/api`)) invalidateApiCache();
217
+ });
218
+ }
219
+ };
220
+ const base = {
221
+ plugins: [react(), virtualPlugin],
222
+ ssr: { noExternal: ["@devlusoft/devix"] },
223
+ ...config2.envPrefix ? { envPrefix: config2.envPrefix } : {}
224
+ };
225
+ return mergeConfig(base, config2.vite ?? {});
226
+ }
227
+
228
+ // src/utils/duration.ts
229
+ function parseDuration(value) {
230
+ if (typeof value === "number") return value;
231
+ const match = value.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h)?$/);
232
+ if (!match) throw new Error(`[devix] Invalid duration: "${value}". Use a number (ms) or a string like "5s", "2m", "500ms".`);
233
+ const n = parseFloat(match[1]);
234
+ switch (match[2]) {
235
+ case "h":
236
+ return n * 36e5;
237
+ case "m":
238
+ return n * 6e4;
239
+ case "s":
240
+ return n * 1e3;
241
+ case "ms":
242
+ default:
243
+ return n;
244
+ }
245
+ }
246
+
247
+ // src/cli/build.ts
248
+ var config = (await import(`${process.cwd()}/devix.config.ts`)).default;
249
+ var baseConfig = devix(config);
250
+ await build({
251
+ ...baseConfig,
252
+ configFile: false,
253
+ build: {
254
+ outDir: "dist/client",
255
+ manifest: true,
256
+ rolldownOptions: {
257
+ input: "virtual:devix/entry-client"
258
+ }
259
+ }
260
+ });
261
+ await build({
262
+ ...baseConfig,
263
+ configFile: false,
264
+ build: {
265
+ ssr: true,
266
+ outDir: "dist/server",
267
+ rolldownOptions: {
268
+ input: {
269
+ render: "virtual:devix/render",
270
+ api: "virtual:devix/api"
271
+ }
272
+ }
273
+ }
274
+ });
275
+ var runtimeConfig = {
276
+ port: config.port ?? 3e3,
277
+ host: config.host ?? false,
278
+ loaderTimeout: parseDuration(config.loaderTimeout ?? 1e4),
279
+ output: config.output ?? "server"
280
+ };
281
+ writeFileSync(
282
+ resolve2(process.cwd(), "dist/devix.config.json"),
283
+ JSON.stringify(runtimeConfig, null, 2),
284
+ "utf-8"
285
+ );
286
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cli/build.ts", "../../src/vite/index.ts", "../../src/vite/codegen/entry-client.ts", "../../src/vite/codegen/client-routes.ts", "../../src/vite/codegen/render.ts", "../../src/vite/codegen/api.ts", "../../src/server/pages-router.ts", "../../src/server/api-router.ts", "../../src/vite/codegen/context.ts", "../../src/utils/duration.ts"],
4
+ "sourcesContent": ["import {writeFileSync} from 'node:fs'\nimport {resolve} from 'node:path'\nimport {build} from 'vite'\nimport type {DevixConfig} from '../config'\nimport {devix} from '../vite'\nimport {parseDuration} from '../utils/duration'\n\nconst config: DevixConfig = (await import(`${process.cwd()}/devix.config.ts`)).default\nconst baseConfig = devix(config)\n\nawait build({\n ...baseConfig,\n configFile: false,\n build: {\n outDir: 'dist/client',\n manifest: true,\n rolldownOptions: {\n input: 'virtual:devix/entry-client',\n },\n },\n})\n\nawait build({\n ...baseConfig,\n configFile: false,\n build: {\n ssr: true,\n outDir: 'dist/server',\n rolldownOptions: {\n input: {\n render: 'virtual:devix/render',\n api: 'virtual:devix/api',\n },\n },\n },\n})\n\nconst runtimeConfig = {\n port: config.port ?? 3000,\n host: config.host ?? false,\n loaderTimeout: parseDuration(config.loaderTimeout ?? 10_000),\n output: config.output ?? 'server',\n}\n\nwriteFileSync(\n resolve(process.cwd(), 'dist/devix.config.json'),\n JSON.stringify(runtimeConfig, null, 2),\n 'utf-8'\n)\n\n\nexport {}", "import {UserConfig, Plugin, mergeConfig} from 'vite'\nimport type {DevixConfig} from '../config'\nimport react from '@vitejs/plugin-react'\nimport {fileURLToPath} from 'node:url'\nimport {dirname, resolve} from 'node:path'\nimport {generateEntryClient} from './codegen/entry-client'\nimport {generateClientRoutes} from './codegen/client-routes'\nimport {generateRender} from './codegen/render'\nimport {generateApi} from './codegen/api'\nimport {invalidatePagesCache} from \"../server/pages-router\";\nimport {invalidateApiCache} from \"../server/api-router\";\nimport {generateContext} from \"./codegen/context\";\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'\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\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 },\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 },\n\n configureServer(server) {\n server.watcher.on('add', (file) => {\n if (file.startsWith(resolve(process.cwd(), pagesDir))) invalidatePagesCache()\n if (file.includes(`${appDir}/api`)) invalidateApiCache()\n })\n server.watcher.on('unlink', (file) => {\n if (file.startsWith(resolve(process.cwd(), pagesDir))) invalidatePagesCache()\n if (file.includes(`${appDir}/api`)) invalidateApiCache()\n })\n },\n }\n\n const base: UserConfig = {\n plugins: [react(), virtualPlugin],\n ssr: {noExternal: ['@devlusoft/devix']},\n ...(config.envPrefix ? {envPrefix: config.envPrefix} : {}),\n }\n\n return mergeConfig(base, config.vite ?? {})\n}", "interface EntryClientOptions {\n cssUrls: string[]\n}\n\nexport function generateEntryClient({cssUrls}: EntryClientOptions): string {\n const cssImports = cssUrls.map(u => `import '${u}'`).join('\\n')\n\n return `\n${cssImports}\nimport \"@vitejs/plugin-react/preamble\"\nimport React from \"react\"\nimport {hydrateRoot, createRoot} from 'react-dom/client'\nimport {matchClientRoute, loadErrorPage, getDefaultErrorPage} from 'virtual:devix/client-routes'\nimport {RouterProvider} from '@devlusoft/devix'\n\nconst root = document.getElementById('devix-root')\n\nif (!window.__DEVIX__) {\n const ErrorPage = getDefaultErrorPage()\n createRoot(root).render(React.createElement(ErrorPage, {statusCode: 500, message: 'Server error'}))\n} else {\n const {metadata, viewport, clientEntry} = window.__DEVIX__\n const loaderData = window.__LOADER_DATA__\n const layoutsData = window.__LAYOUTS_DATA__ ?? []\n\n const matched = matchClientRoute(window.location.pathname)\n\n if (matched) {\n const [pageMod, ...layoutMods] = await Promise.all([\n matched.load(),\n ...matched.loadLayouts.map(l => l()),\n ])\n hydrateRoot(\n root,\n React.createElement(RouterProvider, {\n clientEntry,\n initialData: loaderData,\n initialParams: matched.params,\n initialPage: pageMod.default,\n initialLayouts: layoutMods.map(m => m.default),\n initialLayoutsData: layoutsData,\n initialMeta: metadata,\n initialViewport: viewport,\n })\n )\n } 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", "import {routePattern} from \"../utils/patterns\";\n\nexport interface Page {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface Layout {\n dir: string\n key: string\n}\n\nexport interface PagesResult {\n pages: Page[]\n layouts: Layout[]\n}\n\nfunction keyToRoutePattern(key: string, pagesDir: string): string {\n const rel = key.slice(pagesDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === \"/\" ? \"/\" : `/${pattern}`\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: PagesResult | null = null\n\nexport function invalidatePagesCache() {\n cache = null\n}\n\nexport function buildPages(pageKeys: string[], layoutKeys: string[], pagesDir: string): PagesResult {\n if (cache) return cache\n\n const pages: Page[] = []\n const layouts: Layout[] = []\n\n for (const key of layoutKeys) {\n layouts.push({dir: keyToDir(key), key})\n }\n\n for (const key of pageKeys) {\n const pattern = keyToRoutePattern(key, pagesDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n pages.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n\n pages.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {pages, layouts}\n return cache\n}\n\nexport function collectLayoutChain(pageKey: string, layouts: Layout[]): Layout[] {\n const pageDir = keyToDir(pageKey)\n\n return layouts\n .filter(layout => pageDir.startsWith(layout.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchPage(pathname: string, pages: Page[]): {\n page: Page\n params: Record<string, string>\n} | null {\n for (const page of pages) {\n const match = pathname.match(page.regex)\n if (match) {\n const params: Record<string, string> = {}\n page.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {page, params}\n }\n }\n return null\n}\n", "import {routePattern} from \"../utils/patterns\";\n\nexport interface ApiRoute {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface ApiMiddleware {\n dir: string\n key: string\n}\n\nexport interface ApiResult {\n routes: ApiRoute[]\n middlewares: ApiMiddleware[]\n}\n\nfunction keyToRoutePattern(key: string, apiDir: string): string {\n const rel = key.slice(apiDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === '/' ? '/api' : `/api/${pattern}`.replace('/api//', '/api/')\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: ApiResult | null = null\n\nexport function invalidateApiCache() {\n cache = null\n}\n\nexport function buildRoutes(routeKeys: string[], middlewareKeys: string[], apiDir: string): ApiResult {\n if (cache) return cache\n\n const routes: ApiRoute[] = []\n const middlewares: ApiMiddleware[] = []\n\n for (const key of middlewareKeys) {\n middlewares.push({dir: keyToDir(key), key})\n }\n\n for (const key of routeKeys) {\n const pattern = keyToRoutePattern(key, apiDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n routes.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n routes.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {routes, middlewares}\n return cache\n}\n\nexport function collectMiddlewareChain(routeKey: string, middlewares: ApiMiddleware[]): ApiMiddleware[] {\n const routeDir = keyToDir(routeKey)\n\n return middlewares\n .filter(mw => routeDir.startsWith(mw.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchRoute(\n pathname: string,\n routes: ApiRoute[]\n): {route: ApiRoute; params: Record<string, string>} | null {\n for (const route of routes) {\n const match = pathname.match(route.regex)\n if (match) {\n const params: Record<string, string> = {}\n route.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {route, params}\n }\n }\n return null\n}\n", "export function generateContext(): string {\n return `\nexport {RouterContext} from '@devlusoft/devix/runtime/context'\n`\n}", "export function parseDuration(value: number | string): number {\n if (typeof value === 'number') return value\n const match = value.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h)?$/)\n if (!match) throw new Error(`[devix] Invalid duration: \"${value}\". Use a number (ms) or a string like \"5s\", \"2m\", \"500ms\".`)\n const n = parseFloat(match[1])\n switch (match[2]) {\n case 'h': return n * 3_600_000\n case 'm': return n * 60_000\n case 's': return n * 1_000\n case 'ms':\n default: return n\n }\n}\n"],
5
+ "mappings": ";AAAA,SAAQ,qBAAoB;AAC5B,SAAQ,WAAAA,gBAAc;AACtB,SAAQ,aAAY;;;ACFpB,SAA4B,mBAAkB;AAE9C,OAAO,WAAW;AAClB,SAAQ,qBAAoB;AAC5B,SAAQ,SAAS,eAAc;;;ACAxB,SAAS,oBAAoB,EAAC,QAAO,GAA+B;AACvE,QAAM,aAAa,QAAQ,IAAI,OAAK,WAAW,CAAC,GAAG,EAAE,KAAK,IAAI;AAE9D,SAAO;AAAA,EACT,UAAU;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;AAuDZ;;;AC1DO,SAAS,qBAAqB,EAAC,UAAU,YAAW,GAAwB;AAC/E,SAAO;AAAA;AAAA,iCAEsB,WAAW;AAAA,wCACJ,QAAQ;AAAA,yCACP,QAAQ;AAAA,wCACT,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBhD;;;AC9BO,SAAS,eAAe,EAAC,UAAU,WAAU,GAA0B;AAC1E,SAAO;AAAA,mGACwF,UAAU;AAAA;AAAA,qCAExE,QAAQ;AAAA,sCACP,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,kBAK5B,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAe1B;;;ACzBO,SAAS,YAAY,EAAC,SAAS,OAAM,GAAuB;AAC/D,SAAO;AAAA,yDAC8C,OAAO;AAAA;AAAA,sCAE1B,MAAM;AAAA,0CACF,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,gBAKhC,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOtB;;;ACOA,IAAI,QAA4B;AAEzB,SAAS,uBAAuB;AACnC,UAAQ;AACZ;;;ACJA,IAAIC,SAA0B;AAEvB,SAAS,qBAAqB;AACjC,EAAAA,SAAQ;AACZ;;;ACjCO,SAAS,kBAA0B;AACtC,SAAO;AAAA;AAAA;AAGX;;;APSA,IAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAExD,IAAM,uBAAuB;AAC7B,IAAM,wBAAwB;AAC9B,IAAM,iBAAiB;AACvB,IAAM,cAAc;AACpB,IAAM,kBAAkB;AAEjB,SAAS,MAAMC,SAAiC;AACnD,QAAM,SAASA,QAAO,UAAU;AAChC,QAAM,WAAW,GAAG,MAAM;AAC1B,QAAM,WAAWA,QAAO,OAAO,CAAC,GAAG,IAAI,OAAK,EAAE,WAAW,GAAG,IAAI,IAAI,IAAI,EAAE,QAAQ,SAAS,EAAE,CAAC,EAAE;AAEhG,QAAM,aAAa,QAAQ,WAAW,qBAAqB,EAAE,QAAQ,OAAO,GAAG;AAC/E,QAAM,UAAU,QAAQ,WAAW,kBAAkB,EAAE,QAAQ,OAAO,GAAG;AACzE,QAAM,cAAc,QAAQ,WAAW,6BAA6B,EAAE,QAAQ,OAAO,GAAG;AAExF,QAAM,gBAAwB;AAAA,IAC1B,MAAM;AAAA,IACN,SAAS;AAAA,IAET,UAAU,IAAI;AACV,UAAI,OAAO,qBAAsB,QAAO,KAAK,oBAAoB;AACjE,UAAI,OAAO,sBAAuB,QAAO,KAAK,qBAAqB;AACnE,UAAI,OAAO,eAAgB,QAAO,KAAK,cAAc;AACrD,UAAI,OAAO,YAAa,QAAO,KAAK,WAAW;AAC/C,UAAI,OAAO,gBAAiB,QAAO,KAAK,eAAe;AAAA,IAC3D;AAAA,IAEA,KAAK,IAAI;AACL,UAAI,OAAO,KAAK,oBAAoB;AAChC,eAAO,oBAAoB,EAAC,QAAO,CAAC;AACxC,UAAI,OAAO,KAAK,qBAAqB;AACjC,eAAO,qBAAqB,EAAC,UAAU,YAAW,CAAC;AACvD,UAAI,OAAO,KAAK,cAAc;AAC1B,eAAO,eAAe,EAAC,UAAU,WAAU,CAAC;AAChD,UAAI,OAAO,KAAK,WAAW;AACvB,eAAO,YAAY,EAAC,SAAS,OAAM,CAAC;AACxC,UAAI,OAAO,KAAK,eAAe;AAC3B,eAAO,gBAAgB;AAAA,IAC/B;AAAA,IAEA,gBAAgB,QAAQ;AACpB,aAAO,QAAQ,GAAG,OAAO,CAAC,SAAS;AAC/B,YAAI,KAAK,WAAW,QAAQ,QAAQ,IAAI,GAAG,QAAQ,CAAC,EAAG,sBAAqB;AAC5E,YAAI,KAAK,SAAS,GAAG,MAAM,MAAM,EAAG,oBAAmB;AAAA,MAC3D,CAAC;AACD,aAAO,QAAQ,GAAG,UAAU,CAAC,SAAS;AAClC,YAAI,KAAK,WAAW,QAAQ,QAAQ,IAAI,GAAG,QAAQ,CAAC,EAAG,sBAAqB;AAC5E,YAAI,KAAK,SAAS,GAAG,MAAM,MAAM,EAAG,oBAAmB;AAAA,MAC3D,CAAC;AAAA,IACL;AAAA,EACJ;AAEA,QAAM,OAAmB;AAAA,IACrB,SAAS,CAAC,MAAM,GAAG,aAAa;AAAA,IAChC,KAAK,EAAC,YAAY,CAAC,kBAAkB,EAAC;AAAA,IACtC,GAAIA,QAAO,YAAY,EAAC,WAAWA,QAAO,UAAS,IAAI,CAAC;AAAA,EAC5D;AAEA,SAAO,YAAY,MAAMA,QAAO,QAAQ,CAAC,CAAC;AAC9C;;;AQ1EO,SAAS,cAAc,OAAgC;AAC1D,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,QAAQ,MAAM,KAAK,EAAE,MAAM,iCAAiC;AAClE,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,8BAA8B,KAAK,4DAA4D;AAC3H,QAAM,IAAI,WAAW,MAAM,CAAC,CAAC;AAC7B,UAAQ,MAAM,CAAC,GAAG;AAAA,IACd,KAAK;AAAM,aAAO,IAAI;AAAA,IACtB,KAAK;AAAM,aAAO,IAAI;AAAA,IACtB,KAAK;AAAM,aAAO,IAAI;AAAA,IACtB,KAAK;AAAA,IACL;AAAW,aAAO;AAAA,EACtB;AACJ;;;ATLA,IAAM,UAAuB,MAAM,OAAO,GAAG,QAAQ,IAAI,CAAC,qBAAqB;AAC/E,IAAM,aAAa,MAAM,MAAM;AAE/B,MAAM,MAAM;AAAA,EACR,GAAG;AAAA,EACH,YAAY;AAAA,EACZ,OAAO;AAAA,IACH,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,iBAAiB;AAAA,MACb,OAAO;AAAA,IACX;AAAA,EACJ;AACJ,CAAC;AAED,MAAM,MAAM;AAAA,EACR,GAAG;AAAA,EACH,YAAY;AAAA,EACZ,OAAO;AAAA,IACH,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,iBAAiB;AAAA,MACb,OAAO;AAAA,QACH,QAAQ;AAAA,QACR,KAAK;AAAA,MACT;AAAA,IACJ;AAAA,EACJ;AACJ,CAAC;AAED,IAAM,gBAAgB;AAAA,EAClB,MAAM,OAAO,QAAQ;AAAA,EACrB,MAAM,OAAO,QAAQ;AAAA,EACrB,eAAe,cAAc,OAAO,iBAAiB,GAAM;AAAA,EAC3D,QAAQ,OAAO,UAAU;AAC7B;AAEA;AAAA,EACIC,SAAQ,QAAQ,IAAI,GAAG,wBAAwB;AAAA,EAC/C,KAAK,UAAU,eAAe,MAAM,CAAC;AAAA,EACrC;AACJ;",
6
+ "names": ["resolve", "cache", "config", "resolve"]
7
+ }
@@ -0,0 +1 @@
1
+ export {};