vector-framework 0.9.9 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/cache/manager.d.ts +5 -2
- package/dist/cache/manager.d.ts.map +1 -1
- package/dist/cache/manager.js +21 -7
- package/dist/cache/manager.js.map +1 -1
- package/dist/cli/index.js +76 -98
- package/dist/cli/index.js.map +1 -1
- package/dist/cli.js +134 -69
- package/dist/core/config-loader.d.ts +2 -2
- package/dist/core/config-loader.d.ts.map +1 -1
- package/dist/core/config-loader.js +16 -21
- package/dist/core/config-loader.js.map +1 -1
- package/dist/core/router.d.ts +2 -0
- package/dist/core/router.d.ts.map +1 -1
- package/dist/core/router.js +52 -16
- package/dist/core/router.js.map +1 -1
- package/dist/core/server.d.ts +4 -3
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +40 -20
- package/dist/core/server.js.map +1 -1
- package/dist/core/vector.d.ts +7 -7
- package/dist/core/vector.d.ts.map +1 -1
- package/dist/core/vector.js +20 -21
- package/dist/core/vector.js.map +1 -1
- package/dist/dev/route-scanner.d.ts +1 -1
- package/dist/dev/route-scanner.d.ts.map +1 -1
- package/dist/dev/route-scanner.js +40 -42
- package/dist/dev/route-scanner.js.map +1 -1
- package/dist/http.d.ts +2 -2
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +70 -63
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/index.mjs +4 -4
- package/dist/middleware/manager.d.ts +1 -1
- package/dist/middleware/manager.d.ts.map +1 -1
- package/dist/middleware/manager.js.map +1 -1
- package/dist/utils/path.d.ts +1 -0
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js +9 -3
- package/dist/utils/path.js.map +1 -1
- package/package.json +14 -9
- package/src/cache/manager.ts +23 -14
- package/src/cli/index.ts +83 -117
- package/src/core/config-loader.ts +19 -27
- package/src/core/router.ts +52 -18
- package/src/core/server.ts +43 -30
- package/src/core/vector.ts +25 -35
- package/src/dev/route-scanner.ts +41 -47
- package/src/http.ts +82 -112
- package/src/index.ts +3 -3
- package/src/middleware/manager.ts +4 -11
- package/src/utils/path.ts +13 -4
package/src/core/server.ts
CHANGED
|
@@ -1,56 +1,66 @@
|
|
|
1
|
-
import type { Server } from
|
|
2
|
-
import { cors } from
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
DefaultVectorTypes,
|
|
6
|
-
VectorConfig,
|
|
7
|
-
VectorTypes,
|
|
8
|
-
} from "../types";
|
|
9
|
-
import type { VectorRouter } from "./router";
|
|
1
|
+
import type { Server } from 'bun';
|
|
2
|
+
import { cors } from 'itty-router';
|
|
3
|
+
import type { CorsOptions, DefaultVectorTypes, VectorConfig, VectorTypes } from '../types';
|
|
4
|
+
import type { VectorRouter } from './router';
|
|
10
5
|
|
|
11
6
|
export class VectorServer<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
12
7
|
private server: Server | null = null;
|
|
13
8
|
private router: VectorRouter<TTypes>;
|
|
14
9
|
private config: VectorConfig<TTypes>;
|
|
15
10
|
private corsHandler: any;
|
|
11
|
+
private corsHeaders: Record<string, string> | null = null;
|
|
16
12
|
|
|
17
13
|
constructor(router: VectorRouter<TTypes>, config: VectorConfig<TTypes>) {
|
|
18
14
|
this.router = router;
|
|
19
15
|
this.config = config;
|
|
20
16
|
|
|
21
17
|
if (config.cors) {
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
);
|
|
18
|
+
const opts = this.normalizeCorsOptions(config.cors);
|
|
19
|
+
const { preflight, corsify } = cors(opts);
|
|
25
20
|
this.corsHandler = { preflight, corsify };
|
|
21
|
+
|
|
22
|
+
// Pre-build static CORS headers when origin is a fixed string.
|
|
23
|
+
// Avoids cloning the Response on every request via corsify().
|
|
24
|
+
if (typeof opts.origin === 'string') {
|
|
25
|
+
this.corsHeaders = {
|
|
26
|
+
'access-control-allow-origin': opts.origin,
|
|
27
|
+
'access-control-allow-methods': opts.allowMethods,
|
|
28
|
+
'access-control-allow-headers': opts.allowHeaders,
|
|
29
|
+
'access-control-expose-headers': opts.exposeHeaders,
|
|
30
|
+
'access-control-max-age': String(opts.maxAge),
|
|
31
|
+
};
|
|
32
|
+
if (opts.credentials) {
|
|
33
|
+
this.corsHeaders['access-control-allow-credentials'] = 'true';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
26
36
|
}
|
|
27
37
|
}
|
|
28
38
|
|
|
29
39
|
private normalizeCorsOptions(options: CorsOptions): any {
|
|
30
40
|
return {
|
|
31
|
-
origin: options.origin ||
|
|
41
|
+
origin: options.origin || '*',
|
|
32
42
|
credentials: options.credentials !== false,
|
|
33
43
|
allowHeaders: Array.isArray(options.allowHeaders)
|
|
34
|
-
? options.allowHeaders.join(
|
|
35
|
-
: options.allowHeaders ||
|
|
44
|
+
? options.allowHeaders.join(', ')
|
|
45
|
+
: options.allowHeaders || 'Content-Type, Authorization',
|
|
36
46
|
allowMethods: Array.isArray(options.allowMethods)
|
|
37
|
-
? options.allowMethods.join(
|
|
38
|
-
: options.allowMethods ||
|
|
47
|
+
? options.allowMethods.join(', ')
|
|
48
|
+
: options.allowMethods || 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
|
|
39
49
|
exposeHeaders: Array.isArray(options.exposeHeaders)
|
|
40
|
-
? options.exposeHeaders.join(
|
|
41
|
-
: options.exposeHeaders ||
|
|
50
|
+
? options.exposeHeaders.join(', ')
|
|
51
|
+
: options.exposeHeaders || 'Authorization',
|
|
42
52
|
maxAge: options.maxAge || 86400,
|
|
43
53
|
};
|
|
44
54
|
}
|
|
45
55
|
|
|
46
56
|
async start(): Promise<Server> {
|
|
47
57
|
const port = this.config.port || 3000;
|
|
48
|
-
const hostname = this.config.hostname ||
|
|
58
|
+
const hostname = this.config.hostname || 'localhost';
|
|
49
59
|
|
|
50
60
|
const fetch = async (request: Request): Promise<Response> => {
|
|
51
61
|
try {
|
|
52
62
|
// Handle CORS preflight
|
|
53
|
-
if (this.corsHandler && request.method ===
|
|
63
|
+
if (this.corsHandler && request.method === 'OPTIONS') {
|
|
54
64
|
return this.corsHandler.preflight(request);
|
|
55
65
|
}
|
|
56
66
|
|
|
@@ -58,14 +68,18 @@ export class VectorServer<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
58
68
|
let response = await this.router.handle(request);
|
|
59
69
|
|
|
60
70
|
// Apply CORS headers if configured
|
|
61
|
-
if (this.
|
|
71
|
+
if (this.corsHeaders) {
|
|
72
|
+
for (const [k, v] of Object.entries(this.corsHeaders)) {
|
|
73
|
+
response.headers.set(k, v);
|
|
74
|
+
}
|
|
75
|
+
} else if (this.corsHandler) {
|
|
62
76
|
response = this.corsHandler.corsify(response, request);
|
|
63
77
|
}
|
|
64
78
|
|
|
65
79
|
return response;
|
|
66
80
|
} catch (error) {
|
|
67
|
-
console.error(
|
|
68
|
-
return new Response(
|
|
81
|
+
console.error('Server error:', error);
|
|
82
|
+
return new Response('Internal Server Error', { status: 500 });
|
|
69
83
|
}
|
|
70
84
|
};
|
|
71
85
|
|
|
@@ -77,8 +91,8 @@ export class VectorServer<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
77
91
|
fetch,
|
|
78
92
|
idleTimeout: this.config.idleTimeout || 60,
|
|
79
93
|
error: (error) => {
|
|
80
|
-
console.error(
|
|
81
|
-
return new Response(
|
|
94
|
+
console.error('[ERROR] Server error:', error);
|
|
95
|
+
return new Response('Internal Server Error', { status: 500 });
|
|
82
96
|
},
|
|
83
97
|
});
|
|
84
98
|
|
|
@@ -87,8 +101,7 @@ export class VectorServer<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
87
101
|
throw new Error(`Failed to start server on ${hostname}:${port} - server object is invalid`);
|
|
88
102
|
}
|
|
89
103
|
|
|
90
|
-
// Server logs are handled by CLI
|
|
91
|
-
console.log(`→ Vector server running at http://${hostname}:${port}`);
|
|
104
|
+
// Server logs are handled by CLI
|
|
92
105
|
|
|
93
106
|
return this.server;
|
|
94
107
|
} catch (error: any) {
|
|
@@ -112,7 +125,7 @@ export class VectorServer<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
112
125
|
if (this.server) {
|
|
113
126
|
this.server.stop();
|
|
114
127
|
this.server = null;
|
|
115
|
-
console.log(
|
|
128
|
+
console.log('Server stopped');
|
|
116
129
|
}
|
|
117
130
|
}
|
|
118
131
|
|
|
@@ -125,7 +138,7 @@ export class VectorServer<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
125
138
|
}
|
|
126
139
|
|
|
127
140
|
getHostname(): string {
|
|
128
|
-
return this.server?.hostname || this.config.hostname ||
|
|
141
|
+
return this.server?.hostname || this.config.hostname || 'localhost';
|
|
129
142
|
}
|
|
130
143
|
|
|
131
144
|
getUrl(): string {
|
package/src/core/vector.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { Server } from
|
|
2
|
-
import type { RouteEntry } from
|
|
3
|
-
import { AuthManager } from
|
|
4
|
-
import { CacheManager } from
|
|
5
|
-
import { RouteGenerator } from
|
|
6
|
-
import { RouteScanner } from
|
|
7
|
-
import { MiddlewareManager } from
|
|
8
|
-
import { toFileUrl } from
|
|
1
|
+
import type { Server } from 'bun';
|
|
2
|
+
import type { RouteEntry } from 'itty-router';
|
|
3
|
+
import { AuthManager } from '../auth/protected';
|
|
4
|
+
import { CacheManager } from '../cache/manager';
|
|
5
|
+
import { RouteGenerator } from '../dev/route-generator';
|
|
6
|
+
import { RouteScanner } from '../dev/route-scanner';
|
|
7
|
+
import { MiddlewareManager } from '../middleware/manager';
|
|
8
|
+
import { toFileUrl } from '../utils/path';
|
|
9
9
|
import type {
|
|
10
10
|
CacheHandler,
|
|
11
11
|
DefaultVectorTypes,
|
|
@@ -14,9 +14,9 @@ import type {
|
|
|
14
14
|
RouteOptions,
|
|
15
15
|
VectorConfig,
|
|
16
16
|
VectorTypes,
|
|
17
|
-
} from
|
|
18
|
-
import { VectorRouter } from
|
|
19
|
-
import { VectorServer } from
|
|
17
|
+
} from '../types';
|
|
18
|
+
import { VectorRouter } from './router';
|
|
19
|
+
import { VectorServer } from './server';
|
|
20
20
|
|
|
21
21
|
// Internal-only class - not exposed to users
|
|
22
22
|
export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
@@ -72,10 +72,7 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
// Internal method to add route
|
|
75
|
-
addRoute(
|
|
76
|
-
options: RouteOptions<TTypes>,
|
|
77
|
-
handler: RouteHandler<TTypes>
|
|
78
|
-
): RouteEntry {
|
|
75
|
+
addRoute(options: RouteOptions<TTypes>, handler: RouteHandler<TTypes>): RouteEntry {
|
|
79
76
|
return this.router.route(options, handler);
|
|
80
77
|
}
|
|
81
78
|
|
|
@@ -110,7 +107,7 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
110
107
|
}
|
|
111
108
|
|
|
112
109
|
private async discoverRoutes() {
|
|
113
|
-
const routesDir = this.config.routesDir ||
|
|
110
|
+
const routesDir = this.config.routesDir || './routes';
|
|
114
111
|
const excludePatterns = this.config.routeExcludePatterns;
|
|
115
112
|
|
|
116
113
|
// Always create a new RouteScanner with the current config's routesDir
|
|
@@ -134,8 +131,7 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
134
131
|
const importPath = toFileUrl(route.path);
|
|
135
132
|
|
|
136
133
|
const module = await import(importPath);
|
|
137
|
-
const exported =
|
|
138
|
-
route.name === "default" ? module.default : module[route.name];
|
|
134
|
+
const exported = route.name === 'default' ? module.default : module[route.name];
|
|
139
135
|
|
|
140
136
|
if (exported) {
|
|
141
137
|
if (this.isRouteDefinition(exported)) {
|
|
@@ -147,16 +143,13 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
147
143
|
// Legacy support for direct RouteEntry (won't have middleware)
|
|
148
144
|
this.router.addRoute(exported as RouteEntry);
|
|
149
145
|
this.logRouteLoaded(exported as RouteEntry);
|
|
150
|
-
} else if (typeof exported ===
|
|
146
|
+
} else if (typeof exported === 'function') {
|
|
151
147
|
this.router.route(route.options as any, exported);
|
|
152
148
|
this.logRouteLoaded(route.options);
|
|
153
149
|
}
|
|
154
150
|
}
|
|
155
151
|
} catch (error) {
|
|
156
|
-
console.error(
|
|
157
|
-
`Failed to load route ${route.name} from ${route.path}:`,
|
|
158
|
-
error
|
|
159
|
-
);
|
|
152
|
+
console.error(`Failed to load route ${route.name} from ${route.path}:`, error);
|
|
160
153
|
}
|
|
161
154
|
}
|
|
162
155
|
|
|
@@ -164,24 +157,21 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
164
157
|
this.router.sortRoutes();
|
|
165
158
|
}
|
|
166
159
|
} catch (error) {
|
|
167
|
-
if (
|
|
168
|
-
(
|
|
169
|
-
(error as any).code !== "ENOTDIR"
|
|
170
|
-
) {
|
|
171
|
-
console.error("Failed to discover routes:", error);
|
|
160
|
+
if ((error as any).code !== 'ENOENT' && (error as any).code !== 'ENOTDIR') {
|
|
161
|
+
console.error('Failed to discover routes:', error);
|
|
172
162
|
}
|
|
173
163
|
}
|
|
174
164
|
}
|
|
175
165
|
|
|
176
166
|
async loadRoute(routeModule: any) {
|
|
177
|
-
if (typeof routeModule ===
|
|
167
|
+
if (typeof routeModule === 'function') {
|
|
178
168
|
const routeEntry = routeModule();
|
|
179
169
|
if (Array.isArray(routeEntry)) {
|
|
180
170
|
this.router.addRoute(routeEntry as RouteEntry);
|
|
181
171
|
}
|
|
182
|
-
} else if (routeModule && typeof routeModule ===
|
|
172
|
+
} else if (routeModule && typeof routeModule === 'object') {
|
|
183
173
|
for (const [, value] of Object.entries(routeModule)) {
|
|
184
|
-
if (typeof value ===
|
|
174
|
+
if (typeof value === 'function') {
|
|
185
175
|
const routeEntry = (value as any)();
|
|
186
176
|
if (Array.isArray(routeEntry)) {
|
|
187
177
|
this.router.addRoute(routeEntry as RouteEntry);
|
|
@@ -198,10 +188,10 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
198
188
|
private isRouteDefinition(value: any): boolean {
|
|
199
189
|
return (
|
|
200
190
|
value &&
|
|
201
|
-
typeof value ===
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
191
|
+
typeof value === 'object' &&
|
|
192
|
+
'entry' in value &&
|
|
193
|
+
'options' in value &&
|
|
194
|
+
'handler' in value
|
|
205
195
|
);
|
|
206
196
|
}
|
|
207
197
|
|
package/src/dev/route-scanner.ts
CHANGED
|
@@ -1,32 +1,31 @@
|
|
|
1
|
-
import { existsSync, promises as fs } from
|
|
2
|
-
import { join, relative, resolve, sep } from
|
|
3
|
-
import type { GeneratedRoute } from
|
|
1
|
+
import { existsSync, promises as fs } from 'node:fs';
|
|
2
|
+
import { join, relative, resolve, sep } from 'node:path';
|
|
3
|
+
import type { GeneratedRoute } from '../types';
|
|
4
4
|
|
|
5
5
|
export class RouteScanner {
|
|
6
6
|
private routesDir: string;
|
|
7
7
|
private excludePatterns: string[];
|
|
8
8
|
private static readonly DEFAULT_EXCLUDE_PATTERNS = [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
9
|
+
'*.test.ts',
|
|
10
|
+
'*.test.js',
|
|
11
|
+
'*.test.tsx',
|
|
12
|
+
'*.test.jsx',
|
|
13
|
+
'*.spec.ts',
|
|
14
|
+
'*.spec.js',
|
|
15
|
+
'*.spec.tsx',
|
|
16
|
+
'*.spec.jsx',
|
|
17
|
+
'*.tests.ts',
|
|
18
|
+
'*.tests.js',
|
|
19
|
+
'**/__tests__/**',
|
|
20
|
+
'*.interface.ts',
|
|
21
|
+
'*.type.ts',
|
|
22
|
+
'*.d.ts',
|
|
23
23
|
];
|
|
24
24
|
|
|
25
|
-
constructor(routesDir =
|
|
25
|
+
constructor(routesDir = './routes', excludePatterns?: string[]) {
|
|
26
26
|
// Always resolve from the current working directory (user's project)
|
|
27
27
|
this.routesDir = resolve(process.cwd(), routesDir);
|
|
28
|
-
this.excludePatterns =
|
|
29
|
-
excludePatterns || RouteScanner.DEFAULT_EXCLUDE_PATTERNS;
|
|
28
|
+
this.excludePatterns = excludePatterns || RouteScanner.DEFAULT_EXCLUDE_PATTERNS;
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
async scan(): Promise<GeneratedRoute[]> {
|
|
@@ -40,7 +39,7 @@ export class RouteScanner {
|
|
|
40
39
|
try {
|
|
41
40
|
await this.scanDirectory(this.routesDir, routes);
|
|
42
41
|
} catch (error) {
|
|
43
|
-
if ((error as any).code ===
|
|
42
|
+
if ((error as any).code === 'ENOENT') {
|
|
44
43
|
console.warn(` ✗ Routes directory not accessible: ${this.routesDir}`);
|
|
45
44
|
return [];
|
|
46
45
|
}
|
|
@@ -56,15 +55,16 @@ export class RouteScanner {
|
|
|
56
55
|
for (const pattern of this.excludePatterns) {
|
|
57
56
|
// Convert glob pattern to regex
|
|
58
57
|
const regexPattern = pattern
|
|
59
|
-
.replace(/\./g,
|
|
60
|
-
.replace(
|
|
61
|
-
.replace(
|
|
62
|
-
.replace(
|
|
58
|
+
.replace(/\./g, '\\.') // Escape dots
|
|
59
|
+
.replace(/\*\*/g, '__GLOBSTAR__') // protect ** before * replacement
|
|
60
|
+
.replace(/\*/g, '[^/]*') // * matches anything except /
|
|
61
|
+
.replace(/__GLOBSTAR__/g, '.*') // ** matches anything including /
|
|
62
|
+
.replace(/\?/g, '.'); // ? matches single character
|
|
63
63
|
|
|
64
64
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
65
65
|
|
|
66
66
|
// Check both the full relative path and just the filename
|
|
67
|
-
const filename = relativePath.split(sep).pop() ||
|
|
67
|
+
const filename = relativePath.split(sep).pop() || '';
|
|
68
68
|
if (regex.test(relativePath) || regex.test(filename)) {
|
|
69
69
|
return true;
|
|
70
70
|
}
|
|
@@ -73,11 +73,7 @@ export class RouteScanner {
|
|
|
73
73
|
return false;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
private async scanDirectory(
|
|
77
|
-
dir: string,
|
|
78
|
-
routes: GeneratedRoute[],
|
|
79
|
-
basePath = ""
|
|
80
|
-
): Promise<void> {
|
|
76
|
+
private async scanDirectory(dir: string, routes: GeneratedRoute[], basePath = ''): Promise<void> {
|
|
81
77
|
const entries = await fs.readdir(dir);
|
|
82
78
|
|
|
83
79
|
for (const entry of entries) {
|
|
@@ -87,32 +83,30 @@ export class RouteScanner {
|
|
|
87
83
|
if (stats.isDirectory()) {
|
|
88
84
|
const newBasePath = basePath ? `${basePath}/${entry}` : entry;
|
|
89
85
|
await this.scanDirectory(fullPath, routes, newBasePath);
|
|
90
|
-
} else if (entry.endsWith(
|
|
86
|
+
} else if (entry.endsWith('.ts') || entry.endsWith('.js')) {
|
|
91
87
|
// Skip excluded files (test files, etc.)
|
|
92
88
|
if (this.isExcluded(fullPath)) {
|
|
93
89
|
continue;
|
|
94
90
|
}
|
|
95
91
|
const routePath = relative(this.routesDir, fullPath)
|
|
96
|
-
.replace(/\.(ts|js)$/,
|
|
92
|
+
.replace(/\.(ts|js)$/, '')
|
|
97
93
|
.split(sep)
|
|
98
|
-
.join(
|
|
94
|
+
.join('/');
|
|
99
95
|
|
|
100
96
|
try {
|
|
101
97
|
// Convert Windows paths to URLs for import
|
|
102
98
|
const importPath =
|
|
103
|
-
process.platform ===
|
|
104
|
-
? `file:///${fullPath.replace(/\\/g, "/")}`
|
|
105
|
-
: fullPath;
|
|
99
|
+
process.platform === 'win32' ? `file:///${fullPath.replace(/\\/g, '/')}` : fullPath;
|
|
106
100
|
|
|
107
101
|
const module = await import(importPath);
|
|
108
102
|
|
|
109
|
-
if (module.default && typeof module.default ===
|
|
103
|
+
if (module.default && typeof module.default === 'function') {
|
|
110
104
|
routes.push({
|
|
111
|
-
name:
|
|
105
|
+
name: 'default',
|
|
112
106
|
path: fullPath,
|
|
113
|
-
method:
|
|
107
|
+
method: 'GET',
|
|
114
108
|
options: {
|
|
115
|
-
method:
|
|
109
|
+
method: 'GET',
|
|
116
110
|
path: `/${routePath}`,
|
|
117
111
|
expose: true,
|
|
118
112
|
},
|
|
@@ -120,15 +114,15 @@ export class RouteScanner {
|
|
|
120
114
|
}
|
|
121
115
|
|
|
122
116
|
for (const [name, value] of Object.entries(module)) {
|
|
123
|
-
if (name ===
|
|
117
|
+
if (name === 'default') continue;
|
|
124
118
|
|
|
125
119
|
// Check for new RouteDefinition format
|
|
126
120
|
if (
|
|
127
121
|
value &&
|
|
128
|
-
typeof value ===
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
122
|
+
typeof value === 'object' &&
|
|
123
|
+
'entry' in value &&
|
|
124
|
+
'options' in value &&
|
|
125
|
+
'handler' in value
|
|
132
126
|
) {
|
|
133
127
|
const routeDef = value as any;
|
|
134
128
|
routes.push({
|
|
@@ -161,7 +155,7 @@ export class RouteScanner {
|
|
|
161
155
|
}
|
|
162
156
|
|
|
163
157
|
enableWatch(callback: () => void) {
|
|
164
|
-
if (typeof Bun !==
|
|
158
|
+
if (typeof Bun !== 'undefined' && Bun.env.NODE_ENV === 'development') {
|
|
165
159
|
console.log(`Watching for route changes in ${this.routesDir}`);
|
|
166
160
|
|
|
167
161
|
setInterval(async () => {
|