@cinnabun/core 0.0.1 → 0.0.2
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/__tests__/autowired.test.d.ts +1 -0
- package/dist/__tests__/autowired.test.js +109 -0
- package/dist/__tests__/autowired.test.js.map +1 -0
- package/dist/__tests__/cinnabun-application.test.d.ts +1 -0
- package/dist/__tests__/cinnabun-application.test.js +96 -0
- package/dist/__tests__/cinnabun-application.test.js.map +1 -0
- package/dist/__tests__/cinnabun-factory.test.d.ts +1 -0
- package/dist/__tests__/cinnabun-factory.test.js +269 -0
- package/dist/__tests__/cinnabun-factory.test.js.map +1 -0
- package/dist/__tests__/circular-dependency.test.d.ts +1 -0
- package/dist/__tests__/circular-dependency.test.js +318 -0
- package/dist/__tests__/circular-dependency.test.js.map +1 -0
- package/dist/__tests__/compression.test.d.ts +1 -0
- package/dist/__tests__/compression.test.js +459 -0
- package/dist/__tests__/compression.test.js.map +1 -0
- package/dist/__tests__/config.test.d.ts +1 -0
- package/dist/__tests__/config.test.js +86 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/__tests__/cors.test.d.ts +1 -0
- package/dist/__tests__/cors.test.js +575 -0
- package/dist/__tests__/cors.test.js.map +1 -0
- package/dist/__tests__/env-config.test.d.ts +1 -0
- package/dist/__tests__/env-config.test.js +367 -0
- package/dist/__tests__/env-config.test.js.map +1 -0
- package/dist/__tests__/exception.test.d.ts +1 -0
- package/dist/__tests__/exception.test.js +207 -0
- package/dist/__tests__/exception.test.js.map +1 -0
- package/dist/__tests__/guards-interceptors.test.d.ts +1 -0
- package/dist/__tests__/guards-interceptors.test.js +660 -0
- package/dist/__tests__/guards-interceptors.test.js.map +1 -0
- package/dist/__tests__/health-check.test.d.ts +1 -0
- package/dist/__tests__/health-check.test.js +240 -0
- package/dist/__tests__/health-check.test.js.map +1 -0
- package/dist/__tests__/http.test.d.ts +1 -0
- package/dist/__tests__/http.test.js +629 -0
- package/dist/__tests__/http.test.js.map +1 -0
- package/dist/__tests__/integration/e2e.test.d.ts +1 -0
- package/dist/__tests__/integration/e2e.test.js +192 -0
- package/dist/__tests__/integration/e2e.test.js.map +1 -0
- package/dist/__tests__/integration/performance.bench.d.ts +1 -0
- package/dist/__tests__/integration/performance.bench.js +129 -0
- package/dist/__tests__/integration/performance.bench.js.map +1 -0
- package/dist/__tests__/integration/validation.test.d.ts +1 -0
- package/dist/__tests__/integration/validation.test.js +133 -0
- package/dist/__tests__/integration/validation.test.js.map +1 -0
- package/dist/__tests__/lifecycle-management.test.d.ts +1 -0
- package/dist/__tests__/lifecycle-management.test.js +688 -0
- package/dist/__tests__/lifecycle-management.test.js.map +1 -0
- package/dist/__tests__/lifecycle.test.d.ts +1 -0
- package/dist/__tests__/lifecycle.test.js +196 -0
- package/dist/__tests__/lifecycle.test.js.map +1 -0
- package/dist/__tests__/logger.test.d.ts +1 -0
- package/dist/__tests__/logger.test.js +109 -0
- package/dist/__tests__/logger.test.js.map +1 -0
- package/dist/__tests__/middleware.test.d.ts +1 -0
- package/dist/__tests__/middleware.test.js +329 -0
- package/dist/__tests__/middleware.test.js.map +1 -0
- package/dist/__tests__/module.test.d.ts +1 -0
- package/dist/__tests__/module.test.js +280 -0
- package/dist/__tests__/module.test.js.map +1 -0
- package/dist/__tests__/plugin.test.d.ts +1 -0
- package/dist/__tests__/plugin.test.js +283 -0
- package/dist/__tests__/plugin.test.js.map +1 -0
- package/dist/__tests__/request-logger.test.d.ts +1 -0
- package/dist/__tests__/request-logger.test.js +342 -0
- package/dist/__tests__/request-logger.test.js.map +1 -0
- package/dist/__tests__/request-mapping.test.d.ts +1 -0
- package/dist/__tests__/request-mapping.test.js +201 -0
- package/dist/__tests__/request-mapping.test.js.map +1 -0
- package/dist/__tests__/routes.test.d.ts +1 -0
- package/dist/__tests__/routes.test.js +119 -0
- package/dist/__tests__/routes.test.js.map +1 -0
- package/dist/__tests__/scan-fixtures/controllers/hello.controller.d.ts +4 -0
- package/dist/__tests__/scan-fixtures/controllers/hello.controller.js +28 -0
- package/dist/__tests__/scan-fixtures/controllers/hello.controller.js.map +1 -0
- package/dist/__tests__/scan-fixtures/modules/feature.module.d.ts +6 -0
- package/dist/__tests__/scan-fixtures/modules/feature.module.js +28 -0
- package/dist/__tests__/scan-fixtures/modules/feature.module.js.map +1 -0
- package/dist/__tests__/scan-fixtures/services/greeting.service.d.ts +4 -0
- package/dist/__tests__/scan-fixtures/services/greeting.service.js +18 -0
- package/dist/__tests__/scan-fixtures/services/greeting.service.js.map +1 -0
- package/dist/__tests__/scanner.test.d.ts +1 -0
- package/dist/__tests__/scanner.test.js +49 -0
- package/dist/__tests__/scanner.test.js.map +1 -0
- package/dist/__tests__/validation.test.d.ts +1 -0
- package/dist/__tests__/validation.test.js +561 -0
- package/dist/__tests__/validation.test.js.map +1 -0
- package/dist/__tests__/websocket-auth.test.d.ts +1 -0
- package/dist/__tests__/websocket-auth.test.js +431 -0
- package/dist/__tests__/websocket-auth.test.js.map +1 -0
- package/dist/__tests__/websocket-decorators.test.d.ts +1 -0
- package/dist/__tests__/websocket-decorators.test.js +173 -0
- package/dist/__tests__/websocket-decorators.test.js.map +1 -0
- package/dist/__tests__/websocket-validation.test.d.ts +1 -0
- package/dist/__tests__/websocket-validation.test.js +827 -0
- package/dist/__tests__/websocket-validation.test.js.map +1 -0
- package/dist/__tests__/websocket.test.d.ts +1 -0
- package/dist/__tests__/websocket.test.js +415 -0
- package/dist/__tests__/websocket.test.js.map +1 -0
- package/dist/config/config.module.d.ts +2 -0
- package/dist/config/config.module.js +18 -0
- package/dist/config/config.module.js.map +1 -0
- package/dist/config/config.service.d.ts +15 -0
- package/dist/config/config.service.js +58 -0
- package/dist/config/config.service.js.map +1 -0
- package/dist/config/schemas.d.ts +107 -0
- package/dist/config/schemas.js +87 -0
- package/dist/config/schemas.js.map +1 -0
- package/dist/core/app.d.ts +44 -0
- package/dist/core/app.js +178 -0
- package/dist/core/app.js.map +1 -0
- package/dist/core/cinnabun-factory.d.ts +5 -0
- package/dist/core/cinnabun-factory.js +130 -0
- package/dist/core/cinnabun-factory.js.map +1 -0
- package/dist/core/config-loader.d.ts +2 -0
- package/dist/core/config-loader.js +76 -0
- package/dist/core/config-loader.js.map +1 -0
- package/dist/core/config.d.ts +12 -0
- package/dist/core/config.js +27 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/container.d.ts +10 -0
- package/dist/core/container.js +82 -0
- package/dist/core/container.js.map +1 -0
- package/dist/core/dependency-validator.d.ts +12 -0
- package/dist/core/dependency-validator.js +76 -0
- package/dist/core/dependency-validator.js.map +1 -0
- package/dist/core/guard.d.ts +3 -0
- package/dist/core/guard.js +2 -0
- package/dist/core/guard.js.map +1 -0
- package/dist/core/interceptor.d.ts +4 -0
- package/dist/core/interceptor.js +2 -0
- package/dist/core/interceptor.js.map +1 -0
- package/dist/core/logger.d.ts +15 -0
- package/dist/core/logger.js +71 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/module-resolver.d.ts +6 -0
- package/dist/core/module-resolver.js +67 -0
- package/dist/core/module-resolver.js.map +1 -0
- package/dist/core/plugin.d.ts +12 -0
- package/dist/core/plugin.js +2 -0
- package/dist/core/plugin.js.map +1 -0
- package/dist/core/router.d.ts +38 -0
- package/dist/core/router.js +406 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/scanner.d.ts +7 -0
- package/dist/core/scanner.js +83 -0
- package/dist/core/scanner.js.map +1 -0
- package/dist/core/shutdown-manager.d.ts +15 -0
- package/dist/core/shutdown-manager.js +68 -0
- package/dist/core/shutdown-manager.js.map +1 -0
- package/dist/core/websocket-handler.d.ts +41 -0
- package/dist/core/websocket-handler.js +242 -0
- package/dist/core/websocket-handler.js.map +1 -0
- package/dist/decorators/autowired.d.ts +3 -0
- package/dist/decorators/autowired.js +11 -0
- package/dist/decorators/autowired.js.map +1 -0
- package/dist/decorators/cinnabun-application.d.ts +14 -0
- package/dist/decorators/cinnabun-application.js +17 -0
- package/dist/decorators/cinnabun-application.js.map +1 -0
- package/dist/decorators/lifecycle.d.ts +2 -0
- package/dist/decorators/lifecycle.js +12 -0
- package/dist/decorators/lifecycle.js.map +1 -0
- package/dist/decorators/middleware.d.ts +2 -0
- package/dist/decorators/middleware.js +12 -0
- package/dist/decorators/middleware.js.map +1 -0
- package/dist/decorators/module.d.ts +10 -0
- package/dist/decorators/module.js +13 -0
- package/dist/decorators/module.js.map +1 -0
- package/dist/decorators/on-shutdown.d.ts +1 -0
- package/dist/decorators/on-shutdown.js +10 -0
- package/dist/decorators/on-shutdown.js.map +1 -0
- package/dist/decorators/params.d.ts +6 -0
- package/dist/decorators/params.js +31 -0
- package/dist/decorators/params.js.map +1 -0
- package/dist/decorators/request-mapping.d.ts +7 -0
- package/dist/decorators/request-mapping.js +34 -0
- package/dist/decorators/request-mapping.js.map +1 -0
- package/dist/decorators/response.d.ts +2 -0
- package/dist/decorators/response.js +17 -0
- package/dist/decorators/response.js.map +1 -0
- package/dist/decorators/rest-controller.d.ts +1 -0
- package/dist/decorators/rest-controller.js +19 -0
- package/dist/decorators/rest-controller.js.map +1 -0
- package/dist/decorators/routes.d.ts +5 -0
- package/dist/decorators/routes.js +19 -0
- package/dist/decorators/routes.js.map +1 -0
- package/dist/decorators/service.d.ts +1 -0
- package/dist/decorators/service.js +7 -0
- package/dist/decorators/service.js.map +1 -0
- package/dist/decorators/use-guard.d.ts +2 -0
- package/dist/decorators/use-guard.js +12 -0
- package/dist/decorators/use-guard.js.map +1 -0
- package/dist/decorators/use-interceptor.d.ts +2 -0
- package/dist/decorators/use-interceptor.js +12 -0
- package/dist/decorators/use-interceptor.js.map +1 -0
- package/dist/decorators/validate.d.ts +12 -0
- package/dist/decorators/validate.js +7 -0
- package/dist/decorators/validate.js.map +1 -0
- package/dist/decorators/websocket.d.ts +9 -0
- package/dist/decorators/websocket.js +38 -0
- package/dist/decorators/websocket.js.map +1 -0
- package/dist/decorators/ws-event.d.ts +28 -0
- package/dist/decorators/ws-event.js +37 -0
- package/dist/decorators/ws-event.js.map +1 -0
- package/dist/decorators/ws-gateway.d.ts +18 -0
- package/dist/decorators/ws-gateway.js +24 -0
- package/dist/decorators/ws-gateway.js.map +1 -0
- package/dist/dev/index.d.ts +6 -0
- package/dist/dev/index.js +28 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/exceptions/circular-dependency-error.d.ts +5 -0
- package/dist/exceptions/circular-dependency-error.js +16 -0
- package/dist/exceptions/circular-dependency-error.js.map +1 -0
- package/dist/exceptions/http-exception.d.ts +41 -0
- package/dist/exceptions/http-exception.js +96 -0
- package/dist/exceptions/http-exception.js.map +1 -0
- package/dist/guards/jwt-websocket.guard.d.ts +11 -0
- package/dist/guards/jwt-websocket.guard.js +37 -0
- package/dist/guards/jwt-websocket.guard.js.map +1 -0
- package/dist/guards/websocket-auth.guard.d.ts +16 -0
- package/dist/guards/websocket-auth.guard.js +43 -0
- package/dist/guards/websocket-auth.guard.js.map +1 -0
- package/dist/health/health-check.service.d.ts +45 -0
- package/dist/health/health-check.service.js +95 -0
- package/dist/health/health-check.service.js.map +1 -0
- package/dist/health/health.controller.d.ts +15 -0
- package/dist/health/health.controller.js +63 -0
- package/dist/health/health.controller.js.map +1 -0
- package/dist/health/health.module.d.ts +2 -0
- package/dist/health/health.module.js +20 -0
- package/dist/health/health.module.js.map +1 -0
- package/dist/index.d.ts +74 -11
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/metadata/storage.d.ts +171 -0
- package/dist/metadata/storage.js +257 -0
- package/dist/metadata/storage.js.map +1 -0
- package/dist/middleware/compression.middleware.d.ts +32 -0
- package/dist/middleware/compression.middleware.js +113 -0
- package/dist/middleware/compression.middleware.js.map +1 -0
- package/dist/middleware/cors.middleware.d.ts +18 -0
- package/dist/middleware/cors.middleware.js +79 -0
- package/dist/middleware/cors.middleware.js.map +1 -0
- package/dist/middleware/performance-tracker.middleware.d.ts +35 -0
- package/dist/middleware/performance-tracker.middleware.js +79 -0
- package/dist/middleware/performance-tracker.middleware.js.map +1 -0
- package/dist/middleware/request-logger.middleware.d.ts +32 -0
- package/dist/middleware/request-logger.middleware.js +125 -0
- package/dist/middleware/request-logger.middleware.js.map +1 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/validation/helpers.d.ts +36 -0
- package/dist/validation/helpers.js +27 -0
- package/dist/validation/helpers.js.map +1 -0
- package/dist/websocket/error.d.ts +27 -0
- package/dist/websocket/error.js +38 -0
- package/dist/websocket/error.js.map +1 -0
- package/package.json +38 -5
- package/LICENSE +0 -9
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { metadataStorage } from "../metadata/storage.js";
|
|
2
|
+
import { HttpException, NotFoundException, BadRequestException, ForbiddenException, InternalServerErrorException, ValidationException } from "../exceptions/http-exception.js";
|
|
3
|
+
export class Router {
|
|
4
|
+
routes = [];
|
|
5
|
+
globalMiddleware = [];
|
|
6
|
+
container = null;
|
|
7
|
+
timeout = 30000; // Default 30s
|
|
8
|
+
routeCache = new Map();
|
|
9
|
+
cacheSize = 100;
|
|
10
|
+
setContainer(container) {
|
|
11
|
+
this.container = container;
|
|
12
|
+
}
|
|
13
|
+
setTimeout(timeout) {
|
|
14
|
+
this.timeout = timeout;
|
|
15
|
+
}
|
|
16
|
+
setGlobalMiddleware(middleware) {
|
|
17
|
+
this.globalMiddleware = middleware;
|
|
18
|
+
}
|
|
19
|
+
registerController(target, instance) {
|
|
20
|
+
const basePath = metadataStorage.getControllerPath(target);
|
|
21
|
+
const routes = metadataStorage.getRoutesFor(target);
|
|
22
|
+
for (const route of routes) {
|
|
23
|
+
const methodPath = route.path === "/" ? "" : normalizePath(route.path);
|
|
24
|
+
const fullPath = normalizePath(basePath + methodPath) || "/";
|
|
25
|
+
const { regex, paramNames } = pathToRegex(fullPath);
|
|
26
|
+
this.routes.push({
|
|
27
|
+
httpMethod: route.httpMethod,
|
|
28
|
+
regex,
|
|
29
|
+
paramNames,
|
|
30
|
+
instance,
|
|
31
|
+
target,
|
|
32
|
+
methodKey: route.methodKey,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
match(method, pathname) {
|
|
37
|
+
// Normalize trailing slash for matching
|
|
38
|
+
const normalized = pathname.length > 1 && pathname.endsWith("/")
|
|
39
|
+
? pathname.slice(0, -1)
|
|
40
|
+
: pathname;
|
|
41
|
+
const cacheKey = `${method}:${normalized}`;
|
|
42
|
+
// Check cache
|
|
43
|
+
if (this.routeCache.has(cacheKey)) {
|
|
44
|
+
return this.routeCache.get(cacheKey);
|
|
45
|
+
}
|
|
46
|
+
// Find match
|
|
47
|
+
for (const route of this.routes) {
|
|
48
|
+
if (route.httpMethod !== method)
|
|
49
|
+
continue;
|
|
50
|
+
const match = route.regex.exec(normalized);
|
|
51
|
+
if (!match)
|
|
52
|
+
continue;
|
|
53
|
+
const pathParams = {};
|
|
54
|
+
for (let i = 0; i < route.paramNames.length; i++) {
|
|
55
|
+
pathParams[route.paramNames[i]] = match[i + 1];
|
|
56
|
+
}
|
|
57
|
+
const result = { route, pathParams };
|
|
58
|
+
// Cache result (LRU)
|
|
59
|
+
if (this.routeCache.size >= this.cacheSize) {
|
|
60
|
+
const firstKey = this.routeCache.keys().next().value;
|
|
61
|
+
if (firstKey !== undefined) {
|
|
62
|
+
this.routeCache.delete(firstKey);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
this.routeCache.set(cacheKey, result);
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
// Cache null result
|
|
69
|
+
if (this.routeCache.size >= this.cacheSize) {
|
|
70
|
+
const firstKey = this.routeCache.keys().next().value;
|
|
71
|
+
if (firstKey !== undefined) {
|
|
72
|
+
this.routeCache.delete(firstKey);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
this.routeCache.set(cacheKey, null);
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
async handle(req) {
|
|
79
|
+
const url = new URL(req.url);
|
|
80
|
+
// Build global middleware instances first
|
|
81
|
+
const globalMiddlewareInstances = this.globalMiddleware.map((mw) => {
|
|
82
|
+
if (typeof mw === "object" && "use" in mw) {
|
|
83
|
+
return mw;
|
|
84
|
+
}
|
|
85
|
+
return this.container.resolve(mw);
|
|
86
|
+
});
|
|
87
|
+
// Execute global middleware first (before route matching)
|
|
88
|
+
// This allows CORS middleware to handle OPTIONS preflight even for unmatched routes
|
|
89
|
+
const executeGlobalMiddleware = async (index) => {
|
|
90
|
+
if (index < globalMiddlewareInstances.length) {
|
|
91
|
+
return globalMiddlewareInstances[index].use(req, () => executeGlobalMiddleware(index + 1));
|
|
92
|
+
}
|
|
93
|
+
// After global middleware, check for route match
|
|
94
|
+
const matched = this.match(req.method, url.pathname);
|
|
95
|
+
if (!matched) {
|
|
96
|
+
const ex = new NotFoundException();
|
|
97
|
+
return Response.json(ex.toJSON(), { status: ex.statusCode });
|
|
98
|
+
}
|
|
99
|
+
const { route, pathParams } = matched;
|
|
100
|
+
return this.executeRouteWithMiddleware(route, pathParams, url, req);
|
|
101
|
+
};
|
|
102
|
+
try {
|
|
103
|
+
return await executeGlobalMiddleware(0);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
return this.handleError(error, req);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async executeRouteWithMiddleware(route, pathParams, url, req) {
|
|
110
|
+
// Create AbortController for timeout
|
|
111
|
+
const controller = new AbortController();
|
|
112
|
+
const timeoutId = setTimeout(() => {
|
|
113
|
+
controller.abort();
|
|
114
|
+
}, this.timeout);
|
|
115
|
+
// Build middleware chain: class-level -> method-level
|
|
116
|
+
// (global middleware already executed in handle())
|
|
117
|
+
const middlewareClasses = metadataStorage.getMiddlewareFor(route.target, route.methodKey);
|
|
118
|
+
const middlewareInstances = middlewareClasses.map((mw) => {
|
|
119
|
+
// If it's already an instance (has 'use' method), return it directly
|
|
120
|
+
if (typeof mw === "object" && "use" in mw) {
|
|
121
|
+
return mw;
|
|
122
|
+
}
|
|
123
|
+
// Otherwise, resolve it from the container
|
|
124
|
+
return this.container.resolve(mw);
|
|
125
|
+
});
|
|
126
|
+
// Resolve guards
|
|
127
|
+
const guardClasses = metadataStorage.getGuardsFor(route.target, route.methodKey);
|
|
128
|
+
const guardInstances = guardClasses.map((g) => this.container.resolve(g));
|
|
129
|
+
// Resolve interceptors
|
|
130
|
+
const interceptorClasses = metadataStorage.getInterceptorsFor(route.target, route.methodKey);
|
|
131
|
+
const interceptorInstances = interceptorClasses.map((i) => this.container.resolve(i));
|
|
132
|
+
// Execute middleware chain, then guards, then interceptors, then route handler
|
|
133
|
+
const executeChain = async (index) => {
|
|
134
|
+
if (index < middlewareInstances.length) {
|
|
135
|
+
return middlewareInstances[index].use(req, () => executeChain(index + 1));
|
|
136
|
+
}
|
|
137
|
+
// Run guards after middleware
|
|
138
|
+
for (const guard of guardInstances) {
|
|
139
|
+
const allowed = await guard.canActivate(req);
|
|
140
|
+
if (!allowed) {
|
|
141
|
+
throw new ForbiddenException();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Run interceptor before hooks
|
|
145
|
+
for (const interceptor of interceptorInstances) {
|
|
146
|
+
if (interceptor.before) {
|
|
147
|
+
await interceptor.before(req);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Execute route handler
|
|
151
|
+
let response = await this.executeRoute(route, req, pathParams, url);
|
|
152
|
+
// Run interceptor after hooks
|
|
153
|
+
for (const interceptor of interceptorInstances) {
|
|
154
|
+
if (interceptor.after) {
|
|
155
|
+
response = await interceptor.after(req, response);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return response;
|
|
159
|
+
};
|
|
160
|
+
// Race the execution against the timeout
|
|
161
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
162
|
+
controller.signal.addEventListener("abort", () => {
|
|
163
|
+
reject(new Error("Request timeout"));
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
try {
|
|
167
|
+
const response = await Promise.race([executeChain(0), timeoutPromise]);
|
|
168
|
+
clearTimeout(timeoutId);
|
|
169
|
+
return response;
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
clearTimeout(timeoutId);
|
|
173
|
+
// Handle timeout specifically
|
|
174
|
+
if (error instanceof Error && error.message === "Request timeout") {
|
|
175
|
+
const errorId = `err_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
176
|
+
const url = new URL(req.url);
|
|
177
|
+
console.error({
|
|
178
|
+
errorId,
|
|
179
|
+
type: "TimeoutError",
|
|
180
|
+
message: `Request timed out after ${this.timeout}ms`,
|
|
181
|
+
method: req.method,
|
|
182
|
+
path: url.pathname,
|
|
183
|
+
timestamp: new Date().toISOString(),
|
|
184
|
+
});
|
|
185
|
+
return Response.json({
|
|
186
|
+
error: "Gateway Timeout",
|
|
187
|
+
message: `Request timed out after ${this.timeout}ms`,
|
|
188
|
+
statusCode: 504,
|
|
189
|
+
errorId,
|
|
190
|
+
}, { status: 504 });
|
|
191
|
+
}
|
|
192
|
+
return this.handleError(error, req);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async executeRoute(route, req, pathParams, url) {
|
|
196
|
+
const queryParams = Object.fromEntries(url.searchParams);
|
|
197
|
+
let body = undefined;
|
|
198
|
+
if (["POST", "PUT", "PATCH"].includes(req.method)) {
|
|
199
|
+
// Check content-length
|
|
200
|
+
const contentLength = req.headers.get("content-length");
|
|
201
|
+
const maxSize = 10 * 1024 * 1024; // 10MB default
|
|
202
|
+
if (contentLength && parseInt(contentLength) > maxSize) {
|
|
203
|
+
throw new BadRequestException(`Payload too large. Max size: ${maxSize} bytes`);
|
|
204
|
+
}
|
|
205
|
+
// Validate content-type for JSON bodies
|
|
206
|
+
const contentType = req.headers.get("content-type");
|
|
207
|
+
const text = await req.text();
|
|
208
|
+
if (text) {
|
|
209
|
+
if (contentType && !contentType.includes("application/json")) {
|
|
210
|
+
throw new BadRequestException(`Invalid content-type: ${contentType}. Expected application/json`);
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
body = JSON.parse(text);
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
throw new BadRequestException(`Invalid JSON body: ${error.message}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const paramsMeta = metadataStorage.getParamsFor(route.target, route.methodKey);
|
|
221
|
+
const args = buildArgs(paramsMeta, {
|
|
222
|
+
pathParams,
|
|
223
|
+
queryParams,
|
|
224
|
+
body,
|
|
225
|
+
headers: req.headers,
|
|
226
|
+
req,
|
|
227
|
+
});
|
|
228
|
+
// Run validation if @Validate() is present
|
|
229
|
+
const validationSchema = metadataStorage.getValidationSchema(route.target, route.methodKey);
|
|
230
|
+
if (validationSchema) {
|
|
231
|
+
const errors = [];
|
|
232
|
+
if (validationSchema.body) {
|
|
233
|
+
const result = validationSchema.body.safeParse(body);
|
|
234
|
+
if (!result.success) {
|
|
235
|
+
for (const issue of result.error.issues) {
|
|
236
|
+
errors.push({ field: issue.path.join(".") || "body", message: issue.message });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
// Replace body in args with parsed (coerced) value
|
|
241
|
+
for (const param of paramsMeta) {
|
|
242
|
+
if (param.source === "body") {
|
|
243
|
+
args[param.parameterIndex] = result.data;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (validationSchema.query) {
|
|
249
|
+
const result = validationSchema.query.safeParse(queryParams);
|
|
250
|
+
if (!result.success) {
|
|
251
|
+
for (const issue of result.error.issues) {
|
|
252
|
+
errors.push({ field: issue.path.join(".") || "query", message: issue.message });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
for (const param of paramsMeta) {
|
|
257
|
+
if (param.source === "query" && param.name) {
|
|
258
|
+
args[param.parameterIndex] = result.data[param.name];
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (validationSchema.params) {
|
|
264
|
+
const result = validationSchema.params.safeParse(pathParams);
|
|
265
|
+
if (!result.success) {
|
|
266
|
+
for (const issue of result.error.issues) {
|
|
267
|
+
errors.push({ field: issue.path.join(".") || "params", message: issue.message });
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
for (const param of paramsMeta) {
|
|
272
|
+
if (param.source === "param" && param.name) {
|
|
273
|
+
args[param.parameterIndex] = result.data[param.name];
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (errors.length > 0) {
|
|
279
|
+
throw new ValidationException(errors);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const result = await route.instance[route.methodKey](...args);
|
|
283
|
+
const statusCode = metadataStorage.getHttpCode(route.target, route.methodKey);
|
|
284
|
+
const responseHeaders = metadataStorage.getResponseHeaders(route.target, route.methodKey);
|
|
285
|
+
return sendResponse(result, statusCode, responseHeaders);
|
|
286
|
+
}
|
|
287
|
+
handleError(error, req) {
|
|
288
|
+
if (error instanceof HttpException) {
|
|
289
|
+
return Response.json(error.toJSON(), { status: error.statusCode });
|
|
290
|
+
}
|
|
291
|
+
// Generate error ID for tracking
|
|
292
|
+
const errorId = `err_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
293
|
+
const url = new URL(req.url);
|
|
294
|
+
// Log with structured context
|
|
295
|
+
console.error({
|
|
296
|
+
errorId,
|
|
297
|
+
type: error instanceof Error ? error.constructor.name : "Error",
|
|
298
|
+
message: error instanceof Error ? error.message : String(error),
|
|
299
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
300
|
+
method: req.method,
|
|
301
|
+
path: url.pathname,
|
|
302
|
+
timestamp: new Date().toISOString(),
|
|
303
|
+
});
|
|
304
|
+
// Return safe error response (don't leak internals in production)
|
|
305
|
+
const isDevelopment = process.env.NODE_ENV !== "production";
|
|
306
|
+
const ex = new InternalServerErrorException();
|
|
307
|
+
return Response.json({
|
|
308
|
+
...ex.toJSON(),
|
|
309
|
+
errorId,
|
|
310
|
+
...(isDevelopment && error instanceof Error && {
|
|
311
|
+
details: {
|
|
312
|
+
message: error.message,
|
|
313
|
+
type: error.constructor.name,
|
|
314
|
+
},
|
|
315
|
+
}),
|
|
316
|
+
}, { status: ex.statusCode });
|
|
317
|
+
}
|
|
318
|
+
getRoutes() {
|
|
319
|
+
return this.routes.map((route) => {
|
|
320
|
+
// Reconstruct path from regex by reversing the pathToRegex logic
|
|
321
|
+
const path = route.regex.source
|
|
322
|
+
.replace(/^\^/, "")
|
|
323
|
+
.replace(/\$$/, "")
|
|
324
|
+
.replace(/\(\[\^\/\]\+\)/g, (_, index) => {
|
|
325
|
+
const paramIndex = Math.floor(index / 11); // Approximate index
|
|
326
|
+
return route.paramNames[paramIndex] ? `:${route.paramNames[paramIndex]}` : ":param";
|
|
327
|
+
});
|
|
328
|
+
return {
|
|
329
|
+
method: route.httpMethod,
|
|
330
|
+
path: path || "/",
|
|
331
|
+
};
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function buildArgs(paramsMeta, ctx) {
|
|
336
|
+
if (paramsMeta.length === 0)
|
|
337
|
+
return [];
|
|
338
|
+
const maxIndex = Math.max(...paramsMeta.map((p) => p.parameterIndex));
|
|
339
|
+
const args = new Array(maxIndex + 1).fill(undefined);
|
|
340
|
+
for (const param of paramsMeta) {
|
|
341
|
+
switch (param.source) {
|
|
342
|
+
case "param":
|
|
343
|
+
args[param.parameterIndex] = ctx.pathParams[param.name];
|
|
344
|
+
break;
|
|
345
|
+
case "query":
|
|
346
|
+
args[param.parameterIndex] = ctx.queryParams[param.name];
|
|
347
|
+
break;
|
|
348
|
+
case "body":
|
|
349
|
+
args[param.parameterIndex] = ctx.body;
|
|
350
|
+
break;
|
|
351
|
+
case "headers":
|
|
352
|
+
if (param.name) {
|
|
353
|
+
args[param.parameterIndex] = ctx.headers.get(param.name);
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
args[param.parameterIndex] = Object.fromEntries(ctx.headers.entries());
|
|
357
|
+
}
|
|
358
|
+
break;
|
|
359
|
+
case "req":
|
|
360
|
+
args[param.parameterIndex] = ctx.req;
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return args;
|
|
365
|
+
}
|
|
366
|
+
function sendResponse(result, statusCode, responseHeaders) {
|
|
367
|
+
const headers = new globalThis.Headers();
|
|
368
|
+
if (responseHeaders) {
|
|
369
|
+
for (const h of responseHeaders) {
|
|
370
|
+
// Normalize header names to lowercase for HTTP/2 compatibility
|
|
371
|
+
headers.set(h.name.toLowerCase(), h.value);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (result === null || result === undefined) {
|
|
375
|
+
return new Response(null, { status: statusCode ?? 204, headers });
|
|
376
|
+
}
|
|
377
|
+
if (typeof result === "string") {
|
|
378
|
+
headers.set("Content-Type", "text/plain");
|
|
379
|
+
return new Response(result, { status: statusCode ?? 200, headers });
|
|
380
|
+
}
|
|
381
|
+
headers.set("Content-Type", "application/json");
|
|
382
|
+
return new Response(JSON.stringify(result), {
|
|
383
|
+
status: statusCode ?? 200,
|
|
384
|
+
headers,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
function normalizePath(path) {
|
|
388
|
+
if (!path || path === "/")
|
|
389
|
+
return path || "";
|
|
390
|
+
if (!path.startsWith("/"))
|
|
391
|
+
path = "/" + path;
|
|
392
|
+
if (path.endsWith("/") && path.length > 1)
|
|
393
|
+
path = path.slice(0, -1);
|
|
394
|
+
// Fix double slashes
|
|
395
|
+
path = path.replace(/\/+/g, "/");
|
|
396
|
+
return path;
|
|
397
|
+
}
|
|
398
|
+
function pathToRegex(path) {
|
|
399
|
+
const paramNames = [];
|
|
400
|
+
const regexStr = path.replace(/:(\w+)/g, (_, name) => {
|
|
401
|
+
paramNames.push(name);
|
|
402
|
+
return "([^/]+)";
|
|
403
|
+
});
|
|
404
|
+
return { regex: new RegExp(`^${regexStr}$`), paramNames };
|
|
405
|
+
}
|
|
406
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/core/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Constructor } from "../metadata/storage.js";
|
|
2
|
+
export interface ScannedComponents {
|
|
3
|
+
controllers: Constructor[];
|
|
4
|
+
providers: Constructor[];
|
|
5
|
+
modules: Constructor[];
|
|
6
|
+
}
|
|
7
|
+
export declare function scanComponents(basePaths: string[]): Promise<ScannedComponents>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { resolve } from "path";
|
|
2
|
+
import { pathToFileURL } from "url";
|
|
3
|
+
import { Glob } from "bun";
|
|
4
|
+
import { metadataStorage } from "../metadata/storage.js";
|
|
5
|
+
export async function scanComponents(basePaths) {
|
|
6
|
+
// Snapshot what's already registered so we only return newly scanned classes
|
|
7
|
+
const knownProviders = new Set(metadataStorage.providers);
|
|
8
|
+
const knownControllers = new Set(metadataStorage.controllerPaths.keys());
|
|
9
|
+
const knownModules = new Set(metadataStorage.modules.keys());
|
|
10
|
+
// Track imported files to avoid duplicates
|
|
11
|
+
const importedFiles = new Set();
|
|
12
|
+
// Scan and import files
|
|
13
|
+
for (const basePath of basePaths) {
|
|
14
|
+
const cwd = resolve(basePath);
|
|
15
|
+
// Support both .ts (dev) and .js (production/tests)
|
|
16
|
+
// Check if running from compiled dist directory
|
|
17
|
+
const isCompiledDist = cwd.includes("/dist/") || cwd.includes("\\dist\\");
|
|
18
|
+
const isProduction = process.env.NODE_ENV === "production" || isCompiledDist;
|
|
19
|
+
const extension = isProduction ? "js" : "ts";
|
|
20
|
+
// Use two patterns to ensure we catch files at all levels:
|
|
21
|
+
// - *.ext matches files in the current directory
|
|
22
|
+
// - **/*.ext matches files in subdirectories
|
|
23
|
+
const patterns = [`*.${extension}`, `**/*.${extension}`];
|
|
24
|
+
for (const pattern of patterns) {
|
|
25
|
+
const glob = new Glob(pattern);
|
|
26
|
+
try {
|
|
27
|
+
for await (const file of glob.scan({ cwd })) {
|
|
28
|
+
// Skip node_modules
|
|
29
|
+
if (file.includes("node_modules"))
|
|
30
|
+
continue;
|
|
31
|
+
// Skip test files (but allow scanning fixture directories for tests)
|
|
32
|
+
if (file.endsWith(".test.ts") || file.endsWith(".spec.ts"))
|
|
33
|
+
continue;
|
|
34
|
+
if (file.endsWith(".test.js") || file.endsWith(".spec.js"))
|
|
35
|
+
continue;
|
|
36
|
+
if (file.endsWith(".d.ts"))
|
|
37
|
+
continue;
|
|
38
|
+
const fullPath = resolve(cwd, file);
|
|
39
|
+
// Skip if already imported (prevents duplicates from overlapping patterns)
|
|
40
|
+
if (importedFiles.has(fullPath))
|
|
41
|
+
continue;
|
|
42
|
+
importedFiles.add(fullPath);
|
|
43
|
+
try {
|
|
44
|
+
// Use file URL for Bun compatibility with absolute paths
|
|
45
|
+
const fileUrl = pathToFileURL(fullPath).href;
|
|
46
|
+
await import(fileUrl);
|
|
47
|
+
}
|
|
48
|
+
catch (importError) {
|
|
49
|
+
// Log import errors but continue scanning
|
|
50
|
+
console.warn(`Warning: Failed to import ${fullPath}:`, importError.message);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
// Gracefully handle nonexistent directories or permission errors
|
|
56
|
+
if (error.code === "ENOENT" || error.code === "EACCES") {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Classify newly discovered classes
|
|
64
|
+
const controllers = [];
|
|
65
|
+
const providers = [];
|
|
66
|
+
const modules = [];
|
|
67
|
+
for (const [target] of metadataStorage.controllerPaths) {
|
|
68
|
+
if (!knownControllers.has(target))
|
|
69
|
+
controllers.push(target);
|
|
70
|
+
}
|
|
71
|
+
for (const target of metadataStorage.providers) {
|
|
72
|
+
if (!knownProviders.has(target) &&
|
|
73
|
+
!metadataStorage.controllerPaths.has(target)) {
|
|
74
|
+
providers.push(target);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
for (const [target] of metadataStorage.modules) {
|
|
78
|
+
if (!knownModules.has(target))
|
|
79
|
+
modules.push(target);
|
|
80
|
+
}
|
|
81
|
+
return { controllers, providers, modules };
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/core/scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Container } from "./container.js";
|
|
2
|
+
export interface ShutdownHook {
|
|
3
|
+
name: string;
|
|
4
|
+
execute: () => Promise<void> | void;
|
|
5
|
+
timeout?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class ShutdownManager {
|
|
8
|
+
private hooks;
|
|
9
|
+
private isShuttingDown;
|
|
10
|
+
private logger;
|
|
11
|
+
registerHook(hook: ShutdownHook): void;
|
|
12
|
+
shutdown(container: Container, timeout?: number): Promise<void>;
|
|
13
|
+
private shutdownContainer;
|
|
14
|
+
private executeWithTimeout;
|
|
15
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Logger } from "./logger.js";
|
|
2
|
+
export class ShutdownManager {
|
|
3
|
+
hooks = [];
|
|
4
|
+
isShuttingDown = false;
|
|
5
|
+
logger = new Logger("ShutdownManager");
|
|
6
|
+
registerHook(hook) {
|
|
7
|
+
this.hooks.push(hook);
|
|
8
|
+
}
|
|
9
|
+
async shutdown(container, timeout = 5000) {
|
|
10
|
+
if (this.isShuttingDown) {
|
|
11
|
+
this.logger.warn("Shutdown already in progress");
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
this.isShuttingDown = true;
|
|
15
|
+
this.logger.info("Starting graceful shutdown...");
|
|
16
|
+
const startTime = Date.now();
|
|
17
|
+
const errors = [];
|
|
18
|
+
// 1. Call container PreDestroy hooks
|
|
19
|
+
try {
|
|
20
|
+
await this.shutdownContainer(container, timeout);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
errors.push({
|
|
24
|
+
name: "Container",
|
|
25
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
// 2. Execute custom shutdown hooks in parallel
|
|
29
|
+
const hookPromises = this.hooks.map(async (hook) => {
|
|
30
|
+
const hookTimeout = hook.timeout ?? timeout;
|
|
31
|
+
try {
|
|
32
|
+
await this.executeWithTimeout(hook.execute(), hookTimeout, `Hook: ${hook.name}`);
|
|
33
|
+
this.logger.info(`✓ ${hook.name} cleaned up successfully`);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
this.logger.error(`✗ ${hook.name} cleanup failed:`, error);
|
|
37
|
+
errors.push({
|
|
38
|
+
name: hook.name,
|
|
39
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
await Promise.allSettled(hookPromises);
|
|
44
|
+
const duration = Date.now() - startTime;
|
|
45
|
+
if (errors.length > 0) {
|
|
46
|
+
this.logger.error(`Shutdown completed with ${errors.length} error(s) in ${duration}ms`);
|
|
47
|
+
errors.forEach(({ name, error }) => {
|
|
48
|
+
this.logger.error(` • ${name}: ${error.message}`);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
this.logger.info(`Graceful shutdown completed in ${duration}ms`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async shutdownContainer(container, timeout) {
|
|
56
|
+
const containerShutdown = container.shutdown();
|
|
57
|
+
await this.executeWithTimeout(containerShutdown, timeout, "Container shutdown");
|
|
58
|
+
}
|
|
59
|
+
async executeWithTimeout(promise, timeout, name) {
|
|
60
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
61
|
+
setTimeout(() => {
|
|
62
|
+
reject(new Error(`${name} timed out after ${timeout}ms`));
|
|
63
|
+
}, timeout);
|
|
64
|
+
});
|
|
65
|
+
await Promise.race([Promise.resolve(promise), timeoutPromise]);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=shutdown-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shutdown-manager.js","sourceRoot":"","sources":["../../src/core/shutdown-manager.ts"],"names":[],"mappings":"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"}
|