vector-framework 1.1.1 → 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 -635
- package/dist/auth/protected.d.ts.map +1 -1
- package/dist/auth/protected.js.map +1 -1
- package/dist/cache/manager.d.ts.map +1 -1
- package/dist/cache/manager.js +2 -7
- package/dist/cache/manager.js.map +1 -1
- package/dist/cli/index.js +17 -62
- 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 +2721 -617
- 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.map +1 -1
- package/dist/core/config-loader.js +2 -0
- package/dist/core/config-loader.js.map +1 -1
- package/dist/core/router.d.ts +41 -17
- package/dist/core/router.d.ts.map +1 -1
- package/dist/core/router.js +432 -153
- package/dist/core/router.js.map +1 -1
- package/dist/core/server.d.ts +14 -1
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +250 -30
- package/dist/core/server.js.map +1 -1
- package/dist/core/vector.d.ts +4 -3
- package/dist/core/vector.d.ts.map +1 -1
- package/dist/core/vector.js +21 -12
- 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.map +1 -1
- package/dist/dev/route-scanner.js +1 -5
- 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 +34 -41
- package/dist/http.js.map +1 -1
- package/dist/index.js +1314 -8
- package/dist/index.mjs +1314 -8
- 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 +6 -0
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js +5 -0
- 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 +13 -12
- package/src/auth/protected.ts +3 -13
- package/src/cache/manager.ts +4 -18
- package/src/cli/index.ts +19 -75
- package/src/cli/option-resolution.ts +40 -0
- package/src/constants/index.ts +7 -0
- package/src/core/config-loader.ts +3 -3
- package/src/core/router.ts +502 -156
- package/src/core/server.ts +327 -32
- package/src/core/vector.ts +49 -29
- package/src/dev/route-generator.ts +1 -3
- package/src/dev/route-scanner.ts +2 -9
- package/src/http.ts +85 -125
- package/src/middleware/manager.ts +4 -0
- 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 +6 -0
- package/src/utils/schema-validation.ts +123 -0
- package/src/utils/validation.ts +1 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
function getAllowedOrigin(origin, config) {
|
|
2
|
+
if (!origin) {
|
|
3
|
+
if (typeof config.origin === 'string') {
|
|
4
|
+
// Credentials cannot be combined with wildcard; only reflect concrete request origins.
|
|
5
|
+
if (config.origin === '*' && config.credentials)
|
|
6
|
+
return null;
|
|
7
|
+
return config.origin;
|
|
8
|
+
}
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
if (typeof config.origin === 'string') {
|
|
12
|
+
if (config.origin === '*') {
|
|
13
|
+
return config.credentials ? origin : '*';
|
|
14
|
+
}
|
|
15
|
+
return config.origin === origin ? origin : null;
|
|
16
|
+
}
|
|
17
|
+
if (Array.isArray(config.origin)) {
|
|
18
|
+
return config.origin.includes(origin) ? origin : null;
|
|
19
|
+
}
|
|
20
|
+
if (typeof config.origin === 'function') {
|
|
21
|
+
return config.origin(origin) ? origin : null;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
function shouldVaryByOrigin(config) {
|
|
26
|
+
return ((typeof config.origin === 'string' && config.origin === '*' && config.credentials) ||
|
|
27
|
+
Array.isArray(config.origin) ||
|
|
28
|
+
typeof config.origin === 'function');
|
|
29
|
+
}
|
|
30
|
+
function buildCorsHeaders(origin, config, varyByOrigin) {
|
|
31
|
+
const headers = {};
|
|
32
|
+
if (origin) {
|
|
33
|
+
headers['access-control-allow-origin'] = origin;
|
|
34
|
+
headers['access-control-allow-methods'] = config.allowMethods;
|
|
35
|
+
headers['access-control-allow-headers'] = config.allowHeaders;
|
|
36
|
+
headers['access-control-expose-headers'] = config.exposeHeaders;
|
|
37
|
+
headers['access-control-max-age'] = String(config.maxAge);
|
|
38
|
+
if (config.credentials) {
|
|
39
|
+
headers['access-control-allow-credentials'] = 'true';
|
|
40
|
+
}
|
|
41
|
+
if (varyByOrigin) {
|
|
42
|
+
headers.vary = 'Origin';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return headers;
|
|
46
|
+
}
|
|
47
|
+
function mergeVary(existing, nextValue) {
|
|
48
|
+
if (!existing)
|
|
49
|
+
return nextValue;
|
|
50
|
+
const parts = existing
|
|
51
|
+
.split(',')
|
|
52
|
+
.map((v) => v.trim())
|
|
53
|
+
.filter(Boolean);
|
|
54
|
+
const lower = parts.map((v) => v.toLowerCase());
|
|
55
|
+
if (!lower.includes(nextValue.toLowerCase())) {
|
|
56
|
+
parts.push(nextValue);
|
|
57
|
+
}
|
|
58
|
+
return parts.join(', ');
|
|
59
|
+
}
|
|
60
|
+
export function cors(config) {
|
|
61
|
+
return {
|
|
62
|
+
preflight(request) {
|
|
63
|
+
const origin = request.headers.get('origin') ?? undefined;
|
|
64
|
+
const allowed = getAllowedOrigin(origin, config);
|
|
65
|
+
const varyByOrigin = Boolean(origin && allowed && shouldVaryByOrigin(config));
|
|
66
|
+
return new Response(null, {
|
|
67
|
+
status: 204,
|
|
68
|
+
headers: buildCorsHeaders(allowed, config, varyByOrigin),
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
corsify(response, request) {
|
|
72
|
+
const origin = request.headers.get('origin') ?? undefined;
|
|
73
|
+
const allowed = getAllowedOrigin(origin, config);
|
|
74
|
+
if (!allowed)
|
|
75
|
+
return response;
|
|
76
|
+
const varyByOrigin = Boolean(origin && shouldVaryByOrigin(config));
|
|
77
|
+
const headers = buildCorsHeaders(allowed, config, varyByOrigin);
|
|
78
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
79
|
+
if (k === 'vary') {
|
|
80
|
+
response.headers.set('vary', mergeVary(response.headers.get('vary'), v));
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
response.headers.set(k, v);
|
|
84
|
+
}
|
|
85
|
+
return response;
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=cors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.js","sourceRoot":"","sources":["../../src/utils/cors.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/path.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
export declare function toFileUrl(path: string): string;
|
|
2
2
|
export declare function normalizePath(path: string): string;
|
|
3
3
|
export declare function buildRouteRegex(path: string): RegExp;
|
|
4
|
+
declare const _default: {
|
|
5
|
+
toFileUrl: typeof toFileUrl;
|
|
6
|
+
normalizePath: typeof normalizePath;
|
|
7
|
+
buildRouteRegex: typeof buildRouteRegex;
|
|
8
|
+
};
|
|
9
|
+
export default _default;
|
|
4
10
|
//# sourceMappingURL=path.d.ts.map
|
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,CAE9C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASpD"}
|
|
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;;;;;;AAED,wBAIE"}
|
package/dist/utils/path.js
CHANGED
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,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"}
|
|
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;AAED,eAAe;IACb,SAAS;IACT,aAAa;IACb,eAAe;CAChB,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { StandardRouteSchema } from '../types';
|
|
2
|
+
export interface NormalizedValidationIssue {
|
|
3
|
+
message: string;
|
|
4
|
+
path: Array<string | number>;
|
|
5
|
+
code?: string;
|
|
6
|
+
raw?: unknown;
|
|
7
|
+
}
|
|
8
|
+
interface StandardValidationSuccess {
|
|
9
|
+
success: true;
|
|
10
|
+
value: unknown;
|
|
11
|
+
}
|
|
12
|
+
interface StandardValidationFailure {
|
|
13
|
+
success: false;
|
|
14
|
+
issues: readonly unknown[];
|
|
15
|
+
}
|
|
16
|
+
export type StandardValidationResult = StandardValidationSuccess | StandardValidationFailure;
|
|
17
|
+
export declare function isStandardRouteSchema(schema: unknown): schema is StandardRouteSchema;
|
|
18
|
+
export declare function runStandardValidation(schema: StandardRouteSchema, value: unknown): Promise<StandardValidationResult>;
|
|
19
|
+
export declare function extractThrownIssues(error: unknown): readonly unknown[] | null;
|
|
20
|
+
export declare function normalizeValidationIssues(issues: readonly unknown[], includeRawIssues: boolean): NormalizedValidationIssue[];
|
|
21
|
+
export declare function createValidationErrorPayload(target: 'input' | 'output', issues: NormalizedValidationIssue[]): {
|
|
22
|
+
error: boolean;
|
|
23
|
+
message: string;
|
|
24
|
+
statusCode: number;
|
|
25
|
+
source: string;
|
|
26
|
+
target: "input" | "output";
|
|
27
|
+
issues: NormalizedValidationIssue[];
|
|
28
|
+
timestamp: string;
|
|
29
|
+
};
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=schema-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-validation.d.ts","sourceRoot":"","sources":["../../src/utils/schema-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAEpD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,UAAU,yBAAyB;IACjC,OAAO,EAAE,IAAI,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,UAAU,yBAAyB;IACjC,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;CAC5B;AAED,MAAM,MAAM,wBAAwB,GAAG,yBAAyB,GAAG,yBAAyB,CAAC;AAE7F,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,mBAAmB,CAKpF;AAED,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,wBAAwB,CAAC,CASnC;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,OAAO,EAAE,GAAG,IAAI,CAc7E;AA2BD,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,SAAS,OAAO,EAAE,EAC1B,gBAAgB,EAAE,OAAO,GACxB,yBAAyB,EAAE,CAwB7B;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,OAAO,GAAG,QAAQ,EAAE,MAAM,EAAE,yBAAyB,EAAE;;;;;;;;EAU3G"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export function isStandardRouteSchema(schema) {
|
|
2
|
+
const standard = schema?.['~standard'];
|
|
3
|
+
return (!!standard && typeof standard === 'object' && typeof standard.validate === 'function' && standard.version === 1);
|
|
4
|
+
}
|
|
5
|
+
export async function runStandardValidation(schema, value) {
|
|
6
|
+
const result = await schema['~standard'].validate(value);
|
|
7
|
+
const issues = result?.issues;
|
|
8
|
+
if (Array.isArray(issues) && issues.length > 0) {
|
|
9
|
+
return { success: false, issues };
|
|
10
|
+
}
|
|
11
|
+
return { success: true, value: result?.value };
|
|
12
|
+
}
|
|
13
|
+
export function extractThrownIssues(error) {
|
|
14
|
+
if (Array.isArray(error)) {
|
|
15
|
+
return error;
|
|
16
|
+
}
|
|
17
|
+
if (error && typeof error === 'object' && Array.isArray(error.issues)) {
|
|
18
|
+
return error.issues;
|
|
19
|
+
}
|
|
20
|
+
if (error && typeof error === 'object' && error.cause && Array.isArray(error.cause.issues)) {
|
|
21
|
+
return error.cause.issues;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
function normalizePath(path) {
|
|
26
|
+
if (!Array.isArray(path))
|
|
27
|
+
return [];
|
|
28
|
+
const normalized = [];
|
|
29
|
+
for (let i = 0; i < path.length; i++) {
|
|
30
|
+
const segment = path[i];
|
|
31
|
+
let value = segment;
|
|
32
|
+
if (segment && typeof segment === 'object' && 'key' in segment) {
|
|
33
|
+
value = segment.key;
|
|
34
|
+
}
|
|
35
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
36
|
+
normalized.push(value);
|
|
37
|
+
}
|
|
38
|
+
else if (typeof value === 'symbol') {
|
|
39
|
+
normalized.push(String(value));
|
|
40
|
+
}
|
|
41
|
+
else if (value !== undefined && value !== null) {
|
|
42
|
+
normalized.push(String(value));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return normalized;
|
|
46
|
+
}
|
|
47
|
+
export function normalizeValidationIssues(issues, includeRawIssues) {
|
|
48
|
+
const normalized = [];
|
|
49
|
+
for (let i = 0; i < issues.length; i++) {
|
|
50
|
+
const issue = issues[i];
|
|
51
|
+
const maybeIssue = issue;
|
|
52
|
+
const normalizedIssue = {
|
|
53
|
+
message: typeof maybeIssue?.message === 'string' && maybeIssue.message.length > 0 ? maybeIssue.message : 'Invalid value',
|
|
54
|
+
path: normalizePath(maybeIssue?.path),
|
|
55
|
+
};
|
|
56
|
+
if (typeof maybeIssue?.code === 'string') {
|
|
57
|
+
normalizedIssue.code = maybeIssue.code;
|
|
58
|
+
}
|
|
59
|
+
if (includeRawIssues) {
|
|
60
|
+
normalizedIssue.raw = issue;
|
|
61
|
+
}
|
|
62
|
+
normalized.push(normalizedIssue);
|
|
63
|
+
}
|
|
64
|
+
return normalized;
|
|
65
|
+
}
|
|
66
|
+
export function createValidationErrorPayload(target, issues) {
|
|
67
|
+
return {
|
|
68
|
+
error: true,
|
|
69
|
+
message: 'Validation failed',
|
|
70
|
+
statusCode: 422,
|
|
71
|
+
source: 'validation',
|
|
72
|
+
target,
|
|
73
|
+
issues,
|
|
74
|
+
timestamp: new Date().toISOString(),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=schema-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-validation.js","sourceRoot":"","sources":["../../src/utils/schema-validation.ts"],"names":[],"mappings":"AAqBA,MAAM,UAAU,qBAAqB,CAAC,MAAe;IACnD,MAAM,QAAQ,GAAI,MAAc,EAAE,CAAC,WAAW,CAAC,CAAC;IAChD,OAAO,CACL,CAAC,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,QAAQ,CAAC,QAAQ,KAAK,UAAU,IAAI,QAAQ,CAAC,OAAO,KAAK,CAAC,CAChH,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAA2B,EAC3B,KAAc;IAEd,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACzD,MAAM,MAAM,GAAI,MAAc,EAAE,MAAM,CAAC;IAEvC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IACpC,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAG,MAAc,EAAE,KAAK,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAE,KAAa,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/E,OAAQ,KAAa,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAK,KAAa,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAE,KAAa,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7G,OAAQ,KAAa,CAAC,KAAK,CAAC,MAAM,CAAC;IACrC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,aAAa,CAAC,IAAa;IAClC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,UAAU,GAA2B,EAAE,CAAC;IAE9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,KAAK,GAAG,OAAO,CAAC;QAEpB,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,KAAK,IAAK,OAAe,EAAE,CAAC;YACxE,KAAK,GAAI,OAAe,CAAC,GAAG,CAAC;QAC/B,CAAC;QAED,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC3D,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACrC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACjC,CAAC;aAAM,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACjD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,MAA0B,EAC1B,gBAAyB;IAEzB,MAAM,UAAU,GAAgC,EAAE,CAAC;IAEnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,UAAU,GAAG,KAAY,CAAC;QAChC,MAAM,eAAe,GAA8B;YACjD,OAAO,EACL,OAAO,UAAU,EAAE,OAAO,KAAK,QAAQ,IAAI,UAAU,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;YACjH,IAAI,EAAE,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC;SACtC,CAAC;QAEF,IAAI,OAAO,UAAU,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;YACzC,eAAe,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC;QACzC,CAAC;QAED,IAAI,gBAAgB,EAAE,CAAC;YACrB,eAAe,CAAC,GAAG,GAAG,KAAK,CAAC;QAC9B,CAAC;QAED,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,MAA0B,EAAE,MAAmC;IAC1G,OAAO;QACL,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,mBAAmB;QAC5B,UAAU,EAAE,GAAG;QACf,MAAM,EAAE,YAAY;QACpB,MAAM;QACN,MAAM;QACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,UAAU,CAAC;AAE1D,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,UAAU,CAAC;AAE1D,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAejE;AAiCD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD"}
|
package/dist/utils/validation.js
CHANGED
|
@@ -7,6 +7,7 @@ export function validateConfig(config) {
|
|
|
7
7
|
development: config.development || false,
|
|
8
8
|
routesDir: config.routesDir || DEFAULT_CONFIG.ROUTES_DIR,
|
|
9
9
|
autoDiscover: config.autoDiscover !== false,
|
|
10
|
+
defaults: config.defaults,
|
|
10
11
|
cors: config.cors ? validateCorsOptions(config.cors) : undefined,
|
|
11
12
|
before: config.before || [],
|
|
12
13
|
finally: config.finally || [],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,MAAM,eAAe,GAAiB;QACpC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;QAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,cAAc,CAAC,QAAQ;QACpD,SAAS,EAAE,MAAM,CAAC,SAAS,KAAK,KAAK;QACrC,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,KAAK;QACxC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,cAAc,CAAC,UAAU;QACxD,YAAY,EAAE,MAAM,CAAC,YAAY,KAAK,KAAK;QAC3C,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;QAChE,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE;KAC9B,CAAC;IAEF,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,SAAS,YAAY,CAAC,IAAa;IACjC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,cAAc,CAAC,IAAI,CAAC;IAC7B,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,qCAAqC,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,mBAAmB,CAAC,IAA2B;IACtD,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,OAAO;YACL,MAAM,EAAE,GAAG;YACX,WAAW,EAAE,IAAI;YACjB,YAAY,EAAE,CAAC,cAAc,EAAE,eAAe,CAAC;YAC/C,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC;YAClE,aAAa,EAAE,CAAC,eAAe,CAAC;YAChC,MAAM,EAAE,cAAc,CAAC,YAAY;SACpC,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAClF,OAAO,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACrD,CAAC"}
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,MAAM,eAAe,GAAiB;QACpC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;QAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,cAAc,CAAC,QAAQ;QACpD,SAAS,EAAE,MAAM,CAAC,SAAS,KAAK,KAAK;QACrC,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,KAAK;QACxC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,cAAc,CAAC,UAAU;QACxD,YAAY,EAAE,MAAM,CAAC,YAAY,KAAK,KAAK;QAC3C,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;QAChE,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE;KAC9B,CAAC;IAEF,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,SAAS,YAAY,CAAC,IAAa;IACjC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,cAAc,CAAC,IAAI,CAAC;IAC7B,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,qCAAqC,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,mBAAmB,CAAC,IAA2B;IACtD,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,OAAO;YACL,MAAM,EAAE,GAAG;YACX,WAAW,EAAE,IAAI;YACjB,YAAY,EAAE,CAAC,cAAc,EAAE,eAAe,CAAC;YAC/C,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC;YAClE,aAAa,EAAE,CAAC,eAAe,CAAC;YAChC,MAAM,EAAE,cAAc,CAAC,YAAY;SACpC,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAClF,OAAO,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACrD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vector-framework",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"author": "webhie-com",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -8,15 +8,14 @@
|
|
|
8
8
|
},
|
|
9
9
|
"main": "./dist/index.js",
|
|
10
10
|
"module": "./dist/index.mjs",
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"itty-router": "^5.0.0"
|
|
13
|
-
},
|
|
11
|
+
"dependencies": {},
|
|
14
12
|
"devDependencies": {
|
|
15
13
|
"@biomejs/biome": "^2.4.6",
|
|
16
14
|
"@biomejs/cli-darwin-arm64": "^2.4.6",
|
|
17
15
|
"@types/bun": "latest",
|
|
18
16
|
"oxlint": "^1.15.0",
|
|
19
|
-
"typescript": "^5.0.0"
|
|
17
|
+
"typescript": "^5.0.0",
|
|
18
|
+
"zod": "^4.3.6"
|
|
20
19
|
},
|
|
21
20
|
"peerDependencies": {
|
|
22
21
|
"bun": ">=1.0.0"
|
|
@@ -49,7 +48,7 @@
|
|
|
49
48
|
"bugs": {
|
|
50
49
|
"url": "https://github.com/webhie-com/vector/issues"
|
|
51
50
|
},
|
|
52
|
-
"description": "A modern TypeScript API framework built with Bun
|
|
51
|
+
"description": "A modern TypeScript API framework built with Bun",
|
|
53
52
|
"engines": {
|
|
54
53
|
"bun": ">=1.0.0"
|
|
55
54
|
},
|
|
@@ -65,7 +64,6 @@
|
|
|
65
64
|
"api",
|
|
66
65
|
"framework",
|
|
67
66
|
"bun",
|
|
68
|
-
"itty-router",
|
|
69
67
|
"typescript",
|
|
70
68
|
"rest",
|
|
71
69
|
"http",
|
|
@@ -77,22 +75,25 @@
|
|
|
77
75
|
"scripts": {
|
|
78
76
|
"dev": "bun run src/cli/index.ts dev",
|
|
79
77
|
"start": "bun run src/cli/index.ts start",
|
|
80
|
-
"build": "bun run
|
|
81
|
-
"build:app": "bun run src/cli/index.ts build",
|
|
78
|
+
"build": "bun run build:lib",
|
|
82
79
|
"build:lib": "bun run build:clean && bun run build:ts && bun run build:bundle && bun run build:cli",
|
|
83
80
|
"build:clean": "rm -rf dist",
|
|
84
81
|
"build:ts": "tsc",
|
|
85
82
|
"build:bundle": "bun build src/index.ts --format esm --minify --outfile dist/index.mjs && bun build src/index.ts --format cjs --minify --outfile dist/index.js",
|
|
86
83
|
"build:cli": "bun build src/cli/index.ts --target bun --outfile dist/cli.js",
|
|
87
|
-
"
|
|
84
|
+
"local:cli:build": "bun run build:lib",
|
|
85
|
+
"local:cli:dev": "bun run dist/cli.js dev --config ./vector.config.ts",
|
|
86
|
+
"local:cli:start": "bun run dist/cli.js start --config ./vector.config.ts",
|
|
87
|
+
"test": "bun test ./tests/*.test.ts",
|
|
88
88
|
"test:unit": "bun test tests/*.test.ts",
|
|
89
89
|
"test:watch": "bun test --watch tests/*.test.ts",
|
|
90
90
|
"test:coverage": "bun test --coverage tests/*.test.ts",
|
|
91
|
-
"test:e2e": "bun test tests/e2e/e2e.test.ts",
|
|
91
|
+
"test:e2e": "bun test --max-concurrency 1 tests/e2e/e2e.test.ts tests/e2e/zod-io.e2e.test.ts",
|
|
92
92
|
"test:load": "bun run tests/e2e/load.test.ts",
|
|
93
93
|
"test:soak": "bun run tests/e2e/soak.test.ts",
|
|
94
94
|
"test:benchmark": "bun run tests/e2e/benchmark.test.ts",
|
|
95
|
-
"test:
|
|
95
|
+
"test:benchmark:io-schema": "bun run tests/e2e/concurrency-io-schema-benchmark.ts",
|
|
96
|
+
"test:all": "bun test ./tests/**/*.test.ts",
|
|
96
97
|
"test:perf": "bun run test:load && bun run test:soak && bun run test:benchmark",
|
|
97
98
|
"docker:build": "docker build -t vector:latest .",
|
|
98
99
|
"docker:build:test": "docker build -t vector:test --target test .",
|
package/src/auth/protected.ts
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
DefaultVectorTypes,
|
|
3
|
-
GetAuthType,
|
|
4
|
-
ProtectedHandler,
|
|
5
|
-
VectorRequest,
|
|
6
|
-
VectorTypes,
|
|
7
|
-
} from '../types';
|
|
1
|
+
import type { DefaultVectorTypes, GetAuthType, ProtectedHandler, VectorRequest, VectorTypes } from '../types';
|
|
8
2
|
|
|
9
3
|
export class AuthManager<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
10
4
|
private protectedHandler: ProtectedHandler<TTypes> | null = null;
|
|
@@ -15,9 +9,7 @@ export class AuthManager<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
15
9
|
|
|
16
10
|
async authenticate(request: VectorRequest<TTypes>): Promise<GetAuthType<TTypes> | null> {
|
|
17
11
|
if (!this.protectedHandler) {
|
|
18
|
-
throw new Error(
|
|
19
|
-
'Protected handler not configured. Use vector.protected() to set authentication handler.'
|
|
20
|
-
);
|
|
12
|
+
throw new Error('Protected handler not configured. Use vector.protected() to set authentication handler.');
|
|
21
13
|
}
|
|
22
14
|
|
|
23
15
|
try {
|
|
@@ -25,9 +17,7 @@ export class AuthManager<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
25
17
|
request.authUser = authUser;
|
|
26
18
|
return authUser;
|
|
27
19
|
} catch (error) {
|
|
28
|
-
throw new Error(
|
|
29
|
-
`Authentication failed: ${error instanceof Error ? error.message : String(error)}`
|
|
30
|
-
);
|
|
20
|
+
throw new Error(`Authentication failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
31
21
|
}
|
|
32
22
|
}
|
|
33
23
|
|
package/src/cache/manager.ts
CHANGED
|
@@ -32,11 +32,7 @@ export class CacheManager<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
32
32
|
return this.getFromMemoryCache(key, factory, ttl);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
private async getFromMemoryCache<T>(
|
|
36
|
-
key: string,
|
|
37
|
-
factory: () => Promise<T>,
|
|
38
|
-
ttl: number
|
|
39
|
-
): Promise<T> {
|
|
35
|
+
private async getFromMemoryCache<T>(key: string, factory: () => Promise<T>, ttl: number): Promise<T> {
|
|
40
36
|
const now = Date.now();
|
|
41
37
|
const cached = this.memoryCache.get(key);
|
|
42
38
|
|
|
@@ -104,11 +100,7 @@ export class CacheManager<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
104
100
|
}
|
|
105
101
|
}
|
|
106
102
|
|
|
107
|
-
async set<T = GetCacheType<TTypes>>(
|
|
108
|
-
key: string,
|
|
109
|
-
value: T,
|
|
110
|
-
ttl: number = DEFAULT_CONFIG.CACHE_TTL
|
|
111
|
-
): Promise<void> {
|
|
103
|
+
async set<T = GetCacheType<TTypes>>(key: string, value: T, ttl: number = DEFAULT_CONFIG.CACHE_TTL): Promise<void> {
|
|
112
104
|
if (ttl <= 0) {
|
|
113
105
|
return;
|
|
114
106
|
}
|
|
@@ -140,13 +132,7 @@ export class CacheManager<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
140
132
|
|
|
141
133
|
generateKey(request: Request & { _parsedUrl?: URL }, options?: { authUser?: any }): string {
|
|
142
134
|
const url = request._parsedUrl ?? new URL(request.url);
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
url.pathname,
|
|
146
|
-
url.search,
|
|
147
|
-
options?.authUser?.id != null ? String(options.authUser.id) : 'anonymous',
|
|
148
|
-
];
|
|
149
|
-
|
|
150
|
-
return parts.join(':');
|
|
135
|
+
const userId = options?.authUser?.id != null ? String(options.authUser.id) : 'anonymous';
|
|
136
|
+
return `${request.method}:${url.pathname}:${url.search}:${userId}`;
|
|
151
137
|
}
|
|
152
138
|
}
|
package/src/cli/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { watch } from 'node:fs';
|
|
|
4
4
|
import { parseArgs } from 'node:util';
|
|
5
5
|
import { getVectorInstance } from '../core/vector';
|
|
6
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
10
|
const args = typeof Bun !== 'undefined' ? Bun.argv.slice(2) : process.argv.slice(2);
|
|
@@ -45,6 +46,9 @@ const { values, positionals } = parseArgs({
|
|
|
45
46
|
});
|
|
46
47
|
|
|
47
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='));
|
|
48
52
|
|
|
49
53
|
async function runDev() {
|
|
50
54
|
const isDev = command === 'dev';
|
|
@@ -62,15 +66,16 @@ async function runDev() {
|
|
|
62
66
|
|
|
63
67
|
// Create the actual server start promise
|
|
64
68
|
const serverStartPromise = (async (): Promise<{ server: any; vector: any; config: any }> => {
|
|
65
|
-
|
|
66
|
-
const configLoader = new ConfigLoader(
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
config.
|
|
73
|
-
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);
|
|
74
79
|
config.development = config.development ?? isDev;
|
|
75
80
|
config.autoDiscover = true; // Always auto-discover routes
|
|
76
81
|
|
|
@@ -142,9 +147,7 @@ async function runDev() {
|
|
|
142
147
|
if (isReloading || now - lastReloadTime < 1000) return;
|
|
143
148
|
|
|
144
149
|
const segments = filename ? filename.split(/[/\\]/) : [];
|
|
145
|
-
const excluded = segments.some((s) =>
|
|
146
|
-
['node_modules', '.git', '.vector', 'dist'].includes(s)
|
|
147
|
-
);
|
|
150
|
+
const excluded = segments.some((s) => ['node_modules', '.git', '.vector', 'dist'].includes(s));
|
|
148
151
|
if (
|
|
149
152
|
filename &&
|
|
150
153
|
(filename.endsWith('.ts') || filename.endsWith('.js') || filename.endsWith('.json')) &&
|
|
@@ -213,73 +216,15 @@ async function runDev() {
|
|
|
213
216
|
}
|
|
214
217
|
}
|
|
215
218
|
|
|
216
|
-
async function runBuild() {
|
|
217
|
-
try {
|
|
218
|
-
const { RouteScanner } = await import('../dev/route-scanner');
|
|
219
|
-
const { RouteGenerator } = await import('../dev/route-generator');
|
|
220
|
-
|
|
221
|
-
// Step 1: Scan and generate routes
|
|
222
|
-
const scanner = new RouteScanner(values.routes as string);
|
|
223
|
-
const generator = new RouteGenerator();
|
|
224
|
-
|
|
225
|
-
const routes = await scanner.scan();
|
|
226
|
-
await generator.generate(routes);
|
|
227
|
-
|
|
228
|
-
// Step 2: Build the application with Bun
|
|
229
|
-
if (typeof Bun !== 'undefined') {
|
|
230
|
-
// Build the CLI as an executable
|
|
231
|
-
const buildProcess = Bun.spawn([
|
|
232
|
-
'bun',
|
|
233
|
-
'build',
|
|
234
|
-
'src/cli/index.ts',
|
|
235
|
-
'--target',
|
|
236
|
-
'bun',
|
|
237
|
-
'--outfile',
|
|
238
|
-
'dist/server.js',
|
|
239
|
-
'--minify',
|
|
240
|
-
]);
|
|
241
|
-
|
|
242
|
-
const exitCode = await buildProcess.exited;
|
|
243
|
-
if (exitCode !== 0) {
|
|
244
|
-
throw new Error(`Build failed with exit code ${exitCode}`);
|
|
245
|
-
}
|
|
246
|
-
} else {
|
|
247
|
-
// For Node.js, use child_process
|
|
248
|
-
const { spawnSync } = await import('child_process');
|
|
249
|
-
const result = spawnSync(
|
|
250
|
-
'bun',
|
|
251
|
-
['build', 'src/cli/index.ts', '--target', 'bun', '--outfile', 'dist/server.js', '--minify'],
|
|
252
|
-
{
|
|
253
|
-
stdio: 'inherit',
|
|
254
|
-
shell: true,
|
|
255
|
-
}
|
|
256
|
-
);
|
|
257
|
-
|
|
258
|
-
if (result.status !== 0) {
|
|
259
|
-
throw new Error(`Build failed with exit code ${result.status}`);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
console.log('\nBuild complete: dist/server.js\n');
|
|
264
|
-
} catch (error: any) {
|
|
265
|
-
const red = '\x1b[31m';
|
|
266
|
-
const reset = '\x1b[0m';
|
|
267
|
-
console.error(`\n${red}Error: ${error.message || error}${reset}\n`);
|
|
268
|
-
process.exit(1);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
219
|
switch (command) {
|
|
273
220
|
case 'dev':
|
|
274
221
|
await runDev();
|
|
275
222
|
break;
|
|
276
|
-
case '
|
|
277
|
-
await runBuild();
|
|
278
|
-
break;
|
|
279
|
-
case 'start':
|
|
223
|
+
case 'start': {
|
|
280
224
|
process.env.NODE_ENV = 'production';
|
|
281
225
|
await runDev();
|
|
282
226
|
break;
|
|
227
|
+
}
|
|
283
228
|
default:
|
|
284
229
|
console.error(`Unknown command: ${command}`);
|
|
285
230
|
console.log(`
|
|
@@ -287,15 +232,14 @@ Usage: vector [command] [options]
|
|
|
287
232
|
|
|
288
233
|
Commands:
|
|
289
234
|
dev Start development server (default)
|
|
290
|
-
build Build for production
|
|
291
235
|
start Start production server
|
|
292
236
|
|
|
293
237
|
Options:
|
|
294
238
|
-p, --port <port> Port to listen on (default: 3000)
|
|
295
239
|
-h, --host <host> Hostname to bind to (default: localhost)
|
|
296
|
-
-r, --routes <dir> Routes directory (
|
|
240
|
+
-r, --routes <dir> Routes directory (dev/start)
|
|
297
241
|
-w, --watch Watch for file changes (default: true)
|
|
298
|
-
-c, --config <path> Path to config file (
|
|
242
|
+
-c, --config <path> Path to config file (dev/start)
|
|
299
243
|
--cors Enable CORS (default: true)
|
|
300
244
|
`);
|
|
301
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
|
+
};
|
|
@@ -36,9 +36,7 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
36
36
|
} catch (error: any) {
|
|
37
37
|
const msg = error instanceof Error ? error.message : String(error);
|
|
38
38
|
console.error(`[Vector] Failed to load config from ${this.configPath}: ${msg}`);
|
|
39
|
-
console.error(
|
|
40
|
-
'[Vector] Server is using default configuration. Fix your config file and restart.'
|
|
41
|
-
);
|
|
39
|
+
console.error('[Vector] Server is using default configuration. Fix your config file and restart.');
|
|
42
40
|
this.config = {};
|
|
43
41
|
}
|
|
44
42
|
} else {
|
|
@@ -65,6 +63,8 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
65
63
|
config.development = this.config.development;
|
|
66
64
|
config.routesDir = this.config.routesDir || './routes';
|
|
67
65
|
config.idleTimeout = this.config.idleTimeout;
|
|
66
|
+
config.defaults = this.config.defaults;
|
|
67
|
+
config.openapi = this.config.openapi;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
// Always auto-discover routes
|