vector-framework 1.0.0 → 1.1.1

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 (54) hide show
  1. package/README.md +6 -5
  2. package/dist/cache/manager.d.ts +5 -2
  3. package/dist/cache/manager.d.ts.map +1 -1
  4. package/dist/cache/manager.js +21 -7
  5. package/dist/cache/manager.js.map +1 -1
  6. package/dist/cli/index.js +62 -83
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/cli.js +108 -37
  9. package/dist/core/config-loader.d.ts +2 -2
  10. package/dist/core/config-loader.d.ts.map +1 -1
  11. package/dist/core/config-loader.js +16 -18
  12. package/dist/core/config-loader.js.map +1 -1
  13. package/dist/core/router.d.ts +2 -0
  14. package/dist/core/router.d.ts.map +1 -1
  15. package/dist/core/router.js +52 -16
  16. package/dist/core/router.js.map +1 -1
  17. package/dist/core/server.d.ts +4 -3
  18. package/dist/core/server.d.ts.map +1 -1
  19. package/dist/core/server.js +39 -18
  20. package/dist/core/server.js.map +1 -1
  21. package/dist/core/vector.d.ts +7 -7
  22. package/dist/core/vector.d.ts.map +1 -1
  23. package/dist/core/vector.js +20 -21
  24. package/dist/core/vector.js.map +1 -1
  25. package/dist/dev/route-scanner.d.ts +1 -1
  26. package/dist/dev/route-scanner.d.ts.map +1 -1
  27. package/dist/dev/route-scanner.js +40 -42
  28. package/dist/dev/route-scanner.js.map +1 -1
  29. package/dist/http.d.ts +2 -2
  30. package/dist/http.d.ts.map +1 -1
  31. package/dist/http.js +70 -63
  32. package/dist/http.js.map +1 -1
  33. package/dist/index.d.ts +3 -3
  34. package/dist/index.js +4 -4
  35. package/dist/index.mjs +4 -4
  36. package/dist/middleware/manager.d.ts +1 -1
  37. package/dist/middleware/manager.d.ts.map +1 -1
  38. package/dist/middleware/manager.js.map +1 -1
  39. package/dist/utils/path.d.ts +1 -0
  40. package/dist/utils/path.d.ts.map +1 -1
  41. package/dist/utils/path.js +9 -3
  42. package/dist/utils/path.js.map +1 -1
  43. package/package.json +12 -8
  44. package/src/cache/manager.ts +23 -14
  45. package/src/cli/index.ts +66 -89
  46. package/src/core/config-loader.ts +18 -20
  47. package/src/core/router.ts +52 -18
  48. package/src/core/server.ts +42 -28
  49. package/src/core/vector.ts +25 -35
  50. package/src/dev/route-scanner.ts +41 -47
  51. package/src/http.ts +82 -112
  52. package/src/index.ts +3 -3
  53. package/src/middleware/manager.ts +4 -11
  54. package/src/utils/path.ts +13 -4
@@ -1,3 +1,4 @@
1
1
  export declare function toFileUrl(path: string): string;
2
2
  export declare function normalizePath(path: string): string;
3
+ export declare function buildRouteRegex(path: string): RegExp;
3
4
  //# sourceMappingURL=path.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI9C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD"}
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASpD"}
@@ -1,9 +1,15 @@
1
1
  export function toFileUrl(path) {
2
- return process.platform === 'win32'
3
- ? `file:///${path.replace(/\\/g, '/')}`
4
- : path;
2
+ return process.platform === 'win32' ? `file:///${path.replace(/\\/g, '/')}` : path;
5
3
  }
6
4
  export function normalizePath(path) {
7
5
  return path.replace(/\\/g, '/').replace(/\/+/g, '/');
8
6
  }
7
+ export function buildRouteRegex(path) {
8
+ return RegExp(`^${path
9
+ .replace(/\/+(\/|$)/g, '$1')
10
+ .replace(/(\/?\.?):(\w+)\+/g, '($1(?<$2>[\\s\\S]+))')
11
+ .replace(/(\/?\.?):(\w+)/g, '($1(?<$2>[^$1/]+?))')
12
+ .replace(/\./g, '\\.')
13
+ .replace(/(\/?)\*/g, '($1.*)?')}/*$`);
14
+ }
9
15
  //# sourceMappingURL=path.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"path.js","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO;QACjC,CAAC,CAAC,WAAW,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE;QACvC,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AACvD,CAAC"}
1
+ {"version":3,"file":"path.js","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,MAAM,CACX,IAAI,IAAI;SACL,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC;SAC3B,OAAO,CAAC,mBAAmB,EAAE,sBAAsB,CAAC;SACpD,OAAO,CAAC,iBAAiB,EAAE,qBAAqB,CAAC;SACjD,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,UAAU,EAAE,SAAS,CAAC,KAAK,CACvC,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vector-framework",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "author": "webhie-com",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,6 +12,8 @@
12
12
  "itty-router": "^5.0.0"
13
13
  },
14
14
  "devDependencies": {
15
+ "@biomejs/biome": "^2.4.6",
16
+ "@biomejs/cli-darwin-arm64": "^2.4.6",
15
17
  "@types/bun": "latest",
16
18
  "oxlint": "^1.15.0",
17
19
  "typescript": "^5.0.0"
@@ -94,13 +96,15 @@
94
96
  "test:perf": "bun run test:load && bun run test:soak && bun run test:benchmark",
95
97
  "docker:build": "docker build -t vector:latest .",
96
98
  "docker:build:test": "docker build -t vector:test --target test .",
97
- "docker:run": "docker-compose up",
98
- "docker:run:dev": "docker-compose --profile dev up",
99
- "docker:test": "docker-compose -f docker-compose.test.yml run test-all",
100
- "docker:test:unit": "docker-compose -f docker-compose.test.yml run test-unit",
101
- "docker:test:e2e": "docker-compose -f docker-compose.test.yml run test-e2e",
102
- "docker:test:load": "docker-compose -f docker-compose.test.yml run test-load",
103
- "docker:test:benchmark": "docker-compose -f docker-compose.test.yml run test-benchmark",
99
+ "docker:run": "docker compose up",
100
+ "docker:run:dev": "docker compose --profile dev up",
101
+ "docker:test": "docker compose -f docker-compose.test.yml run test-all",
102
+ "docker:test:unit": "docker compose -f docker-compose.test.yml run test-unit",
103
+ "docker:test:e2e": "docker compose -f docker-compose.test.yml run test-e2e",
104
+ "docker:test:load": "docker compose -f docker-compose.test.yml run test-load",
105
+ "docker:test:benchmark": "docker compose -f docker-compose.test.yml run test-benchmark",
106
+ "format": "biome format --write .",
107
+ "format:check": "biome format .",
104
108
  "lint": "oxlint .",
105
109
  "lint:fix": "oxlint . --fix",
106
110
  "typecheck": "tsc --noEmit",
@@ -1,10 +1,5 @@
1
- import { DEFAULT_CONFIG } from "../constants";
2
- import type {
3
- CacheHandler,
4
- DefaultVectorTypes,
5
- GetCacheType,
6
- VectorTypes,
7
- } from "../types";
1
+ import { DEFAULT_CONFIG } from '../constants';
2
+ import type { CacheHandler, DefaultVectorTypes, GetCacheType, VectorTypes } from '../types';
8
3
 
9
4
  interface CacheEntry<T = any> {
10
5
  value: T;
@@ -15,6 +10,7 @@ export class CacheManager<TTypes extends VectorTypes = DefaultVectorTypes> {
15
10
  private cacheHandler: CacheHandler | null = null;
16
11
  private memoryCache: Map<string, CacheEntry> = new Map();
17
12
  private cleanupInterval: Timer | null = null;
13
+ private inflight: Map<string, Promise<any>> = new Map();
18
14
 
19
15
  setCacheHandler(handler: CacheHandler) {
20
16
  this.cacheHandler = handler;
@@ -48,10 +44,23 @@ export class CacheManager<TTypes extends VectorTypes = DefaultVectorTypes> {
48
44
  return cached!.value as T;
49
45
  }
50
46
 
51
- const value = await factory();
52
- this.setInMemoryCache(key, value, ttl);
47
+ // Deduplicate concurrent requests for the same key (cache stampede prevention)
48
+ if (this.inflight.has(key)) {
49
+ return (await this.inflight.get(key)!) as T;
50
+ }
53
51
 
54
- return value;
52
+ const promise = (async () => {
53
+ const value = await factory();
54
+ this.setInMemoryCache(key, value, ttl);
55
+ return value;
56
+ })();
57
+
58
+ this.inflight.set(key, promise);
59
+ try {
60
+ return await promise;
61
+ } finally {
62
+ this.inflight.delete(key);
63
+ }
55
64
  }
56
65
 
57
66
  private isCacheValid(entry: CacheEntry | undefined, now: number): boolean {
@@ -129,15 +138,15 @@ export class CacheManager<TTypes extends VectorTypes = DefaultVectorTypes> {
129
138
  return true;
130
139
  }
131
140
 
132
- generateKey(request: Request, options?: { authUser?: any }): string {
133
- const url = new URL(request.url);
141
+ generateKey(request: Request & { _parsedUrl?: URL }, options?: { authUser?: any }): string {
142
+ const url = request._parsedUrl ?? new URL(request.url);
134
143
  const parts = [
135
144
  request.method,
136
145
  url.pathname,
137
146
  url.search,
138
- options?.authUser?.id || "anonymous",
147
+ options?.authUser?.id != null ? String(options.authUser.id) : 'anonymous',
139
148
  ];
140
149
 
141
- return parts.join(":");
150
+ return parts.join(':');
142
151
  }
143
152
  }
package/src/cli/index.ts CHANGED
@@ -1,54 +1,53 @@
1
1
  #!/usr/bin/env bun
2
2
 
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";
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
7
 
8
8
  // Compatibility layer for both Node and Bun
9
- const args =
10
- typeof Bun !== "undefined" ? Bun.argv.slice(2) : process.argv.slice(2);
9
+ const args = typeof Bun !== 'undefined' ? Bun.argv.slice(2) : process.argv.slice(2);
11
10
 
12
11
  const { values, positionals } = parseArgs({
13
12
  args,
14
13
  options: {
15
14
  port: {
16
- type: "string",
17
- short: "p",
18
- default: "3000",
15
+ type: 'string',
16
+ short: 'p',
17
+ default: '3000',
19
18
  },
20
19
  host: {
21
- type: "string",
22
- short: "h",
23
- default: "localhost",
20
+ type: 'string',
21
+ short: 'h',
22
+ default: 'localhost',
24
23
  },
25
24
  routes: {
26
- type: "string",
27
- short: "r",
28
- default: "./routes",
25
+ type: 'string',
26
+ short: 'r',
27
+ default: './routes',
29
28
  },
30
29
  watch: {
31
- type: "boolean",
32
- short: "w",
30
+ type: 'boolean',
31
+ short: 'w',
33
32
  default: true,
34
33
  },
35
34
  cors: {
36
- type: "boolean",
35
+ type: 'boolean',
37
36
  default: true,
38
37
  },
39
38
  config: {
40
- type: "string",
41
- short: "c",
39
+ type: 'string',
40
+ short: 'c',
42
41
  },
43
42
  },
44
43
  strict: true,
45
44
  allowPositionals: true,
46
45
  });
47
46
 
48
- const command = positionals[0] || "dev";
47
+ const command = positionals[0] || 'dev';
49
48
 
50
49
  async function runDev() {
51
- const isDev = command === "dev";
50
+ const isDev = command === 'dev';
52
51
 
53
52
  let server: any = null;
54
53
  let vector: any = null;
@@ -57,7 +56,7 @@ async function runDev() {
57
56
  // Create a timeout promise that rejects after 10 seconds
58
57
  const timeoutPromise = new Promise<never>((_, reject) => {
59
58
  setTimeout(() => {
60
- reject(new Error("Server startup timed out (10s)"));
59
+ reject(new Error('Server startup timed out (10s)'));
61
60
  }, 10000);
62
61
  });
63
62
 
@@ -79,11 +78,11 @@ async function runDev() {
79
78
  // Only apply default CORS if config.cors is undefined (not set)
80
79
  if (config.cors === undefined && values.cors) {
81
80
  config.cors = {
82
- origin: "*",
81
+ origin: '*',
83
82
  credentials: true,
84
- allowHeaders: "Content-Type, Authorization",
85
- allowMethods: "GET, POST, PUT, PATCH, DELETE, OPTIONS",
86
- exposeHeaders: "Authorization",
83
+ allowHeaders: 'Content-Type, Authorization',
84
+ allowMethods: 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
85
+ exposeHeaders: 'Authorization',
87
86
  maxAge: 86400,
88
87
  };
89
88
  }
@@ -108,15 +107,13 @@ async function runDev() {
108
107
 
109
108
  // Verify the server is actually running
110
109
  if (!server || !server.port) {
111
- throw new Error("Server started but is not responding correctly");
110
+ throw new Error('Server started but is not responding correctly');
112
111
  }
113
112
 
114
- const cyan = "\x1b[36m";
115
- const reset = "\x1b[0m";
113
+ const cyan = '\x1b[36m';
114
+ const reset = '\x1b[0m';
116
115
 
117
- console.log(
118
- `\nListening on ${cyan}http://${config.hostname}:${config.port}${reset}\n`
119
- );
116
+ console.log(`\nListening on ${cyan}http://${config.hostname}:${config.port}${reset}\n`);
120
117
 
121
118
  return { server, vector, config };
122
119
  })();
@@ -144,17 +141,16 @@ async function runDev() {
144
141
  const now = Date.now();
145
142
  if (isReloading || now - lastReloadTime < 1000) return;
146
143
 
144
+ const segments = filename ? filename.split(/[/\\]/) : [];
145
+ const excluded = segments.some((s) =>
146
+ ['node_modules', '.git', '.vector', 'dist'].includes(s)
147
+ );
147
148
  if (
148
149
  filename &&
149
- (filename.endsWith(".ts") ||
150
- filename.endsWith(".js") ||
151
- filename.endsWith(".json")) &&
152
- !filename.includes("node_modules") &&
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
150
+ (filename.endsWith('.ts') || filename.endsWith('.js') || filename.endsWith('.json')) &&
151
+ !excluded &&
152
+ !filename.includes('bun.lockb') && // Ignore lock files
153
+ !filename.endsWith('.generated.ts') // Ignore generated files
158
154
  ) {
159
155
  // Track changed files
160
156
  changedFiles.add(filename);
@@ -181,24 +177,13 @@ async function runDev() {
181
177
  // Small delay to ensure file system operations complete
182
178
  await new Promise((resolve) => setTimeout(resolve, 100));
183
179
 
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
180
  // Restart the server
196
181
  try {
197
182
  const result = await startServer();
198
183
  server = result.server;
199
184
  vector = result.vector;
200
185
  } catch (error: any) {
201
- console.error("\n[Reload Error]", error.message || error);
186
+ console.error('\n[Reload Error]', error.message || error);
202
187
  // Don't exit the process on reload failures, just continue watching
203
188
  } finally {
204
189
  // Reset flag immediately after reload completes
@@ -209,18 +194,18 @@ async function runDev() {
209
194
  }
210
195
  });
211
196
  } catch {
212
- const yellow = "\x1b[33m";
213
- const reset = "\x1b[0m";
197
+ const yellow = '\x1b[33m';
198
+ const reset = '\x1b[0m';
214
199
  console.warn(`${yellow}Warning: File watching not available${reset}`);
215
200
  }
216
201
  }
217
202
  } catch (error: any) {
218
- const red = "\x1b[31m";
219
- const reset = "\x1b[0m";
203
+ const red = '\x1b[31m';
204
+ const reset = '\x1b[0m';
220
205
 
221
206
  console.error(`\n${red}Error: ${error.message || error}${reset}\n`);
222
207
 
223
- if (error.stack && process.env.NODE_ENV === "development") {
208
+ if (error.stack && process.env.NODE_ENV === 'development') {
224
209
  console.error(error.stack);
225
210
  }
226
211
 
@@ -230,8 +215,8 @@ async function runDev() {
230
215
 
231
216
  async function runBuild() {
232
217
  try {
233
- const { RouteScanner } = await import("../dev/route-scanner");
234
- const { RouteGenerator } = await import("../dev/route-generator");
218
+ const { RouteScanner } = await import('../dev/route-scanner');
219
+ const { RouteGenerator } = await import('../dev/route-generator');
235
220
 
236
221
  // Step 1: Scan and generate routes
237
222
  const scanner = new RouteScanner(values.routes as string);
@@ -241,17 +226,17 @@ async function runBuild() {
241
226
  await generator.generate(routes);
242
227
 
243
228
  // Step 2: Build the application with Bun
244
- if (typeof Bun !== "undefined") {
229
+ if (typeof Bun !== 'undefined') {
245
230
  // Build the CLI as an executable
246
231
  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",
232
+ 'bun',
233
+ 'build',
234
+ 'src/cli/index.ts',
235
+ '--target',
236
+ 'bun',
237
+ '--outfile',
238
+ 'dist/server.js',
239
+ '--minify',
255
240
  ]);
256
241
 
257
242
  const exitCode = await buildProcess.exited;
@@ -260,20 +245,12 @@ async function runBuild() {
260
245
  }
261
246
  } else {
262
247
  // For Node.js, use child_process
263
- const { spawnSync } = await import("child_process");
248
+ const { spawnSync } = await import('child_process');
264
249
  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
- ],
250
+ 'bun',
251
+ ['build', 'src/cli/index.ts', '--target', 'bun', '--outfile', 'dist/server.js', '--minify'],
275
252
  {
276
- stdio: "inherit",
253
+ stdio: 'inherit',
277
254
  shell: true,
278
255
  }
279
256
  );
@@ -283,24 +260,24 @@ async function runBuild() {
283
260
  }
284
261
  }
285
262
 
286
- console.log("\nBuild complete: dist/server.js\n");
263
+ console.log('\nBuild complete: dist/server.js\n');
287
264
  } catch (error: any) {
288
- const red = "\x1b[31m";
289
- const reset = "\x1b[0m";
265
+ const red = '\x1b[31m';
266
+ const reset = '\x1b[0m';
290
267
  console.error(`\n${red}Error: ${error.message || error}${reset}\n`);
291
268
  process.exit(1);
292
269
  }
293
270
  }
294
271
 
295
272
  switch (command) {
296
- case "dev":
273
+ case 'dev':
297
274
  await runDev();
298
275
  break;
299
- case "build":
276
+ case 'build':
300
277
  await runBuild();
301
278
  break;
302
- case "start":
303
- process.env.NODE_ENV = "production";
279
+ case 'start':
280
+ process.env.NODE_ENV = 'production';
304
281
  await runDev();
305
282
  break;
306
283
  default:
@@ -1,6 +1,6 @@
1
- import { existsSync } from "node:fs";
2
- import { resolve, isAbsolute } from "node:path";
3
- import { toFileUrl } from "../utils/path";
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 "../types";
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: "user" | "default" = "default";
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 || "vector.config.ts";
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,12 +32,12 @@ 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 = "user";
35
+ this.configSource = 'user';
38
36
  } catch (error: any) {
39
- const red = "\x1b[31m";
40
- const reset = "\x1b[0m";
37
+ const msg = error instanceof Error ? error.message : String(error);
38
+ console.error(`[Vector] Failed to load config from ${this.configPath}: ${msg}`);
41
39
  console.error(
42
- `${red}Error loading config: ${error.message || error}${reset}`
40
+ '[Vector] Server is using default configuration. Fix your config file and restart.'
43
41
  );
44
42
  this.config = {};
45
43
  }
@@ -52,7 +50,7 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
52
50
  return await this.buildLegacyConfig();
53
51
  }
54
52
 
55
- getConfigSource(): "user" | "default" {
53
+ getConfigSource(): 'user' | 'default' {
56
54
  return this.configSource;
57
55
  }
58
56
 
@@ -65,7 +63,7 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
65
63
  config.hostname = this.config.hostname;
66
64
  config.reusePort = this.config.reusePort;
67
65
  config.development = this.config.development;
68
- config.routesDir = this.config.routesDir || "./routes";
66
+ config.routesDir = this.config.routesDir || './routes';
69
67
  config.idleTimeout = this.config.idleTimeout;
70
68
  }
71
69
 
@@ -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 === "boolean") {
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: "Content-Type, Authorization",
83
- allowMethods: "GET, POST, PUT, PATCH, DELETE, OPTIONS",
84
- exposeHeaders: "Authorization",
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;