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.
Files changed (98) hide show
  1. package/README.md +87 -635
  2. package/dist/auth/protected.d.ts.map +1 -1
  3. package/dist/auth/protected.js.map +1 -1
  4. package/dist/cache/manager.d.ts.map +1 -1
  5. package/dist/cache/manager.js +2 -7
  6. package/dist/cache/manager.js.map +1 -1
  7. package/dist/cli/index.js +17 -62
  8. package/dist/cli/index.js.map +1 -1
  9. package/dist/cli/option-resolution.d.ts +4 -0
  10. package/dist/cli/option-resolution.d.ts.map +1 -0
  11. package/dist/cli/option-resolution.js +28 -0
  12. package/dist/cli/option-resolution.js.map +1 -0
  13. package/dist/cli.js +2721 -617
  14. package/dist/constants/index.d.ts +3 -0
  15. package/dist/constants/index.d.ts.map +1 -1
  16. package/dist/constants/index.js +6 -0
  17. package/dist/constants/index.js.map +1 -1
  18. package/dist/core/config-loader.d.ts.map +1 -1
  19. package/dist/core/config-loader.js +2 -0
  20. package/dist/core/config-loader.js.map +1 -1
  21. package/dist/core/router.d.ts +41 -17
  22. package/dist/core/router.d.ts.map +1 -1
  23. package/dist/core/router.js +432 -153
  24. package/dist/core/router.js.map +1 -1
  25. package/dist/core/server.d.ts +14 -1
  26. package/dist/core/server.d.ts.map +1 -1
  27. package/dist/core/server.js +250 -30
  28. package/dist/core/server.js.map +1 -1
  29. package/dist/core/vector.d.ts +4 -3
  30. package/dist/core/vector.d.ts.map +1 -1
  31. package/dist/core/vector.js +21 -12
  32. package/dist/core/vector.js.map +1 -1
  33. package/dist/dev/route-generator.d.ts.map +1 -1
  34. package/dist/dev/route-generator.js.map +1 -1
  35. package/dist/dev/route-scanner.d.ts.map +1 -1
  36. package/dist/dev/route-scanner.js +1 -5
  37. package/dist/dev/route-scanner.js.map +1 -1
  38. package/dist/http.d.ts +14 -14
  39. package/dist/http.d.ts.map +1 -1
  40. package/dist/http.js +34 -41
  41. package/dist/http.js.map +1 -1
  42. package/dist/index.js +1314 -8
  43. package/dist/index.mjs +1314 -8
  44. package/dist/middleware/manager.d.ts.map +1 -1
  45. package/dist/middleware/manager.js +4 -0
  46. package/dist/middleware/manager.js.map +1 -1
  47. package/dist/openapi/docs-ui.d.ts +2 -0
  48. package/dist/openapi/docs-ui.d.ts.map +1 -0
  49. package/dist/openapi/docs-ui.js +1313 -0
  50. package/dist/openapi/docs-ui.js.map +1 -0
  51. package/dist/openapi/generator.d.ts +12 -0
  52. package/dist/openapi/generator.d.ts.map +1 -0
  53. package/dist/openapi/generator.js +273 -0
  54. package/dist/openapi/generator.js.map +1 -0
  55. package/dist/types/index.d.ts +70 -11
  56. package/dist/types/index.d.ts.map +1 -1
  57. package/dist/types/standard-schema.d.ts +118 -0
  58. package/dist/types/standard-schema.d.ts.map +1 -0
  59. package/dist/types/standard-schema.js +2 -0
  60. package/dist/types/standard-schema.js.map +1 -0
  61. package/dist/utils/cors.d.ts +13 -0
  62. package/dist/utils/cors.d.ts.map +1 -0
  63. package/dist/utils/cors.js +89 -0
  64. package/dist/utils/cors.js.map +1 -0
  65. package/dist/utils/path.d.ts +6 -0
  66. package/dist/utils/path.d.ts.map +1 -1
  67. package/dist/utils/path.js +5 -0
  68. package/dist/utils/path.js.map +1 -1
  69. package/dist/utils/schema-validation.d.ts +31 -0
  70. package/dist/utils/schema-validation.d.ts.map +1 -0
  71. package/dist/utils/schema-validation.js +77 -0
  72. package/dist/utils/schema-validation.js.map +1 -0
  73. package/dist/utils/validation.d.ts.map +1 -1
  74. package/dist/utils/validation.js +1 -0
  75. package/dist/utils/validation.js.map +1 -1
  76. package/package.json +13 -12
  77. package/src/auth/protected.ts +3 -13
  78. package/src/cache/manager.ts +4 -18
  79. package/src/cli/index.ts +19 -75
  80. package/src/cli/option-resolution.ts +40 -0
  81. package/src/constants/index.ts +7 -0
  82. package/src/core/config-loader.ts +3 -3
  83. package/src/core/router.ts +502 -156
  84. package/src/core/server.ts +327 -32
  85. package/src/core/vector.ts +49 -29
  86. package/src/dev/route-generator.ts +1 -3
  87. package/src/dev/route-scanner.ts +2 -9
  88. package/src/http.ts +85 -125
  89. package/src/middleware/manager.ts +4 -0
  90. package/src/openapi/assets/tailwindcdn.js +83 -0
  91. package/src/openapi/docs-ui.ts +1317 -0
  92. package/src/openapi/generator.ts +359 -0
  93. package/src/types/index.ts +104 -17
  94. package/src/types/standard-schema.ts +147 -0
  95. package/src/utils/cors.ts +101 -0
  96. package/src/utils/path.ts +6 -0
  97. package/src/utils/schema-validation.ts +123 -0
  98. 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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"}
@@ -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
@@ -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"}
@@ -12,4 +12,9 @@ export function buildRouteRegex(path) {
12
12
  .replace(/\./g, '\\.')
13
13
  .replace(/(\/?)\*/g, '($1.*)?')}/*$`);
14
14
  }
15
+ export default {
16
+ toFileUrl,
17
+ normalizePath,
18
+ buildRouteRegex,
19
+ };
15
20
  //# sourceMappingURL=path.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"path.js","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO,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":"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"}
@@ -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,CAcjE;AAiCD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD"}
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"}
@@ -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.1.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 and itty-router",
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 src/cli/index.ts build",
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
- "test": "bun test tests/api-error.test.ts tests/cache.test.ts tests/middleware.test.ts tests/middleware-integration.test.ts tests/router.test.ts",
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:all": "bun test 'tests/**/*.test.ts'",
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 .",
@@ -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
 
@@ -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 parts = [
144
- request.method,
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
- // Load configuration using ConfigLoader
66
- const configLoader = new ConfigLoader(values.config as string | undefined);
67
- const config = await configLoader.load();
68
-
69
- // Merge CLI options with loaded config
70
- // Only use CLI values if config doesn't have them
71
- config.port = config.port ?? Number.parseInt(values.port as string);
72
- config.hostname = config.hostname ?? (values.host as string);
73
- config.routesDir = config.routesDir ?? (values.routes as string);
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 'build':
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 (default: ./routes)
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 (default: vector.config.ts)
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
+ }
@@ -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