vitek-plugin 0.1.2-beta.6 → 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.
- package/README.md +35 -4
- package/dist/adapters/vite/dev-server-middleware.d.ts +8 -0
- package/dist/adapters/vite/dev-server-middleware.d.ts.map +1 -0
- package/dist/adapters/vite/dev-server-middleware.js +30 -0
- package/dist/adapters/vite/dev-server-state.d.ts +41 -0
- package/dist/adapters/vite/dev-server-state.d.ts.map +1 -0
- package/dist/adapters/vite/dev-server-state.js +191 -0
- package/dist/adapters/vite/dev-server.d.ts +2 -21
- package/dist/adapters/vite/dev-server.d.ts.map +1 -1
- package/dist/adapters/vite/dev-server.js +7 -216
- package/dist/adapters/vite/path-utils.d.ts +20 -0
- package/dist/adapters/vite/path-utils.d.ts.map +1 -0
- package/dist/adapters/vite/path-utils.js +46 -0
- package/dist/adapters/vite/path-utils.test.d.ts +2 -0
- package/dist/adapters/vite/path-utils.test.d.ts.map +1 -0
- package/dist/adapters/vite/path-utils.test.js +79 -0
- package/dist/build/build-api-bundle.d.ts +1 -0
- package/dist/build/build-api-bundle.d.ts.map +1 -1
- package/dist/build/build-api-bundle.js +38 -3
- package/dist/build/build-api-bundle.test.d.ts +2 -0
- package/dist/build/build-api-bundle.test.d.ts.map +1 -0
- package/dist/build/build-api-bundle.test.js +50 -0
- package/dist/build/build-sockets-bundle.test.d.ts +2 -0
- package/dist/build/build-sockets-bundle.test.d.ts.map +1 -0
- package/dist/build/build-sockets-bundle.test.js +49 -0
- package/dist/cli/cli.d.ts +8 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/cli/cli.js +25 -0
- package/dist/cli/fixtures/serve-config/vitek.config.d.mts +6 -0
- package/dist/cli/fixtures/serve-config/vitek.config.d.mts.map +1 -0
- package/dist/cli/fixtures/serve-config/vitek.config.mjs +19 -0
- package/dist/cli/init.d.ts +15 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +99 -0
- package/dist/cli/init.test.d.ts +2 -0
- package/dist/cli/init.test.d.ts.map +1 -0
- package/dist/cli/init.test.js +117 -0
- package/dist/cli/mcp-project-config.d.ts +8 -0
- package/dist/cli/mcp-project-config.d.ts.map +1 -0
- package/dist/cli/mcp-project-config.js +26 -0
- package/dist/cli/mcp-project.d.ts +2 -0
- package/dist/cli/mcp-project.d.ts.map +1 -0
- package/dist/cli/mcp-project.js +101 -0
- package/dist/cli/serve.d.ts +27 -1
- package/dist/cli/serve.d.ts.map +1 -1
- package/dist/cli/serve.js +85 -10
- package/dist/cli/serve.test.d.ts +2 -0
- package/dist/cli/serve.test.d.ts.map +1 -0
- package/dist/cli/serve.test.js +108 -0
- package/dist/core/asyncapi/generate.test.d.ts +2 -0
- package/dist/core/asyncapi/generate.test.d.ts.map +1 -0
- package/dist/core/asyncapi/generate.test.js +120 -0
- package/dist/core/context/create-context.d.ts +2 -0
- package/dist/core/context/create-context.d.ts.map +1 -1
- package/dist/core/file-system/watch-api-dir.d.ts +4 -1
- package/dist/core/file-system/watch-api-dir.d.ts.map +1 -1
- package/dist/core/file-system/watch-api-dir.js +31 -6
- package/dist/core/file-system/watch-api-dir.test.d.ts +2 -0
- package/dist/core/file-system/watch-api-dir.test.d.ts.map +1 -0
- package/dist/core/file-system/watch-api-dir.test.js +38 -0
- package/dist/core/generation/run-file-generation.d.ts +2 -0
- package/dist/core/generation/run-file-generation.d.ts.map +1 -1
- package/dist/core/generation/run-file-generation.js +4 -1
- package/dist/core/introspection/manifest.d.ts +24 -0
- package/dist/core/introspection/manifest.d.ts.map +1 -0
- package/dist/core/introspection/manifest.js +41 -0
- package/dist/core/introspection/manifest.test.d.ts +2 -0
- package/dist/core/introspection/manifest.test.d.ts.map +1 -0
- package/dist/core/introspection/manifest.test.js +62 -0
- package/dist/core/middleware/get-applicable-middlewares.d.ts +7 -0
- package/dist/core/middleware/get-applicable-middlewares.d.ts.map +1 -1
- package/dist/core/middleware/get-applicable-middlewares.js +23 -15
- package/dist/core/middleware/get-applicable-middlewares.test.js +36 -1
- package/dist/core/openapi/generate.d.ts +3 -79
- package/dist/core/openapi/generate.d.ts.map +1 -1
- package/dist/core/openapi/generate.js +4 -419
- package/dist/core/openapi/generate.test.d.ts +2 -0
- package/dist/core/openapi/generate.test.d.ts.map +1 -0
- package/dist/core/openapi/generate.test.js +184 -0
- package/dist/core/openapi/jsdoc.d.ts +3 -0
- package/dist/core/openapi/jsdoc.d.ts.map +1 -0
- package/dist/core/openapi/jsdoc.js +68 -0
- package/dist/core/openapi/jsdoc.test.d.ts +2 -0
- package/dist/core/openapi/jsdoc.test.d.ts.map +1 -0
- package/dist/core/openapi/jsdoc.test.js +111 -0
- package/dist/core/openapi/spec-builder.d.ts +4 -0
- package/dist/core/openapi/spec-builder.d.ts.map +1 -0
- package/dist/core/openapi/spec-builder.js +257 -0
- package/dist/core/openapi/spec-builder.test.d.ts +2 -0
- package/dist/core/openapi/spec-builder.test.d.ts.map +1 -0
- package/dist/core/openapi/spec-builder.test.js +93 -0
- package/dist/core/openapi/types.d.ts +42 -0
- package/dist/core/openapi/types.d.ts.map +1 -0
- package/dist/core/openapi/types.js +5 -0
- package/dist/core/server/cors.d.ts +29 -0
- package/dist/core/server/cors.d.ts.map +1 -0
- package/dist/core/server/cors.js +55 -0
- package/dist/core/server/cors.test.d.ts +2 -0
- package/dist/core/server/cors.test.d.ts.map +1 -0
- package/dist/core/server/cors.test.js +49 -0
- package/dist/core/server/proxy.d.ts +16 -0
- package/dist/core/server/proxy.d.ts.map +1 -0
- package/dist/core/server/proxy.js +20 -0
- package/dist/core/server/proxy.test.d.ts +2 -0
- package/dist/core/server/proxy.test.d.ts.map +1 -0
- package/dist/core/server/proxy.test.js +53 -0
- package/dist/core/server/request-handler.d.ts +17 -3
- package/dist/core/server/request-handler.d.ts.map +1 -1
- package/dist/core/server/request-handler.js +192 -84
- package/dist/core/server/request-handler.test.js +287 -22
- package/dist/core/socket/socket-handler.test.d.ts +2 -0
- package/dist/core/socket/socket-handler.test.d.ts.map +1 -0
- package/dist/core/socket/socket-handler.test.js +107 -0
- package/dist/core/types/schema.test.d.ts +2 -0
- package/dist/core/types/schema.test.d.ts.map +1 -0
- package/dist/core/types/schema.test.js +41 -0
- package/dist/core/validation/types.d.ts +2 -1
- package/dist/core/validation/types.d.ts.map +1 -1
- package/dist/core/validation/validator.d.ts +4 -16
- package/dist/core/validation/validator.d.ts.map +1 -1
- package/dist/core/validation/validator.js +4 -16
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/plugin/context.d.ts +15 -0
- package/dist/plugin/context.d.ts.map +1 -0
- package/dist/plugin/context.js +12 -0
- package/dist/plugin/options.d.ts +46 -0
- package/dist/plugin/options.d.ts.map +1 -0
- package/dist/plugin/options.js +1 -0
- package/dist/plugin/plugin-api.d.ts +49 -0
- package/dist/plugin/plugin-api.d.ts.map +1 -0
- package/dist/plugin/plugin-api.js +5 -0
- package/dist/plugin/vitek-build.d.ts +7 -0
- package/dist/plugin/vitek-build.d.ts.map +1 -0
- package/dist/plugin/vitek-build.js +104 -0
- package/dist/plugin/vitek-config.d.ts +4 -0
- package/dist/plugin/vitek-config.d.ts.map +1 -0
- package/dist/plugin/vitek-config.js +51 -0
- package/dist/plugin/vitek-config.test.d.ts +2 -0
- package/dist/plugin/vitek-config.test.d.ts.map +1 -0
- package/dist/plugin/vitek-config.test.js +62 -0
- package/dist/plugin/vitek-dev.d.ts +7 -0
- package/dist/plugin/vitek-dev.d.ts.map +1 -0
- package/dist/plugin/vitek-dev.js +71 -0
- package/dist/plugin/vitek-preview.d.ts +7 -0
- package/dist/plugin/vitek-preview.d.ts.map +1 -0
- package/dist/plugin/vitek-preview.js +107 -0
- package/dist/plugin/vitek-resolve.d.ts +7 -0
- package/dist/plugin/vitek-resolve.d.ts.map +1 -0
- package/dist/plugin/vitek-resolve.js +25 -0
- package/dist/plugin/vitek-transform.d.ts +7 -0
- package/dist/plugin/vitek-transform.d.ts.map +1 -0
- package/dist/plugin/vitek-transform.js +55 -0
- package/dist/plugin/vitek.d.ts +10 -0
- package/dist/plugin/vitek.d.ts.map +1 -0
- package/dist/plugin/vitek.js +27 -0
- package/dist/plugin.d.ts +3 -32
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +2 -274
- package/dist/plugin.test.js +99 -29
- package/dist/shared/response-helpers.d.ts +21 -0
- package/dist/shared/response-helpers.d.ts.map +1 -1
- package/dist/shared/response-helpers.js +41 -0
- package/dist/shared/response-helpers.test.js +54 -1
- package/package.json +19 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-project-config.d.ts","sourceRoot":"","sources":["../../src/cli/mcp-project-config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AASD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAgB1D"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
const DEFAULT_CONFIG = {
|
|
4
|
+
apiDir: 'src/api',
|
|
5
|
+
apiBasePath: '/api',
|
|
6
|
+
socketBasePath: '/api/ws',
|
|
7
|
+
baseUrl: 'http://localhost:5173',
|
|
8
|
+
};
|
|
9
|
+
export function loadMcpConfig(root) {
|
|
10
|
+
const configPath = path.join(root, 'vitek.mcp.json');
|
|
11
|
+
if (!fs.existsSync(configPath)) {
|
|
12
|
+
return { ...DEFAULT_CONFIG };
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const raw = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
16
|
+
return {
|
|
17
|
+
apiDir: raw.apiDir ?? DEFAULT_CONFIG.apiDir,
|
|
18
|
+
apiBasePath: raw.apiBasePath ?? DEFAULT_CONFIG.apiBasePath,
|
|
19
|
+
socketBasePath: raw.socketBasePath ?? DEFAULT_CONFIG.socketBasePath,
|
|
20
|
+
baseUrl: raw.baseUrl ?? DEFAULT_CONFIG.baseUrl,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return { ...DEFAULT_CONFIG };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-project.d.ts","sourceRoot":"","sources":["../../src/cli/mcp-project.ts"],"names":[],"mappings":"AAgBA,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CA+HnD"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import { getManifest } from '../core/introspection/manifest.js';
|
|
3
|
+
import { generateOpenApiSpec } from '../core/openapi/generate.js';
|
|
4
|
+
import { generateAsyncApiSpec } from '../core/asyncapi/generate.js';
|
|
5
|
+
import { loadMcpConfig } from './mcp-project-config.js';
|
|
6
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
const MANIFEST_URI = 'vitek-api://manifest';
|
|
10
|
+
const ROUTES_URI = 'vitek-api://routes';
|
|
11
|
+
const SOCKETS_URI = 'vitek-api://sockets';
|
|
12
|
+
const OPENAPI_URI = 'vitek-api://openapi';
|
|
13
|
+
const ASYNCAPI_URI = 'vitek-api://asyncapi';
|
|
14
|
+
export async function runMcpProject() {
|
|
15
|
+
const root = process.cwd();
|
|
16
|
+
const config = loadMcpConfig(root);
|
|
17
|
+
const server = new McpServer({ name: 'vitek-api', version: '0.1.0' }, { capabilities: { resources: {}, tools: {} } });
|
|
18
|
+
function getManifestData() {
|
|
19
|
+
return getManifest(root, config.apiDir);
|
|
20
|
+
}
|
|
21
|
+
server.registerResource('vitek-api-manifest', MANIFEST_URI, { title: 'Vitek API manifest', description: 'Full manifest (routes, middlewares, sockets)', mimeType: 'application/json' }, async () => {
|
|
22
|
+
const manifest = getManifestData();
|
|
23
|
+
return { contents: [{ uri: MANIFEST_URI, text: JSON.stringify(manifest, null, 2) }] };
|
|
24
|
+
});
|
|
25
|
+
server.registerResource('vitek-api-routes', ROUTES_URI, { title: 'Vitek API routes', description: 'List of HTTP routes', mimeType: 'application/json' }, async () => {
|
|
26
|
+
const manifest = getManifestData();
|
|
27
|
+
return { contents: [{ uri: ROUTES_URI, text: JSON.stringify(manifest.routes, null, 2) }] };
|
|
28
|
+
});
|
|
29
|
+
server.registerResource('vitek-api-sockets', SOCKETS_URI, { title: 'Vitek API sockets', description: 'List of WebSocket routes', mimeType: 'application/json' }, async () => {
|
|
30
|
+
const manifest = getManifestData();
|
|
31
|
+
return { contents: [{ uri: SOCKETS_URI, text: JSON.stringify(manifest.sockets, null, 2) }] };
|
|
32
|
+
});
|
|
33
|
+
server.registerResource('vitek-api-openapi', OPENAPI_URI, { title: 'OpenAPI spec', description: 'OpenAPI 3.0 spec for HTTP API', mimeType: 'application/json' }, async () => {
|
|
34
|
+
const manifest = getManifestData();
|
|
35
|
+
const routesForDocs = manifest.routes.map((r) => ({
|
|
36
|
+
pattern: r.pattern,
|
|
37
|
+
method: r.method,
|
|
38
|
+
params: r.params,
|
|
39
|
+
file: path.join(root, r.file),
|
|
40
|
+
}));
|
|
41
|
+
const spec = generateOpenApiSpec(routesForDocs, { apiBasePath: config.apiBasePath });
|
|
42
|
+
return { contents: [{ uri: OPENAPI_URI, text: JSON.stringify(spec, null, 2) }] };
|
|
43
|
+
});
|
|
44
|
+
server.registerResource('vitek-api-asyncapi', ASYNCAPI_URI, { title: 'AsyncAPI spec', description: 'AsyncAPI 2.x spec for WebSockets', mimeType: 'application/json' }, async () => {
|
|
45
|
+
const manifest = getManifestData();
|
|
46
|
+
const socketsForDocs = manifest.sockets.map((s) => ({ pattern: s.pattern }));
|
|
47
|
+
const spec = generateAsyncApiSpec(socketsForDocs, config.socketBasePath, {});
|
|
48
|
+
return { contents: [{ uri: ASYNCAPI_URI, text: JSON.stringify(spec, null, 2) }] };
|
|
49
|
+
});
|
|
50
|
+
server.registerTool('vitek_api_call', {
|
|
51
|
+
title: 'Call project API',
|
|
52
|
+
description: 'Calls an endpoint of the local Vitek API. Requires the API to be running (e.g. pnpm dev or pnpm start). baseUrl defaults to config or http://localhost:5173.',
|
|
53
|
+
inputSchema: {
|
|
54
|
+
method: z.enum(['get', 'post', 'put', 'patch', 'delete', 'head', 'options']).describe('HTTP method'),
|
|
55
|
+
path: z.string().describe('Path relative to API base, e.g. health or users/1'),
|
|
56
|
+
body: z.any().optional().describe('Request body (for POST/PUT/PATCH)'),
|
|
57
|
+
headers: z.record(z.string()).optional().describe('Additional headers'),
|
|
58
|
+
},
|
|
59
|
+
}, async ({ method, path: pathArg, body, headers }) => {
|
|
60
|
+
const baseUrl = config.baseUrl.replace(/\/+$/, '');
|
|
61
|
+
const apiPath = pathArg.startsWith('/') ? pathArg : `/${pathArg}`;
|
|
62
|
+
const url = `${baseUrl}${config.apiBasePath}${apiPath}`;
|
|
63
|
+
try {
|
|
64
|
+
const res = await fetch(url, {
|
|
65
|
+
method: method.toUpperCase(),
|
|
66
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
67
|
+
body: body != null ? JSON.stringify(body) : undefined,
|
|
68
|
+
});
|
|
69
|
+
const text = await res.text();
|
|
70
|
+
let parsed;
|
|
71
|
+
try {
|
|
72
|
+
parsed = JSON.parse(text);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
parsed = text;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
content: [
|
|
79
|
+
{
|
|
80
|
+
type: 'text',
|
|
81
|
+
text: `Status: ${res.status}\nBody: ${JSON.stringify(parsed, null, 2)}`,
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
88
|
+
return {
|
|
89
|
+
content: [
|
|
90
|
+
{
|
|
91
|
+
type: 'text',
|
|
92
|
+
text: `Request failed. Is the API running at ${baseUrl}? ${message}`,
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
isError: true,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
const transport = new StdioServerTransport();
|
|
100
|
+
await server.connect(transport);
|
|
101
|
+
}
|
package/dist/cli/serve.d.ts
CHANGED
|
@@ -3,5 +3,31 @@
|
|
|
3
3
|
* Usage: vitek-serve [--dir=dist] [--port=3000] [--host=0.0.0.0]
|
|
4
4
|
* Also accepts space-separated: --dir dist --port 3000 --host 0.0.0.0
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
import * as http from 'http';
|
|
7
|
+
import type { ApiClient, SocketEmitter } from '../core/shared/vitek-app.js';
|
|
8
|
+
export type BeforeApiRequestHook = import('../core/server/request-handler.js').BeforeApiRequestHook;
|
|
9
|
+
export interface OnServerStartContext {
|
|
10
|
+
api: ApiClient;
|
|
11
|
+
sockets: SocketEmitter;
|
|
12
|
+
server: http.Server;
|
|
13
|
+
}
|
|
14
|
+
export type OnServerStartHook = (ctx: OnServerStartContext) => void | Promise<void>;
|
|
15
|
+
export type OnServerShutdownHook = () => void | Promise<void>;
|
|
16
|
+
export interface ProductionConfig {
|
|
17
|
+
beforeApiRequest?: BeforeApiRequestHook[];
|
|
18
|
+
onError?: (err: Error, req: http.IncomingMessage, res: http.ServerResponse) => void | Promise<void>;
|
|
19
|
+
onServerStart?: OnServerStartHook;
|
|
20
|
+
onServerShutdown?: OnServerShutdownHook;
|
|
21
|
+
maxBodySize?: number;
|
|
22
|
+
}
|
|
23
|
+
/** Load beforeApiRequest, onError, onServerStart, onServerShutdown from dist/vitek.config.mjs if present. Throws if file exists but import fails. */
|
|
24
|
+
export declare function loadProductionConfig(distDir: string): Promise<ProductionConfig>;
|
|
25
|
+
export declare function parseArgs(): {
|
|
26
|
+
dir: string;
|
|
27
|
+
port: number;
|
|
28
|
+
host: string;
|
|
29
|
+
cors: boolean;
|
|
30
|
+
trustProxy: boolean;
|
|
31
|
+
};
|
|
32
|
+
export declare function main(): Promise<void>;
|
|
7
33
|
//# sourceMappingURL=serve.d.ts.map
|
package/dist/cli/serve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/cli/serve.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/cli/serve.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAW7B,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAY,MAAM,6BAA6B,CAAC;AAItF,MAAM,MAAM,oBAAoB,GAAG,OAAO,mCAAmC,EAAE,oBAAoB,CAAC;AAEpG,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,SAAS,CAAC;IACf,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AACpF,MAAM,MAAM,oBAAoB,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAC1C,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpG,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qJAAqJ;AACrJ,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAoBrF;AAED,wBAAgB,SAAS,IAAI;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAsB3G;AAED,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAiI1C"}
|
package/dist/cli/serve.js
CHANGED
|
@@ -14,10 +14,38 @@ import { createSocketHandler } from '../core/socket/socket-handler.js';
|
|
|
14
14
|
import { API_BASE_PATH, getSocketBasePath } from '../shared/constants.js';
|
|
15
15
|
import { getApiBundleFilename } from '../build/build-api-bundle.js';
|
|
16
16
|
import { getSocketsBundleFilename } from '../build/build-sockets-bundle.js';
|
|
17
|
-
|
|
17
|
+
const VITEK_SERVE_CONFIG_FILENAME = 'vitek.config.mjs';
|
|
18
|
+
/** Load beforeApiRequest, onError, onServerStart, onServerShutdown from dist/vitek.config.mjs if present. Throws if file exists but import fails. */
|
|
19
|
+
export async function loadProductionConfig(distDir) {
|
|
20
|
+
const configPath = path.join(distDir, VITEK_SERVE_CONFIG_FILENAME);
|
|
21
|
+
if (!fs.existsSync(configPath))
|
|
22
|
+
return {};
|
|
23
|
+
const configUrl = pathToFileURL(configPath).href;
|
|
24
|
+
const configMod = await import(configUrl);
|
|
25
|
+
const result = {};
|
|
26
|
+
if (configMod.beforeApiRequest) {
|
|
27
|
+
result.beforeApiRequest = Array.isArray(configMod.beforeApiRequest) ? configMod.beforeApiRequest : [configMod.beforeApiRequest];
|
|
28
|
+
}
|
|
29
|
+
if (configMod.onError)
|
|
30
|
+
result.onError = configMod.onError;
|
|
31
|
+
if (configMod.onServerStart)
|
|
32
|
+
result.onServerStart = configMod.onServerStart;
|
|
33
|
+
if (configMod.onServerShutdown)
|
|
34
|
+
result.onServerShutdown = configMod.onServerShutdown;
|
|
35
|
+
if (configMod.maxBodySize != null)
|
|
36
|
+
result.maxBodySize = configMod.maxBodySize;
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
export function parseArgs() {
|
|
18
40
|
let dir = 'dist';
|
|
19
|
-
|
|
20
|
-
|
|
41
|
+
const portEnv = process.env.PORT;
|
|
42
|
+
const hostEnv = process.env.HOST;
|
|
43
|
+
let port = portEnv !== undefined && portEnv !== '' ? parseInt(portEnv, 10) : 3000;
|
|
44
|
+
if (Number.isNaN(port))
|
|
45
|
+
port = 3000;
|
|
46
|
+
let host = hostEnv !== undefined && hostEnv !== '' ? hostEnv : '0.0.0.0';
|
|
47
|
+
let cors = false;
|
|
48
|
+
let trustProxy = false;
|
|
21
49
|
const argv = process.argv.slice(2);
|
|
22
50
|
for (let i = 0; i < argv.length; i++) {
|
|
23
51
|
const arg = argv[i];
|
|
@@ -33,11 +61,15 @@ function parseArgs() {
|
|
|
33
61
|
host = arg.slice(7);
|
|
34
62
|
else if (arg === '--host' && argv[i + 1])
|
|
35
63
|
host = argv[++i];
|
|
64
|
+
else if (arg === '--cors')
|
|
65
|
+
cors = true;
|
|
66
|
+
else if (arg === '--trust-proxy')
|
|
67
|
+
trustProxy = true;
|
|
36
68
|
}
|
|
37
|
-
return { dir, port, host };
|
|
69
|
+
return { dir, port, host, cors, trustProxy };
|
|
38
70
|
}
|
|
39
|
-
async function main() {
|
|
40
|
-
const { dir, port, host } = parseArgs();
|
|
71
|
+
export async function main() {
|
|
72
|
+
const { dir, port, host, cors, trustProxy } = parseArgs();
|
|
41
73
|
const distDir = path.resolve(process.cwd(), dir);
|
|
42
74
|
if (!fs.existsSync(distDir) || !fs.statSync(distDir).isDirectory()) {
|
|
43
75
|
console.error(`[vitek-serve] Directory not found or not a directory: ${distDir}`);
|
|
@@ -71,6 +103,14 @@ async function main() {
|
|
|
71
103
|
const shared = { sockets: noopSockets, api };
|
|
72
104
|
const app = connect();
|
|
73
105
|
const bundlePath = path.join(distDir, getApiBundleFilename());
|
|
106
|
+
let productionConfig = {};
|
|
107
|
+
try {
|
|
108
|
+
productionConfig = await loadProductionConfig(distDir);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
console.warn('[vitek-serve] Failed to load vitek.config.mjs; continuing without production hooks:', err instanceof Error ? err.message : String(err));
|
|
112
|
+
}
|
|
113
|
+
const { beforeApiRequest, onError, onServerStart, onServerShutdown, maxBodySize } = productionConfig;
|
|
74
114
|
if (fs.existsSync(bundlePath)) {
|
|
75
115
|
try {
|
|
76
116
|
const bundleUrl = pathToFileURL(bundlePath).href;
|
|
@@ -78,6 +118,11 @@ async function main() {
|
|
|
78
118
|
const apiHandler = createRequestHandler({
|
|
79
119
|
routes: mod.routes,
|
|
80
120
|
middlewares: mod.middlewares,
|
|
121
|
+
beforeApiRequest,
|
|
122
|
+
cors: cors ? true : undefined,
|
|
123
|
+
trustProxy,
|
|
124
|
+
maxBodySize,
|
|
125
|
+
onError,
|
|
81
126
|
shared,
|
|
82
127
|
});
|
|
83
128
|
app.use(apiHandler);
|
|
@@ -119,12 +164,42 @@ async function main() {
|
|
|
119
164
|
console.warn('[vitek-serve] Failed to load sockets bundle:', err instanceof Error ? err.message : String(err));
|
|
120
165
|
}
|
|
121
166
|
}
|
|
167
|
+
if (onServerStart) {
|
|
168
|
+
try {
|
|
169
|
+
await Promise.resolve(onServerStart({ api: shared.api, sockets: shared.sockets, server }));
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
console.error('[vitek-serve] onServerStart failed:', err instanceof Error ? err.message : String(err));
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
let shuttingDown = false;
|
|
177
|
+
const shutdown = async () => {
|
|
178
|
+
if (shuttingDown)
|
|
179
|
+
return;
|
|
180
|
+
shuttingDown = true;
|
|
181
|
+
if (onServerShutdown) {
|
|
182
|
+
try {
|
|
183
|
+
await Promise.resolve(onServerShutdown());
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
console.warn('[vitek-serve] onServerShutdown error:', err instanceof Error ? err.message : String(err));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
server.close(() => process.exit(0));
|
|
190
|
+
setTimeout(() => process.exit(0), 5000);
|
|
191
|
+
};
|
|
192
|
+
process.on('SIGTERM', shutdown);
|
|
193
|
+
process.on('SIGINT', shutdown);
|
|
122
194
|
server.listen(port, host, () => {
|
|
123
195
|
const base = `http://${host === '0.0.0.0' ? 'localhost' : host}:${port}`;
|
|
124
196
|
console.log(`[vitek-serve] Ready at ${base}`);
|
|
125
197
|
});
|
|
126
198
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
199
|
+
const isServeEntry = process.argv[1]?.endsWith('serve.js');
|
|
200
|
+
if (typeof process.env.VITEST === 'undefined' && isServeEntry) {
|
|
201
|
+
main().catch((err) => {
|
|
202
|
+
console.error('[vitek-serve]', err);
|
|
203
|
+
process.exit(1);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.test.d.ts","sourceRoot":"","sources":["../../src/cli/serve.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
4
|
+
import { parseArgs, loadProductionConfig } from './serve.js';
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
describe('parseArgs', () => {
|
|
7
|
+
const originalEnv = { ...process.env };
|
|
8
|
+
const originalArgv = [...process.argv];
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
process.argv = ['node', 'vitek-serve'];
|
|
11
|
+
process.env = { ...originalEnv };
|
|
12
|
+
});
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
process.env = originalEnv;
|
|
15
|
+
process.argv = originalArgv;
|
|
16
|
+
});
|
|
17
|
+
it('uses default dir, port, host when no args or env', () => {
|
|
18
|
+
delete process.env.PORT;
|
|
19
|
+
delete process.env.HOST;
|
|
20
|
+
process.argv = ['node', 'vitek-serve'];
|
|
21
|
+
const result = parseArgs();
|
|
22
|
+
expect(result.dir).toBe('dist');
|
|
23
|
+
expect(result.port).toBe(3000);
|
|
24
|
+
expect(result.host).toBe('0.0.0.0');
|
|
25
|
+
expect(result.cors).toBe(false);
|
|
26
|
+
expect(result.trustProxy).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
it('uses process.env.PORT when --port not passed', () => {
|
|
29
|
+
process.env.PORT = '8080';
|
|
30
|
+
delete process.env.HOST;
|
|
31
|
+
process.argv = ['node', 'vitek-serve'];
|
|
32
|
+
const result = parseArgs();
|
|
33
|
+
expect(result.port).toBe(8080);
|
|
34
|
+
expect(result.host).toBe('0.0.0.0');
|
|
35
|
+
});
|
|
36
|
+
it('uses process.env.HOST when --host not passed', () => {
|
|
37
|
+
delete process.env.PORT;
|
|
38
|
+
process.env.HOST = '127.0.0.1';
|
|
39
|
+
process.argv = ['node', 'vitek-serve'];
|
|
40
|
+
const result = parseArgs();
|
|
41
|
+
expect(result.port).toBe(3000);
|
|
42
|
+
expect(result.host).toBe('127.0.0.1');
|
|
43
|
+
});
|
|
44
|
+
it('--port overrides process.env.PORT', () => {
|
|
45
|
+
process.env.PORT = '8080';
|
|
46
|
+
process.argv = ['node', 'vitek-serve', '--port', '4000'];
|
|
47
|
+
const result = parseArgs();
|
|
48
|
+
expect(result.port).toBe(4000);
|
|
49
|
+
});
|
|
50
|
+
it('--host overrides process.env.HOST', () => {
|
|
51
|
+
process.env.HOST = '127.0.0.1';
|
|
52
|
+
process.argv = ['node', 'vitek-serve', '--host', '0.0.0.0'];
|
|
53
|
+
const result = parseArgs();
|
|
54
|
+
expect(result.host).toBe('0.0.0.0');
|
|
55
|
+
});
|
|
56
|
+
it('invalid PORT falls back to 3000', () => {
|
|
57
|
+
process.env.PORT = 'not-a-number';
|
|
58
|
+
process.argv = ['node', 'vitek-serve'];
|
|
59
|
+
const result = parseArgs();
|
|
60
|
+
expect(result.port).toBe(3000);
|
|
61
|
+
});
|
|
62
|
+
it('parses --cors and --trust-proxy', () => {
|
|
63
|
+
process.argv = ['node', 'vitek-serve', '--cors', '--trust-proxy'];
|
|
64
|
+
const result = parseArgs();
|
|
65
|
+
expect(result.cors).toBe(true);
|
|
66
|
+
expect(result.trustProxy).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe('loadProductionConfig', () => {
|
|
70
|
+
it('returns empty object when vitek.config.mjs does not exist', async () => {
|
|
71
|
+
const result = await loadProductionConfig(path.join(__dirname, '..', '..', 'core'));
|
|
72
|
+
expect(result).toEqual({});
|
|
73
|
+
});
|
|
74
|
+
it('loads beforeApiRequest and onError when vitek.config.mjs exists', async () => {
|
|
75
|
+
const fixtureDir = path.join(__dirname, 'fixtures', 'serve-config');
|
|
76
|
+
const result = await loadProductionConfig(fixtureDir);
|
|
77
|
+
expect(result.beforeApiRequest).toBeDefined();
|
|
78
|
+
expect(Array.isArray(result.beforeApiRequest)).toBe(true);
|
|
79
|
+
expect(result.beforeApiRequest.length).toBe(1);
|
|
80
|
+
expect(typeof result.beforeApiRequest[0]).toBe('function');
|
|
81
|
+
expect(result.onError).toBeDefined();
|
|
82
|
+
expect(typeof result.onError).toBe('function');
|
|
83
|
+
});
|
|
84
|
+
it('loads onServerStart and onServerShutdown when vitek.config.mjs exports them', async () => {
|
|
85
|
+
const fixtureDir = path.join(__dirname, 'fixtures', 'serve-config');
|
|
86
|
+
const result = await loadProductionConfig(fixtureDir);
|
|
87
|
+
expect(result.onServerStart).toBeDefined();
|
|
88
|
+
expect(typeof result.onServerStart).toBe('function');
|
|
89
|
+
expect(result.onServerShutdown).toBeDefined();
|
|
90
|
+
expect(typeof result.onServerShutdown).toBe('function');
|
|
91
|
+
});
|
|
92
|
+
it('onServerStart receives context with api, sockets, server', async () => {
|
|
93
|
+
const fixtureDir = path.join(__dirname, 'fixtures', 'serve-config');
|
|
94
|
+
const result = await loadProductionConfig(fixtureDir);
|
|
95
|
+
const mockCtx = {
|
|
96
|
+
api: { fetch: async () => ({}) },
|
|
97
|
+
sockets: { emit: () => { } },
|
|
98
|
+
server: {},
|
|
99
|
+
};
|
|
100
|
+
delete globalThis.__vitekOnServerStartCtx;
|
|
101
|
+
delete globalThis.__vitekOnServerStartCalled;
|
|
102
|
+
result.onServerStart(mockCtx);
|
|
103
|
+
expect(globalThis.__vitekOnServerStartCalled).toBe(true);
|
|
104
|
+
expect(globalThis.__vitekOnServerStartCtx).toEqual(mockCtx);
|
|
105
|
+
delete globalThis.__vitekOnServerStartCtx;
|
|
106
|
+
delete globalThis.__vitekOnServerStartCalled;
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.test.d.ts","sourceRoot":"","sources":["../../../src/core/asyncapi/generate.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { generateAsyncApiSpec, generateAsyncApiFile, } from './generate.js';
|
|
5
|
+
function socket(pattern) {
|
|
6
|
+
return { pattern };
|
|
7
|
+
}
|
|
8
|
+
describe('generateAsyncApiSpec', () => {
|
|
9
|
+
it('returns valid AsyncAPI 2.x spec with empty sockets', () => {
|
|
10
|
+
const spec = generateAsyncApiSpec([], '/ws', {});
|
|
11
|
+
expect(spec.asyncapi).toBe('2.4.0');
|
|
12
|
+
expect(spec.info).toEqual({
|
|
13
|
+
title: 'Vitek WebSocket API',
|
|
14
|
+
version: '1.0.0',
|
|
15
|
+
description: 'WebSocket endpoints (auto-generated from socket routes)',
|
|
16
|
+
});
|
|
17
|
+
expect(spec.channels).toEqual({});
|
|
18
|
+
expect(spec.servers).toBeDefined();
|
|
19
|
+
expect(spec.servers.development).toBeDefined();
|
|
20
|
+
});
|
|
21
|
+
it('uses custom info when provided', () => {
|
|
22
|
+
const spec = generateAsyncApiSpec([], '/ws', {
|
|
23
|
+
info: {
|
|
24
|
+
title: 'My WebSocket API',
|
|
25
|
+
version: '2.0.0',
|
|
26
|
+
description: 'Custom WS API',
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
expect(spec.info).toEqual({
|
|
30
|
+
title: 'My WebSocket API',
|
|
31
|
+
version: '2.0.0',
|
|
32
|
+
description: 'Custom WS API',
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
it('uses custom serverUrl when provided', () => {
|
|
36
|
+
const spec = generateAsyncApiSpec([], '/ws', {
|
|
37
|
+
serverUrl: 'wss://api.example.com/ws',
|
|
38
|
+
});
|
|
39
|
+
const servers = spec.servers;
|
|
40
|
+
const dev = servers.development;
|
|
41
|
+
expect(dev.url).toBe('wss://api.example.com/ws');
|
|
42
|
+
expect(dev.protocol).toBe('wss');
|
|
43
|
+
});
|
|
44
|
+
it('default serverUrl uses ws protocol', () => {
|
|
45
|
+
const spec = generateAsyncApiSpec([], '/ws', {});
|
|
46
|
+
const servers = spec.servers;
|
|
47
|
+
const dev = servers.development;
|
|
48
|
+
expect(dev.url).toBe('ws://localhost:5173');
|
|
49
|
+
expect(dev.protocol).toBe('ws');
|
|
50
|
+
});
|
|
51
|
+
it('generates channel for root socket pattern', () => {
|
|
52
|
+
const sockets = [socket('')];
|
|
53
|
+
const spec = generateAsyncApiSpec(sockets, '/ws', {});
|
|
54
|
+
const channels = spec.channels;
|
|
55
|
+
expect(channels['/ws']).toBeDefined();
|
|
56
|
+
const channel = channels['/ws'];
|
|
57
|
+
expect(channel.description).toContain('Root WebSocket');
|
|
58
|
+
expect(channel.subscribe).toBeDefined();
|
|
59
|
+
expect(channel.publish).toBeDefined();
|
|
60
|
+
});
|
|
61
|
+
it('generates channel for path socket pattern', () => {
|
|
62
|
+
const sockets = [socket('notifications')];
|
|
63
|
+
const spec = generateAsyncApiSpec(sockets, '/ws', {});
|
|
64
|
+
const channels = spec.channels;
|
|
65
|
+
expect(channels['/ws/notifications']).toBeDefined();
|
|
66
|
+
const channel = channels['/ws/notifications'];
|
|
67
|
+
expect(channel.description).toContain('WebSocket');
|
|
68
|
+
expect(channel.subscribe.operationId).toContain('onMessage');
|
|
69
|
+
expect(channel.publish.operationId).toContain('send');
|
|
70
|
+
});
|
|
71
|
+
it('generates multiple channels for multiple sockets', () => {
|
|
72
|
+
const sockets = [socket('chat'), socket('notifications'), socket('')];
|
|
73
|
+
const spec = generateAsyncApiSpec(sockets, '/ws', {});
|
|
74
|
+
const channels = spec.channels;
|
|
75
|
+
expect(Object.keys(channels)).toHaveLength(3);
|
|
76
|
+
expect(channels['/ws/chat']).toBeDefined();
|
|
77
|
+
expect(channels['/ws/notifications']).toBeDefined();
|
|
78
|
+
expect(channels['/ws']).toBeDefined();
|
|
79
|
+
});
|
|
80
|
+
it('channel subscribe and publish have message payload schema', () => {
|
|
81
|
+
const sockets = [socket('events')];
|
|
82
|
+
const spec = generateAsyncApiSpec(sockets, '/ws', {});
|
|
83
|
+
const channel = spec.channels['/ws/events'];
|
|
84
|
+
const sub = channel.subscribe;
|
|
85
|
+
const subMsg = sub.message.payload;
|
|
86
|
+
expect(subMsg.type).toBe('object');
|
|
87
|
+
const pub = channel.publish;
|
|
88
|
+
const pubMsg = pub.message.payload;
|
|
89
|
+
expect(pubMsg.type).toBe('object');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe('generateAsyncApiFile', () => {
|
|
93
|
+
let tmpDir;
|
|
94
|
+
beforeEach(() => {
|
|
95
|
+
tmpDir = fs.mkdtempSync(path.join(process.cwd(), 'asyncapi-gen-test-'));
|
|
96
|
+
});
|
|
97
|
+
afterEach(() => {
|
|
98
|
+
try {
|
|
99
|
+
fs.rmSync(tmpDir, { recursive: true });
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
//
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
it('writes valid JSON spec to file', async () => {
|
|
106
|
+
const outputPath = path.join(tmpDir, 'asyncapi.json');
|
|
107
|
+
const sockets = [socket('chat')];
|
|
108
|
+
await generateAsyncApiFile(outputPath, sockets, '/ws', {});
|
|
109
|
+
expect(fs.existsSync(outputPath)).toBe(true);
|
|
110
|
+
const content = fs.readFileSync(outputPath, 'utf-8');
|
|
111
|
+
const parsed = JSON.parse(content);
|
|
112
|
+
expect(parsed.asyncapi).toBe('2.4.0');
|
|
113
|
+
expect(parsed.channels['/ws/chat']).toBeDefined();
|
|
114
|
+
});
|
|
115
|
+
it('creates directory if it does not exist', async () => {
|
|
116
|
+
const outputPath = path.join(tmpDir, 'nested', 'dir', 'asyncapi.json');
|
|
117
|
+
await generateAsyncApiFile(outputPath, [], '/ws', {});
|
|
118
|
+
expect(fs.existsSync(outputPath)).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -11,6 +11,8 @@ export interface VitekContext {
|
|
|
11
11
|
params: Record<string, string>;
|
|
12
12
|
headers: Record<string, string>;
|
|
13
13
|
body?: any;
|
|
14
|
+
/** When trustProxy is true, client IP from X-Forwarded-For or socket.remoteAddress. */
|
|
15
|
+
clientIp?: string;
|
|
14
16
|
/** When the app runs with shared context (dev, preview, serve), use to broadcast to WebSocket clients. */
|
|
15
17
|
sockets?: SocketEmitter;
|
|
16
18
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-context.d.ts","sourceRoot":"","sources":["../../../src/core/context/create-context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,0GAA0G;IAC1G,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,aAAa,CAWlE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,YAAY,EACrB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACnC,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAM,GAC5C,YAAY,CAYd"}
|
|
1
|
+
{"version":3,"file":"create-context.d.ts","sourceRoot":"","sources":["../../../src/core/context/create-context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0GAA0G;IAC1G,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,aAAa,CAWlE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,YAAY,EACrB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACnC,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAM,GAC5C,YAAY,CAYd"}
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export type FileChangeEvent = 'add' | 'change' | 'unlink';
|
|
6
6
|
export type FileChangeCallback = (event: FileChangeEvent, filePath: string) => void;
|
|
7
|
+
export interface WatchApiDirectoryOptions {
|
|
8
|
+
debounceMs?: number;
|
|
9
|
+
}
|
|
7
10
|
/**
|
|
8
11
|
* Interface for watcher (allows different implementations)
|
|
9
12
|
*/
|
|
@@ -14,5 +17,5 @@ export interface ApiWatcher {
|
|
|
14
17
|
* Creates a watcher for the API directory using Node.js fs.watch
|
|
15
18
|
* Returns a function to stop watching
|
|
16
19
|
*/
|
|
17
|
-
export declare function watchApiDirectory(apiDir: string, callback: FileChangeCallback): ApiWatcher;
|
|
20
|
+
export declare function watchApiDirectory(apiDir: string, callback: FileChangeCallback, options?: WatchApiDirectoryOptions): ApiWatcher;
|
|
18
21
|
//# sourceMappingURL=watch-api-dir.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch-api-dir.d.ts","sourceRoot":"","sources":["../../../src/core/file-system/watch-api-dir.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAC1D,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpF;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"watch-api-dir.d.ts","sourceRoot":"","sources":["../../../src/core/file-system/watch-api-dir.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAC1D,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpF,MAAM,WAAW,wBAAwB;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,GAAE,wBAA6B,GACrC,UAAU,CA2DZ"}
|