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.
- package/README.md +6 -5
- package/dist/cache/manager.d.ts +5 -2
- package/dist/cache/manager.d.ts.map +1 -1
- package/dist/cache/manager.js +21 -7
- package/dist/cache/manager.js.map +1 -1
- package/dist/cli/index.js +62 -83
- package/dist/cli/index.js.map +1 -1
- package/dist/cli.js +108 -37
- 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 +16 -18
- package/dist/core/config-loader.js.map +1 -1
- package/dist/core/router.d.ts +2 -0
- package/dist/core/router.d.ts.map +1 -1
- package/dist/core/router.js +52 -16
- package/dist/core/router.js.map +1 -1
- package/dist/core/server.d.ts +4 -3
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +39 -18
- package/dist/core/server.js.map +1 -1
- package/dist/core/vector.d.ts +7 -7
- package/dist/core/vector.d.ts.map +1 -1
- package/dist/core/vector.js +20 -21
- package/dist/core/vector.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 +40 -42
- package/dist/dev/route-scanner.js.map +1 -1
- package/dist/http.d.ts +2 -2
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +70 -63
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/index.mjs +4 -4
- package/dist/middleware/manager.d.ts +1 -1
- package/dist/middleware/manager.d.ts.map +1 -1
- package/dist/middleware/manager.js.map +1 -1
- package/dist/utils/path.d.ts +1 -0
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js +9 -3
- package/dist/utils/path.js.map +1 -1
- package/package.json +12 -8
- package/src/cache/manager.ts +23 -14
- package/src/cli/index.ts +66 -89
- package/src/core/config-loader.ts +18 -20
- package/src/core/router.ts +52 -18
- package/src/core/server.ts +42 -28
- package/src/core/vector.ts +25 -35
- package/src/dev/route-scanner.ts +41 -47
- package/src/http.ts +82 -112
- package/src/index.ts +3 -3
- package/src/middleware/manager.ts +4 -11
- package/src/utils/path.ts +13 -4
package/dist/utils/path.d.ts
CHANGED
package/dist/utils/path.d.ts.map
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/utils/path.js
CHANGED
|
@@ -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
|
package/dist/utils/path.js.map
CHANGED
|
@@ -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
|
|
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.
|
|
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
|
|
98
|
-
"docker:run:dev": "docker
|
|
99
|
-
"docker:test": "docker
|
|
100
|
-
"docker:test:unit": "docker
|
|
101
|
-
"docker:test:e2e": "docker
|
|
102
|
-
"docker:test:load": "docker
|
|
103
|
-
"docker:test:benchmark": "docker
|
|
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",
|
package/src/cache/manager.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import { DEFAULT_CONFIG } from
|
|
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
|
-
|
|
52
|
-
this.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
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:
|
|
17
|
-
short:
|
|
18
|
-
default:
|
|
15
|
+
type: 'string',
|
|
16
|
+
short: 'p',
|
|
17
|
+
default: '3000',
|
|
19
18
|
},
|
|
20
19
|
host: {
|
|
21
|
-
type:
|
|
22
|
-
short:
|
|
23
|
-
default:
|
|
20
|
+
type: 'string',
|
|
21
|
+
short: 'h',
|
|
22
|
+
default: 'localhost',
|
|
24
23
|
},
|
|
25
24
|
routes: {
|
|
26
|
-
type:
|
|
27
|
-
short:
|
|
28
|
-
default:
|
|
25
|
+
type: 'string',
|
|
26
|
+
short: 'r',
|
|
27
|
+
default: './routes',
|
|
29
28
|
},
|
|
30
29
|
watch: {
|
|
31
|
-
type:
|
|
32
|
-
short:
|
|
30
|
+
type: 'boolean',
|
|
31
|
+
short: 'w',
|
|
33
32
|
default: true,
|
|
34
33
|
},
|
|
35
34
|
cors: {
|
|
36
|
-
type:
|
|
35
|
+
type: 'boolean',
|
|
37
36
|
default: true,
|
|
38
37
|
},
|
|
39
38
|
config: {
|
|
40
|
-
type:
|
|
41
|
-
short:
|
|
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] ||
|
|
47
|
+
const command = positionals[0] || 'dev';
|
|
49
48
|
|
|
50
49
|
async function runDev() {
|
|
51
|
-
const isDev = command ===
|
|
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(
|
|
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:
|
|
85
|
-
allowMethods:
|
|
86
|
-
exposeHeaders:
|
|
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(
|
|
110
|
+
throw new Error('Server started but is not responding correctly');
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
const cyan =
|
|
115
|
-
const reset =
|
|
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(
|
|
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
|
|
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(
|
|
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 =
|
|
213
|
-
const reset =
|
|
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 =
|
|
219
|
-
const reset =
|
|
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 ===
|
|
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(
|
|
234
|
-
const { RouteGenerator } = await import(
|
|
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 !==
|
|
229
|
+
if (typeof Bun !== 'undefined') {
|
|
245
230
|
// Build the CLI as an executable
|
|
246
231
|
const buildProcess = Bun.spawn([
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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(
|
|
248
|
+
const { spawnSync } = await import('child_process');
|
|
264
249
|
const result = spawnSync(
|
|
265
|
-
|
|
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:
|
|
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(
|
|
263
|
+
console.log('\nBuild complete: dist/server.js\n');
|
|
287
264
|
} catch (error: any) {
|
|
288
|
-
const red =
|
|
289
|
-
const reset =
|
|
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
|
|
273
|
+
case 'dev':
|
|
297
274
|
await runDev();
|
|
298
275
|
break;
|
|
299
|
-
case
|
|
276
|
+
case 'build':
|
|
300
277
|
await runBuild();
|
|
301
278
|
break;
|
|
302
|
-
case
|
|
303
|
-
process.env.NODE_ENV =
|
|
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
|
|
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,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 =
|
|
35
|
+
this.configSource = 'user';
|
|
38
36
|
} catch (error: any) {
|
|
39
|
-
const
|
|
40
|
-
|
|
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
|
-
|
|
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():
|
|
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 ||
|
|
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 ===
|
|
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;
|