vector-framework 0.8.2 → 0.9.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/dist/cli/index.js +89 -52
- package/dist/cli/index.js.map +1 -1
- package/dist/core/config-loader.d.ts +13 -0
- package/dist/core/config-loader.d.ts.map +1 -0
- package/dist/core/config-loader.js +166 -0
- package/dist/core/config-loader.js.map +1 -0
- package/dist/core/router.d.ts +1 -0
- package/dist/core/router.d.ts.map +1 -1
- package/dist/core/router.js +3 -0
- package/dist/core/router.js.map +1 -1
- package/dist/core/vector.d.ts +10 -12
- package/dist/core/vector.d.ts.map +1 -1
- package/dist/core/vector.js +36 -25
- package/dist/core/vector.js.map +1 -1
- package/dist/dev/route-scanner.d.ts.map +1 -1
- package/dist/dev/route-scanner.js +12 -1
- package/dist/dev/route-scanner.js.map +1 -1
- package/dist/http.d.ts +6 -1
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +13 -4
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +4 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -5
- package/dist/middleware/manager.d.ts +2 -1
- 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/types/index.d.ts +26 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/path.d.ts +3 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +9 -0
- package/dist/utils/path.js.map +1 -0
- package/package.json +3 -3
- package/src/cli/index.ts +103 -62
- package/src/core/config-loader.ts +193 -0
- package/src/core/router.ts +4 -0
- package/src/core/vector.ts +38 -32
- package/src/dev/route-scanner.ts +12 -1
- package/src/http.ts +21 -5
- package/src/index.ts +11 -16
- package/src/middleware/manager.ts +16 -4
- package/src/types/index.ts +44 -0
- package/src/utils/path.ts +9 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { toFileUrl } from '../utils/path';
|
|
3
|
+
import type {
|
|
4
|
+
AfterMiddlewareHandler,
|
|
5
|
+
BeforeMiddlewareHandler,
|
|
6
|
+
CacheHandler,
|
|
7
|
+
CorsOptions,
|
|
8
|
+
DefaultVectorTypes,
|
|
9
|
+
ProtectedHandler,
|
|
10
|
+
VectorConfig,
|
|
11
|
+
VectorConfigSchema,
|
|
12
|
+
VectorTypes,
|
|
13
|
+
} from '../types';
|
|
14
|
+
|
|
15
|
+
export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
16
|
+
private configPath: string;
|
|
17
|
+
private config: VectorConfigSchema<TTypes> | null = null;
|
|
18
|
+
|
|
19
|
+
constructor(configPath = 'vector.config.ts') {
|
|
20
|
+
this.configPath = resolve(process.cwd(), configPath);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async load(): Promise<VectorConfig<TTypes>> {
|
|
24
|
+
try {
|
|
25
|
+
// Try to load user config
|
|
26
|
+
const userConfigPath = toFileUrl(this.configPath);
|
|
27
|
+
const userConfig = await import(userConfigPath);
|
|
28
|
+
this.config = userConfig.default || userConfig;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
// No config file, use defaults
|
|
31
|
+
console.log('No vector.config.ts found, using defaults');
|
|
32
|
+
this.config = {};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Convert new config schema to legacy VectorConfig format
|
|
36
|
+
return await this.buildLegacyConfig();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private async buildLegacyConfig(): Promise<VectorConfig<TTypes>> {
|
|
40
|
+
const config: VectorConfig<TTypes> = {};
|
|
41
|
+
|
|
42
|
+
// Server configuration
|
|
43
|
+
if (this.config?.server) {
|
|
44
|
+
config.port = this.config.server.port;
|
|
45
|
+
config.hostname = this.config.server.hostname;
|
|
46
|
+
config.reusePort = this.config.server.reusePort;
|
|
47
|
+
config.development = this.config.server.development;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Routes configuration
|
|
51
|
+
if (this.config?.routes) {
|
|
52
|
+
config.routesDir = this.config.routes.dir || './routes';
|
|
53
|
+
config.autoDiscover = this.config.routes.autoDiscover !== false;
|
|
54
|
+
} else {
|
|
55
|
+
config.routesDir = './routes';
|
|
56
|
+
config.autoDiscover = true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// CORS configuration
|
|
60
|
+
if (this.config?.cors) {
|
|
61
|
+
if (typeof this.config.cors === 'boolean') {
|
|
62
|
+
config.cors = this.config.cors
|
|
63
|
+
? {
|
|
64
|
+
origin: '*',
|
|
65
|
+
credentials: true,
|
|
66
|
+
allowHeaders: 'Content-Type, Authorization',
|
|
67
|
+
allowMethods: 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
|
|
68
|
+
exposeHeaders: 'Authorization',
|
|
69
|
+
maxAge: 86400,
|
|
70
|
+
}
|
|
71
|
+
: undefined;
|
|
72
|
+
} else {
|
|
73
|
+
config.cors = this.config.cors as CorsOptions;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Load middleware - support both direct functions and file paths
|
|
78
|
+
if (this.config?.before) {
|
|
79
|
+
// Direct functions provided
|
|
80
|
+
console.log('Using direct before middleware functions:', this.config.before.length);
|
|
81
|
+
config.before = this.config.before;
|
|
82
|
+
} else if (this.config?.middleware?.before) {
|
|
83
|
+
// File paths provided (legacy)
|
|
84
|
+
console.log('Loading before middleware from file paths:', this.config.middleware.before);
|
|
85
|
+
config.before = await this.loadMiddleware<BeforeMiddlewareHandler<TTypes>>(
|
|
86
|
+
this.config.middleware.before
|
|
87
|
+
);
|
|
88
|
+
console.log('Loaded before middleware:', config.before?.length);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (this.config?.after) {
|
|
92
|
+
// Direct functions provided
|
|
93
|
+
console.log('Using direct after middleware functions:', this.config.after.length);
|
|
94
|
+
config.finally = this.config.after;
|
|
95
|
+
} else if (this.config?.middleware?.after) {
|
|
96
|
+
// File paths provided (legacy)
|
|
97
|
+
console.log('Loading after middleware from file paths:', this.config.middleware.after);
|
|
98
|
+
config.finally = await this.loadMiddleware<AfterMiddlewareHandler<TTypes>>(
|
|
99
|
+
this.config.middleware.after
|
|
100
|
+
);
|
|
101
|
+
console.log('Loaded after middleware:', config.finally?.length);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return config;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private async loadMiddleware<T>(paths: string[]): Promise<T[]> {
|
|
108
|
+
const middleware: T[] = [];
|
|
109
|
+
|
|
110
|
+
for (const path of paths) {
|
|
111
|
+
try {
|
|
112
|
+
const modulePath = resolve(process.cwd(), path);
|
|
113
|
+
const importPath = toFileUrl(modulePath);
|
|
114
|
+
const module = await import(importPath);
|
|
115
|
+
const handler = module.default || module;
|
|
116
|
+
|
|
117
|
+
if (typeof handler === 'function') {
|
|
118
|
+
middleware.push(handler as T);
|
|
119
|
+
} else {
|
|
120
|
+
console.warn(`Middleware at ${path} does not export a function`);
|
|
121
|
+
}
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error(`Failed to load middleware from ${path}:`, error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return middleware;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async loadAuthHandler(): Promise<ProtectedHandler<TTypes> | null> {
|
|
131
|
+
// Direct function provided
|
|
132
|
+
if (this.config?.auth) {
|
|
133
|
+
console.log('Using direct auth handler function');
|
|
134
|
+
return this.config.auth;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// File path provided (legacy)
|
|
138
|
+
if (!this.config?.handlers?.auth) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
const modulePath = resolve(process.cwd(), this.config.handlers.auth);
|
|
144
|
+
const importPath = toFileUrl(modulePath);
|
|
145
|
+
const module = await import(importPath);
|
|
146
|
+
const handler = module.default || module;
|
|
147
|
+
|
|
148
|
+
if (typeof handler === 'function') {
|
|
149
|
+
return handler as ProtectedHandler<TTypes>;
|
|
150
|
+
} else {
|
|
151
|
+
console.warn(`Auth handler at ${this.config.handlers.auth} does not export a function`);
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.error(`Failed to load auth handler from ${this.config.handlers.auth}:`, error);
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async loadCacheHandler(): Promise<CacheHandler | null> {
|
|
161
|
+
// Direct function provided
|
|
162
|
+
if (this.config?.cache) {
|
|
163
|
+
console.log('Using direct cache handler function');
|
|
164
|
+
return this.config.cache;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// File path provided (legacy)
|
|
168
|
+
if (!this.config?.handlers?.cache) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
const modulePath = resolve(process.cwd(), this.config.handlers.cache);
|
|
174
|
+
const importPath = toFileUrl(modulePath);
|
|
175
|
+
const module = await import(importPath);
|
|
176
|
+
const handler = module.default || module;
|
|
177
|
+
|
|
178
|
+
if (typeof handler === 'function') {
|
|
179
|
+
return handler as CacheHandler;
|
|
180
|
+
} else {
|
|
181
|
+
console.warn(`Cache handler at ${this.config.handlers.cache} does not export a function`);
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
} catch (error) {
|
|
185
|
+
console.error(`Failed to load cache handler from ${this.config.handlers.cache}:`, error);
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
getConfig(): VectorConfigSchema<TTypes> | null {
|
|
191
|
+
return this.config;
|
|
192
|
+
}
|
|
193
|
+
}
|
package/src/core/router.ts
CHANGED
package/src/core/vector.ts
CHANGED
|
@@ -5,9 +5,8 @@ import { CacheManager } from '../cache/manager';
|
|
|
5
5
|
import { RouteGenerator } from '../dev/route-generator';
|
|
6
6
|
import { RouteScanner } from '../dev/route-scanner';
|
|
7
7
|
import { MiddlewareManager } from '../middleware/manager';
|
|
8
|
+
import { toFileUrl } from '../utils/path';
|
|
8
9
|
import type {
|
|
9
|
-
AfterMiddlewareHandler,
|
|
10
|
-
BeforeMiddlewareHandler,
|
|
11
10
|
CacheHandler,
|
|
12
11
|
DefaultVectorTypes,
|
|
13
12
|
ProtectedHandler,
|
|
@@ -19,6 +18,7 @@ import type {
|
|
|
19
18
|
import { VectorRouter } from './router';
|
|
20
19
|
import { VectorServer } from './server';
|
|
21
20
|
|
|
21
|
+
// Internal-only class - not exposed to users
|
|
22
22
|
export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
23
23
|
private static instance: Vector<any>;
|
|
24
24
|
private router: VectorRouter<TTypes>;
|
|
@@ -43,6 +43,7 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
43
43
|
);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
// Internal use only - not exposed to users
|
|
46
47
|
static getInstance<T extends VectorTypes = DefaultVectorTypes>(): Vector<T> {
|
|
47
48
|
if (!Vector.instance) {
|
|
48
49
|
Vector.instance = new Vector<T>();
|
|
@@ -50,46 +51,38 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
50
51
|
return Vector.instance as Vector<T>;
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
set protected
|
|
54
|
+
// Internal method to set protected handler
|
|
55
|
+
setProtectedHandler(handler: ProtectedHandler<TTypes>) {
|
|
54
56
|
this._protectedHandler = handler;
|
|
55
57
|
this.authManager.setProtectedHandler(handler);
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
|
|
60
|
+
getProtectedHandler(): ProtectedHandler<TTypes> | null {
|
|
59
61
|
return this._protectedHandler;
|
|
60
62
|
}
|
|
61
63
|
|
|
62
|
-
set cache
|
|
64
|
+
// Internal method to set cache handler
|
|
65
|
+
setCacheHandler(handler: CacheHandler) {
|
|
63
66
|
this._cacheHandler = handler;
|
|
64
67
|
this.cacheManager.setCacheHandler(handler);
|
|
65
68
|
}
|
|
66
69
|
|
|
67
|
-
|
|
70
|
+
getCacheHandler(): CacheHandler | null {
|
|
68
71
|
return this._cacheHandler;
|
|
69
72
|
}
|
|
70
73
|
|
|
71
|
-
|
|
74
|
+
// Internal method to add route
|
|
75
|
+
addRoute(options: RouteOptions<TTypes>, handler: RouteHandler<TTypes>): RouteEntry {
|
|
72
76
|
return this.router.route(options, handler);
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return this;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
before(...middleware: BeforeMiddlewareHandler<TTypes>[]): this {
|
|
81
|
-
this.middlewareManager.addBefore(...middleware);
|
|
82
|
-
return this;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
finally(...middleware: AfterMiddlewareHandler<TTypes>[]): this {
|
|
86
|
-
this.middlewareManager.addFinally(...middleware);
|
|
87
|
-
return this;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async serve(config?: VectorConfig<TTypes>): Promise<Server> {
|
|
79
|
+
// Internal method to start server - only called by CLI
|
|
80
|
+
async startServer(config?: VectorConfig<TTypes>): Promise<Server> {
|
|
91
81
|
this.config = { ...this.config, ...config };
|
|
92
82
|
|
|
83
|
+
// Clear previous middleware to avoid accumulation across multiple starts
|
|
84
|
+
this.middlewareManager.clear();
|
|
85
|
+
|
|
93
86
|
if (config?.before) {
|
|
94
87
|
this.middlewareManager.addBefore(...config.before);
|
|
95
88
|
}
|
|
@@ -129,17 +122,19 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
129
122
|
|
|
130
123
|
for (const route of routes) {
|
|
131
124
|
try {
|
|
132
|
-
|
|
133
|
-
const importPath =
|
|
134
|
-
process.platform === 'win32'
|
|
135
|
-
? `file:///${route.path.replace(/\\/g, '/')}`
|
|
136
|
-
: route.path;
|
|
125
|
+
const importPath = toFileUrl(route.path);
|
|
137
126
|
|
|
138
127
|
const module = await import(importPath);
|
|
139
128
|
const exported = route.name === 'default' ? module.default : module[route.name];
|
|
140
129
|
|
|
141
130
|
if (exported) {
|
|
142
|
-
if (this.
|
|
131
|
+
if (this.isRouteDefinition(exported)) {
|
|
132
|
+
// Use router.route() to ensure middleware is applied
|
|
133
|
+
const routeDef = exported as any;
|
|
134
|
+
this.router.route(routeDef.options, routeDef.handler);
|
|
135
|
+
this.logRouteLoaded(routeDef.options);
|
|
136
|
+
} else if (this.isRouteEntry(exported)) {
|
|
137
|
+
// Legacy support for direct RouteEntry (won't have middleware)
|
|
143
138
|
this.router.addRoute(exported as RouteEntry);
|
|
144
139
|
this.logRouteLoaded(exported as RouteEntry);
|
|
145
140
|
} else if (typeof exported === 'function') {
|
|
@@ -185,6 +180,10 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
185
180
|
return Array.isArray(value) && value.length >= 3;
|
|
186
181
|
}
|
|
187
182
|
|
|
183
|
+
private isRouteDefinition(value: any): boolean {
|
|
184
|
+
return value && typeof value === 'object' && 'entry' in value && 'options' in value && 'handler' in value;
|
|
185
|
+
}
|
|
186
|
+
|
|
188
187
|
private logRouteLoaded(route: RouteEntry | RouteOptions): void {
|
|
189
188
|
if (Array.isArray(route)) {
|
|
190
189
|
console.log(` ✓ Loaded route: ${route[0]} ${route[3] || route[1]}`);
|
|
@@ -198,6 +197,9 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
198
197
|
this.server.stop();
|
|
199
198
|
this.server = null;
|
|
200
199
|
}
|
|
200
|
+
// Don't reset managers - they should persist for the singleton
|
|
201
|
+
// Only clear route-specific state if needed
|
|
202
|
+
this.router.clearRoutes();
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
getServer(): VectorServer<TTypes> | null {
|
|
@@ -215,8 +217,12 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
215
217
|
getAuthManager(): AuthManager<TTypes> {
|
|
216
218
|
return this.authManager;
|
|
217
219
|
}
|
|
218
|
-
}
|
|
219
220
|
|
|
220
|
-
|
|
221
|
+
// Reset instance for testing purposes only
|
|
222
|
+
static resetInstance(): void {
|
|
223
|
+
Vector.instance = null as any;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
221
226
|
|
|
222
|
-
|
|
227
|
+
// Export for internal use only
|
|
228
|
+
export const getVectorInstance = Vector.getInstance;
|
package/src/dev/route-scanner.ts
CHANGED
|
@@ -64,7 +64,18 @@ export class RouteScanner {
|
|
|
64
64
|
for (const [name, value] of Object.entries(module)) {
|
|
65
65
|
if (name === 'default') continue;
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
// Check for new RouteDefinition format
|
|
68
|
+
if (value && typeof value === 'object' && 'entry' in value && 'options' in value && 'handler' in value) {
|
|
69
|
+
const routeDef = value as any;
|
|
70
|
+
routes.push({
|
|
71
|
+
name,
|
|
72
|
+
path: fullPath,
|
|
73
|
+
method: routeDef.options.method as string,
|
|
74
|
+
options: routeDef.options,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
// Legacy RouteEntry format support
|
|
78
|
+
else if (Array.isArray(value) && value.length >= 4) {
|
|
68
79
|
const [method, , , path] = value;
|
|
69
80
|
routes.push({
|
|
70
81
|
name,
|
package/src/http.ts
CHANGED
|
@@ -33,13 +33,19 @@ interface ExtendedApiOptions extends ApiOptions {
|
|
|
33
33
|
path: string;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
export interface RouteDefinition<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
37
|
+
entry: RouteEntry;
|
|
38
|
+
options: ExtendedApiOptions;
|
|
39
|
+
handler: (req: VectorRequest<TTypes>) => Promise<unknown>;
|
|
40
|
+
}
|
|
41
|
+
|
|
36
42
|
export function route<TTypes extends VectorTypes = DefaultVectorTypes>(
|
|
37
43
|
options: ExtendedApiOptions,
|
|
38
44
|
fn: (req: VectorRequest<TTypes>) => Promise<unknown>
|
|
39
|
-
):
|
|
45
|
+
): RouteDefinition<TTypes> {
|
|
40
46
|
const handler = api(options, fn);
|
|
41
47
|
|
|
42
|
-
|
|
48
|
+
const entry: RouteEntry = [
|
|
43
49
|
options.method.toUpperCase(),
|
|
44
50
|
RegExp(
|
|
45
51
|
`^${
|
|
@@ -54,6 +60,12 @@ export function route<TTypes extends VectorTypes = DefaultVectorTypes>(
|
|
|
54
60
|
[handler],
|
|
55
61
|
options.path,
|
|
56
62
|
];
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
entry,
|
|
66
|
+
options,
|
|
67
|
+
handler: fn
|
|
68
|
+
};
|
|
57
69
|
}
|
|
58
70
|
|
|
59
71
|
function stringifyData(data: unknown): string {
|
|
@@ -251,9 +263,11 @@ export const protectedRoute = async <
|
|
|
251
263
|
responseContentType?: string
|
|
252
264
|
) => {
|
|
253
265
|
// Get the Vector instance to access the protected handler
|
|
254
|
-
const
|
|
266
|
+
const { getVectorInstance } = await import("./core/vector");
|
|
267
|
+
const vector = getVectorInstance();
|
|
255
268
|
|
|
256
|
-
|
|
269
|
+
const protectedHandler = vector.getProtectedHandler();
|
|
270
|
+
if (!protectedHandler) {
|
|
257
271
|
throw APIError.unauthorized(
|
|
258
272
|
"Authentication not configured",
|
|
259
273
|
responseContentType
|
|
@@ -261,7 +275,7 @@ export const protectedRoute = async <
|
|
|
261
275
|
}
|
|
262
276
|
|
|
263
277
|
try {
|
|
264
|
-
const authUser = await
|
|
278
|
+
const authUser = await protectedHandler(request as any);
|
|
265
279
|
request.authUser = authUser as GetAuthType<TTypes>;
|
|
266
280
|
} catch (error) {
|
|
267
281
|
throw APIError.unauthorized(
|
|
@@ -292,6 +306,8 @@ export function api<TTypes extends VectorTypes = DefaultVectorTypes>(
|
|
|
292
306
|
responseContentType = CONTENT_TYPES.JSON,
|
|
293
307
|
} = options;
|
|
294
308
|
|
|
309
|
+
// For backward compatibility with direct route usage (not auto-discovered)
|
|
310
|
+
// This wrapper is only used when routes are NOT auto-discovered
|
|
295
311
|
return async (request: IRequest) => {
|
|
296
312
|
if (!expose) {
|
|
297
313
|
return APIError.forbidden("Forbidden");
|
package/src/index.ts
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
import { route } from
|
|
3
|
-
import type { DefaultVectorTypes, VectorTypes } from './types';
|
|
1
|
+
// Public exports for route definitions only
|
|
2
|
+
import { route } from "./http";
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
export { CacheManager } from './cache/manager';
|
|
8
|
-
export { APIError, createResponse } from './http';
|
|
9
|
-
export { MiddlewareManager } from './middleware/manager';
|
|
10
|
-
export * from './types';
|
|
4
|
+
// Export route function for defining routes
|
|
5
|
+
export { route };
|
|
11
6
|
|
|
12
|
-
//
|
|
13
|
-
export
|
|
14
|
-
return Vector.getInstance<TTypes>();
|
|
15
|
-
}
|
|
7
|
+
// Export utilities for route handlers
|
|
8
|
+
export { APIError, createResponse } from "./http";
|
|
16
9
|
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
// Export types for TypeScript users
|
|
11
|
+
export * from "./types";
|
|
12
|
+
|
|
13
|
+
// Note: Vector framework is now config-driven and runs via CLI
|
|
14
|
+
// Usage: Create vector.config.ts and run 'vector dev' or 'vector start'
|
|
@@ -4,9 +4,11 @@ import type {
|
|
|
4
4
|
DefaultVectorTypes,
|
|
5
5
|
VectorRequest,
|
|
6
6
|
VectorTypes,
|
|
7
|
-
} from
|
|
7
|
+
} from "../types";
|
|
8
8
|
|
|
9
|
-
export class MiddlewareManager<
|
|
9
|
+
export class MiddlewareManager<
|
|
10
|
+
TTypes extends VectorTypes = DefaultVectorTypes
|
|
11
|
+
> {
|
|
10
12
|
private beforeHandlers: BeforeMiddlewareHandler<TTypes>[] = [];
|
|
11
13
|
private finallyHandlers: AfterMiddlewareHandler<TTypes>[] = [];
|
|
12
14
|
|
|
@@ -18,7 +20,9 @@ export class MiddlewareManager<TTypes extends VectorTypes = DefaultVectorTypes>
|
|
|
18
20
|
this.finallyHandlers.push(...handlers);
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
async executeBefore(
|
|
23
|
+
async executeBefore(
|
|
24
|
+
request: VectorRequest<TTypes>
|
|
25
|
+
): Promise<VectorRequest<TTypes> | Response> {
|
|
22
26
|
let currentRequest = request;
|
|
23
27
|
|
|
24
28
|
for (const handler of this.beforeHandlers) {
|
|
@@ -34,7 +38,10 @@ export class MiddlewareManager<TTypes extends VectorTypes = DefaultVectorTypes>
|
|
|
34
38
|
return currentRequest;
|
|
35
39
|
}
|
|
36
40
|
|
|
37
|
-
async executeFinally(
|
|
41
|
+
async executeFinally(
|
|
42
|
+
response: Response,
|
|
43
|
+
request: VectorRequest<TTypes>
|
|
44
|
+
): Promise<Response> {
|
|
38
45
|
let currentResponse = response;
|
|
39
46
|
|
|
40
47
|
for (const handler of this.finallyHandlers) {
|
|
@@ -50,4 +57,9 @@ export class MiddlewareManager<TTypes extends VectorTypes = DefaultVectorTypes>
|
|
|
50
57
|
manager.finallyHandlers = [...this.finallyHandlers];
|
|
51
58
|
return manager;
|
|
52
59
|
}
|
|
60
|
+
|
|
61
|
+
clear(): void {
|
|
62
|
+
this.beforeHandlers = [];
|
|
63
|
+
this.finallyHandlers = [];
|
|
64
|
+
}
|
|
53
65
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -72,6 +72,7 @@ export interface RouteOptions<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
72
72
|
metadata?: GetMetadataType<TTypes>;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
// Legacy config interface - will be deprecated
|
|
75
76
|
export interface VectorConfig<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
76
77
|
port?: number;
|
|
77
78
|
hostname?: string;
|
|
@@ -84,6 +85,49 @@ export interface VectorConfig<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
84
85
|
autoDiscover?: boolean;
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
// New config-driven schema
|
|
89
|
+
export interface VectorConfigSchema<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
90
|
+
// Server configuration
|
|
91
|
+
server?: {
|
|
92
|
+
port?: number;
|
|
93
|
+
hostname?: string;
|
|
94
|
+
reusePort?: boolean;
|
|
95
|
+
development?: boolean;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// Routes configuration
|
|
99
|
+
routes?: {
|
|
100
|
+
dir?: string;
|
|
101
|
+
autoDiscover?: boolean;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Middleware configuration - supports both file paths and direct functions
|
|
105
|
+
middleware?: {
|
|
106
|
+
before?: string[];
|
|
107
|
+
after?: string[];
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Direct middleware functions (preferred approach)
|
|
111
|
+
before?: BeforeMiddlewareHandler<TTypes>[];
|
|
112
|
+
after?: AfterMiddlewareHandler<TTypes>[];
|
|
113
|
+
|
|
114
|
+
// Handler configuration - supports both file paths and direct functions
|
|
115
|
+
handlers?: {
|
|
116
|
+
auth?: string;
|
|
117
|
+
cache?: string;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// Direct handler functions (preferred approach)
|
|
121
|
+
auth?: ProtectedHandler<TTypes>;
|
|
122
|
+
cache?: CacheHandler;
|
|
123
|
+
|
|
124
|
+
// CORS configuration
|
|
125
|
+
cors?: CorsOptions | boolean;
|
|
126
|
+
|
|
127
|
+
// Custom types for TypeScript
|
|
128
|
+
types?: VectorTypes;
|
|
129
|
+
}
|
|
130
|
+
|
|
87
131
|
export interface CorsOptions {
|
|
88
132
|
origin?: string | string[] | ((origin: string) => boolean);
|
|
89
133
|
credentials?: boolean;
|