vitek-plugin 0.1.2-beta.5 → 0.2.0-beta

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 (177) hide show
  1. package/README.md +35 -4
  2. package/dist/adapters/vite/dev-server-middleware.d.ts +8 -0
  3. package/dist/adapters/vite/dev-server-middleware.d.ts.map +1 -0
  4. package/dist/adapters/vite/dev-server-middleware.js +30 -0
  5. package/dist/adapters/vite/dev-server-state.d.ts +41 -0
  6. package/dist/adapters/vite/dev-server-state.d.ts.map +1 -0
  7. package/dist/adapters/vite/dev-server-state.js +191 -0
  8. package/dist/adapters/vite/dev-server.d.ts +2 -21
  9. package/dist/adapters/vite/dev-server.d.ts.map +1 -1
  10. package/dist/adapters/vite/dev-server.js +7 -379
  11. package/dist/adapters/vite/path-utils.d.ts +20 -0
  12. package/dist/adapters/vite/path-utils.d.ts.map +1 -0
  13. package/dist/adapters/vite/path-utils.js +46 -0
  14. package/dist/adapters/vite/path-utils.test.d.ts +2 -0
  15. package/dist/adapters/vite/path-utils.test.d.ts.map +1 -0
  16. package/dist/adapters/vite/path-utils.test.js +79 -0
  17. package/dist/build/build-api-bundle.d.ts +1 -0
  18. package/dist/build/build-api-bundle.d.ts.map +1 -1
  19. package/dist/build/build-api-bundle.js +38 -3
  20. package/dist/build/build-api-bundle.test.d.ts +2 -0
  21. package/dist/build/build-api-bundle.test.d.ts.map +1 -0
  22. package/dist/build/build-api-bundle.test.js +50 -0
  23. package/dist/build/build-sockets-bundle.test.d.ts +2 -0
  24. package/dist/build/build-sockets-bundle.test.d.ts.map +1 -0
  25. package/dist/build/build-sockets-bundle.test.js +49 -0
  26. package/dist/cli/cli.d.ts +8 -0
  27. package/dist/cli/cli.d.ts.map +1 -0
  28. package/dist/cli/cli.js +25 -0
  29. package/dist/cli/fixtures/serve-config/vitek.config.d.mts +6 -0
  30. package/dist/cli/fixtures/serve-config/vitek.config.d.mts.map +1 -0
  31. package/dist/cli/fixtures/serve-config/vitek.config.mjs +19 -0
  32. package/dist/cli/init.d.ts +15 -0
  33. package/dist/cli/init.d.ts.map +1 -0
  34. package/dist/cli/init.js +99 -0
  35. package/dist/cli/init.test.d.ts +2 -0
  36. package/dist/cli/init.test.d.ts.map +1 -0
  37. package/dist/cli/init.test.js +117 -0
  38. package/dist/cli/mcp-project-config.d.ts +8 -0
  39. package/dist/cli/mcp-project-config.d.ts.map +1 -0
  40. package/dist/cli/mcp-project-config.js +26 -0
  41. package/dist/cli/mcp-project.d.ts +2 -0
  42. package/dist/cli/mcp-project.d.ts.map +1 -0
  43. package/dist/cli/mcp-project.js +101 -0
  44. package/dist/cli/serve.d.ts +27 -1
  45. package/dist/cli/serve.d.ts.map +1 -1
  46. package/dist/cli/serve.js +85 -10
  47. package/dist/cli/serve.test.d.ts +2 -0
  48. package/dist/cli/serve.test.d.ts.map +1 -0
  49. package/dist/cli/serve.test.js +108 -0
  50. package/dist/core/asyncapi/generate.d.ts +5 -3
  51. package/dist/core/asyncapi/generate.d.ts.map +1 -1
  52. package/dist/core/asyncapi/generate.test.d.ts +2 -0
  53. package/dist/core/asyncapi/generate.test.d.ts.map +1 -0
  54. package/dist/core/asyncapi/generate.test.js +120 -0
  55. package/dist/core/context/create-context.d.ts +2 -0
  56. package/dist/core/context/create-context.d.ts.map +1 -1
  57. package/dist/core/file-system/extract-type-from-file.d.ts +4 -0
  58. package/dist/core/file-system/extract-type-from-file.d.ts.map +1 -0
  59. package/dist/core/file-system/extract-type-from-file.js +77 -0
  60. package/dist/core/file-system/extract-type-from-file.test.d.ts +2 -0
  61. package/dist/core/file-system/extract-type-from-file.test.d.ts.map +1 -0
  62. package/dist/core/file-system/extract-type-from-file.test.js +75 -0
  63. package/dist/core/file-system/watch-api-dir.d.ts +4 -1
  64. package/dist/core/file-system/watch-api-dir.d.ts.map +1 -1
  65. package/dist/core/file-system/watch-api-dir.js +31 -6
  66. package/dist/core/file-system/watch-api-dir.test.d.ts +2 -0
  67. package/dist/core/file-system/watch-api-dir.test.d.ts.map +1 -0
  68. package/dist/core/file-system/watch-api-dir.test.js +38 -0
  69. package/dist/core/generation/run-file-generation.d.ts +24 -0
  70. package/dist/core/generation/run-file-generation.d.ts.map +1 -0
  71. package/dist/core/generation/run-file-generation.js +90 -0
  72. package/dist/core/generation/run-file-generation.test.d.ts +2 -0
  73. package/dist/core/generation/run-file-generation.test.d.ts.map +1 -0
  74. package/dist/core/generation/run-file-generation.test.js +151 -0
  75. package/dist/core/introspection/manifest.d.ts +24 -0
  76. package/dist/core/introspection/manifest.d.ts.map +1 -0
  77. package/dist/core/introspection/manifest.js +41 -0
  78. package/dist/core/introspection/manifest.test.d.ts +2 -0
  79. package/dist/core/introspection/manifest.test.d.ts.map +1 -0
  80. package/dist/core/introspection/manifest.test.js +62 -0
  81. package/dist/core/middleware/get-applicable-middlewares.d.ts +7 -0
  82. package/dist/core/middleware/get-applicable-middlewares.d.ts.map +1 -1
  83. package/dist/core/middleware/get-applicable-middlewares.js +23 -15
  84. package/dist/core/middleware/get-applicable-middlewares.test.js +36 -1
  85. package/dist/core/openapi/generate.d.ts +5 -74
  86. package/dist/core/openapi/generate.d.ts.map +1 -1
  87. package/dist/core/openapi/generate.js +4 -419
  88. package/dist/core/openapi/generate.test.d.ts +2 -0
  89. package/dist/core/openapi/generate.test.d.ts.map +1 -0
  90. package/dist/core/openapi/generate.test.js +184 -0
  91. package/dist/core/openapi/jsdoc.d.ts +3 -0
  92. package/dist/core/openapi/jsdoc.d.ts.map +1 -0
  93. package/dist/core/openapi/jsdoc.js +68 -0
  94. package/dist/core/openapi/jsdoc.test.d.ts +2 -0
  95. package/dist/core/openapi/jsdoc.test.d.ts.map +1 -0
  96. package/dist/core/openapi/jsdoc.test.js +111 -0
  97. package/dist/core/openapi/spec-builder.d.ts +4 -0
  98. package/dist/core/openapi/spec-builder.d.ts.map +1 -0
  99. package/dist/core/openapi/spec-builder.js +257 -0
  100. package/dist/core/openapi/spec-builder.test.d.ts +2 -0
  101. package/dist/core/openapi/spec-builder.test.d.ts.map +1 -0
  102. package/dist/core/openapi/spec-builder.test.js +93 -0
  103. package/dist/core/openapi/types.d.ts +42 -0
  104. package/dist/core/openapi/types.d.ts.map +1 -0
  105. package/dist/core/openapi/types.js +5 -0
  106. package/dist/core/server/cors.d.ts +29 -0
  107. package/dist/core/server/cors.d.ts.map +1 -0
  108. package/dist/core/server/cors.js +55 -0
  109. package/dist/core/server/cors.test.d.ts +2 -0
  110. package/dist/core/server/cors.test.d.ts.map +1 -0
  111. package/dist/core/server/cors.test.js +49 -0
  112. package/dist/core/server/proxy.d.ts +16 -0
  113. package/dist/core/server/proxy.d.ts.map +1 -0
  114. package/dist/core/server/proxy.js +20 -0
  115. package/dist/core/server/proxy.test.d.ts +2 -0
  116. package/dist/core/server/proxy.test.d.ts.map +1 -0
  117. package/dist/core/server/proxy.test.js +53 -0
  118. package/dist/core/server/request-handler.d.ts +17 -3
  119. package/dist/core/server/request-handler.d.ts.map +1 -1
  120. package/dist/core/server/request-handler.js +192 -84
  121. package/dist/core/server/request-handler.test.js +287 -22
  122. package/dist/core/socket/socket-handler.test.d.ts +2 -0
  123. package/dist/core/socket/socket-handler.test.d.ts.map +1 -0
  124. package/dist/core/socket/socket-handler.test.js +107 -0
  125. package/dist/core/types/schema.test.d.ts +2 -0
  126. package/dist/core/types/schema.test.d.ts.map +1 -0
  127. package/dist/core/types/schema.test.js +41 -0
  128. package/dist/core/validation/types.d.ts +2 -1
  129. package/dist/core/validation/types.d.ts.map +1 -1
  130. package/dist/core/validation/validator.d.ts +4 -16
  131. package/dist/core/validation/validator.d.ts.map +1 -1
  132. package/dist/core/validation/validator.js +4 -16
  133. package/dist/index.d.ts +6 -1
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +2 -1
  136. package/dist/plugin/context.d.ts +15 -0
  137. package/dist/plugin/context.d.ts.map +1 -0
  138. package/dist/plugin/context.js +12 -0
  139. package/dist/plugin/options.d.ts +46 -0
  140. package/dist/plugin/options.d.ts.map +1 -0
  141. package/dist/plugin/options.js +1 -0
  142. package/dist/plugin/plugin-api.d.ts +49 -0
  143. package/dist/plugin/plugin-api.d.ts.map +1 -0
  144. package/dist/plugin/plugin-api.js +5 -0
  145. package/dist/plugin/vitek-build.d.ts +7 -0
  146. package/dist/plugin/vitek-build.d.ts.map +1 -0
  147. package/dist/plugin/vitek-build.js +104 -0
  148. package/dist/plugin/vitek-config.d.ts +4 -0
  149. package/dist/plugin/vitek-config.d.ts.map +1 -0
  150. package/dist/plugin/vitek-config.js +51 -0
  151. package/dist/plugin/vitek-config.test.d.ts +2 -0
  152. package/dist/plugin/vitek-config.test.d.ts.map +1 -0
  153. package/dist/plugin/vitek-config.test.js +62 -0
  154. package/dist/plugin/vitek-dev.d.ts +7 -0
  155. package/dist/plugin/vitek-dev.d.ts.map +1 -0
  156. package/dist/plugin/vitek-dev.js +71 -0
  157. package/dist/plugin/vitek-preview.d.ts +7 -0
  158. package/dist/plugin/vitek-preview.d.ts.map +1 -0
  159. package/dist/plugin/vitek-preview.js +107 -0
  160. package/dist/plugin/vitek-resolve.d.ts +7 -0
  161. package/dist/plugin/vitek-resolve.d.ts.map +1 -0
  162. package/dist/plugin/vitek-resolve.js +25 -0
  163. package/dist/plugin/vitek-transform.d.ts +7 -0
  164. package/dist/plugin/vitek-transform.d.ts.map +1 -0
  165. package/dist/plugin/vitek-transform.js +55 -0
  166. package/dist/plugin/vitek.d.ts +10 -0
  167. package/dist/plugin/vitek.d.ts.map +1 -0
  168. package/dist/plugin/vitek.js +27 -0
  169. package/dist/plugin.d.ts +3 -32
  170. package/dist/plugin.d.ts.map +1 -1
  171. package/dist/plugin.js +2 -246
  172. package/dist/plugin.test.js +114 -28
  173. package/dist/shared/response-helpers.d.ts +21 -0
  174. package/dist/shared/response-helpers.d.ts.map +1 -1
  175. package/dist/shared/response-helpers.js +41 -0
  176. package/dist/shared/response-helpers.test.js +54 -1
  177. package/package.json +19 -4
package/README.md CHANGED
@@ -5,9 +5,9 @@
5
5
 
6
6
  **File-based HTTP API generation for Vite**
7
7
 
8
- [![Version](https://img.shields.io/badge/version-0.1.1--beta-orange.svg)](https://github.com/martinsbicudo/vitek-plugin)
8
+ [![Version](https://img.shields.io/badge/version-0.1.2--beta-orange.svg)](https://github.com/martinsbicudo/vitek-plugin)
9
9
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
10
- [![Vite](https://img.shields.io/badge/vite-^5.0.0-646CFF.svg)](https://vitejs.dev/)
10
+ [![Vite](https://img.shields.io/badge/vite-^5.0.0%20%7C%7C%20^6.0.0-646CFF.svg)](https://vitejs.dev/)
11
11
 
12
12
  > **Beta Version**: This project is currently in beta. APIs may change in future releases.
13
13
  </div>
@@ -20,12 +20,25 @@ Vitek is a Vite plugin that turns a folder of files into an HTTP API.
20
20
 
21
21
  **Full documentation:** [docs/](./docs/) · [View online](https://martinsbicudo.github.io/vitek-plugin/) (VitePress — run `npm run docs:dev` or `pnpm docs:dev` to view locally).
22
22
 
23
- **Examples:** [examples/](./examples/) `basic-js`, `js-react`, `typescript-react`, `docker`, and `api-docs`.
23
+ **MCP:** Expose your project API to AI assistants (Cursor, Claude) with `vitek mcp` [MCP API do projeto](docs/guide/mcp-project.md).
24
+
25
+ **Examples:** [examples/](./examples/) — `basic-js`, `js-react`, `typescript-react`, `import-external`, `socket-only`, `api-docs`, `prisma`, and `docker`.
24
26
 
25
27
  ---
26
28
 
27
29
  ## Quick Start
28
30
 
31
+ **Option A — scaffold with init (recommended for new projects):**
32
+
33
+ ```bash
34
+ npm install vitek-plugin
35
+ npx vitek init
36
+ ```
37
+
38
+ Then `npm run dev` and open `http://localhost:5173/api/health`. The init command creates `src/api/health.get.ts` and adds vitek to your Vite config.
39
+
40
+ **Option B — manual setup:**
41
+
29
42
  ```bash
30
43
  npm install vitek-plugin
31
44
  ```
@@ -86,11 +99,29 @@ Then open `http://localhost:5173/api-docs.html` for interactive API documentatio
86
99
 
87
100
  ---
88
101
 
102
+ ## Security
103
+
104
+ - **Body size**: Use `maxBodySize` (bytes) in plugin options or in `vitek.config.mjs` for production to reject oversized bodies with 413 and avoid unbounded memory use.
105
+ - **CORS**: Configure `cors` (e.g. specific `origin`) in production; avoid `*` with credentials.
106
+ - **Trust proxy**: Set `trustProxy: true` only when behind a reverse proxy; do not trust client-sent `X-Forwarded-*` without it.
107
+ - **Response headers**: Header values set from handler responses are sanitized (CRLF removed) to reduce response-splitting risk.
108
+ - **Validation**: `ValidationRule.pattern` (string) is compiled with `new RegExp`. Avoid complex or user-supplied patterns (ReDoS); prefer allowlists or simple character classes.
109
+ - **Dependencies**: Run `pnpm audit` (or `npm audit`) and keep `connect`, `serve-static`, `ws`, and other dependencies updated.
110
+ - **Logging**: Avoid logging full request body or headers in production.
111
+
112
+ [Security (full) →](./docs/guide/security.md) · [Configuration →](./docs/guide/configuration.md) · [Production →](./docs/guide/production-deploy.md)
113
+
114
+ ---
115
+
89
116
  ## Links
90
117
 
91
118
  - [Documentation](./docs/) — [view online](https://martinsbicudo.github.io/vitek-plugin/) · guides, API reference, configuration, examples
92
119
  - [OpenAPI / Swagger + AsyncAPI](./docs/guide/openapi.md) — Auto-generate API docs (REST + WebSockets)
93
- - [Examples](./examples/) — socket-only, basic-js, js-react, typescript-react, docker, api-docs
120
+ - [Plugin API](./docs/guide/plugin-api.md) — Extend Vitek with `afterTypesGenerated` and `beforeApiRequest` hooks
121
+ - [Alias](./docs/guide/alias.md) — Use `resolve.alias` for stable import paths
122
+ - [Introspection](./docs/guide/introspection.md) — Programmatic API: `getRoutes`, `getSockets`, `vitek-manifest.json`
123
+ - [Bundle size](./docs/guide/bundle-size.md) — Plugin and generated bundles (vitek-api.mjs); tree-shaking, heavy imports
124
+ - [Examples](./examples/) — socket-only, basic-js, js-react, typescript-react, import-external, api-docs, prisma, docker
94
125
  - [GitHub](https://github.com/martinsbicudo/vitek-plugin)
95
126
  - [NPM](https://www.npmjs.com/package/vitek-plugin)
96
127
  - [License](LICENSE)
@@ -0,0 +1,8 @@
1
+ import type { VitekApp } from '../../core/shared/vitek-app.js';
2
+ import type { DevServerState } from './dev-server-state.js';
3
+ import type { ViteDevServerOptions } from './dev-server-state.js';
4
+ export declare function createApiMiddleware(state: DevServerState, options: ViteDevServerOptions, shared: VitekApp): (req: import("http").IncomingMessage, res: import("http").ServerResponse, next: import("vite").Connect.NextFunction) => Promise<void>;
5
+ export declare function createSocketSetup(state: DevServerState, options: ViteDevServerOptions, shared: VitekApp): (httpServer: {
6
+ on(event: "upgrade", listener: (req: import("http").IncomingMessage, socket: import("stream").Duplex, head: Buffer) => void): void;
7
+ }) => void;
8
+ //# sourceMappingURL=dev-server-middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-server-middleware.d.ts","sourceRoot":"","sources":["../../../src/adapters/vite/dev-server-middleware.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,oBAAoB,EAC7B,MAAM,EAAE,QAAQ,yIAajB;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,oBAAoB,EAC7B,MAAM,EAAE,QAAQ,IAER,YAAY;IAAE,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAA;CAAE,UAY3J"}
@@ -0,0 +1,30 @@
1
+ import { createRequestHandler } from '../../core/server/request-handler.js';
2
+ import { createSocketHandler } from '../../core/socket/socket-handler.js';
3
+ import { SOCKET_BASE_PATH } from '../../shared/constants.js';
4
+ export function createApiMiddleware(state, options, shared) {
5
+ return createRequestHandler({
6
+ routes: state.routes,
7
+ middlewares: state.middlewares,
8
+ beforeApiRequest: options.beforeApiRequest,
9
+ cors: options.cors,
10
+ trustProxy: options.trustProxy,
11
+ maxBodySize: options.maxBodySize,
12
+ onError: options.onError,
13
+ logger: options.logger,
14
+ shared,
15
+ });
16
+ }
17
+ export function createSocketSetup(state, options, shared) {
18
+ return (httpServer) => {
19
+ if (options.sockets !== false && state.sockets.length > 0) {
20
+ const socketBasePath = options.socketBasePath ?? SOCKET_BASE_PATH;
21
+ const handler = createSocketHandler({
22
+ sockets: state.sockets,
23
+ socketBasePath,
24
+ shared,
25
+ logger: options.logger,
26
+ });
27
+ httpServer.on('upgrade', handler);
28
+ }
29
+ };
30
+ }
@@ -0,0 +1,41 @@
1
+ import type { ViteDevServer } from 'vite';
2
+ import { type ApiWatcher } from '../../core/file-system/watch-api-dir.js';
3
+ import { type SocketEntry } from '../../core/socket/socket-handler.js';
4
+ import type { OpenApiOptions } from '../../core/openapi/generate.js';
5
+ import type { Route } from '../../core/routing/route-types.js';
6
+ import type { LoadedMiddleware } from '../../core/middleware/get-applicable-middlewares.js';
7
+ import type { BeforeApiRequestHook } from '../../core/server/request-handler.js';
8
+ import type { AfterTypesGeneratedContext } from '../../plugin/plugin-api.js';
9
+ import type { VitekLogger } from './logger.js';
10
+ export interface ViteDevServerOptions {
11
+ root: string;
12
+ apiDir: string;
13
+ logger: VitekLogger;
14
+ viteServer: ViteDevServer;
15
+ enableValidation?: boolean;
16
+ openApi?: OpenApiOptions | boolean;
17
+ sockets?: boolean;
18
+ socketBasePath?: string;
19
+ onGenerationError?: (error: Error) => void;
20
+ beforeApiRequest?: BeforeApiRequestHook[];
21
+ afterTypesGenerated?: ((ctx: AfterTypesGeneratedContext) => void | Promise<void>)[];
22
+ apiBasePath?: string;
23
+ cors?: boolean | import('../../core/server/cors.js').CorsOptions;
24
+ trustProxy?: boolean;
25
+ maxBodySize?: number;
26
+ onError?: (err: Error, req: import('http').IncomingMessage, res: import('http').ServerResponse) => void | Promise<void>;
27
+ }
28
+ export declare class DevServerState {
29
+ private options;
30
+ routes: Route[];
31
+ middlewares: LoadedMiddleware[];
32
+ sockets: SocketEntry[];
33
+ watcher: ApiWatcher | null;
34
+ constructor(options: ViteDevServerOptions);
35
+ initialize(): Promise<void>;
36
+ reload(showReloadLog?: boolean): Promise<void>;
37
+ setupWatcher(): void;
38
+ generateTypes(): Promise<void>;
39
+ cleanup(): void;
40
+ }
41
+ //# sourceMappingURL=dev-server-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-server-state.d.ts","sourceRoot":"","sources":["../../../src/adapters/vite/dev-server-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAG1C,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,yCAAyC,CAAC;AAK7F,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAG5F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,KAAK,EAA4B,MAAM,mCAAmC,CAAC;AACzF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qDAAqD,CAAC;AAC5F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAC7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAqB/C,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,aAAa,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC3C,gBAAgB,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAC1C,mBAAmB,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,0BAA0B,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;IACpF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,2BAA2B,EAAE,WAAW,CAAC;IACjE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,OAAO,MAAM,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzH;AAED,qBAAa,cAAc;IAMb,OAAO,CAAC,OAAO;IAL3B,MAAM,EAAE,KAAK,EAAE,CAAM;IACrB,WAAW,EAAE,gBAAgB,EAAE,CAAM;IACrC,OAAO,EAAE,WAAW,EAAE,CAAM;IAC5B,OAAO,EAAE,UAAU,GAAG,IAAI,CAAQ;gBAEd,OAAO,EAAE,oBAAoB;IAE3C,UAAU;IAKV,MAAM,CAAC,aAAa,UAAO;IAwHjC,YAAY;IAWN,aAAa;IAuCnB,OAAO;CAMR"}
@@ -0,0 +1,191 @@
1
+ import * as path from 'path';
2
+ import { scanApiDirectory } from '../../core/file-system/scan-api-dir.js';
3
+ import { watchApiDirectory } from '../../core/file-system/watch-api-dir.js';
4
+ import { createRoute } from '../../core/routing/route-parser.js';
5
+ import { routesToSchema } from '../../core/types/schema.js';
6
+ import { runFileGeneration } from '../../core/generation/run-file-generation.js';
7
+ import { patternToRegex } from '../../core/normalize/normalize-path.js';
8
+ import { extractBodyTypeFromFile, extractQueryTypeFromFile } from '../../core/file-system/extract-type-from-file.js';
9
+ import { API_BASE_PATH, SOCKET_BASE_PATH } from '../../shared/constants.js';
10
+ function deduplicateRoutesByKey(routes) {
11
+ const seen = new Set();
12
+ return routes.filter((r) => {
13
+ const key = `${r.method}:${r.pattern}`;
14
+ if (seen.has(key))
15
+ return false;
16
+ seen.add(key);
17
+ return true;
18
+ });
19
+ }
20
+ function deduplicateSocketsByPattern(sockets) {
21
+ const seen = new Set();
22
+ return sockets.filter((s) => {
23
+ if (seen.has(s.pattern))
24
+ return false;
25
+ seen.add(s.pattern);
26
+ return true;
27
+ });
28
+ }
29
+ export class DevServerState {
30
+ options;
31
+ routes = [];
32
+ middlewares = [];
33
+ sockets = [];
34
+ watcher = null;
35
+ constructor(options) {
36
+ this.options = options;
37
+ }
38
+ async initialize() {
39
+ await this.reload(false);
40
+ this.setupWatcher();
41
+ }
42
+ async reload(showReloadLog = true) {
43
+ if (showReloadLog) {
44
+ this.options.logger.info('Reloading API routes...');
45
+ }
46
+ const scanResult = scanApiDirectory(this.options.apiDir);
47
+ this.middlewares.length = 0;
48
+ for (const middlewareInfo of scanResult.middlewares) {
49
+ try {
50
+ const relativePath = path.relative(this.options.root, middlewareInfo.path);
51
+ const vitePath = `/${relativePath.replace(/\\/g, '/')}`;
52
+ const middlewareModule = await this.options.viteServer.ssrLoadModule(vitePath);
53
+ const middleware = middlewareModule.default || middlewareModule.middleware;
54
+ let middlewareArray = [];
55
+ if (Array.isArray(middleware)) {
56
+ middlewareArray = middleware;
57
+ }
58
+ else if (typeof middleware === 'function') {
59
+ middlewareArray = [middleware];
60
+ }
61
+ if (middlewareArray.length > 0) {
62
+ let pathPatterns;
63
+ if (middlewareInfo.basePattern === '' && middlewareModule.config?.path) {
64
+ const raw = Array.isArray(middlewareModule.config.path) ? middlewareModule.config.path : [middlewareModule.config.path];
65
+ pathPatterns = raw.map((p) => String(p).replace(/^\/api\/?/, '').replace(/^\/+|\/+$/g, '')).filter(Boolean);
66
+ }
67
+ this.middlewares.push({
68
+ middleware: middlewareArray,
69
+ basePattern: middlewareInfo.basePattern,
70
+ pathPatterns,
71
+ });
72
+ }
73
+ }
74
+ catch (error) {
75
+ this.options.logger.warn(`Failed to load middleware ${middlewareInfo.path}: ${error instanceof Error ? error.message : String(error)}`);
76
+ }
77
+ }
78
+ const totalMiddlewareCount = this.middlewares.reduce((sum, m) => sum + m.middleware.length, 0);
79
+ this.options.logger.middlewareLoaded(totalMiddlewareCount);
80
+ this.routes.length = 0;
81
+ for (const parsedRoute of scanResult.routes) {
82
+ try {
83
+ const relativePath = path.relative(this.options.root, parsedRoute.file);
84
+ const vitePath = `/${relativePath.replace(/\\/g, '/')}`;
85
+ const handlerModule = await this.options.viteServer.ssrLoadModule(vitePath);
86
+ const handler = handlerModule.default || handlerModule.handler || handlerModule[parsedRoute.method];
87
+ if (typeof handler !== 'function') {
88
+ this.options.logger.warn(`Route file ${parsedRoute.file} does not export a handler function`);
89
+ continue;
90
+ }
91
+ const bodyType = extractBodyTypeFromFile(parsedRoute.file);
92
+ const queryType = extractQueryTypeFromFile(parsedRoute.file);
93
+ const route = createRoute(parsedRoute, handler, bodyType, queryType);
94
+ this.routes.push(route);
95
+ }
96
+ catch (error) {
97
+ this.options.logger.error(`Failed to load route ${parsedRoute.file}: ${error instanceof Error ? error.message : String(error)}`);
98
+ }
99
+ }
100
+ this.routes = deduplicateRoutesByKey(this.routes);
101
+ const routesInfo = this.routes.map((r) => ({
102
+ method: r.method,
103
+ pattern: r.pattern,
104
+ }));
105
+ this.options.logger.routesRegistered(routesInfo, API_BASE_PATH);
106
+ this.sockets.length = 0;
107
+ const socketsEnabled = this.options.sockets !== false;
108
+ if (socketsEnabled) {
109
+ for (const parsedSocket of scanResult.sockets) {
110
+ try {
111
+ const relativePath = path.relative(this.options.root, parsedSocket.file);
112
+ const vitePath = `/${relativePath.replace(/\\/g, '/')}`;
113
+ const handlerModule = await this.options.viteServer.ssrLoadModule(vitePath);
114
+ const handler = handlerModule.default ?? handlerModule.handler;
115
+ if (typeof handler !== 'function') {
116
+ this.options.logger.warn(`Socket file ${parsedSocket.file} does not export a handler function`);
117
+ continue;
118
+ }
119
+ const regex = patternToRegex(parsedSocket.pattern);
120
+ this.sockets.push({
121
+ pattern: parsedSocket.pattern,
122
+ params: parsedSocket.params,
123
+ file: parsedSocket.file,
124
+ regex,
125
+ handler,
126
+ });
127
+ }
128
+ catch (error) {
129
+ this.options.logger.error(`Failed to load socket ${parsedSocket.file}: ${error instanceof Error ? error.message : String(error)}`);
130
+ }
131
+ }
132
+ }
133
+ this.sockets = deduplicateSocketsByPattern(this.sockets);
134
+ const socketBasePath = this.options.socketBasePath ?? SOCKET_BASE_PATH;
135
+ this.options.logger.socketsRegistered(this.sockets.map((s) => ({ pattern: s.pattern })), socketBasePath);
136
+ await this.generateTypes();
137
+ }
138
+ setupWatcher() {
139
+ if (this.watcher) {
140
+ this.watcher.close();
141
+ }
142
+ this.watcher = watchApiDirectory(this.options.apiDir, async (event, filePath) => {
143
+ this.options.logger.info(`API file ${event}: ${filePath}`);
144
+ await this.reload();
145
+ });
146
+ }
147
+ async generateTypes() {
148
+ try {
149
+ const schema = routesToSchema(this.routes);
150
+ const socketBasePath = this.options.socketBasePath ?? SOCKET_BASE_PATH;
151
+ const port = this.options.viteServer.config.server?.port || 5173;
152
+ await runFileGeneration({
153
+ root: this.options.root,
154
+ schema,
155
+ sockets: this.sockets,
156
+ apiBasePath: API_BASE_PATH,
157
+ socketBasePath,
158
+ openApi: this.options.openApi,
159
+ serverPort: port,
160
+ logger: {
161
+ typesGenerated: (p) => this.options.logger.typesGenerated(p),
162
+ servicesGenerated: (p) => this.options.logger.servicesGenerated(p),
163
+ info: (m) => this.options.logger.info(m),
164
+ warn: (m) => this.options.logger.warn(m),
165
+ },
166
+ onGenerationError: this.options.onGenerationError,
167
+ });
168
+ const apiBasePath = this.options.apiBasePath ?? API_BASE_PATH;
169
+ for (const hook of this.options.afterTypesGenerated ?? []) {
170
+ await hook({
171
+ root: this.options.root,
172
+ schema,
173
+ sockets: this.sockets.map((s) => ({ pattern: s.pattern, params: s.params, file: s.file })),
174
+ apiBasePath,
175
+ socketBasePath,
176
+ });
177
+ }
178
+ }
179
+ catch (error) {
180
+ const err = error instanceof Error ? error : new Error(String(error));
181
+ this.options.logger.error(`Failed to generate types: ${err.message}`);
182
+ this.options.onGenerationError?.(err);
183
+ }
184
+ }
185
+ cleanup() {
186
+ if (this.watcher) {
187
+ this.watcher.close();
188
+ this.watcher = null;
189
+ }
190
+ }
191
+ }
@@ -1,24 +1,5 @@
1
- /**
2
- * Adapter for integration with Vite development server
3
- * Thin layer that connects core → Vite
4
- */
5
- import type { ViteDevServer } from 'vite';
6
- import type { OpenApiOptions } from '../../core/openapi/generate.js';
7
- import type { VitekLogger } from './logger.js';
8
- export interface ViteDevServerOptions {
9
- root: string;
10
- apiDir: string;
11
- logger: VitekLogger;
12
- viteServer: ViteDevServer;
13
- enableValidation?: boolean;
14
- openApi?: OpenApiOptions | boolean;
15
- sockets?: boolean;
16
- /** Base path for WebSocket endpoints (e.g. /api/ws). Default from constants. */
17
- socketBasePath?: string;
18
- }
19
- /**
20
- * Creates middleware for Vite development server
21
- */
1
+ import { type ViteDevServerOptions } from './dev-server-state.js';
2
+ export type { ViteDevServerOptions } from './dev-server-state.js';
22
3
  export declare function createViteDevServerMiddleware(options: ViteDevServerOptions): {
23
4
  ready: Promise<void>;
24
5
  middleware: (req: import("http").IncomingMessage, res: import("http").ServerResponse, next: import("vite").Connect.NextFunction) => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../../src/adapters/vite/dev-server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAgC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAGrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAqB/C,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,aAAa,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAgXD;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,oBAAoB;;;;;+BA+C5C;QAAE,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAA;KAAE;EAapK"}
1
+ {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../../src/adapters/vite/dev-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAOlF,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,oBAAoB;;;;;;;;EA4C1E"}