vector-framework 1.0.0 → 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 (104) hide show
  1. package/README.md +87 -634
  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 +5 -2
  5. package/dist/cache/manager.d.ts.map +1 -1
  6. package/dist/cache/manager.js +21 -12
  7. package/dist/cache/manager.js.map +1 -1
  8. package/dist/cli/index.js +60 -126
  9. package/dist/cli/index.js.map +1 -1
  10. package/dist/cli/option-resolution.d.ts +4 -0
  11. package/dist/cli/option-resolution.d.ts.map +1 -0
  12. package/dist/cli/option-resolution.js +28 -0
  13. package/dist/cli/option-resolution.js.map +1 -0
  14. package/dist/cli.js +2774 -599
  15. package/dist/constants/index.d.ts +3 -0
  16. package/dist/constants/index.d.ts.map +1 -1
  17. package/dist/constants/index.js +6 -0
  18. package/dist/constants/index.js.map +1 -1
  19. package/dist/core/config-loader.d.ts +2 -2
  20. package/dist/core/config-loader.d.ts.map +1 -1
  21. package/dist/core/config-loader.js +18 -18
  22. package/dist/core/config-loader.js.map +1 -1
  23. package/dist/core/router.d.ts +41 -15
  24. package/dist/core/router.d.ts.map +1 -1
  25. package/dist/core/router.js +465 -150
  26. package/dist/core/router.js.map +1 -1
  27. package/dist/core/server.d.ts +17 -3
  28. package/dist/core/server.d.ts.map +1 -1
  29. package/dist/core/server.js +274 -33
  30. package/dist/core/server.js.map +1 -1
  31. package/dist/core/vector.d.ts +9 -8
  32. package/dist/core/vector.d.ts.map +1 -1
  33. package/dist/core/vector.js +40 -32
  34. package/dist/core/vector.js.map +1 -1
  35. package/dist/dev/route-generator.d.ts.map +1 -1
  36. package/dist/dev/route-generator.js.map +1 -1
  37. package/dist/dev/route-scanner.d.ts +1 -1
  38. package/dist/dev/route-scanner.d.ts.map +1 -1
  39. package/dist/dev/route-scanner.js +37 -43
  40. package/dist/dev/route-scanner.js.map +1 -1
  41. package/dist/http.d.ts +14 -14
  42. package/dist/http.d.ts.map +1 -1
  43. package/dist/http.js +84 -84
  44. package/dist/http.js.map +1 -1
  45. package/dist/index.d.ts +3 -3
  46. package/dist/index.js +1314 -8
  47. package/dist/index.mjs +1314 -8
  48. package/dist/middleware/manager.d.ts +1 -1
  49. package/dist/middleware/manager.d.ts.map +1 -1
  50. package/dist/middleware/manager.js +4 -0
  51. package/dist/middleware/manager.js.map +1 -1
  52. package/dist/openapi/docs-ui.d.ts +2 -0
  53. package/dist/openapi/docs-ui.d.ts.map +1 -0
  54. package/dist/openapi/docs-ui.js +1313 -0
  55. package/dist/openapi/docs-ui.js.map +1 -0
  56. package/dist/openapi/generator.d.ts +12 -0
  57. package/dist/openapi/generator.d.ts.map +1 -0
  58. package/dist/openapi/generator.js +273 -0
  59. package/dist/openapi/generator.js.map +1 -0
  60. package/dist/types/index.d.ts +70 -11
  61. package/dist/types/index.d.ts.map +1 -1
  62. package/dist/types/standard-schema.d.ts +118 -0
  63. package/dist/types/standard-schema.d.ts.map +1 -0
  64. package/dist/types/standard-schema.js +2 -0
  65. package/dist/types/standard-schema.js.map +1 -0
  66. package/dist/utils/cors.d.ts +13 -0
  67. package/dist/utils/cors.d.ts.map +1 -0
  68. package/dist/utils/cors.js +89 -0
  69. package/dist/utils/cors.js.map +1 -0
  70. package/dist/utils/path.d.ts +7 -0
  71. package/dist/utils/path.d.ts.map +1 -1
  72. package/dist/utils/path.js +14 -3
  73. package/dist/utils/path.js.map +1 -1
  74. package/dist/utils/schema-validation.d.ts +31 -0
  75. package/dist/utils/schema-validation.d.ts.map +1 -0
  76. package/dist/utils/schema-validation.js +77 -0
  77. package/dist/utils/schema-validation.js.map +1 -0
  78. package/dist/utils/validation.d.ts.map +1 -1
  79. package/dist/utils/validation.js +1 -0
  80. package/dist/utils/validation.js.map +1 -1
  81. package/package.json +24 -19
  82. package/src/auth/protected.ts +3 -13
  83. package/src/cache/manager.ts +25 -30
  84. package/src/cli/index.ts +62 -141
  85. package/src/cli/option-resolution.ts +40 -0
  86. package/src/constants/index.ts +7 -0
  87. package/src/core/config-loader.ts +20 -22
  88. package/src/core/router.ts +535 -155
  89. package/src/core/server.ts +354 -45
  90. package/src/core/vector.ts +71 -61
  91. package/src/dev/route-generator.ts +1 -3
  92. package/src/dev/route-scanner.ts +38 -51
  93. package/src/http.ts +117 -187
  94. package/src/index.ts +3 -3
  95. package/src/middleware/manager.ts +8 -11
  96. package/src/openapi/assets/tailwindcdn.js +83 -0
  97. package/src/openapi/docs-ui.ts +1317 -0
  98. package/src/openapi/generator.ts +359 -0
  99. package/src/types/index.ts +104 -17
  100. package/src/types/standard-schema.ts +147 -0
  101. package/src/utils/cors.ts +101 -0
  102. package/src/utils/path.ts +19 -4
  103. package/src/utils/schema-validation.ts +123 -0
  104. 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,3 +1,10 @@
1
1
  export declare function toFileUrl(path: string): string;
2
2
  export declare function normalizePath(path: string): string;
3
+ export declare function buildRouteRegex(path: string): RegExp;
4
+ declare const _default: {
5
+ toFileUrl: typeof toFileUrl;
6
+ normalizePath: typeof normalizePath;
7
+ buildRouteRegex: typeof buildRouteRegex;
8
+ };
9
+ export default _default;
3
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,CAI9C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD"}
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASpD;;;;;;AAED,wBAIE"}
@@ -1,9 +1,20 @@
1
1
  export function toFileUrl(path) {
2
- return process.platform === 'win32'
3
- ? `file:///${path.replace(/\\/g, '/')}`
4
- : path;
2
+ return process.platform === 'win32' ? `file:///${path.replace(/\\/g, '/')}` : path;
5
3
  }
6
4
  export function normalizePath(path) {
7
5
  return path.replace(/\\/g, '/').replace(/\/+/g, '/');
8
6
  }
7
+ export function buildRouteRegex(path) {
8
+ return RegExp(`^${path
9
+ .replace(/\/+(\/|$)/g, '$1')
10
+ .replace(/(\/?\.?):(\w+)\+/g, '($1(?<$2>[\\s\\S]+))')
11
+ .replace(/(\/?\.?):(\w+)/g, '($1(?<$2>[^$1/]+?))')
12
+ .replace(/\./g, '\\.')
13
+ .replace(/(\/?)\*/g, '($1.*)?')}/*$`);
14
+ }
15
+ export default {
16
+ toFileUrl,
17
+ normalizePath,
18
+ buildRouteRegex,
19
+ };
9
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;QACjC,CAAC,CAAC,WAAW,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE;QACvC,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AACvD,CAAC"}
1
+ {"version":3,"file":"path.js","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,MAAM,CACX,IAAI,IAAI;SACL,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC;SAC3B,OAAO,CAAC,mBAAmB,EAAE,sBAAsB,CAAC;SACpD,OAAO,CAAC,iBAAiB,EAAE,qBAAqB,CAAC;SACjD,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,UAAU,EAAE,SAAS,CAAC,KAAK,CACvC,CAAC;AACJ,CAAC;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.0.0",
3
+ "version": "1.2.0",
4
4
  "author": "webhie-com",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,13 +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": {
13
+ "@biomejs/biome": "^2.4.6",
14
+ "@biomejs/cli-darwin-arm64": "^2.4.6",
15
15
  "@types/bun": "latest",
16
16
  "oxlint": "^1.15.0",
17
- "typescript": "^5.0.0"
17
+ "typescript": "^5.0.0",
18
+ "zod": "^4.3.6"
18
19
  },
19
20
  "peerDependencies": {
20
21
  "bun": ">=1.0.0"
@@ -47,7 +48,7 @@
47
48
  "bugs": {
48
49
  "url": "https://github.com/webhie-com/vector/issues"
49
50
  },
50
- "description": "A modern TypeScript API framework built with Bun and itty-router",
51
+ "description": "A modern TypeScript API framework built with Bun",
51
52
  "engines": {
52
53
  "bun": ">=1.0.0"
53
54
  },
@@ -63,7 +64,6 @@
63
64
  "api",
64
65
  "framework",
65
66
  "bun",
66
- "itty-router",
67
67
  "typescript",
68
68
  "rest",
69
69
  "http",
@@ -75,32 +75,37 @@
75
75
  "scripts": {
76
76
  "dev": "bun run src/cli/index.ts dev",
77
77
  "start": "bun run src/cli/index.ts start",
78
- "build": "bun run src/cli/index.ts build",
79
- "build:app": "bun run src/cli/index.ts build",
78
+ "build": "bun run build:lib",
80
79
  "build:lib": "bun run build:clean && bun run build:ts && bun run build:bundle && bun run build:cli",
81
80
  "build:clean": "rm -rf dist",
82
81
  "build:ts": "tsc",
83
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",
84
83
  "build:cli": "bun build src/cli/index.ts --target bun --outfile dist/cli.js",
85
- "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",
86
88
  "test:unit": "bun test tests/*.test.ts",
87
89
  "test:watch": "bun test --watch tests/*.test.ts",
88
90
  "test:coverage": "bun test --coverage tests/*.test.ts",
89
- "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",
90
92
  "test:load": "bun run tests/e2e/load.test.ts",
91
93
  "test:soak": "bun run tests/e2e/soak.test.ts",
92
94
  "test:benchmark": "bun run tests/e2e/benchmark.test.ts",
93
- "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",
94
97
  "test:perf": "bun run test:load && bun run test:soak && bun run test:benchmark",
95
98
  "docker:build": "docker build -t vector:latest .",
96
99
  "docker:build:test": "docker build -t vector:test --target test .",
97
- "docker:run": "docker-compose up",
98
- "docker:run:dev": "docker-compose --profile dev up",
99
- "docker:test": "docker-compose -f docker-compose.test.yml run test-all",
100
- "docker:test:unit": "docker-compose -f docker-compose.test.yml run test-unit",
101
- "docker:test:e2e": "docker-compose -f docker-compose.test.yml run test-e2e",
102
- "docker:test:load": "docker-compose -f docker-compose.test.yml run test-load",
103
- "docker:test:benchmark": "docker-compose -f docker-compose.test.yml run test-benchmark",
100
+ "docker:run": "docker compose up",
101
+ "docker:run:dev": "docker compose --profile dev up",
102
+ "docker:test": "docker compose -f docker-compose.test.yml run test-all",
103
+ "docker:test:unit": "docker compose -f docker-compose.test.yml run test-unit",
104
+ "docker:test:e2e": "docker compose -f docker-compose.test.yml run test-e2e",
105
+ "docker:test:load": "docker compose -f docker-compose.test.yml run test-load",
106
+ "docker:test:benchmark": "docker compose -f docker-compose.test.yml run test-benchmark",
107
+ "format": "biome format --write .",
108
+ "format:check": "biome format .",
104
109
  "lint": "oxlint .",
105
110
  "lint:fix": "oxlint . --fix",
106
111
  "typecheck": "tsc --noEmit",
@@ -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
 
@@ -1,10 +1,5 @@
1
- import { DEFAULT_CONFIG } from "../constants";
2
- import type {
3
- CacheHandler,
4
- DefaultVectorTypes,
5
- GetCacheType,
6
- VectorTypes,
7
- } from "../types";
1
+ import { DEFAULT_CONFIG } from '../constants';
2
+ import type { CacheHandler, DefaultVectorTypes, GetCacheType, VectorTypes } from '../types';
8
3
 
9
4
  interface CacheEntry<T = any> {
10
5
  value: T;
@@ -15,6 +10,7 @@ export class CacheManager<TTypes extends VectorTypes = DefaultVectorTypes> {
15
10
  private cacheHandler: CacheHandler | null = null;
16
11
  private memoryCache: Map<string, CacheEntry> = new Map();
17
12
  private cleanupInterval: Timer | null = null;
13
+ private inflight: Map<string, Promise<any>> = new Map();
18
14
 
19
15
  setCacheHandler(handler: CacheHandler) {
20
16
  this.cacheHandler = handler;
@@ -36,11 +32,7 @@ export class CacheManager<TTypes extends VectorTypes = DefaultVectorTypes> {
36
32
  return this.getFromMemoryCache(key, factory, ttl);
37
33
  }
38
34
 
39
- private async getFromMemoryCache<T>(
40
- key: string,
41
- factory: () => Promise<T>,
42
- ttl: number
43
- ): Promise<T> {
35
+ private async getFromMemoryCache<T>(key: string, factory: () => Promise<T>, ttl: number): Promise<T> {
44
36
  const now = Date.now();
45
37
  const cached = this.memoryCache.get(key);
46
38
 
@@ -48,10 +40,23 @@ export class CacheManager<TTypes extends VectorTypes = DefaultVectorTypes> {
48
40
  return cached!.value as T;
49
41
  }
50
42
 
51
- const value = await factory();
52
- this.setInMemoryCache(key, value, ttl);
43
+ // Deduplicate concurrent requests for the same key (cache stampede prevention)
44
+ if (this.inflight.has(key)) {
45
+ return (await this.inflight.get(key)!) as T;
46
+ }
53
47
 
54
- return value;
48
+ const promise = (async () => {
49
+ const value = await factory();
50
+ this.setInMemoryCache(key, value, ttl);
51
+ return value;
52
+ })();
53
+
54
+ this.inflight.set(key, promise);
55
+ try {
56
+ return await promise;
57
+ } finally {
58
+ this.inflight.delete(key);
59
+ }
55
60
  }
56
61
 
57
62
  private isCacheValid(entry: CacheEntry | undefined, now: number): boolean {
@@ -95,11 +100,7 @@ export class CacheManager<TTypes extends VectorTypes = DefaultVectorTypes> {
95
100
  }
96
101
  }
97
102
 
98
- async set<T = GetCacheType<TTypes>>(
99
- key: string,
100
- value: T,
101
- ttl: number = DEFAULT_CONFIG.CACHE_TTL
102
- ): Promise<void> {
103
+ async set<T = GetCacheType<TTypes>>(key: string, value: T, ttl: number = DEFAULT_CONFIG.CACHE_TTL): Promise<void> {
103
104
  if (ttl <= 0) {
104
105
  return;
105
106
  }
@@ -129,15 +130,9 @@ export class CacheManager<TTypes extends VectorTypes = DefaultVectorTypes> {
129
130
  return true;
130
131
  }
131
132
 
132
- generateKey(request: Request, options?: { authUser?: any }): string {
133
- const url = new URL(request.url);
134
- const parts = [
135
- request.method,
136
- url.pathname,
137
- url.search,
138
- options?.authUser?.id || "anonymous",
139
- ];
140
-
141
- return parts.join(":");
133
+ generateKey(request: Request & { _parsedUrl?: URL }, options?: { authUser?: any }): string {
134
+ const url = request._parsedUrl ?? new URL(request.url);
135
+ const userId = options?.authUser?.id != null ? String(options.authUser.id) : 'anonymous';
136
+ return `${request.method}:${url.pathname}:${url.search}:${userId}`;
142
137
  }
143
138
  }