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.
Files changed (47) hide show
  1. package/dist/cli/index.js +89 -52
  2. package/dist/cli/index.js.map +1 -1
  3. package/dist/core/config-loader.d.ts +13 -0
  4. package/dist/core/config-loader.d.ts.map +1 -0
  5. package/dist/core/config-loader.js +166 -0
  6. package/dist/core/config-loader.js.map +1 -0
  7. package/dist/core/router.d.ts +1 -0
  8. package/dist/core/router.d.ts.map +1 -1
  9. package/dist/core/router.js +3 -0
  10. package/dist/core/router.js.map +1 -1
  11. package/dist/core/vector.d.ts +10 -12
  12. package/dist/core/vector.d.ts.map +1 -1
  13. package/dist/core/vector.js +36 -25
  14. package/dist/core/vector.js.map +1 -1
  15. package/dist/dev/route-scanner.d.ts.map +1 -1
  16. package/dist/dev/route-scanner.js +12 -1
  17. package/dist/dev/route-scanner.js.map +1 -1
  18. package/dist/http.d.ts +6 -1
  19. package/dist/http.d.ts.map +1 -1
  20. package/dist/http.js +13 -4
  21. package/dist/http.js.map +1 -1
  22. package/dist/index.d.ts +4 -12
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +3 -3
  25. package/dist/index.js.map +1 -1
  26. package/dist/index.mjs +5 -5
  27. package/dist/middleware/manager.d.ts +2 -1
  28. package/dist/middleware/manager.d.ts.map +1 -1
  29. package/dist/middleware/manager.js +4 -0
  30. package/dist/middleware/manager.js.map +1 -1
  31. package/dist/types/index.d.ts +26 -0
  32. package/dist/types/index.d.ts.map +1 -1
  33. package/dist/utils/path.d.ts +3 -0
  34. package/dist/utils/path.d.ts.map +1 -0
  35. package/dist/utils/path.js +9 -0
  36. package/dist/utils/path.js.map +1 -0
  37. package/package.json +3 -3
  38. package/src/cli/index.ts +103 -62
  39. package/src/core/config-loader.ts +193 -0
  40. package/src/core/router.ts +4 -0
  41. package/src/core/vector.ts +38 -32
  42. package/src/dev/route-scanner.ts +12 -1
  43. package/src/http.ts +21 -5
  44. package/src/index.ts +11 -16
  45. package/src/middleware/manager.ts +16 -4
  46. package/src/types/index.ts +44 -0
  47. 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
+ }
@@ -256,4 +256,8 @@ export class VectorRouter<TTypes extends VectorTypes = DefaultVectorTypes> {
256
256
 
257
257
  return APIError.notFound('Route not found');
258
258
  }
259
+
260
+ clearRoutes(): void {
261
+ this.routes = [];
262
+ }
259
263
  }
@@ -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(handler: ProtectedHandler<TTypes>) {
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
- get protected(): ProtectedHandler<TTypes> | null {
60
+ getProtectedHandler(): ProtectedHandler<TTypes> | null {
59
61
  return this._protectedHandler;
60
62
  }
61
63
 
62
- set cache(handler: CacheHandler) {
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
- get cache(): CacheHandler | null {
70
+ getCacheHandler(): CacheHandler | null {
68
71
  return this._cacheHandler;
69
72
  }
70
73
 
71
- route(options: RouteOptions<TTypes>, handler: RouteHandler<TTypes>): RouteEntry {
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
- use(...middleware: BeforeMiddlewareHandler<TTypes>[]): this {
76
- this.middlewareManager.addBefore(...middleware);
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
- // Convert Windows paths to URLs for import
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.isRouteEntry(exported)) {
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
- const vector = Vector.getInstance();
221
+ // Reset instance for testing purposes only
222
+ static resetInstance(): void {
223
+ Vector.instance = null as any;
224
+ }
225
+ }
221
226
 
222
- export default vector;
227
+ // Export for internal use only
228
+ export const getVectorInstance = Vector.getInstance;
@@ -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
- if (Array.isArray(value) && value.length >= 4) {
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
- ): RouteEntry {
45
+ ): RouteDefinition<TTypes> {
40
46
  const handler = api(options, fn);
41
47
 
42
- return [
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 vector = (await import("./core/vector")).default;
266
+ const { getVectorInstance } = await import("./core/vector");
267
+ const vector = getVectorInstance();
255
268
 
256
- if (!vector.protected) {
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 vector.protected(request as any);
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
- import { Vector } from './core/vector';
2
- import { route } from './http';
3
- import type { DefaultVectorTypes, VectorTypes } from './types';
1
+ // Public exports for route definitions only
2
+ import { route } from "./http";
4
3
 
5
- export { route, Vector };
6
- export { AuthManager } from './auth/protected';
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
- // Create a typed Vector instance with custom types
13
- export function createVector<TTypes extends VectorTypes = DefaultVectorTypes>(): Vector<TTypes> {
14
- return Vector.getInstance<TTypes>();
15
- }
7
+ // Export utilities for route handlers
8
+ export { APIError, createResponse } from "./http";
16
9
 
17
- // Default vector instance with default AuthUser type
18
- const vector = Vector.getInstance();
19
- export default vector;
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 '../types';
7
+ } from "../types";
8
8
 
9
- export class MiddlewareManager<TTypes extends VectorTypes = DefaultVectorTypes> {
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(request: VectorRequest<TTypes>): Promise<VectorRequest<TTypes> | Response> {
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(response: Response, request: VectorRequest<TTypes>): Promise<Response> {
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
  }
@@ -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;
@@ -0,0 +1,9 @@
1
+ export function toFileUrl(path: string): string {
2
+ return process.platform === 'win32'
3
+ ? `file:///${path.replace(/\\/g, '/')}`
4
+ : path;
5
+ }
6
+
7
+ export function normalizePath(path: string): string {
8
+ return path.replace(/\\/g, '/').replace(/\/+/g, '/');
9
+ }