vector-framework 0.9.9 → 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 +76 -98
- package/dist/cli/index.js.map +1 -1
- package/dist/cli.js +134 -69
- 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 -21
- 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 +40 -20
- 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 +14 -9
- package/src/cache/manager.ts +23 -14
- package/src/cli/index.ts +83 -117
- package/src/core/config-loader.ts +19 -27
- package/src/core/router.ts +52 -18
- package/src/core/server.ts +43 -30
- 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/cli.js
CHANGED
|
@@ -161,7 +161,7 @@ var init_route_scanner = __esm(() => {
|
|
|
161
161
|
isExcluded(filePath) {
|
|
162
162
|
const relativePath = relative2(this.routesDir, filePath);
|
|
163
163
|
for (const pattern of this.excludePatterns) {
|
|
164
|
-
const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, "[^/]*").replace(
|
|
164
|
+
const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "__GLOBSTAR__").replace(/\*/g, "[^/]*").replace(/__GLOBSTAR__/g, ".*").replace(/\?/g, ".");
|
|
165
165
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
166
166
|
const filename = relativePath.split(sep).pop() || "";
|
|
167
167
|
if (regex.test(relativePath) || regex.test(filename)) {
|
|
@@ -351,6 +351,7 @@ class CacheManager {
|
|
|
351
351
|
cacheHandler = null;
|
|
352
352
|
memoryCache = new Map;
|
|
353
353
|
cleanupInterval = null;
|
|
354
|
+
inflight = new Map;
|
|
354
355
|
setCacheHandler(handler) {
|
|
355
356
|
this.cacheHandler = handler;
|
|
356
357
|
}
|
|
@@ -369,9 +370,20 @@ class CacheManager {
|
|
|
369
370
|
if (this.isCacheValid(cached, now)) {
|
|
370
371
|
return cached.value;
|
|
371
372
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
373
|
+
if (this.inflight.has(key)) {
|
|
374
|
+
return await this.inflight.get(key);
|
|
375
|
+
}
|
|
376
|
+
const promise = (async () => {
|
|
377
|
+
const value = await factory();
|
|
378
|
+
this.setInMemoryCache(key, value, ttl);
|
|
379
|
+
return value;
|
|
380
|
+
})();
|
|
381
|
+
this.inflight.set(key, promise);
|
|
382
|
+
try {
|
|
383
|
+
return await promise;
|
|
384
|
+
} finally {
|
|
385
|
+
this.inflight.delete(key);
|
|
386
|
+
}
|
|
375
387
|
}
|
|
376
388
|
isCacheValid(entry, now) {
|
|
377
389
|
return entry !== undefined && entry.expires > now;
|
|
@@ -431,12 +443,12 @@ class CacheManager {
|
|
|
431
443
|
return true;
|
|
432
444
|
}
|
|
433
445
|
generateKey(request, options) {
|
|
434
|
-
const url = new URL(request.url);
|
|
446
|
+
const url = request._parsedUrl ?? new URL(request.url);
|
|
435
447
|
const parts = [
|
|
436
448
|
request.method,
|
|
437
449
|
url.pathname,
|
|
438
450
|
url.search,
|
|
439
|
-
options?.authUser?.id
|
|
451
|
+
options?.authUser?.id != null ? String(options.authUser.id) : "anonymous"
|
|
440
452
|
];
|
|
441
453
|
return parts.join(":");
|
|
442
454
|
}
|
|
@@ -494,6 +506,9 @@ class MiddlewareManager {
|
|
|
494
506
|
function toFileUrl(path) {
|
|
495
507
|
return process.platform === "win32" ? `file:///${path.replace(/\\/g, "/")}` : path;
|
|
496
508
|
}
|
|
509
|
+
function buildRouteRegex(path) {
|
|
510
|
+
return RegExp(`^${path.replace(/\/+(\/|$)/g, "$1").replace(/(\/?\.?):(\w+)\+/g, "($1(?<$2>[\\s\\S]+))").replace(/(\/?\.?):(\w+)/g, "($1(?<$2>[^$1/]+?))").replace(/\./g, "\\.").replace(/(\/?)\*/g, "($1.*)?")}/*$`);
|
|
511
|
+
}
|
|
497
512
|
|
|
498
513
|
// node_modules/itty-router/index.mjs
|
|
499
514
|
var r = (e = "text/plain; charset=utf-8", t) => (r2, o = {}) => {
|
|
@@ -508,9 +523,6 @@ var f = r("text/html");
|
|
|
508
523
|
var u = r("image/jpeg");
|
|
509
524
|
var h = r("image/png");
|
|
510
525
|
var g = r("image/webp");
|
|
511
|
-
var w = (e) => {
|
|
512
|
-
e.cookies = (e.headers.get("Cookie") || "").split(/;\s*/).map((e2) => e2.split(/=(.+)/)).reduce((e2, [t, r2]) => r2 ? (e2[t] = r2, e2) : e2, {});
|
|
513
|
-
};
|
|
514
526
|
var y = (e = {}) => {
|
|
515
527
|
const { origin: t = "*", credentials: r2 = false, allowMethods: o2 = "*", allowHeaders: a, exposeHeaders: s, maxAge: c } = e, n = (e2) => {
|
|
516
528
|
const o3 = e2?.headers.get("origin");
|
|
@@ -537,8 +549,22 @@ var { preflight, corsify } = y({
|
|
|
537
549
|
exposeHeaders: "Authorization",
|
|
538
550
|
maxAge: 86400
|
|
539
551
|
});
|
|
552
|
+
function hasBigInt(value, depth = 0) {
|
|
553
|
+
if (typeof value === "bigint")
|
|
554
|
+
return true;
|
|
555
|
+
if (depth > 4 || value === null || typeof value !== "object")
|
|
556
|
+
return false;
|
|
557
|
+
for (const v of Object.values(value)) {
|
|
558
|
+
if (hasBigInt(v, depth + 1))
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
540
563
|
function stringifyData(data) {
|
|
541
|
-
|
|
564
|
+
const val = data ?? null;
|
|
565
|
+
if (!hasBigInt(val))
|
|
566
|
+
return JSON.stringify(val);
|
|
567
|
+
return JSON.stringify(val, (_key, value) => typeof value === "bigint" ? value.toString() : value);
|
|
542
568
|
}
|
|
543
569
|
function createErrorResponse(code, message, contentType) {
|
|
544
570
|
const errorBody = {
|
|
@@ -608,12 +634,16 @@ class VectorRouter {
|
|
|
608
634
|
authManager;
|
|
609
635
|
cacheManager;
|
|
610
636
|
routes = [];
|
|
637
|
+
specificityCache = new Map;
|
|
611
638
|
constructor(middlewareManager, authManager, cacheManager) {
|
|
612
639
|
this.middlewareManager = middlewareManager;
|
|
613
640
|
this.authManager = authManager;
|
|
614
641
|
this.cacheManager = cacheManager;
|
|
615
642
|
}
|
|
616
643
|
getRouteSpecificity(path) {
|
|
644
|
+
const cached = this.specificityCache.get(path);
|
|
645
|
+
if (cached !== undefined)
|
|
646
|
+
return cached;
|
|
617
647
|
const STATIC_SEGMENT_WEIGHT = 1000;
|
|
618
648
|
const PARAM_SEGMENT_WEIGHT = 10;
|
|
619
649
|
const WILDCARD_WEIGHT = 1;
|
|
@@ -633,6 +663,7 @@ class VectorRouter {
|
|
|
633
663
|
if (this.isExactPath(path)) {
|
|
634
664
|
score += EXACT_MATCH_BONUS;
|
|
635
665
|
}
|
|
666
|
+
this.specificityCache.set(path, score);
|
|
636
667
|
return score;
|
|
637
668
|
}
|
|
638
669
|
isStaticSegment(segment) {
|
|
@@ -673,7 +704,7 @@ class VectorRouter {
|
|
|
673
704
|
return routeEntry;
|
|
674
705
|
}
|
|
675
706
|
createRouteRegex(path) {
|
|
676
|
-
return
|
|
707
|
+
return buildRouteRegex(path);
|
|
677
708
|
}
|
|
678
709
|
prepareRequest(request, options) {
|
|
679
710
|
if (!request.context) {
|
|
@@ -689,7 +720,7 @@ class VectorRouter {
|
|
|
689
720
|
request.metadata = options.metadata;
|
|
690
721
|
}
|
|
691
722
|
if (!request.query && request.url) {
|
|
692
|
-
const url = new URL(request.url);
|
|
723
|
+
const url = request._parsedUrl ?? new URL(request.url);
|
|
693
724
|
const query = {};
|
|
694
725
|
for (const [key, value] of url.searchParams) {
|
|
695
726
|
if (key in query) {
|
|
@@ -704,8 +735,30 @@ class VectorRouter {
|
|
|
704
735
|
}
|
|
705
736
|
request.query = query;
|
|
706
737
|
}
|
|
707
|
-
if (!request
|
|
708
|
-
|
|
738
|
+
if (!Object.getOwnPropertyDescriptor(request, "cookies")) {
|
|
739
|
+
Object.defineProperty(request, "cookies", {
|
|
740
|
+
get() {
|
|
741
|
+
const cookieHeader = this.headers.get("cookie") ?? "";
|
|
742
|
+
const cookies = {};
|
|
743
|
+
if (cookieHeader) {
|
|
744
|
+
for (const pair of cookieHeader.split(";")) {
|
|
745
|
+
const idx = pair.indexOf("=");
|
|
746
|
+
if (idx > 0) {
|
|
747
|
+
cookies[pair.slice(0, idx).trim()] = pair.slice(idx + 1).trim();
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
Object.defineProperty(this, "cookies", {
|
|
752
|
+
value: cookies,
|
|
753
|
+
writable: true,
|
|
754
|
+
configurable: true,
|
|
755
|
+
enumerable: true
|
|
756
|
+
});
|
|
757
|
+
return cookies;
|
|
758
|
+
},
|
|
759
|
+
configurable: true,
|
|
760
|
+
enumerable: true
|
|
761
|
+
});
|
|
709
762
|
}
|
|
710
763
|
}
|
|
711
764
|
wrapHandler(options, handler) {
|
|
@@ -801,11 +854,23 @@ class VectorRouter {
|
|
|
801
854
|
this.routes.push(routeEntry);
|
|
802
855
|
this.sortRoutes();
|
|
803
856
|
}
|
|
857
|
+
bulkAddRoutes(entries) {
|
|
858
|
+
for (const entry of entries) {
|
|
859
|
+
this.routes.push(entry);
|
|
860
|
+
}
|
|
861
|
+
this.sortRoutes();
|
|
862
|
+
}
|
|
804
863
|
getRoutes() {
|
|
805
864
|
return this.routes;
|
|
806
865
|
}
|
|
807
866
|
async handle(request) {
|
|
808
|
-
|
|
867
|
+
let url;
|
|
868
|
+
try {
|
|
869
|
+
url = new URL(request.url);
|
|
870
|
+
} catch {
|
|
871
|
+
return APIError.badRequest("Malformed request URL");
|
|
872
|
+
}
|
|
873
|
+
request._parsedUrl = url;
|
|
809
874
|
const pathname = url.pathname;
|
|
810
875
|
for (const [method, regex, handlers, path] of this.routes) {
|
|
811
876
|
if (request.method === "OPTIONS" || request.method === method) {
|
|
@@ -828,6 +893,7 @@ class VectorRouter {
|
|
|
828
893
|
}
|
|
829
894
|
clearRoutes() {
|
|
830
895
|
this.routes = [];
|
|
896
|
+
this.specificityCache.clear();
|
|
831
897
|
}
|
|
832
898
|
}
|
|
833
899
|
|
|
@@ -837,12 +903,26 @@ class VectorServer {
|
|
|
837
903
|
router;
|
|
838
904
|
config;
|
|
839
905
|
corsHandler;
|
|
906
|
+
corsHeaders = null;
|
|
840
907
|
constructor(router, config) {
|
|
841
908
|
this.router = router;
|
|
842
909
|
this.config = config;
|
|
843
910
|
if (config.cors) {
|
|
844
|
-
const
|
|
911
|
+
const opts = this.normalizeCorsOptions(config.cors);
|
|
912
|
+
const { preflight: preflight2, corsify: corsify2 } = y(opts);
|
|
845
913
|
this.corsHandler = { preflight: preflight2, corsify: corsify2 };
|
|
914
|
+
if (typeof opts.origin === "string") {
|
|
915
|
+
this.corsHeaders = {
|
|
916
|
+
"access-control-allow-origin": opts.origin,
|
|
917
|
+
"access-control-allow-methods": opts.allowMethods,
|
|
918
|
+
"access-control-allow-headers": opts.allowHeaders,
|
|
919
|
+
"access-control-expose-headers": opts.exposeHeaders,
|
|
920
|
+
"access-control-max-age": String(opts.maxAge)
|
|
921
|
+
};
|
|
922
|
+
if (opts.credentials) {
|
|
923
|
+
this.corsHeaders["access-control-allow-credentials"] = "true";
|
|
924
|
+
}
|
|
925
|
+
}
|
|
846
926
|
}
|
|
847
927
|
}
|
|
848
928
|
normalizeCorsOptions(options) {
|
|
@@ -864,7 +944,11 @@ class VectorServer {
|
|
|
864
944
|
return this.corsHandler.preflight(request);
|
|
865
945
|
}
|
|
866
946
|
let response = await this.router.handle(request);
|
|
867
|
-
if (this.
|
|
947
|
+
if (this.corsHeaders) {
|
|
948
|
+
for (const [k, v] of Object.entries(this.corsHeaders)) {
|
|
949
|
+
response.headers.set(k, v);
|
|
950
|
+
}
|
|
951
|
+
} else if (this.corsHandler) {
|
|
868
952
|
response = this.corsHandler.corsify(response, request);
|
|
869
953
|
}
|
|
870
954
|
return response;
|
|
@@ -888,7 +972,6 @@ class VectorServer {
|
|
|
888
972
|
if (!this.server || !this.server.port) {
|
|
889
973
|
throw new Error(`Failed to start server on ${hostname}:${port} - server object is invalid`);
|
|
890
974
|
}
|
|
891
|
-
console.log(`\u2192 Vector server running at http://${hostname}:${port}`);
|
|
892
975
|
return this.server;
|
|
893
976
|
} catch (error) {
|
|
894
977
|
if (error.code === "EADDRINUSE" || error.message?.includes("address already in use")) {
|
|
@@ -1093,20 +1176,17 @@ class ConfigLoader {
|
|
|
1093
1176
|
async load() {
|
|
1094
1177
|
if (existsSync2(this.configPath)) {
|
|
1095
1178
|
try {
|
|
1096
|
-
console.log(`\u2192 Loading config from: ${this.configPath}`);
|
|
1097
1179
|
const userConfigPath = toFileUrl(this.configPath);
|
|
1098
1180
|
const userConfig = await import(userConfigPath);
|
|
1099
1181
|
this.config = userConfig.default || userConfig;
|
|
1100
1182
|
this.configSource = "user";
|
|
1101
|
-
console.log(" \u2713 User config loaded successfully");
|
|
1102
1183
|
} catch (error) {
|
|
1103
|
-
|
|
1104
|
-
console.
|
|
1184
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1185
|
+
console.error(`[Vector] Failed to load config from ${this.configPath}: ${msg}`);
|
|
1186
|
+
console.error("[Vector] Server is using default configuration. Fix your config file and restart.");
|
|
1105
1187
|
this.config = {};
|
|
1106
1188
|
}
|
|
1107
1189
|
} else {
|
|
1108
|
-
console.log(` \u2192 No config file found at: ${this.configPath}`);
|
|
1109
|
-
console.log(" \u2192 Using default configuration");
|
|
1110
1190
|
this.config = {};
|
|
1111
1191
|
}
|
|
1112
1192
|
return await this.buildLegacyConfig();
|
|
@@ -1198,9 +1278,6 @@ var { values, positionals } = parseArgs({
|
|
|
1198
1278
|
var command = positionals[0] || "dev";
|
|
1199
1279
|
async function runDev() {
|
|
1200
1280
|
const isDev = command === "dev";
|
|
1201
|
-
console.log(`
|
|
1202
|
-
\u2192 Starting Vector ${isDev ? "development" : "production"} server
|
|
1203
|
-
`);
|
|
1204
1281
|
let server = null;
|
|
1205
1282
|
let vector = null;
|
|
1206
1283
|
async function startServer() {
|
|
@@ -1212,7 +1289,6 @@ async function runDev() {
|
|
|
1212
1289
|
const serverStartPromise = (async () => {
|
|
1213
1290
|
const configLoader = new ConfigLoader(values.config);
|
|
1214
1291
|
const config = await configLoader.load();
|
|
1215
|
-
const configSource = configLoader.getConfigSource();
|
|
1216
1292
|
config.port = config.port ?? Number.parseInt(values.port);
|
|
1217
1293
|
config.hostname = config.hostname ?? values.host;
|
|
1218
1294
|
config.routesDir = config.routesDir ?? values.routes;
|
|
@@ -1241,19 +1317,10 @@ async function runDev() {
|
|
|
1241
1317
|
if (!server || !server.port) {
|
|
1242
1318
|
throw new Error("Server started but is not responding correctly");
|
|
1243
1319
|
}
|
|
1244
|
-
const gray = "\x1B[90m";
|
|
1245
|
-
const reset = "\x1B[0m";
|
|
1246
1320
|
const cyan = "\x1B[36m";
|
|
1247
|
-
const
|
|
1248
|
-
console.log(`
|
|
1249
|
-
|
|
1250
|
-
if (isDev && values.watch) {
|
|
1251
|
-
console.log(` ${gray}Watching${reset} All project files`);
|
|
1252
|
-
}
|
|
1253
|
-
console.log(` ${gray}CORS${reset} ${config.cors ? "Enabled" : "Disabled"}`);
|
|
1254
|
-
console.log(` ${gray}Mode${reset} ${config.development ? "Development" : "Production"}
|
|
1255
|
-
`);
|
|
1256
|
-
console.log(` ${green}Ready${reset} \u2192 ${cyan}http://${config.hostname}:${config.port}${reset}
|
|
1321
|
+
const reset = "\x1B[0m";
|
|
1322
|
+
console.log(`
|
|
1323
|
+
Listening on ${cyan}http://${config.hostname}:${config.port}${reset}
|
|
1257
1324
|
`);
|
|
1258
1325
|
return { server, vector, config };
|
|
1259
1326
|
})();
|
|
@@ -1272,7 +1339,9 @@ async function runDev() {
|
|
|
1272
1339
|
const now = Date.now();
|
|
1273
1340
|
if (isReloading || now - lastReloadTime < 1000)
|
|
1274
1341
|
return;
|
|
1275
|
-
|
|
1342
|
+
const segments = filename ? filename.split(/[/\\]/) : [];
|
|
1343
|
+
const excluded = segments.some((s) => ["node_modules", ".git", ".vector", "dist"].includes(s));
|
|
1344
|
+
if (filename && (filename.endsWith(".ts") || filename.endsWith(".js") || filename.endsWith(".json")) && !excluded && !filename.includes("bun.lockb") && !filename.endsWith(".generated.ts")) {
|
|
1276
1345
|
changedFiles.add(filename);
|
|
1277
1346
|
if (reloadTimeout) {
|
|
1278
1347
|
clearTimeout(reloadTimeout);
|
|
@@ -1287,13 +1356,6 @@ async function runDev() {
|
|
|
1287
1356
|
vector.stop();
|
|
1288
1357
|
}
|
|
1289
1358
|
await new Promise((resolve3) => setTimeout(resolve3, 100));
|
|
1290
|
-
if (__require.cache) {
|
|
1291
|
-
for (const key in __require.cache) {
|
|
1292
|
-
if (!key.includes("node_modules")) {
|
|
1293
|
-
delete __require.cache[key];
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
1359
|
try {
|
|
1298
1360
|
const result2 = await startServer();
|
|
1299
1361
|
server = result2.server;
|
|
@@ -1308,32 +1370,24 @@ async function runDev() {
|
|
|
1308
1370
|
}
|
|
1309
1371
|
});
|
|
1310
1372
|
} catch {
|
|
1311
|
-
|
|
1373
|
+
const yellow = "\x1B[33m";
|
|
1374
|
+
const reset = "\x1B[0m";
|
|
1375
|
+
console.warn(`${yellow}Warning: File watching not available${reset}`);
|
|
1312
1376
|
}
|
|
1313
1377
|
}
|
|
1314
1378
|
} catch (error) {
|
|
1315
1379
|
const red = "\x1B[31m";
|
|
1316
1380
|
const reset = "\x1B[0m";
|
|
1317
1381
|
console.error(`
|
|
1318
|
-
${red}
|
|
1382
|
+
${red}Error: ${error.message || error}${reset}
|
|
1319
1383
|
`);
|
|
1320
|
-
if (error.
|
|
1321
|
-
console.error(`Message: ${error.message}`);
|
|
1322
|
-
}
|
|
1323
|
-
if (error.stack) {
|
|
1324
|
-
console.error(`
|
|
1325
|
-
Stack trace:`);
|
|
1384
|
+
if (error.stack && true) {
|
|
1326
1385
|
console.error(error.stack);
|
|
1327
|
-
} else if (!error.message) {
|
|
1328
|
-
console.error(`Raw error:`, error);
|
|
1329
1386
|
}
|
|
1330
1387
|
process.exit(1);
|
|
1331
1388
|
}
|
|
1332
1389
|
}
|
|
1333
1390
|
async function runBuild() {
|
|
1334
|
-
console.log(`
|
|
1335
|
-
\u2192 Building Vector application
|
|
1336
|
-
`);
|
|
1337
1391
|
try {
|
|
1338
1392
|
const { RouteScanner: RouteScanner2 } = await Promise.resolve().then(() => (init_route_scanner(), exports_route_scanner));
|
|
1339
1393
|
const { RouteGenerator: RouteGenerator2 } = await Promise.resolve().then(() => (init_route_generator(), exports_route_generator));
|
|
@@ -1341,29 +1395,40 @@ async function runBuild() {
|
|
|
1341
1395
|
const generator = new RouteGenerator2;
|
|
1342
1396
|
const routes = await scanner.scan();
|
|
1343
1397
|
await generator.generate(routes);
|
|
1344
|
-
console.log(` Generated ${routes.length} routes`);
|
|
1345
1398
|
if (typeof Bun !== "undefined") {
|
|
1346
1399
|
const buildProcess = Bun.spawn([
|
|
1347
1400
|
"bun",
|
|
1348
1401
|
"build",
|
|
1349
|
-
"src/index.ts",
|
|
1350
|
-
"--
|
|
1351
|
-
"
|
|
1402
|
+
"src/cli/index.ts",
|
|
1403
|
+
"--target",
|
|
1404
|
+
"bun",
|
|
1405
|
+
"--outfile",
|
|
1406
|
+
"dist/server.js",
|
|
1352
1407
|
"--minify"
|
|
1353
1408
|
]);
|
|
1354
|
-
await buildProcess.exited;
|
|
1409
|
+
const exitCode = await buildProcess.exited;
|
|
1410
|
+
if (exitCode !== 0) {
|
|
1411
|
+
throw new Error(`Build failed with exit code ${exitCode}`);
|
|
1412
|
+
}
|
|
1355
1413
|
} else {
|
|
1356
1414
|
const { spawnSync } = await import("child_process");
|
|
1357
|
-
spawnSync("bun", ["build", "src/index.ts", "--
|
|
1415
|
+
const result = spawnSync("bun", ["build", "src/cli/index.ts", "--target", "bun", "--outfile", "dist/server.js", "--minify"], {
|
|
1358
1416
|
stdio: "inherit",
|
|
1359
1417
|
shell: true
|
|
1360
1418
|
});
|
|
1419
|
+
if (result.status !== 0) {
|
|
1420
|
+
throw new Error(`Build failed with exit code ${result.status}`);
|
|
1421
|
+
}
|
|
1361
1422
|
}
|
|
1362
1423
|
console.log(`
|
|
1363
|
-
|
|
1424
|
+
Build complete: dist/server.js
|
|
1364
1425
|
`);
|
|
1365
1426
|
} catch (error) {
|
|
1366
|
-
|
|
1427
|
+
const red = "\x1B[31m";
|
|
1428
|
+
const reset = "\x1B[0m";
|
|
1429
|
+
console.error(`
|
|
1430
|
+
${red}Error: ${error.message || error}${reset}
|
|
1431
|
+
`);
|
|
1367
1432
|
process.exit(1);
|
|
1368
1433
|
}
|
|
1369
1434
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { CacheHandler, DefaultVectorTypes, ProtectedHandler, VectorConfig, VectorConfigSchema, VectorTypes } from
|
|
1
|
+
import type { CacheHandler, DefaultVectorTypes, ProtectedHandler, VectorConfig, VectorConfigSchema, VectorTypes } from '../types';
|
|
2
2
|
export declare class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
3
3
|
private configPath;
|
|
4
4
|
private config;
|
|
5
5
|
private configSource;
|
|
6
6
|
constructor(configPath?: string);
|
|
7
7
|
load(): Promise<VectorConfig<TTypes>>;
|
|
8
|
-
getConfigSource():
|
|
8
|
+
getConfigSource(): 'user' | 'default';
|
|
9
9
|
private buildLegacyConfig;
|
|
10
10
|
loadAuthHandler(): Promise<ProtectedHandler<TTypes> | null>;
|
|
11
11
|
loadCacheHandler(): Promise<CacheHandler | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/core/config-loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,YAAY,EAEZ,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACZ,MAAM,UAAU,CAAC;AAElB,qBAAa,YAAY,CAAC,MAAM,SAAS,WAAW,GAAG,kBAAkB;IACvE,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAA2C;IACzD,OAAO,CAAC,YAAY,CAAiC;gBAEzC,UAAU,CAAC,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/core/config-loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,YAAY,EAEZ,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACZ,MAAM,UAAU,CAAC;AAElB,qBAAa,YAAY,CAAC,MAAM,SAAS,WAAW,GAAG,kBAAkB;IACvE,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAA2C;IACzD,OAAO,CAAC,YAAY,CAAiC;gBAEzC,UAAU,CAAC,EAAE,MAAM;IAQzB,IAAI,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IA0B3C,eAAe,IAAI,MAAM,GAAG,SAAS;YAIvB,iBAAiB;IA8CzB,eAAe,IAAI,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAI3D,gBAAgB,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAItD,SAAS,IAAI,kBAAkB,CAAC,MAAM,CAAC,GAAG,IAAI;CAG/C"}
|
|
@@ -1,40 +1,35 @@
|
|
|
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
|
export class ConfigLoader {
|
|
5
5
|
configPath;
|
|
6
6
|
config = null;
|
|
7
|
-
configSource =
|
|
7
|
+
configSource = 'default';
|
|
8
8
|
constructor(configPath) {
|
|
9
9
|
// Use provided config path or default to vector.config.ts
|
|
10
|
-
const path = configPath ||
|
|
10
|
+
const path = configPath || 'vector.config.ts';
|
|
11
11
|
// Handle absolute vs relative paths
|
|
12
|
-
this.configPath = isAbsolute(path)
|
|
13
|
-
? path
|
|
14
|
-
: resolve(process.cwd(), path);
|
|
12
|
+
this.configPath = isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
15
13
|
}
|
|
16
14
|
async load() {
|
|
17
15
|
// Check if config file exists before attempting to load
|
|
18
16
|
if (existsSync(this.configPath)) {
|
|
19
17
|
try {
|
|
20
|
-
console.log(`→ Loading config from: ${this.configPath}`);
|
|
21
18
|
// Use explicit file:// URL to ensure correct resolution
|
|
22
19
|
const userConfigPath = toFileUrl(this.configPath);
|
|
23
20
|
const userConfig = await import(userConfigPath);
|
|
24
21
|
this.config = userConfig.default || userConfig;
|
|
25
|
-
this.configSource =
|
|
26
|
-
console.log(" ✓ User config loaded successfully");
|
|
22
|
+
this.configSource = 'user';
|
|
27
23
|
}
|
|
28
24
|
catch (error) {
|
|
29
|
-
|
|
30
|
-
console.
|
|
25
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
26
|
+
console.error(`[Vector] Failed to load config from ${this.configPath}: ${msg}`);
|
|
27
|
+
console.error('[Vector] Server is using default configuration. Fix your config file and restart.');
|
|
31
28
|
this.config = {};
|
|
32
29
|
}
|
|
33
30
|
}
|
|
34
31
|
else {
|
|
35
32
|
// Config file doesn't exist, use defaults
|
|
36
|
-
console.log(` → No config file found at: ${this.configPath}`);
|
|
37
|
-
console.log(" → Using default configuration");
|
|
38
33
|
this.config = {};
|
|
39
34
|
}
|
|
40
35
|
// Convert new config schema to legacy VectorConfig format
|
|
@@ -51,21 +46,21 @@ export class ConfigLoader {
|
|
|
51
46
|
config.hostname = this.config.hostname;
|
|
52
47
|
config.reusePort = this.config.reusePort;
|
|
53
48
|
config.development = this.config.development;
|
|
54
|
-
config.routesDir = this.config.routesDir ||
|
|
49
|
+
config.routesDir = this.config.routesDir || './routes';
|
|
55
50
|
config.idleTimeout = this.config.idleTimeout;
|
|
56
51
|
}
|
|
57
52
|
// Always auto-discover routes
|
|
58
53
|
config.autoDiscover = true;
|
|
59
54
|
// CORS configuration
|
|
60
55
|
if (this.config?.cors) {
|
|
61
|
-
if (typeof this.config.cors ===
|
|
56
|
+
if (typeof this.config.cors === 'boolean') {
|
|
62
57
|
config.cors = this.config.cors
|
|
63
58
|
? {
|
|
64
|
-
origin:
|
|
59
|
+
origin: '*',
|
|
65
60
|
credentials: true,
|
|
66
|
-
allowHeaders:
|
|
67
|
-
allowMethods:
|
|
68
|
-
exposeHeaders:
|
|
61
|
+
allowHeaders: 'Content-Type, Authorization',
|
|
62
|
+
allowMethods: 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
|
|
63
|
+
exposeHeaders: 'Authorization',
|
|
69
64
|
maxAge: 86400,
|
|
70
65
|
}
|
|
71
66
|
: undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/core/config-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAW1C,MAAM,OAAO,YAAY;IACf,UAAU,CAAS;IACnB,MAAM,GAAsC,IAAI,CAAC;IACjD,YAAY,GAAuB,SAAS,CAAC;IAErD,YAAY,UAAmB;QAC7B,0DAA0D;QAC1D,MAAM,IAAI,GAAG,UAAU,IAAI,kBAAkB,CAAC;QAE9C,oCAAoC;QACpC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC
|
|
1
|
+
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/core/config-loader.ts"],"names":[],"mappings":"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"}
|
package/dist/core/router.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare class VectorRouter<TTypes extends VectorTypes = DefaultVectorType
|
|
|
8
8
|
private authManager;
|
|
9
9
|
private cacheManager;
|
|
10
10
|
private routes;
|
|
11
|
+
private specificityCache;
|
|
11
12
|
constructor(middlewareManager: MiddlewareManager<TTypes>, authManager: AuthManager<TTypes>, cacheManager: CacheManager<TTypes>);
|
|
12
13
|
private getRouteSpecificity;
|
|
13
14
|
private isStaticSegment;
|
|
@@ -21,6 +22,7 @@ export declare class VectorRouter<TTypes extends VectorTypes = DefaultVectorType
|
|
|
21
22
|
private prepareRequest;
|
|
22
23
|
private wrapHandler;
|
|
23
24
|
addRoute(routeEntry: RouteEntry): void;
|
|
25
|
+
bulkAddRoutes(entries: RouteEntry[]): void;
|
|
24
26
|
getRoutes(): RouteEntry[];
|
|
25
27
|
handle(request: Request): Promise<Response>;
|
|
26
28
|
clearRoutes(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/core/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/core/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,YAAY,EAEZ,WAAW,EACZ,MAAM,UAAU,CAAC;AAGlB,qBAAa,YAAY,CAAC,MAAM,SAAS,WAAW,GAAG,kBAAkB;IACvE,OAAO,CAAC,iBAAiB,CAA4B;IACrD,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,gBAAgB,CAAkC;gBAGxD,iBAAiB,EAAE,iBAAiB,CAAC,MAAM,CAAC,EAC5C,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,YAAY,EAAE,YAAY,CAAC,MAAM,CAAC;IAOpC,OAAO,CAAC,mBAAmB;IAgC3B,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,WAAW;IAInB,UAAU,IAAI,IAAI;IAYlB,OAAO,CAAC,WAAW;IAKnB,KAAK,CAAC,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,GAAG,UAAU;IAc/E,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,cAAc;IAsEtB,OAAO,CAAC,WAAW;IAqHnB,QAAQ,CAAC,UAAU,EAAE,UAAU;IAK/B,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI;IAO1C,SAAS,IAAI,UAAU,EAAE;IAInB,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAiCjD,WAAW,IAAI,IAAI;CAIpB"}
|