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

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 (84) hide show
  1. package/dist/cli/build.d.ts +1 -0
  2. package/dist/cli/build.js +86 -7
  3. package/dist/cli/build.js.map +4 -4
  4. package/dist/cli/dev-server.d.ts +1 -0
  5. package/dist/cli/dev-server.js +234 -0
  6. package/dist/cli/dev-server.js.map +7 -0
  7. package/dist/cli/dev.d.ts +1 -0
  8. package/dist/cli/dev.js +1 -1
  9. package/dist/cli/dev.js.map +3 -3
  10. package/dist/cli/generate.d.ts +1 -0
  11. package/dist/cli/generate.js +88 -9
  12. package/dist/cli/generate.js.map +4 -4
  13. package/dist/cli/index.d.ts +2 -0
  14. package/dist/cli/index.js +102 -23
  15. package/dist/cli/index.js.map +4 -4
  16. package/dist/cli/start.d.ts +1 -0
  17. package/dist/cli/start.js +1 -1
  18. package/dist/cli/start.js.map +3 -3
  19. package/dist/config.d.ts +22 -0
  20. package/dist/runtime/api-context.d.ts +24 -0
  21. package/dist/runtime/client-router.d.ts +13 -0
  22. package/dist/runtime/context.d.ts +32 -0
  23. package/dist/runtime/create-handler.d.ts +10 -0
  24. package/dist/runtime/error-boundary.d.ts +19 -0
  25. package/dist/runtime/fetch.d.ts +39 -0
  26. package/dist/runtime/head.d.ts +7 -0
  27. package/dist/runtime/head.js +1 -1
  28. package/dist/runtime/head.js.map +3 -3
  29. package/dist/runtime/index.d.ts +14 -0
  30. package/dist/runtime/index.js +1 -1
  31. package/dist/runtime/index.js.map +3 -3
  32. package/dist/runtime/link.d.ts +8 -0
  33. package/dist/runtime/metadata.d.ts +10 -0
  34. package/dist/runtime/router-provider.d.ts +25 -0
  35. package/dist/runtime/router-provider.js +1 -1
  36. package/dist/runtime/router-provider.js.map +3 -3
  37. package/dist/runtime/server-app.d.ts +15 -0
  38. package/dist/runtime/server-app.js +1 -1
  39. package/dist/runtime/server-app.js.map +3 -3
  40. package/dist/server/api-router.d.ts +22 -0
  41. package/dist/server/api.d.ts +2 -0
  42. package/dist/server/collect-css.d.ts +2 -0
  43. package/dist/server/handler-store.d.ts +10 -0
  44. package/dist/server/index.d.ts +6 -0
  45. package/dist/server/pages-router.d.ts +21 -0
  46. package/dist/server/public-index.d.ts +1 -0
  47. package/dist/server/render.d.ts +62 -0
  48. package/dist/server/render.js +1 -1
  49. package/dist/server/render.js.map +3 -3
  50. package/dist/server/routes.d.ts +11 -0
  51. package/dist/server/types.d.ts +52 -0
  52. package/dist/src/cli/dev-server.d.ts +1 -0
  53. package/dist/types.d.ts +49 -0
  54. package/dist/utils/async.d.ts +1 -0
  55. package/dist/utils/banner.d.ts +1 -0
  56. package/dist/utils/banner.js +1 -1
  57. package/dist/utils/banner.js.map +1 -1
  58. package/dist/utils/cookies.d.ts +12 -0
  59. package/dist/utils/duration.d.ts +1 -0
  60. package/dist/utils/env.d.ts +1 -0
  61. package/dist/utils/html.d.ts +2 -0
  62. package/dist/utils/load-config.d.ts +2 -0
  63. package/dist/utils/load-config.js +2 -0
  64. package/dist/utils/load-config.js.map +7 -0
  65. package/dist/utils/patterns.d.ts +1 -0
  66. package/dist/utils/response.d.ts +19 -0
  67. package/dist/vite/codegen/api.d.ts +6 -0
  68. package/dist/vite/codegen/client-routes.d.ts +6 -0
  69. package/dist/vite/codegen/context.d.ts +1 -0
  70. package/dist/vite/codegen/entry-client.d.ts +5 -0
  71. package/dist/vite/codegen/entry-client.js +11 -3
  72. package/dist/vite/codegen/entry-client.js.map +2 -2
  73. package/dist/vite/codegen/extract-methods.d.ts +4 -0
  74. package/dist/vite/codegen/render.d.ts +6 -0
  75. package/dist/vite/codegen/routes-dts.d.ts +10 -0
  76. package/dist/vite/codegen/scan-api.d.ts +2 -0
  77. package/dist/vite/codegen/server-entry.d.ts +6 -0
  78. package/dist/vite/codegen/server-entry.js +73 -0
  79. package/dist/vite/codegen/server-entry.js.map +7 -0
  80. package/dist/vite/codegen/write-routes-dts.d.ts +1 -0
  81. package/dist/vite/index.d.ts +3 -0
  82. package/dist/vite/index.js +84 -5
  83. package/dist/vite/index.js.map +4 -4
  84. package/package.json +1 -1
@@ -0,0 +1,49 @@
1
+ export interface MetadataIcon {
2
+ href: string;
3
+ rel?: string;
4
+ type?: string;
5
+ sizes?: string;
6
+ }
7
+ export interface Metadata {
8
+ title?: string;
9
+ description?: string;
10
+ keywords?: string[];
11
+ og?: {
12
+ title?: string;
13
+ description?: string;
14
+ image?: string;
15
+ type?: 'website' | 'article' | 'product';
16
+ url?: string;
17
+ };
18
+ twitter?: {
19
+ card?: 'summary' | 'summary_large_image';
20
+ title?: string;
21
+ description?: string;
22
+ image?: string;
23
+ creator?: string;
24
+ };
25
+ canonical?: string;
26
+ robots?: string;
27
+ alternates?: Record<string, string>;
28
+ icons?: string | MetadataIcon | MetadataIcon[];
29
+ }
30
+ export interface Viewport {
31
+ width?: string | number;
32
+ initialScale?: number;
33
+ maximumScale?: number;
34
+ userScalable?: boolean;
35
+ themeColor?: string;
36
+ }
37
+ export interface LoaderContext<TParams = Record<string, string>> {
38
+ params: TParams;
39
+ request: Request;
40
+ guardData: unknown;
41
+ }
42
+ import type { Redirect } from './utils/response';
43
+ export type LoaderFunction<TData = unknown, TParams = Record<string, string>> = (ctx: LoaderContext<TParams>) => Promise<TData | Redirect | void> | TData | Redirect | void;
44
+ export type GuardFunction<TParams = Record<string, string>> = (ctx: LoaderContext<TParams>) => Promise<string | Redirect | Record<string, unknown> | null> | string | Redirect | Record<string, unknown> | null;
45
+ type GuardData<TGuard> = TGuard extends (...args: any[]) => infer R ? Exclude<Awaited<R>, string | Redirect | null | undefined> : unknown;
46
+ export type LoaderContextWithGuard<TGuard extends GuardFunction | undefined = undefined, TParams = Record<string, string>> = LoaderContext<TParams> & {
47
+ guardData: GuardData<TGuard>;
48
+ };
49
+ export {};
@@ -0,0 +1 @@
1
+ export declare function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T>;
@@ -0,0 +1 @@
1
+ export declare function printDevBanner(port: number): void;
@@ -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.4.1-beta.1",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.4.1-beta.11",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
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/banner.ts"],
4
4
  "sourcesContent": ["import pc from 'picocolors'\nimport {networkInterfaces} from 'node:os'\n\ndeclare const __DEVIX_VERSION__: string\n\nfunction getNetworkUrl(port: number): string | null {\n const nets = networkInterfaces()\n for (const interfaces of Object.values(nets)) {\n for (const net of interfaces ?? []) {\n if (net.family === 'IPv4' && !net.internal) {\n return `http://${net.address}:${port}/`\n }\n }\n }\n return null\n}\n\nexport function printDevBanner(port: number) {\n const version = __DEVIX_VERSION__\n const networkUrl = getNetworkUrl(port)\n\n console.log()\n console.log(` ${pc.bold(pc.yellow('devix'))} ${pc.dim(`v${version}`)}`)\n console.log()\n console.log(` ${pc.green('\u279C')} ${pc.bold('Local:')} ${pc.cyan(`http://localhost:${port}/`)}`)\n if (networkUrl) {\n console.log(` ${pc.green('\u279C')} ${pc.bold('Network:')} ${pc.cyan(networkUrl)}`)\n } else {\n console.log(` ${pc.green('\u279C')} ${pc.bold('Network:')} ${pc.dim('use --host to expose')}`)\n }\n console.log()\n}"],
5
- "mappings": "AAAA,OAAOA,MAAQ,aACf,OAAQ,qBAAAC,MAAwB,UAIhC,SAASC,EAAcC,EAA6B,CAChD,IAAMC,EAAOH,EAAkB,EAC/B,QAAWI,KAAc,OAAO,OAAOD,CAAI,EACvC,QAAWE,KAAOD,GAAc,CAAC,EAC7B,GAAIC,EAAI,SAAW,QAAU,CAACA,EAAI,SAC9B,MAAO,UAAUA,EAAI,OAAO,IAAIH,CAAI,IAIhD,OAAO,IACX,CAEO,SAASI,EAAeJ,EAAc,CACzC,IAAMK,EAAU,eACVC,EAAaP,EAAcC,CAAI,EAErC,QAAQ,IAAI,EACZ,QAAQ,IAAI,KAAKH,EAAG,KAAKA,EAAG,OAAO,OAAO,CAAC,CAAC,IAAIA,EAAG,IAAI,IAAIQ,CAAO,EAAE,CAAC,EAAE,EACvE,QAAQ,IAAI,EACZ,QAAQ,IAAI,KAAKR,EAAG,MAAM,QAAG,CAAC,KAAKA,EAAG,KAAK,QAAQ,CAAC,MAAMA,EAAG,KAAK,oBAAoBG,CAAI,GAAG,CAAC,EAAE,EAE5F,QAAQ,IADRM,EACY,KAAKT,EAAG,MAAM,QAAG,CAAC,KAAKA,EAAG,KAAK,UAAU,CAAC,IAAIA,EAAG,KAAKS,CAAU,CAAC,GAEjE,KAAKT,EAAG,MAAM,QAAG,CAAC,KAAKA,EAAG,KAAK,UAAU,CAAC,IAAIA,EAAG,IAAI,sBAAsB,CAAC,EAFT,EAInF,QAAQ,IAAI,CAChB",
5
+ "mappings": "AAAA,OAAOA,MAAQ,aACf,OAAQ,qBAAAC,MAAwB,UAIhC,SAASC,EAAcC,EAA6B,CAChD,IAAMC,EAAOH,EAAkB,EAC/B,QAAWI,KAAc,OAAO,OAAOD,CAAI,EACvC,QAAWE,KAAOD,GAAc,CAAC,EAC7B,GAAIC,EAAI,SAAW,QAAU,CAACA,EAAI,SAC9B,MAAO,UAAUA,EAAI,OAAO,IAAIH,CAAI,IAIhD,OAAO,IACX,CAEO,SAASI,EAAeJ,EAAc,CACzC,IAAMK,EAAU,gBACVC,EAAaP,EAAcC,CAAI,EAErC,QAAQ,IAAI,EACZ,QAAQ,IAAI,KAAKH,EAAG,KAAKA,EAAG,OAAO,OAAO,CAAC,CAAC,IAAIA,EAAG,IAAI,IAAIQ,CAAO,EAAE,CAAC,EAAE,EACvE,QAAQ,IAAI,EACZ,QAAQ,IAAI,KAAKR,EAAG,MAAM,QAAG,CAAC,KAAKA,EAAG,KAAK,QAAQ,CAAC,MAAMA,EAAG,KAAK,oBAAoBG,CAAI,GAAG,CAAC,EAAE,EAE5F,QAAQ,IADRM,EACY,KAAKT,EAAG,MAAM,QAAG,CAAC,KAAKA,EAAG,KAAK,UAAU,CAAC,IAAIA,EAAG,KAAKS,CAAU,CAAC,GAEjE,KAAKT,EAAG,MAAM,QAAG,CAAC,KAAKA,EAAG,KAAK,UAAU,CAAC,IAAIA,EAAG,IAAI,sBAAsB,CAAC,EAFT,EAInF,QAAQ,IAAI,CAChB",
6
6
  "names": ["pc", "networkInterfaces", "getNetworkUrl", "port", "nets", "interfaces", "net", "printDevBanner", "version", "networkUrl"]
7
7
  }
@@ -0,0 +1,12 @@
1
+ export interface CookieOptions {
2
+ httpOnly?: boolean;
3
+ secure?: boolean;
4
+ sameSite?: 'Strict' | 'Lax' | 'None';
5
+ maxAge?: number;
6
+ expires?: Date;
7
+ path?: string;
8
+ domain?: string;
9
+ }
10
+ export declare function getCookie(req: Request, name: string): string | undefined;
11
+ export declare function setCookie(headers: Headers, name: string, value: string, options?: CookieOptions): void;
12
+ export declare function deleteCookie(headers: Headers, name: string, options?: Pick<CookieOptions, 'path' | 'domain'>): void;
@@ -0,0 +1 @@
1
+ export declare function parseDuration(value: number | string): number;
@@ -0,0 +1 @@
1
+ export declare function loadDotenv(mode: string): void;
@@ -0,0 +1,2 @@
1
+ export declare function safeJsonStringify(value: unknown): string;
2
+ export declare function escapeAttr(value: string): string;
@@ -0,0 +1,2 @@
1
+ import type { DevixConfig } from "../config";
2
+ export declare function loadConfig(cwd: string): Promise<DevixConfig>;
@@ -0,0 +1,2 @@
1
+ import{build as n}from"esbuild";import{join as i}from"node:path";import{unlinkSync as r,writeFileSync as m}from"node:fs";import{pathToFileURL as f}from"node:url";async function u(o){let e=await n({entryPoints:[i(o,"devix.config.ts")],bundle:!0,write:!1,format:"esm",platform:"node",packages:"external"}),t=i(o,`.devix-config-${Date.now()}.mjs`);m(t,e.outputFiles[0].text);try{return(await import(f(t).href)).default}finally{r(t)}}export{u as loadConfig};
2
+ //# sourceMappingURL=load-config.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/load-config.ts"],
4
+ "sourcesContent": ["import {build} from 'esbuild'\nimport type {DevixConfig} from \"../config\"\nimport {join} from \"node:path\"\nimport {unlinkSync, writeFileSync} from \"node:fs\";\nimport {pathToFileURL} from \"node:url\";\n\nexport async function loadConfig(cwd: string): Promise<DevixConfig> {\n const result = await build({\n entryPoints: [join(cwd, 'devix.config.ts')],\n bundle: true,\n write: false,\n format: 'esm',\n platform: 'node',\n packages: 'external',\n })\n\n const tmpFile = join(cwd, `.devix-config-${Date.now()}.mjs`)\n writeFileSync(tmpFile, result.outputFiles[0].text)\n\n try {\n const mod = await import(pathToFileURL(tmpFile).href)\n return mod.default\n } finally {\n unlinkSync(tmpFile)\n }\n}"],
5
+ "mappings": "AAAA,OAAQ,SAAAA,MAAY,UAEpB,OAAQ,QAAAC,MAAW,YACnB,OAAQ,cAAAC,EAAY,iBAAAC,MAAoB,UACxC,OAAQ,iBAAAC,MAAoB,WAE5B,eAAsBC,EAAWC,EAAmC,CAChE,IAAMC,EAAS,MAAMP,EAAM,CACvB,YAAa,CAACC,EAAKK,EAAK,iBAAiB,CAAC,EAC1C,OAAQ,GACR,MAAO,GACP,OAAQ,MACR,SAAU,OACV,SAAU,UACd,CAAC,EAEKE,EAAUP,EAAKK,EAAK,iBAAiB,KAAK,IAAI,CAAC,MAAM,EAC3DH,EAAcK,EAASD,EAAO,YAAY,CAAC,EAAE,IAAI,EAEjD,GAAI,CAEA,OADY,MAAM,OAAOH,EAAcI,CAAO,EAAE,OACrC,OACf,QAAE,CACEN,EAAWM,CAAO,CACtB,CACJ",
6
+ "names": ["build", "join", "unlinkSync", "writeFileSync", "pathToFileURL", "loadConfig", "cwd", "result", "tmpFile"]
7
+ }
@@ -0,0 +1 @@
1
+ export declare function routePattern(rel: string): string;
@@ -0,0 +1,19 @@
1
+ export type JsonResponse<T = unknown> = Response & {
2
+ readonly __body: T;
3
+ };
4
+ export declare const json: <const T>(data: T, status?: number) => JsonResponse<T>;
5
+ export declare const text: (body: string, status?: number) => Response;
6
+ declare const REDIRECT_BRAND: unique symbol;
7
+ export interface RedirectOptions {
8
+ status?: number;
9
+ replace?: boolean;
10
+ }
11
+ export interface Redirect {
12
+ readonly [REDIRECT_BRAND]: true;
13
+ readonly url: string;
14
+ readonly status: number;
15
+ readonly replace: boolean;
16
+ }
17
+ export declare function redirect(url: string, statusOrOptions?: number | RedirectOptions): Redirect;
18
+ export declare function isRedirect(value: unknown): value is Redirect;
19
+ export {};
@@ -0,0 +1,6 @@
1
+ interface ApiOptions {
2
+ apiPath: string;
3
+ appDir: string;
4
+ }
5
+ export declare function generateApi({ apiPath, appDir }: ApiOptions): string;
6
+ export {};
@@ -0,0 +1,6 @@
1
+ interface ClientRoutesOptions {
2
+ pagesDir: string;
3
+ matcherPath: string;
4
+ }
5
+ export declare function generateClientRoutes({ pagesDir, matcherPath }: ClientRoutesOptions): string;
6
+ export {};
@@ -0,0 +1 @@
1
+ export declare function generateContext(): string;
@@ -0,0 +1,5 @@
1
+ interface EntryClientOptions {
2
+ cssUrls: string[];
3
+ }
4
+ export declare function generateEntryClient({ cssUrls }: EntryClientOptions): string;
5
+ export {};
@@ -1,5 +1,5 @@
1
- function r({cssUrls:t}){return`
2
- ${t.map(a=>`import '${a}'`).join(`
1
+ function o({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"
@@ -37,6 +37,14 @@ if (!window.__DEVIX__) {
37
37
  initialViewport: viewport,
38
38
  })
39
39
  )
40
+
41
+ if (window.location.hash) {
42
+ const id = window.location.hash.slice(1)
43
+ const scrollBehavior = getComputedStyle(document.documentElement).scrollBehavior
44
+ requestAnimationFrame(() => {
45
+ document.getElementById(id)?.scrollIntoView({ behavior: scrollBehavior })
46
+ })
47
+ }
40
48
  } else {
41
49
  const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()
42
50
  createRoot(root).render(
@@ -54,5 +62,5 @@ if (!window.__DEVIX__) {
54
62
  )
55
63
  }
56
64
  }
57
- `}export{r as generateEntryClient};
65
+ `}export{o as generateEntryClient};
58
66
  //# 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\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}"],
5
- "mappings": "AAIO,SAASA,EAAoB,CAAC,QAAAC,CAAO,EAA+B,CAGvE,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,CAuDZ",
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\n const matched = matchClientRoute(window.location.pathname)\n\n if (matched) {\n const [pageMod, ...layoutMods] = await Promise.all([\n matched.load(),\n ...matched.loadLayouts.map(l => l()),\n ])\n hydrateRoot(\n root,\n React.createElement(RouterProvider, {\n clientEntry,\n initialData: loaderData,\n initialParams: matched.params,\n initialPage: pageMod.default,\n initialLayouts: layoutMods.map(m => m.default),\n initialLayoutsData: layoutsData,\n initialMeta: metadata,\n initialViewport: viewport,\n })\n )\n\n if (window.location.hash) { \n const id = window.location.hash.slice(1) \n const scrollBehavior = getComputedStyle(document.documentElement).scrollBehavior \n requestAnimationFrame(() => { \n document.getElementById(id)?.scrollIntoView({ behavior: scrollBehavior }) \n }) \n } \n } else {\n const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()\n createRoot(root).render(\n React.createElement(RouterProvider, {\n clientEntry,\n initialData: null,\n initialParams: {},\n initialPage: () => null,\n initialLayouts: [],\n initialLayoutsData: [],\n initialMeta: null,\n initialError: {statusCode: 404, message: 'Not found'},\n initialErrorPage: ErrorPage,\n })\n )\n }\n}\n`\n}"],
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,CA+DZ",
6
6
  "names": ["generateEntryClient", "cssUrls", "u"]
7
7
  }
@@ -0,0 +1,4 @@
1
+ declare const HTTP_METHODS: readonly ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
2
+ export type HttpMethod = (typeof HTTP_METHODS)[number];
3
+ export declare function extractHttpMethods(content: string): HttpMethod[];
4
+ export {};
@@ -0,0 +1,6 @@
1
+ interface RenderOptions {
2
+ pagesDir: string;
3
+ renderPath: string;
4
+ }
5
+ export declare function generateRender({ pagesDir, renderPath }: RenderOptions): string;
6
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { HttpMethod } from './extract-methods';
2
+ export interface RouteEntry {
3
+ filePath: string;
4
+ urlPattern: string;
5
+ identifier: string;
6
+ methods: HttpMethod[];
7
+ }
8
+ export declare function filePathToIdentifier(filePath: string, apiDir: string): string;
9
+ export declare function buildRouteEntry(filePath: string, apiDir: string, methods: HttpMethod[]): RouteEntry;
10
+ export declare function generateRoutesDts(entries: RouteEntry[], apiDir: string): string;
@@ -0,0 +1,2 @@
1
+ import type { RouteEntry } from './routes-dts';
2
+ export declare function scanApiFiles(appDir: string, projectRoot: string): RouteEntry[];
@@ -0,0 +1,6 @@
1
+ interface ServerEntryOptions {
2
+ routesPath: string;
3
+ envPath: string;
4
+ }
5
+ export declare function generateServerEntry({ routesPath, envPath }: ServerEntryOptions): string;
6
+ export {};
@@ -0,0 +1,73 @@
1
+ function t({routesPath:e,envPath:o}){return`
2
+ import { readFileSync } from 'node:fs'
3
+ import { serve } from '@hono/node-server'
4
+ import { serveStatic } from '@hono/node-server/serve-static'
5
+ import { Hono } from 'hono'
6
+ import { resolve, join, dirname } from 'node:path'
7
+ import { fileURLToPath, pathToFileURL } from 'node:url'
8
+ import { registerApiRoutes, registerSsrRoute } from '${e}'
9
+ import { loadDotenv } from '${o}'
10
+
11
+ loadDotenv('production')
12
+
13
+ const __dir = dirname(fileURLToPath(import.meta.url))
14
+
15
+ let renderModule, apiModule, manifest, runtimeConfig
16
+
17
+ try {
18
+ runtimeConfig = JSON.parse(readFileSync(resolve(__dir, '../devix.config.json'), 'utf-8'))
19
+ if (runtimeConfig.output !== 'static') {
20
+ renderModule = await import(pathToFileURL(resolve(__dir, 'render.js')).href)
21
+ apiModule = await import(pathToFileURL(resolve(__dir, 'api.js')).href)
22
+ }
23
+ manifest = JSON.parse(readFileSync(resolve(__dir, '../client/.vite/manifest.json'), 'utf-8'))
24
+ } catch {
25
+ console.error('[devix] Build not found. Run "devix build" first.')
26
+ process.exit(1)
27
+ }
28
+
29
+ const port = Number(process.env.PORT) || runtimeConfig.port || 3000
30
+ const host = typeof runtimeConfig.host === 'string'
31
+ ? runtimeConfig.host
32
+ : runtimeConfig.host ? '0.0.0.0' : (process.env.HOST || '0.0.0.0')
33
+
34
+ const clientRoot = resolve(__dir, '../client')
35
+ const app = new Hono()
36
+
37
+ if (runtimeConfig.output === 'static') {
38
+ app.get('/_data/*', (c) => {
39
+ const pathname = c.req.path.replace(/^\\/_data/, '') || '/'
40
+ const filePath = pathname === '/'
41
+ ? join(clientRoot, '_data/index.json')
42
+ : join(clientRoot, '_data', pathname + '.json')
43
+ try {
44
+ return c.json(JSON.parse(readFileSync(filePath, 'utf-8')))
45
+ } catch {
46
+ return c.json({ error: 'not found' }, 404)
47
+ }
48
+ })
49
+ }
50
+
51
+ app.use('/*', serveStatic({
52
+ root: clientRoot,
53
+ onFound: (_path, c) => {
54
+ c.header('Cache-Control', _path.includes('/assets/')
55
+ ? 'public, immutable, max-age=31536000'
56
+ : 'no-cache')
57
+ }
58
+ }))
59
+
60
+ if (runtimeConfig.output === 'static') {
61
+ console.log('[devix] Static mode \u2014 serving pre-generated files from dist/client')
62
+ } else {
63
+ registerApiRoutes(app, { renderModule, apiModule, manifest })
64
+ registerSsrRoute(app, { renderModule, apiModule, manifest, loaderTimeout: runtimeConfig.loaderTimeout })
65
+ }
66
+
67
+ const server = serve({ fetch: app.fetch, port, hostname: host }, (info) =>
68
+ console.log(\`http://\${info.address}:\${info.port}\`))
69
+
70
+ process.on('SIGTERM', () => server.close())
71
+ process.on('SIGINT', () => server.close())
72
+ `}export{t as generateServerEntry};
73
+ //# sourceMappingURL=server-entry.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/vite/codegen/server-entry.ts"],
4
+ "sourcesContent": ["interface ServerEntryOptions {\n routesPath: string\n envPath: string\n}\n\nexport function generateServerEntry({ routesPath, envPath }: ServerEntryOptions): string {\n return `\nimport { readFileSync } from 'node:fs'\n import { serve } from '@hono/node-server' \n import { serveStatic } from '@hono/node-server/serve-static'\n import { Hono } from 'hono' \n import { resolve, join, dirname } from 'node:path' \n import { fileURLToPath, pathToFileURL } from 'node:url'\n import { registerApiRoutes, registerSsrRoute } from '${routesPath}' \n import { loadDotenv } from '${envPath}'\n \n loadDotenv('production')\n \n const __dir = dirname(fileURLToPath(import.meta.url))\n\n let renderModule, apiModule, manifest, runtimeConfig \n \n try { \n runtimeConfig = JSON.parse(readFileSync(resolve(__dir, '../devix.config.json'), 'utf-8'))\n if (runtimeConfig.output !== 'static') { \n renderModule = await import(pathToFileURL(resolve(__dir, 'render.js')).href)\n apiModule = await import(pathToFileURL(resolve(__dir, 'api.js')).href) \n } \n manifest = JSON.parse(readFileSync(resolve(__dir, '../client/.vite/manifest.json'), 'utf-8')) \n } catch { \n console.error('[devix] Build not found. Run \"devix build\" first.')\n process.exit(1) \n } \n \n const port = Number(process.env.PORT) || runtimeConfig.port || 3000 \n const host = typeof runtimeConfig.host === 'string'\n ? runtimeConfig.host \n : runtimeConfig.host ? '0.0.0.0' : (process.env.HOST || '0.0.0.0') \n \n const clientRoot = resolve(__dir, '../client') \n const app = new Hono()\n \n if (runtimeConfig.output === 'static') {\n app.get('/_data/*', (c) => {\n const pathname = c.req.path.replace(/^\\\\/_data/, '') || '/' \n const filePath = pathname === '/' \n ? join(clientRoot, '_data/index.json') \n : join(clientRoot, '_data', pathname + '.json') \n try { \n return c.json(JSON.parse(readFileSync(filePath, 'utf-8')))\n } catch { \n return c.json({ error: 'not found' }, 404)\n } \n }) \n }\n\n app.use('/*', serveStatic({ \n root: clientRoot,\n onFound: (_path, c) => { \n c.header('Cache-Control', _path.includes('/assets/') \n ? 'public, immutable, max-age=31536000'\n : 'no-cache') \n } \n })) \n \n if (runtimeConfig.output === 'static') {\n console.log('[devix] Static mode \u2014 serving pre-generated files from dist/client')\n } else { \n registerApiRoutes(app, { renderModule, apiModule, manifest })\n registerSsrRoute(app, { renderModule, apiModule, manifest, loaderTimeout: runtimeConfig.loaderTimeout })\n } \n \n const server = serve({ fetch: app.fetch, port, hostname: host }, (info) => \n console.log(\\`http://\\${info.address}:\\${info.port}\\`))\n\nprocess.on('SIGTERM', () => server.close())\nprocess.on('SIGINT', () => server.close())\n`\n}"],
5
+ "mappings": "AAKO,SAASA,EAAoB,CAAE,WAAAC,EAAY,QAAAC,CAAQ,EAA+B,CACrF,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yDAO8CD,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,CAgEvC",
6
+ "names": ["generateServerEntry", "routesPath", "envPath"]
7
+ }
@@ -0,0 +1 @@
1
+ export declare function writeRoutesDts(content: string, projectRoot: string): boolean;
@@ -0,0 +1,3 @@
1
+ import { UserConfig } from 'vite';
2
+ import type { DevixConfig } from '../config';
3
+ export declare function devix(config: DevixConfig): UserConfig;
@@ -1,4 +1,4 @@
1
- import{mergeConfig as ot}from"vite";import it from"@vitejs/plugin-react";import{fileURLToPath as at}from"node:url";import{dirname as st,resolve as u}from"node:path";function b({cssUrls:t}){return`
1
+ import{mergeConfig as ct}from"vite";import lt from"@vitejs/plugin-react";import{fileURLToPath as ut}from"node:url";import{dirname as pt,resolve as l}from"node:path";function M({cssUrls:t}){return`
2
2
  ${t.map(n=>`import '${n}'`).join(`
3
3
  `)}
4
4
  import "@vitejs/plugin-react/preamble"
@@ -37,6 +37,14 @@ if (!window.__DEVIX__) {
37
37
  initialViewport: viewport,
38
38
  })
39
39
  )
40
+
41
+ if (window.location.hash) {
42
+ const id = window.location.hash.slice(1)
43
+ const scrollBehavior = getComputedStyle(document.documentElement).scrollBehavior
44
+ requestAnimationFrame(() => {
45
+ document.getElementById(id)?.scrollIntoView({ behavior: scrollBehavior })
46
+ })
47
+ }
40
48
  } else {
41
49
  const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()
42
50
  createRoot(root).render(
@@ -105,7 +113,7 @@ export function runLoader(url, request, options) {
105
113
  export function getStaticRoutes() {
106
114
  return _getStaticRoutes(_glob)
107
115
  }
108
- `}function M({apiPath:t,appDir:e}){return`
116
+ `}function O({apiPath:t,appDir:e}){return`
109
117
  import { handleApiRequest as _handleApiRequest } from '${t}'
110
118
 
111
119
  const _routes = import.meta.glob(['/${e}/api/**/*.ts', '!**/middleware.ts'])
@@ -120,9 +128,9 @@ const _glob = {
120
128
  export function handleApiRequest(url, request) {
121
129
  return _handleApiRequest(url, request, _glob)
122
130
  }
123
- `}function y(t){return t.replace(/\.(tsx|ts|jsx|js)$/,"").replace(/\(.*?\)\//g,"").replace(/^index$|\/index$/,"").replace(/\[([^\]]+)]/g,":$1")||"/"}var J=null;function R(){J=null}function O(t,e){let n=t.slice(e.length+1).replace(/\\/g,"/"),i=y(n);return i==="/"?"/api":`/api/${i}`.replace("/api//","/api/")}var X=null;function E(){X=null}function U(){return`
131
+ `}function R(t){return t.replace(/\.(tsx|ts|jsx|js)$/,"").replace(/\(.*?\)\//g,"").replace(/^index$|\/index$/,"").replace(/\[([^\]]+)]/g,":$1")||"/"}var Y=null;function v(){Y=null}function U(t,e){let n=t.slice(e.length+1).replace(/\\/g,"/"),i=R(n);return i==="/"?"/api":`/api/${i}`.replace("/api//","/api/")}var z=null;function _(){z=null}function F(){return`
124
132
  export {RouterContext} from '@devlusoft/devix/runtime/context'
125
- `}import{readFileSync as Y,readdirSync as Z,statSync as K}from"node:fs";import{join as _,relative as Q}from"node:path";var B=/export\s+(?:const|async\s+function|function)\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g;function z(t){return t.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}function H(t){let e=new Set;for(let n of z(t).matchAll(B))e.add(n[1]);return[...e]}function G(t,e){return"_api_"+t.slice(`${e}/`.length).replace(/\.(ts|tsx)$/,"").replace(/[^a-zA-Z0-9]/g,"_")}function k(t,e,n){return{filePath:t,urlPattern:O(t,e),identifier:G(t,e),methods:n}}function P(t,e){if(t.length===0)return`// auto-generado por devix \u2014 no editar
133
+ `}import{readFileSync as tt,readdirSync as et,statSync as rt}from"node:fs";import{join as P,relative as nt}from"node:path";var Z=/export\s+(?:const|async\s+function|function)\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g;function K(t){return t.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}function j(t){let e=new Set;for(let n of K(t).matchAll(Z))e.add(n[1]);return[...e]}function Q(t,e){return"_api_"+t.slice(`${e}/`.length).replace(/\.(ts|tsx)$/,"").replace(/[^a-zA-Z0-9]/g,"_")}function H(t,e,n){return{filePath:t,urlPattern:U(t,e),identifier:Q(t,e),methods:n}}function E(t,e){if(t.length===0)return`// auto-generado por devix \u2014 no editar
126
134
  declare module '@devlusoft/devix' {
127
135
  interface ApiRoutes {}
128
136
  }
@@ -149,5 +157,76 @@ declare module '@devlusoft/devix' {
149
157
  ${i}
150
158
  }
151
159
  }
152
- `}function F(t,e){let n=[];for(let i of Z(t)){let o=_(t,i);K(o).isDirectory()?n.push(...F(o,e)):/\.(ts|tsx)$/.test(i)&&n.push(Q(e,o).replace(/\\/g,"/"))}return n}function T(t,e){let n=_(e,t,"api"),i;try{i=F(n,e)}catch{return[]}return i.filter(o=>!o.endsWith("middleware.ts")&&!o.endsWith("middleware.tsx")).flatMap(o=>{try{let p=Y(_(e,o),"utf-8"),m=H(p);return m.length===0?[]:[k(o,`${t}/api`,m)]}catch{return[]}})}import{mkdirSync as tt,readFileSync as et,writeFileSync as rt,existsSync as nt}from"node:fs";import{join as j}from"node:path";function v(t,e){let n=j(e,".devix"),i=j(n,"routes.d.ts");return tt(n,{recursive:!0}),nt(i)&&et(i,"utf-8")===t?!1:(rt(i,t,"utf-8"),!0)}import{parseSync as ct}from"oxc-parser";var $=st(at(import.meta.url)),w="virtual:devix/entry-client",A="virtual:devix/client-routes",D="virtual:devix/render",C="virtual:devix/api",S="virtual:devix/context",q=new Set(["loader","guard","generateStaticParams","headers"]);function Bt(t){let e=t.appDir??"app",n=`${e}/pages`,i=(t.css??[]).map(r=>r.startsWith("/")?r:`/${r.replace(/^\.\//,"")}`),o=u($,"../server/render.js").replace(/\\/g,"/"),p=u($,"../server/api.js").replace(/\\/g,"/"),m=u($,"../runtime/client-router.js").replace(/\\/g,"/"),V={name:"devix",enforce:"pre",resolveId(r){if(r===w)return`\0${w}`;if(r===A)return`\0${A}`;if(r===D)return`\0${D}`;if(r===C)return`\0${C}`;if(r===S)return`\0${S}`},load(r){if(r===`\0${w}`)return b({cssUrls:i});if(r===`\0${A}`)return I({pagesDir:n,matcherPath:m});if(r===`\0${D}`)return L({pagesDir:n,renderPath:o});if(r===`\0${C}`)return M({apiPath:p,appDir:e});if(r===`\0${S}`)return U()},transform(r,c,d){if(d?.ssr)return;let a=u(process.cwd(),n);if(!c.startsWith(a))return;let N=ct(c,r,{sourceType:"module"}),g=[];for(let s of N.program.body){if(s.type!=="ExportNamedDeclaration"||!s.declaration)continue;let l=s.declaration;if(l.type==="FunctionDeclaration"&&l.id&&q.has(l.id.name)&&g.push({start:s.start,end:s.end,name:l.id.name}),l.type==="VariableDeclaration"){let h=new Set;for(let x of l.declarations)x.id.type==="Identifier"&&q.has(x.id.name)&&(h.has(s.start)||(h.add(s.start),g.push({start:s.start,end:s.end,name:x.id.name})))}}if(g.length===0)return;g.sort((s,l)=>l.start-s.start);let f=r;for(let{start:s,end:l,name:h}of g)f=f.slice(0,s)+`export const ${h} = undefined`+f.slice(l);return{code:f,map:null}},buildStart(){let r=process.cwd(),c=T(e,r);v(P(c,`${e}/api`),r)},configureServer(r){let c=process.cwd(),d=()=>{let a=T(e,c);v(P(a,`${e}/api`),c)};r.watcher.add(u(c,"devix.config.ts")),r.watcher.on("change",a=>{a===u(c,"devix.config.ts")&&(console.log("[devix] Config changed, restarting..."),process.exit(75))}),r.watcher.on("add",a=>{a.startsWith(u(c,n))&&R(),a.includes(`${e}/api`)&&(E(),d())}),r.watcher.on("unlink",a=>{a.startsWith(u(c,n))&&R(),a.includes(`${e}/api`)&&(E(),d())}),r.watcher.on("change",a=>{a.includes(`${e}/api`)&&!a.endsWith("middleware.ts")&&d()})}},W={plugins:[it(),V],publicDir:u(process.cwd(),t.publicDir??"public"),ssr:{noExternal:["@devlusoft/devix"]},...t.envPrefix?{envPrefix:t.envPrefix}:{}};return ot(W,t.vite??{})}export{Bt as devix};
160
+ `}function k(t,e){let n=[];for(let i of et(t)){let o=P(t,i);rt(o).isDirectory()?n.push(...k(o,e)):/\.(ts|tsx)$/.test(i)&&n.push(nt(e,o).replace(/\\/g,"/"))}return n}function T(t,e){let n=P(e,t,"api"),i;try{i=k(n,e)}catch{return[]}return i.filter(o=>!o.endsWith("middleware.ts")&&!o.endsWith("middleware.tsx")).flatMap(o=>{try{let p=tt(P(e,o),"utf-8"),g=j(p);return g.length===0?[]:[H(o,`${t}/api`,g)]}catch{return[]}})}import{mkdirSync as ot,readFileSync as it,writeFileSync as at,existsSync as st}from"node:fs";import{join as N}from"node:path";function w(t,e){let n=N(e,".devix"),i=N(n,"routes.d.ts");return ot(n,{recursive:!0}),st(i)&&it(i,"utf-8")===t?!1:(at(i,t,"utf-8"),!0)}import{parseSync as dt}from"oxc-parser";function V({routesPath:t,envPath:e}){return`
161
+ import { readFileSync } from 'node:fs'
162
+ import { serve } from '@hono/node-server'
163
+ import { serveStatic } from '@hono/node-server/serve-static'
164
+ import { Hono } from 'hono'
165
+ import { resolve, join, dirname } from 'node:path'
166
+ import { fileURLToPath, pathToFileURL } from 'node:url'
167
+ import { registerApiRoutes, registerSsrRoute } from '${t}'
168
+ import { loadDotenv } from '${e}'
169
+
170
+ loadDotenv('production')
171
+
172
+ const __dir = dirname(fileURLToPath(import.meta.url))
173
+
174
+ let renderModule, apiModule, manifest, runtimeConfig
175
+
176
+ try {
177
+ runtimeConfig = JSON.parse(readFileSync(resolve(__dir, '../devix.config.json'), 'utf-8'))
178
+ if (runtimeConfig.output !== 'static') {
179
+ renderModule = await import(pathToFileURL(resolve(__dir, 'render.js')).href)
180
+ apiModule = await import(pathToFileURL(resolve(__dir, 'api.js')).href)
181
+ }
182
+ manifest = JSON.parse(readFileSync(resolve(__dir, '../client/.vite/manifest.json'), 'utf-8'))
183
+ } catch {
184
+ console.error('[devix] Build not found. Run "devix build" first.')
185
+ process.exit(1)
186
+ }
187
+
188
+ const port = Number(process.env.PORT) || runtimeConfig.port || 3000
189
+ const host = typeof runtimeConfig.host === 'string'
190
+ ? runtimeConfig.host
191
+ : runtimeConfig.host ? '0.0.0.0' : (process.env.HOST || '0.0.0.0')
192
+
193
+ const clientRoot = resolve(__dir, '../client')
194
+ const app = new Hono()
195
+
196
+ if (runtimeConfig.output === 'static') {
197
+ app.get('/_data/*', (c) => {
198
+ const pathname = c.req.path.replace(/^\\/_data/, '') || '/'
199
+ const filePath = pathname === '/'
200
+ ? join(clientRoot, '_data/index.json')
201
+ : join(clientRoot, '_data', pathname + '.json')
202
+ try {
203
+ return c.json(JSON.parse(readFileSync(filePath, 'utf-8')))
204
+ } catch {
205
+ return c.json({ error: 'not found' }, 404)
206
+ }
207
+ })
208
+ }
209
+
210
+ app.use('/*', serveStatic({
211
+ root: clientRoot,
212
+ onFound: (_path, c) => {
213
+ c.header('Cache-Control', _path.includes('/assets/')
214
+ ? 'public, immutable, max-age=31536000'
215
+ : 'no-cache')
216
+ }
217
+ }))
218
+
219
+ if (runtimeConfig.output === 'static') {
220
+ console.log('[devix] Static mode \u2014 serving pre-generated files from dist/client')
221
+ } else {
222
+ registerApiRoutes(app, { renderModule, apiModule, manifest })
223
+ registerSsrRoute(app, { renderModule, apiModule, manifest, loaderTimeout: runtimeConfig.loaderTimeout })
224
+ }
225
+
226
+ const server = serve({ fetch: app.fetch, port, hostname: host }, (info) =>
227
+ console.log(\`http://\${info.address}:\${info.port}\`))
228
+
229
+ process.on('SIGTERM', () => server.close())
230
+ process.on('SIGINT', () => server.close())
231
+ `}var f=pt(ut(import.meta.url)),$="virtual:devix/entry-client",S="virtual:devix/client-routes",A="virtual:devix/render",C="virtual:devix/api",D="virtual:devix/context",b="virtual:devix/server-entry",q=new Set(["loader","guard","generateStaticParams","headers"]);function Qt(t){let e=t.appDir??"app",n=`${e}/pages`,i=(t.css??[]).map(r=>r.startsWith("/")?r:`/${r.replace(/^\.\//,"")}`),o=l(f,"../server/render.js").replace(/\\/g,"/"),p=l(f,"../server/api.js").replace(/\\/g,"/"),g=l(f,"../runtime/client-router.js").replace(/\\/g,"/"),W=l(f,"../server/routes.js").replace(/\\/g,"/"),B=l(f,"../utils/env.js").replace(/\\/g,"/"),J={name:"devix",enforce:"pre",resolveId(r){if(r===$)return`\0${$}`;if(r===S)return`\0${S}`;if(r===A)return`\0${A}`;if(r===C)return`\0${C}`;if(r===D)return`\0${D}`;if(r===b)return`\0${b}`},load(r){if(r===`\0${$}`)return M({cssUrls:i});if(r===`\0${S}`)return I({pagesDir:n,matcherPath:g});if(r===`\0${A}`)return L({pagesDir:n,renderPath:o});if(r===`\0${C}`)return O({apiPath:p,appDir:e});if(r===`\0${D}`)return F();if(r===`\0${b}`)return V({routesPath:W,envPath:B})},transform(r,c,d){if(d?.ssr)return;let a=l(process.cwd(),n);if(!c.startsWith(a))return;let G=dt(c,r,{sourceType:"module"}),m=[];for(let s of G.program.body){if(s.type!=="ExportNamedDeclaration"||!s.declaration)continue;let u=s.declaration;if(u.type==="FunctionDeclaration"&&u.id&&q.has(u.id.name)&&m.push({start:s.start,end:s.end,name:u.id.name}),u.type==="VariableDeclaration"){let x=new Set;for(let y of u.declarations)y.id.type==="Identifier"&&q.has(y.id.name)&&(x.has(s.start)||(x.add(s.start),m.push({start:s.start,end:s.end,name:y.id.name})))}}if(m.length===0)return;m.sort((s,u)=>u.start-s.start);let h=r;for(let{start:s,end:u,name:x}of m)h=h.slice(0,s)+`export const ${x} = undefined`+h.slice(u);return{code:h,map:null}},buildStart(){let r=process.cwd(),c=T(e,r);w(E(c,`${e}/api`),r)},configureServer(r){let c=process.cwd(),d=()=>{let a=T(e,c);w(E(a,`${e}/api`),c)};r.watcher.add(l(c,"devix.config.ts")),r.watcher.on("change",a=>{a===l(c,"devix.config.ts")&&(console.log("[devix] Config changed, restarting..."),process.exit(75))}),r.watcher.on("add",a=>{a.startsWith(l(c,n))&&v(),a.includes(`${e}/api`)&&(_(),d())}),r.watcher.on("unlink",a=>{a.startsWith(l(c,n))&&v(),a.includes(`${e}/api`)&&(_(),d())}),r.watcher.on("change",a=>{a.includes(`${e}/api`)&&!a.endsWith("middleware.ts")&&d()})}},X={plugins:[lt(),J],publicDir:l(process.cwd(),t.publicDir??"public"),ssr:{noExternal:["@devlusoft/devix"]},...t.envPrefix?{envPrefix:t.envPrefix}:{}};return ct(X,t.vite??{})}export{Qt as devix};
153
232
  //# sourceMappingURL=index.js.map