vector-framework 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -634
- package/dist/auth/protected.d.ts.map +1 -1
- package/dist/auth/protected.js.map +1 -1
- package/dist/cache/manager.d.ts +5 -2
- package/dist/cache/manager.d.ts.map +1 -1
- package/dist/cache/manager.js +21 -12
- package/dist/cache/manager.js.map +1 -1
- package/dist/cli/index.js +60 -126
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/option-resolution.d.ts +4 -0
- package/dist/cli/option-resolution.d.ts.map +1 -0
- package/dist/cli/option-resolution.js +28 -0
- package/dist/cli/option-resolution.js.map +1 -0
- package/dist/cli.js +2774 -599
- package/dist/constants/index.d.ts +3 -0
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/index.js +6 -0
- package/dist/constants/index.js.map +1 -1
- package/dist/core/config-loader.d.ts +2 -2
- package/dist/core/config-loader.d.ts.map +1 -1
- package/dist/core/config-loader.js +18 -18
- package/dist/core/config-loader.js.map +1 -1
- package/dist/core/router.d.ts +41 -15
- package/dist/core/router.d.ts.map +1 -1
- package/dist/core/router.js +465 -150
- package/dist/core/router.js.map +1 -1
- package/dist/core/server.d.ts +17 -3
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +274 -33
- package/dist/core/server.js.map +1 -1
- package/dist/core/vector.d.ts +9 -8
- package/dist/core/vector.d.ts.map +1 -1
- package/dist/core/vector.js +40 -32
- package/dist/core/vector.js.map +1 -1
- package/dist/dev/route-generator.d.ts.map +1 -1
- package/dist/dev/route-generator.js.map +1 -1
- package/dist/dev/route-scanner.d.ts +1 -1
- package/dist/dev/route-scanner.d.ts.map +1 -1
- package/dist/dev/route-scanner.js +37 -43
- package/dist/dev/route-scanner.js.map +1 -1
- package/dist/http.d.ts +14 -14
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +84 -84
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1314 -8
- package/dist/index.mjs +1314 -8
- package/dist/middleware/manager.d.ts +1 -1
- package/dist/middleware/manager.d.ts.map +1 -1
- package/dist/middleware/manager.js +4 -0
- package/dist/middleware/manager.js.map +1 -1
- package/dist/openapi/docs-ui.d.ts +2 -0
- package/dist/openapi/docs-ui.d.ts.map +1 -0
- package/dist/openapi/docs-ui.js +1313 -0
- package/dist/openapi/docs-ui.js.map +1 -0
- package/dist/openapi/generator.d.ts +12 -0
- package/dist/openapi/generator.d.ts.map +1 -0
- package/dist/openapi/generator.js +273 -0
- package/dist/openapi/generator.js.map +1 -0
- package/dist/types/index.d.ts +70 -11
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/standard-schema.d.ts +118 -0
- package/dist/types/standard-schema.d.ts.map +1 -0
- package/dist/types/standard-schema.js +2 -0
- package/dist/types/standard-schema.js.map +1 -0
- package/dist/utils/cors.d.ts +13 -0
- package/dist/utils/cors.d.ts.map +1 -0
- package/dist/utils/cors.js +89 -0
- package/dist/utils/cors.js.map +1 -0
- package/dist/utils/path.d.ts +7 -0
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js +14 -3
- package/dist/utils/path.js.map +1 -1
- package/dist/utils/schema-validation.d.ts +31 -0
- package/dist/utils/schema-validation.d.ts.map +1 -0
- package/dist/utils/schema-validation.js +77 -0
- package/dist/utils/schema-validation.js.map +1 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +1 -0
- package/dist/utils/validation.js.map +1 -1
- package/package.json +24 -19
- package/src/auth/protected.ts +3 -13
- package/src/cache/manager.ts +25 -30
- package/src/cli/index.ts +62 -141
- package/src/cli/option-resolution.ts +40 -0
- package/src/constants/index.ts +7 -0
- package/src/core/config-loader.ts +20 -22
- package/src/core/router.ts +535 -155
- package/src/core/server.ts +354 -45
- package/src/core/vector.ts +71 -61
- package/src/dev/route-generator.ts +1 -3
- package/src/dev/route-scanner.ts +38 -51
- package/src/http.ts +117 -187
- package/src/index.ts +3 -3
- package/src/middleware/manager.ts +8 -11
- package/src/openapi/assets/tailwindcdn.js +83 -0
- package/src/openapi/docs-ui.ts +1317 -0
- package/src/openapi/generator.ts +359 -0
- package/src/types/index.ts +104 -17
- package/src/types/standard-schema.ts +147 -0
- package/src/utils/cors.ts +101 -0
- package/src/utils/path.ts +19 -4
- package/src/utils/schema-validation.ts +123 -0
- package/src/utils/validation.ts +1 -0
package/src/cli/index.ts
CHANGED
|
@@ -1,54 +1,57 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import { watch } from
|
|
4
|
-
import { parseArgs } from
|
|
5
|
-
import { getVectorInstance } from
|
|
6
|
-
import { ConfigLoader } from
|
|
3
|
+
import { watch } from 'node:fs';
|
|
4
|
+
import { parseArgs } from 'node:util';
|
|
5
|
+
import { getVectorInstance } from '../core/vector';
|
|
6
|
+
import { ConfigLoader } from '../core/config-loader';
|
|
7
|
+
import { resolveHost, resolvePort, resolveRoutesDir } from './option-resolution';
|
|
7
8
|
|
|
8
9
|
// Compatibility layer for both Node and Bun
|
|
9
|
-
const args =
|
|
10
|
-
typeof Bun !== "undefined" ? Bun.argv.slice(2) : process.argv.slice(2);
|
|
10
|
+
const args = typeof Bun !== 'undefined' ? Bun.argv.slice(2) : process.argv.slice(2);
|
|
11
11
|
|
|
12
12
|
const { values, positionals } = parseArgs({
|
|
13
13
|
args,
|
|
14
14
|
options: {
|
|
15
15
|
port: {
|
|
16
|
-
type:
|
|
17
|
-
short:
|
|
18
|
-
default:
|
|
16
|
+
type: 'string',
|
|
17
|
+
short: 'p',
|
|
18
|
+
default: '3000',
|
|
19
19
|
},
|
|
20
20
|
host: {
|
|
21
|
-
type:
|
|
22
|
-
short:
|
|
23
|
-
default:
|
|
21
|
+
type: 'string',
|
|
22
|
+
short: 'h',
|
|
23
|
+
default: 'localhost',
|
|
24
24
|
},
|
|
25
25
|
routes: {
|
|
26
|
-
type:
|
|
27
|
-
short:
|
|
28
|
-
default:
|
|
26
|
+
type: 'string',
|
|
27
|
+
short: 'r',
|
|
28
|
+
default: './routes',
|
|
29
29
|
},
|
|
30
30
|
watch: {
|
|
31
|
-
type:
|
|
32
|
-
short:
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
short: 'w',
|
|
33
33
|
default: true,
|
|
34
34
|
},
|
|
35
35
|
cors: {
|
|
36
|
-
type:
|
|
36
|
+
type: 'boolean',
|
|
37
37
|
default: true,
|
|
38
38
|
},
|
|
39
39
|
config: {
|
|
40
|
-
type:
|
|
41
|
-
short:
|
|
40
|
+
type: 'string',
|
|
41
|
+
short: 'c',
|
|
42
42
|
},
|
|
43
43
|
},
|
|
44
44
|
strict: true,
|
|
45
45
|
allowPositionals: true,
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
const command = positionals[0] ||
|
|
48
|
+
const command = positionals[0] || 'dev';
|
|
49
|
+
const hasRoutesOption = args.some((arg) => arg === '--routes' || arg === '-r' || arg.startsWith('--routes='));
|
|
50
|
+
const hasHostOption = args.some((arg) => arg === '--host' || arg === '-h' || arg.startsWith('--host='));
|
|
51
|
+
const hasPortOption = args.some((arg) => arg === '--port' || arg === '-p' || arg.startsWith('--port='));
|
|
49
52
|
|
|
50
53
|
async function runDev() {
|
|
51
|
-
const isDev = command ===
|
|
54
|
+
const isDev = command === 'dev';
|
|
52
55
|
|
|
53
56
|
let server: any = null;
|
|
54
57
|
let vector: any = null;
|
|
@@ -57,21 +60,22 @@ async function runDev() {
|
|
|
57
60
|
// Create a timeout promise that rejects after 10 seconds
|
|
58
61
|
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
59
62
|
setTimeout(() => {
|
|
60
|
-
reject(new Error(
|
|
63
|
+
reject(new Error('Server startup timed out (10s)'));
|
|
61
64
|
}, 10000);
|
|
62
65
|
});
|
|
63
66
|
|
|
64
67
|
// Create the actual server start promise
|
|
65
68
|
const serverStartPromise = (async (): Promise<{ server: any; vector: any; config: any }> => {
|
|
66
|
-
|
|
67
|
-
const configLoader = new ConfigLoader(
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
config.
|
|
74
|
-
config.
|
|
69
|
+
const explicitConfigPath = values.config as string | undefined;
|
|
70
|
+
const configLoader = new ConfigLoader(explicitConfigPath);
|
|
71
|
+
const loadedConfig = await configLoader.load();
|
|
72
|
+
const config = { ...loadedConfig } as Record<string, any>;
|
|
73
|
+
|
|
74
|
+
// Merge CLI options with loaded config.
|
|
75
|
+
// Explicit --port/--host always override config values.
|
|
76
|
+
config.port = resolvePort(config.port, hasPortOption, values.port as string);
|
|
77
|
+
config.hostname = resolveHost(config.hostname, hasHostOption, values.host as string);
|
|
78
|
+
config.routesDir = resolveRoutesDir(config.routesDir, hasRoutesOption, values.routes as string);
|
|
75
79
|
config.development = config.development ?? isDev;
|
|
76
80
|
config.autoDiscover = true; // Always auto-discover routes
|
|
77
81
|
|
|
@@ -79,11 +83,11 @@ async function runDev() {
|
|
|
79
83
|
// Only apply default CORS if config.cors is undefined (not set)
|
|
80
84
|
if (config.cors === undefined && values.cors) {
|
|
81
85
|
config.cors = {
|
|
82
|
-
origin:
|
|
86
|
+
origin: '*',
|
|
83
87
|
credentials: true,
|
|
84
|
-
allowHeaders:
|
|
85
|
-
allowMethods:
|
|
86
|
-
exposeHeaders:
|
|
88
|
+
allowHeaders: 'Content-Type, Authorization',
|
|
89
|
+
allowMethods: 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
|
|
90
|
+
exposeHeaders: 'Authorization',
|
|
87
91
|
maxAge: 86400,
|
|
88
92
|
};
|
|
89
93
|
}
|
|
@@ -108,15 +112,13 @@ async function runDev() {
|
|
|
108
112
|
|
|
109
113
|
// Verify the server is actually running
|
|
110
114
|
if (!server || !server.port) {
|
|
111
|
-
throw new Error(
|
|
115
|
+
throw new Error('Server started but is not responding correctly');
|
|
112
116
|
}
|
|
113
117
|
|
|
114
|
-
const cyan =
|
|
115
|
-
const reset =
|
|
118
|
+
const cyan = '\x1b[36m';
|
|
119
|
+
const reset = '\x1b[0m';
|
|
116
120
|
|
|
117
|
-
console.log(
|
|
118
|
-
`\nListening on ${cyan}http://${config.hostname}:${config.port}${reset}\n`
|
|
119
|
-
);
|
|
121
|
+
console.log(`\nListening on ${cyan}http://${config.hostname}:${config.port}${reset}\n`);
|
|
120
122
|
|
|
121
123
|
return { server, vector, config };
|
|
122
124
|
})();
|
|
@@ -144,17 +146,14 @@ async function runDev() {
|
|
|
144
146
|
const now = Date.now();
|
|
145
147
|
if (isReloading || now - lastReloadTime < 1000) return;
|
|
146
148
|
|
|
149
|
+
const segments = filename ? filename.split(/[/\\]/) : [];
|
|
150
|
+
const excluded = segments.some((s) => ['node_modules', '.git', '.vector', 'dist'].includes(s));
|
|
147
151
|
if (
|
|
148
152
|
filename &&
|
|
149
|
-
(filename.endsWith(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
!filename.
|
|
153
|
-
!filename.includes(".git") &&
|
|
154
|
-
!filename.includes(".vector") && // Ignore generated files
|
|
155
|
-
!filename.includes("dist") && // Ignore dist folder
|
|
156
|
-
!filename.includes("bun.lockb") && // Ignore lock files
|
|
157
|
-
!filename.endsWith(".generated.ts") // Ignore generated files
|
|
153
|
+
(filename.endsWith('.ts') || filename.endsWith('.js') || filename.endsWith('.json')) &&
|
|
154
|
+
!excluded &&
|
|
155
|
+
!filename.includes('bun.lockb') && // Ignore lock files
|
|
156
|
+
!filename.endsWith('.generated.ts') // Ignore generated files
|
|
158
157
|
) {
|
|
159
158
|
// Track changed files
|
|
160
159
|
changedFiles.add(filename);
|
|
@@ -181,24 +180,13 @@ async function runDev() {
|
|
|
181
180
|
// Small delay to ensure file system operations complete
|
|
182
181
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
183
182
|
|
|
184
|
-
// Clear module cache to ensure fresh imports
|
|
185
|
-
// Note: Bun uses ESM and doesn't have require.cache
|
|
186
|
-
// The Loader API will handle module reloading automatically
|
|
187
|
-
if (typeof require !== 'undefined' && require.cache) {
|
|
188
|
-
for (const key in require.cache) {
|
|
189
|
-
if (!key.includes("node_modules")) {
|
|
190
|
-
delete require.cache[key];
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
183
|
// Restart the server
|
|
196
184
|
try {
|
|
197
185
|
const result = await startServer();
|
|
198
186
|
server = result.server;
|
|
199
187
|
vector = result.vector;
|
|
200
188
|
} catch (error: any) {
|
|
201
|
-
console.error(
|
|
189
|
+
console.error('\n[Reload Error]', error.message || error);
|
|
202
190
|
// Don't exit the process on reload failures, just continue watching
|
|
203
191
|
} finally {
|
|
204
192
|
// Reset flag immediately after reload completes
|
|
@@ -209,18 +197,18 @@ async function runDev() {
|
|
|
209
197
|
}
|
|
210
198
|
});
|
|
211
199
|
} catch {
|
|
212
|
-
const yellow =
|
|
213
|
-
const reset =
|
|
200
|
+
const yellow = '\x1b[33m';
|
|
201
|
+
const reset = '\x1b[0m';
|
|
214
202
|
console.warn(`${yellow}Warning: File watching not available${reset}`);
|
|
215
203
|
}
|
|
216
204
|
}
|
|
217
205
|
} catch (error: any) {
|
|
218
|
-
const red =
|
|
219
|
-
const reset =
|
|
206
|
+
const red = '\x1b[31m';
|
|
207
|
+
const reset = '\x1b[0m';
|
|
220
208
|
|
|
221
209
|
console.error(`\n${red}Error: ${error.message || error}${reset}\n`);
|
|
222
210
|
|
|
223
|
-
if (error.stack && process.env.NODE_ENV ===
|
|
211
|
+
if (error.stack && process.env.NODE_ENV === 'development') {
|
|
224
212
|
console.error(error.stack);
|
|
225
213
|
}
|
|
226
214
|
|
|
@@ -228,81 +216,15 @@ async function runDev() {
|
|
|
228
216
|
}
|
|
229
217
|
}
|
|
230
218
|
|
|
231
|
-
async function runBuild() {
|
|
232
|
-
try {
|
|
233
|
-
const { RouteScanner } = await import("../dev/route-scanner");
|
|
234
|
-
const { RouteGenerator } = await import("../dev/route-generator");
|
|
235
|
-
|
|
236
|
-
// Step 1: Scan and generate routes
|
|
237
|
-
const scanner = new RouteScanner(values.routes as string);
|
|
238
|
-
const generator = new RouteGenerator();
|
|
239
|
-
|
|
240
|
-
const routes = await scanner.scan();
|
|
241
|
-
await generator.generate(routes);
|
|
242
|
-
|
|
243
|
-
// Step 2: Build the application with Bun
|
|
244
|
-
if (typeof Bun !== "undefined") {
|
|
245
|
-
// Build the CLI as an executable
|
|
246
|
-
const buildProcess = Bun.spawn([
|
|
247
|
-
"bun",
|
|
248
|
-
"build",
|
|
249
|
-
"src/cli/index.ts",
|
|
250
|
-
"--target",
|
|
251
|
-
"bun",
|
|
252
|
-
"--outfile",
|
|
253
|
-
"dist/server.js",
|
|
254
|
-
"--minify",
|
|
255
|
-
]);
|
|
256
|
-
|
|
257
|
-
const exitCode = await buildProcess.exited;
|
|
258
|
-
if (exitCode !== 0) {
|
|
259
|
-
throw new Error(`Build failed with exit code ${exitCode}`);
|
|
260
|
-
}
|
|
261
|
-
} else {
|
|
262
|
-
// For Node.js, use child_process
|
|
263
|
-
const { spawnSync } = await import("child_process");
|
|
264
|
-
const result = spawnSync(
|
|
265
|
-
"bun",
|
|
266
|
-
[
|
|
267
|
-
"build",
|
|
268
|
-
"src/cli/index.ts",
|
|
269
|
-
"--target",
|
|
270
|
-
"bun",
|
|
271
|
-
"--outfile",
|
|
272
|
-
"dist/server.js",
|
|
273
|
-
"--minify",
|
|
274
|
-
],
|
|
275
|
-
{
|
|
276
|
-
stdio: "inherit",
|
|
277
|
-
shell: true,
|
|
278
|
-
}
|
|
279
|
-
);
|
|
280
|
-
|
|
281
|
-
if (result.status !== 0) {
|
|
282
|
-
throw new Error(`Build failed with exit code ${result.status}`);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
console.log("\nBuild complete: dist/server.js\n");
|
|
287
|
-
} catch (error: any) {
|
|
288
|
-
const red = "\x1b[31m";
|
|
289
|
-
const reset = "\x1b[0m";
|
|
290
|
-
console.error(`\n${red}Error: ${error.message || error}${reset}\n`);
|
|
291
|
-
process.exit(1);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
219
|
switch (command) {
|
|
296
|
-
case
|
|
220
|
+
case 'dev':
|
|
297
221
|
await runDev();
|
|
298
222
|
break;
|
|
299
|
-
case
|
|
300
|
-
|
|
301
|
-
break;
|
|
302
|
-
case "start":
|
|
303
|
-
process.env.NODE_ENV = "production";
|
|
223
|
+
case 'start': {
|
|
224
|
+
process.env.NODE_ENV = 'production';
|
|
304
225
|
await runDev();
|
|
305
226
|
break;
|
|
227
|
+
}
|
|
306
228
|
default:
|
|
307
229
|
console.error(`Unknown command: ${command}`);
|
|
308
230
|
console.log(`
|
|
@@ -310,15 +232,14 @@ Usage: vector [command] [options]
|
|
|
310
232
|
|
|
311
233
|
Commands:
|
|
312
234
|
dev Start development server (default)
|
|
313
|
-
build Build for production
|
|
314
235
|
start Start production server
|
|
315
236
|
|
|
316
237
|
Options:
|
|
317
238
|
-p, --port <port> Port to listen on (default: 3000)
|
|
318
239
|
-h, --host <host> Hostname to bind to (default: localhost)
|
|
319
|
-
-r, --routes <dir> Routes directory (
|
|
240
|
+
-r, --routes <dir> Routes directory (dev/start)
|
|
320
241
|
-w, --watch Watch for file changes (default: true)
|
|
321
|
-
-c, --config <path> Path to config file (
|
|
242
|
+
-c, --config <path> Path to config file (dev/start)
|
|
322
243
|
--cors Enable CORS (default: true)
|
|
323
244
|
`);
|
|
324
245
|
process.exit(1);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export function resolveRoutesDir(
|
|
2
|
+
configRoutesDir: string | null | undefined,
|
|
3
|
+
hasRoutesOption: boolean,
|
|
4
|
+
cliRoutes: string
|
|
5
|
+
): string {
|
|
6
|
+
if (hasRoutesOption) {
|
|
7
|
+
return cliRoutes;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return configRoutesDir ?? cliRoutes;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function parseAndValidatePort(value: unknown): number {
|
|
14
|
+
const parsed = typeof value === 'number' ? value : Number.parseInt(String(value), 10);
|
|
15
|
+
|
|
16
|
+
if (!Number.isInteger(parsed) || parsed < 0 || parsed > 65535) {
|
|
17
|
+
throw new Error(`Invalid port value: ${String(value)}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return parsed;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function resolvePort(configPort: number | null | undefined, hasPortOption: boolean, cliPort: string): number {
|
|
24
|
+
if (hasPortOption) {
|
|
25
|
+
return parseAndValidatePort(cliPort);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const resolved = configPort ?? cliPort;
|
|
29
|
+
return parseAndValidatePort(resolved);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function resolveHost(configHost: string | null | undefined, hasHostOption: boolean, cliHost: string): string {
|
|
33
|
+
const resolved = hasHostOption ? cliHost : (configHost ?? cliHost);
|
|
34
|
+
|
|
35
|
+
if (typeof resolved !== 'string' || resolved.length === 0) {
|
|
36
|
+
throw new Error(`Invalid host value: ${String(resolved)}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return resolved;
|
|
40
|
+
}
|
package/src/constants/index.ts
CHANGED
|
@@ -91,3 +91,10 @@ export const HTTP_METHODS = {
|
|
|
91
91
|
OPTIONS: 'OPTIONS',
|
|
92
92
|
HEAD: 'HEAD',
|
|
93
93
|
} as const;
|
|
94
|
+
|
|
95
|
+
export const STATIC_RESPONSES: { NOT_FOUND: Response } = {
|
|
96
|
+
NOT_FOUND: new Response(JSON.stringify({ error: true, message: 'Not Found', statusCode: 404 }), {
|
|
97
|
+
status: 404,
|
|
98
|
+
headers: { 'content-type': 'application/json' },
|
|
99
|
+
}) as Response,
|
|
100
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { existsSync } from
|
|
2
|
-
import { resolve, isAbsolute } from
|
|
3
|
-
import { toFileUrl } from
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { resolve, isAbsolute } from 'node:path';
|
|
3
|
+
import { toFileUrl } from '../utils/path';
|
|
4
4
|
import type {
|
|
5
5
|
CacheHandler,
|
|
6
6
|
CorsOptions,
|
|
@@ -9,21 +9,19 @@ import type {
|
|
|
9
9
|
VectorConfig,
|
|
10
10
|
VectorConfigSchema,
|
|
11
11
|
VectorTypes,
|
|
12
|
-
} from
|
|
12
|
+
} from '../types';
|
|
13
13
|
|
|
14
14
|
export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
15
15
|
private configPath: string;
|
|
16
16
|
private config: VectorConfigSchema<TTypes> | null = null;
|
|
17
|
-
private configSource:
|
|
17
|
+
private configSource: 'user' | 'default' = 'default';
|
|
18
18
|
|
|
19
19
|
constructor(configPath?: string) {
|
|
20
20
|
// Use provided config path or default to vector.config.ts
|
|
21
|
-
const path = configPath ||
|
|
21
|
+
const path = configPath || 'vector.config.ts';
|
|
22
22
|
|
|
23
23
|
// Handle absolute vs relative paths
|
|
24
|
-
this.configPath = isAbsolute(path)
|
|
25
|
-
? path
|
|
26
|
-
: resolve(process.cwd(), path);
|
|
24
|
+
this.configPath = isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
async load(): Promise<VectorConfig<TTypes>> {
|
|
@@ -34,13 +32,11 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
34
32
|
const userConfigPath = toFileUrl(this.configPath);
|
|
35
33
|
const userConfig = await import(userConfigPath);
|
|
36
34
|
this.config = userConfig.default || userConfig;
|
|
37
|
-
this.configSource =
|
|
35
|
+
this.configSource = 'user';
|
|
38
36
|
} catch (error: any) {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
console.error(
|
|
42
|
-
`${red}Error loading config: ${error.message || error}${reset}`
|
|
43
|
-
);
|
|
37
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
38
|
+
console.error(`[Vector] Failed to load config from ${this.configPath}: ${msg}`);
|
|
39
|
+
console.error('[Vector] Server is using default configuration. Fix your config file and restart.');
|
|
44
40
|
this.config = {};
|
|
45
41
|
}
|
|
46
42
|
} else {
|
|
@@ -52,7 +48,7 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
52
48
|
return await this.buildLegacyConfig();
|
|
53
49
|
}
|
|
54
50
|
|
|
55
|
-
getConfigSource():
|
|
51
|
+
getConfigSource(): 'user' | 'default' {
|
|
56
52
|
return this.configSource;
|
|
57
53
|
}
|
|
58
54
|
|
|
@@ -65,8 +61,10 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
65
61
|
config.hostname = this.config.hostname;
|
|
66
62
|
config.reusePort = this.config.reusePort;
|
|
67
63
|
config.development = this.config.development;
|
|
68
|
-
config.routesDir = this.config.routesDir ||
|
|
64
|
+
config.routesDir = this.config.routesDir || './routes';
|
|
69
65
|
config.idleTimeout = this.config.idleTimeout;
|
|
66
|
+
config.defaults = this.config.defaults;
|
|
67
|
+
config.openapi = this.config.openapi;
|
|
70
68
|
}
|
|
71
69
|
|
|
72
70
|
// Always auto-discover routes
|
|
@@ -74,14 +72,14 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
74
72
|
|
|
75
73
|
// CORS configuration
|
|
76
74
|
if (this.config?.cors) {
|
|
77
|
-
if (typeof this.config.cors ===
|
|
75
|
+
if (typeof this.config.cors === 'boolean') {
|
|
78
76
|
config.cors = this.config.cors
|
|
79
77
|
? {
|
|
80
|
-
origin:
|
|
78
|
+
origin: '*',
|
|
81
79
|
credentials: true,
|
|
82
|
-
allowHeaders:
|
|
83
|
-
allowMethods:
|
|
84
|
-
exposeHeaders:
|
|
80
|
+
allowHeaders: 'Content-Type, Authorization',
|
|
81
|
+
allowMethods: 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
|
|
82
|
+
exposeHeaders: 'Authorization',
|
|
85
83
|
maxAge: 86400,
|
|
86
84
|
}
|
|
87
85
|
: undefined;
|